1fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// Protocol Buffers - Google's data interchange format
2fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// Copyright 2008 Google Inc.  All rights reserved.
3afb4b72037e3f13db208590fc782c4bc8e27f862Jeff Davidson// https://developers.google.com/protocol-buffers/
4fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//
5fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// Redistribution and use in source and binary forms, with or without
6fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// modification, are permitted provided that the following conditions are
7fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// met:
8fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//
9fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//     * Redistributions of source code must retain the above copyright
10fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// notice, this list of conditions and the following disclaimer.
11fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//     * Redistributions in binary form must reproduce the above
12fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// copyright notice, this list of conditions and the following disclaimer
13fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// in the documentation and/or other materials provided with the
14fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// distribution.
15fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//     * Neither the name of Google Inc. nor the names of its
16fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// contributors may be used to endorse or promote products derived from
17fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// this software without specific prior written permission.
18fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//
19fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
31fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// Author: kenton@google.com (Kenton Varda)
32fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//  Based on original Protocol Buffers design by
33fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//  Sanjay Ghemawat, Jeff Dean, and others.
34fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
35fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#include <map>
36fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
37fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#include <google/protobuf/compiler/cpp/cpp_enum.h>
38fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#include <google/protobuf/compiler/cpp/cpp_helpers.h>
39fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#include <google/protobuf/io/printer.h>
40fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#include <google/protobuf/stubs/strutil.h>
41fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
42fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillenamespace google {
43fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillenamespace protobuf {
44fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillenamespace compiler {
45fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillenamespace cpp {
46fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
47a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonnamespace {
48a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// The GOOGLE_ARRAYSIZE constant is the max enum value plus 1. If the max enum value
49b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// is ::google::protobuf::kint32max, GOOGLE_ARRAYSIZE will overflow. In such cases we should omit the
50a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// generation of the GOOGLE_ARRAYSIZE constant.
51a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonbool ShouldGenerateArraySize(const EnumDescriptor* descriptor) {
52a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  int32 max_value = descriptor->value(0)->number();
53a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  for (int i = 0; i < descriptor->value_count(); i++) {
54a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    if (descriptor->value(i)->number() > max_value) {
55a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      max_value = descriptor->value(i)->number();
56a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    }
57a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  }
58b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return max_value != ::google::protobuf::kint32max;
59a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson}
60a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson}  // namespace
61a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
62fbaaef999ba563838ebd00874ed8a1c01fbf286dWink SavilleEnumGenerator::EnumGenerator(const EnumDescriptor* descriptor,
63a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson                             const Options& options)
64fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  : descriptor_(descriptor),
65fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    classname_(ClassName(descriptor, false)),
66a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    options_(options),
67a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    generate_array_size_(ShouldGenerateArraySize(descriptor)) {
68fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville}
69fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
70fbaaef999ba563838ebd00874ed8a1c01fbf286dWink SavilleEnumGenerator::~EnumGenerator() {}
71fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
72b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammervoid EnumGenerator::FillForwardDeclaration(
73b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    map<string, const EnumDescriptor*>* enum_names) {
74b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (!options_.proto_h) {
75b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return;
76b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
77b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  (*enum_names)[classname_] = descriptor_;
78b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
79b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
80fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillevoid EnumGenerator::GenerateDefinition(io::Printer* printer) {
81fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  map<string, string> vars;
82fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  vars["classname"] = classname_;
83fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  vars["short_name"] = descriptor_->name();
84b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  vars["enumbase"] = classname_ + (options_.proto_h ? " : int" : "");
85fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
86b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  printer->Print(vars, "enum $enumbase$ {\n");
87b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  printer->Annotate("enumbase", descriptor_);
88fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  printer->Indent();
89fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
90fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  const EnumValueDescriptor* min_value = descriptor_->value(0);
91fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  const EnumValueDescriptor* max_value = descriptor_->value(0);
92fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
93fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  for (int i = 0; i < descriptor_->value_count(); i++) {
94b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    vars["name"] = EnumValueName(descriptor_->value(i));
95a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    // In C++, an value of -2147483648 gets interpreted as the negative of
96a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    // 2147483648, and since 2147483648 can't fit in an integer, this produces a
97a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    // compiler warning.  This works around that issue.
98a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    vars["number"] = Int32ToString(descriptor_->value(i)->number());
99fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    vars["prefix"] = (descriptor_->containing_type() == NULL) ?
100fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      "" : classname_ + "_";
101b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    vars["deprecation"] = descriptor_->value(i)->options().deprecated() ?
102b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        " PROTOBUF_DEPRECATED" : "";
103fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
104fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    if (i > 0) printer->Print(",\n");
105b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    printer->Print(vars, "$prefix$$name$$deprecation$ = $number$");
106fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
107fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    if (descriptor_->value(i)->number() < min_value->number()) {
108fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      min_value = descriptor_->value(i);
109fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
110fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    if (descriptor_->value(i)->number() > max_value->number()) {
111fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      max_value = descriptor_->value(i);
112fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
113fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
114fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
115b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
116b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // For new enum semantics: generate min and max sentinel values equal to
117b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // INT32_MIN and INT32_MAX
118b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (descriptor_->value_count() > 0) printer->Print(",\n");
119b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    printer->Print(vars,
120b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        "$classname$_$prefix$INT_MIN_SENTINEL_DO_NOT_USE_ = ::google::protobuf::kint32min,\n"
121b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        "$classname$_$prefix$INT_MAX_SENTINEL_DO_NOT_USE_ = ::google::protobuf::kint32max");
122b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
123b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
124fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  printer->Outdent();
125fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  printer->Print("\n};\n");
126fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
127b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  vars["min_name"] = EnumValueName(min_value);
128b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  vars["max_name"] = EnumValueName(max_value);
129fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
130a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  if (options_.dllexport_decl.empty()) {
131fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    vars["dllexport"] = "";
132fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  } else {
133a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    vars["dllexport"] = options_.dllexport_decl + " ";
134fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
135fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
136fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  printer->Print(vars,
137fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    "$dllexport$bool $classname$_IsValid(int value);\n"
138fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    "const $classname$ $prefix$$short_name$_MIN = $prefix$$min_name$;\n"
139a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    "const $classname$ $prefix$$short_name$_MAX = $prefix$$max_name$;\n");
140a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
141a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  if (generate_array_size_) {
142a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    printer->Print(vars,
143a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      "const int $prefix$$short_name$_ARRAYSIZE = "
144a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      "$prefix$$short_name$_MAX + 1;\n\n");
145a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  }
146fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
147b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (HasDescriptorMethods(descriptor_->file(), options_)) {
148fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    printer->Print(vars,
149fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      "$dllexport$const ::google::protobuf::EnumDescriptor* $classname$_descriptor();\n");
150fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    // The _Name and _Parse methods
151b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    printer->Print(
152b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        vars,
153b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        "inline const ::std::string& $classname$_Name($classname$ value) {\n"
154b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        "  return ::google::protobuf::internal::NameOfEnum(\n"
155b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        "    $classname$_descriptor(), value);\n"
156b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        "}\n");
157fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    printer->Print(vars,
158fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      "inline bool $classname$_Parse(\n"
159fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      "    const ::std::string& name, $classname$* value) {\n"
160fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      "  return ::google::protobuf::internal::ParseNamedEnum<$classname$>(\n"
161fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      "    $classname$_descriptor(), name, value);\n"
162fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      "}\n");
163fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
164fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville}
165fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
166fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillevoid EnumGenerator::
167fbaaef999ba563838ebd00874ed8a1c01fbf286dWink SavilleGenerateGetEnumDescriptorSpecializations(io::Printer* printer) {
168b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  printer->Print(
169b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      "template <> struct is_proto_enum< $classname$> : ::google::protobuf::internal::true_type "
170b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      "{};\n",
171b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      "classname", ClassName(descriptor_, true));
172b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (HasDescriptorMethods(descriptor_->file(), options_)) {
173fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    printer->Print(
174fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      "template <>\n"
175fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      "inline const EnumDescriptor* GetEnumDescriptor< $classname$>() {\n"
176fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      "  return $classname$_descriptor();\n"
177fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      "}\n",
178fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      "classname", ClassName(descriptor_, true));
179fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
180fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville}
181fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
182fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillevoid EnumGenerator::GenerateSymbolImports(io::Printer* printer) {
183fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  map<string, string> vars;
184fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  vars["nested_name"] = descriptor_->name();
185fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  vars["classname"] = classname_;
186b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  vars["constexpr"] = options_.proto_h ? "constexpr " : "";
187fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  printer->Print(vars, "typedef $classname$ $nested_name$;\n");
188fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
189fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  for (int j = 0; j < descriptor_->value_count(); j++) {
190b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    vars["tag"] = EnumValueName(descriptor_->value(j));
191b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    vars["deprecated_attr"] = descriptor_->value(j)->options().deprecated() ?
192b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      "PROTOBUF_DEPRECATED_ATTR " : "";
193fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    printer->Print(vars,
194b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      "$deprecated_attr$static $constexpr$const $nested_name$ $tag$ =\n"
195b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      "  $classname$_$tag$;\n");
196fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
197fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
198fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  printer->Print(vars,
199fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    "static inline bool $nested_name$_IsValid(int value) {\n"
200fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    "  return $classname$_IsValid(value);\n"
201fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    "}\n"
202fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    "static const $nested_name$ $nested_name$_MIN =\n"
203fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    "  $classname$_$nested_name$_MIN;\n"
204fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    "static const $nested_name$ $nested_name$_MAX =\n"
205a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    "  $classname$_$nested_name$_MAX;\n");
206a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  if (generate_array_size_) {
207a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    printer->Print(vars,
208a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      "static const int $nested_name$_ARRAYSIZE =\n"
209a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      "  $classname$_$nested_name$_ARRAYSIZE;\n");
210a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  }
211fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
212b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (HasDescriptorMethods(descriptor_->file(), options_)) {
213fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    printer->Print(vars,
214fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      "static inline const ::google::protobuf::EnumDescriptor*\n"
215fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      "$nested_name$_descriptor() {\n"
216fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      "  return $classname$_descriptor();\n"
217d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      "}\n");
218d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    printer->Print(vars,
219b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                   "static inline const ::std::string& "
220b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                   "$nested_name$_Name($nested_name$ value) {"
221b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                   "\n"
222b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                   "  return $classname$_Name(value);\n"
223b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                   "}\n");
224d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    printer->Print(vars,
225fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      "static inline bool $nested_name$_Parse(const ::std::string& name,\n"
226fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      "    $nested_name$* value) {\n"
227fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      "  return $classname$_Parse(name, value);\n"
228fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      "}\n");
229fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
230fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville}
231fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
232fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillevoid EnumGenerator::GenerateDescriptorInitializer(
233fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    io::Printer* printer, int index) {
234fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  map<string, string> vars;
235fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  vars["classname"] = classname_;
236fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  vars["index"] = SimpleItoa(index);
237fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
238fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  if (descriptor_->containing_type() == NULL) {
239fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    printer->Print(vars,
240fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      "$classname$_descriptor_ = file->enum_type($index$);\n");
241fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  } else {
242fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    vars["parent"] = ClassName(descriptor_->containing_type(), false);
243fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    printer->Print(vars,
244fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      "$classname$_descriptor_ = $parent$_descriptor_->enum_type($index$);\n");
245fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
246fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville}
247fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
248fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillevoid EnumGenerator::GenerateMethods(io::Printer* printer) {
249fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  map<string, string> vars;
250fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  vars["classname"] = classname_;
251b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  vars["constexpr"] = options_.proto_h ? "constexpr " : "";
252fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
253b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (HasDescriptorMethods(descriptor_->file(), options_)) {
254fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    printer->Print(vars,
255fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      "const ::google::protobuf::EnumDescriptor* $classname$_descriptor() {\n"
256fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      "  protobuf_AssignDescriptorsOnce();\n"
257fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      "  return $classname$_descriptor_;\n"
258fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      "}\n");
259fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
260fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
261fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  printer->Print(vars,
262fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    "bool $classname$_IsValid(int value) {\n"
263fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    "  switch(value) {\n");
264fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
265fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  // Multiple values may have the same number.  Make sure we only cover
266fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  // each number once by first constructing a set containing all valid
267fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  // numbers, then printing a case statement for each element.
268fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
269fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  set<int> numbers;
270fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  for (int j = 0; j < descriptor_->value_count(); j++) {
271fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    const EnumValueDescriptor* value = descriptor_->value(j);
272fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    numbers.insert(value->number());
273fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
274fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
275fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  for (set<int>::iterator iter = numbers.begin();
276fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville       iter != numbers.end(); ++iter) {
277fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    printer->Print(
278fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      "    case $number$:\n",
279a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      "number", Int32ToString(*iter));
280fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
281fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
282fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  printer->Print(vars,
283fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    "      return true;\n"
284fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    "    default:\n"
285fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    "      return false;\n"
286fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    "  }\n"
287fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    "}\n"
288fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    "\n");
289fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
290fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  if (descriptor_->containing_type() != NULL) {
291fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    // We need to "define" the static constants which were declared in the
292fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    // header, to give the linker a place to put them.  Or at least the C++
293b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // standard says we have to.  MSVC actually insists that we do _not_ define
294b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // them again in the .cc file, prior to VC++ 2015.
295b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    printer->Print("#if !defined(_MSC_VER) || _MSC_VER >= 1900\n");
296fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
297fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    vars["parent"] = ClassName(descriptor_->containing_type(), false);
298fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    vars["nested_name"] = descriptor_->name();
299fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    for (int i = 0; i < descriptor_->value_count(); i++) {
300b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      vars["value"] = EnumValueName(descriptor_->value(i));
301fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      printer->Print(vars,
302b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        "$constexpr$const $classname$ $parent$::$value$;\n");
303fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
304fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    printer->Print(vars,
305fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      "const $classname$ $parent$::$nested_name$_MIN;\n"
306a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      "const $classname$ $parent$::$nested_name$_MAX;\n");
307a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    if (generate_array_size_) {
308a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      printer->Print(vars,
309a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson        "const int $parent$::$nested_name$_ARRAYSIZE;\n");
310a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    }
311fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
312b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    printer->Print("#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900\n");
313fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
314fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville}
315fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
316fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville}  // namespace cpp
317fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville}  // namespace compiler
318fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville}  // namespace protobuf
319fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville}  // namespace google
320