commit
0eb74768d0
91 changed files with 8300 additions and 3168 deletions
@ -0,0 +1,255 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <google/protobuf/compiler/cpp/cpp_map_field.h> |
||||
#include <google/protobuf/compiler/cpp/cpp_helpers.h> |
||||
#include <google/protobuf/io/printer.h> |
||||
#include <google/protobuf/stubs/strutil.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace cpp { |
||||
|
||||
bool IsProto3Field(const FieldDescriptor* field_descriptor) { |
||||
const FileDescriptor* file_descriptor = field_descriptor->file(); |
||||
return file_descriptor->syntax() == FileDescriptor::SYNTAX_PROTO3; |
||||
} |
||||
|
||||
void SetMessageVariables(const FieldDescriptor* descriptor, |
||||
map<string, string>* variables, |
||||
const Options& options) { |
||||
SetCommonFieldVariables(descriptor, variables, options); |
||||
(*variables)["type"] = FieldMessageTypeName(descriptor); |
||||
(*variables)["stream_writer"] = (*variables)["declared_type"] + |
||||
(HasFastArraySerialization(descriptor->message_type()->file()) ? |
||||
"MaybeToArray" : |
||||
""); |
||||
(*variables)["full_name"] = descriptor->full_name(); |
||||
|
||||
const FieldDescriptor* key = |
||||
descriptor->message_type()->FindFieldByName("key"); |
||||
const FieldDescriptor* val = |
||||
descriptor->message_type()->FindFieldByName("value"); |
||||
(*variables)["key_cpp"] = PrimitiveTypeName(key->cpp_type()); |
||||
switch (val->cpp_type()) { |
||||
case FieldDescriptor::CPPTYPE_MESSAGE: |
||||
(*variables)["val_cpp"] = FieldMessageTypeName(val); |
||||
(*variables)["wrapper"] = "EntryWrapper"; |
||||
break; |
||||
case FieldDescriptor::CPPTYPE_ENUM: |
||||
(*variables)["val_cpp"] = ClassName(val->enum_type(), false); |
||||
(*variables)["wrapper"] = "EnumEntryWrapper"; |
||||
break; |
||||
default: |
||||
(*variables)["val_cpp"] = PrimitiveTypeName(val->cpp_type()); |
||||
(*variables)["wrapper"] = "EntryWrapper"; |
||||
} |
||||
(*variables)["key_type"] = |
||||
"::google::protobuf::FieldDescriptor::TYPE_" + |
||||
ToUpper(DeclaredTypeMethodName(key->type())); |
||||
(*variables)["val_type"] = |
||||
"::google::protobuf::FieldDescriptor::TYPE_" + |
||||
ToUpper(DeclaredTypeMethodName(val->type())); |
||||
(*variables)["map_classname"] = ClassName(descriptor->message_type(), false); |
||||
(*variables)["number"] = Int32ToString(descriptor->number()); |
||||
|
||||
if (!IsProto3Field(descriptor) && |
||||
val->type() == FieldDescriptor::TYPE_ENUM) { |
||||
const EnumValueDescriptor* default_value = val->default_value_enum(); |
||||
(*variables)["default_enum_value"] = Int32ToString(default_value->number()); |
||||
} else { |
||||
(*variables)["default_enum_value"] = "0"; |
||||
} |
||||
} |
||||
|
||||
MapFieldGenerator:: |
||||
MapFieldGenerator(const FieldDescriptor* descriptor, |
||||
const Options& options) |
||||
: descriptor_(descriptor) { |
||||
SetMessageVariables(descriptor, &variables_, options); |
||||
} |
||||
|
||||
MapFieldGenerator::~MapFieldGenerator() {} |
||||
|
||||
void MapFieldGenerator:: |
||||
GeneratePrivateMembers(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"typedef ::google::protobuf::internal::MapEntry<\n" |
||||
" $key_cpp$, $val_cpp$,\n" |
||||
" $key_type$,\n" |
||||
" $val_type$, $default_enum_value$>\n" |
||||
" $map_classname$;\n" |
||||
"::google::protobuf::internal::MapField< $key_cpp$, $val_cpp$," |
||||
"$key_type$, $val_type$, $default_enum_value$ > $name$_;\n"); |
||||
} |
||||
|
||||
void MapFieldGenerator:: |
||||
GenerateAccessorDeclarations(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"inline const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n" |
||||
" $name$() const$deprecation$;\n" |
||||
"inline ::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n" |
||||
" mutable_$name$()$deprecation$;\n"); |
||||
} |
||||
|
||||
void MapFieldGenerator:: |
||||
GenerateInlineAccessorDefinitions(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"inline const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n" |
||||
"$classname$::$name$() const {\n" |
||||
" // @@protoc_insertion_point(field_map:$full_name$)\n" |
||||
" return $name$_.GetMap();\n" |
||||
"}\n" |
||||
"inline ::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n" |
||||
"$classname$::mutable_$name$() {\n" |
||||
" // @@protoc_insertion_point(field_mutable_map:$full_name$)\n" |
||||
" return $name$_.MutableMap();\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void MapFieldGenerator:: |
||||
GenerateClearingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "$name$_.Clear();\n"); |
||||
} |
||||
|
||||
void MapFieldGenerator:: |
||||
GenerateMergingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n"); |
||||
} |
||||
|
||||
void MapFieldGenerator:: |
||||
GenerateSwappingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n"); |
||||
} |
||||
|
||||
void MapFieldGenerator:: |
||||
GenerateConstructorCode(io::Printer* printer) const { |
||||
if (HasDescriptorMethods(descriptor_->file())) { |
||||
printer->Print(variables_, |
||||
"$name$_.SetAssignDescriptorCallback(\n" |
||||
" protobuf_AssignDescriptorsOnce);\n" |
||||
"$name$_.SetEntryDescriptor(\n" |
||||
" &$type$_descriptor_);\n"); |
||||
} |
||||
} |
||||
|
||||
void MapFieldGenerator:: |
||||
GenerateMergeFromCodedStream(io::Printer* printer) const { |
||||
const FieldDescriptor* value_field = |
||||
descriptor_->message_type()->FindFieldByName("value"); |
||||
printer->Print(variables_, |
||||
"::google::protobuf::scoped_ptr<$map_classname$> entry($name$_.NewEntry());\n"); |
||||
|
||||
if (IsProto3Field(descriptor_) || |
||||
value_field->type() != FieldDescriptor::TYPE_ENUM) { |
||||
printer->Print(variables_, |
||||
"DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(\n" |
||||
" input, entry.get()));\n"); |
||||
switch (value_field->cpp_type()) { |
||||
case FieldDescriptor::CPPTYPE_MESSAGE: |
||||
printer->Print(variables_, |
||||
"(*mutable_$name$())[entry->key()].Swap(" |
||||
"entry->mutable_value());\n"); |
||||
break; |
||||
case FieldDescriptor::CPPTYPE_ENUM: |
||||
printer->Print(variables_, |
||||
"(*mutable_$name$())[entry->key()] =\n" |
||||
" static_cast<$val_cpp$>(*entry->mutable_value());\n"); |
||||
break; |
||||
default: |
||||
printer->Print(variables_, |
||||
"(*mutable_$name$())[entry->key()] = *entry->mutable_value();\n"); |
||||
break; |
||||
} |
||||
} else { |
||||
printer->Print(variables_, |
||||
"{\n" |
||||
" ::std::string data;\n" |
||||
" DO_(::google::protobuf::internal::WireFormatLite::ReadString(input, &data));\n" |
||||
" DO_(entry->ParseFromString(data));\n" |
||||
" if ($val_cpp$_IsValid(*entry->mutable_value())) {\n" |
||||
" (*mutable_$name$())[entry->key()] =\n" |
||||
" static_cast<$val_cpp$>(*entry->mutable_value());\n" |
||||
" } else {\n" |
||||
" mutable_unknown_fields()->AddLengthDelimited($number$, data);\n" |
||||
" }\n" |
||||
"}\n"); |
||||
} |
||||
} |
||||
|
||||
void MapFieldGenerator:: |
||||
GenerateSerializeWithCachedSizes(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"{\n" |
||||
" ::google::protobuf::scoped_ptr<$map_classname$> entry;\n" |
||||
" for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n" |
||||
" it = $name$().begin(); it != $name$().end(); ++it) {\n" |
||||
" entry.reset($name$_.New$wrapper$(it->first, it->second));\n" |
||||
" ::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n" |
||||
" $number$, *entry, output);\n" |
||||
" }\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void MapFieldGenerator:: |
||||
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"{\n" |
||||
" ::google::protobuf::scoped_ptr<$map_classname$> entry;\n" |
||||
" for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n" |
||||
" it = $name$().begin(); it != $name$().end(); ++it) {\n" |
||||
" entry.reset($name$_.New$wrapper$(it->first, it->second));\n" |
||||
" target = ::google::protobuf::internal::WireFormatLite::\n" |
||||
" Write$declared_type$NoVirtualToArray(\n" |
||||
" $number$, *entry, target);\n" |
||||
" }\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void MapFieldGenerator:: |
||||
GenerateByteSize(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"total_size += $tag_size$ * this->$name$_size();\n" |
||||
"{\n" |
||||
" ::google::protobuf::scoped_ptr<$map_classname$> entry;\n" |
||||
" for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n" |
||||
" it = $name$().begin(); it != $name$().end(); ++it) {\n" |
||||
" entry.reset($name$_.New$wrapper$(it->first, it->second));\n" |
||||
" total_size += ::google::protobuf::internal::WireFormatLite::\n" |
||||
" $declared_type$SizeNoVirtual(*entry);\n" |
||||
" }\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,75 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MAP_FIELD_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_MAP_FIELD_H__ |
||||
|
||||
#include <map> |
||||
#include <string> |
||||
|
||||
#include <google/protobuf/compiler/cpp/cpp_message_field.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace cpp { |
||||
|
||||
class MapFieldGenerator : public FieldGenerator { |
||||
public: |
||||
explicit MapFieldGenerator(const FieldDescriptor* descriptor, |
||||
const Options& options); |
||||
~MapFieldGenerator(); |
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
void GeneratePrivateMembers(io::Printer* printer) const; |
||||
void GenerateAccessorDeclarations(io::Printer* printer) const; |
||||
void GenerateInlineAccessorDefinitions(io::Printer* printer) const; |
||||
void GenerateClearingCode(io::Printer* printer) const; |
||||
void GenerateMergingCode(io::Printer* printer) const; |
||||
void GenerateSwappingCode(io::Printer* printer) const; |
||||
void GenerateConstructorCode(io::Printer* printer) const; |
||||
void GenerateMergeFromCodedStream(io::Printer* printer) const; |
||||
void GenerateSerializeWithCachedSizes(io::Printer* printer) const; |
||||
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; |
||||
void GenerateByteSize(io::Printer* printer) const; |
||||
|
||||
private: |
||||
const FieldDescriptor* descriptor_; |
||||
map<string, string> variables_; |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator); |
||||
}; |
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_MAP_FIELD_H__
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,282 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_MAP_H__ |
||||
#define GOOGLE_PROTOBUF_MAP_H__ |
||||
|
||||
#include <vector> |
||||
|
||||
#include <google/protobuf/map_type_handler.h> |
||||
#include <google/protobuf/stubs/hash.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
|
||||
template <typename Key, typename T> |
||||
class Map; |
||||
|
||||
template <typename Enum> struct is_proto_enum; |
||||
|
||||
namespace internal { |
||||
template <typename K, typename V, FieldDescriptor::Type KeyProto, |
||||
FieldDescriptor::Type ValueProto, int default_enum_value> |
||||
class MapField; |
||||
} |
||||
|
||||
// This is the class for google::protobuf::Map's internal value_type. Instead of using
|
||||
// std::pair as value_type, we use this class which provides us more control of
|
||||
// its process of construction and destruction.
|
||||
template <typename Key, typename T> |
||||
class MapPair { |
||||
public: |
||||
typedef Key first_type; |
||||
typedef T second_type; |
||||
|
||||
MapPair(const Key& other_first, const T& other_second) |
||||
: first(other_first), second(other_second) {} |
||||
|
||||
MapPair(const Key& other_first) : first(other_first), second() {} |
||||
|
||||
MapPair(const MapPair& other) |
||||
: first(other.first), second(other.second) {} |
||||
|
||||
MapPair& operator=(const MapPair& other) { |
||||
first = other.first; |
||||
second = other.second; |
||||
return *this; |
||||
} |
||||
|
||||
~MapPair() {} |
||||
|
||||
const Key first; |
||||
T second; |
||||
|
||||
private: |
||||
friend class Map<Key, T>; |
||||
}; |
||||
|
||||
// STL-like iterator implementation for google::protobuf::Map. Users should not refer to
|
||||
// this class directly; use google::protobuf::Map<Key, T>::iterator instead.
|
||||
template <typename Key, typename T> |
||||
class MapIterator { |
||||
public: |
||||
typedef MapPair<Key, T> value_type; |
||||
typedef value_type* pointer; |
||||
typedef value_type& reference; |
||||
typedef MapIterator iterator; |
||||
|
||||
// constructor
|
||||
MapIterator(const typename hash_map<Key, value_type*>::iterator& it) |
||||
: it_(it) {} |
||||
MapIterator(const MapIterator& other) : it_(other.it_) {} |
||||
MapIterator& operator=(const MapIterator& other) { |
||||
it_ = other.it_; |
||||
return *this; |
||||
} |
||||
|
||||
// deferenceable
|
||||
reference operator*() const { return *it_->second; } |
||||
pointer operator->() const { return it_->second; } |
||||
|
||||
// incrementable
|
||||
iterator& operator++() { |
||||
++it_; |
||||
return *this; |
||||
} |
||||
iterator operator++(int) { return iterator(it_++); } |
||||
|
||||
// equality_comparable
|
||||
bool operator==(const iterator& x) const { return it_ == x.it_; } |
||||
bool operator!=(const iterator& x) const { return it_ != x.it_; } |
||||
|
||||
private: |
||||
typename hash_map<Key, value_type*>::iterator it_; |
||||
|
||||
friend Map<Key, T>; |
||||
}; |
||||
|
||||
// google::protobuf::Map is an associative container type used to store protobuf map
|
||||
// fields. Its interface is similar to std::unordered_map. Users should use this
|
||||
// interface directly to visit or change map fields.
|
||||
template <typename Key, typename T> |
||||
class Map { |
||||
typedef internal::MapCppTypeHandler<T> ValueTypeHandler; |
||||
public: |
||||
typedef Key key_type; |
||||
typedef T mapped_type; |
||||
typedef MapPair<Key, T> value_type; |
||||
|
||||
typedef value_type* pointer; |
||||
typedef const value_type* const_pointer; |
||||
typedef value_type& reference; |
||||
typedef const value_type& const_reference; |
||||
|
||||
typedef MapIterator<Key, T> iterator; |
||||
typedef MapIterator<Key, T> const_iterator; |
||||
|
||||
typedef size_t size_type; |
||||
typedef hash<Key> hasher; |
||||
|
||||
Map() : default_enum_value_(0) {} |
||||
|
||||
Map(const Map& other) { |
||||
insert(other.begin(), other.end()); |
||||
} |
||||
|
||||
~Map() { clear(); } |
||||
|
||||
// Iterators
|
||||
iterator begin() { return iterator(elements_.begin()); } |
||||
iterator end() { return iterator(elements_.end()); } |
||||
const_iterator begin() const { |
||||
return const_iterator( |
||||
const_cast<hash_map<Key, value_type*>&>(elements_).begin()); |
||||
} |
||||
const_iterator end() const { |
||||
return const_iterator( |
||||
const_cast<hash_map<Key, value_type*>&>(elements_).end()); |
||||
} |
||||
const_iterator cbegin() const { return begin(); } |
||||
const_iterator cend() const { return end(); } |
||||
|
||||
// Capacity
|
||||
size_type size() const { return elements_.size(); } |
||||
bool empty() const { return elements_.empty(); } |
||||
|
||||
// Element access
|
||||
T& operator[](const key_type& key) { |
||||
value_type** value = &elements_[key]; |
||||
if (*value == NULL) { |
||||
*value = new value_type(key); |
||||
internal::MapValueInitializer<google::protobuf::is_proto_enum<T>::value, |
||||
T>::Initialize((*value)->second, |
||||
default_enum_value_); |
||||
} |
||||
return (*value)->second; |
||||
} |
||||
const T& at(const key_type& key) const { |
||||
const_iterator it = find(key); |
||||
GOOGLE_CHECK(it != end()); |
||||
return it->second; |
||||
} |
||||
T& at(const key_type& key) { |
||||
iterator it = find(key); |
||||
GOOGLE_CHECK(it != end()); |
||||
return it->second; |
||||
} |
||||
|
||||
// Lookup
|
||||
size_type count(const key_type& key) const { |
||||
return elements_.count(key); |
||||
} |
||||
const_iterator find(const key_type& key) const { |
||||
// When elements_ is a const instance, find(key) returns a const iterator.
|
||||
// However, to reduce code complexity, we use MapIterator for Map's both
|
||||
// const and non-const iterator, which only takes non-const iterator to
|
||||
// construct.
|
||||
return const_iterator( |
||||
const_cast<hash_map<Key, value_type*>&>(elements_).find(key)); |
||||
} |
||||
iterator find(const key_type& key) { |
||||
return iterator(elements_.find(key)); |
||||
} |
||||
|
||||
// insert
|
||||
std::pair<iterator, bool> insert(const value_type& value) { |
||||
iterator it = find(value.first); |
||||
if (it != end()) { |
||||
return std::pair<iterator, bool>(it, false); |
||||
} else { |
||||
return elements_.insert( |
||||
std::pair<Key, value_type*>(value.first, new value_type(value))); |
||||
} |
||||
} |
||||
template <class InputIt> |
||||
void insert(InputIt first, InputIt last) { |
||||
for (InputIt it = first; it != last; ++it) { |
||||
iterator exist_it = find(it->first); |
||||
if (exist_it == end()) { |
||||
operator[](it->first) = it->second; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Erase
|
||||
size_type erase(const key_type& key) { |
||||
typename hash_map<Key, value_type*>::iterator it = elements_.find(key); |
||||
if (it == elements_.end()) { |
||||
return 0; |
||||
} else { |
||||
delete it->second; |
||||
elements_.erase(it); |
||||
return 1; |
||||
} |
||||
} |
||||
void erase(iterator pos) { |
||||
delete pos.it_->second; |
||||
elements_.erase(pos.it_); |
||||
} |
||||
void erase(iterator first, iterator last) { |
||||
for (iterator it = first; it != last;) { |
||||
delete it.it_->second; |
||||
elements_.erase((it++).it_); |
||||
} |
||||
} |
||||
void clear() { |
||||
for (iterator it = begin(); it != end(); ++it) { |
||||
delete it.it_->second; |
||||
} |
||||
elements_.clear(); |
||||
} |
||||
|
||||
// Assign
|
||||
Map& operator=(const Map& other) { |
||||
insert(other.begin(), other.end()); |
||||
return *this; |
||||
} |
||||
|
||||
private: |
||||
// Set default enum value only for proto2 map field whose value is enum type.
|
||||
void SetDefaultEnumValue(int default_enum_value) { |
||||
default_enum_value_ = default_enum_value; |
||||
} |
||||
|
||||
hash_map<Key, value_type*> elements_; |
||||
int default_enum_value_; |
||||
|
||||
template <typename K, typename V, FieldDescriptor::Type KeyProto, |
||||
FieldDescriptor::Type ValueProto, int default_enum> |
||||
friend class LIBPROTOBUF_EXPORT internal::MapField; |
||||
}; |
||||
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_MAP_H__
|
@ -0,0 +1,449 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_MAP_ENTRY_H__ |
||||
#define GOOGLE_PROTOBUF_MAP_ENTRY_H__ |
||||
|
||||
#include <google/protobuf/reflection_ops.h> |
||||
#include <google/protobuf/map_type_handler.h> |
||||
#include <google/protobuf/wire_format_lite_inl.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
class Arena; |
||||
} |
||||
|
||||
namespace protobuf { |
||||
namespace internal { |
||||
|
||||
// This is the common base class for MapEntry. It is used by MapFieldBase in
|
||||
// reflection api, in which the static type of key and value is unknown.
|
||||
class LIBPROTOBUF_EXPORT MapEntryBase : public Message { |
||||
public: |
||||
::google::protobuf::Metadata GetMetadata() const { |
||||
::google::protobuf::Metadata metadata; |
||||
metadata.descriptor = descriptor_; |
||||
metadata.reflection = reflection_; |
||||
return metadata; |
||||
} |
||||
|
||||
protected: |
||||
MapEntryBase() : descriptor_(NULL), reflection_(NULL) { } |
||||
virtual ~MapEntryBase() {} |
||||
|
||||
const Descriptor* descriptor_; |
||||
const Reflection* reflection_; |
||||
}; |
||||
|
||||
// MapEntry is the returned google::protobuf::Message when calling AddMessage of
|
||||
// google::protobuf::Reflection. In order to let it work with generated message
|
||||
// reflection, its internal layout is the same as generated message with the
|
||||
// same fields. However, in order to decide the internal layout of key/value, we
|
||||
// need to know both their cpp type in generated api and proto type.
|
||||
//
|
||||
// cpp type | proto type | internal layout
|
||||
// int32 TYPE_INT32 int32
|
||||
// int32 TYPE_FIXED32 int32
|
||||
// FooEnum TYPE_ENUM int
|
||||
// FooMessage TYPE_MESSAGE FooMessage*
|
||||
//
|
||||
// The internal layouts of primitive types can be inferred from its proto type,
|
||||
// while we need to explicitly tell cpp type if proto type is TYPE_MESSAGE to
|
||||
// get internal layout.
|
||||
// Moreover, default_enum_value is used to initialize enum field in proto2.
|
||||
template <typename Key, typename Value, FieldDescriptor::Type KeyProtoType, |
||||
FieldDescriptor::Type ValueProtoType, int default_enum_value> |
||||
class LIBPROTOBUF_EXPORT MapEntry : public MapEntryBase { |
||||
// Handlers for key/value's proto field type. Used to infer internal layout
|
||||
// and provide parsing/serialization support.
|
||||
typedef MapProtoTypeHandler<KeyProtoType> KeyProtoHandler; |
||||
typedef MapProtoTypeHandler<ValueProtoType> ValueProtoHandler; |
||||
|
||||
// Define key/value's internal stored type. Message is the only one whose
|
||||
// internal stored type cannot be inferred from its proto type.
|
||||
typedef typename KeyProtoHandler::CppType KeyProtoHandlerCppType; |
||||
typedef typename ValueProtoHandler::CppType ValueProtoHandlerCppType; |
||||
static const bool kIsKeyMessage = KeyProtoHandler::kIsMessage; |
||||
static const bool kIsValueMessage = ValueProtoHandler::kIsMessage; |
||||
typedef typename MapIf<kIsKeyMessage, Key, KeyProtoHandlerCppType>::type |
||||
KeyCppType; |
||||
typedef typename MapIf<kIsValueMessage, Value, ValueProtoHandlerCppType>::type |
||||
ValCppType; |
||||
|
||||
// Handlers for key/value's internal stored type. Provide utilities to
|
||||
// manipulate internal stored type. We need it because some types are stored
|
||||
// as values and others are stored as pointers (Message and string), but we
|
||||
// need to keep the code in MapEntry unified instead of providing different
|
||||
// codes for each type.
|
||||
typedef MapCppTypeHandler<KeyCppType> KeyCppHandler; |
||||
typedef MapCppTypeHandler<ValCppType> ValueCppHandler; |
||||
|
||||
// Define internal memory layout. Strings and messages are stored as
|
||||
// pointers, while other types are stored as values.
|
||||
static const bool kKeyIsStringOrMessage = KeyCppHandler::kIsStringOrMessage; |
||||
static const bool kValIsStringOrMessage = ValueCppHandler::kIsStringOrMessage; |
||||
typedef typename MapIf<kKeyIsStringOrMessage, KeyCppType*, KeyCppType>::type |
||||
KeyBase; |
||||
typedef typename MapIf<kValIsStringOrMessage, ValCppType*, ValCppType>::type |
||||
ValueBase; |
||||
|
||||
// Abbreviation for MapEntry
|
||||
typedef typename google::protobuf::internal::MapEntry< |
||||
Key, Value, KeyProtoType, ValueProtoType, default_enum_value> EntryType; |
||||
|
||||
// Constants for field number.
|
||||
static const int kKeyFieldNumber = 1; |
||||
static const int kValueFieldNumber = 2; |
||||
|
||||
// Constants for field tag.
|
||||
static const uint8 kKeyTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG( |
||||
kKeyFieldNumber, KeyProtoHandler::kWireType); |
||||
static const uint8 kValueTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG( |
||||
kValueFieldNumber, ValueProtoHandler::kWireType); |
||||
static const int kTagSize = 1; |
||||
|
||||
public: |
||||
~MapEntry() { |
||||
if (this == default_instance_) { |
||||
delete reflection_; |
||||
} else { |
||||
KeyCppHandler::Delete(key_); |
||||
ValueCppHandler::Delete(value_); |
||||
} |
||||
} |
||||
|
||||
// accessors ======================================================
|
||||
|
||||
inline void set_key(const KeyCppType& key) { |
||||
KeyCppHandler::EnsureMutable(&key_); |
||||
KeyCppHandler::Merge(key, &key_); |
||||
set_has_key(); |
||||
} |
||||
virtual inline const KeyCppType& key() const { |
||||
return KeyCppHandler::Reference(key_); |
||||
} |
||||
inline KeyCppType* mutable_key() { |
||||
set_has_key(); |
||||
KeyCppHandler::EnsureMutable(&key_); |
||||
return KeyCppHandler::Pointer(key_); |
||||
} |
||||
inline void set_value(const ValCppType& value) { |
||||
ValueCppHandler::EnsureMutable(&value_); |
||||
ValueCppHandler::Merge(value, &value_); |
||||
set_has_value(); |
||||
} |
||||
virtual inline const ValCppType& value() const { |
||||
GOOGLE_CHECK(default_instance_ != NULL); |
||||
return ValueCppHandler::DefaultIfNotInitialized(value_, |
||||
default_instance_->value_); |
||||
} |
||||
inline ValCppType* mutable_value() { |
||||
set_has_value(); |
||||
ValueCppHandler::EnsureMutable(&value_); |
||||
return ValueCppHandler::Pointer(value_); |
||||
} |
||||
|
||||
// implements Message =============================================
|
||||
|
||||
bool MergePartialFromCodedStream(::google::protobuf::io::CodedInputStream* input) { |
||||
uint32 tag; |
||||
|
||||
for (;;) { |
||||
// 1) corrupted data: return false;
|
||||
// 2) unknown field: skip without putting into unknown field set;
|
||||
// 3) unknown enum value: keep it in parsing. In proto2, caller should
|
||||
// check the value and put this entry into containing message's unknown
|
||||
// field set if the value is an unknown enum. In proto3, caller doesn't
|
||||
// need to care whether the value is unknown enum;
|
||||
// 4) missing key/value: missed key/value will have default value. caller
|
||||
// should take this entry as if key/value is set to default value.
|
||||
tag = input->ReadTag(); |
||||
switch (tag) { |
||||
case kKeyTag: |
||||
if (!KeyProtoHandler::Read(input, mutable_key())) return false; |
||||
set_has_key(); |
||||
if (!input->ExpectTag(kValueTag)) break; |
||||
GOOGLE_FALLTHROUGH_INTENDED; |
||||
|
||||
case kValueTag: |
||||
if (!ValueProtoHandler::Read(input, mutable_value())) return false; |
||||
set_has_value(); |
||||
if (input->ExpectAtEnd()) return true; |
||||
break; |
||||
|
||||
default: |
||||
if (tag == 0 || |
||||
WireFormatLite::GetTagWireType(tag) == |
||||
WireFormatLite::WIRETYPE_END_GROUP) { |
||||
return true; |
||||
} |
||||
if (!WireFormatLite::SkipField(input, tag)) return false; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
int ByteSize() const { |
||||
int size = 0; |
||||
size += has_key() ? kTagSize + KeyProtoHandler::ByteSize(key()) : 0; |
||||
size += has_value() ? kTagSize + ValueProtoHandler::ByteSize(value()) : 0; |
||||
return size; |
||||
} |
||||
|
||||
void SerializeWithCachedSizes(::google::protobuf::io::CodedOutputStream* output) const { |
||||
KeyProtoHandler::Write(kKeyFieldNumber, key(), output); |
||||
ValueProtoHandler::Write(kValueFieldNumber, value(), output); |
||||
} |
||||
|
||||
::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const { |
||||
output = KeyProtoHandler::WriteToArray(kKeyFieldNumber, key(), output); |
||||
output = |
||||
ValueProtoHandler::WriteToArray(kValueFieldNumber, value(), output); |
||||
return output; |
||||
} |
||||
|
||||
int GetCachedSize() const { |
||||
int size = 0; |
||||
size += has_key() ? kTagSize + KeyProtoHandler::GetCachedSize(key()) : 0; |
||||
size += |
||||
has_value() ? kTagSize + ValueProtoHandler::GetCachedSize(value()) : 0; |
||||
return size; |
||||
} |
||||
|
||||
bool IsInitialized() const { return ValueCppHandler::IsInitialized(value_); } |
||||
|
||||
Message* New() const { |
||||
MapEntry* entry = new MapEntry; |
||||
entry->descriptor_ = descriptor_; |
||||
entry->reflection_ = reflection_; |
||||
entry->default_instance_ = default_instance_; |
||||
return entry; |
||||
} |
||||
|
||||
int SpaceUsed() const { |
||||
int size = sizeof(MapEntry); |
||||
size += KeyCppHandler::SpaceUsedInMapEntry(key_); |
||||
size += ValueCppHandler::SpaceUsedInMapEntry(value_); |
||||
return size; |
||||
} |
||||
|
||||
void CopyFrom(const ::google::protobuf::Message& from) { |
||||
Clear(); |
||||
MergeFrom(from); |
||||
} |
||||
|
||||
void MergeFrom(const ::google::protobuf::Message& from) { |
||||
GOOGLE_CHECK_NE(&from, this); |
||||
const MapEntry* source = dynamic_cast_if_available<const MapEntry*>(&from); |
||||
if (source == NULL) { |
||||
ReflectionOps::Merge(from, this); |
||||
} else { |
||||
MergeFrom(*source); |
||||
} |
||||
} |
||||
|
||||
void CopyFrom(const MapEntry& from) { |
||||
Clear(); |
||||
MergeFrom(from); |
||||
} |
||||
|
||||
void MergeFrom(const MapEntry& from) { |
||||
if (from._has_bits_[0]) { |
||||
if (from.has_key()) { |
||||
KeyCppHandler::EnsureMutable(&key_); |
||||
KeyCppHandler::Merge(from.key(), &key_); |
||||
set_has_key(); |
||||
} |
||||
if (from.has_value()) { |
||||
ValueCppHandler::EnsureMutable(&value_); |
||||
ValueCppHandler::Merge(from.value(), &value_); |
||||
set_has_value(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void Clear() { |
||||
KeyCppHandler::Clear(&key_); |
||||
ValueCppHandler::ClearMaybeByDefaultEnum(&value_, default_enum_value); |
||||
clear_has_key(); |
||||
clear_has_value(); |
||||
} |
||||
|
||||
void InitAsDefaultInstance() { |
||||
KeyCppHandler::AssignDefaultValue(&key_); |
||||
ValueCppHandler::AssignDefaultValue(&value_); |
||||
} |
||||
|
||||
// Create default MapEntry instance for given descriptor. Descriptor has to be
|
||||
// given when creating default MapEntry instance because different map field
|
||||
// may have the same type and MapEntry class. The given descriptor is needed
|
||||
// to distinguish instances of the same MapEntry class.
|
||||
static MapEntry* CreateDefaultInstance(const Descriptor* descriptor) { |
||||
MapEntry* entry = new MapEntry(); |
||||
const Reflection* reflection = new GeneratedMessageReflection( |
||||
descriptor, entry, offsets_, |
||||
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MapEntry, _has_bits_), |
||||
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MapEntry, _unknown_fields_), -1, |
||||
DescriptorPool::generated_pool(), |
||||
::google::protobuf::MessageFactory::generated_factory(), sizeof(MapEntry), -1); |
||||
entry->descriptor_ = descriptor; |
||||
entry->reflection_ = reflection; |
||||
entry->default_instance_ = entry; |
||||
entry->InitAsDefaultInstance(); |
||||
return entry; |
||||
} |
||||
|
||||
// Create a MapEntry for given key and value from google::protobuf::Map in
|
||||
// serialization. This function is only called when value is enum. Enum is
|
||||
// treated differently because its type in MapEntry is int and its type in
|
||||
// google::protobuf::Map is enum. We cannot create a reference to int from an enum.
|
||||
static MapEntry* EnumWrap(const Key& key, const Value value) { |
||||
return new MapEnumEntryWrapper<Key, Value, KeyProtoType, ValueProtoType, |
||||
default_enum_value>(key, value); |
||||
} |
||||
|
||||
// Like above, but for all the other types. This avoids value copy to create
|
||||
// MapEntry from google::protobuf::Map in serialization.
|
||||
static MapEntry* Wrap(const Key& key, const Value& value) { |
||||
return new MapEntryWrapper<Key, Value, KeyProtoType, ValueProtoType, |
||||
default_enum_value>(key, value); |
||||
} |
||||
|
||||
protected: |
||||
void set_has_key() { _has_bits_[0] |= 0x00000001u; } |
||||
bool has_key() const { return (_has_bits_[0] & 0x00000001u) != 0; } |
||||
void clear_has_key() { _has_bits_[0] &= ~0x00000001u; } |
||||
void set_has_value() { _has_bits_[0] |= 0x00000002u; } |
||||
bool has_value() const { return (_has_bits_[0] & 0x00000002u) != 0; } |
||||
void clear_has_value() { _has_bits_[0] &= ~0x00000002u; } |
||||
|
||||
private: |
||||
// Serializing a generated message containing map field involves serializing
|
||||
// key-value pairs from google::protobuf::Map. The wire format of each key-value pair
|
||||
// after serialization should be the same as that of a MapEntry message
|
||||
// containing the same key and value inside it. However, google::protobuf::Map doesn't
|
||||
// store key and value as MapEntry message, which disables us to use existing
|
||||
// code to serialize message. In order to use existing code to serialize
|
||||
// message, we need to construct a MapEntry from key-value pair. But it
|
||||
// involves copy of key and value to construct a MapEntry. In order to avoid
|
||||
// this copy in constructing a MapEntry, we need the following class which
|
||||
// only takes references of given key and value.
|
||||
template <typename KeyNested, typename ValueNested, |
||||
FieldDescriptor::Type KeyProtoNested, |
||||
FieldDescriptor::Type ValueProtoNested, int default_enum> |
||||
class LIBPROTOBUF_EXPORT MapEntryWrapper |
||||
: public MapEntry<KeyNested, ValueNested, KeyProtoNested, |
||||
ValueProtoNested, default_enum> { |
||||
typedef MapEntry<KeyNested, ValueNested, KeyProtoNested, ValueProtoNested, |
||||
default_enum_value> Base; |
||||
typedef typename Base::KeyCppType KeyCppType; |
||||
typedef typename Base::ValCppType ValCppType; |
||||
|
||||
public: |
||||
MapEntryWrapper(const KeyNested& key, const ValueNested& value) |
||||
: key_(key), value_(value) { |
||||
Base::set_has_key(); |
||||
Base::set_has_value(); |
||||
} |
||||
inline const KeyCppType& key() const { return key_; } |
||||
inline const ValCppType& value() const { return value_; } |
||||
|
||||
private: |
||||
const Key& key_; |
||||
const Value& value_; |
||||
}; |
||||
|
||||
// Like above, but for enum value only, which stores value instead of
|
||||
// reference of value field inside. This is needed because the type of value
|
||||
// field in constructor is an enum, while we need to store it as an int. If we
|
||||
// initialize a reference to int with a reference to enum, compiler will
|
||||
// generate a temporary int from enum and initialize the reference to int with
|
||||
// the temporary.
|
||||
template <typename KeyNested, typename ValueNested, |
||||
FieldDescriptor::Type KeyProtoNested, |
||||
FieldDescriptor::Type ValueProtoNested, int default_enum> |
||||
class LIBPROTOBUF_EXPORT MapEnumEntryWrapper |
||||
: public MapEntry<KeyNested, ValueNested, KeyProtoNested, |
||||
ValueProtoNested, default_enum> { |
||||
typedef MapEntry<KeyNested, ValueNested, KeyProtoNested, ValueProtoNested, |
||||
default_enum> Base; |
||||
typedef typename Base::KeyCppType KeyCppType; |
||||
typedef typename Base::ValCppType ValCppType; |
||||
|
||||
public: |
||||
MapEnumEntryWrapper(const KeyNested& key, const ValueNested& value) |
||||
: key_(key), value_(value) { |
||||
Base::set_has_key(); |
||||
Base::set_has_value(); |
||||
} |
||||
inline const KeyCppType& key() const { return key_; } |
||||
inline const ValCppType& value() const { return value_; } |
||||
|
||||
private: |
||||
const KeyCppType& key_; |
||||
const ValCppType value_; |
||||
}; |
||||
|
||||
MapEntry() : default_instance_(NULL) { |
||||
KeyCppHandler::Initialize(&key_); |
||||
ValueCppHandler::InitializeMaybeByDefaultEnum(&value_, default_enum_value); |
||||
_has_bits_[0] = 0; |
||||
} |
||||
|
||||
KeyBase key_; |
||||
ValueBase value_; |
||||
static int offsets_[2]; |
||||
UnknownFieldSet _unknown_fields_; |
||||
uint32 _has_bits_[1]; |
||||
MapEntry* default_instance_; |
||||
|
||||
friend class ::google::protobuf::Arena; |
||||
template <typename K, typename V, |
||||
FieldDescriptor::Type KType, |
||||
FieldDescriptor::Type VType, int default_enum> |
||||
friend class LIBPROTOBUF_EXPORT internal::MapField; |
||||
friend class LIBPROTOBUF_EXPORT internal::GeneratedMessageReflection; |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntry); |
||||
}; |
||||
|
||||
template <typename Key, typename Value, FieldDescriptor::Type KeyProtoType, |
||||
FieldDescriptor::Type ValueProtoType, int default_enum_value> |
||||
int MapEntry<Key, Value, KeyProtoType, ValueProtoType, |
||||
default_enum_value>::offsets_[2] = { |
||||
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MapEntry, key_), |
||||
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MapEntry, value_), |
||||
}; |
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_MAP_ENTRY_H__
|
@ -0,0 +1,113 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <google/protobuf/map_field.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace internal { |
||||
|
||||
MapFieldBase::~MapFieldBase() { |
||||
if (repeated_field_ != NULL) delete repeated_field_; |
||||
} |
||||
|
||||
const RepeatedPtrFieldBase& MapFieldBase::GetRepeatedField() const { |
||||
SyncRepeatedFieldWithMap(); |
||||
return *repeated_field_; |
||||
} |
||||
|
||||
RepeatedPtrFieldBase* MapFieldBase::MutableRepeatedField() { |
||||
SyncRepeatedFieldWithMap(); |
||||
SetRepeatedDirty(); |
||||
return repeated_field_; |
||||
} |
||||
|
||||
int MapFieldBase::SpaceUsedExcludingSelf() const { |
||||
mutex_.Lock(); |
||||
int size = SpaceUsedExcludingSelfNoLock(); |
||||
mutex_.Unlock(); |
||||
return size; |
||||
} |
||||
|
||||
int MapFieldBase::SpaceUsedExcludingSelfNoLock() const { |
||||
if (repeated_field_ != NULL) { |
||||
return repeated_field_->SpaceUsedExcludingSelf(); |
||||
} else { |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
void MapFieldBase::InitMetadataOnce() const { |
||||
GOOGLE_CHECK(entry_descriptor_ != NULL); |
||||
GOOGLE_CHECK(assign_descriptor_callback_ != NULL); |
||||
(*assign_descriptor_callback_)(); |
||||
} |
||||
|
||||
void MapFieldBase::SetMapDirty() { state_ = STATE_MODIFIED_MAP; } |
||||
|
||||
void MapFieldBase::SetRepeatedDirty() { state_ = STATE_MODIFIED_REPEATED; } |
||||
|
||||
void* MapFieldBase::MutableRepeatedPtrField() const { return repeated_field_; } |
||||
|
||||
void MapFieldBase::SyncRepeatedFieldWithMap() const { |
||||
Atomic32 state = google::protobuf::internal::NoBarrier_Load(&state_); |
||||
if (state == STATE_MODIFIED_MAP) { |
||||
mutex_.Lock(); |
||||
// Double check state, because another thread may have seen the same state
|
||||
// and done the synchronization before the current thread.
|
||||
if (state_ == STATE_MODIFIED_MAP) { |
||||
SyncRepeatedFieldWithMapNoLock(); |
||||
google::protobuf::internal::NoBarrier_Store(&state_, CLEAN); |
||||
} |
||||
mutex_.Unlock(); |
||||
} |
||||
} |
||||
|
||||
void MapFieldBase::SyncRepeatedFieldWithMapNoLock() const { |
||||
if (repeated_field_ == NULL) repeated_field_ = new RepeatedPtrField<Message>; |
||||
} |
||||
|
||||
void MapFieldBase::SyncMapWithRepeatedField() const { |
||||
Atomic32 state = google::protobuf::internal::NoBarrier_Load(&state_); |
||||
if (state == STATE_MODIFIED_REPEATED) { |
||||
mutex_.Lock(); |
||||
// Double check state, because another thread may have seen the same state
|
||||
// and done the synchronization before the current thread.
|
||||
if (state_ == STATE_MODIFIED_REPEATED) { |
||||
SyncMapWithRepeatedFieldNoLock(); |
||||
google::protobuf::internal::NoBarrier_Store(&state_, CLEAN); |
||||
} |
||||
mutex_.Unlock(); |
||||
} |
||||
} |
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,220 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_MAP_FIELD_H__ |
||||
#define GOOGLE_PROTOBUF_MAP_FIELD_H__ |
||||
|
||||
#include <google/protobuf/stubs/atomicops.h> |
||||
#include <google/protobuf/stubs/common.h> |
||||
#include <google/protobuf/generated_message_reflection.h> |
||||
#include <google/protobuf/map.h> |
||||
#include <google/protobuf/map_entry.h> |
||||
#include <google/protobuf/message.h> |
||||
#include <google/protobuf/repeated_field.h> |
||||
#include <google/protobuf/unknown_field_set.h> |
||||
|
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
|
||||
namespace internal { |
||||
|
||||
class ContendedMapCleanTest; |
||||
class GeneratedMessageReflection; |
||||
class MapFieldAccessor; |
||||
|
||||
// This class provides accesss to map field using reflection, which is the same
|
||||
// as those provided for RepeatedPtrField<Message>. It is used for internal
|
||||
// reflection implentation only. Users should never use this directly.
|
||||
class LIBPROTOBUF_EXPORT MapFieldBase { |
||||
public: |
||||
MapFieldBase() |
||||
: base_map_(NULL), |
||||
repeated_field_(NULL), |
||||
entry_descriptor_(NULL), |
||||
assign_descriptor_callback_(NULL), |
||||
state_(STATE_MODIFIED_MAP) {} |
||||
virtual ~MapFieldBase(); |
||||
|
||||
// Returns reference to internal repeated field. Data written using
|
||||
// google::protobuf::Map's api prior to calling this function is guarantted to be
|
||||
// included in repeated field.
|
||||
const RepeatedPtrFieldBase& GetRepeatedField() const; |
||||
|
||||
// Like above. Returns mutable pointer to the internal repeated field.
|
||||
RepeatedPtrFieldBase* MutableRepeatedField(); |
||||
|
||||
// Returns the number of bytes used by the repeated field, excluding
|
||||
// sizeof(*this)
|
||||
int SpaceUsedExcludingSelf() const; |
||||
|
||||
protected: |
||||
// Gets the size of space used by map field.
|
||||
virtual int SpaceUsedExcludingSelfNoLock() const; |
||||
|
||||
// Synchronizes the content in Map to RepeatedPtrField if there is any change
|
||||
// to Map after last synchronization.
|
||||
void SyncRepeatedFieldWithMap() const; |
||||
virtual void SyncRepeatedFieldWithMapNoLock() const; |
||||
|
||||
// Synchronizes the content in RepeatedPtrField to Map if there is any change
|
||||
// to RepeatedPtrField after last synchronization.
|
||||
void SyncMapWithRepeatedField() const; |
||||
virtual void SyncMapWithRepeatedFieldNoLock() const {} |
||||
|
||||
// Tells MapFieldBase that there is new change to Map.
|
||||
void SetMapDirty(); |
||||
|
||||
// Tells MapFieldBase that there is new change to RepeatedPTrField.
|
||||
void SetRepeatedDirty(); |
||||
|
||||
// Provides derived class the access to repeated field.
|
||||
void* MutableRepeatedPtrField() const; |
||||
|
||||
// Creates descriptor for only one time.
|
||||
void InitMetadataOnce() const; |
||||
|
||||
enum State { |
||||
STATE_MODIFIED_MAP = 0, // map has newly added data that has not been
|
||||
// synchronized to repeated field
|
||||
STATE_MODIFIED_REPEATED = 1, // repeated field has newly added data that
|
||||
// has not been synchronized to map
|
||||
CLEAN = 2, // data in map and repeated field are same
|
||||
}; |
||||
|
||||
mutable void* base_map_; |
||||
mutable RepeatedPtrField<Message>* repeated_field_; |
||||
// MapEntry can only be created from MapField. To create MapEntry, MapField
|
||||
// needs to know its descriptor, because MapEntry is not generated class which
|
||||
// cannot initialize its own descriptor by calling generated
|
||||
// descriptor-assign-function. Thus, we need to register a callback to
|
||||
// initialize MapEntry's descriptor.
|
||||
const Descriptor** entry_descriptor_; |
||||
void (*assign_descriptor_callback_)(); |
||||
|
||||
mutable Mutex mutex_; // The thread to synchronize map and repeated field
|
||||
// needs to get lock first;
|
||||
mutable volatile Atomic32 state_; // 0: STATE_MODIFIED_MAP
|
||||
// 1: STATE_MODIFIED_REPEATED
|
||||
// 2: CLEAN
|
||||
|
||||
private: |
||||
friend class ContendedMapCleanTest; |
||||
friend class GeneratedMessageReflection; |
||||
friend class MapFieldAccessor; |
||||
}; |
||||
|
||||
// This class provides accesss to map field using generated api. It is used for
|
||||
// internal generated message implentation only. Users should never use this
|
||||
// directly.
|
||||
template<typename Key, typename T, |
||||
FieldDescriptor::Type KeyProto, |
||||
FieldDescriptor::Type ValueProto, int default_enum_value = 0> |
||||
class LIBPROTOBUF_EXPORT MapField : public MapFieldBase { |
||||
// Handlers for key/value's proto field type.
|
||||
typedef MapProtoTypeHandler<KeyProto> KeyProtoHandler; |
||||
typedef MapProtoTypeHandler<ValueProto> ValueProtoHandler; |
||||
|
||||
// Define key/value's internal stored type.
|
||||
typedef typename KeyProtoHandler::CppType KeyHandlerCpp; |
||||
typedef typename ValueProtoHandler::CppType ValHandlerCpp; |
||||
static const bool kIsKeyMessage = KeyProtoHandler::kIsMessage; |
||||
static const bool kIsValMessage = ValueProtoHandler::kIsMessage; |
||||
typedef typename MapIf<kIsKeyMessage, Key, KeyHandlerCpp>::type KeyCpp; |
||||
typedef typename MapIf<kIsValMessage, T , ValHandlerCpp>::type ValCpp; |
||||
|
||||
// Handlers for key/value's internal stored type.
|
||||
typedef MapCppTypeHandler<KeyCpp> KeyHandler; |
||||
typedef MapCppTypeHandler<ValCpp> ValHandler; |
||||
|
||||
// Define message type for internal repeated field.
|
||||
typedef MapEntry<Key, T, KeyProto, ValueProto, default_enum_value> EntryType; |
||||
|
||||
// Enum needs to be handled differently from other types because it has
|
||||
// different exposed type in google::protobuf::Map's api and repeated field's api. For
|
||||
// details see the comment in the implementation of
|
||||
// SyncMapWithRepeatedFieldNoLocki.
|
||||
static const bool kIsValueEnum = ValueProtoHandler::kIsEnum; |
||||
typedef typename MapIf<kIsValueEnum, T, const T&>::type CastValueType; |
||||
|
||||
public: |
||||
MapField(); |
||||
// MapField doesn't own the default_entry, which means default_entry must
|
||||
// outlive the lifetime of MapField.
|
||||
MapField(const Message* default_entry); |
||||
~MapField(); |
||||
|
||||
// Accessors
|
||||
const Map<Key, T>& GetMap() const; |
||||
Map<Key, T>* MutableMap(); |
||||
|
||||
// Convenient methods for generated message implementation.
|
||||
int size() const; |
||||
void Clear(); |
||||
void MergeFrom(const MapField& other); |
||||
void Swap(MapField* other); |
||||
|
||||
// Allocates metadata only if this MapField is part of a generated message.
|
||||
void SetEntryDescriptor(const Descriptor** descriptor); |
||||
void SetAssignDescriptorCallback(void (*callback)()); |
||||
|
||||
// Set default enum value only for proto2 map field whose value is enum type.
|
||||
void SetDefaultEnumValue(); |
||||
|
||||
// Used in the implementation of parsing. Caller should take the ownership.
|
||||
EntryType* NewEntry() const; |
||||
// Used in the implementation of serializing enum value type. Caller should
|
||||
// take the ownership.
|
||||
EntryType* NewEnumEntryWrapper(const Key& key, const T t) const; |
||||
// Used in the implementation of serializing other value types. Caller should
|
||||
// take the ownership.
|
||||
EntryType* NewEntryWrapper(const Key& key, const T& t) const; |
||||
|
||||
private: |
||||
// MapField needs MapEntry's default instance to create new MapEntry.
|
||||
void InitDefaultEntryOnce() const; |
||||
|
||||
// Convenient methods to get internal google::protobuf::Map
|
||||
const Map<Key, T>& GetInternalMap() const; |
||||
Map<Key, T>* MutableInternalMap(); |
||||
|
||||
// Implements MapFieldBase
|
||||
void SyncRepeatedFieldWithMapNoLock() const; |
||||
void SyncMapWithRepeatedFieldNoLock() const; |
||||
int SpaceUsedExcludingSelfNoLock() const; |
||||
|
||||
mutable const EntryType* default_entry_; |
||||
}; |
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_MAP_FIELD_H__
|
@ -0,0 +1,269 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_MAP_FIELD_INL_H__ |
||||
#define GOOGLE_PROTOBUF_MAP_FIELD_INL_H__ |
||||
|
||||
#include <memory> |
||||
#ifndef _SHARED_PTR_H |
||||
#include <google/protobuf/stubs/shared_ptr.h> |
||||
#endif |
||||
|
||||
#include <google/protobuf/map_field.h> |
||||
#include <google/protobuf/map_type_handler.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace internal { |
||||
|
||||
template <typename Key, typename T, FieldDescriptor::Type KeyProto, |
||||
FieldDescriptor::Type ValueProto, int default_enum_value> |
||||
MapField<Key, T, KeyProto, ValueProto, default_enum_value>::MapField() |
||||
: default_entry_(NULL) { |
||||
MapFieldBase::base_map_ = new Map<Key, T>; |
||||
SetDefaultEnumValue(); |
||||
} |
||||
|
||||
template <typename Key, typename T, FieldDescriptor::Type KeyProto, |
||||
FieldDescriptor::Type ValueProto, int default_enum_value> |
||||
MapField<Key, T, KeyProto, ValueProto, default_enum_value>::MapField( |
||||
const Message* default_entry) |
||||
: default_entry_(down_cast<const EntryType*>(default_entry)) { |
||||
MapFieldBase::base_map_ = new Map<Key, T>; |
||||
SetDefaultEnumValue(); |
||||
} |
||||
|
||||
template <typename Key, typename T, FieldDescriptor::Type KeyProto, |
||||
FieldDescriptor::Type ValueProto, int default_enum_value> |
||||
MapField<Key, T, KeyProto, ValueProto, default_enum_value>::~MapField() { |
||||
delete reinterpret_cast<Map<Key, T>*>(MapFieldBase::base_map_); |
||||
} |
||||
|
||||
template <typename Key, typename T, FieldDescriptor::Type KeyProto, |
||||
FieldDescriptor::Type ValueProto, int default_enum_value> |
||||
int MapField<Key, T, KeyProto, ValueProto, default_enum_value>::size() const { |
||||
SyncMapWithRepeatedField(); |
||||
return GetInternalMap().size(); |
||||
} |
||||
|
||||
template <typename Key, typename T, FieldDescriptor::Type KeyProto, |
||||
FieldDescriptor::Type ValueProto, int default_enum_value> |
||||
void MapField<Key, T, KeyProto, ValueProto, default_enum_value>::Clear() { |
||||
SyncMapWithRepeatedField(); |
||||
MutableInternalMap()->clear(); |
||||
SetMapDirty(); |
||||
} |
||||
|
||||
template <typename Key, typename T, FieldDescriptor::Type KeyProto, |
||||
FieldDescriptor::Type ValueProto, int default_enum_value> |
||||
const Map<Key, T>& |
||||
MapField<Key, T, KeyProto, ValueProto, default_enum_value>::GetMap() const { |
||||
SyncMapWithRepeatedField(); |
||||
return GetInternalMap(); |
||||
} |
||||
|
||||
template <typename Key, typename T, FieldDescriptor::Type KeyProto, |
||||
FieldDescriptor::Type ValueProto, int default_enum_value> |
||||
Map<Key, T>* |
||||
MapField<Key, T, KeyProto, ValueProto, default_enum_value>::MutableMap() { |
||||
SyncMapWithRepeatedField(); |
||||
Map<Key, T>* result = MutableInternalMap(); |
||||
SetMapDirty(); |
||||
return result; |
||||
} |
||||
|
||||
template <typename Key, typename T, FieldDescriptor::Type KeyProto, |
||||
FieldDescriptor::Type ValueProto, int default_enum_value> |
||||
void MapField<Key, T, KeyProto, ValueProto, default_enum_value>::MergeFrom( |
||||
const MapField& other) { |
||||
SyncMapWithRepeatedField(); |
||||
other.SyncMapWithRepeatedField(); |
||||
|
||||
Map<Key, T>* map = MutableInternalMap(); |
||||
const Map<Key, T>& other_map = other.GetInternalMap(); |
||||
for (typename Map<Key, T>::const_iterator it = other_map.begin(); |
||||
it != other_map.end(); ++it) { |
||||
(*map)[it->first] = it->second; |
||||
} |
||||
SetMapDirty(); |
||||
} |
||||
|
||||
template <typename Key, typename T, FieldDescriptor::Type KeyProto, |
||||
FieldDescriptor::Type ValueProto, int default_enum_value> |
||||
void MapField<Key, T, KeyProto, ValueProto, default_enum_value>::Swap( |
||||
MapField* other) { |
||||
std::swap(repeated_field_, other->repeated_field_); |
||||
std::swap(base_map_, other->base_map_); |
||||
std::swap(state_, other->state_); |
||||
} |
||||
|
||||
template <typename Key, typename T, FieldDescriptor::Type KeyProto, |
||||
FieldDescriptor::Type ValueProto, int default_enum_value> |
||||
void |
||||
MapField<Key, T, KeyProto, ValueProto, default_enum_value>::SetEntryDescriptor( |
||||
const Descriptor** descriptor) { |
||||
entry_descriptor_ = descriptor; |
||||
} |
||||
|
||||
template <typename Key, typename T, FieldDescriptor::Type KeyProto, |
||||
FieldDescriptor::Type ValueProto, int default_enum_value> |
||||
void |
||||
MapField<Key, T, KeyProto, ValueProto, |
||||
default_enum_value>::SetAssignDescriptorCallback(void (*callback)()) { |
||||
assign_descriptor_callback_ = callback; |
||||
} |
||||
|
||||
template <typename Key, typename T, FieldDescriptor::Type KeyProto, |
||||
FieldDescriptor::Type ValueProto, int default_enum_value> |
||||
void MapField<Key, T, KeyProto, ValueProto, |
||||
default_enum_value>::SetDefaultEnumValue() { |
||||
MutableInternalMap()->SetDefaultEnumValue(default_enum_value); |
||||
} |
||||
|
||||
template <typename Key, typename T, FieldDescriptor::Type KeyProto, |
||||
FieldDescriptor::Type ValueProto, int default_enum_value> |
||||
MapEntry<Key, T, KeyProto, ValueProto, default_enum_value>* |
||||
MapField<Key, T, KeyProto, ValueProto, default_enum_value>::NewEntry() const { |
||||
// The MapEntry instance created here is only used in generated code for
|
||||
// parsing. It doesn't have default instance, descriptor or reflection,
|
||||
// because these are not needed in parsing and will prevent us from using it
|
||||
// for parsing MessageLite.
|
||||
return new EntryType(); |
||||
} |
||||
|
||||
template <typename Key, typename T, FieldDescriptor::Type KeyProto, |
||||
FieldDescriptor::Type ValueProto, int default_enum_value> |
||||
MapEntry<Key, T, KeyProto, ValueProto, default_enum_value>* |
||||
MapField<Key, T, KeyProto, ValueProto, default_enum_value>::NewEntryWrapper( |
||||
const Key& key, const T& t) const { |
||||
return EntryType::Wrap(key, t); |
||||
} |
||||
|
||||
template <typename Key, typename T, FieldDescriptor::Type KeyProto, |
||||
FieldDescriptor::Type ValueProto, int default_enum_value> |
||||
MapEntry<Key, T, KeyProto, ValueProto, default_enum_value>* |
||||
MapField<Key, T, KeyProto, ValueProto, default_enum_value>::NewEnumEntryWrapper( |
||||
const Key& key, const T t) const { |
||||
return EntryType::EnumWrap(key, t); |
||||
} |
||||
|
||||
template <typename Key, typename T, FieldDescriptor::Type KeyProto, |
||||
FieldDescriptor::Type ValueProto, int default_enum_value> |
||||
const Map<Key, T>& MapField<Key, T, KeyProto, ValueProto, |
||||
default_enum_value>::GetInternalMap() const { |
||||
return *reinterpret_cast<Map<Key, T>*>(MapFieldBase::base_map_); |
||||
} |
||||
|
||||
template <typename Key, typename T, FieldDescriptor::Type KeyProto, |
||||
FieldDescriptor::Type ValueProto, int default_enum_value> |
||||
Map<Key, T>* MapField<Key, T, KeyProto, ValueProto, |
||||
default_enum_value>::MutableInternalMap() { |
||||
return reinterpret_cast<Map<Key, T>*>(MapFieldBase::base_map_); |
||||
} |
||||
|
||||
template <typename Key, typename T, FieldDescriptor::Type KeyProto, |
||||
FieldDescriptor::Type ValueProto, int default_enum_value> |
||||
void MapField<Key, T, KeyProto, ValueProto, |
||||
default_enum_value>::SyncRepeatedFieldWithMapNoLock() const { |
||||
if (repeated_field_ == NULL) { |
||||
repeated_field_ = new RepeatedPtrField<Message>(); |
||||
} |
||||
const Map<Key, T>& map = |
||||
*static_cast<const Map<Key, T>*>(MapFieldBase::base_map_); |
||||
RepeatedPtrField<EntryType>* repeated_field = |
||||
reinterpret_cast<RepeatedPtrField<EntryType>*>(repeated_field_); |
||||
|
||||
repeated_field->Clear(); |
||||
|
||||
for (typename Map<Key, T>::const_iterator it = map.begin(); |
||||
it != map.end(); ++it) { |
||||
InitDefaultEntryOnce(); |
||||
GOOGLE_CHECK(default_entry_ != NULL); |
||||
EntryType* new_entry = down_cast<EntryType*>(default_entry_->New()); |
||||
repeated_field->AddAllocated(new_entry); |
||||
new_entry->set_key(it->first); |
||||
new_entry->set_value(it->second); |
||||
} |
||||
} |
||||
|
||||
template <typename Key, typename T, FieldDescriptor::Type KeyProto, |
||||
FieldDescriptor::Type ValueProto, int default_enum_value> |
||||
void MapField<Key, T, KeyProto, ValueProto, |
||||
default_enum_value>::SyncMapWithRepeatedFieldNoLock() const { |
||||
Map<Key, T>* map = reinterpret_cast<Map<Key, T>*>(MapFieldBase::base_map_); |
||||
RepeatedPtrField<EntryType>* repeated_field = |
||||
reinterpret_cast<RepeatedPtrField<EntryType>*>(repeated_field_); |
||||
map->clear(); |
||||
for (typename RepeatedPtrField<EntryType>::iterator it = |
||||
repeated_field->begin(); it != repeated_field->end(); ++it) { |
||||
// Cast is needed because Map's api and internal storage is different when
|
||||
// value is enum. For enum, we cannot cast an int to enum. Thus, we have to
|
||||
// copy value. For other types, they have same exposed api type and internal
|
||||
// stored type. We should not introduce value copy for them. We achieve this
|
||||
// by casting to value for enum while casting to reference for other types.
|
||||
(*map)[it->key()] = static_cast<CastValueType>(it->value()); |
||||
} |
||||
} |
||||
|
||||
template <typename Key, typename T, FieldDescriptor::Type KeyProto, |
||||
FieldDescriptor::Type ValueProto, int default_enum_value> |
||||
int MapField<Key, T, KeyProto, ValueProto, |
||||
default_enum_value>::SpaceUsedExcludingSelfNoLock() const { |
||||
int size = 0; |
||||
if (repeated_field_ != NULL) { |
||||
size += repeated_field_->SpaceUsedExcludingSelf(); |
||||
} |
||||
Map<Key, T>* map = reinterpret_cast<Map<Key, T>*>(MapFieldBase::base_map_); |
||||
size += sizeof(*map); |
||||
for (typename Map<Key, T>::iterator it = map->begin(); |
||||
it != map->end(); ++it) { |
||||
size += KeyHandler::SpaceUsedInMap(it->first); |
||||
size += ValHandler::SpaceUsedInMap(it->second); |
||||
} |
||||
return size; |
||||
} |
||||
|
||||
template <typename Key, typename T, FieldDescriptor::Type KeyProto, |
||||
FieldDescriptor::Type ValueProto, int default_enum_value> |
||||
void MapField<Key, T, KeyProto, ValueProto, |
||||
default_enum_value>::InitDefaultEntryOnce() const { |
||||
if (default_entry_ == NULL) { |
||||
InitMetadataOnce(); |
||||
GOOGLE_CHECK(*entry_descriptor_ != NULL); |
||||
default_entry_ = down_cast<const EntryType*>( |
||||
MessageFactory::generated_factory()->GetPrototype(*entry_descriptor_)); |
||||
} |
||||
} |
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_MAP_FIELD_INL_H__
|
@ -0,0 +1,470 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <map> |
||||
#include <memory> |
||||
#ifndef _SHARED_PTR_H |
||||
#include <google/protobuf/stubs/shared_ptr.h> |
||||
#endif |
||||
|
||||
#include <google/protobuf/stubs/common.h> |
||||
#include <google/protobuf/map.h> |
||||
#include <google/protobuf/map_unittest.pb.h> |
||||
#include <google/protobuf/map_test_util.h> |
||||
#include <google/protobuf/unittest.pb.h> |
||||
#include <google/protobuf/map_field_inl.h> |
||||
#include <google/protobuf/message.h> |
||||
#include <google/protobuf/repeated_field.h> |
||||
#include <gtest/gtest.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
|
||||
namespace internal { |
||||
|
||||
using unittest::TestAllTypes; |
||||
|
||||
class MapFieldBaseStub : public MapFieldBase { |
||||
public: |
||||
void SyncRepeatedFieldWithMap() const { |
||||
MapFieldBase::SyncRepeatedFieldWithMap(); |
||||
} |
||||
void SyncMapWithRepeatedField() const { |
||||
MapFieldBase::SyncMapWithRepeatedField(); |
||||
} |
||||
// Get underlined repeated field without synchronizing map.
|
||||
RepeatedPtrField<Message>* InternalRepeatedField() { |
||||
return repeated_field_; |
||||
} |
||||
// Get underlined map without synchronizing repeated field.
|
||||
template <typename MapType> |
||||
const MapType& GetMap() { |
||||
return *reinterpret_cast<MapType*>(base_map_); |
||||
} |
||||
// Get underlined map without synchronizing repeated field.
|
||||
template <typename MapType> |
||||
MapType* MutableMap() { |
||||
return reinterpret_cast<MapType*>(base_map_); |
||||
} |
||||
bool IsMapClean() { return state_ != 0; } |
||||
bool IsRepeatedClean() { return state_ != 1; } |
||||
void SetMapDirty() { state_ = 0; } |
||||
void SetRepeatedDirty() { state_ = 1; } |
||||
}; |
||||
|
||||
class MapFieldBasePrimitiveTest : public ::testing::Test { |
||||
protected: |
||||
typedef MapField<int32, int32, FieldDescriptor::TYPE_INT32, |
||||
FieldDescriptor::TYPE_INT32> MapFieldType; |
||||
|
||||
MapFieldBasePrimitiveTest() { |
||||
// Get descriptors
|
||||
map_descriptor_ = unittest::TestMap::descriptor() |
||||
->FindFieldByName("map_int32_int32") |
||||
->message_type(); |
||||
key_descriptor_ = map_descriptor_->FindFieldByName("key"); |
||||
value_descriptor_ = map_descriptor_->FindFieldByName("value"); |
||||
|
||||
// Build map field
|
||||
default_entry_ = |
||||
MessageFactory::generated_factory()->GetPrototype(map_descriptor_); |
||||
map_field_.reset(new MapFieldType(default_entry_)); |
||||
map_field_base_ = map_field_.get(); |
||||
map_ = map_field_->MutableMap(); |
||||
initial_value_map_[0] = 100; |
||||
initial_value_map_[1] = 101; |
||||
map_->insert(initial_value_map_.begin(), initial_value_map_.end()); |
||||
EXPECT_EQ(2, map_->size()); |
||||
} |
||||
|
||||
google::protobuf::scoped_ptr<MapFieldType> map_field_; |
||||
MapFieldBase* map_field_base_; |
||||
Map<int32, int32>* map_; |
||||
const Descriptor* map_descriptor_; |
||||
const FieldDescriptor* key_descriptor_; |
||||
const FieldDescriptor* value_descriptor_; |
||||
const Message* default_entry_; |
||||
std::map<int32, int32> initial_value_map_; // copy of initial values inserted
|
||||
}; |
||||
|
||||
TEST_F(MapFieldBasePrimitiveTest, SpaceUsedExcludingSelf) { |
||||
EXPECT_LT(0, map_field_base_->SpaceUsedExcludingSelf()); |
||||
} |
||||
|
||||
TEST_F(MapFieldBasePrimitiveTest, GetRepeatedField) { |
||||
const RepeatedPtrField<Message>& repeated = |
||||
reinterpret_cast<const RepeatedPtrField<Message>&>( |
||||
map_field_base_->GetRepeatedField()); |
||||
EXPECT_EQ(2, repeated.size()); |
||||
for (int i = 0; i < repeated.size(); i++) { |
||||
const Message& message = repeated.Get(i); |
||||
int key = message.GetReflection()->GetInt32(message, key_descriptor_); |
||||
int value = message.GetReflection()->GetInt32(message, value_descriptor_); |
||||
EXPECT_EQ(value, initial_value_map_[key]); |
||||
} |
||||
} |
||||
|
||||
TEST_F(MapFieldBasePrimitiveTest, MutableRepeatedField) { |
||||
RepeatedPtrField<Message>* repeated = |
||||
reinterpret_cast<RepeatedPtrField<Message>*>( |
||||
map_field_base_->MutableRepeatedField()); |
||||
EXPECT_EQ(2, repeated->size()); |
||||
for (int i = 0; i < repeated->size(); i++) { |
||||
const Message& message = repeated->Get(i); |
||||
int key = message.GetReflection()->GetInt32(message, key_descriptor_); |
||||
int value = message.GetReflection()->GetInt32(message, value_descriptor_); |
||||
EXPECT_EQ(value, initial_value_map_[key]); |
||||
} |
||||
} |
||||
|
||||
namespace { |
||||
enum State { CLEAN, MAP_DIRTY, REPEATED_DIRTY }; |
||||
} // anonymous namespace
|
||||
|
||||
class MapFieldStateTest |
||||
: public testing::TestWithParam<State> { |
||||
public: |
||||
protected: |
||||
typedef MapField<int32, int32, FieldDescriptor::TYPE_INT32, |
||||
FieldDescriptor::TYPE_INT32> MapFieldType; |
||||
MapFieldStateTest() : state_(GetParam()) { |
||||
// Build map field
|
||||
const Descriptor* map_descriptor = |
||||
unittest::TestMap::descriptor() |
||||
->FindFieldByName("map_int32_int32") |
||||
->message_type(); |
||||
default_entry_ = |
||||
MessageFactory::generated_factory()->GetPrototype(map_descriptor); |
||||
map_field_.reset(new MapFieldType(default_entry_)); |
||||
map_field_base_ = map_field_.get(); |
||||
|
||||
Expect(map_field_.get(), MAP_DIRTY, 0, 0, true); |
||||
switch (state_) { |
||||
case CLEAN: |
||||
AddOneStillClean(map_field_.get()); |
||||
break; |
||||
case MAP_DIRTY: |
||||
MakeMapDirty(map_field_.get()); |
||||
break; |
||||
case REPEATED_DIRTY: |
||||
MakeRepeatedDirty(map_field_.get()); |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
} |
||||
|
||||
void AddOneStillClean(MapFieldType* map_field) { |
||||
MapFieldBase* map_field_base = map_field; |
||||
Map<int32, int32>* map = map_field->MutableMap(); |
||||
(*map)[0] = 0; |
||||
map_field_base->GetRepeatedField(); |
||||
Expect(map_field, CLEAN, 1, 1, false); |
||||
} |
||||
|
||||
void MakeMapDirty(MapFieldType* map_field) { |
||||
Map<int32, int32>* map = map_field->MutableMap(); |
||||
(*map)[0] = 0; |
||||
Expect(map_field, MAP_DIRTY, 1, 0, true); |
||||
} |
||||
|
||||
void MakeRepeatedDirty(MapFieldType* map_field) { |
||||
MakeMapDirty(map_field); |
||||
MapFieldBase* map_field_base = map_field; |
||||
map_field_base->MutableRepeatedField(); |
||||
MapFieldBaseStub* stub = |
||||
reinterpret_cast<MapFieldBaseStub*>(map_field_base); |
||||
Map<int32, int32>* map = stub->MutableMap<Map<int32, int32> >(); |
||||
map->clear(); |
||||
|
||||
Expect(map_field, REPEATED_DIRTY, 0, 1, false); |
||||
} |
||||
|
||||
void Expect(MapFieldType* map_field, State state, int map_size, |
||||
int repeated_size, bool is_repeated_null) { |
||||
MapFieldBase* map_field_base = map_field; |
||||
MapFieldBaseStub* stub = |
||||
reinterpret_cast<MapFieldBaseStub*>(map_field_base); |
||||
|
||||
Map<int32, int32>* map = stub->MutableMap<Map<int32, int32> >(); |
||||
RepeatedPtrField<Message>* repeated_field = stub->InternalRepeatedField(); |
||||
|
||||
switch (state) { |
||||
case MAP_DIRTY: |
||||
EXPECT_FALSE(stub->IsMapClean()); |
||||
EXPECT_TRUE(stub->IsRepeatedClean()); |
||||
break; |
||||
case REPEATED_DIRTY: |
||||
EXPECT_TRUE(stub->IsMapClean()); |
||||
EXPECT_FALSE(stub->IsRepeatedClean()); |
||||
break; |
||||
case CLEAN: |
||||
EXPECT_TRUE(stub->IsMapClean()); |
||||
EXPECT_TRUE(stub->IsRepeatedClean()); |
||||
break; |
||||
default: |
||||
FAIL(); |
||||
} |
||||
|
||||
EXPECT_EQ(map_size, map->size()); |
||||
if (is_repeated_null) { |
||||
EXPECT_TRUE(repeated_field == NULL); |
||||
} else { |
||||
EXPECT_EQ(repeated_size, repeated_field->size()); |
||||
} |
||||
} |
||||
|
||||
google::protobuf::scoped_ptr<MapFieldType> map_field_; |
||||
MapFieldBase* map_field_base_; |
||||
State state_; |
||||
const Message* default_entry_; |
||||
}; |
||||
|
||||
INSTANTIATE_TEST_CASE_P(MapFieldStateTestInstance, MapFieldStateTest, |
||||
::testing::Values(CLEAN, MAP_DIRTY, REPEATED_DIRTY)); |
||||
|
||||
TEST_P(MapFieldStateTest, GetMap) { |
||||
map_field_->GetMap(); |
||||
if (state_ != MAP_DIRTY) { |
||||
Expect(map_field_.get(), CLEAN, 1, 1, false); |
||||
} else { |
||||
Expect(map_field_.get(), MAP_DIRTY, 1, 0, true); |
||||
} |
||||
} |
||||
|
||||
TEST_P(MapFieldStateTest, MutableMap) { |
||||
map_field_->MutableMap(); |
||||
if (state_ != MAP_DIRTY) { |
||||
Expect(map_field_.get(), MAP_DIRTY, 1, 1, false); |
||||
} else { |
||||
Expect(map_field_.get(), MAP_DIRTY, 1, 0, true); |
||||
} |
||||
} |
||||
|
||||
TEST_P(MapFieldStateTest, MergeFromClean) { |
||||
MapFieldType other(default_entry_); |
||||
AddOneStillClean(&other); |
||||
|
||||
map_field_->MergeFrom(other); |
||||
|
||||
if (state_ != MAP_DIRTY) { |
||||
Expect(map_field_.get(), MAP_DIRTY, 1, 1, false); |
||||
} else { |
||||
Expect(map_field_.get(), MAP_DIRTY, 1, 0, true); |
||||
} |
||||
|
||||
Expect(&other, CLEAN, 1, 1, false); |
||||
} |
||||
|
||||
TEST_P(MapFieldStateTest, MergeFromMapDirty) { |
||||
MapFieldType other(default_entry_); |
||||
MakeMapDirty(&other); |
||||
|
||||
map_field_->MergeFrom(other); |
||||
|
||||
if (state_ != MAP_DIRTY) { |
||||
Expect(map_field_.get(), MAP_DIRTY, 1, 1, false); |
||||
} else { |
||||
Expect(map_field_.get(), MAP_DIRTY, 1, 0, true); |
||||
} |
||||
|
||||
Expect(&other, MAP_DIRTY, 1, 0, true); |
||||
} |
||||
|
||||
TEST_P(MapFieldStateTest, MergeFromRepeatedDirty) { |
||||
MapFieldType other(default_entry_); |
||||
MakeRepeatedDirty(&other); |
||||
|
||||
map_field_->MergeFrom(other); |
||||
|
||||
if (state_ != MAP_DIRTY) { |
||||
Expect(map_field_.get(), MAP_DIRTY, 1, 1, false); |
||||
} else { |
||||
Expect(map_field_.get(), MAP_DIRTY, 1, 0, true); |
||||
} |
||||
|
||||
Expect(&other, CLEAN, 1, 1, false); |
||||
} |
||||
|
||||
TEST_P(MapFieldStateTest, SwapClean) { |
||||
MapFieldType other(default_entry_); |
||||
AddOneStillClean(&other); |
||||
|
||||
map_field_->Swap(&other); |
||||
|
||||
Expect(map_field_.get(), CLEAN, 1, 1, false); |
||||
|
||||
switch (state_) { |
||||
case CLEAN: |
||||
Expect(&other, CLEAN, 1, 1, false); |
||||
break; |
||||
case MAP_DIRTY: |
||||
Expect(&other, MAP_DIRTY, 1, 0, true); |
||||
break; |
||||
case REPEATED_DIRTY: |
||||
Expect(&other, REPEATED_DIRTY, 0, 1, false); |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
} |
||||
|
||||
TEST_P(MapFieldStateTest, SwapMapDirty) { |
||||
MapFieldType other(default_entry_); |
||||
MakeMapDirty(&other); |
||||
|
||||
map_field_->Swap(&other); |
||||
|
||||
Expect(map_field_.get(), MAP_DIRTY, 1, 0, true); |
||||
|
||||
switch (state_) { |
||||
case CLEAN: |
||||
Expect(&other, CLEAN, 1, 1, false); |
||||
break; |
||||
case MAP_DIRTY: |
||||
Expect(&other, MAP_DIRTY, 1, 0, true); |
||||
break; |
||||
case REPEATED_DIRTY: |
||||
Expect(&other, REPEATED_DIRTY, 0, 1, false); |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
} |
||||
|
||||
TEST_P(MapFieldStateTest, SwapRepeatedDirty) { |
||||
MapFieldType other(default_entry_); |
||||
MakeRepeatedDirty(&other); |
||||
|
||||
map_field_->Swap(&other); |
||||
|
||||
Expect(map_field_.get(), REPEATED_DIRTY, 0, 1, false); |
||||
|
||||
switch (state_) { |
||||
case CLEAN: |
||||
Expect(&other, CLEAN, 1, 1, false); |
||||
break; |
||||
case MAP_DIRTY: |
||||
Expect(&other, MAP_DIRTY, 1, 0, true); |
||||
break; |
||||
case REPEATED_DIRTY: |
||||
Expect(&other, REPEATED_DIRTY, 0, 1, false); |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
} |
||||
|
||||
TEST_P(MapFieldStateTest, Clear) { |
||||
map_field_->Clear(); |
||||
|
||||
if (state_ != MAP_DIRTY) { |
||||
Expect(map_field_.get(), MAP_DIRTY, 0, 1, false); |
||||
} else { |
||||
Expect(map_field_.get(), MAP_DIRTY, 0, 0, true); |
||||
} |
||||
} |
||||
|
||||
TEST_P(MapFieldStateTest, SpaceUsedExcludingSelf) { |
||||
map_field_base_->SpaceUsedExcludingSelf(); |
||||
|
||||
switch (state_) { |
||||
case CLEAN: |
||||
Expect(map_field_.get(), CLEAN, 1, 1, false); |
||||
break; |
||||
case MAP_DIRTY: |
||||
Expect(map_field_.get(), MAP_DIRTY, 1, 0, true); |
||||
break; |
||||
case REPEATED_DIRTY: |
||||
Expect(map_field_.get(), REPEATED_DIRTY, 0, 1, false); |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
} |
||||
|
||||
TEST_P(MapFieldStateTest, GetMapField) { |
||||
map_field_base_->GetRepeatedField(); |
||||
|
||||
if (state_ != REPEATED_DIRTY) { |
||||
Expect(map_field_.get(), CLEAN, 1, 1, false); |
||||
} else { |
||||
Expect(map_field_.get(), REPEATED_DIRTY, 0, 1, false); |
||||
} |
||||
} |
||||
|
||||
TEST_P(MapFieldStateTest, MutableMapField) { |
||||
map_field_base_->MutableRepeatedField(); |
||||
|
||||
if (state_ != REPEATED_DIRTY) { |
||||
Expect(map_field_.get(), REPEATED_DIRTY, 1, 1, false); |
||||
} else { |
||||
Expect(map_field_.get(), REPEATED_DIRTY, 0, 1, false); |
||||
} |
||||
} |
||||
|
||||
class MapFieldBaseStateStub : public MapFieldBaseStub { |
||||
public: |
||||
MapFieldBaseStateStub(Mutex* mutex, int* clean_counter, |
||||
int* completed_counter) |
||||
: mutex_(mutex), |
||||
clean_counter_(clean_counter), |
||||
completed_counter_(completed_counter) {} |
||||
~MapFieldBaseStateStub() {} |
||||
|
||||
protected: |
||||
void SyncRepeatedFieldWithMapNoLock() const { Clean(); } |
||||
void SyncMapWithRepeatedFieldNoLock() const { Clean(); } |
||||
|
||||
private: |
||||
void Clean() const { |
||||
{ |
||||
MutexLock lock(mutex_); |
||||
++(*clean_counter_); |
||||
} |
||||
struct timespec tm; |
||||
tm.tv_sec = 0; |
||||
tm.tv_nsec = 100000000; // 100ms
|
||||
nanosleep(&tm, NULL); |
||||
{ |
||||
MutexLock lock(mutex_); |
||||
// No other thread should have completed while this one was initializing.
|
||||
EXPECT_EQ(0, *completed_counter_); |
||||
} |
||||
} |
||||
Mutex* mutex_; |
||||
int* clean_counter_; |
||||
int* completed_counter_; |
||||
}; |
||||
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,39 @@ |
||||
// Protocol Buffers - Google's data interchange format |
||||
// Copyright 2008 Google Inc. All rights reserved. |
||||
// https://developers.google.com/protocol-buffers/ |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
syntax = "proto2"; |
||||
|
||||
option optimize_for = LITE_RUNTIME; |
||||
|
||||
package protobuf_unittest; |
||||
|
||||
message MapLite { |
||||
map<int32, int32> map_field = 1; |
||||
} |
@ -0,0 +1,68 @@ |
||||
// Protocol Buffers - Google's data interchange format |
||||
// Copyright 2008 Google Inc. All rights reserved. |
||||
// https://developers.google.com/protocol-buffers/ |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
syntax = "proto2"; |
||||
|
||||
|
||||
// We don't put this in a package within proto2 because we need to make sure |
||||
// that the generated code doesn't depend on being in the proto2 namespace. |
||||
// In map_test_util.h we do "using namespace unittest = protobuf_unittest". |
||||
package protobuf_unittest; |
||||
|
||||
enum Proto2MapEnum { |
||||
PROTO2_MAP_ENUM_FOO = 0; |
||||
PROTO2_MAP_ENUM_BAR = 1; |
||||
PROTO2_MAP_ENUM_BAZ = 2; |
||||
} |
||||
|
||||
enum Proto2MapEnumPlusExtra { |
||||
E_PROTO2_MAP_ENUM_FOO = 0; |
||||
E_PROTO2_MAP_ENUM_BAR = 1; |
||||
E_PROTO2_MAP_ENUM_BAZ = 2; |
||||
E_PROTO2_MAP_ENUM_EXTRA = 3; |
||||
} |
||||
|
||||
enum Proto2MapEnumStartWithNonZero { |
||||
PROTO2_NON_ZERO_MAP_ENUM_FOO = 1; |
||||
} |
||||
|
||||
message TestEnumMap { |
||||
map<int32, Proto2MapEnum> known_map_field = 101; |
||||
map<int32, Proto2MapEnum> unknown_map_field = 102; |
||||
} |
||||
|
||||
message TestEnumMapPlusExtra { |
||||
map<int32, Proto2MapEnumPlusExtra> known_map_field = 101; |
||||
map<int32, Proto2MapEnumPlusExtra> unknown_map_field = 102; |
||||
} |
||||
|
||||
message TestEnumStartWithNonZeroMap { |
||||
map<int32, Proto2MapEnumStartWithNonZero> map_field = 101; |
||||
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,149 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_MAP_TEST_UTIL_H__ |
||||
#define GOOGLE_PROTOBUF_MAP_TEST_UTIL_H__ |
||||
|
||||
#include <google/protobuf/map_unittest.pb.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
|
||||
namespace unittest = ::protobuf_unittest; |
||||
|
||||
class MapTestUtil { |
||||
public: |
||||
// Set every field in the message to a unique value.
|
||||
static void SetMapFields(unittest::TestMap* message); |
||||
|
||||
// Set every field in the message to a default value.
|
||||
static void SetMapFieldsInitialized(unittest::TestMap* message); |
||||
|
||||
// Modify all the map fields of the messsage (which should already have been
|
||||
// initialized with SetMapFields()).
|
||||
static void ModifyMapFields(unittest::TestMap* message); |
||||
|
||||
// Check that all fields have the values that they should have after
|
||||
// SetMapFields() is called.
|
||||
static void ExpectMapFieldsSet(const unittest::TestMap& message); |
||||
|
||||
// Check that all fields have the values that they should have after
|
||||
// SetMapFieldsInitialized() is called.
|
||||
static void ExpectMapFieldsSetInitialized( |
||||
const unittest::TestMap& message); |
||||
|
||||
// Expect that the message is modified as would be expected from
|
||||
// ModifyMapFields().
|
||||
static void ExpectMapFieldsModified(const unittest::TestMap& message); |
||||
|
||||
// Check that all fields are empty.
|
||||
static void ExpectClear(const unittest::TestMap& message); |
||||
|
||||
// Check that all map fields have the given size.
|
||||
static void ExpectMapsSize(const unittest::TestMap& message, int size); |
||||
|
||||
// Get pointers of map entries at given index.
|
||||
static std::vector<const Message*> GetMapEntries( |
||||
const unittest::TestMap& message, int index); |
||||
|
||||
// Get pointers of map entries from release.
|
||||
static std::vector<const Message*> GetMapEntriesFromRelease( |
||||
unittest::TestMap* message); |
||||
|
||||
// Like above, but use the reflection interface.
|
||||
class MapReflectionTester { |
||||
public: |
||||
// base_descriptor must be a descriptor for TestMap, which is used for
|
||||
// MapReflectionTester to fetch the FieldDescriptors needed to use the
|
||||
// reflection interface.
|
||||
explicit MapReflectionTester(const Descriptor* base_descriptor); |
||||
|
||||
void SetMapFieldsViaReflection(Message* message); |
||||
void ClearMapFieldsViaReflection(Message* message); |
||||
void ModifyMapFieldsViaReflection(Message* message); |
||||
void RemoveLastMapsViaReflection(Message* message); |
||||
void ReleaseLastMapsViaReflection(Message* message); |
||||
void SwapMapsViaReflection(Message* message); |
||||
void MutableUnknownFieldsOfMapFieldsViaReflection(Message* message); |
||||
void ExpectMapFieldsSetViaReflection(const Message& message); |
||||
void ExpectClearViaReflection(const Message& message); |
||||
void ExpectMapEntryClearViaReflection(Message* message); |
||||
|
||||
private: |
||||
const FieldDescriptor* F(const string& name); |
||||
|
||||
const Descriptor* base_descriptor_; |
||||
|
||||
const EnumValueDescriptor* map_enum_bar_; |
||||
const EnumValueDescriptor* map_enum_baz_; |
||||
const EnumValueDescriptor* map_enum_foo_; |
||||
|
||||
const FieldDescriptor* foreign_c_; |
||||
const FieldDescriptor* map_int32_int32_key_; |
||||
const FieldDescriptor* map_int32_int32_val_; |
||||
const FieldDescriptor* map_int64_int64_key_; |
||||
const FieldDescriptor* map_int64_int64_val_; |
||||
const FieldDescriptor* map_uint32_uint32_key_; |
||||
const FieldDescriptor* map_uint32_uint32_val_; |
||||
const FieldDescriptor* map_uint64_uint64_key_; |
||||
const FieldDescriptor* map_uint64_uint64_val_; |
||||
const FieldDescriptor* map_sint32_sint32_key_; |
||||
const FieldDescriptor* map_sint32_sint32_val_; |
||||
const FieldDescriptor* map_sint64_sint64_key_; |
||||
const FieldDescriptor* map_sint64_sint64_val_; |
||||
const FieldDescriptor* map_fixed32_fixed32_key_; |
||||
const FieldDescriptor* map_fixed32_fixed32_val_; |
||||
const FieldDescriptor* map_fixed64_fixed64_key_; |
||||
const FieldDescriptor* map_fixed64_fixed64_val_; |
||||
const FieldDescriptor* map_sfixed32_sfixed32_key_; |
||||
const FieldDescriptor* map_sfixed32_sfixed32_val_; |
||||
const FieldDescriptor* map_sfixed64_sfixed64_key_; |
||||
const FieldDescriptor* map_sfixed64_sfixed64_val_; |
||||
const FieldDescriptor* map_int32_float_key_; |
||||
const FieldDescriptor* map_int32_float_val_; |
||||
const FieldDescriptor* map_int32_double_key_; |
||||
const FieldDescriptor* map_int32_double_val_; |
||||
const FieldDescriptor* map_bool_bool_key_; |
||||
const FieldDescriptor* map_bool_bool_val_; |
||||
const FieldDescriptor* map_string_string_key_; |
||||
const FieldDescriptor* map_string_string_val_; |
||||
const FieldDescriptor* map_int32_bytes_key_; |
||||
const FieldDescriptor* map_int32_bytes_val_; |
||||
const FieldDescriptor* map_int32_enum_key_; |
||||
const FieldDescriptor* map_int32_enum_val_; |
||||
const FieldDescriptor* map_int32_foreign_message_key_; |
||||
const FieldDescriptor* map_int32_foreign_message_val_; |
||||
}; |
||||
}; |
||||
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_MAP_TEST_UTIL_H__
|
@ -0,0 +1,486 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_TYPE_HANDLER_H__ |
||||
#define GOOGLE_PROTOBUF_TYPE_HANDLER_H__ |
||||
|
||||
#include <google/protobuf/generated_message_util.h> |
||||
#include <google/protobuf/message.h> |
||||
#include <google/protobuf/wire_format_lite_inl.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace internal { |
||||
|
||||
// Used for compile time type selection. MapIf::type will be TrueType if Flag is
|
||||
// true and FalseType otherwise.
|
||||
template<bool Flag, typename TrueType, typename FalseType> |
||||
struct MapIf; |
||||
|
||||
template<typename TrueType, typename FalseType> |
||||
struct MapIf<true, TrueType, FalseType> { |
||||
typedef TrueType type; |
||||
}; |
||||
|
||||
template<typename TrueType, typename FalseType> |
||||
struct MapIf<false, TrueType, FalseType> { |
||||
typedef FalseType type; |
||||
}; |
||||
|
||||
// In MapField, string and message are stored as pointer while others are stored
|
||||
// as object. However, google::protobuf::Map has unified api. Functions in this class
|
||||
// convert key/value to type wanted in api regardless how it's stored
|
||||
// internally.
|
||||
template <typename Type> |
||||
class MapCommonTypeHandler { |
||||
public: |
||||
static inline Type& Reference(Type* x) { return *x; } |
||||
static inline Type& Reference(Type& x) { return x; } |
||||
static inline const Type& Reference(const Type& x) { return x; } |
||||
static inline Type* Pointer(Type* x) { return x; } |
||||
static inline Type* Pointer(Type& x) { return &x; } |
||||
static inline const Type* Pointer(const Type* x) { return x; } |
||||
static inline const Type* Pointer(const Type& x) { return &x; } |
||||
}; |
||||
|
||||
// In proto2 Map, enum needs to be initialized to given default value, while
|
||||
// other types' default value can be inferred from the type.
|
||||
template <bool IsEnum, typename Type> |
||||
class MapValueInitializer { |
||||
public: |
||||
static inline void Initialize(Type& type, int default_enum_value); |
||||
}; |
||||
|
||||
template <typename Type> |
||||
class MapValueInitializer<true, Type> { |
||||
public: |
||||
static inline void Initialize(Type& value, int default_enum_value) { |
||||
value = static_cast<Type>(default_enum_value); |
||||
} |
||||
}; |
||||
|
||||
template <typename Type> |
||||
class MapValueInitializer<false, Type> { |
||||
public: |
||||
static inline void Initialize(Type& value, int default_enum_value) {} |
||||
}; |
||||
|
||||
// Handlers for key/value stored type in MapField. ==================
|
||||
|
||||
// Handler for message
|
||||
template <typename Type> |
||||
class MapCppTypeHandler : public MapCommonTypeHandler<Type> { |
||||
public: |
||||
static const bool kIsStringOrMessage = true; |
||||
// SpaceUsedInMapEntry: Return bytes used by value in MapEntry, excluding
|
||||
// those already calculate in sizeof(MapField).
|
||||
static int SpaceUsedInMapEntry(const Type* value) { |
||||
return value->SpaceUsed(); |
||||
} |
||||
// Return bytes used by value in Map.
|
||||
static int SpaceUsedInMap(const Type& value) { return value.SpaceUsed(); } |
||||
static inline void Clear(Type** value) { |
||||
if (*value != NULL) (*value)->Type::Clear(); |
||||
} |
||||
static inline void ClearMaybeByDefaultEnum(Type** value, |
||||
int default_enum_value) { |
||||
if (*value != NULL) (*value)->Type::Clear(); |
||||
} |
||||
static inline void Merge(const Type& from, Type** to) { |
||||
(*to)->MergeFrom(from); |
||||
} |
||||
|
||||
static void Delete(const Type* ptr) { delete ptr; } |
||||
|
||||
// Assign default value to given instance.
|
||||
static inline void AssignDefaultValue(Type** value) { |
||||
*value = const_cast<Type*>(&Type::default_instance()); |
||||
} |
||||
// Initialize value when constructing MapEntry
|
||||
static inline void Initialize(Type** x) { *x = NULL; } |
||||
// Same as above, but use default_enum_value to initialize enum type value.
|
||||
static inline void InitializeMaybeByDefaultEnum( |
||||
Type** x, int default_enum_value) { |
||||
*x = NULL; |
||||
} |
||||
// Initialize value for the first time mutable accessor is called.
|
||||
static inline void EnsureMutable(Type** value) { |
||||
if (*value == NULL) *value = new Type; |
||||
} |
||||
// Return default instance if value is not initialized when calling const
|
||||
// reference accessor.
|
||||
static inline const Type& DefaultIfNotInitialized(Type* value, |
||||
Type* default_value) { |
||||
return value != NULL ? *value : *default_value; |
||||
} |
||||
// Check if all required fields have values set.
|
||||
static inline bool IsInitialized(Type* value) { |
||||
return value->IsInitialized(); |
||||
} |
||||
}; |
||||
|
||||
// Handler for string.
|
||||
template <> |
||||
class MapCppTypeHandler<string> : public MapCommonTypeHandler<string> { |
||||
public: |
||||
static const bool kIsStringOrMessage = true; |
||||
static inline void Merge(const string& from, string** to) { **to = from; } |
||||
static inline void Clear(string** value) { (*value)->clear(); } |
||||
static inline void ClearMaybeByDefaultEnum(string** value, int default_enum) { |
||||
(*value)->clear(); |
||||
} |
||||
static inline int SpaceUsedInMapEntry(const string* value) { |
||||
return sizeof(*value) + StringSpaceUsedExcludingSelf(*value); |
||||
} |
||||
static inline int SpaceUsedInMap(const string& value) { |
||||
return sizeof(value) + StringSpaceUsedExcludingSelf(value); |
||||
} |
||||
static void Delete(const string* ptr) { |
||||
if (ptr != &::google::protobuf::internal::GetEmptyString()) delete ptr; |
||||
} |
||||
static inline void AssignDefaultValue(string** value) {} |
||||
static inline void Initialize(string** value) { |
||||
*value = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyString()); |
||||
} |
||||
static inline void InitializeMaybeByDefaultEnum( |
||||
string** value, int default_enum_value) { |
||||
*value = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyString()); |
||||
} |
||||
static inline void EnsureMutable(string** value) { |
||||
if (*value == &::google::protobuf::internal::GetEmptyString()) *value = new string; |
||||
} |
||||
static inline const string& DefaultIfNotInitialized(string* value, |
||||
string* default_value) { |
||||
return value != default_value ? *value : *default_value; |
||||
} |
||||
static inline bool IsInitialized(string* value) { return true; } |
||||
}; |
||||
|
||||
// Base class for primitive type handlers.
|
||||
template <typename Type> |
||||
class MapPrimitiveTypeHandler : public MapCommonTypeHandler<Type> { |
||||
public: |
||||
static const bool kIsStringOrMessage = false; |
||||
static inline void Delete(const Type& x) {} |
||||
static inline void Merge(const Type& from, Type* to) { *to = from; } |
||||
static inline int SpaceUsedInMapEntry(const Type& value) { return 0; } |
||||
static inline int SpaceUsedInMap(const Type& value) { return sizeof(Type); } |
||||
static inline void AssignDefaultValue(Type* value) {} |
||||
static inline const Type& DefaultIfNotInitialized( |
||||
const Type& value, const Type& default_value) { |
||||
return value; |
||||
} |
||||
static inline bool IsInitialized(const Type& value) { return true; } |
||||
}; |
||||
|
||||
// Handlers for primitive types.
|
||||
#define PRIMITIVE_HANDLER(CType) \ |
||||
template <> \
|
||||
class MapCppTypeHandler<CType> : public MapPrimitiveTypeHandler<CType> { \
|
||||
public: \
|
||||
static inline void Clear(CType* value) { *value = 0; } \
|
||||
static inline void ClearMaybeByDefaultEnum(CType* value, \
|
||||
int default_enum_value) { \
|
||||
*value = static_cast<CType>(default_enum_value); \
|
||||
} \
|
||||
static inline void Initialize(CType* value) { *value = 0; } \
|
||||
static inline void InitializeMaybeByDefaultEnum(CType* value, \
|
||||
int default_enum_value) { \
|
||||
*value = static_cast<CType>(default_enum_value); \
|
||||
} \
|
||||
static inline void EnsureMutable(CType* value) {} \
|
||||
}; |
||||
|
||||
PRIMITIVE_HANDLER(int32 ) |
||||
PRIMITIVE_HANDLER(int64 ) |
||||
PRIMITIVE_HANDLER(uint32) |
||||
PRIMITIVE_HANDLER(uint64) |
||||
PRIMITIVE_HANDLER(double) |
||||
PRIMITIVE_HANDLER(float ) |
||||
PRIMITIVE_HANDLER(bool ) |
||||
|
||||
#undef PRIMITIVE_HANDLER |
||||
|
||||
// Define constants for given proto field type
|
||||
template <FieldDescriptor::Type Type> |
||||
class MapFieldTypeTraits {}; |
||||
|
||||
#define TYPE_TRAITS(FieldType, CType, WireFormatType, IsMessage, IsEnum) \ |
||||
template <> \
|
||||
class MapFieldTypeTraits<FieldDescriptor::TYPE_##FieldType> { \
|
||||
public: \
|
||||
typedef CType CppType; \
|
||||
static const bool kIsMessage = IsMessage; \
|
||||
static const bool kIsEnum = IsEnum; \
|
||||
static const WireFormatLite::WireType kWireType = \
|
||||
WireFormatLite::WIRETYPE_##WireFormatType; \
|
||||
}; |
||||
|
||||
TYPE_TRAITS(MESSAGE , Message, LENGTH_DELIMITED, true, false) |
||||
TYPE_TRAITS(STRING , string , LENGTH_DELIMITED, false, false) |
||||
TYPE_TRAITS(BYTES , string , LENGTH_DELIMITED, false, false) |
||||
TYPE_TRAITS(INT64 , int64 , VARINT , false, false) |
||||
TYPE_TRAITS(UINT64 , uint64 , VARINT , false, false) |
||||
TYPE_TRAITS(INT32 , int32 , VARINT , false, false) |
||||
TYPE_TRAITS(UINT32 , uint32 , VARINT , false, false) |
||||
TYPE_TRAITS(SINT64 , int64 , VARINT , false, false) |
||||
TYPE_TRAITS(SINT32 , int32 , VARINT , false, false) |
||||
TYPE_TRAITS(ENUM , int , VARINT , false, true ) |
||||
TYPE_TRAITS(DOUBLE , double , FIXED64, false, false) |
||||
TYPE_TRAITS(FLOAT , float , FIXED32, false, false) |
||||
TYPE_TRAITS(FIXED64 , uint64 , FIXED64, false, false) |
||||
TYPE_TRAITS(FIXED32 , uint32 , FIXED32, false, false) |
||||
TYPE_TRAITS(SFIXED64, int64 , FIXED64, false, false) |
||||
TYPE_TRAITS(SFIXED32, int32 , FIXED32, false, false) |
||||
TYPE_TRAITS(BOOL , bool , VARINT , false, false) |
||||
|
||||
#undef TYPE_TRAITS |
||||
|
||||
// Handler for proto field type. Define types and constants used in compile
|
||||
// time. Also define functions used in parsing and serializing.
|
||||
template <FieldDescriptor::Type Type> |
||||
class MapProtoTypeHandler { |
||||
public: |
||||
// Internal stored type in MapEntry for given proto field type.
|
||||
typedef typename MapFieldTypeTraits<Type>::CppType CppType; |
||||
|
||||
// Whether given type is a message.
|
||||
static const bool kIsMessage = MapFieldTypeTraits<Type>::kIsMessage; |
||||
|
||||
// Whether given type is an enum.
|
||||
static const bool kIsEnum = MapFieldTypeTraits<Type>::kIsEnum; |
||||
|
||||
// The wire type of given proto field type.
|
||||
static const WireFormatLite::WireType kWireType = |
||||
MapFieldTypeTraits<Type>::kWireType; |
||||
|
||||
// Functions used in parsing and serialization. ===================
|
||||
|
||||
template <typename ValueType> |
||||
static inline int ByteSize(const ValueType& value); |
||||
template <typename ValueType> |
||||
static inline int GetCachedSize(const ValueType& value); |
||||
static inline void Write(int field, const CppType& value, |
||||
io::CodedOutputStream* output); |
||||
static inline uint8* WriteToArray(int field, const CppType& value, |
||||
uint8* output); |
||||
template <typename ValueType> |
||||
static inline bool Read(io::CodedInputStream* input, ValueType* value); |
||||
}; |
||||
|
||||
template <> |
||||
template <typename ValueType> |
||||
inline int MapProtoTypeHandler<FieldDescriptor::TYPE_MESSAGE>::ByteSize( |
||||
const ValueType& value) { |
||||
return WireFormatLite::MessageSizeNoVirtual(value); |
||||
} |
||||
|
||||
#define BYTE_SIZE(FieldType, DeclaredType) \ |
||||
template <> \
|
||||
template <typename ValueType> \
|
||||
inline int MapProtoTypeHandler<FieldDescriptor::TYPE_##FieldType>::ByteSize( \
|
||||
const ValueType& value) { \
|
||||
return WireFormatLite::DeclaredType##Size(value); \
|
||||
} |
||||
|
||||
BYTE_SIZE(STRING, String) |
||||
BYTE_SIZE(BYTES , Bytes) |
||||
BYTE_SIZE(INT64 , Int64) |
||||
BYTE_SIZE(UINT64, UInt64) |
||||
BYTE_SIZE(INT32 , Int32) |
||||
BYTE_SIZE(UINT32, UInt32) |
||||
BYTE_SIZE(SINT64, SInt64) |
||||
BYTE_SIZE(SINT32, SInt32) |
||||
BYTE_SIZE(ENUM , Enum) |
||||
|
||||
#undef BYTE_SIZE |
||||
|
||||
#define FIXED_BYTE_SIZE(FieldType, DeclaredType) \ |
||||
template <> \
|
||||
template <typename ValueType> \
|
||||
inline int MapProtoTypeHandler<FieldDescriptor::TYPE_##FieldType>::ByteSize( \
|
||||
const ValueType& value) { \
|
||||
return WireFormatLite::k##DeclaredType##Size; \
|
||||
} |
||||
|
||||
FIXED_BYTE_SIZE(DOUBLE , Double) |
||||
FIXED_BYTE_SIZE(FLOAT , Float) |
||||
FIXED_BYTE_SIZE(FIXED64 , Fixed64) |
||||
FIXED_BYTE_SIZE(FIXED32 , Fixed32) |
||||
FIXED_BYTE_SIZE(SFIXED64, SFixed64) |
||||
FIXED_BYTE_SIZE(SFIXED32, SFixed32) |
||||
FIXED_BYTE_SIZE(BOOL , Bool) |
||||
|
||||
#undef FIXED_BYTE_SIZE |
||||
|
||||
template <> |
||||
template <typename ValueType> |
||||
inline int MapProtoTypeHandler<FieldDescriptor::TYPE_MESSAGE>::GetCachedSize( |
||||
const ValueType& value) { |
||||
return WireFormatLite::LengthDelimitedSize(value.GetCachedSize()); |
||||
} |
||||
|
||||
#define GET_CACHED_SIZE(FieldType, DeclaredType) \ |
||||
template <> \
|
||||
template <typename ValueType> \
|
||||
inline int \
|
||||
MapProtoTypeHandler<FieldDescriptor::TYPE_##FieldType>::GetCachedSize( \
|
||||
const ValueType& value) { \
|
||||
return WireFormatLite::DeclaredType##Size(value); \
|
||||
} |
||||
|
||||
GET_CACHED_SIZE(STRING, String) |
||||
GET_CACHED_SIZE(BYTES , Bytes) |
||||
GET_CACHED_SIZE(INT64 , Int64) |
||||
GET_CACHED_SIZE(UINT64, UInt64) |
||||
GET_CACHED_SIZE(INT32 , Int32) |
||||
GET_CACHED_SIZE(UINT32, UInt32) |
||||
GET_CACHED_SIZE(SINT64, SInt64) |
||||
GET_CACHED_SIZE(SINT32, SInt32) |
||||
GET_CACHED_SIZE(ENUM , Enum) |
||||
|
||||
#undef GET_CACHED_SIZE |
||||
|
||||
#define GET_FIXED_CACHED_SIZE(FieldType, DeclaredType) \ |
||||
template <> \
|
||||
template <typename ValueType> \
|
||||
inline int \
|
||||
MapProtoTypeHandler<FieldDescriptor::TYPE_##FieldType>::GetCachedSize( \
|
||||
const ValueType& value) { \
|
||||
return WireFormatLite::k##DeclaredType##Size; \
|
||||
} |
||||
|
||||
GET_FIXED_CACHED_SIZE(DOUBLE , Double) |
||||
GET_FIXED_CACHED_SIZE(FLOAT , Float) |
||||
GET_FIXED_CACHED_SIZE(FIXED64 , Fixed64) |
||||
GET_FIXED_CACHED_SIZE(FIXED32 , Fixed32) |
||||
GET_FIXED_CACHED_SIZE(SFIXED64, SFixed64) |
||||
GET_FIXED_CACHED_SIZE(SFIXED32, SFixed32) |
||||
GET_FIXED_CACHED_SIZE(BOOL , Bool) |
||||
|
||||
#undef GET_FIXED_CACHED_SIZE |
||||
|
||||
template <> |
||||
inline void MapProtoTypeHandler<FieldDescriptor::TYPE_MESSAGE>::Write( |
||||
int field, const Message& value, io::CodedOutputStream* output) { |
||||
WireFormatLite::WriteMessageMaybeToArray(field, value, output); |
||||
} |
||||
|
||||
template <> |
||||
inline uint8* MapProtoTypeHandler<FieldDescriptor::TYPE_MESSAGE>::WriteToArray( |
||||
int field, const Message& value, uint8* output) { |
||||
return WireFormatLite::WriteMessageToArray(field, value, output); |
||||
} |
||||
|
||||
#define WRITE_METHOD(FieldType, DeclaredType) \ |
||||
template <> \
|
||||
inline void MapProtoTypeHandler<FieldDescriptor::TYPE_##FieldType>::Write( \
|
||||
int field, const CppType& value, io::CodedOutputStream* output) { \
|
||||
return WireFormatLite::Write##DeclaredType(field, value, output); \
|
||||
} \
|
||||
template <> \
|
||||
inline uint8* \
|
||||
MapProtoTypeHandler<FieldDescriptor::TYPE_##FieldType>::WriteToArray( \
|
||||
int field, const CppType& value, uint8* output) { \
|
||||
return WireFormatLite::Write##DeclaredType##ToArray(field, value, output); \
|
||||
} |
||||
|
||||
WRITE_METHOD(STRING , String) |
||||
WRITE_METHOD(BYTES , Bytes) |
||||
WRITE_METHOD(INT64 , Int64) |
||||
WRITE_METHOD(UINT64 , UInt64) |
||||
WRITE_METHOD(INT32 , Int32) |
||||
WRITE_METHOD(UINT32 , UInt32) |
||||
WRITE_METHOD(SINT64 , SInt64) |
||||
WRITE_METHOD(SINT32 , SInt32) |
||||
WRITE_METHOD(ENUM , Enum) |
||||
WRITE_METHOD(DOUBLE , Double) |
||||
WRITE_METHOD(FLOAT , Float) |
||||
WRITE_METHOD(FIXED64 , Fixed64) |
||||
WRITE_METHOD(FIXED32 , Fixed32) |
||||
WRITE_METHOD(SFIXED64, SFixed64) |
||||
WRITE_METHOD(SFIXED32, SFixed32) |
||||
WRITE_METHOD(BOOL , Bool) |
||||
|
||||
#undef WRITE_METHOD |
||||
|
||||
template <> |
||||
template <typename ValueType> |
||||
inline bool MapProtoTypeHandler<FieldDescriptor::TYPE_MESSAGE>::Read( |
||||
io::CodedInputStream* input, ValueType* value) { |
||||
return WireFormatLite::ReadMessageNoVirtual(input, value); |
||||
} |
||||
|
||||
template <> |
||||
template <typename ValueType> |
||||
inline bool MapProtoTypeHandler<FieldDescriptor::TYPE_STRING>::Read( |
||||
io::CodedInputStream* input, ValueType* value) { |
||||
return WireFormatLite::ReadString(input, value); |
||||
} |
||||
|
||||
template <> |
||||
template <typename ValueType> |
||||
inline bool MapProtoTypeHandler<FieldDescriptor::TYPE_BYTES>::Read( |
||||
io::CodedInputStream* input, ValueType* value) { |
||||
return WireFormatLite::ReadBytes(input, value); |
||||
} |
||||
|
||||
#define READ_METHOD(FieldType) \ |
||||
template <> \
|
||||
template <typename ValueType> \
|
||||
inline bool MapProtoTypeHandler<FieldDescriptor::TYPE_##FieldType>::Read( \
|
||||
io::CodedInputStream* input, ValueType* value) { \
|
||||
return WireFormatLite::ReadPrimitive<CppType, \
|
||||
WireFormatLite::TYPE_##FieldType>( \
|
||||
input, value); \
|
||||
} |
||||
|
||||
READ_METHOD(INT64) |
||||
READ_METHOD(UINT64) |
||||
READ_METHOD(INT32) |
||||
READ_METHOD(UINT32) |
||||
READ_METHOD(SINT64) |
||||
READ_METHOD(SINT32) |
||||
READ_METHOD(ENUM) |
||||
READ_METHOD(DOUBLE) |
||||
READ_METHOD(FLOAT) |
||||
READ_METHOD(FIXED64) |
||||
READ_METHOD(FIXED32) |
||||
READ_METHOD(SFIXED64) |
||||
READ_METHOD(SFIXED32) |
||||
READ_METHOD(BOOL) |
||||
|
||||
#undef READ_METHOD |
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_TYPE_HANDLER_H__
|
@ -0,0 +1,77 @@ |
||||
// Protocol Buffers - Google's data interchange format |
||||
// Copyright 2008 Google Inc. All rights reserved. |
||||
// https://developers.google.com/protocol-buffers/ |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
syntax = "proto3"; |
||||
|
||||
|
||||
import "google/protobuf/unittest.proto"; |
||||
|
||||
// We don't put this in a package within proto2 because we need to make sure |
||||
// that the generated code doesn't depend on being in the proto2 namespace. |
||||
// In map_test_util.h we do "using namespace unittest = protobuf_unittest". |
||||
package protobuf_unittest; |
||||
|
||||
// Tests maps. |
||||
message TestMap { |
||||
map<int32 , int32 > map_int32_int32 = 1; |
||||
map<int64 , int64 > map_int64_int64 = 2; |
||||
map<uint32 , uint32 > map_uint32_uint32 = 3; |
||||
map<uint64 , uint64 > map_uint64_uint64 = 4; |
||||
map<sint32 , sint32 > map_sint32_sint32 = 5; |
||||
map<sint64 , sint64 > map_sint64_sint64 = 6; |
||||
map<fixed32 , fixed32 > map_fixed32_fixed32 = 7; |
||||
map<fixed64 , fixed64 > map_fixed64_fixed64 = 8; |
||||
map<sfixed32, sfixed32> map_sfixed32_sfixed32 = 9; |
||||
map<sfixed64, sfixed64> map_sfixed64_sfixed64 = 10; |
||||
map<int32 , float > map_int32_float = 11; |
||||
map<int32 , double > map_int32_double = 12; |
||||
map<bool , bool > map_bool_bool = 13; |
||||
map<string , string > map_string_string = 14; |
||||
map<int32 , bytes > map_int32_bytes = 15; |
||||
map<int32 , MapEnum > map_int32_enum = 16; |
||||
map<int32 , ForeignMessage> map_int32_foreign_message = 17; |
||||
} |
||||
|
||||
message TestMessageMap { |
||||
map<int32, TestAllTypes> map_int32_message = 1; |
||||
} |
||||
|
||||
// Two map fields share the same entry default instance. |
||||
message TestSameTypeMap { |
||||
map<int32, int32> map1 = 1; |
||||
map<int32, int32> map2 = 2; |
||||
} |
||||
|
||||
|
||||
enum MapEnum { |
||||
MAP_ENUM_FOO = 0; |
||||
MAP_ENUM_BAR = 1; |
||||
MAP_ENUM_BAZ = 2; |
||||
} |
Loading…
Reference in new issue