LCOV - app.info - objdir/dist/include/js/HashTable.h

LCOV - code coverage report
| Current view: | directory - objdir/dist/include/js - HashTable.h (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 429 | 403 | 93.9 %
| Date: | 2012-04-07 | Functions: | 2975 | 2528 | 85.0 %

           1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
           2                 :  * vim: set ts=8 sw=4 et tw=99 ft=cpp:
           3                 :  *
           4                 :  * ***** BEGIN LICENSE BLOCK *****
           5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           6                 :  *
           7                 :  * The contents of this file are subject to the Mozilla Public License Version
           8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           9                 :  * the License. You may obtain a copy of the License at
          10                 :  * http://www.mozilla.org/MPL/
          11                 :  *
          12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          14                 :  * for the specific language governing rights and limitations under the
          15                 :  * License.
          16                 :  *
          17                 :  * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
          18                 :  * November 13, 2009.
          19                 :  *
          20                 :  * The Initial Developer of the Original Code is
          21                 :  *   the Mozilla Corporation.
          22                 :  *
          23                 :  * Contributor(s):
          24                 :  *   Brendan Eich <brendan@mozilla.org> (Original Author)
          25                 :  *   Chris Waterson <waterson@netscape.com>
          26                 :  *   L. David Baron <dbaron@dbaron.org>, Mozilla Corporation
          27                 :  *   Luke Wagner <lw@mozilla.com>
          28                 :  *
          29                 :  * Alternatively, the contents of this file may be used under the terms of
          30                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
          31                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          32                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          33                 :  * of those above. If you wish to allow use of your version of this file only
          34                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          35                 :  * use your version of this file under the terms of the MPL, indicate your
          36                 :  * decision by deleting the provisions above and replace them with the notice
          37                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          38                 :  * the provisions above, a recipient may use your version of this file under
          39                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          40                 :  *
          41                 :  * ***** END LICENSE BLOCK ***** */
          42                 :
          43                 : #ifndef jshashtable_h_
          44                 : #define jshashtable_h_
          45                 :
          46                 : #include "TemplateLib.h"
          47                 : #include "Utility.h"
          48                 :
          49                 : namespace js {
          50                 :
          51                 : class TempAllocPolicy;
          52                 :
          53                 : /* Integral types for all hash functions. */
          54                 : typedef uint32_t HashNumber;
          55                 :
          56                 : /*****************************************************************************/
          57                 :
          58                 : namespace detail {
          59                 :
          60                 : template <class T, class HashPolicy, class AllocPolicy>
          61                 : class HashTable;
          62                 :
          63                 : template <class T>
          64       533808308 : class HashTableEntry {
          65                 :     HashNumber keyHash;
          66                 :
          67                 :     typedef typename tl::StripConst<T>::result NonConstT;
          68                 :
          69                 :     static const HashNumber sFreeKey = 0;
          70                 :     static const HashNumber sRemovedKey = 1;
          71                 :     static const HashNumber sCollisionBit = 1;
          72                 :
          73                 :     template <class, class, class> friend class HashTable;
          74                 :
          75     -1922557132 :     static bool isLiveHash(HashNumber hash)
          76                 :     {
          77     -1922557132 :         return hash > sRemovedKey;
          78                 :     }
          79                 :
          80                 :   public:
          81       540800196 :     HashTableEntry() : keyHash(0), t() {}
          82                 :     HashTableEntry(MoveRef<HashTableEntry> rhs) : keyHash(rhs->keyHash), t(Move(rhs->t)) { }
          83                 :     void operator=(const HashTableEntry &rhs) { keyHash = rhs.keyHash; t = rhs.t; }
          84       126752654 :     void operator=(MoveRef<HashTableEntry> rhs) { keyHash = rhs->keyHash; t = Move(rhs->t); }
          85                 :
          86                 :     NonConstT t;
          87                 :
          88       806717889 :     bool isFree() const           { return keyHash == sFreeKey; }
          89        12248994 :     void setFree()                { keyHash = sFreeKey; t = T(); }
          90       355932938 :     bool isRemoved() const        { return keyHash == sRemovedKey; }
          91         3999617 :     void setRemoved()             { keyHash = sRemovedKey; t = T(); }
          92      1422174543 :     bool isLive() const           { return isLiveHash(keyHash); }
          93       102395950 :     void setLive(HashNumber hn)   { JS_ASSERT(isLiveHash(hn)); keyHash = hn; }
          94                 :
          95        22399004 :     void setCollision()           { JS_ASSERT(isLive()); keyHash |= sCollisionBit; }
          96       230454619 :     void setCollision(HashNumber collisionBit) {
          97       230454619 :         JS_ASSERT(isLive()); keyHash |= collisionBit;
          98       230454619 :     }
          99       119750190 :     void unsetCollision()         { keyHash &= ~sCollisionBit; }
         100       135998801 :     bool hasCollision() const     { JS_ASSERT(isLive()); return keyHash & sCollisionBit; }
         101       335262681 :     bool matchHash(HashNumber hn) { return (keyHash & ~sCollisionBit) == hn; }
         102       119750190 :     HashNumber getKeyHash() const { JS_ASSERT(!hasCollision()); return keyHash; }
         103                 : };
         104                 :
         105                 : /*
         106                 :  * js::detail::HashTable is an implementation detail of the js::HashMap and
         107                 :  * js::HashSet templates. For js::Hash{Map,Set} API documentation and examples,
         108                 :  * skip to the end of the detail namespace.
         109                 :  */
         110                 :
         111                 : /* Reusable implementation of HashMap and HashSet. */
         112                 : template <class T, class HashPolicy, class AllocPolicy>
         113                 : class HashTable : private AllocPolicy
         114                 : {
         115                 :     typedef typename tl::StripConst<T>::result NonConstT;
         116                 :     typedef typename HashPolicy::KeyType Key;
         117                 :     typedef typename HashPolicy::Lookup Lookup;
         118                 :
         119                 :   public:
         120                 :     typedef HashTableEntry<T> Entry;
         121                 :
         122                 :     /*
         123                 :      * A nullable pointer to a hash table element. A Ptr |p| can be tested
         124                 :      * either explicitly |if (p.found()) p->...| or using boolean conversion
         125                 :      * |if (p) p->...|. Ptr objects must not be used after any mutating hash
         126                 :      * table operations unless |generation()| is tested.
         127                 :      */
         128                 :     class Ptr
         129                 :     {
         130                 :         friend class HashTable;
         131                 :         typedef void (Ptr::* ConvertibleToBool)();
         132               0 :         void nonNull() {}
         133                 :
         134                 :         Entry *entry;
         135                 :
         136                 :       protected:
         137       414634394 :         Ptr(Entry &entry) : entry(&entry) {}
         138                 :
         139                 :       public:
         140                 :         /* Leaves Ptr uninitialized. */
         141         9487930 :         Ptr() {
         142                 : #ifdef DEBUG
         143         9487930 :             entry = (Entry *)0xbad;
         144                 : #endif
         145         9487930 :         }
         146                 :
         147       532129659 :         bool found() const                    { return entry->isLive(); }
         148       408247616 :         operator ConvertibleToBool() const    { return found() ? &Ptr::nonNull : 0; }
         149                 :         bool operator==(const Ptr &rhs) const { JS_ASSERT(found() && rhs.found()); return entry == rhs.entry; }
         150                 :         bool operator!=(const Ptr &rhs) const { return !(*this == rhs); }
         151                 :
         152        45595323 :         T &operator*() const                  { return entry->t; }
         153        54646749 :         T *operator->() const                 { return &entry->t; }
         154                 :     };
         155                 :
         156                 :     /* A Ptr that can be used to add a key after a failed lookup. */
         157                 :     class AddPtr : public Ptr
         158       186703248 :     {
         159                 :         friend class HashTable;
         160                 :         HashNumber keyHash;
         161                 :         DebugOnly<uint64_t> mutationCount;
         162                 :
         163       180578947 :         AddPtr(Entry &entry, HashNumber hn) : Ptr(entry), keyHash(hn) {}
         164                 :       public:
         165                 :         /* Leaves AddPtr uninitialized. */
         166         4790663 :         AddPtr() {}
         167                 :     };
         168                 :
         169                 :     /*
         170                 :      * A collection of hash table entries. The collection is enumerated by
         171                 :      * calling |front()| followed by |popFront()| as long as |!empty()|. As
         172                 :      * with Ptr/AddPtr, Range objects must not be used after any mutating hash
         173                 :      * table operation unless the |generation()| is tested.
         174                 :      */
         175                 :     class Range
         176                 :     {
         177                 :       protected:
         178                 :         friend class HashTable;
         179                 :
         180         1069429 :         Range(Entry *c, Entry *e) : cur(c), end(e) {
         181        56305919 :             while (cur < end && !cur->isLive())
         182        54167061 :                 ++cur;
         183         1069429 :         }
         184                 :
         185                 :         Entry *cur, *end;
         186                 :
         187                 :       public:
         188          127476 :         Range() : cur(NULL), end(NULL) {}
         189                 :
         190       215289624 :         bool empty() const {
         191       215289624 :             return cur == end;
         192                 :         }
         193                 :
         194        76553596 :         T &front() const {
         195        76553596 :             JS_ASSERT(!empty());
         196        76553596 :             return cur->t;
         197                 :         }
         198                 :
         199        68839776 :         void popFront() {
         200        68839776 :             JS_ASSERT(!empty());
         201       296111544 :             while (++cur < end && !cur->isLive())
         202       158431992 :                 continue;
         203        68839776 :         }
         204                 :     };
         205                 :
         206                 :     /*
         207                 :      * A Range whose lifetime delimits a mutating enumeration of a hash table.
         208                 :      * Since rehashing when elements were removed during enumeration would be
         209                 :      * bad, it is postponed until |endEnumeration()| is called. If
         210                 :      * |endEnumeration()| is not called before an Enum's constructor, it will
         211                 :      * be called automatically. Since |endEnumeration()| touches the hash
         212                 :      * table, the user must ensure that the hash table is still alive when this
         213                 :      * happens.
         214                 :      */
         215                 :     class Enum : public Range
         216                 :     {
         217                 :         friend class HashTable;
         218                 :
         219                 :         HashTable &table;
         220                 :         bool added;
         221                 :         bool removed;
         222                 :
         223                 :         /* Not copyable. */
         224                 :         Enum(const Enum &);
         225                 :         void operator=(const Enum &);
         226                 :
         227                 :       public:
         228                 :         template<class Map> explicit
         229          601929 :         Enum(Map &map) : Range(map.all()), table(map.impl), added(false), removed(false) {}
         230                 :
         231                 :         /*
         232                 :          * Removes the |front()| element from the table, leaving |front()|
         233                 :          * invalid until the next call to |popFront()|. For example:
         234                 :          *
         235                 :          *   HashSet<int> s;
         236                 :          *   for (HashSet<int>::Enum e(s); !e.empty(); e.popFront())
         237                 :          *     if (e.front() == 42)
         238                 :          *       e.removeFront();
         239                 :          */
         240        15387131 :         void removeFront() {
         241        15387131 :             table.remove(*this->cur);
         242        15387131 :             removed = true;
         243        15387131 :         }
         244                 :
         245                 :         /*
         246                 :          * Removes the |front()| element and re-inserts it into the table with
         247                 :          * a new key at the new Lookup position.  |front()| is invalid after
         248                 :          * this operation until the next call to |popFront()|.
         249                 :          */
         250          299938 :         void rekeyFront(Key &k) {
         251          299938 :             JS_ASSERT(&k != &HashPolicy::getKey(this->cur->t));
         252          299938 :             JS_ASSERT(!table.match(*this->cur, k));
         253          299938 :             Entry e = *this->cur;
         254          299938 :             HashPolicy::setKey(e.t, k);
         255          299938 :             table.remove(*this->cur);
         256          299938 :             table.add(k, e);
         257          299938 :             added = true;
         258          299938 :         }
         259                 :
         260                 :         /* Potentially rehashes the table. */
         261          601929 :         ~Enum() {
         262          601929 :             if (added)
         263              40 :                 table.checkOverloaded();
         264          601929 :             if (removed)
         265          164833 :                 table.checkUnderloaded();
         266          601929 :         }
         267                 :
         268                 :         /* Can be used to end the enumeration before the destructor. */
         269                 :         void endEnumeration() {
         270                 :             if (added) {
         271                 :                 table.checkOverloaded();
         272                 :                 added = false;
         273                 :             }
         274                 :             if (removed) {
         275                 :                 table.checkUnderloaded();
         276                 :                 removed = false;
         277                 :             }
         278                 :         }
         279                 :     };
         280                 :
         281                 :   private:
         282                 :     uint32_t    hashShift;      /* multiplicative hash shift */
         283                 :     uint32_t    entryCount;     /* number of entries in table */
         284                 :     uint32_t    gen;            /* entry storage generation number */
         285                 :     uint32_t    removedCount;   /* removed entry sentinels in table */
         286                 :     Entry       *table;         /* entry storage */
         287                 :
         288         3838054 :     void setTableSizeLog2(unsigned sizeLog2) {
         289         3838054 :         hashShift = sHashBits - sizeLog2;
         290         3838054 :     }
         291                 :
         292                 : #ifdef DEBUG
         293                 :     mutable struct Stats {
         294                 :         uint32_t        searches;       /* total number of table searches */
         295                 :         uint32_t        steps;          /* hash chain links traversed */
         296                 :         uint32_t        hits;           /* searches that found key */
         297                 :         uint32_t        misses;         /* searches that didn't find key */
         298                 :         uint32_t        addOverRemoved; /* adds that recycled a removed entry */
         299                 :         uint32_t        removes;        /* calls to remove */
         300                 :         uint32_t        removeFrees;    /* calls to remove that freed the entry */
         301                 :         uint32_t        grows;          /* table expansions */
         302                 :         uint32_t        shrinks;        /* table contractions */
         303                 :         uint32_t        compresses;     /* table compressions */
         304                 :     } stats;
         305                 : #   define METER(x) x
         306                 : #else
         307                 : #   define METER(x)
         308                 : #endif
         309                 :
         310                 :     friend class js::ReentrancyGuard;
         311                 :     mutable DebugOnly<bool> entered;
         312                 :     DebugOnly<uint64_t>     mutationCount;
         313                 :
         314                 :     /* The default initial capacity is 16, but you can ask for as small as 4. */
         315                 :     static const unsigned sMinSizeLog2  = 2;
         316                 :     static const unsigned sMinSize      = 1 << sMinSizeLog2;
         317                 :     static const unsigned sDefaultInitSizeLog2 = 4;
         318                 :   public:
         319                 :     static const unsigned sDefaultInitSize = 1 << sDefaultInitSizeLog2;
         320                 :   private:
         321                 :     static const unsigned sMaxInit      = JS_BIT(23);
         322                 :     static const unsigned sMaxCapacity  = JS_BIT(24);
         323                 :     static const unsigned sHashBits     = tl::BitSize<HashNumber>::result;
         324                 :     static const uint8_t  sMinAlphaFrac = 64;  /* (0x100 * .25) taken from jsdhash.h */
         325                 :     static const uint8_t  sMaxAlphaFrac = 192; /* (0x100 * .75) taken from jsdhash.h */
         326                 :     static const uint8_t  sInvMaxAlpha  = 171; /* (ceil(0x100 / .75) >> 1) */
         327                 :     static const HashNumber sGoldenRatio  = 0x9E3779B9U;       /* taken from jsdhash.h */
         328                 :     static const HashNumber sFreeKey = Entry::sFreeKey;
         329                 :     static const HashNumber sRemovedKey = Entry::sRemovedKey;
         330                 :     static const HashNumber sCollisionBit = Entry::sCollisionBit;
         331                 :
         332                 :     static void staticAsserts()
         333                 :     {
         334                 :         /* Rely on compiler "constant overflow warnings". */
         335                 :         JS_STATIC_ASSERT(((sMaxInit * sInvMaxAlpha) >> 7) < sMaxCapacity);
         336                 :         JS_STATIC_ASSERT((sMaxCapacity * sInvMaxAlpha) <= UINT32_MAX);
         337                 :         JS_STATIC_ASSERT((sMaxCapacity * sizeof(Entry)) <= UINT32_MAX);
         338                 :     }
         339                 :
         340       847839671 :     static bool isLiveHash(HashNumber hash)
         341                 :     {
         342       847839671 :         return Entry::isLiveHash(hash);
         343                 :     }
         344                 :
         345       414934332 :     static HashNumber prepareHash(const Lookup& l)
         346                 :     {
         347       414934332 :         HashNumber keyHash = HashPolicy::hash(l);
         348                 :
         349                 :         /* Improve keyHash distribution. */
         350       414934332 :         keyHash *= sGoldenRatio;
         351                 :
         352                 :         /* Avoid reserved hash codes. */
         353       414934332 :         if (!isLiveHash(keyHash))
         354       119573220 :             keyHash -= (sRemovedKey + 1);
         355       414934332 :         return keyHash & ~sCollisionBit;
         356                 :     }
         357                 :
         358         3838054 :     static Entry *createTable(AllocPolicy &alloc, uint32_t capacity)
         359                 :     {
         360         3838054 :         Entry *newTable = (Entry *)alloc.malloc_(capacity * sizeof(Entry));
         361         3838054 :         if (!newTable)
         362               0 :             return NULL;
         363       537635786 :         for (Entry *e = newTable, *end = e + capacity; e < end; ++e)
         364       533797732 :             new(e) Entry();
         365         3838054 :         return newTable;
         366                 :     }
         367                 :
         368         3838054 :     static void destroyTable(AllocPolicy &alloc, Entry *oldTable, uint32_t capacity)
         369                 :     {
         370       537635786 :         for (Entry *e = oldTable, *end = e + capacity; e < end; ++e)
         371       533797732 :             e->~Entry();
         372         3838054 :         alloc.free_(oldTable);
         373         3838054 :     }
         374                 :
         375                 :   public:
         376         3400418 :     HashTable(AllocPolicy ap)
         377                 :       : AllocPolicy(ap),
         378                 :         hashShift(sHashBits),
         379                 :         entryCount(0),
         380                 :         gen(0),
         381                 :         removedCount(0),
         382                 :         table(NULL),
         383                 :         entered(false),
         384         3400418 :         mutationCount(0)
         385         3400418 :     {}
         386                 :
         387         3092544 :     bool init(uint32_t length)
         388                 :     {
         389                 :         /* Make sure that init isn't called twice. */
         390         3092544 :         JS_ASSERT(table == NULL);
         391                 :
         392                 :         /*
         393                 :          * Correct for sMaxAlphaFrac such that the table will not resize
         394                 :          * when adding 'length' entries.
         395                 :          */
         396         3092544 :         if (length > sMaxInit) {
         397               0 :             this->reportAllocOverflow();
         398               0 :             return false;
         399                 :         }
         400         3092544 :         uint32_t capacity = (length * sInvMaxAlpha) >> 7;
         401                 :
         402         3092544 :         if (capacity < sMinSize)
         403          708946 :             capacity = sMinSize;
         404                 :
         405                 :         /* FIXME: use JS_CEILING_LOG2 when PGO stops crashing (bug 543034). */
         406         3092544 :         uint32_t roundUp = sMinSize, roundUpLog2 = sMinSizeLog2;
         407        15316053 :         while (roundUp < capacity) {
         408         9130965 :             roundUp <<= 1;
         409         9130965 :             ++roundUpLog2;
         410                 :         }
         411                 :
         412         3092544 :         capacity = roundUp;
         413         3092544 :         JS_ASSERT(capacity <= sMaxCapacity);
         414                 :
         415         3092544 :         table = createTable(*this, capacity);
         416         3092544 :         if (!table)
         417               0 :             return false;
         418                 :
         419         3092544 :         setTableSizeLog2(roundUpLog2);
         420         3092544 :         METER(memset(&stats, 0, sizeof(stats)));
         421         3092544 :         return true;
         422                 :     }
         423                 :
         424        54607262 :     bool initialized() const
         425                 :     {
         426        54607262 :         return !!table;
         427                 :     }
         428                 :
         429         3400418 :     ~HashTable()
         430                 :     {
         431         3400418 :         if (table)
         432         3070974 :             destroyTable(*this, table, capacity());
         433         3400418 :     }
         434                 :
         435                 :   private:
         436       553180901 :     static HashNumber hash1(HashNumber hash0, uint32_t shift) {
         437       553180901 :         return hash0 >> shift;
         438                 :     }
         439                 :
         440                 :     struct DoubleHash {
         441                 :         HashNumber h2;
         442                 :         HashNumber sizeMask;
         443                 :     };
         444                 :
         445       117872256 :     DoubleHash hash2(HashNumber curKeyHash, uint32_t hashShift) const {
         446       117872256 :         unsigned sizeLog2 = sHashBits - hashShift;
         447                 :         DoubleHash dh = {
         448                 :             ((curKeyHash << sizeLog2) >> hashShift) | 1,
         449                 :             (HashNumber(1) << sizeLog2) - 1
         450       117872256 :         };
         451                 :         return dh;
         452                 :     }
         453                 :
         454       253536988 :     static HashNumber applyDoubleHash(HashNumber h1, const DoubleHash &dh) {
         455       253536988 :         return (h1 - dh.h2) & dh.sizeMask;
         456                 :     }
         457                 :
         458       102004229 :     bool overloaded() {
         459       102004229 :         return entryCount + removedCount >= ((sMaxAlphaFrac * capacity()) >> 8);
         460                 :     }
         461                 :
         462          726375 :     bool underloaded() {
         463          726375 :         uint32_t tableCapacity = capacity();
         464                 :         return tableCapacity > sMinSize &&
         465          726375 :                entryCount <= ((sMinAlphaFrac * tableCapacity) >> 8);
         466                 :     }
         467                 :
         468       107219695 :     static bool match(Entry &e, const Lookup &l) {
         469       107219695 :         return HashPolicy::match(HashPolicy::getKey(e.t), l);
         470                 :     }
         471                 :
         472       432905339 :     Entry &lookup(const Lookup &l, HashNumber keyHash, unsigned collisionBit) const
         473                 :     {
         474       432905339 :         JS_ASSERT(isLiveHash(keyHash));
         475       432905339 :         JS_ASSERT(!(keyHash & sCollisionBit));
         476       432905339 :         JS_ASSERT(collisionBit == 0 || collisionBit == sCollisionBit);
         477       432905339 :         JS_ASSERT(table);
         478       432905339 :         METER(stats.searches++);
         479                 :
         480                 :         /* Compute the primary hash address. */
         481       432905339 :         HashNumber h1 = hash1(keyHash, hashShift);
         482       432905339 :         Entry *entry = &table[h1];
         483                 :
         484                 :         /* Miss: return space for a new entry. */
         485       432905339 :         if (entry->isFree()) {
         486       251825808 :             METER(stats.misses++);
         487       251825808 :             return *entry;
         488                 :         }
         489                 :
         490                 :         /* Hit: return entry. */
         491       181079531 :         if (entry->matchHash(keyHash) && match(*entry, l)) {
         492        78895236 :             METER(stats.hits++);
         493        78895236 :             return *entry;
         494                 :         }
         495                 :
         496                 :         /* Collision: double hash. */
         497       102184295 :         DoubleHash dh = hash2(keyHash, hashShift);
         498                 :
         499                 :         /* Save the first removed entry pointer so we can recycle later. */
         500       102184295 :         Entry *firstRemoved = NULL;
         501                 :
         502       128953689 :         while(true) {
         503       231137984 :             if (JS_UNLIKELY(entry->isRemoved())) {
         504          683365 :                 if (!firstRemoved)
         505          340707 :                     firstRemoved = entry;
         506                 :             } else {
         507       230454619 :                 entry->setCollision(collisionBit);
         508                 :             }
         509                 :
         510       231137984 :             METER(stats.steps++);
         511       231137984 :             h1 = applyDoubleHash(h1, dh);
         512                 :
         513       231137984 :             entry = &table[h1];
         514       231137984 :             if (entry->isFree()) {
         515        76954834 :                 METER(stats.misses++);
         516        76954834 :                 return firstRemoved ? *firstRemoved : *entry;
         517                 :             }
         518                 :
         519       154183150 :             if (entry->matchHash(keyHash) && match(*entry, l)) {
         520        25229461 :                 METER(stats.hits++);
         521        25229461 :                 return *entry;
         522                 :             }
         523                 :         }
         524                 :     }
         525                 :
         526                 :     /*
         527                 :      * This is a copy of lookup hardcoded to the assumptions:
         528                 :      *   1. the lookup is a lookupForAdd
         529                 :      *   2. the key, whose |keyHash| has been passed is not in the table,
         530                 :      *   3. no entries have been removed from the table.
         531                 :      * This specialized search avoids the need for recovering lookup values
         532                 :      * from entries, which allows more flexible Lookup/Key types.
         533                 :      */
         534       120275562 :     Entry &findFreeEntry(HashNumber keyHash)
         535                 :     {
         536       120275562 :         METER(stats.searches++);
         537       120275562 :         JS_ASSERT(!(keyHash & sCollisionBit));
         538                 :
         539                 :         /* N.B. the |keyHash| has already been distributed. */
         540                 :
         541                 :         /* Compute the primary hash address. */
         542       120275562 :         HashNumber h1 = hash1(keyHash, hashShift);
         543       120275562 :         Entry *entry = &table[h1];
         544                 :
         545                 :         /* Miss: return space for a new entry. */
         546       120275562 :         if (entry->isFree()) {
         547       104587601 :             METER(stats.misses++);
         548       104587601 :             return *entry;
         549                 :         }
         550                 :
         551                 :         /* Collision: double hash. */
         552        15687961 :         DoubleHash dh = hash2(keyHash, hashShift);
         553                 :
         554         6711043 :         while(true) {
         555        22399004 :             JS_ASSERT(!entry->isRemoved());
         556        22399004 :             entry->setCollision();
         557                 :
         558        22399004 :             METER(stats.steps++);
         559        22399004 :             h1 = applyDoubleHash(h1, dh);
         560                 :
         561        22399004 :             entry = &table[h1];
         562        22399004 :             if (entry->isFree()) {
         563        15687961 :                 METER(stats.misses++);
         564        15687961 :                 return *entry;
         565                 :             }
         566                 :         }
         567                 :     }
         568                 :
         569          745510 :     bool changeTableSize(int deltaLog2)
         570                 :     {
         571                 :         /* Look, but don't touch, until we succeed in getting new entry store. */
         572          745510 :         Entry *oldTable = table;
         573          745510 :         uint32_t oldCap = capacity();
         574          745510 :         uint32_t newLog2 = sHashBits - hashShift + deltaLog2;
         575          745510 :         uint32_t newCapacity = JS_BIT(newLog2);
         576          745510 :         if (newCapacity > sMaxCapacity) {
         577               0 :             this->reportAllocOverflow();
         578               0 :             return false;
         579                 :         }
         580                 :
         581          745510 :         Entry *newTable = createTable(*this, newCapacity);
         582          745510 :         if (!newTable)
         583               0 :             return false;
         584                 :
         585                 :         /* We can't fail from here on, so update table parameters. */
         586          745510 :         setTableSizeLog2(newLog2);
         587          745510 :         removedCount = 0;
         588          745510 :         gen++;
         589          745510 :         table = newTable;
         590                 :
         591                 :         /* Copy only live entries, leaving removed ones behind. */
         592       220499078 :         for (Entry *src = oldTable, *end = src + oldCap; src < end; ++src) {
         593       219753568 :             if (src->isLive()) {
         594       119750190 :                 src->unsetCollision();
         595       119750190 :                 findFreeEntry(src->getKeyHash()) = Move(*src);
         596                 :             }
         597                 :         }
         598                 :
         599          745510 :         destroyTable(*this, oldTable, oldCap);
         600          745510 :         return true;
         601                 :     }
         602                 :
         603          299938 :     void add(const Lookup &l, const Entry &e)
         604                 :     {
         605          299938 :         HashNumber keyHash = prepareHash(l);
         606          299938 :         Entry &entry = lookup(l, keyHash, sCollisionBit);
         607                 :
         608          299938 :         if (entry.isRemoved()) {
         609           83798 :             METER(stats.addOverRemoved++);
         610           83798 :             removedCount--;
         611           83798 :             keyHash |= sCollisionBit;
         612                 :         }
         613                 :
         614          299938 :         entry.t = e.t;
         615          299938 :         entry.setLive(keyHash);
         616          299938 :         entryCount++;
         617          299938 :         mutationCount++;
         618          299938 :     }
         619                 :
         620       102004229 :     bool checkOverloaded()
         621                 :     {
         622       102004229 :         if (overloaded()) {
         623                 :             /* Compress if a quarter or more of all entries are removed. */
         624                 :             int deltaLog2;
         625          525392 :             if (removedCount >= (capacity() >> 2)) {
         626             100 :                 METER(stats.compresses++);
         627             100 :                 deltaLog2 = 0;
         628                 :             } else {
         629          525292 :                 METER(stats.grows++);
         630          525292 :                 deltaLog2 = 1;
         631                 :             }
         632                 :
         633          525392 :             (void) changeTableSize(deltaLog2);
         634                 :
         635          525392 :             return true;
         636                 :         }
         637                 :
         638       101478837 :         return false;
         639                 :     }
         640                 :
         641        16248611 :     void remove(Entry &e)
         642                 :     {
         643        16248611 :         METER(stats.removes++);
         644        16248611 :         if (e.hasCollision()) {
         645         3999617 :             e.setRemoved();
         646         3999617 :             removedCount++;
         647                 :         } else {
         648        12248994 :             METER(stats.removeFrees++);
         649        12248994 :             e.setFree();
         650                 :         }
         651        16248611 :         entryCount--;
         652        16248611 :         mutationCount++;
         653        16248611 :     }
         654                 :
         655          726375 :     void checkUnderloaded()
         656                 :     {
         657          726375 :         if (underloaded()) {
         658          220118 :             METER(stats.shrinks++);
         659          220118 :             (void) changeTableSize(-1);
         660                 :         }
         661          726375 :     }
         662                 :
         663                 :   public:
         664           99228 :     void clear()
         665                 :     {
         666                 :         if (tl::IsPodType<Entry>::result) {
         667           19136 :             memset(table, 0, sizeof(*table) * capacity());
         668                 :         } else {
         669           80092 :             uint32_t tableCapacity = capacity();
         670         7082556 :             for (Entry *e = table, *end = table + tableCapacity; e < end; ++e)
         671         7002464 :                 *e = Move(Entry());
         672                 :         }
         673           99228 :         removedCount = 0;
         674           99228 :         entryCount = 0;
         675           99228 :         mutationCount++;
         676           99228 :     }
         677                 :
         678           21570 :     void finish()
         679                 :     {
         680           21570 :         JS_ASSERT(!entered);
         681                 :
         682           21570 :         if (!table)
         683               0 :             return;
         684                 :
         685           21570 :         destroyTable(*this, table, capacity());
         686           21570 :         table = NULL;
         687           21570 :         gen++;
         688           21570 :         entryCount = 0;
         689           21570 :         removedCount = 0;
         690           21570 :         mutationCount++;
         691                 :     }
         692                 :
         693         1069429 :     Range all() const {
         694         1069429 :         return Range(table, table + capacity());
         695                 :     }
         696                 :
         697        28267042 :     bool empty() const {
         698        28267042 :         return !entryCount;
         699                 :     }
         700                 :
         701          198030 :     uint32_t count() const {
         702          198030 :         return entryCount;
         703                 :     }
         704                 :
         705       108262707 :     uint32_t capacity() const {
         706       108262707 :         return JS_BIT(sHashBits - hashShift);
         707                 :     }
         708                 :
         709         6950010 :     uint32_t generation() const {
         710         6950010 :         return gen;
         711                 :     }
         712                 :
         713               0 :     size_t sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf) const {
         714               0 :         return mallocSizeOf(table);
         715                 :     }
         716                 :
         717                 :     size_t sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf) const {
         718                 :         return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf);
         719                 :     }
         720                 :
         721       234055447 :     Ptr lookup(const Lookup &l) const {
         722       468110894 :         ReentrancyGuard g(*this);
         723       234055447 :         HashNumber keyHash = prepareHash(l);
         724       234055447 :         return Ptr(lookup(l, keyHash, 0));
         725                 :     }
         726                 :
         727       180578947 :     AddPtr lookupForAdd(const Lookup &l) const {
         728       361157894 :         ReentrancyGuard g(*this);
         729       180578947 :         HashNumber keyHash = prepareHash(l);
         730       180578947 :         Entry &entry = lookup(l, keyHash, sCollisionBit);
         731       180578947 :         AddPtr p(entry, keyHash);
         732       180578947 :         p.mutationCount = mutationCount;
         733                 :         return p;
         734                 :     }
         735                 :
         736       102096012 :     bool add(AddPtr &p)
         737                 :     {
         738       204192024 :         ReentrancyGuard g(*this);
         739       102096012 :         JS_ASSERT(mutationCount == p.mutationCount);
         740       102096012 :         JS_ASSERT(table);
         741       102096012 :         JS_ASSERT(!p.found());
         742       102096012 :         JS_ASSERT(!(p.keyHash & sCollisionBit));
         743                 :
         744                 :         /*
         745                 :          * Changing an entry from removed to live does not affect whether we
         746                 :          * are overloaded and can be handled separately.
         747                 :          */
         748       102096012 :         if (p.entry->isRemoved()) {
         749           91823 :             METER(stats.addOverRemoved++);
         750           91823 :             removedCount--;
         751           91823 :             p.keyHash |= sCollisionBit;
         752                 :         } else {
         753       102004189 :             if (checkOverloaded())
         754                 :                 /* Preserve the validity of |p.entry|. */
         755          525372 :                 p.entry = &findFreeEntry(p.keyHash);
         756                 :         }
         757                 :
         758       102096012 :         p.entry->setLive(p.keyHash);
         759       102096012 :         entryCount++;
         760       102096012 :         mutationCount++;
         761       102096012 :         return true;
         762                 :     }
         763                 :
         764                 :     /*
         765                 :      * There is an important contract between the caller and callee for this
         766                 :      * function: if add() returns true, the caller must assign the T value
         767                 :      * which produced p before using the hashtable again.
         768                 :      */
         769        17970098 :     bool add(AddPtr &p, T** pentry)
         770                 :     {
         771        17970098 :         if (!add(p))
         772               0 :             return false;
         773        17970098 :         *pentry = &p.entry->t;
         774        17970098 :         return true;
         775                 :     }
         776                 :
         777        84125914 :     bool add(AddPtr &p, const T &t)
         778                 :     {
         779        84125914 :         if (!add(p))
         780               0 :             return false;
         781        84125914 :         p.entry->t = t;
         782        84125914 :         return true;
         783                 :     }
         784                 :
         785        17971007 :     bool relookupOrAdd(AddPtr& p, const Lookup &l, const T& t)
         786                 :     {
         787        17971007 :         p.mutationCount = mutationCount;
         788                 :         {
         789        35942014 :             ReentrancyGuard g(*this);
         790        17971007 :             p.entry = &lookup(l, p.keyHash, sCollisionBit);
         791                 :         }
         792        17971007 :         return p.found() || add(p, t);
         793                 :     }
         794                 :
         795          561542 :     void remove(Ptr p)
         796                 :     {
         797         1123084 :         ReentrancyGuard g(*this);
         798          561542 :         JS_ASSERT(p.found());
         799          561542 :         remove(*p.entry);
         800          561542 :         checkUnderloaded();
         801          561542 :     }
         802                 :
         803                 : #undef METER
         804                 : };
         805                 :
         806                 : }  /* namespace detail */
         807                 :
         808                 : /*****************************************************************************/
         809                 :
         810                 : /*
         811                 :  * Hash policy
         812                 :  *
         813                 :  * A hash policy P for a hash table with key-type Key must provide:
         814                 :  *  - a type |P::Lookup| to use to lookup table entries;
         815                 :  *  - a static member function |P::hash| with signature
         816                 :  *
         817                 :  *      static js::HashNumber hash(Lookup)
         818                 :  *
         819                 :  *    to use to hash the lookup type; and
         820                 :  *  - a static member function |P::match| with signature
         821                 :  *
         822                 :  *      static bool match(Key, Lookup)
         823                 :  *
         824                 :  *    to use to test equality of key and lookup values.
         825                 :  *
         826                 :  * Normally, Lookup = Key. In general, though, different values and types of
         827                 :  * values can be used to lookup and store. If a Lookup value |l| is != to the
         828                 :  * added Key value |k|, the user must ensure that |P::match(k,l)|. E.g.:
         829                 :  *
         830                 :  *   js::HashSet<Key, P>::AddPtr p = h.lookup(l);
         831                 :  *   if (!p) {
         832                 :  *     assert(P::match(k, l));  // must hold
         833                 :  *     h.add(p, k);
         834                 :  *   }
         835                 :  */
         836                 :
         837                 : /* Default hashing policies. */
         838                 : template <class Key>
         839                 : struct DefaultHasher
         840                 : {
         841                 :     typedef Key Lookup;
         842         4233642 :     static HashNumber hash(const Lookup &l) {
         843                 :         /* Hash if can implicitly cast to hash number type. */
         844         4233642 :         return l;
         845                 :     }
         846         1733798 :     static bool match(const Key &k, const Lookup &l) {
         847                 :         /* Use builtin or overloaded operator==. */
         848         1733798 :         return k == l;
         849                 :     }
         850                 : };
         851                 :
         852                 : /*
         853                 :  * Pointer hashing policy that strips the lowest zeroBits when calculating the
         854                 :  * hash to improve key distribution.
         855                 :  */
         856                 : template <typename Key, size_t zeroBits>
         857                 : struct PointerHasher
         858                 : {
         859                 :     typedef Key Lookup;
         860        59806738 :     static HashNumber hash(const Lookup &l) {
         861        59806738 :         size_t word = reinterpret_cast<size_t>(l) >> zeroBits;
         862                 :         JS_STATIC_ASSERT(sizeof(HashNumber) == 4);
         863                 : #if JS_BYTES_PER_WORD == 4
         864        59806738 :         return HashNumber(word);
         865                 : #else
         866                 :         JS_STATIC_ASSERT(sizeof word == 8);
         867                 :         return HashNumber((word >> 32) ^ word);
         868                 : #endif
         869                 :     }
         870        16458018 :     static bool match(const Key &k, const Lookup &l) {
         871        16458018 :         return k == l;
         872                 :     }
         873                 : };
         874                 :
         875                 : template <typename Key, size_t zeroBits>
         876                 : struct TaggedPointerHasher
         877                 : {
         878                 :     typedef Key Lookup;
         879                 :
         880                 :     static HashNumber hash(const Lookup &l) {
         881                 :         return PointerHasher<Key, zeroBits>::hash(l);
         882                 :     }
         883                 :
         884                 :     static const uintptr_t COMPARE_MASK = uintptr_t(-1) - 1;
         885                 :
         886                 :     static bool match(const Key &k, const Lookup &l) {
         887                 :         return (uintptr_t(k) & COMPARE_MASK) == uintptr_t(l);
         888                 :     }
         889                 : };
         890                 :
         891                 : /*
         892                 :  * Specialized hashing policy for pointer types. It assumes that the type is
         893                 :  * at least word-aligned. For types with smaller size use PointerHasher.
         894                 :  */
         895                 : template <class T>
         896                 : struct DefaultHasher<T *>: PointerHasher<T *, tl::FloorLog2<sizeof(void *)>::result> { };
         897                 :
         898                 : /* Looking for a hasher for jsid?  Try the DefaultHasher<jsid> in jsatom.h. */
         899                 :
         900                 : template <class Key, class Value>
         901                 : class HashMapEntry
         902        20774816 : {
         903                 :     template <class, class, class> friend class detail::HashTable;
         904                 :     template <class> friend class detail::HashTableEntry;
         905          810394 :     void operator=(const HashMapEntry &rhs) {
         906          810394 :         const_cast<Key &>(key) = rhs.key;
         907          810394 :         value = rhs.value;
         908          810394 :     }
         909                 :
         910                 :   public:
         911       122223664 :     HashMapEntry() : key(), value() {}
         912                 :
         913                 :     template<typename KeyInput, typename ValueInput>
         914           39665 :     HashMapEntry(const KeyInput &k, const ValueInput &v) : key(k), value(v) {}
         915                 :
         916                 :     HashMapEntry(MoveRef<HashMapEntry> rhs)
         917                 :       : key(Move(rhs->key)), value(Move(rhs->value)) { }
         918        34136545 :     void operator=(MoveRef<HashMapEntry> rhs) {
         919        34136545 :         const_cast<Key &>(key) = Move(rhs->key);
         920        34136545 :         value = Move(rhs->value);
         921        34136545 :     }
         922                 :
         923                 :     const Key key;
         924                 :     Value value;
         925                 : };
         926                 :
         927                 : namespace tl {
         928                 :
         929                 : template <class T>
         930                 : struct IsPodType<detail::HashTableEntry<T> > {
         931                 :     static const bool result = IsPodType<T>::result;
         932                 : };
         933                 :
         934                 : template <class K, class V>
         935                 : struct IsPodType<HashMapEntry<K, V> >
         936                 : {
         937                 :     static const bool result = IsPodType<K>::result && IsPodType<V>::result;
         938                 : };
         939                 :
         940                 : } /* namespace tl */
         941                 :
         942                 : /*
         943                 :  * JS-friendly, STL-like container providing a hash-based map from keys to
         944                 :  * values. In particular, HashMap calls constructors and destructors of all
         945                 :  * objects added so non-PODs may be used safely.
         946                 :  *
         947                 :  * Key/Value requirements:
         948                 :  *  - default constructible, copyable, destructible, assignable
         949                 :  * HashPolicy requirements:
         950                 :  *  - see "Hash policy" above (default js::DefaultHasher<Key>)
         951                 :  * AllocPolicy:
         952                 :  *  - see "Allocation policies" in jsalloc.h
         953                 :  *
         954                 :  * N.B: HashMap is not reentrant: Key/Value/HashPolicy/AllocPolicy members
         955                 :  *      called by HashMap must not call back into the same HashMap object.
         956                 :  * N.B: Due to the lack of exception handling, the user must call |init()|.
         957                 :  */
         958                 : template <class Key,
         959                 :           class Value,
         960                 :           class HashPolicy = DefaultHasher<Key>,
         961                 :           class AllocPolicy = TempAllocPolicy>
         962                 : class HashMap
         963          671751 : {
         964                 :   public:
         965                 :     typedef typename HashPolicy::Lookup Lookup;
         966                 :
         967                 :     typedef HashMapEntry<Key, Value> Entry;
         968                 :
         969                 :   private:
         970                 :     /* Implement HashMap using HashTable. Lift |Key| operations to |Entry|. */
         971                 :     struct MapHashPolicy : HashPolicy
         972                 :     {
         973                 :         typedef Key KeyType;
         974        19061329 :         static const Key &getKey(Entry &e) { return e.key; }
         975          149969 :         static void setKey(Entry &e, Key &k) { const_cast<Key &>(e.key) = k; }
         976                 :     };
         977                 :     typedef detail::HashTable<Entry, MapHashPolicy, AllocPolicy> Impl;
         978                 :
         979                 :     friend class Impl::Enum;
         980                 :
         981                 :     /* Not implicitly copyable (expensive). May add explicit |clone| later. */
         982                 :     HashMap(const HashMap &);
         983                 :     HashMap &operator=(const HashMap &);
         984                 :
         985                 :     Impl impl;
         986                 :
         987                 :   public:
         988                 :     const static unsigned sDefaultInitSize = Impl::sDefaultInitSize;
         989                 :
         990                 :     /*
         991                 :      * HashMap construction is fallible (due to OOM); thus the user must call
         992                 :      * init after constructing a HashMap and check the return value.
         993                 :      */
         994          671751 :     HashMap(AllocPolicy a = AllocPolicy()) : impl(a)  {}
         995          449134 :     bool init(uint32_t len = sDefaultInitSize)        { return impl.init(len); }
         996         6120116 :     bool initialized() const                          { return impl.initialized(); }
         997                 :
         998                 :     /*
         999                 :      * Return whether the given lookup value is present in the map. E.g.:
        1000                 :      *
        1001                 :      *   typedef HashMap<int,char> HM;
        1002                 :      *   HM h;
        1003                 :      *   if (HM::Ptr p = h.lookup(3)) {
        1004                 :      *     const HM::Entry &e = *p; // p acts like a pointer to Entry
        1005                 :      *     assert(p->key == 3);     // Entry contains the key
        1006                 :      *     char val = p->value;     // and value
        1007                 :      *   }
        1008                 :      *
        1009                 :      * Also see the definition of Ptr in HashTable above (with T = Entry).
        1010                 :      */
        1011                 :     typedef typename Impl::Ptr Ptr;
        1012        15394491 :     Ptr lookup(const Lookup &l) const                 { return impl.lookup(l); }
        1013                 :
        1014                 :     /* Assuming |p.found()|, remove |*p|. */
        1015          337152 :     void remove(Ptr p)                                { impl.remove(p); }
        1016                 :
        1017                 :     /*
        1018                 :      * Like |lookup(l)|, but on miss, |p = lookupForAdd(l)| allows efficient
        1019                 :      * insertion of Key |k| (where |HashPolicy::match(k,l) == true|) using
        1020                 :      * |add(p,k,v)|. After |add(p,k,v)|, |p| points to the new Entry. E.g.:
        1021                 :      *
        1022                 :      *   typedef HashMap<int,char> HM;
        1023                 :      *   HM h;
        1024                 :      *   HM::AddPtr p = h.lookupForAdd(3);
        1025                 :      *   if (!p) {
        1026                 :      *     if (!h.add(p, 3, 'a'))
        1027                 :      *       return false;
        1028                 :      *   }
        1029                 :      *   const HM::Entry &e = *p;   // p acts like a pointer to Entry
        1030                 :      *   assert(p->key == 3);       // Entry contains the key
        1031                 :      *   char val = p->value;       // and value
        1032                 :      *
        1033                 :      * Also see the definition of AddPtr in HashTable above (with T = Entry).
        1034                 :      *
        1035                 :      * N.B. The caller must ensure that no mutating hash table operations
        1036                 :      * occur between a pair of |lookupForAdd| and |add| calls. To avoid
        1037                 :      * looking up the key a second time, the caller may use the more efficient
        1038                 :      * relookupOrAdd method. This method reuses part of the hashing computation
        1039                 :      * to more efficiently insert the key if it has not been added. For
        1040                 :      * example, a mutation-handling version of the previous example:
        1041                 :      *
        1042                 :      *    HM::AddPtr p = h.lookupForAdd(3);
        1043                 :      *    if (!p) {
        1044                 :      *      call_that_may_mutate_h();
        1045                 :      *      if (!h.relookupOrAdd(p, 3, 'a'))
        1046                 :      *        return false;
        1047                 :      *    }
        1048                 :      *    const HM::Entry &e = *p;
        1049                 :      *    assert(p->key == 3);
        1050                 :      *    char val = p->value;
        1051                 :      */
        1052                 :     typedef typename Impl::AddPtr AddPtr;
        1053        26650361 :     AddPtr lookupForAdd(const Lookup &l) const {
        1054        26650361 :         return impl.lookupForAdd(l);
        1055                 :     }
        1056                 :
        1057                 :     template<typename KeyInput, typename ValueInput>
        1058        14623946 :     bool add(AddPtr &p, const KeyInput &k, const ValueInput &v) {
        1059                 :         Entry *pentry;
        1060        14623946 :         if (!impl.add(p, &pentry))
        1061               0 :             return false;
        1062        14623946 :         const_cast<Key &>(pentry->key) = k;
        1063        14623946 :         pentry->value = v;
        1064        14623946 :         return true;
        1065                 :     }
        1066                 :
        1067         3346152 :     bool add(AddPtr &p, const Key &k, MoveRef<Value> v) {
        1068                 :         Entry *pentry;
        1069         3346152 :         if (!impl.add(p, &pentry))
        1070               0 :             return false;
        1071         3346152 :         const_cast<Key &>(pentry->key) = k;
        1072         3346152 :         pentry->value = v;
        1073         3346152 :         return true;
        1074                 :     }
        1075                 :
        1076                 :     bool add(AddPtr &p, const Key &k) {
        1077                 :         Entry *pentry;
        1078                 :         if (!impl.add(p, &pentry))
        1079                 :             return false;
        1080                 :         const_cast<Key &>(pentry->key) = k;
        1081                 :         return true;
        1082                 :     }
        1083                 :
        1084                 :     template<typename KeyInput, typename ValueInput>
        1085           39665 :     bool relookupOrAdd(AddPtr &p, const KeyInput &k, const ValueInput &v) {
        1086           39665 :         return impl.relookupOrAdd(p, k, Entry(k, v));
        1087                 :     }
        1088                 :
        1089                 :     /*
        1090                 :      * |all()| returns a Range containing |count()| elements. E.g.:
        1091                 :      *
        1092                 :      *   typedef HashMap<int,char> HM;
        1093                 :      *   HM h;
        1094                 :      *   for (HM::Range r = h.all(); !r.empty(); r.popFront())
        1095                 :      *     char c = r.front().value;
        1096                 :      *
        1097                 :      * Also see the definition of Range in HashTable above (with T = Entry).
        1098                 :      */
        1099                 :     typedef typename Impl::Range Range;
        1100          332554 :     Range all() const                                 { return impl.all(); }
        1101           73144 :     uint32_t count() const                            { return impl.count(); }
        1102                 :     size_t capacity() const                           { return impl.capacity(); }
        1103                 :     size_t sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf) const {
        1104                 :         return impl.sizeOfExcludingThis(mallocSizeOf);
        1105                 :     }
        1106               0 :     size_t sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf) const {
        1107                 :         /*
        1108                 :          * Don't just call |impl.sizeOfExcludingThis()| because there's no
        1109                 :          * guarantee that |impl| is the first field in HashMap.
        1110                 :          */
        1111               0 :         return mallocSizeOf(this) + impl.sizeOfExcludingThis(mallocSizeOf);
        1112                 :     }
        1113                 :
        1114                 :     /*
        1115                 :      * Typedef for the enumeration class. An Enum may be used to examine and
        1116                 :      * remove table entries:
        1117                 :      *
        1118                 :      *   typedef HashMap<int,char> HM;
        1119                 :      *   HM s;
        1120                 :      *   for (HM::Enum e(s); !e.empty(); e.popFront())
        1121                 :      *     if (e.front().value == 'l')
        1122                 :      *       e.removeFront();
        1123                 :      *
        1124                 :      * Table resize may occur in Enum's destructor. Also see the definition of
        1125                 :      * Enum in HashTable above (with T = Entry).
        1126                 :      */
        1127                 :     typedef typename Impl::Enum Enum;
        1128                 :
        1129                 :     /*
        1130                 :      * Remove all entries. This does not shrink the table. For that consider
        1131                 :      * using the finish() method.
        1132                 :      */
        1133           39122 :     void clear()                                      { impl.clear(); }
        1134                 :
        1135                 :     /*
        1136                 :      * Remove all the entries and release all internal buffers. The map must
        1137                 :      * be initialized again before any use.
        1138                 :      */
        1139           21570 :     void finish()                                     { impl.finish(); }
        1140                 :
        1141                 :    /* Does the table contain any entries? */
        1142           60172 :     bool empty() const                                { return impl.empty(); }
        1143                 :
        1144                 :     /*
        1145                 :      * If |generation()| is the same before and after a HashMap operation,
        1146                 :      * pointers into the table remain valid.
        1147                 :      */
        1148         6699954 :     unsigned generation() const                       { return impl.generation(); }
        1149                 :
        1150                 :     /* Shorthand operations: */
        1151                 :
        1152         1266904 :     bool has(const Lookup &l) const {
        1153         1266904 :         return impl.lookup(l) != NULL;
        1154                 :     }
        1155                 :
        1156                 :     /* Overwrite existing value with v. Return false on oom. */
        1157                 :     template<typename KeyInput, typename ValueInput>
        1158         1781288 :     bool put(const KeyInput &k, const ValueInput &v) {
        1159         3562576 :         AddPtr p = lookupForAdd(k);
        1160         1781288 :         if (p) {
        1161             570 :             p->value = v;
        1162             570 :             return true;
        1163                 :         }
        1164         1780718 :         return add(p, k, v);
        1165                 :     }
        1166                 :
        1167                 :     /* Like put, but assert that the given key is not already present. */
        1168          732807 :     bool putNew(const Key &k, const Value &v) {
        1169         1465614 :         AddPtr p = lookupForAdd(k);
        1170          732807 :         JS_ASSERT(!p);
        1171          732807 :         return add(p, k, v);
        1172                 :     }
        1173                 :
        1174                 :     /* Add (k,defaultValue) if k no found. Return false-y Ptr on oom. */
        1175               0 :     Ptr lookupWithDefault(const Key &k, const Value &defaultValue) {
        1176               0 :         AddPtr p = lookupForAdd(k);
        1177               0 :         if (p)
        1178               0 :             return p;
        1179               0 :         (void)add(p, k, defaultValue);  /* p is left false-y on oom. */
        1180               0 :         return p;
        1181                 :     }
        1182                 :
        1183                 :     /* Remove if present. */
        1184           33095 :     void remove(const Lookup &l) {
        1185           33095 :         if (Ptr p = lookup(l))
        1186           33095 :             remove(p);
        1187           33095 :     }
        1188                 : };
        1189                 :
        1190                 : /*
        1191                 :  * JS-friendly, STL-like container providing a hash-based set of values. In
        1192                 :  * particular, HashSet calls constructors and destructors of all objects added
        1193                 :  * so non-PODs may be used safely.
        1194                 :  *
        1195                 :  * T requirements:
        1196                 :  *  - default constructible, copyable, destructible, assignable
        1197                 :  * HashPolicy requirements:
        1198                 :  *  - see "Hash policy" above (default js::DefaultHasher<Key>)
        1199                 :  * AllocPolicy:
        1200                 :  *  - see "Allocation policies" in jsalloc.h
        1201                 :  *
        1202                 :  * N.B: HashSet is not reentrant: T/HashPolicy/AllocPolicy members called by
        1203                 :  *      HashSet must not call back into the same HashSet object.
        1204                 :  * N.B: Due to the lack of exception handling, the user must call |init()|.
        1205                 :  */
        1206                 : template <class T, class HashPolicy = DefaultHasher<T>, class AllocPolicy = TempAllocPolicy>
        1207                 : class HashSet
        1208         2728667 : {
        1209                 :     typedef typename HashPolicy::Lookup Lookup;
        1210                 :
        1211                 :     /* Implement HashSet in terms of HashTable. */
        1212                 :     struct SetOps : HashPolicy {
        1213                 :         typedef T KeyType;
        1214        88458304 :         static const KeyType &getKey(const T &t) { return t; }
        1215          149969 :         static void setKey(T &t, KeyType &k) { t = k; }
        1216                 :     };
        1217                 :     typedef detail::HashTable<const T, SetOps, AllocPolicy> Impl;
        1218                 :
        1219                 :     friend class Impl::Enum;
        1220                 :
        1221                 :     /* Not implicitly copyable (expensive). May add explicit |clone| later. */
        1222                 :     HashSet(const HashSet &);
        1223                 :     HashSet &operator=(const HashSet &);
        1224                 :
        1225                 :     Impl impl;
        1226                 :
        1227                 :   public:
        1228                 :     const static unsigned sDefaultInitSize = Impl::sDefaultInitSize;
        1229                 :
        1230                 :     /*
        1231                 :      * HashSet construction is fallible (due to OOM); thus the user must call
        1232                 :      * init after constructing a HashSet and check the return value.
        1233                 :      */
        1234         2728667 :     HashSet(AllocPolicy a = AllocPolicy()) : impl(a)  {}
        1235         2643410 :     bool init(uint32_t len = sDefaultInitSize)        { return impl.init(len); }
        1236        48487146 :     bool initialized() const                          { return impl.initialized(); }
        1237                 :
        1238                 :     /*
        1239                 :      * Return whether the given lookup value is present in the map. E.g.:
        1240                 :      *
        1241                 :      *   typedef HashSet<int> HS;
        1242                 :      *   HS h;
        1243                 :      *   if (HS::Ptr p = h.lookup(3)) {
        1244                 :      *     assert(*p == 3);   // p acts like a pointer to int
        1245                 :      *   }
        1246                 :      *
        1247                 :      * Also see the definition of Ptr in HashTable above.
        1248                 :      */
        1249                 :     typedef typename Impl::Ptr Ptr;
        1250         8809360 :     Ptr lookup(const Lookup &l) const                 { return impl.lookup(l); }
        1251                 :
        1252                 :     /* Assuming |p.found()|, remove |*p|. */
        1253          224390 :     void remove(Ptr p)                                { impl.remove(p); }
        1254                 :
        1255                 :     /*
        1256                 :      * Like |lookup(l)|, but on miss, |p = lookupForAdd(l)| allows efficient
        1257                 :      * insertion of T value |t| (where |HashPolicy::match(t,l) == true|) using
        1258                 :      * |add(p,t)|. After |add(p,t)|, |p| points to the new element. E.g.:
        1259                 :      *
        1260                 :      *   typedef HashSet<int> HS;
        1261                 :      *   HS h;
        1262                 :      *   HS::AddPtr p = h.lookupForAdd(3);
        1263                 :      *   if (!p) {
        1264                 :      *     if (!h.add(p, 3))
        1265                 :      *       return false;
        1266                 :      *   }
        1267                 :      *   assert(*p == 3);   // p acts like a pointer to int
        1268                 :      *
        1269                 :      * Also see the definition of AddPtr in HashTable above.
        1270                 :      *
        1271                 :      * N.B. The caller must ensure that no mutating hash table operations
        1272                 :      * occur between a pair of |lookupForAdd| and |add| calls. To avoid
        1273                 :      * looking up the key a second time, the caller may use the more efficient
        1274                 :      * relookupOrAdd method. This method reuses part of the hashing computation
        1275                 :      * to more efficiently insert the key if it has not been added. For
        1276                 :      * example, a mutation-handling version of the previous example:
        1277                 :      *
        1278                 :      *    HS::AddPtr p = h.lookupForAdd(3);
        1279                 :      *    if (!p) {
        1280                 :      *      call_that_may_mutate_h();
        1281                 :      *      if (!h.relookupOrAdd(p, 3, 3))
        1282                 :      *        return false;
        1283                 :      *    }
        1284                 :      *    assert(*p == 3);
        1285                 :      *
        1286                 :      * Note that relookupOrAdd(p,l,t) performs Lookup using l and adds the
        1287                 :      * entry t, where the caller ensures match(l,t).
        1288                 :      */
        1289                 :     typedef typename Impl::AddPtr AddPtr;
        1290       153928586 :     AddPtr lookupForAdd(const Lookup &l) const {
        1291       153928586 :         return impl.lookupForAdd(l);
        1292                 :     }
        1293                 :
        1294        66154907 :     bool add(AddPtr &p, const T &t) {
        1295        66154907 :         return impl.add(p, t);
        1296                 :     }
        1297                 :
        1298        17931342 :     bool relookupOrAdd(AddPtr &p, const Lookup &l, const T &t) {
        1299        17931342 :         return impl.relookupOrAdd(p, l, t);
        1300                 :     }
        1301                 :
        1302                 :     /*
        1303                 :      * |all()| returns a Range containing |count()| elements:
        1304                 :      *
        1305                 :      *   typedef HashSet<int> HS;
        1306                 :      *   HS h;
        1307                 :      *   for (HS::Range r = h.all(); !r.empty(); r.popFront())
        1308                 :      *     int i = r.front();
        1309                 :      *
        1310                 :      * Also see the definition of Range in HashTable above.
        1311                 :      */
        1312                 :     typedef typename Impl::Range Range;
        1313          736875 :     Range all() const                                 { return impl.all(); }
        1314          124886 :     uint32_t count() const                            { return impl.count(); }
        1315                 :     size_t capacity() const                           { return impl.capacity(); }
        1316               0 :     size_t sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf) const {
        1317               0 :         return impl.sizeOfExcludingThis(mallocSizeOf);
        1318                 :     }
        1319                 :     size_t sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf) const {
        1320                 :         /*
        1321                 :          * Don't just call |impl.sizeOfExcludingThis()| because there's no
        1322                 :          * guarantee that |impl| is the first field in HashSet.
        1323                 :          */
        1324                 :         return mallocSizeOf(this) + impl.sizeOfExcludingThis(mallocSizeOf);
        1325                 :     }
        1326                 :
        1327                 :     /*
        1328                 :      * Typedef for the enumeration class. An Enum may be used to examine and
        1329                 :      * remove table entries:
        1330                 :      *
        1331                 :      *   typedef HashSet<int> HS;
        1332                 :      *   HS s;
        1333                 :      *   for (HS::Enum e(s); !e.empty(); e.popFront())
        1334                 :      *     if (e.front() == 42)
        1335                 :      *       e.removeFront();
        1336                 :      *
        1337                 :      * Table resize may occur in Enum's destructor. Also see the definition of
        1338                 :      * Enum in HashTable above.
        1339                 :      */
        1340                 :     typedef typename Impl::Enum Enum;
        1341                 :
        1342                 :     /*
        1343                 :      * Remove all entries. This does not shrink the table. For that consider
        1344                 :      * using the finish() method.
        1345                 :      */
        1346           60106 :     void clear()                                      { impl.clear(); }
        1347                 :
        1348                 :     /*
        1349                 :      * Remove all the entries and release all internal buffers. The set must
        1350                 :      * be initialized again before any use.
        1351                 :      */
        1352               0 :     void finish()                                     { impl.finish(); }
        1353                 :
        1354                 :     /* Does the table contain any entries? */
        1355        28206870 :     bool empty() const                                { return impl.empty(); }
        1356                 :
        1357                 :     /*
        1358                 :      * If |generation()| is the same before and after a HashSet operation,
        1359                 :      * pointers into the table remain valid.
        1360                 :      */
        1361          250056 :     unsigned generation() const                       { return impl.generation(); }
        1362                 :
        1363                 :     /* Shorthand operations: */
        1364                 :
        1365       208584692 :     bool has(const Lookup &l) const {
        1366       208584692 :         return impl.lookup(l) != NULL;
        1367                 :     }
        1368                 :
        1369                 :     /* Overwrite existing value with v. Return false on oom. */
        1370          617771 :     bool put(const T &t) {
        1371         1235542 :         AddPtr p = lookupForAdd(t);
        1372          617771 :         return p ? true : add(p, t);
        1373                 :     }
        1374                 :
        1375                 :     /* Like put, but assert that the given key is not already present. */
        1376          699948 :     bool putNew(const T &t) {
        1377         1399896 :         AddPtr p = lookupForAdd(t);
        1378          699948 :         JS_ASSERT(!p);
        1379          699948 :         return add(p, t);
        1380                 :     }
        1381                 :
        1382         1758231 :     bool putNew(const Lookup &l, const T &t) {
        1383         3516462 :         AddPtr p = lookupForAdd(l);
        1384         1758231 :         JS_ASSERT(!p);
        1385         1758231 :         return add(p, t);
        1386                 :     }
        1387                 :
        1388           85417 :     void remove(const Lookup &l) {
        1389           85417 :         if (Ptr p = lookup(l))
        1390           85417 :             remove(p);
        1391           85417 :     }
        1392                 : };
        1393                 :
        1394                 : }  /* namespace js */
        1395                 :
        1396                 : #endif

Generated by: LCOV version 1.7