cpp_enum.cc revision fbaaef999ba563838ebd00874ed8a1c01fbf286d
1// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc.  All rights reserved.
3// http://code.google.com/p/protobuf/
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 <set>
36#include <map>
37
38#include <google/protobuf/compiler/cpp/cpp_enum.h>
39#include <google/protobuf/compiler/cpp/cpp_helpers.h>
40#include <google/protobuf/io/printer.h>
41#include <google/protobuf/stubs/strutil.h>
42
43namespace google {
44namespace protobuf {
45namespace compiler {
46namespace cpp {
47
48EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor,
49                             const string& dllexport_decl)
50  : descriptor_(descriptor),
51    classname_(ClassName(descriptor, false)),
52    dllexport_decl_(dllexport_decl) {
53}
54
55EnumGenerator::~EnumGenerator() {}
56
57void EnumGenerator::GenerateDefinition(io::Printer* printer) {
58  map<string, string> vars;
59  vars["classname"] = classname_;
60  vars["short_name"] = descriptor_->name();
61
62  printer->Print(vars, "enum $classname$ {\n");
63  printer->Indent();
64
65  const EnumValueDescriptor* min_value = descriptor_->value(0);
66  const EnumValueDescriptor* max_value = descriptor_->value(0);
67
68  for (int i = 0; i < descriptor_->value_count(); i++) {
69    vars["name"] = descriptor_->value(i)->name();
70    vars["number"] = SimpleItoa(descriptor_->value(i)->number());
71    vars["prefix"] = (descriptor_->containing_type() == NULL) ?
72      "" : classname_ + "_";
73
74    if (i > 0) printer->Print(",\n");
75    printer->Print(vars, "$prefix$$name$ = $number$");
76
77    if (descriptor_->value(i)->number() < min_value->number()) {
78      min_value = descriptor_->value(i);
79    }
80    if (descriptor_->value(i)->number() > max_value->number()) {
81      max_value = descriptor_->value(i);
82    }
83  }
84
85  printer->Outdent();
86  printer->Print("\n};\n");
87
88  vars["min_name"] = min_value->name();
89  vars["max_name"] = max_value->name();
90
91  if (dllexport_decl_.empty()) {
92    vars["dllexport"] = "";
93  } else {
94    vars["dllexport"] = dllexport_decl_ + " ";
95  }
96
97  printer->Print(vars,
98    "$dllexport$bool $classname$_IsValid(int value);\n"
99    "const $classname$ $prefix$$short_name$_MIN = $prefix$$min_name$;\n"
100    "const $classname$ $prefix$$short_name$_MAX = $prefix$$max_name$;\n"
101    "\n");
102
103  if (HasDescriptorMethods(descriptor_->file())) {
104    printer->Print(vars,
105      "$dllexport$const ::google::protobuf::EnumDescriptor* $classname$_descriptor();\n");
106    // The _Name and _Parse methods
107    printer->Print(vars,
108      "inline const ::std::string& $classname$_Name($classname$ value) {\n"
109      "  return ::google::protobuf::internal::NameOfEnum(\n"
110      "    $classname$_descriptor(), value);\n"
111      "}\n");
112    printer->Print(vars,
113      "inline bool $classname$_Parse(\n"
114      "    const ::std::string& name, $classname$* value) {\n"
115      "  return ::google::protobuf::internal::ParseNamedEnum<$classname$>(\n"
116      "    $classname$_descriptor(), name, value);\n"
117      "}\n");
118  }
119}
120
121void EnumGenerator::
122GenerateGetEnumDescriptorSpecializations(io::Printer* printer) {
123  if (HasDescriptorMethods(descriptor_->file())) {
124    printer->Print(
125      "template <>\n"
126      "inline const EnumDescriptor* GetEnumDescriptor< $classname$>() {\n"
127      "  return $classname$_descriptor();\n"
128      "}\n",
129      "classname", ClassName(descriptor_, true));
130  }
131}
132
133void EnumGenerator::GenerateSymbolImports(io::Printer* printer) {
134  map<string, string> vars;
135  vars["nested_name"] = descriptor_->name();
136  vars["classname"] = classname_;
137  printer->Print(vars, "typedef $classname$ $nested_name$;\n");
138
139  for (int j = 0; j < descriptor_->value_count(); j++) {
140    vars["tag"] = descriptor_->value(j)->name();
141    printer->Print(vars,
142      "static const $nested_name$ $tag$ = $classname$_$tag$;\n");
143  }
144
145  printer->Print(vars,
146    "static inline bool $nested_name$_IsValid(int value) {\n"
147    "  return $classname$_IsValid(value);\n"
148    "}\n"
149    "static const $nested_name$ $nested_name$_MIN =\n"
150    "  $classname$_$nested_name$_MIN;\n"
151    "static const $nested_name$ $nested_name$_MAX =\n"
152    "  $classname$_$nested_name$_MAX;\n");
153
154  if (HasDescriptorMethods(descriptor_->file())) {
155    printer->Print(vars,
156      "static inline const ::google::protobuf::EnumDescriptor*\n"
157      "$nested_name$_descriptor() {\n"
158      "  return $classname$_descriptor();\n"
159      "}\n"
160      "static inline const ::std::string& $nested_name$_Name($nested_name$ value) {\n"
161      "  return $classname$_Name(value);\n"
162      "}\n"
163      "static inline bool $nested_name$_Parse(const ::std::string& name,\n"
164      "    $nested_name$* value) {\n"
165      "  return $classname$_Parse(name, value);\n"
166      "}\n");
167  }
168}
169
170void EnumGenerator::GenerateDescriptorInitializer(
171    io::Printer* printer, int index) {
172  map<string, string> vars;
173  vars["classname"] = classname_;
174  vars["index"] = SimpleItoa(index);
175
176  if (descriptor_->containing_type() == NULL) {
177    printer->Print(vars,
178      "$classname$_descriptor_ = file->enum_type($index$);\n");
179  } else {
180    vars["parent"] = ClassName(descriptor_->containing_type(), false);
181    printer->Print(vars,
182      "$classname$_descriptor_ = $parent$_descriptor_->enum_type($index$);\n");
183  }
184}
185
186void EnumGenerator::GenerateMethods(io::Printer* printer) {
187  map<string, string> vars;
188  vars["classname"] = classname_;
189
190  if (HasDescriptorMethods(descriptor_->file())) {
191    printer->Print(vars,
192      "const ::google::protobuf::EnumDescriptor* $classname$_descriptor() {\n"
193      "  protobuf_AssignDescriptorsOnce();\n"
194      "  return $classname$_descriptor_;\n"
195      "}\n");
196  }
197
198  printer->Print(vars,
199    "bool $classname$_IsValid(int value) {\n"
200    "  switch(value) {\n");
201
202  // Multiple values may have the same number.  Make sure we only cover
203  // each number once by first constructing a set containing all valid
204  // numbers, then printing a case statement for each element.
205
206  set<int> numbers;
207  for (int j = 0; j < descriptor_->value_count(); j++) {
208    const EnumValueDescriptor* value = descriptor_->value(j);
209    numbers.insert(value->number());
210  }
211
212  for (set<int>::iterator iter = numbers.begin();
213       iter != numbers.end(); ++iter) {
214    printer->Print(
215      "    case $number$:\n",
216      "number", SimpleItoa(*iter));
217  }
218
219  printer->Print(vars,
220    "      return true;\n"
221    "    default:\n"
222    "      return false;\n"
223    "  }\n"
224    "}\n"
225    "\n");
226
227  if (descriptor_->containing_type() != NULL) {
228    // We need to "define" the static constants which were declared in the
229    // header, to give the linker a place to put them.  Or at least the C++
230    // standard says we have to.  MSVC actually insists tha we do _not_ define
231    // them again in the .cc file.
232    printer->Print("#ifndef _MSC_VER\n");
233
234    vars["parent"] = ClassName(descriptor_->containing_type(), false);
235    vars["nested_name"] = descriptor_->name();
236    for (int i = 0; i < descriptor_->value_count(); i++) {
237      vars["value"] = descriptor_->value(i)->name();
238      printer->Print(vars,
239        "const $classname$ $parent$::$value$;\n");
240    }
241    printer->Print(vars,
242      "const $classname$ $parent$::$nested_name$_MIN;\n"
243      "const $classname$ $parent$::$nested_name$_MAX;\n");
244
245    printer->Print("#endif  // _MSC_VER\n");
246  }
247}
248
249}  // namespace cpp
250}  // namespace compiler
251}  // namespace protobuf
252}  // namespace google
253