Brian Silverman | 70325d6 | 2015-09-20 17:00:43 -0400 | [diff] [blame] | 1 | // Copyright (c) 2009, Google Inc. |
| 2 | // All rights reserved. |
| 3 | // |
| 4 | // Redistribution and use in source and binary forms, with or without |
| 5 | // modification, are permitted provided that the following conditions are |
| 6 | // met: |
| 7 | // |
| 8 | // * Redistributions of source code must retain the above copyright |
| 9 | // notice, this list of conditions and the following disclaimer. |
| 10 | // * Redistributions in binary form must reproduce the above |
| 11 | // copyright notice, this list of conditions and the following disclaimer |
| 12 | // in the documentation and/or other materials provided with the |
| 13 | // distribution. |
| 14 | // * Neither the name of Google Inc. nor the names of its |
| 15 | // contributors may be used to endorse or promote products derived from |
| 16 | // this software without specific prior written permission. |
| 17 | // |
| 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 29 | |
| 30 | // --- |
| 31 | // |
| 32 | // This file implements the Template Cache used to store templates. |
| 33 | |
| 34 | #ifndef TEMPLATE_TEMPLATE_CACHE_H_ |
| 35 | #define TEMPLATE_TEMPLATE_CACHE_H_ |
| 36 | |
| 37 | #include @ac_cv_cxx_hash_map@ // for @ac_cv_cxx_hash_map_class@<> |
| 38 | #include <string> // for string |
| 39 | #include <utility> // for pair |
| 40 | #include <vector> // for vector<> |
| 41 | #include <ctemplate/template_emitter.h> // for ExpandEmitter, etc |
| 42 | #include <ctemplate/template_enums.h> // for Strip |
| 43 | #include <ctemplate/template_string.h> |
| 44 | #include <ctemplate/per_expand_data.h> |
| 45 | @ac_google_start_namespace@ |
| 46 | class FileStat; |
| 47 | } |
| 48 | class Mutex; |
| 49 | class TemplateCacheUnittest; |
| 50 | |
| 51 | @ac_windows_dllexport_defines@ |
| 52 | |
| 53 | namespace ctemplate { |
| 54 | |
| 55 | class PerExpandData; |
| 56 | class Template; |
| 57 | class TemplateCachePeer; |
| 58 | class TemplateDictionaryInterface; |
| 59 | |
| 60 | // A cache to store parsed templates. |
| 61 | class @ac_windows_dllexport@ TemplateCache { |
| 62 | public: |
| 63 | TemplateCache(); |
| 64 | ~TemplateCache(); |
| 65 | |
| 66 | // ---- CREATING A TEMPLATE OBJECT ------- |
| 67 | // LoadTemplate |
| 68 | // StringToTemplateCache |
| 69 | |
| 70 | // Attempts to load the template object stored under its filename, |
| 71 | // into the template cache. It first checks if the object is already |
| 72 | // in the cache. Any object retrieved from the cache is then |
| 73 | // checked to see if its status is marked for "reload if changed." |
| 74 | // If so, ReloadIfChanged is called on the retrieved object. Returns |
| 75 | // true if the object is loaded. Also returns true if the object |
| 76 | // already exists, and no reload was required. |
| 77 | // |
| 78 | // When it fails to retrieve one from the cache, it creates a new |
| 79 | // template object, passing the filename and 'strip' values to the |
| 80 | // constructor. (See constructor below for the meaning of the |
| 81 | // flags.) If it succeeds in creating an object, including loading |
| 82 | // and parsing the associated template file, the object is stored in |
| 83 | // the cache, and the method returns true. |
| 84 | // |
| 85 | // If it fails in loading and parsing the template file, either |
| 86 | // because the file was not found or it contained syntax errors, |
| 87 | // then the newly created object is deleted and the method returns |
| 88 | // false. (NOTE: This description is much longer and less precise |
| 89 | // and probably harder to understand than the method itself. Read |
| 90 | // the code.) |
| 91 | // |
| 92 | // To enable Auto-Escape on that template, place the corresponding |
| 93 | // AUTOESCAPE pragma at the top of the template file. The template |
| 94 | // will then be Auto-Escaped independently of the template it may be |
| 95 | // included from or the templates it may include. |
| 96 | // |
| 97 | // 'Strip' indicates how to handle whitespace when expanding the |
| 98 | // template. DO_NOT_STRIP keeps the template exactly as-is. |
| 99 | // STRIP_BLANK_LINES elides all blank lines in the template. |
| 100 | // STRIP_WHITESPACE elides all blank lines, and also all whitespace |
| 101 | // at either the beginning or end of a line. See template constructor |
| 102 | // for more details. |
| 103 | bool LoadTemplate(const TemplateString& filename, Strip strip); |
| 104 | |
| 105 | // Parses the string as a template file (e.g. "Hello {{WORLD}}"), |
| 106 | // and inserts it into the parsed template cache, so it can later be |
| 107 | // used by the user. The user specifies a key and a strip, which are |
| 108 | // later passed in to expand the template. |
| 109 | // Returns true if the template was successfully parsed and |
| 110 | // inserted to the template cache, or false otherwise. In particular, |
| 111 | // we return false if a string was already cached with the given key. |
| 112 | // NOTE: to include this template from within another template (via |
| 113 | // "{{>TEMPLATE_THAT_COMES_FROM_A_STRING}}"), the argument you pass |
| 114 | // to TemplateDictionary::SetFilename() is the key you used to register |
| 115 | // the string-template. |
| 116 | bool StringToTemplateCache(const TemplateString& key, |
| 117 | const TemplateString& content, |
| 118 | Strip strip); |
| 119 | bool StringToTemplateCache(const TemplateString& key, |
| 120 | const char* content, |
| 121 | size_t content_len, |
| 122 | Strip strip) { |
| 123 | return StringToTemplateCache(key, |
| 124 | TemplateString(content, content_len), |
| 125 | strip); |
| 126 | } |
| 127 | |
| 128 | // ---- EXPANDING A TEMPLATE ------- |
| 129 | // ExpandWithData |
| 130 | // ExpandFrozen |
| 131 | |
| 132 | // This returns false if the expand failed for some reason: filename |
| 133 | // could not be found on disk (and isn't already in the cache), or |
| 134 | // the template is mal-formed, or a sub-included template couldn't |
| 135 | // be found. Note that even if it returns false, it may have emitted |
| 136 | // some output to ExpandEmitter, before it noticed the problem. |
| 137 | bool ExpandWithData(const TemplateString& filename, Strip strip, |
| 138 | const TemplateDictionaryInterface *dictionary, |
| 139 | PerExpandData* per_expand_data, |
| 140 | ExpandEmitter* output); |
| 141 | bool ExpandWithData(const TemplateString& filename, Strip strip, |
| 142 | const TemplateDictionaryInterface* dictionary, |
| 143 | PerExpandData* per_expand_data, |
| 144 | std::string* output_buffer) { |
| 145 | if (output_buffer == NULL) return false; |
| 146 | StringEmitter e(output_buffer); |
| 147 | return ExpandWithData(filename, strip, dictionary, per_expand_data, &e); |
| 148 | } |
| 149 | |
| 150 | // Const version of ExpandWithData, intended for use with frozen |
| 151 | // caches. This method returns false if the requested |
| 152 | // template-filename is not found in the cache, rather than fetching |
| 153 | // the template from disk and continuing, as ExpandWithData does. |
| 154 | // (That is why the method can be const.) Likewise, it will return |
| 155 | // false, rather than fetch, if any sub-included template filename |
| 156 | // is not found in the cache. |
| 157 | // Unfortunately, the only way to enforce this last requirement at |
| 158 | // the moment is to have the template-cache be Frozen(). So that |
| 159 | // is a pre-requisite for calling this method. It may be relaxed |
| 160 | // in the future (if we rewrite the control flow to pass around the |
| 161 | // necessary state). |
| 162 | // Like ExpandWithData(), this may write partial results into output |
| 163 | // even if it returns false (due to template error or file not found). |
| 164 | bool ExpandNoLoad(const TemplateString& filename, Strip strip, |
| 165 | const TemplateDictionaryInterface *dictionary, |
| 166 | PerExpandData* per_expand_data, |
| 167 | ExpandEmitter* output) const; |
| 168 | bool ExpandNoLoad(const TemplateString& filename, Strip strip, |
| 169 | const TemplateDictionaryInterface* dictionary, |
| 170 | PerExpandData* per_expand_data, |
| 171 | std::string* output_buffer) const { |
| 172 | if (output_buffer == NULL) return false; |
| 173 | StringEmitter e(output_buffer); |
| 174 | return ExpandNoLoad(filename, strip, dictionary, per_expand_data, &e); |
| 175 | } |
| 176 | |
| 177 | // ---- FINDING A TEMPLATE FILE ------- |
| 178 | |
| 179 | // Sets the root directory for all templates used by the program. |
| 180 | // After calling this method, the filename passed to GetTemplate may |
| 181 | // be a relative pathname (no leading '/'), in which case this |
| 182 | // root-directory is prepended to the filename. This clears the old |
| 183 | // 'main' root directory, and also all alternate root directories |
| 184 | // that may had been added previously. |
| 185 | bool SetTemplateRootDirectory(const std::string& directory); |
| 186 | |
| 187 | // Adds an additional search path for all templates used by the |
| 188 | // program. You may call this multiple times. |
| 189 | bool AddAlternateTemplateRootDirectory(const std::string& directory); |
| 190 | |
| 191 | // Returns the 'main' root directory set by SetTemplateRootDirectory(). |
| 192 | std::string template_root_directory() const; |
| 193 | |
| 194 | // Given an unresolved filename, look through the template search |
| 195 | // path to see if the template can be found. If so, return the path |
| 196 | // of the resolved filename, otherwise return an empty string. |
| 197 | std::string FindTemplateFilename(const std::string& unresolved) |
| 198 | const; |
| 199 | |
| 200 | // ---- MANAGING THE CACHE ------- |
| 201 | // Freeze |
| 202 | // Delete |
| 203 | // ClearCache |
| 204 | // ReloadAllIfChanged |
| 205 | // Clone |
| 206 | |
| 207 | // Marks the template cache as immutable. After this method is called, |
| 208 | // the cache can no longer be modified by loading new templates or |
| 209 | // reloading existing templates. During expansion only cached |
| 210 | // included templates will be used, they won't be loaded on-demand. |
| 211 | void Freeze(); |
| 212 | |
| 213 | // Delete |
| 214 | // Deletes one template object from the cache, if it exists. |
| 215 | // This can be used for either file- or string-based templates. |
| 216 | // Returns true if the object was deleted, false otherwise. |
| 217 | bool Delete(const TemplateString& key); |
| 218 | |
| 219 | // ClearCache |
| 220 | // Deletes all the template objects in the cache and all raw |
| 221 | // contents cached from StringToTemplateCache. This should only |
| 222 | // be done once, just before exiting the program and after all |
| 223 | // template expansions are completed. (If you want to refresh the |
| 224 | // cache, the correct method to use is ReloadAllIfChanged, not |
| 225 | // this one.) Note: this method is not necessary unless you are |
| 226 | // testing for memory leaks. Calling this before exiting the |
| 227 | // program will prevent unnecessary reporting in that case. |
| 228 | void ClearCache(); |
| 229 | |
| 230 | // ReloadAllIfChanged |
| 231 | // If IMMEDIATE_RELOAD, reloads and parses all templates right away, |
| 232 | // if the corresponding template files have changed. |
| 233 | // If LAZY_RELOAD, then sets the reload bit on all templates. |
| 234 | // Subsequent call to GetTemplate() checks if file has changed, and if so |
| 235 | // reloads and parses the file into the cache. |
| 236 | // |
| 237 | // IMMEDIATE_RELOAD gives a more consistent snapshot of the current |
| 238 | // templates, since all templates in the cache are reloaded at |
| 239 | // (approximately) the same time. On the other hand, LAZY_RELOAD |
| 240 | // causes less of a latency spike, since it does not require |
| 241 | // loading lots of templates from disk at the same time. If in |
| 242 | // doubt, LAZY_RELOAD is probably a better choice. |
| 243 | |
| 244 | // If a file with the same name as an existing template-file, is added |
| 245 | // in another search path, ReloadAllIfChanged will pick up the file in the |
| 246 | // earlier search-path. |
| 247 | enum ReloadType { LAZY_RELOAD, IMMEDIATE_RELOAD }; |
| 248 | void ReloadAllIfChanged(ReloadType reload_tyle); |
| 249 | |
| 250 | // Clone |
| 251 | // Returns a copy of the cache. It makes a shallow copy of the |
| 252 | // parsed_template_cache_, incrementing refcount of templates. |
| 253 | // The caller is responsible for deallocating the returned TemplateCache. |
| 254 | // NOTE(user): Annotalysis expects this method to have a lock for |
| 255 | // a TemplateCache instance local to the method, but we |
| 256 | // know that no other threads will have access to the |
| 257 | // instance, so ignore thread safety errors. |
| 258 | TemplateCache* Clone() const; |
| 259 | |
| 260 | // ---- INSPECTING THE CACHE ------- |
| 261 | // Dump |
| 262 | // DumpToString |
| 263 | // TODO(csilvers): implement these? |
| 264 | |
| 265 | private: |
| 266 | // TODO(csilvers): nix Template friend once Template::ReloadIfChanged is gone |
| 267 | friend class Template; // for ResolveTemplateFilename |
| 268 | friend class TemplateTemplateNode; // for ExpandLocked |
| 269 | friend class TemplateCachePeer; // for unittests |
| 270 | friend class ::TemplateCacheUnittest; // for unittests |
| 271 | |
| 272 | class RefcountedTemplate; |
| 273 | struct CachedTemplate; |
| 274 | class TemplateCacheHash; |
| 275 | class RefTplPtrHash; |
| 276 | // due to a bug(?) in MSVC, TemplateCachePeer won't compile unless this |
| 277 | // particular typedef is public. Ugh. |
| 278 | public: |
| 279 | typedef std::pair<TemplateId, int> TemplateCacheKey; |
| 280 | private: |
| 281 | typedef @ac_cv_cxx_hash_map_class@<TemplateCacheKey, CachedTemplate, TemplateCacheHash> |
| 282 | TemplateMap; |
| 283 | typedef @ac_cv_cxx_hash_map_class@<RefcountedTemplate*, int, RefTplPtrHash> TemplateCallMap; |
| 284 | // Where to search for files. |
| 285 | typedef std::vector<std::string> TemplateSearchPath; |
| 286 | |
| 287 | // GetTemplate |
| 288 | // This method is deprecated. It exists here because it is called by |
| 289 | // Template::GetTemplate. Also this is used in tests. |
| 290 | const Template* GetTemplate(const TemplateString& key, Strip strip); |
| 291 | |
| 292 | bool ResolveTemplateFilename(const std::string& unresolved, |
| 293 | std::string* resolved, |
| 294 | FileStat* statbuf) const; |
| 295 | |
| 296 | // This is used only for internal (recursive) calls to Expand due |
| 297 | // to internal template-includes. It doesn't try to acquire the |
| 298 | // global template_lock again, in template.cc. |
| 299 | // TODO(csilvers): remove this when template.cc's g_template_lock goes away. |
| 300 | bool ExpandLocked(const TemplateString& filename, Strip strip, |
| 301 | ExpandEmitter* output, |
| 302 | const TemplateDictionaryInterface *dictionary, |
| 303 | PerExpandData* per_expand_data); |
| 304 | |
| 305 | bool AddAlternateTemplateRootDirectoryHelper( |
| 306 | const std::string& directory, |
| 307 | bool clear_template_search_path); |
| 308 | |
| 309 | // DoneWithGetTemplatePtrs |
| 310 | // For historical reasons, GetTemplate() returns a raw Template |
| 311 | // pointer rather than a refcounted pointer. So it's impossible |
| 312 | // for the user to call DecRef on the template when it's done |
| 313 | // using it. To make up for that, we provide this routine, which |
| 314 | // says "call DecRef()" on *all* Templates ever used by |
| 315 | // GetTemplate(). It's safe for the client to call this when it's |
| 316 | // done using all templates it's ever retrieved before (via |
| 317 | // GetTemplate). Most likely, the user will call this indirectly, |
| 318 | // via ClearCache(). |
| 319 | // TODO(panicker): Consider making this method public. |
| 320 | void DoneWithGetTemplatePtrs(); |
| 321 | |
| 322 | // ValidTemplateFilename |
| 323 | // Validates the user provided filename before constructing the template |
| 324 | bool IsValidTemplateFilename(const std::string& filename, |
| 325 | std::string* resolved_filename, |
| 326 | FileStat* statbuf) const; |
| 327 | |
| 328 | // GetTemplateLocked |
| 329 | // Internal version of GetTemplate. It's used when the function already |
| 330 | // has a write-lock on mutex_. It returns a pointer to a refcounted |
| 331 | // template (in the cache), or NULL if the template is not found. |
| 332 | // Its used by GetTemplate & ForceReloadAllIfChanged. |
| 333 | RefcountedTemplate* GetTemplateLocked( |
| 334 | const TemplateString& filename, |
| 335 | Strip strip, |
| 336 | const TemplateCacheKey& key); |
| 337 | |
| 338 | // Refcount |
| 339 | // Testing only. Returns the refcount of a template, given its cache key. |
| 340 | int Refcount(const TemplateCacheKey template_cache_key) const; |
| 341 | |
| 342 | // GetCachedTemplate |
| 343 | // Debug only. Returns whether the cache key is in the parsed cache. |
| 344 | bool TemplateIsCached(const TemplateCacheKey template_cache_key) const; |
| 345 | |
| 346 | TemplateMap* parsed_template_cache_; |
| 347 | bool is_frozen_; |
| 348 | TemplateSearchPath search_path_; |
| 349 | |
| 350 | // Since GetTemplate() returns a raw pointer, it's impossible for |
| 351 | // the caller to call DecRef() on the returned template when it's |
| 352 | // done using it. To make up for that, we store each retval of |
| 353 | // GetTemplate in this data structure. Then the user can call |
| 354 | // DecRef() on all of them at once, via a DoneWithGetTemplatePtrs() |
| 355 | // (which they will probably get at via a call to ClearCache()). |
| 356 | TemplateCallMap* get_template_calls_; |
| 357 | |
| 358 | Mutex* const mutex_; |
| 359 | Mutex* const search_path_mutex_; |
| 360 | |
| 361 | // Can't invoke copy constructor or assignment operator |
| 362 | TemplateCache(const TemplateCache&); |
| 363 | void operator=(const TemplateCache &); |
| 364 | }; |
| 365 | |
| 366 | } |
| 367 | |
| 368 | #endif // TEMPLATE_TEMPLATE_CACHE_H_ |