Skip to content

Commit b9d2709

Browse files
sstricklcommit-bot@chromium.org
authored andcommitted
---
yaml --- r: 191337 b: refs/heads/beta c: 7c6cab9 h: refs/heads/master i: 191335: 6d94b68
1 parent 5fa53bb commit b9d2709

File tree

3 files changed

+104
-1
lines changed

3 files changed

+104
-1
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -911,7 +911,7 @@ refs/tags/2.3.0-flutter-1.5.4-hotfix.1: a1668566e563aef64025d0af88a099cbbe847b7e
911911
refs/tags/2.3.1: 929b013ddc83a013b49a98fc28b6b503a972bddd
912912
refs/tags/2.3.1-dev.0.0: 1d1742efd39cd4762b844b510acf8c2f1fa6604e
913913
refs/tags/2.3.2-dev.0.0: c567183bac8a895014d79cd3bf1d8908d45547d6
914-
refs/heads/beta: e7614adedbd30727b2aab0f3af0d7d3ec7ea56bb
914+
refs/heads/beta: 7c6cab995a1bf955992cde62adeb440a4e38e19e
915915
refs/heads/sjindel.mep: b113b36c157cf54b257e82550e9bbde16f05ad8d
916916
refs/tags/2.3.2: f7ab96133aa79301daf812ef40b33c99d8ad1495
917917
refs/tags/2.3.2-dev.0.1: ef57e27c9798b54a54e9a1f74b1bd1f9be7290b1

branches/beta/runtime/vm/hash_map.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,15 @@ class BaseDirectChainedHashMap : public B {
3939
void Insert(typename KeyValueTrait::Pair kv);
4040
bool Remove(typename KeyValueTrait::Key key);
4141

42+
// If a pair already exists in the map with an equal key, replace that pair
43+
// with this one. Otherwise, insert the pair as a new entry.
44+
//
45+
// Note: Insert operates in constant time, while Update must walk the chained
46+
// entries for a given hash value, checking keys for equality. However, if
47+
// multiple value updates are needed for the same key, only using Update
48+
// guarantees constant space usage whereas Insert does not.
49+
void Update(typename KeyValueTrait::Pair kv);
50+
4251
typename KeyValueTrait::Value LookupValue(
4352
typename KeyValueTrait::Key key) const;
4453

@@ -314,6 +323,20 @@ void BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>::Insert(
314323
}
315324
}
316325

326+
template <typename KeyValueTrait, typename B, typename Allocator>
327+
void BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>::Update(
328+
typename KeyValueTrait::Pair kv) {
329+
const typename KeyValueTrait::Value kNoValue =
330+
KeyValueTrait::ValueOf(typename KeyValueTrait::Pair());
331+
332+
ASSERT(KeyValueTrait::ValueOf(kv) != kNoValue);
333+
if (auto const old_kv = Lookup(KeyValueTrait::KeyOf(kv))) {
334+
*old_kv = kv;
335+
} else {
336+
Insert(kv);
337+
}
338+
}
339+
317340
template <typename KeyValueTrait, typename B, typename Allocator>
318341
bool BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>::Remove(
319342
typename KeyValueTrait::Key key) {

branches/beta/runtime/vm/hash_map_test.cc

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,4 +220,84 @@ TEST_CASE(CStringMap) {
220220
free(str1);
221221
}
222222

223+
TEST_CASE(CStringMapUpdate) {
224+
const char* const kConst1 = "test";
225+
const char* const kConst2 = "test 2";
226+
227+
char* str1 = OS::SCreate(nullptr, "%s", kConst1);
228+
char* str2 = OS::SCreate(nullptr, "%s", kConst2);
229+
char* str3 = OS::SCreate(nullptr, "%s", kConst1);
230+
char* str4 = OS::SCreate(nullptr, "%s", kConst1); // Only used for lookup.
231+
232+
// Make sure these strings are pointer-distinct, but C-string-equal.
233+
EXPECT_NE(str1, str3);
234+
EXPECT_NE(str1, str4);
235+
EXPECT_NE(str3, str4);
236+
EXPECT_STREQ(str1, str3);
237+
EXPECT_STREQ(str1, str4);
238+
239+
CStringKeyValueTrait<intptr_t>::Pair p1 = {str1, 1};
240+
CStringKeyValueTrait<intptr_t>::Pair p2 = {str2, 2};
241+
CStringKeyValueTrait<intptr_t>::Pair p3 = {str3, 3};
242+
243+
CStringMap<intptr_t> map;
244+
EXPECT(map.IsEmpty());
245+
246+
map.Update(p1);
247+
EXPECT_NOTNULL(map.Lookup(str1));
248+
EXPECT_EQ(p1.value, map.LookupValue(str1));
249+
EXPECT_NULLPTR(map.Lookup(str2));
250+
EXPECT_NOTNULL(map.Lookup(str3));
251+
EXPECT_EQ(p1.value, map.LookupValue(str3));
252+
EXPECT_NOTNULL(map.Lookup(str4));
253+
EXPECT_EQ(p1.value, map.LookupValue(str4));
254+
255+
map.Update(p2);
256+
EXPECT_NOTNULL(map.Lookup(str1));
257+
EXPECT_EQ(p1.value, map.LookupValue(str1));
258+
EXPECT_NOTNULL(map.Lookup(str2));
259+
EXPECT_EQ(p2.value, map.LookupValue(str2));
260+
EXPECT_NOTNULL(map.Lookup(str3));
261+
EXPECT_EQ(p1.value, map.LookupValue(str3));
262+
EXPECT_NOTNULL(map.Lookup(str4));
263+
EXPECT_EQ(p1.value, map.LookupValue(str4));
264+
265+
// Check Lookup after Update.
266+
map.Update(p3);
267+
EXPECT_NOTNULL(map.Lookup(str1));
268+
EXPECT_EQ(p3.value, map.LookupValue(str1));
269+
EXPECT_NOTNULL(map.Lookup(str2));
270+
EXPECT_EQ(p2.value, map.LookupValue(str2));
271+
EXPECT_NOTNULL(map.Lookup(str3));
272+
EXPECT_EQ(p3.value, map.LookupValue(str3));
273+
EXPECT_NOTNULL(map.Lookup(str4));
274+
EXPECT_EQ(p3.value, map.LookupValue(str4));
275+
276+
// Check that single Remove after only Updates ensures Lookup fails after.
277+
EXPECT(map.Remove(str3));
278+
EXPECT_NULLPTR(map.Lookup(str1));
279+
EXPECT_NOTNULL(map.Lookup(str2));
280+
EXPECT_EQ(p2.value, map.LookupValue(str2));
281+
EXPECT_NULLPTR(map.Lookup(str3));
282+
EXPECT_NULLPTR(map.Lookup(str4));
283+
284+
EXPECT(!map.Remove(str3));
285+
EXPECT(map.Remove(str2));
286+
EXPECT(map.IsEmpty());
287+
288+
// Quick double-check that these weren't side-effected by the implementation
289+
// of hash maps (p1 especially).
290+
EXPECT_EQ(str1, p1.key);
291+
EXPECT_EQ(1, p1.value);
292+
EXPECT_EQ(str2, p2.key);
293+
EXPECT_EQ(2, p2.value);
294+
EXPECT_EQ(str3, p3.key);
295+
EXPECT_EQ(3, p3.value);
296+
297+
free(str4);
298+
free(str3);
299+
free(str2);
300+
free(str1);
301+
}
302+
223303
} // namespace dart

0 commit comments

Comments
 (0)