| LEFT | RIGHT |
| 1 /* | 1 /* |
| 2 * This file is part of Adblock Plus <https://adblockplus.org/>, | 2 * This file is part of Adblock Plus <https://adblockplus.org/>, |
| 3 * Copyright (C) 2006-present eyeo GmbH | 3 * Copyright (C) 2006-present eyeo GmbH |
| 4 * | 4 * |
| 5 * Adblock Plus is free software: you can redistribute it and/or modify | 5 * Adblock Plus is free software: you can redistribute it and/or modify |
| 6 * it under the terms of the GNU General Public License version 3 as | 6 * it under the terms of the GNU General Public License version 3 as |
| 7 * published by the Free Software Foundation. | 7 * published by the Free Software Foundation. |
| 8 * | 8 * |
| 9 * Adblock Plus is distributed in the hope that it will be useful, | 9 * Adblock Plus is distributed in the hope that it will be useful, |
| 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 * GNU General Public License for more details. | 12 * GNU General Public License for more details. |
| 13 * | 13 * |
| 14 * You should have received a copy of the GNU General Public License | 14 * You should have received a copy of the GNU General Public License |
| 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. | 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
| 16 */ | 16 */ |
| 17 | 17 |
| 18 #pragma once | 18 #pragma once |
| 19 | 19 |
| 20 #include <cmath> | 20 #include <cmath> |
| 21 #include <initializer_list> | 21 #include <initializer_list> |
| 22 #include <memory> | 22 #include <memory> |
| 23 | 23 |
| 24 #include "debug.h" | 24 #include "debug.h" |
| 25 | 25 #include "String.h" |
| 26 template<typename Entry, typename Value> | 26 |
| 27 template<typename Entry> |
| 27 class Map; | 28 class Map; |
| 28 | 29 |
| 29 namespace Map_internal | 30 namespace Map_internal |
| 30 { | 31 { |
| 31 template<typename Entry> | 32 template<typename Entry> |
| 32 struct HashContainerIterator | 33 struct HashContainerIterator |
| 33 { | 34 { |
| 34 typedef Entry entry_type; | 35 typedef Entry entry_type; |
| 35 typedef HashContainerIterator<Entry> iterator; | 36 typedef HashContainerIterator<Entry> iterator; |
| 36 | 37 |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 94 { | 95 { |
| 95 return !mEntry->is_invalid(); | 96 return !mEntry->is_invalid(); |
| 96 } | 97 } |
| 97 }; | 98 }; |
| 98 | 99 |
| 99 template<typename Entry> | 100 template<typename Entry> |
| 100 class HashContainer | 101 class HashContainer |
| 101 { | 102 { |
| 102 public: | 103 public: |
| 103 typedef Entry entry_type; | 104 typedef Entry entry_type; |
| 104 typedef typename Entry::key_type key_type; | 105 typedef typename Entry::key_type_cref key_type_cref; |
| 105 typedef typename entry_type::size_type size_type; | 106 typedef typename entry_type::size_type size_type; |
| 106 typedef HashContainerIterator<Entry> const_iterator; | 107 typedef HashContainerIterator<Entry> const_iterator; |
| 107 typedef HashContainerReference<const Entry> const_reference; | 108 typedef HashContainerReference<const Entry> const_reference; |
| 108 | 109 |
| 109 private: | 110 private: |
| 110 explicit HashContainer(const HashContainer& other); | 111 explicit HashContainer(const HashContainer& other); |
| 111 void operator=(const HashContainer& other); | 112 void operator=(const HashContainer& other); |
| 112 | 113 |
| 113 protected: | 114 protected: |
| 114 static constexpr size_type MIN_BUCKETS = 1; | 115 static constexpr size_type MIN_BUCKETS = 1; |
| 115 static constexpr double LOAD_FACTOR = 0.8; | 116 static constexpr double LOAD_FACTOR = 0.8; |
| 116 std::unique_ptr<entry_type[]> mBuckets; | 117 std::unique_ptr<entry_type[]> mBuckets; |
| 117 size_type mBucketCount; | 118 size_type mBucketCount; |
| 118 size_type mEntryCount; | 119 size_type mEntryCount; |
| 119 | 120 |
| 120 #if defined(DEBUG) | 121 #if defined(DEBUG) |
| 121 size_type mInsertCounter; | 122 size_type mInsertCounter; |
| 122 #endif | 123 #endif |
| 123 | 124 |
| 124 entry_type* find_bucket(const key_type& key) const | 125 entry_type* find_bucket(key_type_cref key) const |
| 125 { | 126 { |
| 126 size_type h = entry_type::hash(key); | 127 size_type h = entry_type::hash(key); |
| 127 | 128 |
| 128 // This does quadratic probing, effectively the following formula is used: | 129 // This does quadratic probing, effectively the following formula is used: |
| 129 // pos = (hash + 1/2 i + 1/2 i ^ 2) mod bucketCount | 130 // pos = (hash + 1/2 i + 1/2 i ^ 2) mod bucketCount |
| 130 for (size_type i = 0; ; ++i) | 131 for (size_type i = 0; ; ++i) |
| 131 { | 132 { |
| 132 // mBucketCount is 2^n so (h & mBucketCount - 1) is equivalent to | 133 // mBucketCount is 2^n so (h & mBucketCount - 1) is equivalent to |
| 133 // h % mBucketCount but significantly faster. | 134 // h % mBucketCount but significantly faster. |
| 134 entry_type* entry = &mBuckets[h & (mBucketCount - 1)]; | 135 entry_type* entry = &mBuckets[h & (mBucketCount - 1)]; |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 191 mBuckets.reset(new entry_type[mBucketCount]); | 192 mBuckets.reset(new entry_type[mBucketCount]); |
| 192 // Working around https://github.com/waywardmonkeys/emscripten-trace-colle
ctor/issues/2 here | 193 // Working around https://github.com/waywardmonkeys/emscripten-trace-colle
ctor/issues/2 here |
| 193 annotate_address(reinterpret_cast<size_type*>(mBuckets.get()) - 1, "Hash t
able buffer"); | 194 annotate_address(reinterpret_cast<size_type*>(mBuckets.get()) - 1, "Hash t
able buffer"); |
| 194 } | 195 } |
| 195 | 196 |
| 196 void insert(const entry_type& entry) | 197 void insert(const entry_type& entry) |
| 197 { | 198 { |
| 198 assign(find_bucket(entry.first), entry); | 199 assign(find_bucket(entry.first), entry); |
| 199 } | 200 } |
| 200 | 201 |
| 201 bool erase(const key_type& key) | 202 bool erase(key_type_cref key) |
| 202 { | 203 { |
| 203 entry_type* entry = find_bucket(key); | 204 entry_type* entry = find_bucket(key); |
| 204 if (entry->is_invalid()) | 205 if (entry->is_invalid()) |
| 205 return false; | 206 return false; |
| 206 | 207 |
| 207 entry->erase(); | 208 entry->erase(); |
| 208 return true; | 209 return true; |
| 209 } | 210 } |
| 210 | 211 |
| 211 const_reference find(const key_type& key) const | 212 const_reference find(key_type_cref key) const |
| 212 { | 213 { |
| 213 return const_reference(find_bucket(key)); | 214 return const_reference(find_bucket(key)); |
| 214 } | 215 } |
| 215 | 216 |
| 216 const_iterator begin() const | 217 const_iterator begin() const |
| 217 { | 218 { |
| 218 return const_iterator(&mBuckets[0], &mBuckets[mBucketCount]); | 219 return const_iterator(&mBuckets[0], &mBuckets[mBucketCount]); |
| 219 } | 220 } |
| 220 | 221 |
| 221 const_iterator end() const | 222 const_iterator end() const |
| 222 { | 223 { |
| 223 return const_iterator(&mBuckets[mBucketCount], &mBuckets[mBucketCount]); | 224 return const_iterator(&mBuckets[mBucketCount], &mBuckets[mBucketCount]); |
| 224 } | 225 } |
| 225 | 226 |
| 226 size_type size() const | 227 size_type size() const |
| 227 { | 228 { |
| 228 return mEntryCount; | 229 return mEntryCount; |
| 229 } | 230 } |
| 230 }; | 231 }; |
| 231 | 232 |
| 232 template<typename Entry> | 233 template<typename Entry> |
| 233 struct MapReference : public HashContainerReference<Entry> | 234 struct MapReference : public HashContainerReference<Entry> |
| 234 { | 235 { |
| 235 typedef HashContainerReference<Entry> super; | 236 typedef HashContainerReference<Entry> super; |
| 236 typedef typename super::entry_type entry_type; | 237 typedef typename super::entry_type entry_type; |
| 237 typedef typename entry_type::key_type key_type; | 238 typedef typename entry_type::key_type_cref key_type_cref; |
| 238 typedef typename entry_type::value_type value_type; | 239 typedef typename entry_type::value_type value_type; |
| 239 typedef Map<entry_type, value_type> map_type; | 240 typedef Map<entry_type> map_type; |
| 240 | 241 |
| 241 map_type* mMap; | 242 map_type* mMap; |
| 242 | 243 |
| 243 #if defined(DEBUG) | 244 #if defined(DEBUG) |
| 244 typename map_type::size_type mInsertCounter; | 245 typename map_type::size_type mInsertCounter; |
| 245 typename map_type::size_type mHash; | 246 typename map_type::size_type mHash; |
| 246 #endif | 247 #endif |
| 247 | 248 |
| 248 MapReference(map_type* map, const key_type& key, entry_type* entry) | 249 MapReference(map_type* map, key_type_cref key, entry_type* entry) |
| 249 : super(entry), mMap(map) | 250 : super(entry), mMap(map) |
| 250 { | 251 { |
| 251 #if defined(DEBUG) | 252 #if defined(DEBUG) |
| 252 mInsertCounter = mMap->mInsertCounter; | 253 mInsertCounter = mMap->mInsertCounter; |
| 253 mHash = entry_type::hash(key); | 254 mHash = entry_type::hash(key); |
| 254 #endif | 255 #endif |
| 255 } | 256 } |
| 256 | 257 |
| 257 void assign(const key_type& key, const value_type& value) | 258 void assign(key_type_cref key, const value_type& value) |
| 258 { | 259 { |
| 259 #if defined(DEBUG) | 260 #if defined(DEBUG) |
| 260 assert2(mInsertCounter == mMap->mInsertCounter, | 261 assert2(mInsertCounter == mMap->mInsertCounter, |
| 261 u"There should be no insert operations performed between map.find() an
d assign()"_str); | 262 u"There should be no insert operations performed between map.find() an
d assign()"_str); |
| 262 assert2(mHash == entry_type::hash(key), | 263 assert2(mHash == entry_type::hash(key), |
| 263 u"The keys used in map.find() and assign() should be identical"_str); | 264 u"The keys used in map.find() and assign() should be identical"_str); |
| 264 #endif | 265 #endif |
| 265 | 266 |
| 266 mMap->assign(this->mEntry, entry_type(key, value)); | 267 mMap->assign(this->mEntry, entry_type(key, value)); |
| 267 } | 268 } |
| 268 }; | 269 }; |
| 269 } | 270 } |
| 270 | 271 |
| 271 template<typename Entry> | 272 template<typename Entry> |
| 272 class Set : public Map_internal::HashContainer<Entry> | 273 using Set = Map_internal::HashContainer<Entry>; |
| 273 { | 274 |
| 274 public: | 275 template<typename Entry> |
| 275 typedef Map_internal::HashContainer<Entry> super; | |
| 276 | |
| 277 using super::super; | |
| 278 }; | |
| 279 | |
| 280 template<typename Entry, typename Value> | |
| 281 class Map : public Map_internal::HashContainer<Entry> | 276 class Map : public Map_internal::HashContainer<Entry> |
| 282 { | 277 { |
| 283 public: | 278 public: |
| 284 typedef Map_internal::HashContainer<Entry> super; | 279 typedef Map_internal::HashContainer<Entry> super; |
| 285 typedef typename super::size_type size_type; | 280 typedef typename super::size_type size_type; |
| 286 typedef typename super::entry_type entry_type; | 281 typedef typename super::entry_type entry_type; |
| 287 typedef typename super::key_type key_type; | 282 typedef typename super::key_type_cref key_type_cref; |
| 288 typedef Value value_type; | 283 typedef typename entry_type::value_type value_type; |
| 289 typedef typename super::const_reference const_reference; | 284 typedef typename super::const_reference const_reference; |
| 290 typedef Map_internal::MapReference<entry_type> reference; | 285 typedef Map_internal::MapReference<entry_type> reference; |
| 291 friend struct Map_internal::MapReference<entry_type>; | 286 friend struct Map_internal::MapReference<entry_type>; |
| 292 | 287 |
| 293 using super::super; | 288 using super::super; |
| 294 | 289 |
| 295 Map(std::initializer_list<entry_type> list) | 290 Map(std::initializer_list<entry_type> list) |
| 296 : super(list.size()) | 291 : super(list.size()) |
| 297 { | 292 { |
| 298 for (const auto& item : list) | 293 for (const auto& item : list) |
| 299 super::insert(item); | 294 super::insert(item); |
| 300 } | 295 } |
| 301 | 296 |
| 302 value_type& operator[](const key_type& key) | 297 value_type& operator[](key_type_cref key) |
| 303 { | 298 { |
| 304 entry_type* entry = super::find_bucket(key); | 299 entry_type* entry = super::find_bucket(key); |
| 305 if (entry->is_invalid()) | 300 if (entry->is_invalid()) |
| 306 entry = super::assign(entry, key); | 301 entry = super::assign(entry, key); |
| 307 return entry->second; | 302 return entry->second; |
| 308 } | 303 } |
| 309 | 304 |
| 310 const_reference find(const key_type& key) const | 305 const_reference find(key_type_cref key) const |
| 311 { | 306 { |
| 312 return super::find(key); | 307 return super::find(key); |
| 313 } | 308 } |
| 314 | 309 |
| 315 reference find(const key_type& key) | 310 reference find(key_type_cref key) |
| 316 { | 311 { |
| 317 return reference(this, key, super::find_bucket(key)); | 312 return reference(this, key, super::find_bucket(key)); |
| 318 } | 313 } |
| 319 }; | 314 }; |
| LEFT | RIGHT |