diff --git a/src/core/lib/gprpp/map.h b/src/core/lib/gprpp/map.h index 8f0a26146b1..705b605e5b9 100644 --- a/src/core/lib/gprpp/map.h +++ b/src/core/lib/gprpp/map.h @@ -63,6 +63,7 @@ class Map { typedef Pair value_type; typedef Compare key_compare; class iterator; + class const_iterator; Map() = default; ~Map() { clear(); } @@ -83,6 +84,22 @@ class Map { return *this; } + // Copyable. + Map(const Map& other) { + for (const auto& p : other) { + emplace(p); + } + } + Map& operator=(const Map& other) { + if (this != &other) { + clear(); + for (const auto& p : other) { + emplace(p); + } + } + return *this; + } + T& operator[](key_type&& key); T& operator[](const key_type& key); iterator find(const key_type& k); @@ -117,6 +134,13 @@ class Map { iterator end() { return iterator(this, nullptr); } + const_iterator begin() const { + Entry* curr = GetMinEntry(root_); + return const_iterator(this, curr); + } + + const_iterator end() const { return const_iterator(this, nullptr); } + iterator lower_bound(const Key& k) { // This is a workaround for "const key_compare compare;" // because some versions of compilers cannot build this by requiring @@ -209,6 +233,53 @@ class Map::iterator GrpcMap* map_; }; +template +class Map::const_iterator + : public std::iterator, int32_t, + Pair*, Pair&> { + public: + const_iterator(const const_iterator& iter) + : curr_(iter.curr_), map_(iter.map_) {} + bool operator==(const const_iterator& rhs) const { + return (curr_ == rhs.curr_); + } + bool operator!=(const const_iterator& rhs) const { + return (curr_ != rhs.curr_); + } + + const_iterator& operator++() { + curr_ = map_->InOrderSuccessor(curr_); + return *this; + } + + const_iterator operator++(int) { + Entry* prev = curr_; + curr_ = map_->InOrderSuccessor(curr_); + return const_iterator(map_, prev); + } + + const_iterator& operator=(const const_iterator& other) { + if (this != &other) { + this->curr_ = other.curr_; + this->map_ = other.map_; + } + return *this; + } + + // operator*() + const value_type& operator*() const { return curr_->pair; } + + // operator->() + const value_type* operator->() const { return &curr_->pair; } + + private: + friend class Map; + using GrpcMap = typename ::grpc_core::Map; + const_iterator(const GrpcMap* map, Entry* curr) : curr_(curr), map_(map) {} + Entry* curr_; + const GrpcMap* map_; +}; + template T& Map::operator[](key_type&& key) { auto iter = find(key); diff --git a/test/core/gprpp/map_test.cc b/test/core/gprpp/map_test.cc index 21aeee82486..b0be7960b57 100644 --- a/test/core/gprpp/map_test.cc +++ b/test/core/gprpp/map_test.cc @@ -466,6 +466,35 @@ TEST_F(MapTest, MoveAssignment) { EXPECT_EQ(test_map2.end(), test_map2.find("xxx")); } +// Test copy ctor +TEST_F(MapTest, CopyCtor) { + Map test_map; + for (int i = 0; i < 5; i++) { + test_map.emplace(kKeys[i], Payload(i)); + } + Map test_map2 = test_map; + for (int i = 0; i < 5; i++) { + EXPECT_EQ(i, test_map.find(kKeys[i])->second.data()); + EXPECT_EQ(i, test_map2.find(kKeys[i])->second.data()); + } +} + +// Test copy assignment +TEST_F(MapTest, CopyAssignment) { + Map test_map; + for (int i = 0; i < 5; i++) { + test_map.emplace(kKeys[i], Payload(i)); + } + Map test_map2; + test_map2.emplace("xxx", Payload(123)); + test_map2 = test_map; + for (int i = 0; i < 5; i++) { + EXPECT_EQ(i, test_map.find(kKeys[i])->second.data()); + EXPECT_EQ(i, test_map2.find(kKeys[i])->second.data()); + } + EXPECT_EQ(test_map2.end(), test_map2.find("xxx")); +} + } // namespace testing } // namespace grpc_core