1*795d594fSAndroid Build Coastguard Worker /* 2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2012 The Android Open Source Project 3*795d594fSAndroid Build Coastguard Worker * 4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*795d594fSAndroid Build Coastguard Worker * 8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*795d594fSAndroid Build Coastguard Worker * 10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*795d594fSAndroid Build Coastguard Worker * limitations under the License. 15*795d594fSAndroid Build Coastguard Worker */ 16*795d594fSAndroid Build Coastguard Worker 17*795d594fSAndroid Build Coastguard Worker #ifndef ART_LIBARTBASE_BASE_SAFE_MAP_H_ 18*795d594fSAndroid Build Coastguard Worker #define ART_LIBARTBASE_BASE_SAFE_MAP_H_ 19*795d594fSAndroid Build Coastguard Worker 20*795d594fSAndroid Build Coastguard Worker #include <map> 21*795d594fSAndroid Build Coastguard Worker #include <memory> 22*795d594fSAndroid Build Coastguard Worker #include <type_traits> 23*795d594fSAndroid Build Coastguard Worker 24*795d594fSAndroid Build Coastguard Worker #include <android-base/logging.h> 25*795d594fSAndroid Build Coastguard Worker 26*795d594fSAndroid Build Coastguard Worker namespace art { 27*795d594fSAndroid Build Coastguard Worker 28*795d594fSAndroid Build Coastguard Worker // Equivalent to std::map, but without operator[] and its bug-prone semantics (in particular, 29*795d594fSAndroid Build Coastguard Worker // the implicit insertion of a default-constructed value on failed lookups). 30*795d594fSAndroid Build Coastguard Worker template <typename K, typename V, typename Comparator = std::less<K>, 31*795d594fSAndroid Build Coastguard Worker typename Allocator = std::allocator<std::pair<const K, V>>> 32*795d594fSAndroid Build Coastguard Worker class SafeMap { 33*795d594fSAndroid Build Coastguard Worker private: 34*795d594fSAndroid Build Coastguard Worker using Self = SafeMap<K, V, Comparator, Allocator>; 35*795d594fSAndroid Build Coastguard Worker using Impl = std::map<K, V, Comparator, Allocator>; 36*795d594fSAndroid Build Coastguard Worker 37*795d594fSAndroid Build Coastguard Worker public: 38*795d594fSAndroid Build Coastguard Worker using key_compare = typename Impl::key_compare; 39*795d594fSAndroid Build Coastguard Worker using value_compare = typename Impl::value_compare; 40*795d594fSAndroid Build Coastguard Worker using allocator_type = typename Impl::allocator_type; 41*795d594fSAndroid Build Coastguard Worker using iterator = typename Impl::iterator; 42*795d594fSAndroid Build Coastguard Worker using const_iterator = typename Impl::const_iterator; 43*795d594fSAndroid Build Coastguard Worker using size_type = typename Impl::size_type; 44*795d594fSAndroid Build Coastguard Worker using key_type = typename Impl::key_type; 45*795d594fSAndroid Build Coastguard Worker using value_type = typename Impl::value_type; 46*795d594fSAndroid Build Coastguard Worker using node_type = typename Impl::node_type; 47*795d594fSAndroid Build Coastguard Worker using insert_return_type = typename Impl::insert_return_type; 48*795d594fSAndroid Build Coastguard Worker 49*795d594fSAndroid Build Coastguard Worker SafeMap() = default; 50*795d594fSAndroid Build Coastguard Worker SafeMap(const SafeMap&) = default; 51*795d594fSAndroid Build Coastguard Worker SafeMap(SafeMap&&) noexcept = default; SafeMap(const allocator_type & allocator)52*795d594fSAndroid Build Coastguard Worker explicit SafeMap(const allocator_type& allocator) : map_(allocator) {} 53*795d594fSAndroid Build Coastguard Worker explicit SafeMap(const key_compare& cmp, const allocator_type& allocator = allocator_type()) map_(cmp,allocator)54*795d594fSAndroid Build Coastguard Worker : map_(cmp, allocator) { 55*795d594fSAndroid Build Coastguard Worker } 56*795d594fSAndroid Build Coastguard Worker 57*795d594fSAndroid Build Coastguard Worker Self& operator=(const Self& rhs) { 58*795d594fSAndroid Build Coastguard Worker map_ = rhs.map_; 59*795d594fSAndroid Build Coastguard Worker return *this; 60*795d594fSAndroid Build Coastguard Worker } 61*795d594fSAndroid Build Coastguard Worker get_allocator()62*795d594fSAndroid Build Coastguard Worker allocator_type get_allocator() const { return map_.get_allocator(); } key_comp()63*795d594fSAndroid Build Coastguard Worker key_compare key_comp() const { return map_.key_comp(); } value_comp()64*795d594fSAndroid Build Coastguard Worker value_compare value_comp() const { return map_.value_comp(); } 65*795d594fSAndroid Build Coastguard Worker begin()66*795d594fSAndroid Build Coastguard Worker iterator begin() { return map_.begin(); } begin()67*795d594fSAndroid Build Coastguard Worker const_iterator begin() const { return map_.begin(); } end()68*795d594fSAndroid Build Coastguard Worker iterator end() { return map_.end(); } end()69*795d594fSAndroid Build Coastguard Worker const_iterator end() const { return map_.end(); } 70*795d594fSAndroid Build Coastguard Worker empty()71*795d594fSAndroid Build Coastguard Worker bool empty() const { return map_.empty(); } size()72*795d594fSAndroid Build Coastguard Worker size_type size() const { return map_.size(); } 73*795d594fSAndroid Build Coastguard Worker swap(Self & other)74*795d594fSAndroid Build Coastguard Worker void swap(Self& other) { map_.swap(other.map_); } clear()75*795d594fSAndroid Build Coastguard Worker void clear() { map_.clear(); } 76*795d594fSAndroid Build Coastguard Worker erase(const_iterator pos)77*795d594fSAndroid Build Coastguard Worker iterator erase(const_iterator pos) { return map_.erase(pos); } erase(iterator pos)78*795d594fSAndroid Build Coastguard Worker iterator erase(iterator pos) { return map_.erase(pos); } erase(iterator first,iterator last)79*795d594fSAndroid Build Coastguard Worker iterator erase(iterator first, iterator last) { return map_.erase(first, last); } erase(const key_type & k)80*795d594fSAndroid Build Coastguard Worker size_type erase(const key_type& k) { return map_.erase(k); } 81*795d594fSAndroid Build Coastguard Worker extract(const_iterator pos)82*795d594fSAndroid Build Coastguard Worker node_type extract(const_iterator pos) { return map_.extract(pos); } extract(const key_type & k)83*795d594fSAndroid Build Coastguard Worker node_type extract(const key_type& k) { return map_.extract(k); } 84*795d594fSAndroid Build Coastguard Worker insert(value_type && value)85*795d594fSAndroid Build Coastguard Worker std::pair<iterator, bool> insert(value_type&& value) { return map_.insert(std::move(value)); } insert(node_type && node)86*795d594fSAndroid Build Coastguard Worker insert_return_type insert(node_type&& node) { return map_.insert(std::move(node)); } insert(const_iterator hint,node_type && node)87*795d594fSAndroid Build Coastguard Worker insert_return_type insert(const_iterator hint, node_type&& node) { 88*795d594fSAndroid Build Coastguard Worker return map_.insert(hint, std::move(node)); 89*795d594fSAndroid Build Coastguard Worker } 90*795d594fSAndroid Build Coastguard Worker find(const Kv & k)91*795d594fSAndroid Build Coastguard Worker template<typename Kv> iterator find(const Kv& k) { return map_.find(k); } find(const Kv & k)92*795d594fSAndroid Build Coastguard Worker template<typename Kv> const_iterator find(const Kv& k) const { return map_.find(k); } 93*795d594fSAndroid Build Coastguard Worker lower_bound(const Kv & k)94*795d594fSAndroid Build Coastguard Worker template<typename Kv> iterator lower_bound(const Kv& k) { return map_.lower_bound(k); } lower_bound(const Kv & k)95*795d594fSAndroid Build Coastguard Worker template<typename Kv> const_iterator lower_bound(const Kv& k) const { 96*795d594fSAndroid Build Coastguard Worker return map_.lower_bound(k); 97*795d594fSAndroid Build Coastguard Worker } 98*795d594fSAndroid Build Coastguard Worker upper_bound(const Kv & k)99*795d594fSAndroid Build Coastguard Worker template<typename Kv> iterator upper_bound(const Kv& k) { return map_.upper_bound(k); } upper_bound(const Kv & k)100*795d594fSAndroid Build Coastguard Worker template<typename Kv> const_iterator upper_bound(const Kv& k) const { 101*795d594fSAndroid Build Coastguard Worker return map_.upper_bound(k); 102*795d594fSAndroid Build Coastguard Worker } 103*795d594fSAndroid Build Coastguard Worker count(const Kv & k)104*795d594fSAndroid Build Coastguard Worker template<typename Kv> size_type count(const Kv& k) const { return map_.count(k); } 105*795d594fSAndroid Build Coastguard Worker 106*795d594fSAndroid Build Coastguard Worker // Note that unlike std::map's operator[], this doesn't return a reference to the value. Get(const K & k)107*795d594fSAndroid Build Coastguard Worker V Get(const K& k) const { 108*795d594fSAndroid Build Coastguard Worker const_iterator it = map_.find(k); 109*795d594fSAndroid Build Coastguard Worker DCHECK(it != map_.end()); 110*795d594fSAndroid Build Coastguard Worker return it->second; 111*795d594fSAndroid Build Coastguard Worker } 112*795d594fSAndroid Build Coastguard Worker 113*795d594fSAndroid Build Coastguard Worker // Used to insert a new mapping. Put(const K & k,const V & v)114*795d594fSAndroid Build Coastguard Worker iterator Put(const K& k, const V& v) { 115*795d594fSAndroid Build Coastguard Worker std::pair<iterator, bool> result = map_.emplace(k, v); 116*795d594fSAndroid Build Coastguard Worker DCHECK(result.second); // Check we didn't accidentally overwrite an existing value. 117*795d594fSAndroid Build Coastguard Worker return result.first; 118*795d594fSAndroid Build Coastguard Worker } Put(const K & k,V && v)119*795d594fSAndroid Build Coastguard Worker iterator Put(const K& k, V&& v) { 120*795d594fSAndroid Build Coastguard Worker std::pair<iterator, bool> result = map_.emplace(k, std::move(v)); 121*795d594fSAndroid Build Coastguard Worker DCHECK(result.second); // Check we didn't accidentally overwrite an existing value. 122*795d594fSAndroid Build Coastguard Worker return result.first; 123*795d594fSAndroid Build Coastguard Worker } 124*795d594fSAndroid Build Coastguard Worker 125*795d594fSAndroid Build Coastguard Worker // Used to insert a new mapping at a known position for better performance. PutBefore(const_iterator pos,const K & k,const V & v)126*795d594fSAndroid Build Coastguard Worker iterator PutBefore(const_iterator pos, const K& k, const V& v) { 127*795d594fSAndroid Build Coastguard Worker // Check that we're using the correct position and the key is not in the map. 128*795d594fSAndroid Build Coastguard Worker DCHECK(pos == map_.end() || map_.key_comp()(k, pos->first)); 129*795d594fSAndroid Build Coastguard Worker DCHECK(pos == map_.begin() || map_.key_comp()((--const_iterator(pos))->first, k)); 130*795d594fSAndroid Build Coastguard Worker return map_.emplace_hint(pos, k, v); 131*795d594fSAndroid Build Coastguard Worker } PutBefore(const_iterator pos,const K & k,V && v)132*795d594fSAndroid Build Coastguard Worker iterator PutBefore(const_iterator pos, const K& k, V&& v) { 133*795d594fSAndroid Build Coastguard Worker // Check that we're using the correct position and the key is not in the map. 134*795d594fSAndroid Build Coastguard Worker DCHECK(pos == map_.end() || map_.key_comp()(k, pos->first)); 135*795d594fSAndroid Build Coastguard Worker DCHECK(pos == map_.begin() || map_.key_comp()((--const_iterator(pos))->first, k)); 136*795d594fSAndroid Build Coastguard Worker return map_.emplace_hint(pos, k, std::move(v)); 137*795d594fSAndroid Build Coastguard Worker } 138*795d594fSAndroid Build Coastguard Worker 139*795d594fSAndroid Build Coastguard Worker // Used to insert a new mapping or overwrite an existing mapping. Note that if the value type 140*795d594fSAndroid Build Coastguard Worker // of this container is a pointer, any overwritten pointer will be lost and if this container 141*795d594fSAndroid Build Coastguard Worker // was the owner, you have a leak. Returns iterator pointing to the new or overwritten entry. Overwrite(const K & k,const V & v)142*795d594fSAndroid Build Coastguard Worker iterator Overwrite(const K& k, const V& v) { 143*795d594fSAndroid Build Coastguard Worker std::pair<iterator, bool> result = map_.insert(std::make_pair(k, v)); 144*795d594fSAndroid Build Coastguard Worker if (!result.second) { 145*795d594fSAndroid Build Coastguard Worker // Already there - update the value for the existing key 146*795d594fSAndroid Build Coastguard Worker result.first->second = v; 147*795d594fSAndroid Build Coastguard Worker } 148*795d594fSAndroid Build Coastguard Worker return result.first; 149*795d594fSAndroid Build Coastguard Worker } 150*795d594fSAndroid Build Coastguard Worker 151*795d594fSAndroid Build Coastguard Worker template <typename CreateFn> GetOrCreate(const K & k,CreateFn && create)152*795d594fSAndroid Build Coastguard Worker V& GetOrCreate(const K& k, CreateFn&& create) { 153*795d594fSAndroid Build Coastguard Worker static_assert(std::is_same_v<V, std::invoke_result_t<CreateFn>>, 154*795d594fSAndroid Build Coastguard Worker "Argument `create` should return a value of type V."); 155*795d594fSAndroid Build Coastguard Worker auto lb = lower_bound(k); 156*795d594fSAndroid Build Coastguard Worker if (lb != end() && !key_comp()(k, lb->first)) { 157*795d594fSAndroid Build Coastguard Worker return lb->second; 158*795d594fSAndroid Build Coastguard Worker } 159*795d594fSAndroid Build Coastguard Worker auto it = PutBefore(lb, k, create()); 160*795d594fSAndroid Build Coastguard Worker return it->second; 161*795d594fSAndroid Build Coastguard Worker } 162*795d594fSAndroid Build Coastguard Worker FindOrAdd(const K & k,const V & v)163*795d594fSAndroid Build Coastguard Worker iterator FindOrAdd(const K& k, const V& v) { 164*795d594fSAndroid Build Coastguard Worker iterator it = find(k); 165*795d594fSAndroid Build Coastguard Worker return it == end() ? Put(k, v) : it; 166*795d594fSAndroid Build Coastguard Worker } 167*795d594fSAndroid Build Coastguard Worker FindOrAdd(const K & k)168*795d594fSAndroid Build Coastguard Worker iterator FindOrAdd(const K& k) { 169*795d594fSAndroid Build Coastguard Worker iterator it = find(k); 170*795d594fSAndroid Build Coastguard Worker return it == end() ? Put(k, V()) : it; 171*795d594fSAndroid Build Coastguard Worker } 172*795d594fSAndroid Build Coastguard Worker Equals(const Self & rhs)173*795d594fSAndroid Build Coastguard Worker bool Equals(const Self& rhs) const { 174*795d594fSAndroid Build Coastguard Worker return map_ == rhs.map_; 175*795d594fSAndroid Build Coastguard Worker } 176*795d594fSAndroid Build Coastguard Worker 177*795d594fSAndroid Build Coastguard Worker template <class... Args> emplace(Args &&...args)178*795d594fSAndroid Build Coastguard Worker std::pair<iterator, bool> emplace(Args&&... args) { 179*795d594fSAndroid Build Coastguard Worker return map_.emplace(std::forward<Args>(args)...); 180*795d594fSAndroid Build Coastguard Worker } 181*795d594fSAndroid Build Coastguard Worker 182*795d594fSAndroid Build Coastguard Worker private: 183*795d594fSAndroid Build Coastguard Worker Impl map_; 184*795d594fSAndroid Build Coastguard Worker }; 185*795d594fSAndroid Build Coastguard Worker 186*795d594fSAndroid Build Coastguard Worker template <typename K, typename V, typename Comparator, typename Allocator> 187*795d594fSAndroid Build Coastguard Worker bool operator==(const SafeMap<K, V, Comparator, Allocator>& lhs, 188*795d594fSAndroid Build Coastguard Worker const SafeMap<K, V, Comparator, Allocator>& rhs) { 189*795d594fSAndroid Build Coastguard Worker return lhs.Equals(rhs); 190*795d594fSAndroid Build Coastguard Worker } 191*795d594fSAndroid Build Coastguard Worker 192*795d594fSAndroid Build Coastguard Worker template <typename K, typename V, typename Comparator, typename Allocator> 193*795d594fSAndroid Build Coastguard Worker bool operator!=(const SafeMap<K, V, Comparator, Allocator>& lhs, 194*795d594fSAndroid Build Coastguard Worker const SafeMap<K, V, Comparator, Allocator>& rhs) { 195*795d594fSAndroid Build Coastguard Worker return !(lhs == rhs); 196*795d594fSAndroid Build Coastguard Worker } 197*795d594fSAndroid Build Coastguard Worker 198*795d594fSAndroid Build Coastguard Worker } // namespace art 199*795d594fSAndroid Build Coastguard Worker 200*795d594fSAndroid Build Coastguard Worker #endif // ART_LIBARTBASE_BASE_SAFE_MAP_H_ 201