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 "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 122void EnumGenerator:: 123GenerateGetEnumDescriptorSpecializations(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 134void 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 175void 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 191void 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