1 : #include "tests.h"
2 :
3 : #include "js/HashTable.h"
4 :
5 : //#define FUZZ
6 :
7 : typedef js::HashMap<uint32_t, uint32_t, js::DefaultHasher<uint32_t>, js::SystemAllocPolicy> IntMap;
8 : typedef js::HashSet<uint32_t, js::DefaultHasher<uint32_t>, js::SystemAllocPolicy> IntSet;
9 :
10 : /*
11 : * The rekeying test as conducted by adding only keys masked with 0x0000FFFF
12 : * that are unique. We rekey by shifting left 16 bits.
13 : */
14 : #ifdef FUZZ
15 : const size_t TestSize = 0x0000FFFF / 2;
16 : const size_t TestIterations = SIZE_MAX;
17 : #else
18 : const size_t TestSize = 10000;
19 : const size_t TestIterations = 10;
20 : #endif
21 :
22 : JS_STATIC_ASSERT(TestSize <= 0x0000FFFF / 2);
23 :
24 : struct LowToHigh
25 : {
26 470160 : static uint32_t rekey(uint32_t initial) {
27 470160 : if (initial > uint32_t(0x0000FFFF))
28 70160 : return initial;
29 400000 : return initial << 16;
30 : }
31 :
32 200000 : static bool shouldBeRemoved(uint32_t initial) {
33 200000 : return false;
34 : }
35 : };
36 :
37 : struct LowToHighWithRemoval
38 : {
39 231858 : static uint32_t rekey(uint32_t initial) {
40 231858 : if (initial > uint32_t(0x0000FFFF))
41 31962 : return initial;
42 199896 : return initial << 16;
43 : }
44 :
45 431962 : static bool shouldBeRemoved(uint32_t initial) {
46 431962 : if (initial >= 0x00010000)
47 31962 : return (initial >> 16) % 2 == 0;
48 400000 : return initial % 2 == 0;
49 : }
50 : };
51 :
52 : static bool
53 40 : MapsAreEqual(IntMap &am, IntMap &bm)
54 : {
55 40 : bool equal = true;
56 40 : if (am.count() != bm.count()) {
57 0 : equal = false;
58 0 : fprintf(stderr, "A.count() == %u and B.count() == %u\n", am.count(), bm.count());
59 : }
60 350014 : for (IntMap::Range r = am.all(); !r.empty(); r.popFront()) {
61 349974 : if (!bm.has(r.front().key)) {
62 0 : equal = false;
63 0 : fprintf(stderr, "B does not have %x which is in A\n", r.front().key);
64 : }
65 : }
66 350014 : for (IntMap::Range r = bm.all(); !r.empty(); r.popFront()) {
67 349974 : if (!am.has(r.front().key)) {
68 0 : equal = false;
69 0 : fprintf(stderr, "A does not have %x which is in B\n", r.front().key);
70 : }
71 : }
72 40 : return equal;
73 : }
74 :
75 : static bool
76 40 : SetsAreEqual(IntSet &am, IntSet &bm)
77 : {
78 40 : bool equal = true;
79 40 : if (am.count() != bm.count()) {
80 0 : equal = false;
81 0 : fprintf(stderr, "A.count() == %u and B.count() == %u\n", am.count(), bm.count());
82 : }
83 350014 : for (IntSet::Range r = am.all(); !r.empty(); r.popFront()) {
84 349974 : if (!bm.has(r.front())) {
85 0 : equal = false;
86 0 : fprintf(stderr, "B does not have %x which is in A\n", r.front());
87 : }
88 : }
89 350014 : for (IntSet::Range r = bm.all(); !r.empty(); r.popFront()) {
90 349974 : if (!am.has(r.front())) {
91 0 : equal = false;
92 0 : fprintf(stderr, "A does not have %x which is in B\n", r.front());
93 : }
94 : }
95 40 : return equal;
96 : }
97 :
98 : static bool
99 20 : AddLowKeys(IntMap *am, IntMap *bm, int seed)
100 : {
101 20 : size_t i = 0;
102 20 : srand(seed);
103 217022 : while (i < TestSize) {
104 216982 : uint32_t n = rand() & 0x0000FFFF;
105 216982 : if (!am->has(n)) {
106 200000 : if (bm->has(n))
107 0 : return false;
108 200000 : am->putNew(n, n);
109 200000 : bm->putNew(n, n);
110 200000 : i++;
111 : }
112 : }
113 20 : return true;
114 : }
115 :
116 : static bool
117 20 : AddLowKeys(IntSet *as, IntSet *bs, int seed)
118 : {
119 20 : size_t i = 0;
120 20 : srand(seed);
121 217022 : while (i < TestSize) {
122 216982 : uint32_t n = rand() & 0x0000FFFF;
123 216982 : if (!as->has(n)) {
124 200000 : if (bs->has(n))
125 0 : return false;
126 200000 : as->putNew(n);
127 200000 : bs->putNew(n);
128 200000 : i++;
129 : }
130 : }
131 20 : return true;
132 : }
133 :
134 : template <class NewKeyFunction>
135 : static bool
136 20 : SlowRekey(IntMap *m) {
137 40 : IntMap tmp;
138 20 : tmp.init();
139 :
140 200020 : for (IntMap::Range r = m->all(); !r.empty(); r.popFront()) {
141 200000 : if (NewKeyFunction::shouldBeRemoved(r.front().key))
142 50026 : continue;
143 149974 : uint32_t hi = NewKeyFunction::rekey(r.front().key);
144 149974 : if (tmp.has(hi))
145 0 : return false;
146 149974 : tmp.putNew(hi, r.front().value);
147 : }
148 :
149 20 : m->clear();
150 149994 : for (IntMap::Range r = tmp.all(); !r.empty(); r.popFront()) {
151 149974 : m->putNew(r.front().key, r.front().value);
152 : }
153 :
154 20 : return true;
155 : }
156 :
157 : template <class NewKeyFunction>
158 : static bool
159 20 : SlowRekey(IntSet *s) {
160 40 : IntSet tmp;
161 20 : tmp.init();
162 :
163 200020 : for (IntSet::Range r = s->all(); !r.empty(); r.popFront()) {
164 200000 : if (NewKeyFunction::shouldBeRemoved(r.front()))
165 50026 : continue;
166 149974 : uint32_t hi = NewKeyFunction::rekey(r.front());
167 149974 : if (tmp.has(hi))
168 0 : return false;
169 149974 : tmp.putNew(hi);
170 : }
171 :
172 20 : s->clear();
173 149994 : for (IntSet::Range r = tmp.all(); !r.empty(); r.popFront()) {
174 149974 : s->putNew(r.front());
175 : }
176 :
177 20 : return true;
178 : }
179 :
180 4 : BEGIN_TEST(testHashRekeyManual)
181 : {
182 2 : IntMap am, bm;
183 1 : am.init();
184 1 : bm.init();
185 11 : for (size_t i = 0; i < TestIterations; ++i) {
186 : #ifdef FUZZ
187 : fprintf(stderr, "map1: %lu\n", i);
188 : #endif
189 10 : CHECK(AddLowKeys(&am, &bm, i));
190 10 : CHECK(MapsAreEqual(am, bm));
191 :
192 135090 : for (IntMap::Enum e(am); !e.empty(); e.popFront()) {
193 135080 : uint32_t tmp = LowToHigh::rekey(e.front().key);
194 135080 : if (tmp != e.front().key)
195 99995 : e.rekeyFront(tmp);
196 : }
197 10 : CHECK(SlowRekey<LowToHigh>(&bm));
198 :
199 10 : CHECK(MapsAreEqual(am, bm));
200 10 : am.clear();
201 10 : bm.clear();
202 : }
203 :
204 2 : IntSet as, bs;
205 1 : as.init();
206 1 : bs.init();
207 11 : for (size_t i = 0; i < TestIterations; ++i) {
208 : #ifdef FUZZ
209 : fprintf(stderr, "set1: %lu\n", i);
210 : #endif
211 10 : CHECK(AddLowKeys(&as, &bs, i));
212 10 : CHECK(SetsAreEqual(as, bs));
213 :
214 135090 : for (IntSet::Enum e(as); !e.empty(); e.popFront()) {
215 135080 : uint32_t tmp = LowToHigh::rekey(e.front());
216 135080 : if (tmp != e.front())
217 99995 : e.rekeyFront(tmp);
218 : }
219 10 : CHECK(SlowRekey<LowToHigh>(&bs));
220 :
221 10 : CHECK(SetsAreEqual(as, bs));
222 10 : as.clear();
223 10 : bs.clear();
224 : }
225 :
226 1 : return true;
227 : }
228 1 : END_TEST(testHashRekeyManual)
229 :
230 4 : BEGIN_TEST(testHashRekeyManualRemoval)
231 : {
232 2 : IntMap am, bm;
233 1 : am.init();
234 1 : bm.init();
235 11 : for (size_t i = 0; i < TestIterations; ++i) {
236 : #ifdef FUZZ
237 : fprintf(stderr, "map2: %lu\n", i);
238 : #endif
239 10 : CHECK(AddLowKeys(&am, &bm, i));
240 10 : CHECK(MapsAreEqual(am, bm));
241 :
242 115991 : for (IntMap::Enum e(am); !e.empty(); e.popFront()) {
243 115981 : if (LowToHighWithRemoval::shouldBeRemoved(e.front().key)) {
244 50026 : e.removeFront();
245 : } else {
246 65955 : uint32_t tmp = LowToHighWithRemoval::rekey(e.front().key);
247 65955 : if (tmp != e.front().key)
248 49974 : e.rekeyFront(tmp);
249 : }
250 : }
251 10 : CHECK(SlowRekey<LowToHighWithRemoval>(&bm));
252 :
253 10 : CHECK(MapsAreEqual(am, bm));
254 10 : am.clear();
255 10 : bm.clear();
256 : }
257 :
258 2 : IntSet as, bs;
259 1 : as.init();
260 1 : bs.init();
261 11 : for (size_t i = 0; i < TestIterations; ++i) {
262 : #ifdef FUZZ
263 : fprintf(stderr, "set1: %lu\n", i);
264 : #endif
265 10 : CHECK(AddLowKeys(&as, &bs, i));
266 10 : CHECK(SetsAreEqual(as, bs));
267 :
268 115991 : for (IntSet::Enum e(as); !e.empty(); e.popFront()) {
269 115981 : if (LowToHighWithRemoval::shouldBeRemoved(e.front())) {
270 50026 : e.removeFront();
271 : } else {
272 65955 : uint32_t tmp = LowToHighWithRemoval::rekey(e.front());
273 65955 : if (tmp != e.front())
274 49974 : e.rekeyFront(tmp);
275 : }
276 : }
277 10 : CHECK(SlowRekey<LowToHighWithRemoval>(&bs));
278 :
279 10 : CHECK(SetsAreEqual(as, bs));
280 10 : as.clear();
281 10 : bs.clear();
282 : }
283 :
284 1 : return true;
285 : }
286 3 : END_TEST(testHashRekeyManualRemoval)
287 :
|