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