You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

printer.h 16 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  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 <map>
  38. #include <string>
  39. #include <vector>
  40. #include <google/protobuf/stubs/common.h>
  41. // Must be included last.
  42. #include <google/protobuf/port_def.inc>
  43. namespace google {
  44. namespace protobuf {
  45. namespace io {
  46. class ZeroCopyOutputStream; // zero_copy_stream.h
  47. // Records annotations about a Printer's output.
  48. class PROTOBUF_EXPORT AnnotationCollector {
  49. public:
  50. // Annotation is a offset range and a payload pair.
  51. typedef std::pair<std::pair<size_t, size_t>, std::string> Annotation;
  52. // Records that the bytes in file_path beginning with begin_offset and ending
  53. // before end_offset are associated with the SourceCodeInfo-style path.
  54. virtual void AddAnnotation(size_t begin_offset, size_t end_offset,
  55. const std::string& file_path,
  56. const std::vector<int>& path) = 0;
  57. // TODO(gerbens) I don't see why we need virtuals here. Just a vector of
  58. // range, payload pairs stored in a context should suffice.
  59. virtual void AddAnnotationNew(Annotation& /* a */) {}
  60. virtual ~AnnotationCollector() {}
  61. };
  62. // Records annotations about a Printer's output to the given protocol buffer,
  63. // assuming that the buffer has an ::Annotation message exposing path,
  64. // source_file, begin and end fields.
  65. template <typename AnnotationProto>
  66. class AnnotationProtoCollector : public AnnotationCollector {
  67. public:
  68. // annotation_proto is the protocol buffer to which new Annotations should be
  69. // added. It is not owned by the AnnotationProtoCollector.
  70. explicit AnnotationProtoCollector(AnnotationProto* annotation_proto)
  71. : annotation_proto_(annotation_proto) {}
  72. // Override for AnnotationCollector::AddAnnotation.
  73. void AddAnnotation(size_t begin_offset, size_t end_offset,
  74. const std::string& file_path,
  75. const std::vector<int>& path) override {
  76. typename AnnotationProto::Annotation* annotation =
  77. annotation_proto_->add_annotation();
  78. for (int i = 0; i < path.size(); ++i) {
  79. annotation->add_path(path[i]);
  80. }
  81. annotation->set_source_file(file_path);
  82. annotation->set_begin(begin_offset);
  83. annotation->set_end(end_offset);
  84. }
  85. // Override for AnnotationCollector::AddAnnotation.
  86. void AddAnnotationNew(Annotation& a) override {
  87. auto* annotation = annotation_proto_->add_annotation();
  88. annotation->ParseFromString(a.second);
  89. annotation->set_begin(a.first.first);
  90. annotation->set_end(a.first.second);
  91. }
  92. private:
  93. // The protocol buffer to which new annotations should be added.
  94. AnnotationProto* const annotation_proto_;
  95. };
  96. // This simple utility class assists in code generation. It basically
  97. // allows the caller to define a set of variables and then output some
  98. // text with variable substitutions. Example usage:
  99. //
  100. // Printer printer(output, '$');
  101. // map<string, string> vars;
  102. // vars["name"] = "Bob";
  103. // printer.Print(vars, "My name is $name$.");
  104. //
  105. // The above writes "My name is Bob." to the output stream.
  106. //
  107. // Printer aggressively enforces correct usage, crashing (with assert failures)
  108. // in the case of undefined variables in debug builds. This helps greatly in
  109. // debugging code which uses it.
  110. //
  111. // If a Printer is constructed with an AnnotationCollector, it will provide it
  112. // with annotations that connect the Printer's output to paths that can identify
  113. // various descriptors. In the above example, if person_ is a descriptor that
  114. // identifies Bob, we can associate the output string "My name is Bob." with
  115. // a source path pointing to that descriptor with:
  116. //
  117. // printer.Annotate("name", person_);
  118. //
  119. // The AnnotationCollector will be sent an annotation linking the output range
  120. // covering "Bob" to the logical path provided by person_. Tools may use
  121. // this association to (for example) link "Bob" in the output back to the
  122. // source file that defined the person_ descriptor identifying Bob.
  123. //
  124. // Annotate can only examine variables substituted during the last call to
  125. // Print. It is invalid to refer to a variable that was used multiple times
  126. // in a single Print call.
  127. //
  128. // In full generality, one may specify a range of output text using a beginning
  129. // substitution variable and an ending variable. The resulting annotation will
  130. // span from the first character of the substituted value for the beginning
  131. // variable to the last character of the substituted value for the ending
  132. // variable. For example, the Annotate call above is equivalent to this one:
  133. //
  134. // printer.Annotate("name", "name", person_);
  135. //
  136. // This is useful if multiple variables combine to form a single span of output
  137. // that should be annotated with the same source path. For example:
  138. //
  139. // Printer printer(output, '$');
  140. // map<string, string> vars;
  141. // vars["first"] = "Alice";
  142. // vars["last"] = "Smith";
  143. // printer.Print(vars, "My name is $first$ $last$.");
  144. // printer.Annotate("first", "last", person_);
  145. //
  146. // This code would associate the span covering "Alice Smith" in the output with
  147. // the person_ descriptor.
  148. //
  149. // Note that the beginning variable must come before (or overlap with, in the
  150. // case of zero-sized substitution values) the ending variable.
  151. //
  152. // It is also sometimes useful to use variables with zero-sized values as
  153. // markers. This avoids issues with multiple references to the same variable
  154. // and also allows annotation ranges to span literal text from the Print
  155. // templates:
  156. //
  157. // Printer printer(output, '$');
  158. // map<string, string> vars;
  159. // vars["foo"] = "bar";
  160. // vars["function"] = "call";
  161. // vars["mark"] = "";
  162. // printer.Print(vars, "$function$($foo$,$foo$)$mark$");
  163. // printer.Annotate("function", "mark", call_);
  164. //
  165. // This code associates the span covering "call(bar,bar)" in the output with the
  166. // call_ descriptor.
  167. class PROTOBUF_EXPORT Printer {
  168. public:
  169. // Create a printer that writes text to the given output stream. Use the
  170. // given character as the delimiter for variables.
  171. Printer(ZeroCopyOutputStream* output, char variable_delimiter);
  172. // Create a printer that writes text to the given output stream. Use the
  173. // given character as the delimiter for variables. If annotation_collector
  174. // is not null, Printer will provide it with annotations about code written
  175. // to the stream. annotation_collector is not owned by Printer.
  176. Printer(ZeroCopyOutputStream* output, char variable_delimiter,
  177. AnnotationCollector* annotation_collector);
  178. ~Printer();
  179. // Link a substitution variable emitted by the last call to Print to the
  180. // object described by descriptor.
  181. template <typename SomeDescriptor>
  182. void Annotate(const char* varname, const SomeDescriptor* descriptor) {
  183. Annotate(varname, varname, descriptor);
  184. }
  185. // Link the output range defined by the substitution variables as emitted by
  186. // the last call to Print to the object described by descriptor. The range
  187. // begins at begin_varname's value and ends after the last character of the
  188. // value substituted for end_varname.
  189. template <typename SomeDescriptor>
  190. void Annotate(const char* begin_varname, const char* end_varname,
  191. const SomeDescriptor* descriptor) {
  192. if (annotation_collector_ == NULL) {
  193. // Annotations aren't turned on for this Printer, so don't pay the cost
  194. // of building the location path.
  195. return;
  196. }
  197. std::vector<int> path;
  198. descriptor->GetLocationPath(&path);
  199. Annotate(begin_varname, end_varname, descriptor->file()->name(), path);
  200. }
  201. // Link a substitution variable emitted by the last call to Print to the file
  202. // with path file_name.
  203. void Annotate(const char* varname, const std::string& file_name) {
  204. Annotate(varname, varname, file_name);
  205. }
  206. // Link the output range defined by the substitution variables as emitted by
  207. // the last call to Print to the file with path file_name. The range begins
  208. // at begin_varname's value and ends after the last character of the value
  209. // substituted for end_varname.
  210. void Annotate(const char* begin_varname, const char* end_varname,
  211. const std::string& file_name) {
  212. if (annotation_collector_ == NULL) {
  213. // Annotations aren't turned on for this Printer.
  214. return;
  215. }
  216. std::vector<int> empty_path;
  217. Annotate(begin_varname, end_varname, file_name, empty_path);
  218. }
  219. // Print some text after applying variable substitutions. If a particular
  220. // variable in the text is not defined, this will crash. Variables to be
  221. // substituted are identified by their names surrounded by delimiter
  222. // characters (as given to the constructor). The variable bindings are
  223. // defined by the given map.
  224. void Print(const std::map<std::string, std::string>& variables,
  225. const char* text);
  226. // Like the first Print(), except the substitutions are given as parameters.
  227. template <typename... Args>
  228. void Print(const char* text, const Args&... args) {
  229. std::map<std::string, std::string> vars;
  230. PrintInternal(&vars, text, args...);
  231. }
  232. // Indent text by two spaces. After calling Indent(), two spaces will be
  233. // inserted at the beginning of each line of text. Indent() may be called
  234. // multiple times to produce deeper indents.
  235. void Indent();
  236. // Reduces the current indent level by two spaces, or crashes if the indent
  237. // level is zero.
  238. void Outdent();
  239. // Write a string to the output buffer.
  240. // This method does not look for newlines to add indentation.
  241. void PrintRaw(const std::string& data);
  242. // Write a zero-delimited string to output buffer.
  243. // This method does not look for newlines to add indentation.
  244. void PrintRaw(const char* data);
  245. // Write some bytes to the output buffer.
  246. // This method does not look for newlines to add indentation.
  247. void WriteRaw(const char* data, int size);
  248. // FormatInternal is a helper function not meant to use directly, use
  249. // compiler::cpp::Formatter instead. This function is meant to support
  250. // formatting text using named variables (eq. "$foo$) from a lookup map (vars)
  251. // and variables directly supplied by arguments (eq "$1$" meaning first
  252. // argument which is the zero index element of args).
  253. void FormatInternal(const std::vector<std::string>& args,
  254. const std::map<std::string, std::string>& vars,
  255. const char* format);
  256. // True if any write to the underlying stream failed. (We don't just
  257. // crash in this case because this is an I/O failure, not a programming
  258. // error.)
  259. bool failed() const { return failed_; }
  260. private:
  261. // Link the output range defined by the substitution variables as emitted by
  262. // the last call to Print to the object found at the SourceCodeInfo-style path
  263. // in a file with path file_path. The range begins at the start of
  264. // begin_varname's value and ends after the last character of the value
  265. // substituted for end_varname. Note that begin_varname and end_varname
  266. // may refer to the same variable.
  267. void Annotate(const char* begin_varname, const char* end_varname,
  268. const std::string& file_path, const std::vector<int>& path);
  269. // Base case
  270. void PrintInternal(std::map<std::string, std::string>* vars,
  271. const char* text) {
  272. Print(*vars, text);
  273. }
  274. template <typename... Args>
  275. void PrintInternal(std::map<std::string, std::string>* vars, const char* text,
  276. const char* key, const std::string& value,
  277. const Args&... args) {
  278. (*vars)[key] = value;
  279. PrintInternal(vars, text, args...);
  280. }
  281. // Copy size worth of bytes from data to buffer_.
  282. void CopyToBuffer(const char* data, int size);
  283. void push_back(char c) {
  284. if (failed_) return;
  285. if (buffer_size_ == 0) {
  286. if (!Next()) return;
  287. }
  288. *buffer_++ = c;
  289. buffer_size_--;
  290. offset_++;
  291. }
  292. bool Next();
  293. inline void IndentIfAtStart();
  294. const char* WriteVariable(
  295. const std::vector<std::string>& args,
  296. const std::map<std::string, std::string>& vars, const char* format,
  297. int* arg_index,
  298. std::vector<AnnotationCollector::Annotation>* annotations);
  299. const char variable_delimiter_;
  300. ZeroCopyOutputStream* const output_;
  301. char* buffer_;
  302. int buffer_size_;
  303. // The current position, in bytes, in the output stream. This is equivalent
  304. // to the total number of bytes that have been written so far. This value is
  305. // used to calculate annotation ranges in the substitutions_ map below.
  306. size_t offset_;
  307. std::string indent_;
  308. bool at_start_of_line_;
  309. bool failed_;
  310. // A map from variable name to [start, end) offsets in the output buffer.
  311. // These refer to the offsets used for a variable after the last call to
  312. // Print. If a variable was used more than once, the entry used in
  313. // this map is set to a negative-length span. For singly-used variables, the
  314. // start offset is the beginning of the substitution; the end offset is the
  315. // last byte of the substitution plus one (such that (end - start) is the
  316. // length of the substituted string).
  317. std::map<std::string, std::pair<size_t, size_t> > substitutions_;
  318. // Keeps track of the keys in substitutions_ that need to be updated when
  319. // indents are inserted. These are keys that refer to the beginning of the
  320. // current line.
  321. std::vector<std::string> line_start_variables_;
  322. // Returns true and sets range to the substitution range in the output for
  323. // varname if varname was used once in the last call to Print. If varname
  324. // was not used, or if it was used multiple times, returns false (and
  325. // fails a debug assertion).
  326. bool GetSubstitutionRange(const char* varname,
  327. std::pair<size_t, size_t>* range);
  328. // If non-null, annotation_collector_ is used to store annotations about
  329. // generated code.
  330. AnnotationCollector* const annotation_collector_;
  331. GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Printer);
  332. };
  333. } // namespace io
  334. } // namespace protobuf
  335. } // namespace google
  336. #include <google/protobuf/port_undef.inc>
  337. #endif // GOOGLE_PROTOBUF_IO_PRINTER_H__