xpcom/ds/nsStaticNameTable.cpp

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:a8549056cca5
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 /* Class to manage lookup of static names in a table. */
8
9 #include "nsCRT.h"
10
11 #include "nscore.h"
12 #include "mozilla/HashFunctions.h"
13 #include "nsISupportsImpl.h"
14
15 #define PL_ARENA_CONST_ALIGN_MASK 3
16 #include "nsStaticNameTable.h"
17
18 using namespace mozilla;
19
20 struct NameTableKey
21 {
22 NameTableKey(const nsAFlatCString* aKeyStr)
23 : mIsUnichar(false)
24 {
25 mKeyStr.m1b = aKeyStr;
26 }
27
28 NameTableKey(const nsAFlatString* aKeyStr)
29 : mIsUnichar(true)
30 {
31 mKeyStr.m2b = aKeyStr;
32 }
33
34 bool mIsUnichar;
35 union {
36 const nsAFlatCString* m1b;
37 const nsAFlatString* m2b;
38 } mKeyStr;
39 };
40
41 struct NameTableEntry : public PLDHashEntryHdr
42 {
43 // no ownership here!
44 const nsAFlatCString* mString;
45 int32_t mIndex;
46 };
47
48 static bool
49 matchNameKeysCaseInsensitive(PLDHashTable*, const PLDHashEntryHdr* aHdr,
50 const void* key)
51 {
52 const NameTableEntry* entry =
53 static_cast<const NameTableEntry *>(aHdr);
54 const NameTableKey *keyValue = static_cast<const NameTableKey*>(key);
55
56 const nsAFlatCString* entryKey = entry->mString;
57
58 if (keyValue->mIsUnichar) {
59 return keyValue->mKeyStr.m2b->
60 LowerCaseEqualsASCII(entryKey->get(), entryKey->Length());
61 }
62
63 return keyValue->mKeyStr.m1b->
64 LowerCaseEqualsASCII(entryKey->get(), entryKey->Length());
65 }
66
67 /*
68 * caseInsensitiveHashKey is just like PL_DHashStringKey except it
69 * uses (*s & ~0x20) instead of simply *s. This means that "aFOO" and
70 * "afoo" and "aFoo" will all hash to the same thing. It also means
71 * that some strings that aren't case-insensensitively equal will hash
72 * to the same value, but it's just a hash function so it doesn't
73 * matter.
74 */
75 static PLDHashNumber
76 caseInsensitiveStringHashKey(PLDHashTable *table, const void *key)
77 {
78 PLDHashNumber h = 0;
79 const NameTableKey* tableKey = static_cast<const NameTableKey*>(key);
80 if (tableKey->mIsUnichar) {
81 for (const char16_t* s = tableKey->mKeyStr.m2b->get();
82 *s != '\0';
83 s++)
84 h = AddToHash(h, *s & ~0x20);
85 } else {
86 for (const unsigned char* s =
87 reinterpret_cast<const unsigned char*>
88 (tableKey->mKeyStr.m1b->get());
89 *s != '\0';
90 s++)
91 h = AddToHash(h, *s & ~0x20);
92 }
93 return h;
94 }
95
96 static const struct PLDHashTableOps nametable_CaseInsensitiveHashTableOps = {
97 PL_DHashAllocTable,
98 PL_DHashFreeTable,
99 caseInsensitiveStringHashKey,
100 matchNameKeysCaseInsensitive,
101 PL_DHashMoveEntryStub,
102 PL_DHashClearEntryStub,
103 PL_DHashFinalizeStub,
104 nullptr,
105 };
106
107 nsStaticCaseInsensitiveNameTable::nsStaticCaseInsensitiveNameTable()
108 : mNameArray(nullptr), mNullStr("")
109 {
110 MOZ_COUNT_CTOR(nsStaticCaseInsensitiveNameTable);
111 mNameTable.ops = nullptr;
112 }
113
114 nsStaticCaseInsensitiveNameTable::~nsStaticCaseInsensitiveNameTable()
115 {
116 if (mNameArray) {
117 // manually call the destructor on placement-new'ed objects
118 for (uint32_t index = 0; index < mNameTable.entryCount; index++) {
119 mNameArray[index].~nsDependentCString();
120 }
121 nsMemory::Free((void*)mNameArray);
122 }
123 if (mNameTable.ops)
124 PL_DHashTableFinish(&mNameTable);
125 MOZ_COUNT_DTOR(nsStaticCaseInsensitiveNameTable);
126 }
127
128 bool
129 nsStaticCaseInsensitiveNameTable::Init(const char* const aNames[], int32_t Count)
130 {
131 NS_ASSERTION(!mNameArray, "double Init");
132 NS_ASSERTION(!mNameTable.ops, "double Init");
133 NS_ASSERTION(aNames, "null name table");
134 NS_ASSERTION(Count, "0 count");
135
136 mNameArray = (nsDependentCString*)
137 nsMemory::Alloc(Count * sizeof(nsDependentCString));
138 if (!mNameArray)
139 return false;
140
141 if (!PL_DHashTableInit(&mNameTable, &nametable_CaseInsensitiveHashTableOps,
142 nullptr, sizeof(NameTableEntry), Count,
143 fallible_t())) {
144 mNameTable.ops = nullptr;
145 return false;
146 }
147
148 for (int32_t index = 0; index < Count; ++index) {
149 const char* raw = aNames[index];
150 #ifdef DEBUG
151 {
152 // verify invariants of contents
153 nsAutoCString temp1(raw);
154 nsDependentCString temp2(raw);
155 ToLowerCase(temp1);
156 NS_ASSERTION(temp1.Equals(temp2), "upper case char in table");
157 NS_ASSERTION(nsCRT::IsAscii(raw),
158 "non-ascii string in table -- "
159 "case-insensitive matching won't work right");
160 }
161 #endif
162 // use placement-new to initialize the string object
163 nsDependentCString* strPtr = &mNameArray[index];
164 new (strPtr) nsDependentCString(raw);
165
166 NameTableKey key(strPtr);
167
168 NameTableEntry *entry =
169 static_cast<NameTableEntry*>
170 (PL_DHashTableOperate(&mNameTable, &key,
171 PL_DHASH_ADD));
172
173 if (!entry) continue;
174
175 NS_ASSERTION(entry->mString == 0, "Entry already exists!");
176
177 entry->mString = strPtr; // not owned!
178 entry->mIndex = index;
179 }
180 #ifdef DEBUG
181 PL_DHashMarkTableImmutable(&mNameTable);
182 #endif
183 return true;
184 }
185
186 int32_t
187 nsStaticCaseInsensitiveNameTable::Lookup(const nsACString& aName)
188 {
189 NS_ASSERTION(mNameArray, "not inited");
190 NS_ASSERTION(mNameTable.ops, "not inited");
191
192 const nsAFlatCString& str = PromiseFlatCString(aName);
193
194 NameTableKey key(&str);
195 NameTableEntry *entry =
196 static_cast<NameTableEntry*>
197 (PL_DHashTableOperate(&mNameTable, &key,
198 PL_DHASH_LOOKUP));
199
200 if (PL_DHASH_ENTRY_IS_FREE(entry))
201 return nsStaticCaseInsensitiveNameTable::NOT_FOUND;
202
203 return entry->mIndex;
204 }
205
206 int32_t
207 nsStaticCaseInsensitiveNameTable::Lookup(const nsAString& aName)
208 {
209 NS_ASSERTION(mNameArray, "not inited");
210 NS_ASSERTION(mNameTable.ops, "not inited");
211
212 const nsAFlatString& str = PromiseFlatString(aName);
213
214 NameTableKey key(&str);
215 NameTableEntry *entry =
216 static_cast<NameTableEntry*>
217 (PL_DHashTableOperate(&mNameTable, &key,
218 PL_DHASH_LOOKUP));
219
220 if (PL_DHASH_ENTRY_IS_FREE(entry))
221 return nsStaticCaseInsensitiveNameTable::NOT_FOUND;
222
223 return entry->mIndex;
224 }
225
226 const nsAFlatCString&
227 nsStaticCaseInsensitiveNameTable::GetStringValue(int32_t index)
228 {
229 NS_ASSERTION(mNameArray, "not inited");
230 NS_ASSERTION(mNameTable.ops, "not inited");
231
232 if ((NOT_FOUND < index) && ((uint32_t)index < mNameTable.entryCount)) {
233 return mNameArray[index];
234 }
235 return mNullStr;
236 }

mercurial