blob: 998eff2f21feac343dbc43530c80797ca528cceb [file] [log] [blame]
Brian Silverman70325d62015-09-20 17:00:43 -04001// 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@
46class FileStat;
47}
48class Mutex;
49class TemplateCacheUnittest;
50
51@ac_windows_dllexport_defines@
52
53namespace ctemplate {
54
55class PerExpandData;
56class Template;
57class TemplateCachePeer;
58class TemplateDictionaryInterface;
59
60// A cache to store parsed templates.
61class @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_