| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "third_party/blink/public/common/indexeddb/indexeddb_key.h" |
| |
| #include <sstream> |
| #include <string> |
| #include <utility> |
| |
| namespace blink { |
| |
| namespace { |
| std::string string_to_hex(const std::string& input) { |
| static const char* const lut = "0123456789ABCDEF"; |
| size_t len = input.length(); |
| |
| std::string output; |
| output.reserve(2 * len); |
| for (size_t i = 0; i < len; ++i) { |
| const unsigned char c = input[i]; |
| output.push_back(lut[c >> 4]); |
| output.push_back(lut[c & 0xFF]); |
| } |
| return output; |
| } |
| |
| // Very rough estimate of minimum key size overhead. |
| const size_t kOverheadSize = 16; |
| |
| size_t CalculateArraySize(const IndexedDBKey::KeyArray& keys) { |
| size_t size(0); |
| for (const auto& key : keys) |
| size += key.size_estimate(); |
| return size; |
| } |
| |
| template <typename T> |
| int Compare(const T& a, const T& b) { |
| // Using '<' for both comparisons here is as generic as possible (for e.g. |
| // objects which only define operator<() and not operator>() or operator==()) |
| // and also allows e.g. floating point NaNs to compare equal. |
| if (a < b) |
| return -1; |
| return (b < a) ? 1 : 0; |
| } |
| |
| } // namespace |
| |
| IndexedDBKey::IndexedDBKey() |
| : type_(mojom::IDBKeyType::None), size_estimate_(kOverheadSize) {} |
| |
| IndexedDBKey::IndexedDBKey(mojom::IDBKeyType type) |
| : type_(type), size_estimate_(kOverheadSize) { |
| DCHECK(type == mojom::IDBKeyType::None || |
| type == mojom::IDBKeyType::Invalid || type == mojom::IDBKeyType::Min); |
| } |
| |
| IndexedDBKey::IndexedDBKey(double number, mojom::IDBKeyType type) |
| : type_(type), |
| number_(number), |
| size_estimate_(kOverheadSize + sizeof(number)) { |
| DCHECK(type == blink::mojom::IDBKeyType::Number || |
| type == blink::mojom::IDBKeyType::Date); |
| } |
| |
| IndexedDBKey::IndexedDBKey(KeyArray array) |
| : type_(blink::mojom::IDBKeyType::Array), |
| array_(std::move(array)), |
| size_estimate_(kOverheadSize + CalculateArraySize(array_)) {} |
| |
| IndexedDBKey::IndexedDBKey(std::string binary) |
| : type_(blink::mojom::IDBKeyType::Binary), |
| binary_(std::move(binary)), |
| size_estimate_(kOverheadSize + |
| (binary_.length() * sizeof(std::string::value_type))) {} |
| |
| IndexedDBKey::IndexedDBKey(base::string16 string) |
| : type_(mojom::IDBKeyType::String), |
| string_(std::move(string)), |
| size_estimate_(kOverheadSize + |
| (string_.length() * sizeof(base::string16::value_type))) {} |
| |
| IndexedDBKey::IndexedDBKey(const IndexedDBKey& other) = default; |
| IndexedDBKey::~IndexedDBKey() = default; |
| IndexedDBKey& IndexedDBKey::operator=(const IndexedDBKey& other) = default; |
| |
| bool IndexedDBKey::IsValid() const { |
| if (type_ == mojom::IDBKeyType::Invalid || type_ == mojom::IDBKeyType::None) |
| return false; |
| |
| if (type_ == blink::mojom::IDBKeyType::Array) { |
| for (size_t i = 0; i < array_.size(); i++) { |
| if (!array_[i].IsValid()) |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| bool IndexedDBKey::IsLessThan(const IndexedDBKey& other) const { |
| return CompareTo(other) < 0; |
| } |
| |
| bool IndexedDBKey::Equals(const IndexedDBKey& other) const { |
| return !CompareTo(other); |
| } |
| |
| bool IndexedDBKey::HasHoles() const { |
| if (type_ != mojom::IDBKeyType::Array) |
| return false; |
| |
| for (const auto& subkey : array_) { |
| if (subkey.type() == mojom::IDBKeyType::None) |
| return true; |
| } |
| return false; |
| } |
| |
| IndexedDBKey IndexedDBKey::FillHoles(const IndexedDBKey& primary_key) const { |
| if (type_ != mojom::IDBKeyType::Array) |
| return IndexedDBKey(*this); |
| |
| std::vector<IndexedDBKey> subkeys; |
| subkeys.reserve(array_.size()); |
| for (const auto& subkey : array_) { |
| if (subkey.type() == mojom::IDBKeyType::None) { |
| subkeys.push_back(primary_key); |
| } else { |
| // "Holes" can only exist at the top level of an array key, as (1) they |
| // are produced by an index's array keypath when a member matches the |
| // store's keypath, and (2) array keypaths are flat (no |
| // arrays-of-arrays). |
| DCHECK(!subkey.HasHoles()); |
| subkeys.push_back(subkey); |
| } |
| } |
| return IndexedDBKey(subkeys); |
| } |
| |
| std::string IndexedDBKey::DebugString() const { |
| std::stringstream result; |
| result << "IDBKey{"; |
| switch (type_) { |
| case mojom::IDBKeyType::Array: { |
| result << "array: ["; |
| for (size_t i = 0; i < array_.size(); ++i) { |
| result << array_[i].DebugString(); |
| if (i != array_.size() - 1) |
| result << ", "; |
| } |
| result << "]"; |
| break; |
| } |
| case mojom::IDBKeyType::Binary: |
| result << "binary: 0x" << string_to_hex(binary_); |
| break; |
| case mojom::IDBKeyType::String: |
| result << "string: " << string_; |
| break; |
| case mojom::IDBKeyType::Date: |
| result << "date: " << number_; |
| break; |
| case mojom::IDBKeyType::Number: |
| result << "number: " << number_; |
| break; |
| case mojom::IDBKeyType::Invalid: |
| result << "Invalid"; |
| break; |
| case mojom::IDBKeyType::None: |
| result << "None"; |
| break; |
| case mojom::IDBKeyType::Min: |
| result << "Min"; |
| break; |
| default: |
| result << "InvalidKey"; |
| } |
| result << "}"; |
| return result.str(); |
| } |
| |
| int IndexedDBKey::CompareTo(const IndexedDBKey& other) const { |
| DCHECK(IsValid()); |
| DCHECK(other.IsValid()); |
| if (type_ != other.type_) |
| return type_ > other.type_ ? -1 : 1; |
| |
| switch (type_) { |
| case mojom::IDBKeyType::Array: |
| for (size_t i = 0; i < array_.size() && i < other.array_.size(); ++i) { |
| int result = array_[i].CompareTo(other.array_[i]); |
| if (result != 0) |
| return result; |
| } |
| return Compare(array_.size(), other.array_.size()); |
| case mojom::IDBKeyType::Binary: |
| return binary_.compare(other.binary_); |
| case mojom::IDBKeyType::String: |
| return string_.compare(other.string_); |
| case mojom::IDBKeyType::Date: |
| case mojom::IDBKeyType::Number: |
| return Compare(number_, other.number_); |
| case mojom::IDBKeyType::Invalid: |
| case mojom::IDBKeyType::None: |
| case mojom::IDBKeyType::Min: |
| default: |
| NOTREACHED(); |
| return 0; |
| } |
| } |
| |
| } // namespace blink |