cpp_helpers.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 <vector> 36#include <google/protobuf/stubs/hash.h> 37 38#include <google/protobuf/compiler/cpp/cpp_helpers.h> 39#include <google/protobuf/stubs/common.h> 40#include <google/protobuf/stubs/strutil.h> 41#include <google/protobuf/stubs/substitute.h> 42 43namespace google { 44namespace protobuf { 45namespace compiler { 46namespace cpp { 47 48namespace { 49 50string DotsToUnderscores(const string& name) { 51 return StringReplace(name, ".", "_", true); 52} 53 54string DotsToColons(const string& name) { 55 return StringReplace(name, ".", "::", true); 56} 57 58const char* const kKeywordList[] = { 59 "and", "and_eq", "asm", "auto", "bitand", "bitor", "bool", "break", "case", 60 "catch", "char", "class", "compl", "const", "const_cast", "continue", 61 "default", "delete", "do", "double", "dynamic_cast", "else", "enum", 62 "explicit", "extern", "false", "float", "for", "friend", "goto", "if", 63 "inline", "int", "long", "mutable", "namespace", "new", "not", "not_eq", 64 "operator", "or", "or_eq", "private", "protected", "public", "register", 65 "reinterpret_cast", "return", "short", "signed", "sizeof", "static", 66 "static_cast", "struct", "switch", "template", "this", "throw", "true", "try", 67 "typedef", "typeid", "typename", "union", "unsigned", "using", "virtual", 68 "void", "volatile", "wchar_t", "while", "xor", "xor_eq" 69}; 70 71hash_set<string> MakeKeywordsMap() { 72 hash_set<string> result; 73 for (int i = 0; i < GOOGLE_ARRAYSIZE(kKeywordList); i++) { 74 result.insert(kKeywordList[i]); 75 } 76 return result; 77} 78 79hash_set<string> kKeywords = MakeKeywordsMap(); 80 81string UnderscoresToCamelCase(const string& input, bool cap_next_letter) { 82 string result; 83 // Note: I distrust ctype.h due to locales. 84 for (int i = 0; i < input.size(); i++) { 85 if ('a' <= input[i] && input[i] <= 'z') { 86 if (cap_next_letter) { 87 result += input[i] + ('A' - 'a'); 88 } else { 89 result += input[i]; 90 } 91 cap_next_letter = false; 92 } else if ('A' <= input[i] && input[i] <= 'Z') { 93 // Capital letters are left as-is. 94 result += input[i]; 95 cap_next_letter = false; 96 } else if ('0' <= input[i] && input[i] <= '9') { 97 result += input[i]; 98 cap_next_letter = true; 99 } else { 100 cap_next_letter = true; 101 } 102 } 103 return result; 104} 105 106} // namespace 107 108const char kThickSeparator[] = 109 "// ===================================================================\n"; 110const char kThinSeparator[] = 111 "// -------------------------------------------------------------------\n"; 112 113string ClassName(const Descriptor* descriptor, bool qualified) { 114 // Find "outer", the descriptor of the top-level message in which 115 // "descriptor" is embedded. 116 const Descriptor* outer = descriptor; 117 while (outer->containing_type() != NULL) outer = outer->containing_type(); 118 119 const string& outer_name = outer->full_name(); 120 string inner_name = descriptor->full_name().substr(outer_name.size()); 121 122 if (qualified) { 123 return "::" + DotsToColons(outer_name) + DotsToUnderscores(inner_name); 124 } else { 125 return outer->name() + DotsToUnderscores(inner_name); 126 } 127} 128 129string ClassName(const EnumDescriptor* enum_descriptor, bool qualified) { 130 if (enum_descriptor->containing_type() == NULL) { 131 if (qualified) { 132 return DotsToColons(enum_descriptor->full_name()); 133 } else { 134 return enum_descriptor->name(); 135 } 136 } else { 137 string result = ClassName(enum_descriptor->containing_type(), qualified); 138 result += '_'; 139 result += enum_descriptor->name(); 140 return result; 141 } 142} 143 144string FieldName(const FieldDescriptor* field) { 145 string result = field->name(); 146 LowerString(&result); 147 if (kKeywords.count(result) > 0) { 148 result.append("_"); 149 } 150 return result; 151} 152 153string FieldConstantName(const FieldDescriptor *field) { 154 string field_name = UnderscoresToCamelCase(field->name(), true); 155 string result = "k" + field_name + "FieldNumber"; 156 157 if (!field->is_extension() && 158 field->containing_type()->FindFieldByCamelcaseName( 159 field->camelcase_name()) != field) { 160 // This field's camelcase name is not unique. As a hack, add the field 161 // number to the constant name. This makes the constant rather useless, 162 // but what can we do? 163 result += "_" + SimpleItoa(field->number()); 164 } 165 166 return result; 167} 168 169string StripProto(const string& filename) { 170 if (HasSuffixString(filename, ".protodevel")) { 171 return StripSuffixString(filename, ".protodevel"); 172 } else { 173 return StripSuffixString(filename, ".proto"); 174 } 175} 176 177const char* PrimitiveTypeName(FieldDescriptor::CppType type) { 178 switch (type) { 179 case FieldDescriptor::CPPTYPE_INT32 : return "::google::protobuf::int32"; 180 case FieldDescriptor::CPPTYPE_INT64 : return "::google::protobuf::int64"; 181 case FieldDescriptor::CPPTYPE_UINT32 : return "::google::protobuf::uint32"; 182 case FieldDescriptor::CPPTYPE_UINT64 : return "::google::protobuf::uint64"; 183 case FieldDescriptor::CPPTYPE_DOUBLE : return "double"; 184 case FieldDescriptor::CPPTYPE_FLOAT : return "float"; 185 case FieldDescriptor::CPPTYPE_BOOL : return "bool"; 186 case FieldDescriptor::CPPTYPE_ENUM : return "int"; 187 case FieldDescriptor::CPPTYPE_STRING : return "::std::string"; 188 case FieldDescriptor::CPPTYPE_MESSAGE: return NULL; 189 190 // No default because we want the compiler to complain if any new 191 // CppTypes are added. 192 } 193 194 GOOGLE_LOG(FATAL) << "Can't get here."; 195 return NULL; 196} 197 198const char* DeclaredTypeMethodName(FieldDescriptor::Type type) { 199 switch (type) { 200 case FieldDescriptor::TYPE_INT32 : return "Int32"; 201 case FieldDescriptor::TYPE_INT64 : return "Int64"; 202 case FieldDescriptor::TYPE_UINT32 : return "UInt32"; 203 case FieldDescriptor::TYPE_UINT64 : return "UInt64"; 204 case FieldDescriptor::TYPE_SINT32 : return "SInt32"; 205 case FieldDescriptor::TYPE_SINT64 : return "SInt64"; 206 case FieldDescriptor::TYPE_FIXED32 : return "Fixed32"; 207 case FieldDescriptor::TYPE_FIXED64 : return "Fixed64"; 208 case FieldDescriptor::TYPE_SFIXED32: return "SFixed32"; 209 case FieldDescriptor::TYPE_SFIXED64: return "SFixed64"; 210 case FieldDescriptor::TYPE_FLOAT : return "Float"; 211 case FieldDescriptor::TYPE_DOUBLE : return "Double"; 212 213 case FieldDescriptor::TYPE_BOOL : return "Bool"; 214 case FieldDescriptor::TYPE_ENUM : return "Enum"; 215 216 case FieldDescriptor::TYPE_STRING : return "String"; 217 case FieldDescriptor::TYPE_BYTES : return "Bytes"; 218 case FieldDescriptor::TYPE_GROUP : return "Group"; 219 case FieldDescriptor::TYPE_MESSAGE : return "Message"; 220 221 // No default because we want the compiler to complain if any new 222 // types are added. 223 } 224 GOOGLE_LOG(FATAL) << "Can't get here."; 225 return ""; 226} 227 228string DefaultValue(const FieldDescriptor* field) { 229 switch (field->cpp_type()) { 230 case FieldDescriptor::CPPTYPE_INT32: 231 return SimpleItoa(field->default_value_int32()); 232 case FieldDescriptor::CPPTYPE_UINT32: 233 return SimpleItoa(field->default_value_uint32()) + "u"; 234 case FieldDescriptor::CPPTYPE_INT64: 235 return "GOOGLE_LONGLONG(" + SimpleItoa(field->default_value_int64()) + ")"; 236 case FieldDescriptor::CPPTYPE_UINT64: 237 return "GOOGLE_ULONGLONG(" + SimpleItoa(field->default_value_uint64())+ ")"; 238 case FieldDescriptor::CPPTYPE_DOUBLE: 239 return SimpleDtoa(field->default_value_double()); 240 case FieldDescriptor::CPPTYPE_FLOAT: 241 { 242 // If floating point value contains a period (.) or an exponent (either 243 // E or e), then append suffix 'f' to make it a floating-point literal. 244 string float_value = SimpleFtoa(field->default_value_float()); 245 if (float_value.find_first_of(".eE") != string::npos) { 246 float_value.push_back('f'); 247 } 248 return float_value; 249 } 250 case FieldDescriptor::CPPTYPE_BOOL: 251 return field->default_value_bool() ? "true" : "false"; 252 case FieldDescriptor::CPPTYPE_ENUM: 253 // Lazy: Generate a static_cast because we don't have a helper function 254 // that constructs the full name of an enum value. 255 return strings::Substitute( 256 "static_cast< $0 >($1)", 257 ClassName(field->enum_type(), true), 258 field->default_value_enum()->number()); 259 case FieldDescriptor::CPPTYPE_STRING: 260 return "\"" + CEscape(field->default_value_string()) + "\""; 261 case FieldDescriptor::CPPTYPE_MESSAGE: 262 return ClassName(field->message_type(), true) + "::default_instance()"; 263 } 264 // Can't actually get here; make compiler happy. (We could add a default 265 // case above but then we wouldn't get the nice compiler warning when a 266 // new type is added.) 267 GOOGLE_LOG(FATAL) << "Can't get here."; 268 return ""; 269} 270 271// Convert a file name into a valid identifier. 272string FilenameIdentifier(const string& filename) { 273 string result; 274 for (int i = 0; i < filename.size(); i++) { 275 if (ascii_isalnum(filename[i])) { 276 result.push_back(filename[i]); 277 } else { 278 // Not alphanumeric. To avoid any possibility of name conflicts we 279 // use the hex code for the character. 280 result.push_back('_'); 281 char buffer[kFastToBufferSize]; 282 result.append(FastHexToBuffer(static_cast<uint8>(filename[i]), buffer)); 283 } 284 } 285 return result; 286} 287 288// Return the name of the AddDescriptors() function for a given file. 289string GlobalAddDescriptorsName(const string& filename) { 290 return "protobuf_AddDesc_" + FilenameIdentifier(filename); 291} 292 293// Return the name of the AssignDescriptors() function for a given file. 294string GlobalAssignDescriptorsName(const string& filename) { 295 return "protobuf_AssignDesc_" + FilenameIdentifier(filename); 296} 297 298// Return the name of the ShutdownFile() function for a given file. 299string GlobalShutdownFileName(const string& filename) { 300 return "protobuf_ShutdownFile_" + FilenameIdentifier(filename); 301} 302 303} // namespace cpp 304} // namespace compiler 305} // namespace protobuf 306} // namespace google 307