cpp_enum.cc
Go to the documentation of this file.
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 
31 // Author: kenton@google.com (Kenton Varda)
32 // Based on original Protocol Buffers design by
33 // Sanjay Ghemawat, Jeff Dean, and others.
34 
35 #include <map>
36 
41 
42 namespace google {
43 namespace protobuf {
44 namespace compiler {
45 namespace cpp {
46 
47 namespace {
48 // The GOOGLE_ARRAYSIZE constant is the max enum value plus 1. If the max enum value
49 // is kint32max, GOOGLE_ARRAYSIZE will overflow. In such cases we should omit the
50 // generation of the GOOGLE_ARRAYSIZE constant.
51 bool ShouldGenerateArraySize(const EnumDescriptor* descriptor) {
52  int32 max_value = descriptor->value(0)->number();
53  for (int i = 0; i < descriptor->value_count(); i++) {
54  if (descriptor->value(i)->number() > max_value) {
55  max_value = descriptor->value(i)->number();
56  }
57  }
58  return max_value != kint32max;
59 }
60 
61 // Returns the number of unique numeric enum values. This is less than
62 // descriptor->value_count() when there are aliased values.
63 int CountUniqueValues(const EnumDescriptor* descriptor) {
64  std::set<int> values;
65  for (int i = 0; i < descriptor->value_count(); ++i) {
66  values.insert(descriptor->value(i)->number());
67  }
68  return values.size();
69 }
70 
71 } // namespace
72 
74  const std::map<std::string, std::string>& vars,
75  const Options& options)
77  classname_(ClassName(descriptor, false)),
79  generate_array_size_(ShouldGenerateArraySize(descriptor)),
80  variables_(vars) {
81  variables_["classname"] = classname_;
83  variables_["short_name"] = descriptor_->name();
84  variables_["nested_name"] = descriptor_->name();
85  variables_["resolved_name"] = ResolveKeyword(descriptor_->name());
86  variables_["prefix"] =
87  (descriptor_->containing_type() == NULL) ? "" : classname_ + "_";
88 }
89 
91 
93  Formatter format(printer, variables_);
94  format("enum ${1$$classname$$}$ : int {\n", descriptor_);
95  format.Indent();
96 
97  const EnumValueDescriptor* min_value = descriptor_->value(0);
98  const EnumValueDescriptor* max_value = descriptor_->value(0);
99 
100  for (int i = 0; i < descriptor_->value_count(); i++) {
101  auto format_value = format;
102  format_value.Set("name", EnumValueName(descriptor_->value(i)));
103  // In C++, an value of -2147483648 gets interpreted as the negative of
104  // 2147483648, and since 2147483648 can't fit in an integer, this produces a
105  // compiler warning. This works around that issue.
106  format_value.Set("number", Int32ToString(descriptor_->value(i)->number()));
107  format_value.Set(
108  "deprecation",
111 
112  if (i > 0) format_value(",\n");
113  format_value("${1$$prefix$$name$$}$ $deprecation$= $number$",
114  descriptor_->value(i));
115 
116  if (descriptor_->value(i)->number() < min_value->number()) {
117  min_value = descriptor_->value(i);
118  }
119  if (descriptor_->value(i)->number() > max_value->number()) {
120  max_value = descriptor_->value(i);
121  }
122  }
123 
125  // For new enum semantics: generate min and max sentinel values equal to
126  // INT32_MIN and INT32_MAX
127  if (descriptor_->value_count() > 0) format(",\n");
128  format(
129  "$classname$_$prefix$INT_MIN_SENTINEL_DO_NOT_USE_ = "
130  "std::numeric_limits<$int32$>::min(),\n"
131  "$classname$_$prefix$INT_MAX_SENTINEL_DO_NOT_USE_ = "
132  "std::numeric_limits<$int32$>::max()");
133  }
134 
135  format.Outdent();
136  format("\n};\n");
137 
138  format(
139  "$dllexport_decl $bool $classname$_IsValid(int value);\n"
140  "constexpr $classname$ ${1$$prefix$$short_name$_MIN$}$ = "
141  "$prefix$$2$;\n"
142  "constexpr $classname$ ${1$$prefix$$short_name$_MAX$}$ = "
143  "$prefix$$3$;\n",
144  descriptor_, EnumValueName(min_value), EnumValueName(max_value));
145 
146  if (generate_array_size_) {
147  format(
148  "constexpr int ${1$$prefix$$short_name$_ARRAYSIZE$}$ = "
149  "$prefix$$short_name$_MAX + 1;\n\n",
150  descriptor_);
151  }
152 
154  format(
155  "$dllexport_decl $const ::$proto_ns$::EnumDescriptor* "
156  "$classname$_descriptor();\n");
157  }
158 
159  // The _Name and _Parse functions. The lite implementation is table-based, so
160  // we make sure to keep the tables hidden in the .cc file.
162  format("const std::string& $classname$_Name($classname$ value);\n");
163  }
164  // The _Name() function accepts the enum type itself but also any integral
165  // type.
166  format(
167  "template<typename T>\n"
168  "inline const std::string& $classname$_Name(T enum_t_value) {\n"
169  " static_assert(::std::is_same<T, $classname$>::value ||\n"
170  " ::std::is_integral<T>::value,\n"
171  " \"Incorrect type passed to function $classname$_Name.\");\n");
173  format(
174  " return ::$proto_ns$::internal::NameOfEnum(\n"
175  " $classname$_descriptor(), enum_t_value);\n");
176  } else {
177  format(
178  " return $classname$_Name(static_cast<$classname$>(enum_t_value));\n");
179  }
180  format("}\n");
181 
183  format(
184  "inline bool $classname$_Parse(\n"
185  " const std::string& name, $classname$* value) {\n"
186  " return ::$proto_ns$::internal::ParseNamedEnum<$classname$>(\n"
187  " $classname$_descriptor(), name, value);\n"
188  "}\n");
189  } else {
190  format(
191  "bool $classname$_Parse(\n"
192  " const std::string& name, $classname$* value);\n");
193  }
194 }
195 
197  io::Printer* printer) {
198  Formatter format(printer, variables_);
199  format(
200  "template <> struct is_proto_enum< $classtype$> : ::std::true_type "
201  "{};\n");
203  format(
204  "template <>\n"
205  "inline const EnumDescriptor* GetEnumDescriptor< $classtype$>() {\n"
206  " return $classtype$_descriptor();\n"
207  "}\n");
208  }
209 }
210 
212  Formatter format(printer, variables_);
213  format("typedef $classname$ $resolved_name$;\n");
214 
215  for (int j = 0; j < descriptor_->value_count(); j++) {
216  std::string deprecated_attr = DeprecatedAttribute(
218  format(
219  "$1$static constexpr $resolved_name$ ${2$$3$$}$ =\n"
220  " $classname$_$3$;\n",
221  deprecated_attr, descriptor_->value(j),
223  }
224 
225  format(
226  "static inline bool $nested_name$_IsValid(int value) {\n"
227  " return $classname$_IsValid(value);\n"
228  "}\n"
229  "static constexpr $resolved_name$ ${1$$nested_name$_MIN$}$ =\n"
230  " $classname$_$nested_name$_MIN;\n"
231  "static constexpr $resolved_name$ ${1$$nested_name$_MAX$}$ =\n"
232  " $classname$_$nested_name$_MAX;\n",
233  descriptor_);
234  if (generate_array_size_) {
235  format(
236  "static constexpr int ${1$$nested_name$_ARRAYSIZE$}$ =\n"
237  " $classname$_$nested_name$_ARRAYSIZE;\n",
238  descriptor_);
239  }
240 
242  format(
243  "static inline const ::$proto_ns$::EnumDescriptor*\n"
244  "$nested_name$_descriptor() {\n"
245  " return $classname$_descriptor();\n"
246  "}\n");
247  }
248 
249  format(
250  "template<typename T>\n"
251  "static inline const std::string& $nested_name$_Name(T enum_t_value) {\n"
252  " static_assert(::std::is_same<T, $resolved_name$>::value ||\n"
253  " ::std::is_integral<T>::value,\n"
254  " \"Incorrect type passed to function $nested_name$_Name.\");\n"
255  " return $classname$_Name(enum_t_value);\n"
256  "}\n");
257  format(
258  "static inline bool $nested_name$_Parse(const std::string& name,\n"
259  " $resolved_name$* value) {\n"
260  " return $classname$_Parse(name, value);\n"
261  "}\n");
262 }
263 
265  Formatter format(printer, variables_);
267  format(
268  "const ::$proto_ns$::EnumDescriptor* $classname$_descriptor() {\n"
269  " ::$proto_ns$::internal::AssignDescriptors(&$desc_table$);\n"
270  " return $file_level_enum_descriptors$[$1$];\n"
271  "}\n",
272  idx);
273  }
274 
275  format(
276  "bool $classname$_IsValid(int value) {\n"
277  " switch (value) {\n");
278 
279  // Multiple values may have the same number. Make sure we only cover
280  // each number once by first constructing a set containing all valid
281  // numbers, then printing a case statement for each element.
282 
283  std::set<int> numbers;
284  for (int j = 0; j < descriptor_->value_count(); j++) {
286  numbers.insert(value->number());
287  }
288 
289  for (std::set<int>::iterator iter = numbers.begin(); iter != numbers.end();
290  ++iter) {
291  format(" case $1$:\n", Int32ToString(*iter));
292  }
293 
294  format(
295  " return true;\n"
296  " default:\n"
297  " return false;\n"
298  " }\n"
299  "}\n"
300  "\n");
301 
303  // In lite mode (where descriptors are unavailable), we generate separate
304  // tables for mapping between enum names and numbers. The _entries table
305  // contains the bulk of the data and is sorted by name, while
306  // _entries_by_number is sorted by number and just contains pointers into
307  // _entries. The two tables allow mapping from name to number and number to
308  // name, both in time logarithmic in the number of enum entries. This could
309  // probably be made faster, but for now the tables are intended to be simple
310  // and compact.
311  //
312  // Enums with allow_alias = true support multiple entries with the same
313  // numerical value. In cases where there are multiple names for the same
314  // number, we treat the first name appearing in the .proto file as the
315  // canonical one.
316  std::map<std::string, int> name_to_number;
317  std::map<int, std::string> number_to_canonical_name;
318  for (int i = 0; i < descriptor_->value_count(); i++) {
320  name_to_number.emplace(value->name(), value->number());
321  // The same number may appear with multiple names, so we use emplace() to
322  // let the first name win.
323  number_to_canonical_name.emplace(value->number(), value->name());
324  }
325 
326  format(
327  "static ::$proto_ns$::internal::ExplicitlyConstructed<std::string> "
328  "$classname$_strings[$1$] = {};\n\n",
329  CountUniqueValues(descriptor_));
330 
331  // We concatenate all the names for a given enum into one big string
332  // literal. If instead we store an array of string literals, the linker
333  // seems to put all enum strings for a given .proto file in the same
334  // section, which hinders its ability to strip out unused strings.
335  format("static const char $classname$_names[] =");
336  for (const auto& p : name_to_number) {
337  format("\n \"$1$\"", p.first);
338  }
339  format(";\n\n");
340 
341  format(
342  "static const ::$proto_ns$::internal::EnumEntry $classname$_entries[] "
343  "= {\n");
344  int i = 0;
345  std::map<int, int> number_to_index;
346  int data_index = 0;
347  for (const auto& p : name_to_number) {
348  format(" { {$classname$_names + $1$, $2$}, $3$ },\n", data_index,
349  p.first.size(), p.second);
350  if (number_to_canonical_name[p.second] == p.first) {
351  number_to_index.emplace(p.second, i);
352  }
353  ++i;
354  data_index += p.first.size();
355  }
356 
357  format(
358  "};\n"
359  "\n"
360  "static const int $classname$_entries_by_number[] = {\n");
361  for (const auto& p : number_to_index) {
362  format(" $1$, // $2$ -> $3$\n", p.second, p.first,
363  number_to_canonical_name[p.first]);
364  }
365  format(
366  "};\n"
367  "\n");
368 
369  format(
370  "const std::string& $classname$_Name(\n"
371  " $classname$ value) {\n"
372  " static const bool dummy =\n"
373  " ::$proto_ns$::internal::InitializeEnumStrings(\n"
374  " $classname$_entries,\n"
375  " $classname$_entries_by_number,\n"
376  " $1$, $classname$_strings);\n"
377  " (void) dummy;\n"
378  " int idx = ::$proto_ns$::internal::LookUpEnumName(\n"
379  " $classname$_entries,\n"
380  " $classname$_entries_by_number,\n"
381  " $1$, value);\n"
382  " return idx == -1 ? ::$proto_ns$::internal::GetEmptyString() :\n"
383  " $classname$_strings[idx].get();\n"
384  "}\n",
385  CountUniqueValues(descriptor_));
386  format(
387  "bool $classname$_Parse(\n"
388  " const std::string& name, $classname$* value) {\n"
389  " int int_value;\n"
390  " bool success = ::$proto_ns$::internal::LookUpEnumValue(\n"
391  " $classname$_entries, $1$, name, &int_value);\n"
392  " if (success) {\n"
393  " *value = static_cast<$classname$>(int_value);\n"
394  " }\n"
395  " return success;\n"
396  "}\n",
398  }
399 
400  if (descriptor_->containing_type() != NULL) {
401  std::string parent = ClassName(descriptor_->containing_type(), false);
402  // Before C++17, we must define the static constants which were
403  // declared in the header, to give the linker a place to put them.
404  // But pre-2015 MSVC++ insists that we not.
405  format(
406  "#if (__cplusplus < 201703) && "
407  "(!defined(_MSC_VER) || _MSC_VER >= 1900)\n");
408 
409  for (int i = 0; i < descriptor_->value_count(); i++) {
410  format("constexpr $classname$ $1$::$2$;\n", parent,
412  }
413  format(
414  "constexpr $classname$ $1$::$nested_name$_MIN;\n"
415  "constexpr $classname$ $1$::$nested_name$_MAX;\n",
416  parent);
417  if (generate_array_size_) {
418  format("constexpr int $1$::$nested_name$_ARRAYSIZE;\n", parent);
419  }
420 
421  format(
422  "#endif // (__cplusplus < 201703) && "
423  "(!defined(_MSC_VER) || _MSC_VER >= 1900)\n");
424  }
425 }
426 
427 } // namespace cpp
428 } // namespace compiler
429 } // namespace protobuf
430 } // namespace google
google::protobuf::compiler::cpp::EnumGenerator::options_
const Options & options_
Definition: cpp_enum.h:90
google::protobuf::EnumValueDescriptor::options
const EnumValueOptions & options() const
NULL
NULL
Definition: test_security_zap.cpp:405
google::protobuf::compiler::cpp::EnumGenerator::GenerateMethods
void GenerateMethods(int idx, io::Printer *printer)
Definition: cpp_enum.cc:264
options
Message * options
Definition: src/google/protobuf/descriptor.cc:3119
google::protobuf::EnumDescriptor::value_count
int value_count() const
google::protobuf::compiler::cpp::QualifiedClassName
std::string QualifiedClassName(const Descriptor *d, const Options &options)
Definition: cpp_helpers.cc:319
google::protobuf::compiler::cpp::EnumGenerator::EnumGenerator
EnumGenerator(const EnumDescriptor *descriptor, const std::map< std::string, std::string > &vars, const Options &options)
Definition: cpp_enum.cc:73
string
GLsizei const GLchar *const * string
Definition: glcorearb.h:3083
google::protobuf::compiler::cpp::EnumGenerator::GenerateDefinition
void GenerateDefinition(io::Printer *printer)
Definition: cpp_enum.cc:92
descriptor
Descriptor * descriptor
Definition: php/ext/google/protobuf/protobuf.h:936
google::protobuf::compiler::cpp::EnumValueName
std::string EnumValueName(const EnumValueDescriptor *enum_value)
Definition: cpp_helpers.cc:419
google::protobuf::compiler::cpp::EnumGenerator::classname_
const std::string classname_
Definition: cpp_enum.h:89
idx
static uint32_t idx(tarjan *t, const upb_refcounted *r)
Definition: ruby/ext/google/protobuf_c/upb.c:5925
google::protobuf::FileDescriptor::syntax
Syntax syntax() const
Definition: src/google/protobuf/descriptor.h:2175
cpp_helpers.h
values
GLenum GLsizei GLsizei GLint * values
Definition: glcorearb.h:3591
google::protobuf::int32
int32_t int32
Definition: protobuf/src/google/protobuf/stubs/port.h:150
google::protobuf::EnumDescriptor::name
const std::string & name() const
strutil.h
google::protobuf::compiler::cpp::EnumGenerator::GenerateSymbolImports
void GenerateSymbolImports(io::Printer *printer) const
Definition: cpp_enum.cc:211
format
GLint GLint GLsizei GLint GLenum format
Definition: glcorearb.h:2773
google::protobuf::EnumDescriptor::file
const FileDescriptor * file() const
google::protobuf::compiler::cpp::ResolveKeyword
std::string ResolveKeyword(const string &name)
Definition: cpp_helpers.cc:403
google::protobuf::EnumValueDescriptor::number
int number() const
google::protobuf::EnumDescriptor::value
const EnumValueDescriptor * value(int index) const
printer.h
p
const char * p
Definition: gmock-matchers_test.cc:3863
google::protobuf::compiler::cpp::DeprecatedAttribute
std::string DeprecatedAttribute(const Options &options, bool deprecated)
Definition: cpp_helpers.h:68
cpp
Definition: third_party/googletest/googlemock/scripts/generator/cpp/__init__.py:1
google::protobuf::compiler::cpp::Options
Definition: cpp_options.h:52
EnumDescriptor
Definition: ruby/ext/google/protobuf_c/protobuf.h:137
google::protobuf::FileDescriptor::SYNTAX_PROTO3
@ SYNTAX_PROTO3
Definition: src/google/protobuf/descriptor.h:1394
google::protobuf::compiler::cpp::HasDescriptorMethods
bool HasDescriptorMethods(const FileDescriptor *file, const Options &options)
Definition: cpp_helpers.h:365
google::protobuf::compiler::cpp::EnumGenerator::GenerateGetEnumDescriptorSpecializations
void GenerateGetEnumDescriptorSpecializations(io::Printer *printer)
Definition: cpp_enum.cc:196
google::protobuf::io::Printer
Definition: printer.h:181
i
int i
Definition: gmock-matchers_test.cc:764
cpp_enum.h
google::protobuf::compiler::cpp::Int32ToString
std::string Int32ToString(int number)
Definition: cpp_helpers.cc:593
EnumValueOptions::deprecated
bool deprecated() const
Definition: descriptor.pb.h:10814
google::protobuf::kint32max
static const int32 kint32max
Definition: protobuf/src/google/protobuf/stubs/port.h:159
google::protobuf::EnumDescriptor::containing_type
const Descriptor * containing_type() const
google::protobuf::compiler::cpp::EnumGenerator::variables_
std::map< std::string, std::string > variables_
Definition: cpp_enum.h:94
google::protobuf::compiler::cpp::EnumGenerator::generate_array_size_
const bool generate_array_size_
Definition: cpp_enum.h:92
google::protobuf::compiler::cpp::EnumGenerator::~EnumGenerator
~EnumGenerator()
Definition: cpp_enum.cc:90
google::protobuf::EnumValueDescriptor
Definition: src/google/protobuf/descriptor.h:1075
google::protobuf::compiler::cpp::ClassName
std::string ClassName(const Descriptor *descriptor)
Definition: cpp_helpers.cc:301
google::protobuf::compiler::cpp::EnumGenerator::descriptor_
const EnumDescriptor * descriptor_
Definition: cpp_enum.h:88
value
GLsizei const GLfloat * value
Definition: glcorearb.h:3093
descriptor_
const Descriptor * descriptor_
Definition: field_comparator_test.cc:56
google::protobuf::EnumDescriptor
Definition: src/google/protobuf/descriptor.h:918
false
#define false
Definition: cJSON.c:70
variables_
std::map< std::string, std::string > variables_
Definition: cpp_message.cc:520
compiler
Definition: plugin.pb.cc:22
google
Definition: data_proto2_to_proto3_util.h:11
google::protobuf::compiler::cpp::Formatter
Definition: cpp_helpers.h:637
options_
DebugStringOptions options_
Definition: src/google/protobuf/descriptor.cc:2410


libaditof
Author(s):
autogenerated on Wed May 21 2025 02:06:48