xref: /aosp_15_r20/art/libartbase/base/safe_map.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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