/* * Copyright (C) 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #pragma once #if ENABLE(INDEXED_DATABASE) #include "IDBKey.h" #include #include namespace WebCore { class KeyedDecoder; class KeyedEncoder; class IDBKeyData { public: IDBKeyData() : m_type(KeyType::Invalid) , m_isNull(true) { } WEBCORE_EXPORT IDBKeyData(const IDBKey*); enum IsolatedCopyTag { IsolatedCopy }; IDBKeyData(const IDBKeyData&, IsolatedCopyTag); static IDBKeyData minimum() { IDBKeyData result; result.m_type = KeyType::Min; result.m_isNull = false; return result; } static IDBKeyData maximum() { IDBKeyData result; result.m_type = KeyType::Max; result.m_isNull = false; return result; } WEBCORE_EXPORT RefPtr maybeCreateIDBKey() const; IDBKeyData isolatedCopy() const; WEBCORE_EXPORT void encode(KeyedEncoder&) const; WEBCORE_EXPORT static bool decode(KeyedDecoder&, IDBKeyData&); // compare() has the same semantics as strcmp(). // - Returns negative if this IDBKeyData is less than other. // - Returns positive if this IDBKeyData is greater than other. // - Returns zero if this IDBKeyData is equal to other. WEBCORE_EXPORT int compare(const IDBKeyData& other) const; void setArrayValue(const Vector&); void setBinaryValue(const ThreadSafeDataBuffer&); void setStringValue(const String&); void setDateValue(double); WEBCORE_EXPORT void setNumberValue(double); template void encode(Encoder&) const; template static bool decode(Decoder&, IDBKeyData&); #if !LOG_DISABLED WEBCORE_EXPORT String loggingString() const; #endif bool isNull() const { return m_isNull; } bool isValid() const { return m_type != KeyType::Invalid; } KeyType type() const { return m_type; } bool operator<(const IDBKeyData&) const; bool operator>(const IDBKeyData& other) const { return !(*this < other) && !(*this == other); } bool operator<=(const IDBKeyData& other) const { return !(*this > other); } bool operator>=(const IDBKeyData& other) const { return !(*this < other); } bool operator==(const IDBKeyData& other) const; bool operator!=(const IDBKeyData& other) const { return !(*this == other); } unsigned hash() const { Vector hashCodes; hashCodes.append(static_cast(m_type)); hashCodes.append(m_isNull ? 1 : 0); hashCodes.append(m_isDeletedValue ? 1 : 0); switch (m_type) { case KeyType::Invalid: case KeyType::Max: case KeyType::Min: break; case KeyType::Number: case KeyType::Date: hashCodes.append(StringHasher::hashMemory(&WTF::get(m_value))); break; case KeyType::String: hashCodes.append(StringHash::hash(WTF::get(m_value))); break; case KeyType::Binary: { auto* data = WTF::get(m_value).data(); if (!data) hashCodes.append(0); else hashCodes.append(StringHasher::hashMemory(data->data(), data->size())); break; } case KeyType::Array: for (auto& key : WTF::get>(m_value)) hashCodes.append(key.hash()); break; } return StringHasher::hashMemory(hashCodes.data(), hashCodes.size() * sizeof(unsigned)); } static IDBKeyData deletedValue(); bool isDeletedValue() const { return m_isDeletedValue; } String string() const { ASSERT(m_type == KeyType::String); return WTF::get(m_value); } double date() const { ASSERT(m_type == KeyType::Date); return WTF::get(m_value); } double number() const { ASSERT(m_type == KeyType::Number); return WTF::get(m_value); } const ThreadSafeDataBuffer& binary() const { ASSERT(m_type == KeyType::Binary); return WTF::get(m_value); } const Vector& array() const { ASSERT(m_type == KeyType::Array); return WTF::get>(m_value); } private: static void isolatedCopy(const IDBKeyData& source, IDBKeyData& destination); KeyType m_type; Variant, String, double, ThreadSafeDataBuffer> m_value; bool m_isNull { false }; bool m_isDeletedValue { false }; }; struct IDBKeyDataHash { static unsigned hash(const IDBKeyData& a) { return a.hash(); } static bool equal(const IDBKeyData& a, const IDBKeyData& b) { return a == b; } static const bool safeToCompareToEmptyOrDeleted = false; }; struct IDBKeyDataHashTraits : public WTF::CustomHashTraits { static const bool emptyValueIsZero = false; static const bool hasIsEmptyValueFunction = true; static void constructDeletedValue(IDBKeyData& key) { key = IDBKeyData::deletedValue(); } static bool isDeletedValue(const IDBKeyData& key) { return key.isDeletedValue(); } static IDBKeyData emptyValue() { return IDBKeyData(); } static bool isEmptyValue(const IDBKeyData& key) { return key.isNull(); } }; template void IDBKeyData::encode(Encoder& encoder) const { encoder << m_isNull; if (m_isNull) return; encoder.encodeEnum(m_type); switch (m_type) { case KeyType::Invalid: case KeyType::Max: case KeyType::Min: break; case KeyType::Array: encoder << WTF::get>(m_value); break; case KeyType::Binary: encoder << WTF::get(m_value); break; case KeyType::String: encoder << WTF::get(m_value); break; case KeyType::Date: case KeyType::Number: encoder << WTF::get(m_value); break; } } template bool IDBKeyData::decode(Decoder& decoder, IDBKeyData& keyData) { if (!decoder.decode(keyData.m_isNull)) return false; if (keyData.m_isNull) return true; if (!decoder.decodeEnum(keyData.m_type)) return false; switch (keyData.m_type) { case KeyType::Invalid: case KeyType::Max: case KeyType::Min: break; case KeyType::Array: keyData.m_value = Vector(); if (!decoder.decode(WTF::get>(keyData.m_value))) return false; break; case KeyType::Binary: keyData.m_value = ThreadSafeDataBuffer(); if (!decoder.decode(WTF::get(keyData.m_value))) return false; break; case KeyType::String: keyData.m_value = String(); if (!decoder.decode(WTF::get(keyData.m_value))) return false; break; case KeyType::Date: case KeyType::Number: keyData.m_value = 0.0; if (!decoder.decode(WTF::get(keyData.m_value))) return false; break; } return true; } } // namespace WebCore #endif // ENABLE(INDEXED_DATABASE)