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