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