printer.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. // Protocol Buffers - Google's data interchange format
  2. // Copyright 2008 Google Inc. All rights reserved.
  3. // https://developers.google.com/protocol-buffers/
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are
  7. // met:
  8. //
  9. // * Redistributions of source code must retain the above copyright
  10. // notice, this list of conditions and the following disclaimer.
  11. // * Redistributions in binary form must reproduce the above
  12. // copyright notice, this list of conditions and the following disclaimer
  13. // in the documentation and/or other materials provided with the
  14. // distribution.
  15. // * Neither the name of Google Inc. nor the names of its
  16. // contributors may be used to endorse or promote products derived from
  17. // this software without specific prior written permission.
  18. //
  19. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. // Author: kenton@google.com (Kenton Varda)
  31. // Based on original Protocol Buffers design by
  32. // Sanjay Ghemawat, Jeff Dean, and others.
  33. //
  34. // Utility class for writing text to a ZeroCopyOutputStream.
  35. #ifndef GOOGLE_PROTOBUF_IO_PRINTER_H__
  36. #define GOOGLE_PROTOBUF_IO_PRINTER_H__
  37. #include <string>
  38. #include <map>
  39. #include <vector>
  40. #include <google/protobuf/stubs/common.h>
  41. namespace google {
  42. namespace protobuf {
  43. namespace io {
  44. class ZeroCopyOutputStream; // zero_copy_stream.h
  45. // Records annotations about a Printer's output.
  46. class LIBPROTOBUF_EXPORT AnnotationCollector {
  47. public:
  48. // Records that the bytes in file_path beginning with begin_offset and ending
  49. // before end_offset are associated with the SourceCodeInfo-style path.
  50. virtual void AddAnnotation(size_t begin_offset, size_t end_offset,
  51. const string& file_path,
  52. const std::vector<int>& path) = 0;
  53. virtual ~AnnotationCollector() {}
  54. };
  55. // Records annotations about a Printer's output to the given protocol buffer,
  56. // assuming that the buffer has an ::Annotation message exposing path,
  57. // source_file, begin and end fields.
  58. template <typename AnnotationProto>
  59. class AnnotationProtoCollector : public AnnotationCollector {
  60. public:
  61. // annotation_proto is the protocol buffer to which new Annotations should be
  62. // added. It is not owned by the AnnotationProtoCollector.
  63. explicit AnnotationProtoCollector(AnnotationProto* annotation_proto)
  64. : annotation_proto_(annotation_proto) {}
  65. // Override for AnnotationCollector::AddAnnotation.
  66. virtual void AddAnnotation(size_t begin_offset, size_t end_offset,
  67. const string& file_path,
  68. const std::vector<int>& path) {
  69. typename AnnotationProto::Annotation* annotation =
  70. annotation_proto_->add_annotation();
  71. for (int i = 0; i < path.size(); ++i) {
  72. annotation->add_path(path[i]);
  73. }
  74. annotation->set_source_file(file_path);
  75. annotation->set_begin(begin_offset);
  76. annotation->set_end(end_offset);
  77. }
  78. private:
  79. // The protocol buffer to which new annotations should be added.
  80. AnnotationProto* const annotation_proto_;
  81. };
  82. // This simple utility class assists in code generation. It basically
  83. // allows the caller to define a set of variables and then output some
  84. // text with variable substitutions. Example usage:
  85. //
  86. // Printer printer(output, '$');
  87. // map<string, string> vars;
  88. // vars["name"] = "Bob";
  89. // printer.Print(vars, "My name is $name$.");
  90. //
  91. // The above writes "My name is Bob." to the output stream.
  92. //
  93. // Printer aggressively enforces correct usage, crashing (with assert failures)
  94. // in the case of undefined variables in debug builds. This helps greatly in
  95. // debugging code which uses it.
  96. //
  97. // If a Printer is constructed with an AnnotationCollector, it will provide it
  98. // with annotations that connect the Printer's output to paths that can identify
  99. // various descriptors. In the above example, if person_ is a descriptor that
  100. // identifies Bob, we can associate the output string "My name is Bob." with
  101. // a source path pointing to that descriptor with:
  102. //
  103. // printer.Annotate("name", person_);
  104. //
  105. // The AnnotationCollector will be sent an annotation linking the output range
  106. // covering "Bob" to the logical path provided by person_. Tools may use
  107. // this association to (for example) link "Bob" in the output back to the
  108. // source file that defined the person_ descriptor identifying Bob.
  109. //
  110. // Annotate can only examine variables substituted during the last call to
  111. // Print. It is invalid to refer to a variable that was used multiple times
  112. // in a single Print call.
  113. //
  114. // In full generality, one may specify a range of output text using a beginning
  115. // substitution variable and an ending variable. The resulting annotation will
  116. // span from the first character of the substituted value for the beginning
  117. // variable to the last character of the substituted value for the ending
  118. // variable. For example, the Annotate call above is equivalent to this one:
  119. //
  120. // printer.Annotate("name", "name", person_);
  121. //
  122. // This is useful if multiple variables combine to form a single span of output
  123. // that should be annotated with the same source path. For example:
  124. //
  125. // Printer printer(output, '$');
  126. // map<string, string> vars;
  127. // vars["first"] = "Alice";
  128. // vars["last"] = "Smith";
  129. // printer.Print(vars, "My name is $first$ $last$.");
  130. // printer.Annotate("first", "last", person_);
  131. //
  132. // This code would associate the span covering "Alice Smith" in the output with
  133. // the person_ descriptor.
  134. //
  135. // Note that the beginning variable must come before (or overlap with, in the
  136. // case of zero-sized substitution values) the ending variable.
  137. //
  138. // It is also sometimes useful to use variables with zero-sized values as
  139. // markers. This avoids issues with multiple references to the same variable
  140. // and also allows annotation ranges to span literal text from the Print
  141. // templates:
  142. //
  143. // Printer printer(output, '$');
  144. // map<string, string> vars;
  145. // vars["foo"] = "bar";
  146. // vars["function"] = "call";
  147. // vars["mark"] = "";
  148. // printer.Print(vars, "$function$($foo$,$foo$)$mark$");
  149. // printer.Annotate("function", "mark", call_);
  150. //
  151. // This code associates the span covering "call(bar,bar)" in the output with the
  152. // call_ descriptor.
  153. class LIBPROTOBUF_EXPORT Printer {
  154. public:
  155. // Create a printer that writes text to the given output stream. Use the
  156. // given character as the delimiter for variables.
  157. Printer(ZeroCopyOutputStream* output, char variable_delimiter);
  158. // Create a printer that writes text to the given output stream. Use the
  159. // given character as the delimiter for variables. If annotation_collector
  160. // is not null, Printer will provide it with annotations about code written
  161. // to the stream. annotation_collector is not owned by Printer.
  162. Printer(ZeroCopyOutputStream* output, char variable_delimiter,
  163. AnnotationCollector* annotation_collector);
  164. ~Printer();
  165. // Link a subsitution variable emitted by the last call to Print to the object
  166. // described by descriptor.
  167. template <typename SomeDescriptor>
  168. void Annotate(const char* varname, const SomeDescriptor* descriptor) {
  169. Annotate(varname, varname, descriptor);
  170. }
  171. // Link the output range defined by the substitution variables as emitted by
  172. // the last call to Print to the object described by descriptor. The range
  173. // begins at begin_varname's value and ends after the last character of the
  174. // value substituted for end_varname.
  175. template <typename SomeDescriptor>
  176. void Annotate(const char* begin_varname, const char* end_varname,
  177. const SomeDescriptor* descriptor) {
  178. if (annotation_collector_ == NULL) {
  179. // Annotations aren't turned on for this Printer, so don't pay the cost
  180. // of building the location path.
  181. return;
  182. }
  183. std::vector<int> path;
  184. descriptor->GetLocationPath(&path);
  185. Annotate(begin_varname, end_varname, descriptor->file()->name(), path);
  186. }
  187. // Link a subsitution variable emitted by the last call to Print to the file
  188. // with path file_name.
  189. void Annotate(const char* varname, const string& file_name) {
  190. Annotate(varname, varname, file_name);
  191. }
  192. // Link the output range defined by the substitution variables as emitted by
  193. // the last call to Print to the file with path file_name. The range begins
  194. // at begin_varname's value and ends after the last character of the value
  195. // substituted for end_varname.
  196. void Annotate(const char* begin_varname, const char* end_varname,
  197. const string& file_name) {
  198. if (annotation_collector_ == NULL) {
  199. // Annotations aren't turned on for this Printer.
  200. return;
  201. }
  202. std::vector<int> empty_path;
  203. Annotate(begin_varname, end_varname, file_name, empty_path);
  204. }
  205. // Print some text after applying variable substitutions. If a particular
  206. // variable in the text is not defined, this will crash. Variables to be
  207. // substituted are identified by their names surrounded by delimiter
  208. // characters (as given to the constructor). The variable bindings are
  209. // defined by the given map.
  210. void Print(const std::map<string, string>& variables, const char* text);
  211. // Like the first Print(), except the substitutions are given as parameters.
  212. void Print(const char* text);
  213. // Like the first Print(), except the substitutions are given as parameters.
  214. void Print(const char* text, const char* variable, const string& value);
  215. // Like the first Print(), except the substitutions are given as parameters.
  216. void Print(const char* text, const char* variable1, const string& value1,
  217. const char* variable2, const string& value2);
  218. // Like the first Print(), except the substitutions are given as parameters.
  219. void Print(const char* text, const char* variable1, const string& value1,
  220. const char* variable2, const string& value2,
  221. const char* variable3, const string& value3);
  222. // Like the first Print(), except the substitutions are given as parameters.
  223. void Print(const char* text, const char* variable1, const string& value1,
  224. const char* variable2, const string& value2,
  225. const char* variable3, const string& value3,
  226. const char* variable4, const string& value4);
  227. // Like the first Print(), except the substitutions are given as parameters.
  228. void Print(const char* text, const char* variable1, const string& value1,
  229. const char* variable2, const string& value2,
  230. const char* variable3, const string& value3,
  231. const char* variable4, const string& value4,
  232. const char* variable5, const string& value5);
  233. // Like the first Print(), except the substitutions are given as parameters.
  234. void Print(const char* text, const char* variable1, const string& value1,
  235. const char* variable2, const string& value2,
  236. const char* variable3, const string& value3,
  237. const char* variable4, const string& value4,
  238. const char* variable5, const string& value5,
  239. const char* variable6, const string& value6);
  240. // Like the first Print(), except the substitutions are given as parameters.
  241. void Print(const char* text, const char* variable1, const string& value1,
  242. const char* variable2, const string& value2,
  243. const char* variable3, const string& value3,
  244. const char* variable4, const string& value4,
  245. const char* variable5, const string& value5,
  246. const char* variable6, const string& value6,
  247. const char* variable7, const string& value7);
  248. // Like the first Print(), except the substitutions are given as parameters.
  249. void Print(const char* text, const char* variable1, const string& value1,
  250. const char* variable2, const string& value2,
  251. const char* variable3, const string& value3,
  252. const char* variable4, const string& value4,
  253. const char* variable5, const string& value5,
  254. const char* variable6, const string& value6,
  255. const char* variable7, const string& value7,
  256. const char* variable8, const string& value8);
  257. // Indent text by two spaces. After calling Indent(), two spaces will be
  258. // inserted at the beginning of each line of text. Indent() may be called
  259. // multiple times to produce deeper indents.
  260. void Indent();
  261. // Reduces the current indent level by two spaces, or crashes if the indent
  262. // level is zero.
  263. void Outdent();
  264. // Write a string to the output buffer.
  265. // This method does not look for newlines to add indentation.
  266. void PrintRaw(const string& data);
  267. // Write a zero-delimited string to output buffer.
  268. // This method does not look for newlines to add indentation.
  269. void PrintRaw(const char* data);
  270. // Write some bytes to the output buffer.
  271. // This method does not look for newlines to add indentation.
  272. void WriteRaw(const char* data, int size);
  273. // True if any write to the underlying stream failed. (We don't just
  274. // crash in this case because this is an I/O failure, not a programming
  275. // error.)
  276. bool failed() const { return failed_; }
  277. private:
  278. // Link the output range defined by the substitution variables as emitted by
  279. // the last call to Print to the object found at the SourceCodeInfo-style path
  280. // in a file with path file_path. The range begins at the start of
  281. // begin_varname's value and ends after the last character of the value
  282. // substituted for end_varname. Note that begin_varname and end_varname
  283. // may refer to the same variable.
  284. void Annotate(const char* begin_varname, const char* end_varname,
  285. const string& file_path, const std::vector<int>& path);
  286. // Copy size worth of bytes from data to buffer_.
  287. void CopyToBuffer(const char* data, int size);
  288. const char variable_delimiter_;
  289. ZeroCopyOutputStream* const output_;
  290. char* buffer_;
  291. int buffer_size_;
  292. // The current position, in bytes, in the output stream. This is equivalent
  293. // to the total number of bytes that have been written so far. This value is
  294. // used to calculate annotation ranges in the substitutions_ map below.
  295. size_t offset_;
  296. string indent_;
  297. bool at_start_of_line_;
  298. bool failed_;
  299. // A map from variable name to [start, end) offsets in the output buffer.
  300. // These refer to the offsets used for a variable after the last call to
  301. // Print. If a variable was used more than once, the entry used in
  302. // this map is set to a negative-length span. For singly-used variables, the
  303. // start offset is the beginning of the substitution; the end offset is the
  304. // last byte of the substitution plus one (such that (end - start) is the
  305. // length of the substituted string).
  306. std::map<string, std::pair<size_t, size_t> > substitutions_;
  307. // Keeps track of the keys in substitutions_ that need to be updated when
  308. // indents are inserted. These are keys that refer to the beginning of the
  309. // current line.
  310. std::vector<string> line_start_variables_;
  311. // Returns true and sets range to the substitution range in the output for
  312. // varname if varname was used once in the last call to Print. If varname
  313. // was not used, or if it was used multiple times, returns false (and
  314. // fails a debug assertion).
  315. bool GetSubstitutionRange(const char* varname,
  316. std::pair<size_t, size_t>* range);
  317. // If non-null, annotation_collector_ is used to store annotations about
  318. // generated code.
  319. AnnotationCollector* const annotation_collector_;
  320. GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Printer);
  321. };
  322. } // namespace io
  323. } // namespace protobuf
  324. } // namespace google
  325. #endif // GOOGLE_PROTOBUF_IO_PRINTER_H__