/src/mozilla-central/xpcom/ds/nsStaticNameTable.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
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 | | #include "nsStaticNameTable.h" |
16 | | |
17 | | using namespace mozilla; |
18 | | |
19 | | struct NameTableKey |
20 | | { |
21 | | NameTableKey(const nsDependentCString aNameArray[], |
22 | | const nsCString* aKeyStr) |
23 | | : mNameArray(aNameArray) |
24 | | , mIsUnichar(false) |
25 | 1.23k | { |
26 | 1.23k | mKeyStr.m1b = aKeyStr; |
27 | 1.23k | } |
28 | | |
29 | | NameTableKey(const nsDependentCString aNameArray[], |
30 | | const nsString* aKeyStr) |
31 | | : mNameArray(aNameArray) |
32 | | , mIsUnichar(true) |
33 | 0 | { |
34 | 0 | mKeyStr.m2b = aKeyStr; |
35 | 0 | } |
36 | | |
37 | | const nsDependentCString* mNameArray; |
38 | | union |
39 | | { |
40 | | const nsCString* m1b; |
41 | | const nsString* m2b; |
42 | | } mKeyStr; |
43 | | bool mIsUnichar; |
44 | | }; |
45 | | |
46 | | struct NameTableEntry : public PLDHashEntryHdr |
47 | | { |
48 | | int32_t mIndex; |
49 | | }; |
50 | | |
51 | | static bool |
52 | | matchNameKeysCaseInsensitive(const PLDHashEntryHdr* aHdr, const void* aVoidKey) |
53 | 0 | { |
54 | 0 | auto entry = static_cast<const NameTableEntry*>(aHdr); |
55 | 0 | auto key = static_cast<const NameTableKey*>(aVoidKey); |
56 | 0 | const nsDependentCString* name = &key->mNameArray[entry->mIndex]; |
57 | 0 |
|
58 | 0 | return key->mIsUnichar |
59 | 0 | ? key->mKeyStr.m2b->LowerCaseEqualsASCII(name->get(), name->Length()) |
60 | 0 | : key->mKeyStr.m1b->LowerCaseEqualsASCII(name->get(), name->Length()); |
61 | 0 | } |
62 | | |
63 | | /* |
64 | | * caseInsensitiveHashKey is just like PLDHashTable::HashStringKey except it |
65 | | * uses (*s & ~0x20) instead of simply *s. This means that "aFOO" and |
66 | | * "afoo" and "aFoo" will all hash to the same thing. It also means |
67 | | * that some strings that aren't case-insensensitively equal will hash |
68 | | * to the same value, but it's just a hash function so it doesn't |
69 | | * matter. |
70 | | */ |
71 | | static PLDHashNumber |
72 | | caseInsensitiveStringHashKey(const void* aKey) |
73 | 1.23k | { |
74 | 1.23k | PLDHashNumber h = 0; |
75 | 1.23k | const NameTableKey* tableKey = static_cast<const NameTableKey*>(aKey); |
76 | 1.23k | if (tableKey->mIsUnichar) { |
77 | 0 | for (const char16_t* s = tableKey->mKeyStr.m2b->get(); |
78 | 0 | *s != '\0'; |
79 | 0 | s++) { |
80 | 0 | h = AddToHash(h, *s & ~0x20); |
81 | 0 | } |
82 | 1.23k | } else { |
83 | 1.23k | for (const unsigned char* s = reinterpret_cast<const unsigned char*>( |
84 | 1.23k | tableKey->mKeyStr.m1b->get()); |
85 | 12.3k | *s != '\0'; |
86 | 11.0k | s++) { |
87 | 11.0k | h = AddToHash(h, *s & ~0x20); |
88 | 11.0k | } |
89 | 1.23k | } |
90 | 1.23k | return h; |
91 | 1.23k | } |
92 | | |
93 | | static const struct PLDHashTableOps nametable_CaseInsensitiveHashTableOps = { |
94 | | caseInsensitiveStringHashKey, |
95 | | matchNameKeysCaseInsensitive, |
96 | | PLDHashTable::MoveEntryStub, |
97 | | PLDHashTable::ClearEntryStub, |
98 | | nullptr, |
99 | | }; |
100 | | |
101 | | nsStaticCaseInsensitiveNameTable::nsStaticCaseInsensitiveNameTable( |
102 | | const char* const aNames[], int32_t aLength) |
103 | | : mNameArray(nullptr) |
104 | | , mNameTable(&nametable_CaseInsensitiveHashTableOps, |
105 | | sizeof(NameTableEntry), aLength) |
106 | | , mNullStr("") |
107 | 12 | { |
108 | 12 | MOZ_COUNT_CTOR(nsStaticCaseInsensitiveNameTable); |
109 | 12 | |
110 | 12 | MOZ_ASSERT(aNames, "null name table"); |
111 | 12 | MOZ_ASSERT(aLength, "0 length"); |
112 | 12 | |
113 | 12 | mNameArray = (nsDependentCString*) |
114 | 12 | moz_xmalloc(aLength * sizeof(nsDependentCString)); |
115 | 12 | |
116 | 1.24k | for (int32_t index = 0; index < aLength; ++index) { |
117 | 1.23k | const char* raw = aNames[index]; |
118 | | #ifdef DEBUG |
119 | | { |
120 | | // verify invariants of contents |
121 | | nsAutoCString temp1(raw); |
122 | | nsDependentCString temp2(raw); |
123 | | ToLowerCase(temp1); |
124 | | MOZ_ASSERT(temp1.Equals(temp2), "upper case char in table"); |
125 | | MOZ_ASSERT(nsCRT::IsAscii(raw), |
126 | | "non-ascii string in table -- " |
127 | | "case-insensitive matching won't work right"); |
128 | | } |
129 | | #endif |
130 | | // use placement-new to initialize the string object |
131 | 1.23k | nsDependentCString* strPtr = &mNameArray[index]; |
132 | 1.23k | new (strPtr) nsDependentCString(raw); |
133 | 1.23k | |
134 | 1.23k | NameTableKey key(mNameArray, strPtr); |
135 | 1.23k | |
136 | 1.23k | auto entry = static_cast<NameTableEntry*>(mNameTable.Add(&key, fallible)); |
137 | 1.23k | if (!entry) { |
138 | 0 | continue; |
139 | 0 | } |
140 | 1.23k | |
141 | 1.23k | // If the entry already exists it's unlikely but possible that its index is |
142 | 1.23k | // zero, in which case this assertion won't fail. But if the index is |
143 | 1.23k | // non-zero (highly likely) then it will fail. In other words, this |
144 | 1.23k | // assertion is likely but not guaranteed to detect if an entry is already |
145 | 1.23k | // used. |
146 | 1.23k | MOZ_ASSERT(entry->mIndex == 0, "Entry already exists!"); |
147 | 1.23k | |
148 | 1.23k | entry->mIndex = index; |
149 | 1.23k | } |
150 | | #ifdef DEBUG |
151 | | mNameTable.MarkImmutable(); |
152 | | #endif |
153 | | } |
154 | | |
155 | | nsStaticCaseInsensitiveNameTable::~nsStaticCaseInsensitiveNameTable() |
156 | 0 | { |
157 | 0 | // manually call the destructor on placement-new'ed objects |
158 | 0 | for (uint32_t index = 0; index < mNameTable.EntryCount(); index++) { |
159 | 0 | mNameArray[index].~nsDependentCString(); |
160 | 0 | } |
161 | 0 | free((void*)mNameArray); |
162 | 0 | MOZ_COUNT_DTOR(nsStaticCaseInsensitiveNameTable); |
163 | 0 | } |
164 | | |
165 | | int32_t |
166 | | nsStaticCaseInsensitiveNameTable::Lookup(const nsACString& aName) const |
167 | 0 | { |
168 | 0 | NS_ASSERTION(mNameArray, "not inited"); |
169 | 0 |
|
170 | 0 | const nsCString& str = PromiseFlatCString(aName); |
171 | 0 |
|
172 | 0 | NameTableKey key(mNameArray, &str); |
173 | 0 | auto entry = static_cast<NameTableEntry*>(mNameTable.Search(&key)); |
174 | 0 |
|
175 | 0 | return entry ? entry->mIndex : nsStaticCaseInsensitiveNameTable::NOT_FOUND; |
176 | 0 | } |
177 | | |
178 | | int32_t |
179 | | nsStaticCaseInsensitiveNameTable::Lookup(const nsAString& aName) const |
180 | 0 | { |
181 | 0 | NS_ASSERTION(mNameArray, "not inited"); |
182 | 0 |
|
183 | 0 | const nsString& str = PromiseFlatString(aName); |
184 | 0 |
|
185 | 0 | NameTableKey key(mNameArray, &str); |
186 | 0 | auto entry = static_cast<NameTableEntry*>(mNameTable.Search(&key)); |
187 | 0 |
|
188 | 0 | return entry ? entry->mIndex : nsStaticCaseInsensitiveNameTable::NOT_FOUND; |
189 | 0 | } |
190 | | |
191 | | const nsCString& |
192 | | nsStaticCaseInsensitiveNameTable::GetStringValue(int32_t aIndex) |
193 | 0 | { |
194 | 0 | NS_ASSERTION(mNameArray, "not inited"); |
195 | 0 |
|
196 | 0 | if ((NOT_FOUND < aIndex) && ((uint32_t)aIndex < mNameTable.EntryCount())) { |
197 | 0 | return mNameArray[aIndex]; |
198 | 0 | } |
199 | 0 | return mNullStr; |
200 | 0 | } |