| 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     explicit HashContainer(size_type expectedEntries = 0) | 125     entry_type* find_bucket(key_type_cref key) const | 
| 125         : mEntryCount(0) |  | 
| 126     { |  | 
| 127       expectedEntries = ceil(expectedEntries / LOAD_FACTOR); |  | 
| 128       mBucketCount = MIN_BUCKETS; |  | 
| 129       while (mBucketCount < expectedEntries) |  | 
| 130         mBucketCount <<= 1; |  | 
| 131 |  | 
| 132       mBuckets.reset(new entry_type[mBucketCount]); |  | 
| 133       // Working around https://github.com/waywardmonkeys/emscripten-trace-colle
     ctor/issues/2 here |  | 
| 134       annotate_address(reinterpret_cast<size_type*>(mBuckets.get()) - 1, "Hash t
     able buffer"); |  | 
| 135     } |  | 
| 136 |  | 
| 137     entry_type* find_bucket(const key_type& key) const |  | 
| 138     { | 126     { | 
| 139       size_type h = entry_type::hash(key); | 127       size_type h = entry_type::hash(key); | 
| 140 | 128 | 
| 141       // This does quadratic probing, effectively the following formula is used: | 129       // This does quadratic probing, effectively the following formula is used: | 
| 142       // pos = (hash + 1/2 i + 1/2 i ^ 2) mod bucketCount | 130       // pos = (hash + 1/2 i + 1/2 i ^ 2) mod bucketCount | 
| 143       for (size_type i = 0; ; ++i) | 131       for (size_type i = 0; ; ++i) | 
| 144       { | 132       { | 
| 145         // mBucketCount is 2^n so (h & mBucketCount - 1) is equivalent to | 133         // mBucketCount is 2^n so (h & mBucketCount - 1) is equivalent to | 
| 146         // h % mBucketCount but significantly faster. | 134         // h % mBucketCount but significantly faster. | 
| 147         entry_type* entry = &mBuckets[h & (mBucketCount - 1)]; | 135         entry_type* entry = &mBuckets[h & (mBucketCount - 1)]; | 
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 186         mEntryCount++; | 174         mEntryCount++; | 
| 187 #if defined(DEBUG) | 175 #if defined(DEBUG) | 
| 188         mInsertCounter++; | 176         mInsertCounter++; | 
| 189 #endif | 177 #endif | 
| 190       } | 178       } | 
| 191       *existing = entry; | 179       *existing = entry; | 
| 192       return existing; | 180       return existing; | 
| 193     } | 181     } | 
| 194 | 182 | 
| 195   public: | 183   public: | 
|  | 184     explicit HashContainer(size_type expectedEntries = 0) | 
|  | 185         : mEntryCount(0) | 
|  | 186     { | 
|  | 187       expectedEntries = ceil(expectedEntries / LOAD_FACTOR); | 
|  | 188       mBucketCount = MIN_BUCKETS; | 
|  | 189       while (mBucketCount < expectedEntries) | 
|  | 190         mBucketCount <<= 1; | 
|  | 191 | 
|  | 192       mBuckets.reset(new entry_type[mBucketCount]); | 
|  | 193       // Working around https://github.com/waywardmonkeys/emscripten-trace-colle
     ctor/issues/2 here | 
|  | 194       annotate_address(reinterpret_cast<size_type*>(mBuckets.get()) - 1, "Hash t
     able buffer"); | 
|  | 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, typename Value> | 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 Value value_type; | 239     typedef typename entry_type::value_type value_type; | 
| 239     typedef Map<Entry, Value> 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   typedef typename super::size_type size_type; |  | 
| 277   typedef typename super::entry_type entry_type; |  | 
| 278   typedef typename super::key_type key_type; |  | 
| 279 |  | 
| 280   explicit Set(size_type expectedEntries = 0) |  | 
| 281       : super(expectedEntries) |  | 
| 282   { |  | 
| 283   } |  | 
| 284 }; |  | 
| 285 |  | 
| 286 template<typename Entry, typename Value> |  | 
| 287 class Map : public Map_internal::HashContainer<Entry> | 276 class Map : public Map_internal::HashContainer<Entry> | 
| 288 { | 277 { | 
| 289 public: | 278 public: | 
| 290   typedef Map_internal::HashContainer<Entry> super; | 279   typedef Map_internal::HashContainer<Entry> super; | 
| 291   typedef typename super::size_type size_type; | 280   typedef typename super::size_type size_type; | 
| 292   typedef typename super::entry_type entry_type; | 281   typedef typename super::entry_type entry_type; | 
| 293   typedef typename super::key_type key_type; | 282   typedef typename super::key_type_cref key_type_cref; | 
| 294   typedef Value value_type; | 283   typedef typename entry_type::value_type value_type; | 
| 295   typedef typename super::const_reference const_reference; | 284   typedef typename super::const_reference const_reference; | 
| 296   typedef Map_internal::MapReference<entry_type, value_type> reference; | 285   typedef Map_internal::MapReference<entry_type> reference; | 
| 297   friend struct Map_internal::MapReference<entry_type, value_type>; | 286   friend struct Map_internal::MapReference<entry_type>; | 
| 298 | 287 | 
| 299   explicit Map(size_type expectedEntries = 0) | 288   using super::super; | 
| 300       : super(expectedEntries) |  | 
| 301   { |  | 
| 302   } |  | 
| 303 | 289 | 
| 304   Map(std::initializer_list<entry_type> list) | 290   Map(std::initializer_list<entry_type> list) | 
| 305       : super(list.size()) | 291       : super(list.size()) | 
| 306   { | 292   { | 
| 307     for (const auto& item : list) | 293     for (const auto& item : list) | 
| 308       super::insert(item); | 294       super::insert(item); | 
| 309   } | 295   } | 
| 310 | 296 | 
| 311   value_type& operator[](const key_type& key) | 297   value_type& operator[](key_type_cref key) | 
| 312   { | 298   { | 
| 313     entry_type* entry = super::find_bucket(key); | 299     entry_type* entry = super::find_bucket(key); | 
| 314     if (entry->is_invalid()) | 300     if (entry->is_invalid()) | 
| 315       entry = super::assign(entry, key); | 301       entry = super::assign(entry, key); | 
| 316     return entry->second; | 302     return entry->second; | 
| 317   } | 303   } | 
| 318 | 304 | 
| 319   const_reference find(const key_type& key) const | 305   const_reference find(key_type_cref key) const | 
| 320   { | 306   { | 
| 321     return super::find(key); | 307     return super::find(key); | 
| 322   } | 308   } | 
| 323 | 309 | 
| 324   reference find(const key_type& key) | 310   reference find(key_type_cref key) | 
| 325   { | 311   { | 
| 326     return reference(this, key, super::find_bucket(key)); | 312     return reference(this, key, super::find_bucket(key)); | 
| 327   } | 313   } | 
| 328 }; | 314 }; | 
| LEFT | RIGHT | 
|---|