Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(62)

Side by Side Diff: base/id_map.h

Issue 2340813003: Switch base::IDMap to use unique_ptr. (Closed)
Patch Set: Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698