parent
faf581d208
commit
f157a5651c
90 changed files with 8298 additions and 3163 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