From 6ae3bde73dd9090712e22986afe866229e61d305 Mon Sep 17 00:00:00 2001 From: Feng Xiao Date: Tue, 25 Nov 2014 14:01:44 -0800 Subject: [PATCH] Fix issue 99. --- src/google/protobuf/map.h | 13 ++++++------- src/google/protobuf/map_field.h | 7 +++++++ src/google/protobuf/map_field_inl.h | 9 +++++++++ src/google/protobuf/map_test.cc | 21 +++++++++++++++++++++ src/google/protobuf/map_unittest.proto | 5 +++++ 5 files changed, 48 insertions(+), 7 deletions(-) diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h index e55a6d438..f6ae3e52e 100644 --- a/src/google/protobuf/map.h +++ b/src/google/protobuf/map.h @@ -56,7 +56,7 @@ class MapField; template class MapPair { public: - typedef Key first_type; + typedef const Key first_type; typedef T second_type; MapPair(const Key& other_first, const T& other_second) @@ -67,14 +67,13 @@ class MapPair { MapPair(const MapPair& other) : first(other.first), second(other.second) {} - MapPair& operator=(const MapPair& other) { - first = other.first; - second = other.second; - return *this; - } - ~MapPair() {} + // Implicitly convertible to std::pair. + operator std::pair() const { + return std::pair(first, second); + } + const Key first; T second; diff --git a/src/google/protobuf/map_field.h b/src/google/protobuf/map_field.h index 4ceaf4a05..0fad1351f 100644 --- a/src/google/protobuf/map_field.h +++ b/src/google/protobuf/map_field.h @@ -213,6 +213,13 @@ class LIBPROTOBUF_EXPORT MapField : public MapFieldBase { mutable const EntryType* default_entry_; }; +// True if IsInitialized() is true for value field in all elements of t. T is +// expected to be message. It's useful to have this helper here to keep the +// protobuf compiler from ever having to emit loops in IsInitialized() methods. +// We want the C++ compiler to inline this or not as it sees fit. +template +bool AllAreInitialized(const Map& t); + } // namespace internal } // namespace protobuf diff --git a/src/google/protobuf/map_field_inl.h b/src/google/protobuf/map_field_inl.h index 6f17df95b..79302e48f 100644 --- a/src/google/protobuf/map_field_inl.h +++ b/src/google/protobuf/map_field_inl.h @@ -262,6 +262,15 @@ void MapField +bool AllAreInitialized(const Map& t) { + for (typename Map::const_iterator it = t.begin(); it != t.end(); + ++it) { + if (!it->second.IsInitialized()) return false; + } + return true; +} + } // namespace internal } // namespace protobuf diff --git a/src/google/protobuf/map_test.cc b/src/google/protobuf/map_test.cc index f9544efb3..c680ccb2a 100644 --- a/src/google/protobuf/map_test.cc +++ b/src/google/protobuf/map_test.cc @@ -544,6 +544,13 @@ TEST_F(MapImplTest, EqualRange) { EXPECT_TRUE(const_map_.end() == const_range.second); } +TEST_F(MapImplTest, ConvertToStdMap) { + map_[100] = 101; + std::map std_map(map_.begin(), map_.end()); + EXPECT_EQ(1, std_map.size()); + EXPECT_EQ(101, std_map[100]); +} + // Map Field Reflection Test ======================================== static int Func(int i, int j) { @@ -1740,6 +1747,20 @@ TEST(GeneratedMapFieldTest, MessageLiteMap) { EXPECT_EQ(1, to.map_field().at(1)); } +TEST(GeneratedMapFieldTest, IsInitialized) { + unittest::TestRequiredMessageMap map_message; + + // Add an uninitialized message. + (*map_message.mutable_map_field())[0]; + EXPECT_FALSE(map_message.IsInitialized()); + + // Initialize uninitialized message + (*map_message.mutable_map_field())[0].set_a(0); + (*map_message.mutable_map_field())[0].set_b(0); + (*map_message.mutable_map_field())[0].set_c(0); + EXPECT_TRUE(map_message.IsInitialized()); +} + // Generated Message Reflection Test ================================ TEST(GeneratedMapFieldReflectionTest, SpaceUsed) { diff --git a/src/google/protobuf/map_unittest.proto b/src/google/protobuf/map_unittest.proto index 54bc44861..9232d58fe 100644 --- a/src/google/protobuf/map_unittest.proto +++ b/src/google/protobuf/map_unittest.proto @@ -75,3 +75,8 @@ enum MapEnum { MAP_ENUM_BAR = 1; MAP_ENUM_BAZ = 2; } + +// Test embeded message with required fields +message TestRequiredMessageMap { + map map_field = 1; +}