Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(189)

Side by Side Diff: runtime/vm/hash_table_test.cc

Issue 304253002: Hash tables templates, wrapping Array. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 #include <algorithm>
6 #include <cstring>
7 #include <map>
8 #include <set>
9 #include <string>
10 #include <utility>
11 #include <vector>
12
13 #include "platform/assert.h"
14 #include "vm/unit_test.h"
15 #include "vm/hash_table.h"
16
17 namespace dart {
18
19 // Various ways to look up strings. Uses length as the hash code to make it
20 // easy to engineer collisions.
21 class TestTraits {
22 public:
23 static bool IsMatch(const char* key, const Object& obj) {
24 return String::Cast(obj).Equals(key);
25 }
26 static uword Hash(const char* key) {
27 return static_cast<uword>(strlen(key));
28 }
29 static bool IsMatch(const std::string& key, const Object& obj) {
siva 2014/06/13 19:51:18 why do you want the C++ string API here, we try to
koda 2014/06/23 19:44:56 Removed. Mainly, it was to show that an arbitrary
30 return IsMatch(key.c_str(), obj);
31 }
32 static uword Hash(const std::string& key) {
siva 2014/06/13 19:51:18 Ditto comment about C++ string.
koda 2014/06/23 19:44:55 Done.
33 return key.size();
34 }
35 static bool IsMatch(const Object& a, const Object& b) {
36 return b.IsString() && String::Cast(a).Equals(String::Cast(b));
siva 2014/06/13 19:51:19 a.IsString() needs to be checked too?
koda 2014/06/23 19:44:56 Done.
37 }
38 static uword Hash(const Object& obj) {
39 return String::Cast(obj).Length();
40 }
41 };
42
43
44 template<typename Table>
45 void Validate(const Table& table) {
46 // Verify consistency of entry state tracking.
47 intptr_t num_entries = table.NumEntries();
48 intptr_t num_unused = table.NumUnused();
49 intptr_t num_occupied = table.NumOccupied();
50 intptr_t num_deleted = table.NumDeleted();
51 for (intptr_t i = 0; i < num_entries; ++i) {
52 EXPECT_EQ(1, table.IsUnused(i) + table.IsOccupied(i) + table.IsDeleted(i));
53 num_unused -= table.IsUnused(i);
54 num_occupied -= table.IsOccupied(i);
55 num_deleted -= table.IsDeleted(i);
56 }
57 EXPECT_EQ(0, num_unused);
58 EXPECT_EQ(0, num_occupied);
59 EXPECT_EQ(0, num_deleted);
60 }
61
62
63 TEST_CASE(HashTable) {
64 typedef HashTable<TestTraits, 2, 1> Table;
65 Table table(Array::Handle(HashTables::New<Table>(5)));
66 EXPECT_LE(5, table.NumEntries());
siva 2014/06/13 19:51:19 why EXPECT_LE(5, ...) instead of EXPECT_EQ(0, ...)
koda 2014/06/23 19:44:56 NumEntries is the *total* number of entries (contr
67 EXPECT_EQ(0, table.NumOccupied());
68 Validate(table);
69 EXPECT_EQ(-1, table.FindKey("a"));
70
71 // Insertion and lookup.
72 intptr_t a_entry = -1;
73 EXPECT(!table.FindKeyOrDeletedOrUnused("a", &a_entry));
74 EXPECT_NE(-1, a_entry);
75 String& a = String::Handle(String::New("a"));
76 table.InsertKey(a_entry, a);
77 EXPECT_EQ(1, table.NumOccupied());
78 Validate(table);
79 EXPECT_EQ(a_entry, table.FindKey("a"));
80 EXPECT_EQ(-1, table.FindKey("b"));
81 intptr_t a_entry_again = -1;
82 EXPECT(table.FindKeyOrDeletedOrUnused("a", &a_entry_again));
83 EXPECT_EQ(a_entry, a_entry_again);
84 intptr_t b_entry = -1;
85 EXPECT(!table.FindKeyOrDeletedOrUnused("b", &b_entry));
86 String& b = String::Handle(String::New("b"));
87 table.InsertKey(b_entry, b);
88 EXPECT_EQ(2, table.NumOccupied());
89 Validate(table);
90
91 // Deletion.
92 table.DeleteEntry(a_entry);
93 EXPECT_EQ(1, table.NumOccupied());
94 Validate(table);
95 EXPECT_EQ(-1, table.FindKey("a"));
96 EXPECT_EQ(b_entry, table.FindKey("b"));
97 intptr_t c_entry = -1;
98 EXPECT(!table.FindKeyOrDeletedOrUnused("c", &c_entry));
99 String& c = String::Handle(String::New("c"));
100 table.InsertKey(c_entry, c);
101 EXPECT_EQ(2, table.NumOccupied());
102 Validate(table);
103 EXPECT_EQ(c_entry, table.FindKey("c"));
104 table.Release();
105 }
106
107
108 TEST_CASE(EnumIndexHashMap) {
109 typedef EnumIndexHashMap<TestTraits> Table;
110 Table table(Array::Handle(HashTables::New<Table>(5)));
111 table.UpdateOrInsert(String::Handle(String::New("a")),
112 String::Handle(String::New("A")));
113 EXPECT(table.ContainsKey("a"));
114 EXPECT(table.ContainsKey(std::string("a")));
115 table.UpdateValue("a", String::Handle(String::New("AAA")));
116 String& a_value = String::Handle();
117 a_value ^= table.GetOrNull("a");
118 EXPECT(a_value.Equals("AAA"));
119 Object& null_value = Object::Handle(table.GetOrNull("0"));
120 EXPECT(null_value.IsNull());
121 table.Release();
122 }
123
124
125 std::string ToStdString(const String& str) {
126 EXPECT(str.IsOneByteString());
127 std::string result;
128 for (intptr_t i = 0; i < str.Length(); ++i) {
129 result += static_cast<char>(str.CharAt(i));
130 }
131 return result;
132 }
133
134
135 // Checks that 'expected' and 'actual' are equal sets. If 'ordered' is true,
136 // it also verifies that their iteration orders match, i.e., that actual's
137 // insertion order coincides with lexicographic order.
138 template<typename Set>
139 void VerifyStringSetsEqual(const std::set<std::string>& expected,
140 const Set& actual,
141 bool ordered) {
142 // Get actual keys in iteration order.
143 Array& keys = Array::Handle(HashTables::ToArray(actual, true));
144 // Cardinality must match.
145 EXPECT_EQ(static_cast<intptr_t>(expected.size()), keys.Length());
146 std::vector<std::string> expected_vec(expected.begin(), expected.end());
147 // Check containment.
148 for (uintptr_t i = 0; i < expected_vec.size(); ++i) {
149 EXPECT(actual.ContainsKey(expected_vec[i]));
150 }
151 // Equality, including order, if requested.
152 std::vector<std::string> actual_vec;
153 String& key = String::Handle();
154 for (int i = 0; i < keys.Length(); ++i) {
155 key ^= keys.At(i);
156 actual_vec.push_back(ToStdString(key));
157 }
158 if (!ordered) {
159 std::sort(actual_vec.begin(), actual_vec.end());
160 }
161 EXPECT(std::equal(actual_vec.begin(), actual_vec.end(),
162 expected_vec.begin()));
163 }
164
165
166 // Checks that 'expected' and 'actual' are equal maps. If 'ordered' is true,
167 // it also verifies that their iteration orders match, i.e., that actual's
168 // insertion order coincides with lexicographic order.
169 template<typename Map>
170 void VerifyStringMapsEqual(const std::map<std::string, int>& expected,
171 const Map& actual,
172 bool ordered) {
173 intptr_t expected_size = expected.size();
174 // Get actual concatenated (key, value) pairs in iteration order.
175 Array& entries = Array::Handle(HashTables::ToArray(actual, true));
176 // Cardinality must match.
177 EXPECT_EQ(expected_size * 2, entries.Length());
178 std::vector<std::pair<std::string, int> > expected_vec(expected.begin(),
179 expected.end());
180 // Check containment.
181 Smi& value = Smi::Handle();
182 for (uintptr_t i = 0; i < expected_vec.size(); ++i) {
183 std::string key = expected_vec[i].first;
184 EXPECT(actual.ContainsKey(key));
185 value ^= actual.GetOrNull(key);
186 EXPECT_EQ(expected_vec[i].second, value.Value());
187 }
188 if (!ordered) {
189 return;
190 }
191 // Equality including order.
192 std::vector<std::string> actual_vec;
193 String& key = String::Handle();
194 for (int i = 0; i < expected_size; ++i) {
195 key ^= entries.At(2 * i);
196 value ^= entries.At(2 * i + 1);
197 EXPECT(expected_vec[i].first == ToStdString(key));
198 EXPECT_EQ(expected_vec[i].second, value.Value());
199 }
200 }
201
202
203 template<typename Set>
204 void TestSet(intptr_t initial_capacity, bool ordered) {
205 std::set<std::string> expected;
206 Set actual(Array::Handle(HashTables::New<Set>(initial_capacity)));
207 // Insert the following strings twice:
208 // aaa...aaa (length 26)
209 // bbb..bbb
210 // ...
211 // yy
212 // z
213 for (int i = 0; i < 2; ++i) {
214 for (char ch = 'a'; ch <= 'z'; ++ch) {
215 std::string key('z' - ch + 1, ch);
216 expected.insert(key);
217 bool present = actual.Insert(String::Handle(String::New(key.c_str())));
218 EXPECT_EQ((i != 0), present);
219 Validate(actual);
220 VerifyStringSetsEqual(expected, actual, ordered);
221 }
222 }
223 while (!expected.empty()) {
224 actual.Remove(*expected.begin());
225 Validate(actual);
226 expected.erase(expected.begin());
227 VerifyStringSetsEqual(expected, actual, ordered);
228 }
229 actual.Release();
230 }
231
232
233 template<typename Map>
234 void TestMap(intptr_t initial_capacity, bool ordered) {
235 std::map<std::string, int> expected;
236 Map actual(Array::Handle(HashTables::New<Map>(initial_capacity)));
237 // Insert the following (strings, int) mapping:
238 // aaa...aaa -> 26
239 // bbb..bbb -> 25
240 // ...
241 // yy -> 2
242 // z -> 1
243 for (int i = 0; i < 2; ++i) {
244 for (char ch = 'a'; ch <= 'z'; ++ch) {
245 int length = 'z' - ch + 1;
246 std::string key(length, ch);
247 // Map everything to zero initially, then update to their final values.
248 int value = length * i;
249 expected[key] = value;
250 bool present =
251 actual.UpdateOrInsert(String::Handle(String::New(key.c_str())),
252 Smi::Handle(Smi::New(value)));
253 EXPECT_EQ((i != 0), present);
254 Validate(actual);
255 VerifyStringMapsEqual(expected, actual, ordered);
256 }
257 }
258 while (!expected.empty()) {
259 actual.Remove(expected.begin()->first);
260 Validate(actual);
261 expected.erase(expected.begin());
262 VerifyStringMapsEqual(expected, actual, ordered);
263 }
264 actual.Release();
265 }
266
267
268 TEST_CASE(Sets) {
269 for (intptr_t initial_capacity = 0;
270 initial_capacity < 32;
271 ++initial_capacity) {
272 TestSet<UnorderedHashSet<TestTraits> >(initial_capacity, false);
273 TestSet<EnumIndexHashSet<TestTraits> >(initial_capacity, true);
274 }
275 }
276
277
278 TEST_CASE(Maps) {
279 for (intptr_t initial_capacity = 0;
280 initial_capacity < 32;
281 ++initial_capacity) {
282 TestMap<UnorderedHashMap<TestTraits> >(initial_capacity, false);
283 TestMap<EnumIndexHashMap<TestTraits> >(initial_capacity, true);
284 }
285 }
286
287 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698