cpp_map_field.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  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. #include <google/protobuf/compiler/cpp/cpp_map_field.h>
  31. #include <google/protobuf/compiler/cpp/cpp_helpers.h>
  32. #include <google/protobuf/io/printer.h>
  33. #include <google/protobuf/wire_format.h>
  34. #include <google/protobuf/stubs/strutil.h>
  35. namespace google {
  36. namespace protobuf {
  37. namespace compiler {
  38. namespace cpp {
  39. bool IsProto3Field(const FieldDescriptor* field_descriptor) {
  40. const FileDescriptor* file_descriptor = field_descriptor->file();
  41. return file_descriptor->syntax() == FileDescriptor::SYNTAX_PROTO3;
  42. }
  43. void SetMessageVariables(const FieldDescriptor* descriptor,
  44. std::map<string, string>* variables,
  45. const Options& options) {
  46. SetCommonFieldVariables(descriptor, variables, options);
  47. (*variables)["type"] = ClassName(descriptor->message_type(), false);
  48. (*variables)["file_namespace"] =
  49. FileLevelNamespace(descriptor->file()->name());
  50. (*variables)["stream_writer"] =
  51. (*variables)["declared_type"] +
  52. (HasFastArraySerialization(descriptor->message_type()->file(), options)
  53. ? "MaybeToArray"
  54. : "");
  55. (*variables)["full_name"] = descriptor->full_name();
  56. const FieldDescriptor* key =
  57. descriptor->message_type()->FindFieldByName("key");
  58. const FieldDescriptor* val =
  59. descriptor->message_type()->FindFieldByName("value");
  60. (*variables)["key_cpp"] = PrimitiveTypeName(key->cpp_type());
  61. switch (val->cpp_type()) {
  62. case FieldDescriptor::CPPTYPE_MESSAGE:
  63. (*variables)["val_cpp"] = FieldMessageTypeName(val);
  64. (*variables)["wrapper"] = "EntryWrapper";
  65. break;
  66. case FieldDescriptor::CPPTYPE_ENUM:
  67. (*variables)["val_cpp"] = ClassName(val->enum_type(), true);
  68. (*variables)["wrapper"] = "EnumEntryWrapper";
  69. break;
  70. default:
  71. (*variables)["val_cpp"] = PrimitiveTypeName(val->cpp_type());
  72. (*variables)["wrapper"] = "EntryWrapper";
  73. }
  74. (*variables)["key_wire_type"] =
  75. "::google::protobuf::internal::WireFormatLite::TYPE_" +
  76. ToUpper(DeclaredTypeMethodName(key->type()));
  77. (*variables)["val_wire_type"] =
  78. "::google::protobuf::internal::WireFormatLite::TYPE_" +
  79. ToUpper(DeclaredTypeMethodName(val->type()));
  80. (*variables)["map_classname"] = ClassName(descriptor->message_type(), false);
  81. (*variables)["number"] = SimpleItoa(descriptor->number());
  82. (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
  83. if (HasDescriptorMethods(descriptor->file(), options)) {
  84. (*variables)["lite"] = "";
  85. } else {
  86. (*variables)["lite"] = "Lite";
  87. }
  88. if (!IsProto3Field(descriptor) &&
  89. val->type() == FieldDescriptor::TYPE_ENUM) {
  90. const EnumValueDescriptor* default_value = val->default_value_enum();
  91. (*variables)["default_enum_value"] = Int32ToString(default_value->number());
  92. } else {
  93. (*variables)["default_enum_value"] = "0";
  94. }
  95. }
  96. MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor,
  97. const Options& options)
  98. : FieldGenerator(options), descriptor_(descriptor) {
  99. SetMessageVariables(descriptor, &variables_, options);
  100. }
  101. MapFieldGenerator::~MapFieldGenerator() {}
  102. void MapFieldGenerator::
  103. GeneratePrivateMembers(io::Printer* printer) const {
  104. printer->Print(variables_,
  105. "::google::protobuf::internal::MapField$lite$<\n"
  106. " $map_classname$,\n"
  107. " $key_cpp$, $val_cpp$,\n"
  108. " $key_wire_type$,\n"
  109. " $val_wire_type$,\n"
  110. " $default_enum_value$ > $name$_;\n");
  111. }
  112. void MapFieldGenerator::
  113. GenerateAccessorDeclarations(io::Printer* printer) const {
  114. printer->Print(
  115. variables_,
  116. "$deprecated_attr$const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n"
  117. " $name$() const;\n");
  118. printer->Annotate("name", descriptor_);
  119. printer->Print(variables_,
  120. "$deprecated_attr$::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n"
  121. " ${$mutable_$name$$}$();\n");
  122. printer->Annotate("{", "}", descriptor_);
  123. }
  124. void MapFieldGenerator::
  125. GenerateInlineAccessorDefinitions(io::Printer* printer) const {
  126. printer->Print(variables_,
  127. "inline const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n"
  128. "$classname$::$name$() const {\n"
  129. " // @@protoc_insertion_point(field_map:$full_name$)\n"
  130. " return $name$_.GetMap();\n"
  131. "}\n"
  132. "inline ::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n"
  133. "$classname$::mutable_$name$() {\n"
  134. " // @@protoc_insertion_point(field_mutable_map:$full_name$)\n"
  135. " return $name$_.MutableMap();\n"
  136. "}\n");
  137. }
  138. void MapFieldGenerator::
  139. GenerateClearingCode(io::Printer* printer) const {
  140. printer->Print(variables_, "$name$_.Clear();\n");
  141. }
  142. void MapFieldGenerator::
  143. GenerateMergingCode(io::Printer* printer) const {
  144. printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n");
  145. }
  146. void MapFieldGenerator::
  147. GenerateSwappingCode(io::Printer* printer) const {
  148. printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n");
  149. }
  150. void MapFieldGenerator::
  151. GenerateCopyConstructorCode(io::Printer* printer) const {
  152. GenerateConstructorCode(printer);
  153. GenerateMergingCode(printer);
  154. }
  155. void MapFieldGenerator::
  156. GenerateMergeFromCodedStream(io::Printer* printer) const {
  157. const FieldDescriptor* key_field =
  158. descriptor_->message_type()->FindFieldByName("key");
  159. const FieldDescriptor* value_field =
  160. descriptor_->message_type()->FindFieldByName("value");
  161. bool using_entry = false;
  162. string key;
  163. string value;
  164. if (IsProto3Field(descriptor_) ||
  165. value_field->type() != FieldDescriptor::TYPE_ENUM) {
  166. printer->Print(
  167. variables_,
  168. "$map_classname$::Parser< ::google::protobuf::internal::MapField$lite$<\n"
  169. " $map_classname$,\n"
  170. " $key_cpp$, $val_cpp$,\n"
  171. " $key_wire_type$,\n"
  172. " $val_wire_type$,\n"
  173. " $default_enum_value$ >,\n"
  174. " ::google::protobuf::Map< $key_cpp$, $val_cpp$ > >"
  175. " parser(&$name$_);\n"
  176. "DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(\n"
  177. " input, &parser));\n");
  178. key = "parser.key()";
  179. value = "parser.value()";
  180. } else {
  181. using_entry = true;
  182. key = "entry->key()";
  183. value = "entry->value()";
  184. printer->Print(variables_,
  185. "::std::unique_ptr<$map_classname$> entry($name$_.NewEntry());\n");
  186. printer->Print(variables_,
  187. "{\n"
  188. " ::std::string data;\n"
  189. " DO_(::google::protobuf::internal::WireFormatLite::ReadString(input, &data));\n"
  190. " DO_(entry->ParseFromString(data));\n"
  191. " if ($val_cpp$_IsValid(*entry->mutable_value())) {\n"
  192. " (*mutable_$name$())[entry->key()] =\n"
  193. " static_cast< $val_cpp$ >(*entry->mutable_value());\n"
  194. " } else {\n");
  195. if (HasDescriptorMethods(descriptor_->file(), options_)) {
  196. printer->Print(variables_,
  197. " mutable_unknown_fields()"
  198. "->AddLengthDelimited($number$, data);\n");
  199. } else {
  200. printer->Print(variables_,
  201. " unknown_fields_stream.WriteVarint32($tag$u);\n"
  202. " unknown_fields_stream.WriteVarint32(\n"
  203. " static_cast< ::google::protobuf::uint32>(data.size()));\n"
  204. " unknown_fields_stream.WriteString(data);\n");
  205. }
  206. printer->Print(variables_,
  207. " }\n"
  208. "}\n");
  209. }
  210. if (key_field->type() == FieldDescriptor::TYPE_STRING) {
  211. GenerateUtf8CheckCodeForString(
  212. key_field, options_, true, variables_,
  213. StrCat(key, ".data(), static_cast<int>(", key, ".length()),\n").data(),
  214. printer);
  215. }
  216. if (value_field->type() == FieldDescriptor::TYPE_STRING) {
  217. GenerateUtf8CheckCodeForString(
  218. value_field, options_, true, variables_,
  219. StrCat(value, ".data(), static_cast<int>(", value, ".length()),\n")
  220. .data(),
  221. printer);
  222. }
  223. // If entry is allocated by arena, its desctructor should be avoided.
  224. if (using_entry && SupportsArenas(descriptor_)) {
  225. printer->Print(variables_,
  226. "if (entry->GetArena() != NULL) entry.release();\n");
  227. }
  228. }
  229. static void GenerateSerializationLoop(io::Printer* printer,
  230. const std::map<string, string>& variables,
  231. bool supports_arenas,
  232. const string& utf8_check,
  233. const string& loop_header,
  234. const string& ptr,
  235. bool loop_via_iterators) {
  236. printer->Print(variables,
  237. StrCat("::std::unique_ptr<$map_classname$> entry;\n",
  238. loop_header, " {\n").c_str());
  239. printer->Indent();
  240. printer->Print(variables, StrCat(
  241. "entry.reset($name$_.New$wrapper$(\n"
  242. " ", ptr, "->first, ", ptr, "->second));\n"
  243. "$write_entry$;\n").c_str());
  244. // If entry is allocated by arena, its desctructor should be avoided.
  245. if (supports_arenas) {
  246. printer->Print(
  247. "if (entry->GetArena() != NULL) {\n"
  248. " entry.release();\n"
  249. "}\n");
  250. }
  251. if (!utf8_check.empty()) {
  252. // If loop_via_iterators is true then ptr is actually an iterator, and we
  253. // create a pointer by prefixing it with "&*".
  254. printer->Print(
  255. StrCat(utf8_check, "(", (loop_via_iterators ? "&*" : ""), ptr, ");\n")
  256. .c_str());
  257. }
  258. printer->Outdent();
  259. printer->Print(
  260. "}\n");
  261. }
  262. void MapFieldGenerator::
  263. GenerateSerializeWithCachedSizes(io::Printer* printer) const {
  264. std::map<string, string> variables(variables_);
  265. variables["write_entry"] = "::google::protobuf::internal::WireFormatLite::Write" +
  266. variables["stream_writer"] + "(\n " +
  267. variables["number"] + ", *entry, output)";
  268. variables["deterministic"] = "output->IsSerializationDeterministic()";
  269. GenerateSerializeWithCachedSizes(printer, variables);
  270. }
  271. void MapFieldGenerator::
  272. GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
  273. std::map<string, string> variables(variables_);
  274. variables["write_entry"] =
  275. "target = ::google::protobuf::internal::WireFormatLite::\n"
  276. " InternalWrite" + variables["declared_type"] +
  277. "NoVirtualToArray(\n " + variables["number"] +
  278. ", *entry, deterministic, target);\n";
  279. variables["deterministic"] = "deterministic";
  280. GenerateSerializeWithCachedSizes(printer, variables);
  281. }
  282. void MapFieldGenerator::GenerateSerializeWithCachedSizes(
  283. io::Printer* printer, const std::map<string, string>& variables) const {
  284. printer->Print(variables,
  285. "if (!this->$name$().empty()) {\n");
  286. printer->Indent();
  287. const FieldDescriptor* key_field =
  288. descriptor_->message_type()->FindFieldByName("key");
  289. const FieldDescriptor* value_field =
  290. descriptor_->message_type()->FindFieldByName("value");
  291. const bool string_key = key_field->type() == FieldDescriptor::TYPE_STRING;
  292. const bool string_value = value_field->type() == FieldDescriptor::TYPE_STRING;
  293. printer->Print(variables,
  294. "typedef ::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_pointer\n"
  295. " ConstPtr;\n");
  296. if (string_key) {
  297. printer->Print(variables,
  298. "typedef ConstPtr SortItem;\n"
  299. "typedef ::google::protobuf::internal::"
  300. "CompareByDerefFirst<SortItem> Less;\n");
  301. } else {
  302. printer->Print(variables,
  303. "typedef ::google::protobuf::internal::SortItem< $key_cpp$, ConstPtr > "
  304. "SortItem;\n"
  305. "typedef ::google::protobuf::internal::CompareByFirstField<SortItem> Less;\n");
  306. }
  307. string utf8_check;
  308. if (string_key || string_value) {
  309. printer->Print(
  310. "struct Utf8Check {\n"
  311. " static void Check(ConstPtr p) {\n");
  312. printer->Indent();
  313. printer->Indent();
  314. if (string_key) {
  315. GenerateUtf8CheckCodeForString(
  316. key_field, options_, false, variables,
  317. "p->first.data(), static_cast<int>(p->first.length()),\n", printer);
  318. }
  319. if (string_value) {
  320. GenerateUtf8CheckCodeForString(
  321. value_field, options_, false, variables,
  322. "p->second.data(), static_cast<int>(p->second.length()),\n", printer);
  323. }
  324. printer->Outdent();
  325. printer->Outdent();
  326. printer->Print(
  327. " }\n"
  328. "};\n");
  329. utf8_check = "Utf8Check::Check";
  330. }
  331. printer->Print(variables,
  332. "\n"
  333. "if ($deterministic$ &&\n"
  334. " this->$name$().size() > 1) {\n"
  335. " ::std::unique_ptr<SortItem[]> items(\n"
  336. " new SortItem[this->$name$().size()]);\n"
  337. " typedef ::google::protobuf::Map< $key_cpp$, $val_cpp$ >::size_type size_type;\n"
  338. " size_type n = 0;\n"
  339. " for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
  340. " it = this->$name$().begin();\n"
  341. " it != this->$name$().end(); ++it, ++n) {\n"
  342. " items[static_cast<ptrdiff_t>(n)] = SortItem(&*it);\n"
  343. " }\n"
  344. " ::std::sort(&items[0], &items[static_cast<ptrdiff_t>(n)], Less());\n");
  345. printer->Indent();
  346. GenerateSerializationLoop(printer, variables, SupportsArenas(descriptor_),
  347. utf8_check, "for (size_type i = 0; i < n; i++)",
  348. string_key ? "items[static_cast<ptrdiff_t>(i)]" :
  349. "items[static_cast<ptrdiff_t>(i)].second", false);
  350. printer->Outdent();
  351. printer->Print(
  352. "} else {\n");
  353. printer->Indent();
  354. GenerateSerializationLoop(
  355. printer, variables, SupportsArenas(descriptor_), utf8_check,
  356. "for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
  357. " it = this->$name$().begin();\n"
  358. " it != this->$name$().end(); ++it)",
  359. "it", true);
  360. printer->Outdent();
  361. printer->Print("}\n");
  362. printer->Outdent();
  363. printer->Print("}\n");
  364. }
  365. void MapFieldGenerator::
  366. GenerateByteSize(io::Printer* printer) const {
  367. printer->Print(variables_,
  368. "total_size += $tag_size$ *\n"
  369. " ::google::protobuf::internal::FromIntSize(this->$name$_size());\n"
  370. "{\n"
  371. " ::std::unique_ptr<$map_classname$> entry;\n"
  372. " for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
  373. " it = this->$name$().begin();\n"
  374. " it != this->$name$().end(); ++it) {\n");
  375. // If entry is allocated by arena, its desctructor should be avoided.
  376. if (SupportsArenas(descriptor_)) {
  377. printer->Print(variables_,
  378. " if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
  379. " entry.release();\n"
  380. " }\n");
  381. }
  382. printer->Print(variables_,
  383. " entry.reset($name$_.New$wrapper$(it->first, it->second));\n"
  384. " total_size += ::google::protobuf::internal::WireFormatLite::\n"
  385. " $declared_type$SizeNoVirtual(*entry);\n"
  386. " }\n");
  387. // If entry is allocated by arena, its desctructor should be avoided.
  388. if (SupportsArenas(descriptor_)) {
  389. printer->Print(variables_,
  390. " if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
  391. " entry.release();\n"
  392. " }\n");
  393. }
  394. printer->Print("}\n");
  395. }
  396. } // namespace cpp
  397. } // namespace compiler
  398. } // namespace protobuf
  399. } // namespace google