xpcom/ds/nsStaticNameTable.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/xpcom/ds/nsStaticNameTable.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,236 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + *
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +/* Class to manage lookup of static names in a table. */
    1.11 +
    1.12 +#include "nsCRT.h"
    1.13 +
    1.14 +#include "nscore.h"
    1.15 +#include "mozilla/HashFunctions.h"
    1.16 +#include "nsISupportsImpl.h"
    1.17 +
    1.18 +#define PL_ARENA_CONST_ALIGN_MASK 3
    1.19 +#include "nsStaticNameTable.h"
    1.20 +
    1.21 +using namespace mozilla;
    1.22 +
    1.23 +struct NameTableKey
    1.24 +{
    1.25 +    NameTableKey(const nsAFlatCString* aKeyStr)
    1.26 +        : mIsUnichar(false)
    1.27 +    {
    1.28 +        mKeyStr.m1b = aKeyStr;
    1.29 +    }
    1.30 +
    1.31 +    NameTableKey(const nsAFlatString* aKeyStr)
    1.32 +        : mIsUnichar(true)
    1.33 +    {
    1.34 +        mKeyStr.m2b = aKeyStr;
    1.35 +    }
    1.36 +
    1.37 +    bool mIsUnichar;
    1.38 +    union {
    1.39 +        const nsAFlatCString* m1b;
    1.40 +        const nsAFlatString* m2b;
    1.41 +    } mKeyStr;
    1.42 +};
    1.43 +
    1.44 +struct NameTableEntry : public PLDHashEntryHdr
    1.45 +{
    1.46 +    // no ownership here!
    1.47 +    const nsAFlatCString* mString;
    1.48 +    int32_t mIndex;
    1.49 +};
    1.50 +
    1.51 +static bool
    1.52 +matchNameKeysCaseInsensitive(PLDHashTable*, const PLDHashEntryHdr* aHdr,
    1.53 +                             const void* key)
    1.54 +{
    1.55 +    const NameTableEntry* entry =
    1.56 +        static_cast<const NameTableEntry *>(aHdr);
    1.57 +    const NameTableKey *keyValue = static_cast<const NameTableKey*>(key);
    1.58 +
    1.59 +    const nsAFlatCString* entryKey = entry->mString;
    1.60 +
    1.61 +    if (keyValue->mIsUnichar) {
    1.62 +        return keyValue->mKeyStr.m2b->
    1.63 +            LowerCaseEqualsASCII(entryKey->get(), entryKey->Length());
    1.64 +    }
    1.65 +
    1.66 +    return keyValue->mKeyStr.m1b->
    1.67 +        LowerCaseEqualsASCII(entryKey->get(), entryKey->Length());
    1.68 +}
    1.69 +
    1.70 +/*
    1.71 + * caseInsensitiveHashKey is just like PL_DHashStringKey except it
    1.72 + * uses (*s & ~0x20) instead of simply *s.  This means that "aFOO" and
    1.73 + * "afoo" and "aFoo" will all hash to the same thing.  It also means
    1.74 + * that some strings that aren't case-insensensitively equal will hash
    1.75 + * to the same value, but it's just a hash function so it doesn't
    1.76 + * matter.
    1.77 + */
    1.78 +static PLDHashNumber
    1.79 +caseInsensitiveStringHashKey(PLDHashTable *table, const void *key)
    1.80 +{
    1.81 +    PLDHashNumber h = 0;
    1.82 +    const NameTableKey* tableKey = static_cast<const NameTableKey*>(key);
    1.83 +    if (tableKey->mIsUnichar) {
    1.84 +        for (const char16_t* s = tableKey->mKeyStr.m2b->get();
    1.85 +             *s != '\0';
    1.86 +             s++)
    1.87 +            h = AddToHash(h, *s & ~0x20);
    1.88 +    } else {
    1.89 +        for (const unsigned char* s =
    1.90 +                 reinterpret_cast<const unsigned char*>
    1.91 +                                 (tableKey->mKeyStr.m1b->get());
    1.92 +             *s != '\0';
    1.93 +             s++)
    1.94 +            h = AddToHash(h, *s & ~0x20);
    1.95 +    }
    1.96 +    return h;
    1.97 +}
    1.98 +
    1.99 +static const struct PLDHashTableOps nametable_CaseInsensitiveHashTableOps = {
   1.100 +    PL_DHashAllocTable,
   1.101 +    PL_DHashFreeTable,
   1.102 +    caseInsensitiveStringHashKey,
   1.103 +    matchNameKeysCaseInsensitive,
   1.104 +    PL_DHashMoveEntryStub,
   1.105 +    PL_DHashClearEntryStub,
   1.106 +    PL_DHashFinalizeStub,
   1.107 +    nullptr,
   1.108 +};
   1.109 +
   1.110 +nsStaticCaseInsensitiveNameTable::nsStaticCaseInsensitiveNameTable()
   1.111 +  : mNameArray(nullptr), mNullStr("")
   1.112 +{
   1.113 +    MOZ_COUNT_CTOR(nsStaticCaseInsensitiveNameTable);
   1.114 +    mNameTable.ops = nullptr;
   1.115 +}
   1.116 +
   1.117 +nsStaticCaseInsensitiveNameTable::~nsStaticCaseInsensitiveNameTable()
   1.118 +{
   1.119 +    if (mNameArray) {
   1.120 +        // manually call the destructor on placement-new'ed objects
   1.121 +        for (uint32_t index = 0; index < mNameTable.entryCount; index++) {
   1.122 +            mNameArray[index].~nsDependentCString();
   1.123 +        }
   1.124 +        nsMemory::Free((void*)mNameArray);
   1.125 +    }
   1.126 +    if (mNameTable.ops)
   1.127 +        PL_DHashTableFinish(&mNameTable);
   1.128 +    MOZ_COUNT_DTOR(nsStaticCaseInsensitiveNameTable);
   1.129 +}
   1.130 +
   1.131 +bool
   1.132 +nsStaticCaseInsensitiveNameTable::Init(const char* const aNames[], int32_t Count)
   1.133 +{
   1.134 +    NS_ASSERTION(!mNameArray, "double Init");
   1.135 +    NS_ASSERTION(!mNameTable.ops, "double Init");
   1.136 +    NS_ASSERTION(aNames, "null name table");
   1.137 +    NS_ASSERTION(Count, "0 count");
   1.138 +
   1.139 +    mNameArray = (nsDependentCString*)
   1.140 +                   nsMemory::Alloc(Count * sizeof(nsDependentCString));
   1.141 +    if (!mNameArray)
   1.142 +        return false;
   1.143 +
   1.144 +    if (!PL_DHashTableInit(&mNameTable, &nametable_CaseInsensitiveHashTableOps,
   1.145 +                           nullptr, sizeof(NameTableEntry), Count,
   1.146 +                           fallible_t())) {
   1.147 +        mNameTable.ops = nullptr;
   1.148 +        return false;
   1.149 +    }
   1.150 +
   1.151 +    for (int32_t index = 0; index < Count; ++index) {
   1.152 +        const char* raw = aNames[index];
   1.153 +#ifdef DEBUG
   1.154 +        {
   1.155 +            // verify invariants of contents
   1.156 +            nsAutoCString temp1(raw);
   1.157 +            nsDependentCString temp2(raw);
   1.158 +            ToLowerCase(temp1);
   1.159 +            NS_ASSERTION(temp1.Equals(temp2), "upper case char in table");
   1.160 +            NS_ASSERTION(nsCRT::IsAscii(raw),
   1.161 +                         "non-ascii string in table -- "
   1.162 +                         "case-insensitive matching won't work right");
   1.163 +        }
   1.164 +#endif
   1.165 +        // use placement-new to initialize the string object
   1.166 +        nsDependentCString* strPtr = &mNameArray[index];
   1.167 +        new (strPtr) nsDependentCString(raw);
   1.168 +
   1.169 +        NameTableKey key(strPtr);
   1.170 +
   1.171 +        NameTableEntry *entry =
   1.172 +          static_cast<NameTableEntry*>
   1.173 +                     (PL_DHashTableOperate(&mNameTable, &key,
   1.174 +                                              PL_DHASH_ADD));
   1.175 +
   1.176 +        if (!entry) continue;
   1.177 +
   1.178 +        NS_ASSERTION(entry->mString == 0, "Entry already exists!");
   1.179 +
   1.180 +        entry->mString = strPtr;      // not owned!
   1.181 +        entry->mIndex = index;
   1.182 +    }
   1.183 +#ifdef DEBUG
   1.184 +    PL_DHashMarkTableImmutable(&mNameTable);
   1.185 +#endif
   1.186 +    return true;
   1.187 +}
   1.188 +
   1.189 +int32_t
   1.190 +nsStaticCaseInsensitiveNameTable::Lookup(const nsACString& aName)
   1.191 +{
   1.192 +    NS_ASSERTION(mNameArray, "not inited");
   1.193 +    NS_ASSERTION(mNameTable.ops, "not inited");
   1.194 +
   1.195 +    const nsAFlatCString& str = PromiseFlatCString(aName);
   1.196 +
   1.197 +    NameTableKey key(&str);
   1.198 +    NameTableEntry *entry =
   1.199 +        static_cast<NameTableEntry*>
   1.200 +                   (PL_DHashTableOperate(&mNameTable, &key,
   1.201 +                                            PL_DHASH_LOOKUP));
   1.202 +
   1.203 +    if (PL_DHASH_ENTRY_IS_FREE(entry))
   1.204 +        return nsStaticCaseInsensitiveNameTable::NOT_FOUND;
   1.205 +
   1.206 +    return entry->mIndex;
   1.207 +}
   1.208 +
   1.209 +int32_t
   1.210 +nsStaticCaseInsensitiveNameTable::Lookup(const nsAString& aName)
   1.211 +{
   1.212 +    NS_ASSERTION(mNameArray, "not inited");
   1.213 +    NS_ASSERTION(mNameTable.ops, "not inited");
   1.214 +
   1.215 +    const nsAFlatString& str = PromiseFlatString(aName);
   1.216 +
   1.217 +    NameTableKey key(&str);
   1.218 +    NameTableEntry *entry =
   1.219 +        static_cast<NameTableEntry*>
   1.220 +                   (PL_DHashTableOperate(&mNameTable, &key,
   1.221 +                                            PL_DHASH_LOOKUP));
   1.222 +
   1.223 +    if (PL_DHASH_ENTRY_IS_FREE(entry))
   1.224 +        return nsStaticCaseInsensitiveNameTable::NOT_FOUND;
   1.225 +
   1.226 +    return entry->mIndex;
   1.227 +}
   1.228 +
   1.229 +const nsAFlatCString& 
   1.230 +nsStaticCaseInsensitiveNameTable::GetStringValue(int32_t index)
   1.231 +{
   1.232 +    NS_ASSERTION(mNameArray, "not inited");
   1.233 +    NS_ASSERTION(mNameTable.ops, "not inited");
   1.234 +
   1.235 +    if ((NOT_FOUND < index) && ((uint32_t)index < mNameTable.entryCount)) {
   1.236 +        return mNameArray[index];
   1.237 +    }
   1.238 +    return mNullStr;
   1.239 +}

mercurial