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