LCOV - app.info - js/src/ds/InlineMap.h

LCOV - code coverage report
| Current view: | directory - js/src/ds - InlineMap.h (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 166 | 163 | 98.2 %
| Date: | 2012-06-02 | Functions: | 91 | 90 | 98.9 %

           1                 : /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
           2                 :  * vim: set ts=4 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 SpiderMonkey JavaScript engine.
          18                 :  *
          19                 :  * The Initial Developer of the Original Code is
          20                 :  * Mozilla Corporation.
          21                 :  * Portions created by the Initial Developer are Copyright (C) 2011
          22                 :  * the Initial Developer. All Rights Reserved.
          23                 :  *
          24                 :  * Contributor(s):
          25                 :  *   Chris Leary <cdleary@mozilla.com>
          26                 :  *
          27                 :  * Alternatively, the contents of this file may be used under the terms of
          28                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
          29                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          31                 :  * of those above. If you wish to allow use of your version of this file only
          32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          33                 :  * use your version of this file under the terms of the MPL, indicate your
          34                 :  * decision by deleting the provisions above and replace them with the notice
          35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          36                 :  * the provisions above, a recipient may use your version of this file under
          37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          38                 :  *
          39                 :  * ***** END LICENSE BLOCK ***** */
          40                 :
          41                 : #ifndef InlineMap_h__
          42                 : #define InlineMap_h__
          43                 :
          44                 : #include "js/HashTable.h"
          45                 :
          46                 : namespace js {
          47                 :
          48                 : /*
          49                 :  * A type can only be used as an InlineMap key if zero is an invalid key value
          50                 :  * (and thus may be used as a tombstone value by InlineMap).
          51                 :  */
          52                 : template <typename T> struct ZeroIsReserved         { static const bool result = false; };
          53                 : template <typename T> struct ZeroIsReserved<T *>    { static const bool result = true; };
          54                 :
          55                 : template <typename K, typename V, size_t InlineElems>
          56                 : class InlineMap
          57                 : {
          58                 :   public:
          59                 :     typedef HashMap<K, V, DefaultHasher<K>, TempAllocPolicy> WordMap;
          60                 :
          61                 :     struct InlineElem
          62                 :     {
          63                 :         K key;
          64                 :         V value;
          65                 :     };
          66                 :
          67                 :   private:
          68                 :     typedef typename WordMap::Ptr       WordMapPtr;
          69                 :     typedef typename WordMap::AddPtr    WordMapAddPtr;
          70                 :     typedef typename WordMap::Range     WordMapRange;
          71                 :
          72                 :     size_t          inlNext;
          73                 :     size_t          inlCount;
          74                 :     InlineElem      inl[InlineElems];
          75                 :     WordMap         map;
          76                 :
          77          571145 :     void checkStaticInvariants() {
          78                 :         JS_STATIC_ASSERT(ZeroIsReserved<K>::result);
          79          571145 :     }
          80                 :
          81       111864166 :     bool usingMap() const {
          82       111864166 :         return inlNext > InlineElems;
          83                 :     }
          84                 :
          85           92830 :     bool switchToMap() {
          86           92830 :         JS_ASSERT(inlNext == InlineElems);
          87                 :
          88           92830 :         if (map.initialized()) {
          89           69887 :             map.clear();
          90                 :         } else {
          91           22943 :             if (!map.init(count()))
          92               0 :                 return false;
          93           22943 :             JS_ASSERT(map.initialized());
          94                 :         }
          95                 :
          96         2320750 :         for (InlineElem *it = inl, *end = inl + inlNext; it != end; ++it) {
          97         2227920 :             if (it->key && !map.putNew(it->key, it->value))
          98               0 :                 return false;
          99                 :         }
         100                 :
         101           92830 :         inlNext = InlineElems + 1;
         102           92830 :         JS_ASSERT(map.count() == inlCount);
         103           92830 :         JS_ASSERT(usingMap());
         104           92830 :         return true;
         105                 :     }
         106                 :
         107                 :     JS_NEVER_INLINE
         108           92830 :     bool switchAndAdd(const K &key, const V &value) {
         109           92830 :         if (!switchToMap())
         110               0 :             return false;
         111                 :
         112           92830 :         return map.putNew(key, value);
         113                 :     }
         114                 :
         115                 :   public:
         116          571145 :     explicit InlineMap(JSContext *cx)
         117          571145 :       : inlNext(0), inlCount(0), map(cx) {
         118          571145 :         checkStaticInvariants(); /* Force the template to instantiate the static invariants. */
         119          571145 :     }
         120                 :
         121                 :     class Entry
         122                 :     {
         123                 :         friend class InlineMap;
         124                 :         const K &key_;
         125                 :         const V &value_;
         126                 :
         127        12420190 :         Entry(const K &key, const V &value) : key_(key), value_(value) {}
         128                 :
         129                 :       public:
         130         2424962 :         const K &key() { return key_; }
         131         9995228 :         const V &value() { return value_; }
         132                 :     }; /* class Entry */
         133                 :
         134                 :     class Ptr
         135                 :     {
         136                 :         friend class InlineMap;
         137                 :
         138                 :         WordMapPtr  mapPtr;
         139                 :         InlineElem  *inlPtr;
         140                 :         bool        isInlinePtr;
         141                 :
         142                 :         typedef Ptr ******* ConvertibleToBool;
         143                 :
         144         3054045 :         explicit Ptr(WordMapPtr p) : mapPtr(p), isInlinePtr(false) {}
         145        25297898 :         explicit Ptr(InlineElem *ie) : inlPtr(ie), isInlinePtr(true) {}
         146                 :         void operator==(const Ptr &other);
         147                 :
         148                 :       public:
         149                 :         /* Leaves Ptr uninitialized. */
         150         1636333 :         Ptr() {
         151                 : #ifdef DEBUG
         152         1636333 :             inlPtr = (InlineElem *) 0xbad;
         153         1636333 :             isInlinePtr = true;
         154                 : #endif
         155         1636333 :         }
         156                 :
         157                 :         /* Default copy constructor works for this structure. */
         158                 :
         159        37949121 :         bool found() const {
         160        37949121 :             return isInlinePtr ? bool(inlPtr) : mapPtr.found();
         161                 :         }
         162                 :
         163        29163025 :         operator ConvertibleToBool() const {
         164        29163025 :             return ConvertibleToBool(found());
         165                 :         }
         166                 :
         167                 :         K &key() {
         168                 :             JS_ASSERT(found());
         169                 :             return isInlinePtr ? inlPtr->key : mapPtr->key;
         170                 :         }
         171                 :
         172         8786096 :         V &value() {
         173         8786096 :             JS_ASSERT(found());
         174         8786096 :             return isInlinePtr ? inlPtr->value : mapPtr->value;
         175                 :         }
         176                 :     }; /* class Ptr */
         177                 :
         178                 :     class AddPtr
         179                 :     {
         180                 :         friend class InlineMap;
         181                 :
         182                 :         WordMapAddPtr   mapAddPtr;
         183                 :         InlineElem      *inlAddPtr;
         184                 :         bool            isInlinePtr;
         185                 :         /* Indicates whether inlAddPtr is a found result or an add pointer. */
         186                 :         bool            inlPtrFound;
         187                 :
         188        32138147 :         AddPtr(InlineElem *ptr, bool found)
         189        32138147 :           : inlAddPtr(ptr), isInlinePtr(true), inlPtrFound(found)
         190        32138147 :         {}
         191                 :
         192        10732854 :         AddPtr(const WordMapAddPtr &p) : mapAddPtr(p), isInlinePtr(false) {}
         193                 :
         194                 :         void operator==(const AddPtr &other);
         195                 :
         196                 :         typedef AddPtr ******* ConvertibleToBool;
         197                 :
         198                 :       public:
         199                 :         AddPtr() {}
         200                 :
         201        99749062 :         bool found() const {
         202        99749062 :             return isInlinePtr ? inlPtrFound : mapAddPtr.found();
         203                 :         }
         204                 :
         205        62894845 :         operator ConvertibleToBool() const {
         206        62894845 :             return found() ? ConvertibleToBool(1) : ConvertibleToBool(0);
         207                 :         }
         208                 :
         209        22871537 :         V &value() {
         210        22871537 :             JS_ASSERT(found());
         211        22871537 :             if (isInlinePtr)
         212        18083348 :                 return inlAddPtr->value;
         213         4788189 :             return mapAddPtr->value;
         214                 :         }
         215                 :     }; /* class AddPtr */
         216                 :
         217        31867074 :     size_t count() {
         218        31867074 :         return usingMap() ? map.count() : inlCount;
         219                 :     }
         220                 :
         221         1630960 :     bool empty() const {
         222         1630960 :         return usingMap() ? map.empty() : !inlCount;
         223                 :     }
         224                 :
         225         3288711 :     void clear() {
         226         3288711 :         inlNext = 0;
         227         3288711 :         inlCount = 0;
         228         3288711 :     }
         229                 :
         230         3254171 :     bool isMap() const {
         231         3254171 :         return usingMap();
         232                 :     }
         233                 :
         234           73192 :     const WordMap &asMap() const {
         235           73192 :         JS_ASSERT(isMap());
         236           73192 :         return map;
         237                 :     }
         238                 :
         239         1035929 :     const InlineElem *asInline() const {
         240         1035929 :         JS_ASSERT(!isMap());
         241         1035929 :         return inl;
         242                 :     }
         243                 :
         244         1035929 :     const InlineElem *inlineEnd() const {
         245         1035929 :         JS_ASSERT(!isMap());
         246         1035929 :         return inl + inlNext;
         247                 :     }
         248                 :
         249                 :     JS_ALWAYS_INLINE
         250        28351943 :     Ptr lookup(const K &key) {
         251        28351943 :         if (usingMap())
         252         3054045 :             return Ptr(map.lookup(key));
         253                 :
         254        98944072 :         for (InlineElem *it = inl, *end = inl + inlNext; it != end; ++it) {
         255        80768936 :             if (it->key == key)
         256         7122762 :                 return Ptr(it);
         257                 :         }
         258                 :
         259        18175136 :         return Ptr(NULL);
         260                 :     }
         261                 :
         262                 :     JS_ALWAYS_INLINE
         263        42871001 :     AddPtr lookupForAdd(const K &key) {
         264        42871001 :         if (usingMap())
         265        10732854 :             return AddPtr(map.lookupForAdd(key));
         266                 :
         267       167085451 :         for (InlineElem *it = inl, *end = inl + inlNext; it != end; ++it) {
         268       153009758 :             if (it->key == key)
         269        18062454 :                 return AddPtr(it, true);
         270                 :         }
         271                 :
         272                 :         /*
         273                 :          * The add pointer that's returned here may indicate the limit entry of
         274                 :          * the linear space, in which case the |add| operation will initialize
         275                 :          * the map if necessary and add the entry there.
         276                 :          */
         277        14075693 :         return AddPtr(inl + inlNext, false);
         278                 :     }
         279                 :
         280                 :     JS_ALWAYS_INLINE
         281        20023844 :     bool add(AddPtr &p, const K &key, const V &value) {
         282        20023844 :         JS_ASSERT(!p);
         283                 :
         284        20023844 :         if (p.isInlinePtr) {
         285        14075510 :             InlineElem *addPtr = p.inlAddPtr;
         286        14075510 :             JS_ASSERT(addPtr == inl + inlNext);
         287                 :
         288                 :             /* Switching to map mode before we add this pointer. */
         289        14075510 :             if (addPtr == inl + InlineElems)
         290           92830 :                 return switchAndAdd(key, value);
         291                 :
         292        13982680 :             JS_ASSERT(!p.found());
         293        13982680 :             JS_ASSERT(uintptr_t(inl + inlNext) == uintptr_t(p.inlAddPtr));
         294        13982680 :             p.inlAddPtr->key = key;
         295        13982680 :             p.inlAddPtr->value = value;
         296        13982680 :             ++inlCount;
         297        13982680 :             ++inlNext;
         298        13982680 :             return true;
         299                 :         }
         300                 :
         301         5948334 :         return map.add(p.mapAddPtr, key, value);
         302                 :     }
         303                 :
         304                 :     JS_ALWAYS_INLINE
         305             232 :     bool put(const K &key, const V &value) {
         306             232 :         AddPtr p = lookupForAdd(key);
         307             232 :         if (p) {
         308              20 :             p.value() = value;
         309              20 :             return true;
         310                 :         }
         311             212 :         return add(p, key, value);
         312                 :     }
         313                 :
         314          811082 :     void remove(Ptr p) {
         315          811082 :         JS_ASSERT(p);
         316          811082 :         if (p.isInlinePtr) {
         317          463582 :             JS_ASSERT(inlCount > 0);
         318          463582 :             JS_ASSERT(p.inlPtr->key != NULL);
         319          463582 :             p.inlPtr->key = NULL;
         320          463582 :             --inlCount;
         321          463582 :             return;
         322                 :         }
         323          347500 :         JS_ASSERT(map.initialized() && usingMap());
         324          347500 :         map.remove(p.mapPtr);
         325                 :     }
         326                 :
         327           46381 :     void remove(const K &key) {
         328           46381 :         if (Ptr p = lookup(key))
         329           46361 :             remove(p);
         330           46381 :     }
         331                 :
         332                 :     class Range
         333                 :     {
         334                 :         friend class InlineMap;
         335                 :
         336                 :         WordMapRange    mapRange;
         337                 :         InlineElem      *cur;
         338                 :         InlineElem      *end;
         339                 :         bool            isInline;
         340                 :
         341           12754 :         explicit Range(WordMapRange r)
         342                 :           : cur(NULL), end(NULL), /* Avoid GCC 4.3.3 over-warning. */
         343           12754 :             isInline(false) {
         344           12754 :             mapRange = r;
         345           12754 :             JS_ASSERT(!isInlineRange());
         346           12754 :         }
         347                 :
         348         3435933 :         Range(const InlineElem *begin, const InlineElem *end_)
         349                 :           : cur(const_cast<InlineElem *>(begin)),
         350                 :             end(const_cast<InlineElem *>(end_)),
         351         3435933 :             isInline(true) {
         352         3435933 :             advancePastNulls(cur);
         353         3435933 :             JS_ASSERT(isInlineRange());
         354         3435933 :         }
         355                 :
         356        69265361 :         bool checkInlineRangeInvariants() const {
         357        69265361 :             JS_ASSERT(uintptr_t(cur) <= uintptr_t(end));
         358        69265361 :             JS_ASSERT_IF(cur != end, cur->key != NULL);
         359        69265361 :             return true;
         360                 :         }
         361                 :
         362        71061010 :         bool isInlineRange() const {
         363        71061010 :             JS_ASSERT_IF(isInline, checkInlineRangeInvariants());
         364        71061010 :             return isInline;
         365                 :         }
         366                 :
         367        13026915 :         void advancePastNulls(InlineElem *begin) {
         368        13026915 :             InlineElem *newCur = begin;
         369        26266567 :             while (newCur < end && NULL == newCur->key)
         370          212737 :                 ++newCur;
         371        13026915 :             JS_ASSERT(uintptr_t(newCur) <= uintptr_t(end));
         372        13026915 :             cur = newCur;
         373        13026915 :         }
         374                 :
         375         9590982 :         void bumpCurPtr() {
         376         9590982 :             JS_ASSERT(isInlineRange());
         377         9590982 :             advancePastNulls(cur + 1);
         378         9590982 :         }
         379                 :
         380                 :         void operator==(const Range &other);
         381                 :
         382                 :       public:
         383        35688166 :         bool empty() const {
         384        35688166 :             return isInlineRange() ? cur == end : mapRange.empty();
         385                 :         }
         386                 :
         387        12420190 :         Entry front() {
         388        12420190 :             JS_ASSERT(!empty());
         389        12420190 :             if (isInlineRange())
         390        12018124 :                 return Entry(cur->key, cur->value);
         391          402066 :             return Entry(mapRange.front().key, mapRange.front().value);
         392                 :         }
         393                 :
         394         9912985 :         void popFront() {
         395         9912985 :             JS_ASSERT(!empty());
         396         9912985 :             if (isInlineRange())
         397         9590982 :                 bumpCurPtr();
         398                 :             else
         399          322003 :                 mapRange.popFront();
         400         9912985 :         }
         401                 :     }; /* class Range */
         402                 :
         403         3448687 :     Range all() const {
         404         3448687 :         return usingMap() ? Range(map.all()) : Range(inl, inl + inlNext);
         405                 :     }
         406                 : }; /* class InlineMap */
         407                 :
         408                 : } /* namespace js */
         409                 :
         410                 : #endif

Generated by: LCOV version 1.7