Coverage Report

Created: 2018-09-25 14:53

/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
}