OLD | NEW |
1 // Protocol Buffers - Google's data interchange format | 1 // Protocol Buffers - Google's data interchange format |
2 // Copyright 2008 Google Inc. All rights reserved. | 2 // Copyright 2008 Google Inc. All rights reserved. |
3 // https://developers.google.com/protocol-buffers/ | 3 // https://developers.google.com/protocol-buffers/ |
4 // | 4 // |
5 // Redistribution and use in source and binary forms, with or without | 5 // Redistribution and use in source and binary forms, with or without |
6 // modification, are permitted provided that the following conditions are | 6 // modification, are permitted provided that the following conditions are |
7 // met: | 7 // met: |
8 // | 8 // |
9 // * Redistributions of source code must retain the above copyright | 9 // * Redistributions of source code must retain the above copyright |
10 // notice, this list of conditions and the following disclaimer. | 10 // notice, this list of conditions and the following disclaimer. |
(...skipping 13 matching lines...) Expand all Loading... |
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
30 | 30 |
31 #ifndef GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__ | 31 #ifndef GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__ |
32 #define GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__ | 32 #define GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__ |
33 | 33 |
| 34 #include <assert.h> |
34 #include <google/protobuf/map_type_handler.h> | 35 #include <google/protobuf/map_type_handler.h> |
35 #include <google/protobuf/wire_format_lite_inl.h> | 36 #include <google/protobuf/wire_format_lite_inl.h> |
36 | 37 |
37 namespace google { | 38 namespace google { |
38 namespace protobuf { | 39 namespace protobuf { |
39 class Arena; | 40 class Arena; |
40 namespace internal { | 41 namespace internal { |
41 template <typename Key, typename Value, | 42 template <typename Key, typename Value, |
42 WireFormatLite::FieldType kKeyFieldType, | 43 WireFormatLite::FieldType kKeyFieldType, |
43 WireFormatLite::FieldType kValueFieldType, | 44 WireFormatLite::FieldType kValueFieldType, |
44 int default_enum_value> | 45 int default_enum_value> |
45 class MapEntry; | 46 class MapEntry; |
46 template <typename Key, typename Value, | 47 template <typename Key, typename Value, |
47 WireFormatLite::FieldType kKeyFieldType, | 48 WireFormatLite::FieldType kKeyFieldType, |
48 WireFormatLite::FieldType kValueFieldType, | 49 WireFormatLite::FieldType kValueFieldType, |
49 int default_enum_value> | 50 int default_enum_value> |
50 class MapFieldLite; | 51 class MapFieldLite; |
51 } // namespace internal | 52 } // namespace internal |
52 } // namespace protobuf | 53 } // namespace protobuf |
53 | 54 |
54 namespace protobuf { | 55 namespace protobuf { |
55 namespace internal { | 56 namespace internal { |
56 | 57 |
| 58 // MoveHelper::Move is used to set *dest. It copies *src, or moves it (in |
| 59 // the C++11 sense), or swaps it. *src is left in a sane state for |
| 60 // subsequent destruction, but shouldn't be used for anything. |
| 61 template <bool is_enum, bool is_message, bool is_stringlike, typename T> |
| 62 struct MoveHelper { // primitives |
| 63 static void Move(T* src, T* dest) { *dest = *src; } |
| 64 }; |
| 65 |
| 66 template <bool is_message, bool is_stringlike, typename T> |
| 67 struct MoveHelper<true, is_message, is_stringlike, T> { // enums |
| 68 static void Move(T* src, T* dest) { *dest = *src; } |
| 69 // T is an enum here, so allow conversions to and from int. |
| 70 static void Move(T* src, int* dest) { *dest = static_cast<int>(*src); } |
| 71 static void Move(int* src, T* dest) { *dest = static_cast<T>(*src); } |
| 72 }; |
| 73 |
| 74 template <bool is_stringlike, typename T> |
| 75 struct MoveHelper<false, true, is_stringlike, T> { // messages |
| 76 static void Move(T* src, T* dest) { dest->Swap(src); } |
| 77 }; |
| 78 |
| 79 template <typename T> |
| 80 struct MoveHelper<false, false, true, T> { // strings and similar |
| 81 static void Move(T* src, T* dest) { |
| 82 #if __cplusplus >= 201103L |
| 83 *dest = std::move(*src); |
| 84 #else |
| 85 dest->swap(*src); |
| 86 #endif |
| 87 } |
| 88 }; |
| 89 |
57 // MapEntryLite is used to implement parsing and serialization of map for lite | 90 // MapEntryLite is used to implement parsing and serialization of map for lite |
58 // runtime. | 91 // runtime. |
59 template <typename Key, typename Value, | 92 template <typename Key, typename Value, |
60 WireFormatLite::FieldType kKeyFieldType, | 93 WireFormatLite::FieldType kKeyFieldType, |
61 WireFormatLite::FieldType kValueFieldType, | 94 WireFormatLite::FieldType kValueFieldType, |
62 int default_enum_value> | 95 int default_enum_value> |
63 class MapEntryLite : public MessageLite { | 96 class MapEntryLite : public MessageLite { |
64 // Provide utilities to parse/serialize key/value. Provide utilities to | 97 // Provide utilities to parse/serialize key/value. Provide utilities to |
65 // manipulate internal stored type. | 98 // manipulate internal stored type. |
66 typedef MapTypeHandler<kKeyFieldType, Key> KeyTypeHandler; | 99 typedef MapTypeHandler<kKeyFieldType, Key> KeyTypeHandler; |
(...skipping 12 matching lines...) Expand all Loading... |
79 | 112 |
80 // Constants for field number. | 113 // Constants for field number. |
81 static const int kKeyFieldNumber = 1; | 114 static const int kKeyFieldNumber = 1; |
82 static const int kValueFieldNumber = 2; | 115 static const int kValueFieldNumber = 2; |
83 | 116 |
84 // Constants for field tag. | 117 // Constants for field tag. |
85 static const uint8 kKeyTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG( | 118 static const uint8 kKeyTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG( |
86 kKeyFieldNumber, KeyTypeHandler::kWireType); | 119 kKeyFieldNumber, KeyTypeHandler::kWireType); |
87 static const uint8 kValueTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG( | 120 static const uint8 kValueTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG( |
88 kValueFieldNumber, ValueTypeHandler::kWireType); | 121 kValueFieldNumber, ValueTypeHandler::kWireType); |
89 static const int kTagSize = 1; | 122 static const size_t kTagSize = 1; |
90 | 123 |
91 public: | 124 public: |
92 ~MapEntryLite() { | 125 ~MapEntryLite() { |
93 if (this != default_instance_) { | 126 if (this != default_instance_) { |
94 if (GetArenaNoVirtual() != NULL) return; | 127 if (GetArenaNoVirtual() != NULL) return; |
95 KeyTypeHandler::DeleteNoArena(key_); | 128 KeyTypeHandler::DeleteNoArena(key_); |
96 ValueTypeHandler::DeleteNoArena(value_); | 129 ValueTypeHandler::DeleteNoArena(value_); |
97 } | 130 } |
98 } | 131 } |
99 | 132 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
131 | 164 |
132 for (;;) { | 165 for (;;) { |
133 // 1) corrupted data: return false; | 166 // 1) corrupted data: return false; |
134 // 2) unknown field: skip without putting into unknown field set; | 167 // 2) unknown field: skip without putting into unknown field set; |
135 // 3) unknown enum value: keep it in parsing. In proto2, caller should | 168 // 3) unknown enum value: keep it in parsing. In proto2, caller should |
136 // check the value and put this entry into containing message's unknown | 169 // check the value and put this entry into containing message's unknown |
137 // field set if the value is an unknown enum. In proto3, caller doesn't | 170 // field set if the value is an unknown enum. In proto3, caller doesn't |
138 // need to care whether the value is unknown enum; | 171 // need to care whether the value is unknown enum; |
139 // 4) missing key/value: missed key/value will have default value. caller | 172 // 4) missing key/value: missed key/value will have default value. caller |
140 // should take this entry as if key/value is set to default value. | 173 // should take this entry as if key/value is set to default value. |
141 tag = input->ReadTag(); | 174 tag = input->ReadTagNoLastTag(); |
142 switch (tag) { | 175 switch (tag) { |
143 case kKeyTag: | 176 case kKeyTag: |
144 if (!KeyTypeHandler::Read(input, mutable_key())) { | 177 if (!KeyTypeHandler::Read(input, mutable_key())) { |
145 return false; | 178 return false; |
146 } | 179 } |
147 set_has_key(); | 180 set_has_key(); |
148 if (!input->ExpectTag(kValueTag)) break; | 181 if (!input->ExpectTag(kValueTag)) break; |
149 GOOGLE_FALLTHROUGH_INTENDED; | 182 GOOGLE_FALLTHROUGH_INTENDED; |
150 | 183 |
151 case kValueTag: | 184 case kValueTag: |
152 if (!ValueTypeHandler::Read(input, mutable_value())) { | 185 if (!ValueTypeHandler::Read(input, mutable_value())) { |
153 return false; | 186 return false; |
154 } | 187 } |
155 set_has_value(); | 188 set_has_value(); |
156 if (input->ExpectAtEnd()) return true; | 189 if (input->ExpectAtEnd()) return true; |
157 break; | 190 break; |
158 | 191 |
159 default: | 192 default: |
160 if (tag == 0 || | 193 if (tag == 0 || |
161 WireFormatLite::GetTagWireType(tag) == | 194 WireFormatLite::GetTagWireType(tag) == |
162 WireFormatLite::WIRETYPE_END_GROUP) { | 195 WireFormatLite::WIRETYPE_END_GROUP) { |
163 return true; | 196 return true; |
164 } | 197 } |
165 if (!WireFormatLite::SkipField(input, tag)) return false; | 198 if (!WireFormatLite::SkipField(input, tag)) return false; |
166 break; | 199 break; |
167 } | 200 } |
168 } | 201 } |
169 } | 202 } |
170 | 203 |
171 int ByteSize() const { | 204 size_t ByteSizeLong() const { |
172 int size = 0; | 205 size_t size = 0; |
173 size += has_key() ? kTagSize + KeyTypeHandler::ByteSize(key()) : 0; | 206 size += has_key() ? kTagSize + KeyTypeHandler::ByteSize(key()) : 0; |
174 size += has_value() ? kTagSize + ValueTypeHandler::ByteSize(value()) : 0; | 207 size += has_value() ? kTagSize + ValueTypeHandler::ByteSize(value()) : 0; |
175 return size; | 208 return size; |
176 } | 209 } |
177 | 210 |
178 void SerializeWithCachedSizes(::google::protobuf::io::CodedOutputStream* outpu
t) const { | 211 void SerializeWithCachedSizes(::google::protobuf::io::CodedOutputStream* outpu
t) const { |
179 KeyTypeHandler::Write(kKeyFieldNumber, key(), output); | 212 KeyTypeHandler::Write(kKeyFieldNumber, key(), output); |
180 ValueTypeHandler::Write(kValueFieldNumber, value(), output); | 213 ValueTypeHandler::Write(kValueFieldNumber, value(), output); |
181 } | 214 } |
182 | 215 |
| 216 ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(bool determ
inistic, |
| 217 ::google::protobuf::uint8* ou
tput) const { |
| 218 output = KeyTypeHandler::InternalWriteToArray(kKeyFieldNumber, key(), |
| 219 deterministic, output); |
| 220 output = ValueTypeHandler::InternalWriteToArray(kValueFieldNumber, value(), |
| 221 deterministic, output); |
| 222 return output; |
| 223 } |
183 ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf:
:uint8* output) const { | 224 ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf:
:uint8* output) const { |
184 output = KeyTypeHandler::WriteToArray(kKeyFieldNumber, key(), output); | 225 return InternalSerializeWithCachedSizesToArray(false, output); |
185 output = ValueTypeHandler::WriteToArray(kValueFieldNumber, value(), output); | |
186 return output; | |
187 } | 226 } |
188 | 227 |
189 int GetCachedSize() const { | 228 int GetCachedSize() const { |
190 int size = 0; | 229 int size = 0; |
191 size += has_key() | 230 size += has_key() |
192 ? kTagSize + KeyTypeHandler::GetCachedSize(key()) | 231 ? kTagSize + KeyTypeHandler::GetCachedSize(key()) |
193 : 0; | 232 : 0; |
194 size += has_value() | 233 size += has_value() |
195 ? kTagSize + ValueTypeHandler::GetCachedSize( | 234 ? kTagSize + ValueTypeHandler::GetCachedSize( |
196 value()) | 235 value()) |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
264 | 303 |
265 // Like above, but for all the other types. This avoids value copy to create | 304 // Like above, but for all the other types. This avoids value copy to create |
266 // MapEntryLite from google::protobuf::Map in serialization. | 305 // MapEntryLite from google::protobuf::Map in serialization. |
267 static MapEntryLite* Wrap(const Key& key, const Value& value, Arena* arena) { | 306 static MapEntryLite* Wrap(const Key& key, const Value& value, Arena* arena) { |
268 return Arena::CreateMessage<MapEntryWrapper<Key, Value, kKeyFieldType, | 307 return Arena::CreateMessage<MapEntryWrapper<Key, Value, kKeyFieldType, |
269 kValueFieldType, | 308 kValueFieldType, |
270 default_enum_value> >( | 309 default_enum_value> >( |
271 arena, key, value); | 310 arena, key, value); |
272 } | 311 } |
273 | 312 |
| 313 // Parsing using MergePartialFromCodedStream, above, is not as |
| 314 // efficient as it could be. This helper class provides a speedier way. |
| 315 template <typename MapField, typename Map> |
| 316 class Parser { |
| 317 public: |
| 318 explicit Parser(MapField* mf) : mf_(mf), map_(mf->MutableMap()) {} |
| 319 |
| 320 // This does what the typical MergePartialFromCodedStream() is expected to |
| 321 // do, with the additional side-effect that if successful (i.e., if true is |
| 322 // going to be its return value) it inserts the key-value pair into map_. |
| 323 bool MergePartialFromCodedStream(::google::protobuf::io::CodedInputStream* i
nput) { |
| 324 // Look for the expected thing: a key and then a value. If it fails, |
| 325 // invoke the enclosing class's MergePartialFromCodedStream, or return |
| 326 // false if that would be pointless. |
| 327 if (input->ExpectTag(kKeyTag)) { |
| 328 if (!KeyTypeHandler::Read(input, &key_)) { |
| 329 return false; |
| 330 } |
| 331 // Peek at the next byte to see if it is kValueTag. If not, bail out. |
| 332 const void* data; |
| 333 int size; |
| 334 input->GetDirectBufferPointerInline(&data, &size); |
| 335 // We could use memcmp here, but we don't bother. The tag is one byte. |
| 336 GOOGLE_COMPILE_ASSERT(kTagSize == 1, tag_size_error); |
| 337 if (size > 0 && *reinterpret_cast<const char*>(data) == kValueTag) { |
| 338 typename Map::size_type size = map_->size(); |
| 339 value_ptr_ = &(*map_)[key_]; |
| 340 if (GOOGLE_PREDICT_TRUE(size != map_->size())) { |
| 341 // We created a new key-value pair. Fill in the value. |
| 342 typedef |
| 343 typename MapIf<ValueTypeHandler::kIsEnum, int*, Value*>::type T; |
| 344 input->Skip(kTagSize); // Skip kValueTag. |
| 345 if (!ValueTypeHandler::Read(input, |
| 346 reinterpret_cast<T>(value_ptr_))) { |
| 347 map_->erase(key_); // Failure! Undo insertion. |
| 348 return false; |
| 349 } |
| 350 if (input->ExpectAtEnd()) return true; |
| 351 return ReadBeyondKeyValuePair(input); |
| 352 } |
| 353 } |
| 354 } else { |
| 355 key_ = Key(); |
| 356 } |
| 357 |
| 358 entry_.reset(mf_->NewEntry()); |
| 359 *entry_->mutable_key() = key_; |
| 360 const bool result = entry_->MergePartialFromCodedStream(input); |
| 361 if (result) UseKeyAndValueFromEntry(); |
| 362 if (entry_->GetArena() != NULL) entry_.release(); |
| 363 return result; |
| 364 } |
| 365 |
| 366 const Key& key() const { return key_; } |
| 367 const Value& value() const { return *value_ptr_; } |
| 368 |
| 369 private: |
| 370 void UseKeyAndValueFromEntry() GOOGLE_ATTRIBUTE_COLD { |
| 371 // Update key_ in case we need it later (because key() is called). |
| 372 // This is potentially inefficient, especially if the key is |
| 373 // expensive to copy (e.g., a long string), but this is a cold |
| 374 // path, so it's not a big deal. |
| 375 key_ = entry_->key(); |
| 376 value_ptr_ = &(*map_)[key_]; |
| 377 MoveHelper<ValueTypeHandler::kIsEnum, |
| 378 ValueTypeHandler::kIsMessage, |
| 379 ValueTypeHandler::kWireType == |
| 380 WireFormatLite::WIRETYPE_LENGTH_DELIMITED, |
| 381 Value>::Move(entry_->mutable_value(), value_ptr_); |
| 382 } |
| 383 |
| 384 // After reading a key and value successfully, and inserting that data |
| 385 // into map_, we are not at the end of the input. This is unusual, but |
| 386 // allowed by the spec. |
| 387 bool ReadBeyondKeyValuePair(::google::protobuf::io::CodedInputStream* input) |
| 388 GOOGLE_ATTRIBUTE_COLD { |
| 389 typedef MoveHelper<KeyTypeHandler::kIsEnum, |
| 390 KeyTypeHandler::kIsMessage, |
| 391 KeyTypeHandler::kWireType == |
| 392 WireFormatLite::WIRETYPE_LENGTH_DELIMITED, |
| 393 Key> KeyMover; |
| 394 typedef MoveHelper<ValueTypeHandler::kIsEnum, |
| 395 ValueTypeHandler::kIsMessage, |
| 396 ValueTypeHandler::kWireType == |
| 397 WireFormatLite::WIRETYPE_LENGTH_DELIMITED, |
| 398 Value> ValueMover; |
| 399 entry_.reset(mf_->NewEntry()); |
| 400 ValueMover::Move(value_ptr_, entry_->mutable_value()); |
| 401 map_->erase(key_); |
| 402 KeyMover::Move(&key_, entry_->mutable_key()); |
| 403 const bool result = entry_->MergePartialFromCodedStream(input); |
| 404 if (result) UseKeyAndValueFromEntry(); |
| 405 if (entry_->GetArena() != NULL) entry_.release(); |
| 406 return result; |
| 407 } |
| 408 |
| 409 MapField* const mf_; |
| 410 Map* const map_; |
| 411 Key key_; |
| 412 Value* value_ptr_; |
| 413 // On the fast path entry_ is not used. And, when entry_ is used, it's set |
| 414 // to mf_->NewEntry(), so in the arena case we must call entry_.release. |
| 415 google::protobuf::scoped_ptr<MapEntryLite> entry_; |
| 416 }; |
| 417 |
274 protected: | 418 protected: |
275 void set_has_key() { _has_bits_[0] |= 0x00000001u; } | 419 void set_has_key() { _has_bits_[0] |= 0x00000001u; } |
276 bool has_key() const { return (_has_bits_[0] & 0x00000001u) != 0; } | 420 bool has_key() const { return (_has_bits_[0] & 0x00000001u) != 0; } |
277 void clear_has_key() { _has_bits_[0] &= ~0x00000001u; } | 421 void clear_has_key() { _has_bits_[0] &= ~0x00000001u; } |
278 void set_has_value() { _has_bits_[0] |= 0x00000002u; } | 422 void set_has_value() { _has_bits_[0] |= 0x00000002u; } |
279 bool has_value() const { return (_has_bits_[0] & 0x00000002u) != 0; } | 423 bool has_value() const { return (_has_bits_[0] & 0x00000002u) != 0; } |
280 void clear_has_value() { _has_bits_[0] &= ~0x00000002u; } | 424 void clear_has_value() { _has_bits_[0] &= ~0x00000002u; } |
281 | 425 |
282 private: | 426 private: |
283 // Serializing a generated message containing map field involves serializing | 427 // Serializing a generated message containing map field involves serializing |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
387 template <typename K, typename V, WireFormatLite::FieldType, | 531 template <typename K, typename V, WireFormatLite::FieldType, |
388 WireFormatLite::FieldType, int> | 532 WireFormatLite::FieldType, int> |
389 friend class internal::MapEntry; | 533 friend class internal::MapEntry; |
390 template <typename K, typename V, WireFormatLite::FieldType, | 534 template <typename K, typename V, WireFormatLite::FieldType, |
391 WireFormatLite::FieldType, int> | 535 WireFormatLite::FieldType, int> |
392 friend class internal::MapFieldLite; | 536 friend class internal::MapFieldLite; |
393 | 537 |
394 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntryLite); | 538 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntryLite); |
395 }; | 539 }; |
396 | 540 |
| 541 // Helpers for deterministic serialization ============================= |
| 542 |
| 543 // This struct can be used with any generic sorting algorithm. If the Key |
| 544 // type is relatively small and easy to copy then copying Keys into an |
| 545 // array of SortItems can be beneficial. Then all the data the sorting |
| 546 // algorithm needs to touch is in that one array. |
| 547 template <typename Key, typename PtrToKeyValuePair> struct SortItem { |
| 548 SortItem() {} |
| 549 explicit SortItem(PtrToKeyValuePair p) : first(p->first), second(p) {} |
| 550 |
| 551 Key first; |
| 552 PtrToKeyValuePair second; |
| 553 }; |
| 554 |
| 555 template <typename T> struct CompareByFirstField { |
| 556 bool operator()(const T& a, const T& b) const { |
| 557 return a.first < b.first; |
| 558 } |
| 559 }; |
| 560 |
| 561 template <typename T> struct CompareByDerefFirst { |
| 562 bool operator()(const T& a, const T& b) const { |
| 563 return a->first < b->first; |
| 564 } |
| 565 }; |
| 566 |
397 } // namespace internal | 567 } // namespace internal |
398 } // namespace protobuf | 568 } // namespace protobuf |
399 | 569 |
400 } // namespace google | 570 } // namespace google |
401 #endif // GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__ | 571 #endif // GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__ |
OLD | NEW |