Home | History | Annotate | Download | only in cpp
      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 (at) 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 
     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 
     55 EnumGenerator::~EnumGenerator() {}
     56 
     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::
    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 
    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 
    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 
    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