2 * Copyright (C) 2011 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
27 #include "wtf/HashMap.h"
29 #include "wtf/OwnPtr.h"
30 #include "wtf/PassOwnPtr.h"
31 #include "wtf/PassRefPtr.h"
32 #include "wtf/RefCounted.h"
33 #include "wtf/Vector.h"
34 #include <gtest/gtest.h>
40 using IntHashMap
= HashMap
<int, int>;
42 TEST(HashMapTest
, IteratorComparison
)
46 EXPECT_TRUE(map
.begin() != map
.end());
47 EXPECT_FALSE(map
.begin() == map
.end());
49 IntHashMap::const_iterator begin
= map
.begin();
50 EXPECT_TRUE(begin
== map
.begin());
51 EXPECT_TRUE(map
.begin() == begin
);
52 EXPECT_TRUE(begin
!= map
.end());
53 EXPECT_TRUE(map
.end() != begin
);
54 EXPECT_FALSE(begin
!= map
.begin());
55 EXPECT_FALSE(map
.begin() != begin
);
56 EXPECT_FALSE(begin
== map
.end());
57 EXPECT_FALSE(map
.end() == begin
);
60 struct TestDoubleHashTraits
: HashTraits
<double> {
61 static const unsigned minimumTableSize
= 8;
64 using DoubleHashMap
= HashMap
<double, int64_t, DefaultHash
<double>::Hash
, TestDoubleHashTraits
>;
66 int bucketForKey(double key
)
68 return DefaultHash
<double>::Hash::hash(key
) & (TestDoubleHashTraits::minimumTableSize
- 1);
71 TEST(HashMapTest
, DoubleHashCollisions
)
73 // The "clobber" key here is one that ends up stealing the bucket that the -0 key
74 // originally wants to be in. This makes the 0 and -0 keys collide and the test then
75 // fails unless the FloatHash::equals() implementation can distinguish them.
76 const double clobberKey
= 6;
77 const double zeroKey
= 0;
78 const double negativeZeroKey
= -zeroKey
;
82 map
.add(clobberKey
, 1);
84 map
.add(negativeZeroKey
, 3);
86 EXPECT_EQ(bucketForKey(clobberKey
), bucketForKey(negativeZeroKey
));
87 EXPECT_EQ(1, map
.get(clobberKey
));
88 EXPECT_EQ(2, map
.get(zeroKey
));
89 EXPECT_EQ(3, map
.get(negativeZeroKey
));
92 class DestructCounter
{
94 explicit DestructCounter(int i
, int* destructNumber
)
96 , m_destructNumber(destructNumber
)
99 ~DestructCounter() { ++(*m_destructNumber
); }
100 int get() const { return m_i
; }
104 int* m_destructNumber
;
107 using OwnPtrHashMap
= HashMap
<int, OwnPtr
<DestructCounter
>>;
109 TEST(HashMapTest
, OwnPtrAsValue
)
111 int destructNumber
= 0;
113 map
.add(1, adoptPtr(new DestructCounter(1, &destructNumber
)));
114 map
.add(2, adoptPtr(new DestructCounter(2, &destructNumber
)));
116 DestructCounter
* counter1
= map
.get(1);
117 EXPECT_EQ(1, counter1
->get());
118 DestructCounter
* counter2
= map
.get(2);
119 EXPECT_EQ(2, counter2
->get());
120 EXPECT_EQ(0, destructNumber
);
122 for (OwnPtrHashMap::iterator iter
= map
.begin(); iter
!= map
.end(); ++iter
) {
123 OwnPtr
<DestructCounter
>& ownCounter
= iter
->value
;
124 EXPECT_EQ(iter
->key
, ownCounter
->get());
126 ASSERT_EQ(0, destructNumber
);
128 OwnPtr
<DestructCounter
> ownCounter1
= map
.take(1);
129 EXPECT_EQ(ownCounter1
.get(), counter1
);
130 EXPECT_FALSE(map
.contains(1));
131 EXPECT_EQ(0, destructNumber
);
134 EXPECT_FALSE(map
.contains(2));
135 EXPECT_EQ(0UL, map
.size());
136 EXPECT_EQ(1, destructNumber
);
139 EXPECT_EQ(2, destructNumber
);
142 class DummyRefCounted
: public RefCounted
<DummyRefCounted
> {
144 DummyRefCounted(bool& isDeleted
) : m_isDeleted(isDeleted
) { m_isDeleted
= false; }
147 ASSERT(!m_isDeleted
);
153 ASSERT(!m_isDeleted
);
154 WTF::RefCounted
<DummyRefCounted
>::ref();
160 ASSERT(!m_isDeleted
);
161 WTF::RefCounted
<DummyRefCounted
>::deref();
164 static int m_refInvokesCount
;
170 int DummyRefCounted::m_refInvokesCount
= 0;
172 TEST(HashMapTest
, RefPtrAsKey
)
174 bool isDeleted
= false;
175 DummyRefCounted::m_refInvokesCount
= 0;
176 RefPtr
<DummyRefCounted
> ptr
= adoptRef(new DummyRefCounted(isDeleted
));
177 EXPECT_EQ(0, DummyRefCounted::m_refInvokesCount
);
178 HashMap
<RefPtr
<DummyRefCounted
>, int> map
;
180 // Referenced only once (to store a copy in the container).
181 EXPECT_EQ(1, DummyRefCounted::m_refInvokesCount
);
182 EXPECT_EQ(1, map
.get(ptr
));
184 DummyRefCounted
* rawPtr
= ptr
.get();
186 EXPECT_TRUE(map
.contains(rawPtr
));
187 EXPECT_NE(map
.end(), map
.find(rawPtr
));
188 EXPECT_TRUE(map
.contains(ptr
));
189 EXPECT_NE(map
.end(), map
.find(ptr
));
190 EXPECT_EQ(1, DummyRefCounted::m_refInvokesCount
);
193 EXPECT_FALSE(isDeleted
);
196 EXPECT_EQ(1, DummyRefCounted::m_refInvokesCount
);
197 EXPECT_TRUE(isDeleted
);
198 EXPECT_TRUE(map
.isEmpty());
201 TEST(HashMaptest
, RemoveAdd
)
203 DummyRefCounted::m_refInvokesCount
= 0;
204 bool isDeleted
= false;
206 typedef HashMap
<int, RefPtr
<DummyRefCounted
>> Map
;
209 RefPtr
<DummyRefCounted
> ptr
= adoptRef(new DummyRefCounted(isDeleted
));
210 EXPECT_EQ(0, DummyRefCounted::m_refInvokesCount
);
213 // Referenced only once (to store a copy in the container).
214 EXPECT_EQ(1, DummyRefCounted::m_refInvokesCount
);
215 EXPECT_EQ(ptr
, map
.get(1));
218 EXPECT_FALSE(isDeleted
);
221 EXPECT_EQ(1, DummyRefCounted::m_refInvokesCount
);
222 EXPECT_TRUE(isDeleted
);
223 EXPECT_TRUE(map
.isEmpty());
225 // Add and remove until the deleted slot is reused.
226 for (int i
= 1; i
< 100; i
++) {
227 bool isDeleted2
= false;
228 RefPtr
<DummyRefCounted
> ptr2
= adoptRef(new DummyRefCounted(isDeleted2
));
230 EXPECT_FALSE(isDeleted2
);
232 EXPECT_FALSE(isDeleted2
);
234 EXPECT_TRUE(isDeleted2
);
240 explicit SimpleClass(int v
) : m_v(v
) { }
241 int v() { return m_v
; }
246 using IntSimpleMap
= HashMap
<int, OwnPtr
<SimpleClass
>>;
248 TEST(HashMapTest
, AddResult
)
251 IntSimpleMap::AddResult result
= map
.add(1, nullptr);
252 EXPECT_TRUE(result
.isNewEntry
);
253 EXPECT_EQ(1, result
.storedValue
->key
);
254 EXPECT_EQ(0, result
.storedValue
->value
.get());
256 SimpleClass
* simple1
= new SimpleClass(1);
257 result
.storedValue
->value
= adoptPtr(simple1
);
258 EXPECT_EQ(simple1
, map
.get(1));
260 IntSimpleMap::AddResult result2
= map
.add(1, adoptPtr(new SimpleClass(2)));
261 EXPECT_FALSE(result2
.isNewEntry
);
262 EXPECT_EQ(1, result
.storedValue
->key
);
263 EXPECT_EQ(1, result
.storedValue
->value
->v());
264 EXPECT_EQ(1, map
.get(1)->v());
267 TEST(HashMapTest
, AddResultVectorValue
)
269 using IntVectorMap
= HashMap
<int, Vector
<int>>;
271 IntVectorMap::AddResult result
= map
.add(1, Vector
<int>());
272 EXPECT_TRUE(result
.isNewEntry
);
273 EXPECT_EQ(1, result
.storedValue
->key
);
274 EXPECT_EQ(0u, result
.storedValue
->value
.size());
276 result
.storedValue
->value
.append(11);
277 EXPECT_EQ(1u, map
.find(1)->value
.size());
278 EXPECT_EQ(11, map
.find(1)->value
.first());
280 IntVectorMap::AddResult result2
= map
.add(1, Vector
<int>());
281 EXPECT_FALSE(result2
.isNewEntry
);
282 EXPECT_EQ(1, result
.storedValue
->key
);
283 EXPECT_EQ(1u, result
.storedValue
->value
.size());
284 EXPECT_EQ(11, result
.storedValue
->value
.first());
285 EXPECT_EQ(11, map
.find(1)->value
.first());
288 class InstanceCounter
{
290 InstanceCounter() { ++counter
; }
291 InstanceCounter(const InstanceCounter
& another
) { ++counter
; }
292 ~InstanceCounter() { --counter
; }
295 int InstanceCounter::counter
= 0;
297 TEST(HashMapTest
, ValueTypeDestructed
)
299 InstanceCounter::counter
= 0;
300 HashMap
<int, InstanceCounter
> map
;
301 map
.set(1, InstanceCounter());
303 EXPECT_EQ(0, InstanceCounter::counter
);
306 } // anonymous namespace