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 10 matching lines...) Expand all Loading... |
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
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 // This file defines the map container and its helpers to support protobuf maps. | |
32 // | |
33 // The Map and MapIterator types are provided by this header file. | |
34 // Please avoid using other types defined here, unless they are public | |
35 // types within Map or MapIterator, such as Map::value_type. | |
36 | |
37 #ifndef GOOGLE_PROTOBUF_MAP_H__ | 31 #ifndef GOOGLE_PROTOBUF_MAP_H__ |
38 #define GOOGLE_PROTOBUF_MAP_H__ | 32 #define GOOGLE_PROTOBUF_MAP_H__ |
39 | 33 |
40 #include <google/protobuf/stubs/hash.h> | 34 #include <google/protobuf/stubs/hash.h> |
41 #include <iterator> | 35 #include <iterator> |
42 #include <limits> // To support Visual Studio 2008 | 36 #include <limits> // To support Visual Studio 2008 |
43 #include <set> | 37 #include <set> |
44 #include <utility> | 38 #include <utility> |
45 | 39 |
46 #include <google/protobuf/stubs/common.h> | 40 #include <google/protobuf/stubs/common.h> |
47 #include <google/protobuf/arena.h> | 41 #include <google/protobuf/arena.h> |
48 #include <google/protobuf/generated_enum_util.h> | 42 #include <google/protobuf/generated_enum_util.h> |
49 #include <google/protobuf/map_type_handler.h> | 43 #include <google/protobuf/map_type_handler.h> |
50 #include <google/protobuf/message.h> | 44 #include <google/protobuf/message.h> |
51 #include <google/protobuf/descriptor.h> | 45 #include <google/protobuf/descriptor.h> |
52 #if __cpp_exceptions && LANG_CXX11 | 46 #if __cpp_exceptions && LANG_CXX11 |
53 #include <random> | 47 #include <random> |
54 #endif | 48 #endif |
55 | 49 |
56 namespace google { | 50 namespace google { |
57 namespace protobuf { | 51 namespace protobuf { |
58 | 52 |
| 53 // The Map and MapIterator types are provided by this header file. |
| 54 // Please avoid using other types defined here, unless they are public |
| 55 // types within Map or MapIterator, such as Map::value_type. |
59 template <typename Key, typename T> | 56 template <typename Key, typename T> |
60 class Map; | 57 class Map; |
61 | 58 |
62 class MapIterator; | 59 class MapIterator; |
63 | 60 |
64 template <typename Enum> struct is_proto_enum; | 61 template <typename Enum> struct is_proto_enum; |
65 | 62 |
66 namespace internal { | 63 namespace internal { |
67 template <typename Key, typename T, | 64 template <typename Key, typename T, |
68 WireFormatLite::FieldType key_wire_type, | 65 WireFormatLite::FieldType key_wire_type, |
(...skipping 447 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
516 typedef MapPair<Key, T> value_type; | 513 typedef MapPair<Key, T> value_type; |
517 | 514 |
518 typedef value_type* pointer; | 515 typedef value_type* pointer; |
519 typedef const value_type* const_pointer; | 516 typedef const value_type* const_pointer; |
520 typedef value_type& reference; | 517 typedef value_type& reference; |
521 typedef const value_type& const_reference; | 518 typedef const value_type& const_reference; |
522 | 519 |
523 typedef size_t size_type; | 520 typedef size_t size_type; |
524 typedef hash<Key> hasher; | 521 typedef hash<Key> hasher; |
525 | 522 |
526 explicit Map(bool old_style = false) | 523 Map(bool old_style = true) |
527 : arena_(NULL), | 524 : arena_(NULL), |
528 default_enum_value_(0), | 525 default_enum_value_(0), |
529 old_style_(old_style) { | 526 old_style_(old_style) { |
530 Init(); | 527 Init(); |
531 } | 528 } |
532 explicit Map(Arena* arena, bool old_style = false) | 529 explicit Map(Arena* arena, bool old_style = true) |
533 : arena_(arena), | 530 : arena_(arena), |
534 default_enum_value_(0), | 531 default_enum_value_(0), |
535 old_style_(old_style) { | 532 old_style_(old_style) { |
536 Init(); | 533 Init(); |
537 } | 534 } |
538 Map(const Map& other) | 535 Map(const Map& other) |
539 : arena_(NULL), | 536 : arena_(NULL), |
540 default_enum_value_(other.default_enum_value_), | 537 default_enum_value_(other.default_enum_value_), |
541 old_style_(other.old_style_) { | 538 old_style_(other.old_style_) { |
542 Init(); | 539 Init(); |
543 insert(other.begin(), other.end()); | 540 insert(other.begin(), other.end()); |
544 } | 541 } |
545 template <class InputIt> | 542 template <class InputIt> |
546 Map(const InputIt& first, const InputIt& last, bool old_style = false) | 543 Map(const InputIt& first, const InputIt& last, bool old_style = true) |
547 : arena_(NULL), | 544 : arena_(NULL), |
548 default_enum_value_(0), | 545 default_enum_value_(0), |
549 old_style_(old_style) { | 546 old_style_(old_style) { |
550 Init(); | 547 Init(); |
551 insert(first, last); | 548 insert(first, last); |
552 } | 549 } |
553 | 550 |
554 ~Map() { | 551 ~Map() { |
555 clear(); | 552 clear(); |
556 if (arena_ == NULL) { | 553 if (arena_ == NULL) { |
557 if (old_style_) | 554 if (old_style_) |
558 delete deprecated_elements_; | 555 delete deprecated_elements_; |
559 else | 556 else |
560 delete elements_; | 557 delete elements_; |
561 } | 558 } |
562 } | 559 } |
563 | 560 |
564 private: | 561 private: |
565 void Init() { | 562 void Init() { |
566 if (old_style_) | 563 if (old_style_) |
567 deprecated_elements_ = Arena::Create<DeprecatedInnerMap>( | 564 deprecated_elements_ = Arena::Create<DeprecatedInnerMap>( |
568 arena_, 0, hasher(), std::equal_to<Key>(), | 565 arena_, 0, hasher(), equal_to<Key>(), |
569 MapAllocator<std::pair<const Key, MapPair<Key, T>*> >(arena_)); | 566 MapAllocator<std::pair<const Key, MapPair<Key, T>*> >(arena_)); |
570 else | 567 else |
571 elements_ = | 568 elements_ = |
572 Arena::Create<InnerMap>(arena_, 0, hasher(), Allocator(arena_)); | 569 Arena::Create<InnerMap>(arena_, 0, hasher(), Allocator(arena_)); |
573 } | 570 } |
574 | 571 |
575 // re-implement std::allocator to use arena allocator for memory allocation. | 572 // re-implement std::allocator to use arena allocator for memory allocation. |
576 // Used for google::protobuf::Map implementation. Users should not use this cl
ass | 573 // Used for google::protobuf::Map implementation. Users should not use this cl
ass |
577 // directly. | 574 // directly. |
578 template <typename U> | 575 template <typename U> |
579 class MapAllocator { | 576 class MapAllocator { |
580 public: | 577 public: |
581 typedef U value_type; | 578 typedef U value_type; |
582 typedef value_type* pointer; | 579 typedef value_type* pointer; |
583 typedef const value_type* const_pointer; | 580 typedef const value_type* const_pointer; |
584 typedef value_type& reference; | 581 typedef value_type& reference; |
585 typedef const value_type& const_reference; | 582 typedef const value_type& const_reference; |
586 typedef size_t size_type; | 583 typedef size_t size_type; |
587 typedef ptrdiff_t difference_type; | 584 typedef ptrdiff_t difference_type; |
588 | 585 |
589 MapAllocator() : arena_(NULL) {} | 586 MapAllocator() : arena_(NULL) {} |
590 explicit MapAllocator(Arena* arena) : arena_(arena) {} | 587 explicit MapAllocator(Arena* arena) : arena_(arena) {} |
591 template <typename X> | 588 template <typename X> |
592 MapAllocator(const MapAllocator<X>& allocator) | 589 MapAllocator(const MapAllocator<X>& allocator) |
593 : arena_(allocator.arena()) {} | 590 : arena_(allocator.arena_) {} |
594 | 591 |
595 pointer allocate(size_type n, const_pointer hint = 0) { | 592 pointer allocate(size_type n, const_pointer hint = 0) { |
596 // If arena is not given, malloc needs to be called which doesn't | 593 // If arena is not given, malloc needs to be called which doesn't |
597 // construct element object. | 594 // construct element object. |
598 if (arena_ == NULL) { | 595 if (arena_ == NULL) { |
599 return static_cast<pointer>(::operator new(n * sizeof(value_type))); | 596 return reinterpret_cast<pointer>(malloc(n * sizeof(value_type))); |
600 } else { | 597 } else { |
601 return reinterpret_cast<pointer>( | 598 return reinterpret_cast<pointer>( |
602 Arena::CreateArray<uint8>(arena_, n * sizeof(value_type))); | 599 Arena::CreateArray<uint8>(arena_, n * sizeof(value_type))); |
603 } | 600 } |
604 } | 601 } |
605 | 602 |
606 void deallocate(pointer p, size_type n) { | 603 void deallocate(pointer p, size_type n) { |
607 if (arena_ == NULL) { | 604 if (arena_ == NULL) { |
608 #if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation) | 605 free(p); |
609 ::operator delete(p, n * sizeof(value_type)); | |
610 #else | |
611 ::operator delete(p); | |
612 #endif | |
613 } | 606 } |
614 } | 607 } |
615 | 608 |
616 #if __cplusplus >= 201103L && !defined(GOOGLE_PROTOBUF_OS_APPLE) && \ | 609 #if __cplusplus >= 201103L && !defined(GOOGLE_PROTOBUF_OS_APPLE) && \ |
617 !defined(GOOGLE_PROTOBUF_OS_NACL) && \ | 610 !defined(GOOGLE_PROTOBUF_OS_NACL) && \ |
| 611 !defined(GOOGLE_PROTOBUF_OS_ANDROID) && \ |
618 !defined(GOOGLE_PROTOBUF_OS_EMSCRIPTEN) | 612 !defined(GOOGLE_PROTOBUF_OS_EMSCRIPTEN) |
619 template<class NodeType, class... Args> | 613 template<class NodeType, class... Args> |
620 void construct(NodeType* p, Args&&... args) { | 614 void construct(NodeType* p, Args&&... args) { |
621 // Clang 3.6 doesn't compile static casting to void* directly. (Issue | 615 // Clang 3.6 doesn't compile static casting to void* directly. (Issue |
622 // #1266) According C++ standard 5.2.9/1: "The static_cast operator shall | 616 // #1266) According C++ standard 5.2.9/1: "The static_cast operator shall |
623 // not cast away constness". So first the maybe const pointer is casted to | 617 // not cast away constness". So first the maybe const pointer is casted to |
624 // const void* and after the const void* is const casted. | 618 // const void* and after the const void* is const casted. |
625 new (const_cast<void*>(static_cast<const void*>(p))) | 619 new (const_cast<void*>(static_cast<const void*>(p))) |
626 NodeType(std::forward<Args>(args)...); | 620 NodeType(std::forward<Args>(args)...); |
627 } | 621 } |
(...skipping 18 matching lines...) Expand all Loading... |
646 return arena_ == other.arena_; | 640 return arena_ == other.arena_; |
647 } | 641 } |
648 | 642 |
649 template <typename X> | 643 template <typename X> |
650 bool operator!=(const MapAllocator<X>& other) const { | 644 bool operator!=(const MapAllocator<X>& other) const { |
651 return arena_ != other.arena_; | 645 return arena_ != other.arena_; |
652 } | 646 } |
653 | 647 |
654 // To support Visual Studio 2008 | 648 // To support Visual Studio 2008 |
655 size_type max_size() const { | 649 size_type max_size() const { |
656 // parentheses around (std::...:max) prevents macro warning of max() | 650 return std::numeric_limits<size_type>::max(); |
657 return (std::numeric_limits<size_type>::max)(); | |
658 } | |
659 | |
660 // To support gcc-4.4, which does not properly | |
661 // support templated friend classes | |
662 Arena* arena() const { | |
663 return arena_; | |
664 } | 651 } |
665 | 652 |
666 private: | 653 private: |
667 typedef void DestructorSkippable_; | 654 typedef void DestructorSkippable_; |
668 Arena* const arena_; | 655 Arena* const arena_; |
| 656 |
| 657 template <typename X> |
| 658 friend class MapAllocator; |
669 }; | 659 }; |
670 | 660 |
671 // InnerMap's key type is Key and its value type is value_type*. We use a | 661 // InnerMap's key type is Key and its value type is value_type*. We use a |
672 // custom class here and for Node, below, to ensure that k_ is at offset 0, | 662 // custom class here and for Node, below, to ensure that k_ is at offset 0, |
673 // allowing safe conversion from pointer to Node to pointer to Key, and vice | 663 // allowing safe conversion from pointer to Node to pointer to Key, and vice |
674 // versa when appropriate. | 664 // versa when appropriate. |
675 class KeyValuePair { | 665 class KeyValuePair { |
676 public: | 666 public: |
677 KeyValuePair(const Key& k, value_type* v) : k_(k), v_(v) {} | 667 KeyValuePair(const Key& k, value_type* v) : k_(k), v_(v) {} |
678 | 668 |
(...skipping 398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1077 } else { | 1067 } else { |
1078 // Insert into a pre-existing list. This case cannot modify | 1068 // Insert into a pre-existing list. This case cannot modify |
1079 // index_of_first_non_null_, so we skip the code to update it. | 1069 // index_of_first_non_null_, so we skip the code to update it. |
1080 return InsertUniqueInList(b, node); | 1070 return InsertUniqueInList(b, node); |
1081 } | 1071 } |
1082 } else { | 1072 } else { |
1083 // Insert into a pre-existing tree. This case cannot modify | 1073 // Insert into a pre-existing tree. This case cannot modify |
1084 // index_of_first_non_null_, so we skip the code to update it. | 1074 // index_of_first_non_null_, so we skip the code to update it. |
1085 return InsertUniqueInTree(b, node); | 1075 return InsertUniqueInTree(b, node); |
1086 } | 1076 } |
1087 // parentheses around (std::min) prevents macro expansion of min(...) | |
1088 index_of_first_non_null_ = | 1077 index_of_first_non_null_ = |
1089 (std::min)(index_of_first_non_null_, result.bucket_index_); | 1078 std::min(index_of_first_non_null_, result.bucket_index_); |
1090 return result; | 1079 return result; |
1091 } | 1080 } |
1092 | 1081 |
1093 // Helper for InsertUnique. Handles the case where bucket b is a | 1082 // Helper for InsertUnique. Handles the case where bucket b is a |
1094 // not-too-long linked list. | 1083 // not-too-long linked list. |
1095 iterator InsertUniqueInList(size_type b, Node* node) { | 1084 iterator InsertUniqueInList(size_type b, Node* node) { |
1096 node->next = static_cast<Node*>(table_[b]); | 1085 node->next = static_cast<Node*>(table_[b]); |
1097 table_[b] = static_cast<void*>(node); | 1086 table_[b] = static_cast<void*>(node); |
1098 return iterator(node, this, b); | 1087 return iterator(node, this, b); |
1099 } | 1088 } |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1251 Node* next = node->next; | 1240 Node* next = node->next; |
1252 node->next = NULL; | 1241 node->next = NULL; |
1253 node = next; | 1242 node = next; |
1254 } | 1243 } |
1255 return count; | 1244 return count; |
1256 } | 1245 } |
1257 | 1246 |
1258 // Return whether table_[b] is a linked list that seems awfully long. | 1247 // Return whether table_[b] is a linked list that seems awfully long. |
1259 // Requires table_[b] to point to a non-empty linked list. | 1248 // Requires table_[b] to point to a non-empty linked list. |
1260 bool TableEntryIsTooLong(size_type b) { | 1249 bool TableEntryIsTooLong(size_type b) { |
1261 const size_type kMaxLength = 8; | 1250 const int kMaxLength = 8; |
1262 size_type count = 0; | 1251 size_type count = 0; |
1263 Node* node = static_cast<Node*>(table_[b]); | 1252 Node* node = static_cast<Node*>(table_[b]); |
1264 do { | 1253 do { |
1265 ++count; | 1254 ++count; |
1266 node = node->next; | 1255 node = node->next; |
1267 } while (node != NULL); | 1256 } while (node != NULL); |
1268 // Invariant: no linked list ever is more than kMaxLength in length. | 1257 // Invariant: no linked list ever is more than kMaxLength in length. |
1269 GOOGLE_DCHECK_LE(count, kMaxLength); | 1258 GOOGLE_DCHECK_LE(count, kMaxLength); |
1270 return count >= kMaxLength; | 1259 return count >= kMaxLength; |
1271 } | 1260 } |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1349 | 1338 |
1350 size_type num_elements_; | 1339 size_type num_elements_; |
1351 size_type num_buckets_; | 1340 size_type num_buckets_; |
1352 size_type seed_; | 1341 size_type seed_; |
1353 size_type index_of_first_non_null_; | 1342 size_type index_of_first_non_null_; |
1354 void** table_; // an array with num_buckets_ entries | 1343 void** table_; // an array with num_buckets_ entries |
1355 Allocator alloc_; | 1344 Allocator alloc_; |
1356 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(InnerMap); | 1345 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(InnerMap); |
1357 }; // end of class InnerMap | 1346 }; // end of class InnerMap |
1358 | 1347 |
1359 typedef hash_map<Key, value_type*, hash<Key>, std::equal_to<Key>, | 1348 typedef hash_map<Key, value_type*, hash<Key>, equal_to<Key>, |
1360 MapAllocator<std::pair<const Key, MapPair<Key, T>*> > > | 1349 MapAllocator<std::pair<const Key, MapPair<Key, T>*> > > |
1361 DeprecatedInnerMap; | 1350 DeprecatedInnerMap; |
1362 | 1351 |
1363 public: | 1352 public: |
1364 // Iterators | 1353 // Iterators |
1365 class iterator_base { | 1354 class iterator_base { |
1366 public: | 1355 public: |
1367 // We support "old style" and "new style" iterators for now. This is | 1356 // We support "old style" and "new style" iterators for now. This is |
1368 // temporary. Also, for "iterator()" we have an unknown category. | 1357 // temporary. Also, for "iterator()" we have an unknown category. |
1369 // TODO(gpike): get rid of this. | 1358 // TODO(gpike): get rid of this. |
(...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1622 | 1611 |
1623 // Assign | 1612 // Assign |
1624 Map& operator=(const Map& other) { | 1613 Map& operator=(const Map& other) { |
1625 if (this != &other) { | 1614 if (this != &other) { |
1626 clear(); | 1615 clear(); |
1627 insert(other.begin(), other.end()); | 1616 insert(other.begin(), other.end()); |
1628 } | 1617 } |
1629 return *this; | 1618 return *this; |
1630 } | 1619 } |
1631 | 1620 |
1632 void swap(Map& other) { | |
1633 if (arena_ == other.arena_ && old_style_ == other.old_style_) { | |
1634 std::swap(default_enum_value_, other.default_enum_value_); | |
1635 if (old_style_) { | |
1636 std::swap(deprecated_elements_, other.deprecated_elements_); | |
1637 } else { | |
1638 std::swap(elements_, other.elements_); | |
1639 } | |
1640 } else { | |
1641 // TODO(zuguang): optimize this. The temporary copy can be allocated | |
1642 // in the same arena as the other message, and the "other = copy" can | |
1643 // be replaced with the fast-path swap above. | |
1644 Map copy = *this; | |
1645 *this = other; | |
1646 other = copy; | |
1647 } | |
1648 } | |
1649 | |
1650 // Access to hasher. Currently this returns a copy, but it may | 1621 // Access to hasher. Currently this returns a copy, but it may |
1651 // be modified to return a const reference in the future. | 1622 // be modified to return a const reference in the future. |
1652 hasher hash_function() const { | 1623 hasher hash_function() const { |
1653 return old_style_ ? deprecated_elements_->hash_function() | 1624 return old_style_ ? deprecated_elements_->hash_function() |
1654 : elements_->hash_function(); | 1625 : elements_->hash_function(); |
1655 } | 1626 } |
1656 | 1627 |
1657 private: | 1628 private: |
1658 // Set default enum value only for proto2 map field whose value is enum type. | 1629 // Set default enum value only for proto2 map field whose value is enum type. |
1659 void SetDefaultEnumValue(int default_enum_value) { | 1630 void SetDefaultEnumValue(int default_enum_value) { |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1741 } | 1712 } |
1742 bool | 1713 bool |
1743 operator()(const google::protobuf::MapKey& map_key1, | 1714 operator()(const google::protobuf::MapKey& map_key1, |
1744 const google::protobuf::MapKey& map_key2) const { | 1715 const google::protobuf::MapKey& map_key2) const { |
1745 return map_key1 < map_key2; | 1716 return map_key1 < map_key2; |
1746 } | 1717 } |
1747 }; | 1718 }; |
1748 GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_END | 1719 GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_END |
1749 | 1720 |
1750 #endif // GOOGLE_PROTOBUF_MAP_H__ | 1721 #endif // GOOGLE_PROTOBUF_MAP_H__ |
OLD | NEW |