OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef BASE_ID_MAP_H_ | 5 #ifndef BASE_ID_MAP_H_ |
6 #define BASE_ID_MAP_H_ | 6 #define BASE_ID_MAP_H_ |
7 | 7 |
8 #include <stddef.h> | 8 #include <stddef.h> |
9 #include <stdint.h> | 9 #include <stdint.h> |
10 #include <memory> | |
10 #include <set> | 11 #include <set> |
12 #include <type_traits> | |
13 #include <utility> | |
11 | 14 |
12 #include "base/containers/hash_tables.h" | 15 #include "base/containers/hash_tables.h" |
13 #include "base/logging.h" | 16 #include "base/logging.h" |
14 #include "base/macros.h" | 17 #include "base/macros.h" |
15 #include "base/sequence_checker.h" | 18 #include "base/sequence_checker.h" |
16 | 19 |
17 // Ownership semantics - own pointer means the pointer is deleted in Remove() | 20 // Ownership semantics - own pointer means the pointer is deleted in Remove() |
18 // & during destruction | 21 // & during destruction |
19 enum IDMapOwnershipSemantics { | 22 enum IDMapOwnershipSemantics { |
20 IDMapExternalPointer, | 23 IDMapExternalPointer, |
(...skipping 12 matching lines...) Expand all Loading... | |
33 // This class does not have a virtual destructor, do not inherit from it when | 36 // This class does not have a virtual destructor, do not inherit from it when |
34 // ownership semantics are set to own because pointers will leak. | 37 // ownership semantics are set to own because pointers will leak. |
35 template <typename T, | 38 template <typename T, |
36 IDMapOwnershipSemantics OS = IDMapExternalPointer, | 39 IDMapOwnershipSemantics OS = IDMapExternalPointer, |
37 typename K = int32_t> | 40 typename K = int32_t> |
38 class IDMap { | 41 class IDMap { |
39 public: | 42 public: |
40 using KeyType = K; | 43 using KeyType = K; |
41 | 44 |
42 private: | 45 private: |
43 typedef base::hash_map<KeyType, T*> HashTable; | 46 typedef typename std::conditional<OS == IDMapExternalPointer, |
danakj
2016/09/15 20:08:40
can you change these both to "using" instead of ty
aelias_OOO_until_Jul13
2016/09/15 21:09:35
Done.
| |
47 T*, | |
48 std::unique_ptr<T>>::type V; | |
49 typedef base::hash_map<KeyType, V> HashTable; | |
44 | 50 |
45 public: | 51 public: |
46 IDMap() : iteration_depth_(0), next_id_(1), check_on_null_data_(false) { | 52 IDMap() : iteration_depth_(0), next_id_(1), check_on_null_data_(false) { |
47 // A number of consumers of IDMap create it on one thread but always | 53 // A number of consumers of IDMap create it on one thread but always |
48 // access it from a different, but consistent, thread (or sequence) | 54 // access it from a different, but consistent, thread (or sequence) |
49 // post-construction. The first call to CalledOnValidSequence() will re-bind | 55 // post-construction. The first call to CalledOnValidSequence() will re-bind |
50 // it. | 56 // it. |
51 sequence_checker_.DetachFromSequence(); | 57 sequence_checker_.DetachFromSequence(); |
52 } | 58 } |
53 | 59 |
54 ~IDMap() { | 60 ~IDMap() { |
55 // Many IDMap's are static, and hence will be destroyed on the main | 61 // Many IDMap's are static, and hence will be destroyed on the main |
56 // thread. However, all the accesses may take place on another thread (or | 62 // thread. However, all the accesses may take place on another thread (or |
57 // sequence), such as the IO thread. Detaching again to clean this up. | 63 // sequence), such as the IO thread. Detaching again to clean this up. |
58 sequence_checker_.DetachFromSequence(); | 64 sequence_checker_.DetachFromSequence(); |
59 Releaser<OS, 0>::release_all(&data_); | |
60 } | 65 } |
61 | 66 |
62 // Sets whether Add and Replace should DCHECK if passed in NULL data. | 67 // Sets whether Add and Replace should DCHECK if passed in NULL data. |
63 // Default is false. | 68 // Default is false. |
64 void set_check_on_null_data(bool value) { check_on_null_data_ = value; } | 69 void set_check_on_null_data(bool value) { check_on_null_data_ = value; } |
65 | 70 |
66 // Adds a view with an automatically generated unique ID. See AddWithID. | 71 // Adds a view with an automatically generated unique ID. See AddWithID. |
67 KeyType Add(T* data) { | 72 KeyType Add(T* data) { |
danakj
2016/09/15 20:08:40
Can this not take a V instead?
aelias_OOO_until_Jul13
2016/09/15 21:09:35
Yes, it can and should, but it would require expan
danakj
2016/09/16 00:30:27
Cool cool. Can you add a V version now and the com
aelias_OOO_until_Jul13
2016/09/16 01:39:18
Done. Note that because V can be the same as T*,
| |
68 DCHECK(sequence_checker_.CalledOnValidSequence()); | 73 DCHECK(sequence_checker_.CalledOnValidSequence()); |
69 DCHECK(!check_on_null_data_ || data); | 74 DCHECK(!check_on_null_data_ || data); |
70 KeyType this_id = next_id_; | 75 KeyType this_id = next_id_; |
71 DCHECK(data_.find(this_id) == data_.end()) << "Inserting duplicate item"; | 76 DCHECK(data_.find(this_id) == data_.end()) << "Inserting duplicate item"; |
72 data_[this_id] = data; | 77 data_[this_id] = V(data); |
73 next_id_++; | 78 next_id_++; |
74 return this_id; | 79 return this_id; |
75 } | 80 } |
76 | 81 |
77 // Adds a new data member with the specified ID. The ID must not be in | 82 // Adds a new data member with the specified ID. The ID must not be in |
78 // the list. The caller either must generate all unique IDs itself and use | 83 // the list. The caller either must generate all unique IDs itself and use |
79 // this function, or allow this object to generate IDs and call Add. These | 84 // this function, or allow this object to generate IDs and call Add. These |
80 // two methods may not be mixed, or duplicate IDs may be generated | 85 // two methods may not be mixed, or duplicate IDs may be generated |
81 void AddWithID(T* data, KeyType id) { | 86 void AddWithID(T* data, KeyType id) { |
danakj
2016/09/15 20:08:40
And this?
| |
82 DCHECK(sequence_checker_.CalledOnValidSequence()); | 87 DCHECK(sequence_checker_.CalledOnValidSequence()); |
83 DCHECK(!check_on_null_data_ || data); | 88 DCHECK(!check_on_null_data_ || data); |
84 DCHECK(data_.find(id) == data_.end()) << "Inserting duplicate item"; | 89 DCHECK(data_.find(id) == data_.end()) << "Inserting duplicate item"; |
85 data_[id] = data; | 90 data_[id] = V(data); |
86 } | 91 } |
87 | 92 |
88 void Remove(KeyType id) { | 93 void Remove(KeyType id) { |
89 DCHECK(sequence_checker_.CalledOnValidSequence()); | 94 DCHECK(sequence_checker_.CalledOnValidSequence()); |
90 typename HashTable::iterator i = data_.find(id); | 95 typename HashTable::iterator i = data_.find(id); |
91 if (i == data_.end()) { | 96 if (i == data_.end()) { |
92 NOTREACHED() << "Attempting to remove an item not in the list"; | 97 NOTREACHED() << "Attempting to remove an item not in the list"; |
93 return; | 98 return; |
94 } | 99 } |
95 | 100 |
96 if (iteration_depth_ == 0) { | 101 if (iteration_depth_ == 0) { |
97 Releaser<OS, 0>::release(i->second); | |
98 data_.erase(i); | 102 data_.erase(i); |
99 } else { | 103 } else { |
100 removed_ids_.insert(id); | 104 removed_ids_.insert(id); |
101 } | 105 } |
102 } | 106 } |
103 | 107 |
104 // Replaces the value for |id| with |new_data| and returns a pointer to the | 108 // Replaces the value for |id| with |new_data| and returns the existing value |
105 // existing value. If there is no entry for |id|, the map is not altered and | 109 // (as a unique_ptr<> if in IDMapOwnPointer mode). Should only be called with |
106 // nullptr is returned. The OwnershipSemantics of the map have no effect on | 110 // an already added id. |
107 // how the existing value is treated, the IDMap does not delete the existing | 111 V Replace(KeyType id, V new_data) { |
108 // value being replaced. | |
109 T* Replace(KeyType id, T* new_data) { | |
110 DCHECK(sequence_checker_.CalledOnValidSequence()); | 112 DCHECK(sequence_checker_.CalledOnValidSequence()); |
111 DCHECK(!check_on_null_data_ || new_data); | 113 DCHECK(!check_on_null_data_ || new_data); |
112 typename HashTable::iterator i = data_.find(id); | 114 typename HashTable::iterator i = data_.find(id); |
113 if (i == data_.end()) { | 115 DCHECK(i != data_.end()); |
114 NOTREACHED() << "Attempting to replace an item not in the list"; | |
115 return nullptr; | |
116 } | |
117 | 116 |
118 T* temp = i->second; | 117 std::swap(i->second, new_data); |
119 i->second = new_data; | 118 return new_data; |
120 return temp; | |
121 } | 119 } |
122 | 120 |
123 void Clear() { | 121 void Clear() { |
124 DCHECK(sequence_checker_.CalledOnValidSequence()); | 122 DCHECK(sequence_checker_.CalledOnValidSequence()); |
125 if (iteration_depth_ == 0) { | 123 if (iteration_depth_ == 0) { |
126 Releaser<OS, 0>::release_all(&data_); | 124 data_.clear(); |
127 } else { | 125 } else { |
128 for (typename HashTable::iterator i = data_.begin(); | 126 for (typename HashTable::iterator i = data_.begin(); |
129 i != data_.end(); ++i) | 127 i != data_.end(); ++i) |
130 removed_ids_.insert(i->first); | 128 removed_ids_.insert(i->first); |
131 } | 129 } |
132 } | 130 } |
133 | 131 |
134 bool IsEmpty() const { | 132 bool IsEmpty() const { |
135 DCHECK(sequence_checker_.CalledOnValidSequence()); | 133 DCHECK(sequence_checker_.CalledOnValidSequence()); |
136 return size() == 0u; | 134 return size() == 0u; |
137 } | 135 } |
138 | 136 |
139 T* Lookup(KeyType id) const { | 137 T* Lookup(KeyType id) const { |
140 DCHECK(sequence_checker_.CalledOnValidSequence()); | 138 DCHECK(sequence_checker_.CalledOnValidSequence()); |
141 typename HashTable::const_iterator i = data_.find(id); | 139 typename HashTable::const_iterator i = data_.find(id); |
142 if (i == data_.end()) | 140 if (i == data_.end()) |
143 return NULL; | 141 return nullptr; |
144 return i->second; | 142 return &*i->second; |
145 } | 143 } |
146 | 144 |
147 size_t size() const { | 145 size_t size() const { |
148 DCHECK(sequence_checker_.CalledOnValidSequence()); | 146 DCHECK(sequence_checker_.CalledOnValidSequence()); |
149 return data_.size() - removed_ids_.size(); | 147 return data_.size() - removed_ids_.size(); |
150 } | 148 } |
151 | 149 |
152 #if defined(UNIT_TEST) | 150 #if defined(UNIT_TEST) |
153 int iteration_depth() const { | 151 int iteration_depth() const { |
154 return iteration_depth_; | 152 return iteration_depth_; |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
195 return iter_ == map_->data_.end(); | 193 return iter_ == map_->data_.end(); |
196 } | 194 } |
197 | 195 |
198 KeyType GetCurrentKey() const { | 196 KeyType GetCurrentKey() const { |
199 DCHECK(map_->sequence_checker_.CalledOnValidSequence()); | 197 DCHECK(map_->sequence_checker_.CalledOnValidSequence()); |
200 return iter_->first; | 198 return iter_->first; |
201 } | 199 } |
202 | 200 |
203 ReturnType* GetCurrentValue() const { | 201 ReturnType* GetCurrentValue() const { |
204 DCHECK(map_->sequence_checker_.CalledOnValidSequence()); | 202 DCHECK(map_->sequence_checker_.CalledOnValidSequence()); |
205 return iter_->second; | 203 return &*iter_->second; |
206 } | 204 } |
207 | 205 |
208 void Advance() { | 206 void Advance() { |
209 DCHECK(map_->sequence_checker_.CalledOnValidSequence()); | 207 DCHECK(map_->sequence_checker_.CalledOnValidSequence()); |
210 ++iter_; | 208 ++iter_; |
211 SkipRemovedEntries(); | 209 SkipRemovedEntries(); |
212 } | 210 } |
213 | 211 |
214 private: | 212 private: |
215 void Init() { | 213 void Init() { |
(...skipping 11 matching lines...) Expand all Loading... | |
227 } | 225 } |
228 | 226 |
229 IDMap<T, OS, K>* map_; | 227 IDMap<T, OS, K>* map_; |
230 typename HashTable::const_iterator iter_; | 228 typename HashTable::const_iterator iter_; |
231 }; | 229 }; |
232 | 230 |
233 typedef Iterator<T> iterator; | 231 typedef Iterator<T> iterator; |
234 typedef Iterator<const T> const_iterator; | 232 typedef Iterator<const T> const_iterator; |
235 | 233 |
236 private: | 234 private: |
237 | |
238 // The dummy parameter is there because C++ standard does not allow | |
239 // explicitly specialized templates inside classes | |
240 template<IDMapOwnershipSemantics OI, int dummy> struct Releaser { | |
241 static inline void release(T* ptr) {} | |
242 static inline void release_all(HashTable* table) {} | |
243 }; | |
244 | |
245 template<int dummy> struct Releaser<IDMapOwnPointer, dummy> { | |
246 static inline void release(T* ptr) { delete ptr;} | |
247 static inline void release_all(HashTable* table) { | |
248 for (typename HashTable::iterator i = table->begin(); | |
249 i != table->end(); ++i) { | |
250 delete i->second; | |
251 } | |
252 table->clear(); | |
253 } | |
254 }; | |
255 | |
256 void Compact() { | 235 void Compact() { |
257 DCHECK_EQ(0, iteration_depth_); | 236 DCHECK_EQ(0, iteration_depth_); |
258 for (const auto& i : removed_ids_) | 237 for (const auto& i : removed_ids_) |
259 Remove(i); | 238 Remove(i); |
260 removed_ids_.clear(); | 239 removed_ids_.clear(); |
261 } | 240 } |
262 | 241 |
263 // Keep track of how many iterators are currently iterating on us to safely | 242 // Keep track of how many iterators are currently iterating on us to safely |
264 // handle removing items during iteration. | 243 // handle removing items during iteration. |
265 int iteration_depth_; | 244 int iteration_depth_; |
(...skipping 10 matching lines...) Expand all Loading... | |
276 | 255 |
277 // See description above setter. | 256 // See description above setter. |
278 bool check_on_null_data_; | 257 bool check_on_null_data_; |
279 | 258 |
280 base::SequenceChecker sequence_checker_; | 259 base::SequenceChecker sequence_checker_; |
281 | 260 |
282 DISALLOW_COPY_AND_ASSIGN(IDMap); | 261 DISALLOW_COPY_AND_ASSIGN(IDMap); |
283 }; | 262 }; |
284 | 263 |
285 #endif // BASE_ID_MAP_H_ | 264 #endif // BASE_ID_MAP_H_ |
OLD | NEW |