Commit dad9b950 authored by Marijn Kruisselbrink's avatar Marijn Kruisselbrink Committed by Commit Bot

[DOMStorage] Add reverse iteration optimization to blink::StorageAreaMap.

This makes the performance of blink::StorageAreaMap closer to that of
content::DOMStorageMap. In particular this makes any kind of reverse
iteration over a storage area less inefficient (not sure why people
would do so though).

Bug: 781870
Change-Id: I6f313c65868a21de8b0d2fbdff526a23895baa57
Reviewed-on: https://chromium-review.googlesource.com/1117206Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarDaniel Murphy <dmurph@chromium.org>
Commit-Queue: Marijn Kruisselbrink <mek@chromium.org>
Cr-Commit-Position: refs/heads/master@{#571017}
parent 46412e2b
......@@ -27,15 +27,30 @@ String StorageAreaMap::GetKey(unsigned index) const {
if (index >= GetLength())
return String();
// TODO(mek): Figure out if we can support backwards iteration somewhat
// efficiently as well.
if (last_key_index_ > index) {
ResetKeyIterator();
// Decide if we should leave |key_iterator_| alone, or reset to either the
// beginning or end of the map for shortest iteration distance.
const unsigned distance_to_current = index > last_key_index_
? index - last_key_index_
: last_key_index_ - index;
const unsigned distance_to_end = GetLength() - index;
if (index < distance_to_current && index < distance_to_end) {
// Distance from start is shortest, so reset iterator to begin.
last_key_index_ = 0;
key_iterator_ = keys_values_.begin();
} else if (distance_to_end < distance_to_current && distance_to_end < index) {
// Distance from end is shortest, so reset iterator to end.
last_key_index_ = GetLength();
key_iterator_ = keys_values_.end();
}
while (last_key_index_ != index) {
while (last_key_index_ < index) {
++key_iterator_;
++last_key_index_;
}
while (last_key_index_ > index) {
--key_iterator_;
--last_key_index_;
}
return key_iterator_->key;
}
......
......@@ -100,4 +100,33 @@ TEST(StorageAreaMapTest, EnforcesQuota) {
EXPECT_EQ(kValue, map.GetItem(kKey2));
}
TEST(StorageAreaMapTest, Iteration) {
const int kNumTestItems = 100;
const size_t kQuota = 102400; // 100K quota for this test.
StorageAreaMap map(kQuota);
// Fill the map with some data.
for (int i = 0; i < kNumTestItems; ++i)
EXPECT_TRUE(map.SetItem("key" + String::Number(i), "val", nullptr));
EXPECT_EQ(unsigned{kNumTestItems}, map.GetLength());
Vector<String> keys(kNumTestItems);
// Iterate over all keys.
for (int i = 0; i < kNumTestItems; ++i)
keys[i] = map.GetKey(i);
// Now iterate over some subsets, and make sure the right keys are returned.
for (int i = 5; i < 15; ++i)
EXPECT_EQ(keys[i], map.GetKey(i));
for (int i = kNumTestItems - 5; i >= kNumTestItems - 15; --i)
EXPECT_EQ(keys[i], map.GetKey(i));
for (int i = 20; i >= 10; --i)
EXPECT_EQ(keys[i], map.GetKey(i));
for (int i = 15; i < 20; ++i)
EXPECT_EQ(keys[i], map.GetKey(i));
for (int i = kNumTestItems - 1; i >= 0; --i)
EXPECT_EQ(keys[i], map.GetKey(i));
EXPECT_TRUE(map.GetKey(kNumTestItems).IsNull());
}
} // namespace blink
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment