1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
|
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/storage/storage_area_map.h"
namespace blink {
namespace {
// For quota purposes we count each character as 2 bytes.
size_t QuotaForString(const String& s) {
return s.length() * sizeof(UChar);
}
size_t MemoryForString(const String& s) {
return s.CharactersSizeInBytes();
}
} // namespace
StorageAreaMap::StorageAreaMap(size_t quota) : quota_(quota) {
ResetKeyIterator();
}
unsigned StorageAreaMap::GetLength() const {
return keys_values_.size();
}
String StorageAreaMap::GetKey(unsigned index) const {
if (index >= GetLength())
return String();
// 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) {
++key_iterator_;
++last_key_index_;
}
while (last_key_index_ > index) {
--key_iterator_;
--last_key_index_;
}
return key_iterator_->key;
}
String StorageAreaMap::GetItem(const String& key) const {
auto it = keys_values_.find(key);
if (it == keys_values_.end())
return String();
return it->value;
}
bool StorageAreaMap::SetItem(const String& key,
const String& value,
String* old_value) {
return SetItemInternal(key, value, old_value, true);
}
void StorageAreaMap::SetItemIgnoringQuota(const String& key,
const String& value) {
SetItemInternal(key, value, nullptr, false);
}
bool StorageAreaMap::RemoveItem(const String& key, String* old_value) {
const auto it = keys_values_.find(key);
if (it == keys_values_.end())
return false;
quota_used_ -= QuotaForString(key) + QuotaForString(it->value);
memory_used_ -= MemoryForString(key) + MemoryForString(it->value);
if (old_value)
*old_value = it->value;
keys_values_.erase(it);
ResetKeyIterator();
return true;
}
void StorageAreaMap::ResetKeyIterator() const {
key_iterator_ = keys_values_.begin();
last_key_index_ = 0;
}
bool StorageAreaMap::SetItemInternal(const String& key,
const String& value,
String* old_value,
bool check_quota) {
const auto it = keys_values_.find(key);
size_t old_item_size = 0;
size_t old_item_memory = 0;
if (it != keys_values_.end()) {
old_item_size = QuotaForString(key) + QuotaForString(it->value);
old_item_memory = MemoryForString(key) + MemoryForString(it->value);
if (old_value)
*old_value = it->value;
}
DCHECK_GE(quota_used_, old_item_size);
size_t new_item_size = QuotaForString(key) + QuotaForString(value);
size_t new_item_memory = MemoryForString(key) + MemoryForString(value);
size_t new_quota_used = quota_used_ - old_item_size + new_item_size;
size_t new_memory_used = memory_used_ - old_item_memory + new_item_memory;
// Only check quota if the size is increasing, this allows
// shrinking changes to pre-existing files that are over budget.
if (check_quota && new_item_size > old_item_size && new_quota_used > quota_)
return false;
keys_values_.Set(key, value);
ResetKeyIterator();
quota_used_ = new_quota_used;
memory_used_ = new_memory_used;
return true;
}
} // namespace blink
|