aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/google/protobuf/descriptor.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/google/protobuf/descriptor.cc')
-rw-r--r--src/google/protobuf/descriptor.cc344
1 files changed, 245 insertions, 99 deletions
diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc
index 21c709fb..eb5b5937 100644
--- a/src/google/protobuf/descriptor.cc
+++ b/src/google/protobuf/descriptor.cc
@@ -122,6 +122,35 @@ namespace {
const string kEmptyString;
+string ToCamelCase(const string& input) {
+ bool capitalize_next = false;
+ string result;
+ result.reserve(input.size());
+
+ for (int i = 0; i < input.size(); i++) {
+ if (input[i] == '_') {
+ capitalize_next = true;
+ } else if (capitalize_next) {
+ // Note: I distrust ctype.h due to locales.
+ if ('a' <= input[i] && input[i] <= 'z') {
+ result.push_back(input[i] - 'a' + 'A');
+ } else {
+ result.push_back(input[i]);
+ }
+ capitalize_next = false;
+ } else {
+ result.push_back(input[i]);
+ }
+ }
+
+ // Lower-case the first letter.
+ if (!result.empty() && 'A' <= result[0] && result[0] <= 'Z') {
+ result[0] = result[0] - 'A' + 'a';
+ }
+
+ return result;
+}
+
// A DescriptorPool contains a bunch of hash_maps to implement the
// various Find*By*() methods. Since hashtable lookups are O(1), it's
// most efficient to construct a fixed set of large hash_maps used by
@@ -253,6 +282,9 @@ typedef hash_map<PointerStringPair, Symbol,
typedef hash_map<const char*, const FileDescriptor*,
hash<const char*>, CStringEqual>
FilesByNameMap;
+typedef hash_map<PointerStringPair, const FieldDescriptor*,
+ PointerStringPairHash, PointerStringPairEqual>
+ FieldsByNameMap;
typedef hash_map<DescriptorIntPair, const FieldDescriptor*,
PointerIntegerPairHash<DescriptorIntPair> >
FieldsByNumberMap;
@@ -296,21 +328,29 @@ class DescriptorPool::Tables {
// Finding items.
// Find symbols. These return a null Symbol (symbol.IsNull() is true)
- // if not found. FindSymbolOfType() additionally returns null if the
- // symbol is not of the given type.
+ // if not found.
inline Symbol FindSymbol(const string& key) const;
- inline Symbol FindSymbolOfType(const string& key,
- const Symbol::Type type) const;
inline Symbol FindNestedSymbol(const void* parent,
const string& name) const;
inline Symbol FindNestedSymbolOfType(const void* parent,
const string& name,
const Symbol::Type type) const;
+ // This implements the body of DescriptorPool::Find*ByName(). It should
+ // really be a private method of DescriptorPool, but that would require
+ // declaring Symbol in descriptor.h, which would drag all kinds of other
+ // stuff into the header. Yay C++.
+ Symbol FindByNameHelper(
+ const DescriptorPool* pool, const string& name) const;
+
// These return NULL if not found.
inline const FileDescriptor* FindFile(const string& key) const;
inline const FieldDescriptor* FindFieldByNumber(
const Descriptor* parent, int number) const;
+ inline const FieldDescriptor* FindFieldByLowercaseName(
+ const void* parent, const string& lowercase_name) const;
+ inline const FieldDescriptor* FindFieldByCamelcaseName(
+ const void* parent, const string& camelcase_name) const;
inline const EnumValueDescriptor* FindEnumValueByNumber(
const EnumDescriptor* parent, int number) const;
@@ -330,6 +370,10 @@ class DescriptorPool::Tables {
bool AddFieldByNumber(const FieldDescriptor* field);
bool AddEnumValueByNumber(const EnumValueDescriptor* value);
+ // Adds the field to the lowercase_name and camelcase_name maps. Never
+ // fails because we allow duplicates; the first field by the name wins.
+ void AddFieldByStylizedNames(const FieldDescriptor* field);
+
// Like AddSymbol(), but only adds to symbols_by_parent_, not
// symbols_by_name_. Used for enum values, which need to be registered
// under multiple parents (their type and its parent).
@@ -364,6 +408,8 @@ class DescriptorPool::Tables {
SymbolsByNameMap symbols_by_name_;
SymbolsByParentMap symbols_by_parent_;
FilesByNameMap files_by_name_;
+ FieldsByNameMap fields_by_lowercase_name_;
+ FieldsByNameMap fields_by_camelcase_name_;
FieldsByNumberMap fields_by_number_; // Includes extensions.
EnumValuesByNumberMap enum_values_by_number_;
@@ -373,6 +419,8 @@ class DescriptorPool::Tables {
vector<const char* > symbols_after_checkpoint_;
vector<PointerStringPair> symbols_by_parent_after_checkpoint_;
vector<const char* > files_after_checkpoint_;
+ vector<PointerStringPair> field_lowercase_names_after_checkpoint_;
+ vector<PointerStringPair> field_camelcase_names_after_checkpoint_;
vector<DescriptorIntPair> field_numbers_after_checkpoint_;
vector<EnumIntPair > enum_numbers_after_checkpoint_;
@@ -404,6 +452,8 @@ void DescriptorPool::Tables::Checkpoint() {
symbols_after_checkpoint_.clear();
symbols_by_parent_after_checkpoint_.clear();
files_after_checkpoint_.clear();
+ field_lowercase_names_after_checkpoint_.clear();
+ field_camelcase_names_after_checkpoint_.clear();
field_numbers_after_checkpoint_.clear();
enum_numbers_after_checkpoint_.clear();
}
@@ -418,6 +468,12 @@ void DescriptorPool::Tables::Rollback() {
for (int i = 0; i < files_after_checkpoint_.size(); i++) {
files_by_name_.erase(files_after_checkpoint_[i]);
}
+ for (int i = 0; i < field_lowercase_names_after_checkpoint_.size(); i++) {
+ fields_by_lowercase_name_.erase(field_lowercase_names_after_checkpoint_[i]);
+ }
+ for (int i = 0; i < field_camelcase_names_after_checkpoint_.size(); i++) {
+ fields_by_camelcase_name_.erase(field_camelcase_names_after_checkpoint_[i]);
+ }
for (int i = 0; i < field_numbers_after_checkpoint_.size(); i++) {
fields_by_number_.erase(field_numbers_after_checkpoint_[i]);
}
@@ -428,6 +484,8 @@ void DescriptorPool::Tables::Rollback() {
symbols_after_checkpoint_.clear();
symbols_by_parent_after_checkpoint_.clear();
files_after_checkpoint_.clear();
+ field_lowercase_names_after_checkpoint_.clear();
+ field_camelcase_names_after_checkpoint_.clear();
field_numbers_after_checkpoint_.clear();
enum_numbers_after_checkpoint_.clear();
@@ -455,13 +513,6 @@ inline Symbol DescriptorPool::Tables::FindSymbol(const string& key) const {
}
}
-inline Symbol DescriptorPool::Tables::FindSymbolOfType(
- const string& key, const Symbol::Type type) const {
- Symbol result = FindSymbol(key);
- if (result.type != type) return kNullSymbol;
- return result;
-}
-
inline Symbol DescriptorPool::Tables::FindNestedSymbol(
const void* parent, const string& name) const {
const Symbol* result =
@@ -480,6 +531,27 @@ inline Symbol DescriptorPool::Tables::FindNestedSymbolOfType(
return result;
}
+Symbol DescriptorPool::Tables::FindByNameHelper(
+ const DescriptorPool* pool, const string& name) const {
+ MutexLockMaybe lock(pool->mutex_);
+ Symbol result = FindSymbol(name);
+
+ if (result.IsNull() && pool->underlay_ != NULL) {
+ // Symbol not found; check the underlay.
+ result =
+ pool->underlay_->tables_->FindByNameHelper(pool->underlay_, name);
+ }
+
+ if (result.IsNull()) {
+ // Symbol still not found, so check fallback database.
+ if (pool->TryFindSymbolInFallbackDatabase(name)) {
+ result = FindSymbol(name);
+ }
+ }
+
+ return result;
+}
+
inline const FileDescriptor* DescriptorPool::Tables::FindFile(
const string& key) const {
return FindPtrOrNull(files_by_name_, key.c_str());
@@ -490,6 +562,18 @@ inline const FieldDescriptor* DescriptorPool::Tables::FindFieldByNumber(
return FindPtrOrNull(fields_by_number_, make_pair(parent, number));
}
+inline const FieldDescriptor* DescriptorPool::Tables::FindFieldByLowercaseName(
+ const void* parent, const string& lowercase_name) const {
+ return FindPtrOrNull(fields_by_lowercase_name_,
+ PointerStringPair(parent, lowercase_name.c_str()));
+}
+
+inline const FieldDescriptor* DescriptorPool::Tables::FindFieldByCamelcaseName(
+ const void* parent, const string& camelcase_name) const {
+ return FindPtrOrNull(fields_by_camelcase_name_,
+ PointerStringPair(parent, camelcase_name.c_str()));
+}
+
inline const EnumValueDescriptor* DescriptorPool::Tables::FindEnumValueByNumber(
const EnumDescriptor* parent, int number) const {
return FindPtrOrNull(enum_values_by_number_, make_pair(parent, number));
@@ -537,6 +621,30 @@ bool DescriptorPool::Tables::AddFile(const FileDescriptor* file) {
}
}
+void DescriptorPool::Tables::AddFieldByStylizedNames(
+ const FieldDescriptor* field) {
+ const void* parent;
+ if (field->is_extension()) {
+ if (field->extension_scope() == NULL) {
+ parent = field->file();
+ } else {
+ parent = field->extension_scope();
+ }
+ } else {
+ parent = field->containing_type();
+ }
+
+ PointerStringPair lowercase_key(parent, field->lowercase_name().c_str());
+ if (InsertIfNotPresent(&fields_by_lowercase_name_, lowercase_key, field)) {
+ field_lowercase_names_after_checkpoint_.push_back(lowercase_key);
+ }
+
+ PointerStringPair camelcase_key(parent, field->camelcase_name().c_str());
+ if (InsertIfNotPresent(&fields_by_camelcase_name_, camelcase_key, field)) {
+ field_camelcase_names_after_checkpoint_.push_back(camelcase_key);
+ }
+}
+
bool DescriptorPool::Tables::AddFieldByNumber(const FieldDescriptor* field) {
DescriptorIntPair key(field->containing_type(), field->number());
if (InsertIfNotPresent(&fields_by_number_, key, field)) {
@@ -689,122 +797,55 @@ const FileDescriptor* DescriptorPool::FindFileContainingSymbol(
const Descriptor* DescriptorPool::FindMessageTypeByName(
const string& name) const {
- MutexLockMaybe lock(mutex_);
- Symbol result = tables_->FindSymbolOfType(name, Symbol::MESSAGE);
- if (!result.IsNull()) return result.descriptor;
- if (underlay_ != NULL) {
- const Descriptor* result = underlay_->FindMessageTypeByName(name);
- if (result != NULL) return result;
- }
- if (TryFindSymbolInFallbackDatabase(name)) {
- Symbol result = tables_->FindSymbolOfType(name, Symbol::MESSAGE);
- if (!result.IsNull()) return result.descriptor;
- }
- return NULL;
+ Symbol result = tables_->FindByNameHelper(this, name);
+ return (result.type == Symbol::MESSAGE) ? result.descriptor : NULL;
}
const FieldDescriptor* DescriptorPool::FindFieldByName(
const string& name) const {
- MutexLockMaybe lock(mutex_);
- Symbol result = tables_->FindSymbolOfType(name, Symbol::FIELD);
- if (!result.IsNull() && !result.field_descriptor->is_extension()) {
+ Symbol result = tables_->FindByNameHelper(this, name);
+ if (result.type == Symbol::FIELD &&
+ !result.field_descriptor->is_extension()) {
return result.field_descriptor;
+ } else {
+ return NULL;
}
- if (underlay_ != NULL) {
- const FieldDescriptor* result = underlay_->FindFieldByName(name);
- if (result != NULL) return result;
- }
- if (TryFindSymbolInFallbackDatabase(name)) {
- Symbol result = tables_->FindSymbolOfType(name, Symbol::FIELD);
- if (!result.IsNull() && !result.field_descriptor->is_extension()) {
- return result.field_descriptor;
- }
- }
- return NULL;
}
const FieldDescriptor* DescriptorPool::FindExtensionByName(
const string& name) const {
- MutexLockMaybe lock(mutex_);
- Symbol result = tables_->FindSymbolOfType(name, Symbol::FIELD);
- if (!result.IsNull() && result.field_descriptor->is_extension()) {
+ Symbol result = tables_->FindByNameHelper(this, name);
+ if (result.type == Symbol::FIELD &&
+ result.field_descriptor->is_extension()) {
return result.field_descriptor;
+ } else {
+ return NULL;
}
- if (underlay_ != NULL) {
- const FieldDescriptor* result = underlay_->FindExtensionByName(name);
- if (result != NULL) return result;
- }
- if (TryFindSymbolInFallbackDatabase(name)) {
- Symbol result = tables_->FindSymbolOfType(name, Symbol::FIELD);
- if (!result.IsNull() && result.field_descriptor->is_extension()) {
- return result.field_descriptor;
- }
- }
- return NULL;
}
const EnumDescriptor* DescriptorPool::FindEnumTypeByName(
const string& name) const {
- MutexLockMaybe lock(mutex_);
- Symbol result = tables_->FindSymbolOfType(name, Symbol::ENUM);
- if (!result.IsNull()) return result.enum_descriptor;
- if (underlay_ != NULL) {
- const EnumDescriptor* result = underlay_->FindEnumTypeByName(name);
- if (result != NULL) return result;
- }
- if (TryFindSymbolInFallbackDatabase(name)) {
- Symbol result = tables_->FindSymbolOfType(name, Symbol::ENUM);
- if (!result.IsNull()) return result.enum_descriptor;
- }
- return NULL;
+ Symbol result = tables_->FindByNameHelper(this, name);
+ return (result.type == Symbol::ENUM) ? result.enum_descriptor : NULL;
}
const EnumValueDescriptor* DescriptorPool::FindEnumValueByName(
const string& name) const {
- MutexLockMaybe lock(mutex_);
- Symbol result = tables_->FindSymbolOfType(name, Symbol::ENUM_VALUE);
- if (!result.IsNull()) return result.enum_value_descriptor;
- if (underlay_ != NULL) {
- const EnumValueDescriptor* result = underlay_->FindEnumValueByName(name);
- if (result != NULL) return result;
- }
- if (TryFindSymbolInFallbackDatabase(name)) {
- Symbol result = tables_->FindSymbolOfType(name, Symbol::ENUM_VALUE);
- if (!result.IsNull()) return result.enum_value_descriptor;
- }
- return NULL;
+ Symbol result = tables_->FindByNameHelper(this, name);
+ return (result.type == Symbol::ENUM_VALUE) ?
+ result.enum_value_descriptor : NULL;
}
const ServiceDescriptor* DescriptorPool::FindServiceByName(
const string& name) const {
- MutexLockMaybe lock(mutex_);
- Symbol result = tables_->FindSymbolOfType(name, Symbol::SERVICE);
- if (!result.IsNull()) return result.service_descriptor;
- if (underlay_ != NULL) {
- const ServiceDescriptor* result = underlay_->FindServiceByName(name);
- if (result != NULL) return result;
- }
- if (TryFindSymbolInFallbackDatabase(name)) {
- Symbol result = tables_->FindSymbolOfType(name, Symbol::SERVICE);
- if (!result.IsNull()) return result.service_descriptor;
- }
- return NULL;
+ Symbol result = tables_->FindByNameHelper(this, name);
+ return (result.type == Symbol::SERVICE) ? result.service_descriptor : NULL;
}
const MethodDescriptor* DescriptorPool::FindMethodByName(
const string& name) const {
- MutexLockMaybe lock(mutex_);
- Symbol result = tables_->FindSymbolOfType(name, Symbol::METHOD);
- if (!result.IsNull()) return result.method_descriptor;
- if (underlay_ != NULL) {
- const MethodDescriptor* result = underlay_->FindMethodByName(name);
- if (result != NULL) return result;
- }
- if (TryFindSymbolInFallbackDatabase(name)) {
- Symbol result = tables_->FindSymbolOfType(name, Symbol::METHOD);
- if (!result.IsNull()) return result.method_descriptor;
- }
- return NULL;
+ Symbol result = tables_->FindByNameHelper(this, name);
+ return (result.type == Symbol::METHOD) ? result.method_descriptor : NULL;
}
const FieldDescriptor* DescriptorPool::FindExtensionByNumber(
@@ -844,6 +885,30 @@ Descriptor::FindFieldByNumber(int key) const {
}
const FieldDescriptor*
+Descriptor::FindFieldByLowercaseName(const string& key) const {
+ MutexLockMaybe lock(file()->pool()->mutex_);
+ const FieldDescriptor* result =
+ file()->pool()->tables_->FindFieldByLowercaseName(this, key);
+ if (result == NULL || result->is_extension()) {
+ return NULL;
+ } else {
+ return result;
+ }
+}
+
+const FieldDescriptor*
+Descriptor::FindFieldByCamelcaseName(const string& key) const {
+ MutexLockMaybe lock(file()->pool()->mutex_);
+ const FieldDescriptor* result =
+ file()->pool()->tables_->FindFieldByCamelcaseName(this, key);
+ if (result == NULL || result->is_extension()) {
+ return NULL;
+ } else {
+ return result;
+ }
+}
+
+const FieldDescriptor*
Descriptor::FindFieldByName(const string& key) const {
MutexLockMaybe lock(file()->pool()->mutex_);
Symbol result =
@@ -867,6 +932,30 @@ Descriptor::FindExtensionByName(const string& key) const {
}
}
+const FieldDescriptor*
+Descriptor::FindExtensionByLowercaseName(const string& key) const {
+ MutexLockMaybe lock(file()->pool()->mutex_);
+ const FieldDescriptor* result =
+ file()->pool()->tables_->FindFieldByLowercaseName(this, key);
+ if (result == NULL || !result->is_extension()) {
+ return NULL;
+ } else {
+ return result;
+ }
+}
+
+const FieldDescriptor*
+Descriptor::FindExtensionByCamelcaseName(const string& key) const {
+ MutexLockMaybe lock(file()->pool()->mutex_);
+ const FieldDescriptor* result =
+ file()->pool()->tables_->FindFieldByCamelcaseName(this, key);
+ if (result == NULL || !result->is_extension()) {
+ return NULL;
+ } else {
+ return result;
+ }
+}
+
const Descriptor*
Descriptor::FindNestedTypeByName(const string& key) const {
MutexLockMaybe lock(file()->pool()->mutex_);
@@ -995,6 +1084,30 @@ FileDescriptor::FindExtensionByName(const string& key) const {
}
}
+const FieldDescriptor*
+FileDescriptor::FindExtensionByLowercaseName(const string& key) const {
+ MutexLockMaybe lock(pool()->mutex_);
+ const FieldDescriptor* result =
+ pool()->tables_->FindFieldByLowercaseName(this, key);
+ if (result == NULL || !result->is_extension()) {
+ return NULL;
+ } else {
+ return result;
+ }
+}
+
+const FieldDescriptor*
+FileDescriptor::FindExtensionByCamelcaseName(const string& key) const {
+ MutexLockMaybe lock(pool()->mutex_);
+ const FieldDescriptor* result =
+ pool()->tables_->FindFieldByCamelcaseName(this, key);
+ if (result == NULL || !result->is_extension()) {
+ return NULL;
+ } else {
+ return result;
+ }
+}
+
bool Descriptor::IsExtensionNumber(int number) const {
// Linear search should be fine because we don't expect a message to have
// more than a couple extension ranges.
@@ -2504,6 +2617,22 @@ void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto,
result->number_ = proto.number();
result->is_extension_ = is_extension;
+ // If .proto files follow the style guide then the name should already be
+ // lower-cased. If that's the case we can just reuse the string we already
+ // allocated rather than allocate a new one.
+ string lowercase_name(proto.name());
+ LowerString(&lowercase_name);
+ if (lowercase_name == proto.name()) {
+ result->lowercase_name_ = result->name_;
+ } else {
+ result->lowercase_name_ = tables_->AllocateString(lowercase_name);
+ }
+
+ // Don't bother with the above optimization for camel-case names since
+ // .proto files that follow the guide shouldn't be using names in this
+ // format, so the optimization wouldn't help much.
+ result->camelcase_name_ = tables_->AllocateString(ToCamelCase(proto.name()));
+
// Some compilers do not allow static_cast directly between two enum types,
// so we must cast to int first.
result->type_ = static_cast<FieldDescriptor::Type>(
@@ -3042,6 +3171,9 @@ void DescriptorBuilder::CrossLinkField(
conflicting_field->name()));
}
}
+
+ // Add the field to the lowercase-name and camelcase-name tables.
+ tables_->AddFieldByStylizedNames(field);
}
void DescriptorBuilder::CrossLinkEnum(
@@ -3136,6 +3268,20 @@ void DescriptorBuilder::ValidateFieldOptions(FieldDescriptor* field,
ValidateMapKey(field, proto);
}
+ // Only repeated primitive fields may be packed.
+ if (field->options().packed()) {
+ if (!field->is_repeated() ||
+ field->type() == FieldDescriptor::TYPE_STRING ||
+ field->type() == FieldDescriptor::TYPE_GROUP ||
+ field->type() == FieldDescriptor::TYPE_MESSAGE ||
+ field->type() == FieldDescriptor::TYPE_BYTES) {
+ AddError(
+ field->full_name(), proto,
+ DescriptorPool::ErrorCollector::TYPE,
+ "[packed = true] can only be specified for repeated primitive fields.");
+ }
+ }
+
// Note: Default instance may not yet be initialized here, so we have to
// avoid reading from it.
if (field->containing_type_ != NULL &&