| 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 using V = typename std:: |
| 47 conditional<OS == IDMapExternalPointer, T*, std::unique_ptr<T>>::type; |
| 48 using HashTable = base::hash_map<KeyType, V>; |
| 44 | 49 |
| 45 public: | 50 public: |
| 46 IDMap() : iteration_depth_(0), next_id_(1), check_on_null_data_(false) { | 51 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 | 52 // A number of consumers of IDMap create it on one thread but always |
| 48 // access it from a different, but consistent, thread (or sequence) | 53 // access it from a different, but consistent, thread (or sequence) |
| 49 // post-construction. The first call to CalledOnValidSequence() will re-bind | 54 // post-construction. The first call to CalledOnValidSequence() will re-bind |
| 50 // it. | 55 // it. |
| 51 sequence_checker_.DetachFromSequence(); | 56 sequence_checker_.DetachFromSequence(); |
| 52 } | 57 } |
| 53 | 58 |
| 54 ~IDMap() { | 59 ~IDMap() { |
| 55 // Many IDMap's are static, and hence will be destroyed on the main | 60 // 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 | 61 // 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. | 62 // sequence), such as the IO thread. Detaching again to clean this up. |
| 58 sequence_checker_.DetachFromSequence(); | 63 sequence_checker_.DetachFromSequence(); |
| 59 Releaser<OS, 0>::release_all(&data_); | |
| 60 } | 64 } |
| 61 | 65 |
| 62 // Sets whether Add and Replace should DCHECK if passed in NULL data. | 66 // Sets whether Add and Replace should DCHECK if passed in NULL data. |
| 63 // Default is false. | 67 // Default is false. |
| 64 void set_check_on_null_data(bool value) { check_on_null_data_ = value; } | 68 void set_check_on_null_data(bool value) { check_on_null_data_ = value; } |
| 65 | 69 |
| 66 // Adds a view with an automatically generated unique ID. See AddWithID. | 70 // Adds a view with an automatically generated unique ID. See AddWithID. |
| 67 KeyType Add(T* data) { | 71 // (This unique_ptr<> variant will not compile in IDMapExternalPointer mode.) |
| 68 DCHECK(sequence_checker_.CalledOnValidSequence()); | 72 KeyType Add(std::unique_ptr<T> data) { |
| 69 DCHECK(!check_on_null_data_ || data); | 73 return AddInternal(std::move(data)); |
| 70 KeyType this_id = next_id_; | |
| 71 DCHECK(data_.find(this_id) == data_.end()) << "Inserting duplicate item"; | |
| 72 data_[this_id] = data; | |
| 73 next_id_++; | |
| 74 return this_id; | |
| 75 } | 74 } |
| 76 | 75 |
| 77 // Adds a new data member with the specified ID. The ID must not be in | 76 // 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 | 77 // 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 | 78 // 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 | 79 // two methods may not be mixed, or duplicate IDs may be generated. |
| 80 // (This unique_ptr<> variant will not compile in IDMapExternalPointer mode.) |
| 81 void AddWithID(std::unique_ptr<T> data, KeyType id) { |
| 82 AddWithIDInternal(std::move(data), id); |
| 83 } |
| 84 |
| 85 // http://crbug.com/647091: Raw pointer Add()s in IDMapOwnPointer mode are |
| 86 // deprecated. Users of IDMapOwnPointer should transition to the unique_ptr |
| 87 // variant above, and the following methods should only be used in |
| 88 // IDMapExternalPointer mode. |
| 89 KeyType Add(T* data) { |
| 90 return AddInternal(V(data)); |
| 91 } |
| 81 void AddWithID(T* data, KeyType id) { | 92 void AddWithID(T* data, KeyType id) { |
| 82 DCHECK(sequence_checker_.CalledOnValidSequence()); | 93 AddWithIDInternal(V(data), id); |
| 83 DCHECK(!check_on_null_data_ || data); | |
| 84 DCHECK(data_.find(id) == data_.end()) << "Inserting duplicate item"; | |
| 85 data_[id] = data; | |
| 86 } | 94 } |
| 87 | 95 |
| 88 void Remove(KeyType id) { | 96 void Remove(KeyType id) { |
| 89 DCHECK(sequence_checker_.CalledOnValidSequence()); | 97 DCHECK(sequence_checker_.CalledOnValidSequence()); |
| 90 typename HashTable::iterator i = data_.find(id); | 98 typename HashTable::iterator i = data_.find(id); |
| 91 if (i == data_.end()) { | 99 if (i == data_.end()) { |
| 92 NOTREACHED() << "Attempting to remove an item not in the list"; | 100 NOTREACHED() << "Attempting to remove an item not in the list"; |
| 93 return; | 101 return; |
| 94 } | 102 } |
| 95 | 103 |
| 96 if (iteration_depth_ == 0) { | 104 if (iteration_depth_ == 0) { |
| 97 Releaser<OS, 0>::release(i->second); | |
| 98 data_.erase(i); | 105 data_.erase(i); |
| 99 } else { | 106 } else { |
| 100 removed_ids_.insert(id); | 107 removed_ids_.insert(id); |
| 101 } | 108 } |
| 102 } | 109 } |
| 103 | 110 |
| 104 // Replaces the value for |id| with |new_data| and returns a pointer to the | 111 // 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 | 112 // (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 | 113 // an already added id. |
| 107 // how the existing value is treated, the IDMap does not delete the existing | 114 V Replace(KeyType id, V new_data) { |
| 108 // value being replaced. | |
| 109 T* Replace(KeyType id, T* new_data) { | |
| 110 DCHECK(sequence_checker_.CalledOnValidSequence()); | 115 DCHECK(sequence_checker_.CalledOnValidSequence()); |
| 111 DCHECK(!check_on_null_data_ || new_data); | 116 DCHECK(!check_on_null_data_ || new_data); |
| 112 typename HashTable::iterator i = data_.find(id); | 117 typename HashTable::iterator i = data_.find(id); |
| 113 if (i == data_.end()) { | 118 DCHECK(i != data_.end()); |
| 114 NOTREACHED() << "Attempting to replace an item not in the list"; | |
| 115 return nullptr; | |
| 116 } | |
| 117 | 119 |
| 118 T* temp = i->second; | 120 std::swap(i->second, new_data); |
| 119 i->second = new_data; | 121 return new_data; |
| 120 return temp; | |
| 121 } | 122 } |
| 122 | 123 |
| 123 void Clear() { | 124 void Clear() { |
| 124 DCHECK(sequence_checker_.CalledOnValidSequence()); | 125 DCHECK(sequence_checker_.CalledOnValidSequence()); |
| 125 if (iteration_depth_ == 0) { | 126 if (iteration_depth_ == 0) { |
| 126 Releaser<OS, 0>::release_all(&data_); | 127 data_.clear(); |
| 127 } else { | 128 } else { |
| 128 for (typename HashTable::iterator i = data_.begin(); | 129 for (typename HashTable::iterator i = data_.begin(); |
| 129 i != data_.end(); ++i) | 130 i != data_.end(); ++i) |
| 130 removed_ids_.insert(i->first); | 131 removed_ids_.insert(i->first); |
| 131 } | 132 } |
| 132 } | 133 } |
| 133 | 134 |
| 134 bool IsEmpty() const { | 135 bool IsEmpty() const { |
| 135 DCHECK(sequence_checker_.CalledOnValidSequence()); | 136 DCHECK(sequence_checker_.CalledOnValidSequence()); |
| 136 return size() == 0u; | 137 return size() == 0u; |
| 137 } | 138 } |
| 138 | 139 |
| 139 T* Lookup(KeyType id) const { | 140 T* Lookup(KeyType id) const { |
| 140 DCHECK(sequence_checker_.CalledOnValidSequence()); | 141 DCHECK(sequence_checker_.CalledOnValidSequence()); |
| 141 typename HashTable::const_iterator i = data_.find(id); | 142 typename HashTable::const_iterator i = data_.find(id); |
| 142 if (i == data_.end()) | 143 if (i == data_.end()) |
| 143 return NULL; | 144 return nullptr; |
| 144 return i->second; | 145 return &*i->second; |
| 145 } | 146 } |
| 146 | 147 |
| 147 size_t size() const { | 148 size_t size() const { |
| 148 DCHECK(sequence_checker_.CalledOnValidSequence()); | 149 DCHECK(sequence_checker_.CalledOnValidSequence()); |
| 149 return data_.size() - removed_ids_.size(); | 150 return data_.size() - removed_ids_.size(); |
| 150 } | 151 } |
| 151 | 152 |
| 152 #if defined(UNIT_TEST) | 153 #if defined(UNIT_TEST) |
| 153 int iteration_depth() const { | 154 int iteration_depth() const { |
| 154 return iteration_depth_; | 155 return iteration_depth_; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 195 return iter_ == map_->data_.end(); | 196 return iter_ == map_->data_.end(); |
| 196 } | 197 } |
| 197 | 198 |
| 198 KeyType GetCurrentKey() const { | 199 KeyType GetCurrentKey() const { |
| 199 DCHECK(map_->sequence_checker_.CalledOnValidSequence()); | 200 DCHECK(map_->sequence_checker_.CalledOnValidSequence()); |
| 200 return iter_->first; | 201 return iter_->first; |
| 201 } | 202 } |
| 202 | 203 |
| 203 ReturnType* GetCurrentValue() const { | 204 ReturnType* GetCurrentValue() const { |
| 204 DCHECK(map_->sequence_checker_.CalledOnValidSequence()); | 205 DCHECK(map_->sequence_checker_.CalledOnValidSequence()); |
| 205 return iter_->second; | 206 return &*iter_->second; |
| 206 } | 207 } |
| 207 | 208 |
| 208 void Advance() { | 209 void Advance() { |
| 209 DCHECK(map_->sequence_checker_.CalledOnValidSequence()); | 210 DCHECK(map_->sequence_checker_.CalledOnValidSequence()); |
| 210 ++iter_; | 211 ++iter_; |
| 211 SkipRemovedEntries(); | 212 SkipRemovedEntries(); |
| 212 } | 213 } |
| 213 | 214 |
| 214 private: | 215 private: |
| 215 void Init() { | 216 void Init() { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 227 } | 228 } |
| 228 | 229 |
| 229 IDMap<T, OS, K>* map_; | 230 IDMap<T, OS, K>* map_; |
| 230 typename HashTable::const_iterator iter_; | 231 typename HashTable::const_iterator iter_; |
| 231 }; | 232 }; |
| 232 | 233 |
| 233 typedef Iterator<T> iterator; | 234 typedef Iterator<T> iterator; |
| 234 typedef Iterator<const T> const_iterator; | 235 typedef Iterator<const T> const_iterator; |
| 235 | 236 |
| 236 private: | 237 private: |
| 238 KeyType AddInternal(V data) { |
| 239 DCHECK(sequence_checker_.CalledOnValidSequence()); |
| 240 DCHECK(!check_on_null_data_ || data); |
| 241 KeyType this_id = next_id_; |
| 242 DCHECK(data_.find(this_id) == data_.end()) << "Inserting duplicate item"; |
| 243 data_[this_id] = std::move(data); |
| 244 next_id_++; |
| 245 return this_id; |
| 246 } |
| 237 | 247 |
| 238 // The dummy parameter is there because C++ standard does not allow | 248 void AddWithIDInternal(V data, KeyType id) { |
| 239 // explicitly specialized templates inside classes | 249 DCHECK(sequence_checker_.CalledOnValidSequence()); |
| 240 template<IDMapOwnershipSemantics OI, int dummy> struct Releaser { | 250 DCHECK(!check_on_null_data_ || data); |
| 241 static inline void release(T* ptr) {} | 251 DCHECK(data_.find(id) == data_.end()) << "Inserting duplicate item"; |
| 242 static inline void release_all(HashTable* table) {} | 252 data_[id] = std::move(data); |
| 243 }; | 253 } |
| 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 | 254 |
| 256 void Compact() { | 255 void Compact() { |
| 257 DCHECK_EQ(0, iteration_depth_); | 256 DCHECK_EQ(0, iteration_depth_); |
| 258 for (const auto& i : removed_ids_) | 257 for (const auto& i : removed_ids_) |
| 259 Remove(i); | 258 Remove(i); |
| 260 removed_ids_.clear(); | 259 removed_ids_.clear(); |
| 261 } | 260 } |
| 262 | 261 |
| 263 // Keep track of how many iterators are currently iterating on us to safely | 262 // Keep track of how many iterators are currently iterating on us to safely |
| 264 // handle removing items during iteration. | 263 // handle removing items during iteration. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 276 | 275 |
| 277 // See description above setter. | 276 // See description above setter. |
| 278 bool check_on_null_data_; | 277 bool check_on_null_data_; |
| 279 | 278 |
| 280 base::SequenceChecker sequence_checker_; | 279 base::SequenceChecker sequence_checker_; |
| 281 | 280 |
| 282 DISALLOW_COPY_AND_ASSIGN(IDMap); | 281 DISALLOW_COPY_AND_ASSIGN(IDMap); |
| 283 }; | 282 }; |
| 284 | 283 |
| 285 #endif // BASE_ID_MAP_H_ | 284 #endif // BASE_ID_MAP_H_ |
| OLD | NEW |