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
43 namespace google {
44 namespace protobuf {
45 namespace compiler {
46 namespace cpp {
47
EnumGenerator(const EnumDescriptor * descriptor,const string & dllexport_decl)48 EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor,
49 const string& dllexport_decl)
50 : descriptor_(descriptor),
51 classname_(ClassName(descriptor, false)),
52 dllexport_decl_(dllexport_decl) {
53 }
54
~EnumGenerator()55 EnumGenerator::~EnumGenerator() {}
56
GenerateDefinition(io::Printer * printer)57 void 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 "const int $prefix$$short_name$_ARRAYSIZE = $prefix$$short_name$_MAX + 1;\n"
102 "\n");
103
104 if (HasDescriptorMethods(descriptor_->file())) {
105 printer->Print(vars,
106 "$dllexport$const ::google::protobuf::EnumDescriptor* $classname$_descriptor();\n");
107 // The _Name and _Parse methods
108 printer->Print(vars,
109 "inline const ::std::string& $classname$_Name($classname$ value) {\n"
110 " return ::google::protobuf::internal::NameOfEnum(\n"
111 " $classname$_descriptor(), value);\n"
112 "}\n");
113 printer->Print(vars,
114 "inline bool $classname$_Parse(\n"
115 " const ::std::string& name, $classname$* value) {\n"
116 " return ::google::protobuf::internal::ParseNamedEnum<$classname$>(\n"
117 " $classname$_descriptor(), name, value);\n"
118 "}\n");
119 }
120 }
121
122 void EnumGenerator::
GenerateGetEnumDescriptorSpecializations(io::Printer * printer)123 GenerateGetEnumDescriptorSpecializations(io::Printer* printer) {
124 if (HasDescriptorMethods(descriptor_->file())) {
125 printer->Print(
126 "template <>\n"
127 "inline const EnumDescriptor* GetEnumDescriptor< $classname$>() {\n"
128 " return $classname$_descriptor();\n"
129 "}\n",
130 "classname", ClassName(descriptor_, true));
131 }
132 }
133
GenerateSymbolImports(io::Printer * printer)134 void EnumGenerator::GenerateSymbolImports(io::Printer* printer) {
135 map<string, string> vars;
136 vars["nested_name"] = descriptor_->name();
137 vars["classname"] = classname_;
138 printer->Print(vars, "typedef $classname$ $nested_name$;\n");
139
140 for (int j = 0; j < descriptor_->value_count(); j++) {
141 vars["tag"] = descriptor_->value(j)->name();
142 printer->Print(vars,
143 "static const $nested_name$ $tag$ = $classname$_$tag$;\n");
144 }
145
146 printer->Print(vars,
147 "static inline bool $nested_name$_IsValid(int value) {\n"
148 " return $classname$_IsValid(value);\n"
149 "}\n"
150 "static const $nested_name$ $nested_name$_MIN =\n"
151 " $classname$_$nested_name$_MIN;\n"
152 "static const $nested_name$ $nested_name$_MAX =\n"
153 " $classname$_$nested_name$_MAX;\n"
154 "static const int $nested_name$_ARRAYSIZE =\n"
155 " $classname$_$nested_name$_ARRAYSIZE;\n");
156
157 if (HasDescriptorMethods(descriptor_->file())) {
158 printer->Print(vars,
159 "static inline const ::google::protobuf::EnumDescriptor*\n"
160 "$nested_name$_descriptor() {\n"
161 " return $classname$_descriptor();\n"
162 "}\n");
163 printer->Print(vars,
164 "static inline const ::std::string& $nested_name$_Name($nested_name$ value) {\n"
165 " return $classname$_Name(value);\n"
166 "}\n");
167 printer->Print(vars,
168 "static inline bool $nested_name$_Parse(const ::std::string& name,\n"
169 " $nested_name$* value) {\n"
170 " return $classname$_Parse(name, value);\n"
171 "}\n");
172 }
173 }
174
GenerateDescriptorInitializer(io::Printer * printer,int index)175 void EnumGenerator::GenerateDescriptorInitializer(
176 io::Printer* printer, int index) {
177 map<string, string> vars;
178 vars["classname"] = classname_;
179 vars["index"] = SimpleItoa(index);
180
181 if (descriptor_->containing_type() == NULL) {
182 printer->Print(vars,
183 "$classname$_descriptor_ = file->enum_type($index$);\n");
184 } else {
185 vars["parent"] = ClassName(descriptor_->containing_type(), false);
186 printer->Print(vars,
187 "$classname$_descriptor_ = $parent$_descriptor_->enum_type($index$);\n");
188 }
189 }
190
GenerateMethods(io::Printer * printer)191 void EnumGenerator::GenerateMethods(io::Printer* printer) {
192 map<string, string> vars;
193 vars["classname"] = classname_;
194
195 if (HasDescriptorMethods(descriptor_->file())) {
196 printer->Print(vars,
197 "const ::google::protobuf::EnumDescriptor* $classname$_descriptor() {\n"
198 " protobuf_AssignDescriptorsOnce();\n"
199 " return $classname$_descriptor_;\n"
200 "}\n");
201 }
202
203 printer->Print(vars,
204 "bool $classname$_IsValid(int value) {\n"
205 " switch(value) {\n");
206
207 // Multiple values may have the same number. Make sure we only cover
208 // each number once by first constructing a set containing all valid
209 // numbers, then printing a case statement for each element.
210
211 set<int> numbers;
212 for (int j = 0; j < descriptor_->value_count(); j++) {
213 const EnumValueDescriptor* value = descriptor_->value(j);
214 numbers.insert(value->number());
215 }
216
217 for (set<int>::iterator iter = numbers.begin();
218 iter != numbers.end(); ++iter) {
219 printer->Print(
220 " case $number$:\n",
221 "number", SimpleItoa(*iter));
222 }
223
224 printer->Print(vars,
225 " return true;\n"
226 " default:\n"
227 " return false;\n"
228 " }\n"
229 "}\n"
230 "\n");
231
232 if (descriptor_->containing_type() != NULL) {
233 // We need to "define" the static constants which were declared in the
234 // header, to give the linker a place to put them. Or at least the C++
235 // standard says we have to. MSVC actually insists tha we do _not_ define
236 // them again in the .cc file.
237 printer->Print("#ifndef _MSC_VER\n");
238
239 vars["parent"] = ClassName(descriptor_->containing_type(), false);
240 vars["nested_name"] = descriptor_->name();
241 for (int i = 0; i < descriptor_->value_count(); i++) {
242 vars["value"] = descriptor_->value(i)->name();
243 printer->Print(vars,
244 "const $classname$ $parent$::$value$;\n");
245 }
246 printer->Print(vars,
247 "const $classname$ $parent$::$nested_name$_MIN;\n"
248 "const $classname$ $parent$::$nested_name$_MAX;\n"
249 "const int $parent$::$nested_name$_ARRAYSIZE;\n");
250
251 printer->Print("#endif // _MSC_VER\n");
252 }
253 }
254
255 } // namespace cpp
256 } // namespace compiler
257 } // namespace protobuf
258 } // namespace google
259