1 | /* |
2 | * Copyright (C) 2014 Apple Inc. All rights reserved. |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions |
6 | * are met: |
7 | * 1. Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. |
9 | * 2. Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. |
12 | * |
13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
14 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
15 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
18 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
19 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
20 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
21 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
22 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
23 | * THE POSSIBILITY OF SUCH DAMAGE. |
24 | */ |
25 | |
26 | #pragma once |
27 | |
28 | #if ENABLE(INDEXED_DATABASE) |
29 | |
30 | #include "IDBKey.h" |
31 | #include <wtf/StdSet.h> |
32 | #include <wtf/Variant.h> |
33 | #include <wtf/text/StringHash.h> |
34 | |
35 | namespace WebCore { |
36 | |
37 | class KeyedDecoder; |
38 | class KeyedEncoder; |
39 | |
40 | class IDBKeyData { |
41 | WTF_MAKE_FAST_ALLOCATED; |
42 | public: |
43 | IDBKeyData() |
44 | : m_type(IndexedDB::KeyType::Invalid) |
45 | , m_isNull(true) |
46 | { |
47 | } |
48 | |
49 | WEBCORE_EXPORT IDBKeyData(const IDBKey*); |
50 | |
51 | enum IsolatedCopyTag { IsolatedCopy }; |
52 | IDBKeyData(const IDBKeyData&, IsolatedCopyTag); |
53 | |
54 | static IDBKeyData minimum() |
55 | { |
56 | IDBKeyData result; |
57 | result.m_type = IndexedDB::KeyType::Min; |
58 | result.m_isNull = false; |
59 | return result; |
60 | } |
61 | |
62 | static IDBKeyData maximum() |
63 | { |
64 | IDBKeyData result; |
65 | result.m_type = IndexedDB::KeyType::Max; |
66 | result.m_isNull = false; |
67 | return result; |
68 | } |
69 | |
70 | WEBCORE_EXPORT RefPtr<IDBKey> maybeCreateIDBKey() const; |
71 | |
72 | IDBKeyData isolatedCopy() const; |
73 | |
74 | WEBCORE_EXPORT void encode(KeyedEncoder&) const; |
75 | WEBCORE_EXPORT static bool decode(KeyedDecoder&, IDBKeyData&); |
76 | |
77 | // compare() has the same semantics as strcmp(). |
78 | // - Returns negative if this IDBKeyData is less than other. |
79 | // - Returns positive if this IDBKeyData is greater than other. |
80 | // - Returns zero if this IDBKeyData is equal to other. |
81 | WEBCORE_EXPORT int compare(const IDBKeyData& other) const; |
82 | |
83 | void setArrayValue(const Vector<IDBKeyData>&); |
84 | void setBinaryValue(const ThreadSafeDataBuffer&); |
85 | void setStringValue(const String&); |
86 | void setDateValue(double); |
87 | WEBCORE_EXPORT void setNumberValue(double); |
88 | |
89 | template<class Encoder> void encode(Encoder&) const; |
90 | template<class Decoder> static Optional<IDBKeyData> decode(Decoder&); |
91 | |
92 | #if !LOG_DISABLED |
93 | WEBCORE_EXPORT String loggingString() const; |
94 | #endif |
95 | |
96 | bool isNull() const { return m_isNull; } |
97 | bool isValid() const; |
98 | IndexedDB::KeyType type() const { return m_type; } |
99 | |
100 | bool operator<(const IDBKeyData&) const; |
101 | bool operator>(const IDBKeyData& other) const |
102 | { |
103 | return !(*this < other) && !(*this == other); |
104 | } |
105 | |
106 | bool operator<=(const IDBKeyData& other) const |
107 | { |
108 | return !(*this > other); |
109 | } |
110 | |
111 | bool operator>=(const IDBKeyData& other) const |
112 | { |
113 | return !(*this < other); |
114 | } |
115 | |
116 | bool operator==(const IDBKeyData& other) const; |
117 | bool operator!=(const IDBKeyData& other) const |
118 | { |
119 | return !(*this == other); |
120 | } |
121 | |
122 | unsigned hash() const |
123 | { |
124 | Vector<unsigned> hashCodes; |
125 | hashCodes.append(static_cast<unsigned>(m_type)); |
126 | hashCodes.append(m_isNull ? 1 : 0); |
127 | hashCodes.append(m_isDeletedValue ? 1 : 0); |
128 | switch (m_type) { |
129 | case IndexedDB::KeyType::Invalid: |
130 | case IndexedDB::KeyType::Max: |
131 | case IndexedDB::KeyType::Min: |
132 | break; |
133 | case IndexedDB::KeyType::Number: |
134 | case IndexedDB::KeyType::Date: |
135 | hashCodes.append(StringHasher::hashMemory<sizeof(double)>(&WTF::get<double>(m_value))); |
136 | break; |
137 | case IndexedDB::KeyType::String: |
138 | hashCodes.append(StringHash::hash(WTF::get<String>(m_value))); |
139 | break; |
140 | case IndexedDB::KeyType::Binary: { |
141 | auto* data = WTF::get<ThreadSafeDataBuffer>(m_value).data(); |
142 | if (!data) |
143 | hashCodes.append(0); |
144 | else |
145 | hashCodes.append(StringHasher::hashMemory(data->data(), data->size())); |
146 | break; |
147 | } |
148 | case IndexedDB::KeyType::Array: |
149 | for (auto& key : WTF::get<Vector<IDBKeyData>>(m_value)) |
150 | hashCodes.append(key.hash()); |
151 | break; |
152 | } |
153 | |
154 | return StringHasher::hashMemory(hashCodes.data(), hashCodes.size() * sizeof(unsigned)); |
155 | } |
156 | |
157 | static IDBKeyData deletedValue(); |
158 | bool isDeletedValue() const { return m_isDeletedValue; } |
159 | |
160 | String string() const |
161 | { |
162 | ASSERT(m_type == IndexedDB::KeyType::String); |
163 | return WTF::get<String>(m_value); |
164 | } |
165 | |
166 | double date() const |
167 | { |
168 | ASSERT(m_type == IndexedDB::KeyType::Date); |
169 | return WTF::get<double>(m_value); |
170 | } |
171 | |
172 | double number() const |
173 | { |
174 | ASSERT(m_type == IndexedDB::KeyType::Number); |
175 | return WTF::get<double>(m_value); |
176 | } |
177 | |
178 | const ThreadSafeDataBuffer& binary() const |
179 | { |
180 | ASSERT(m_type == IndexedDB::KeyType::Binary); |
181 | return WTF::get<ThreadSafeDataBuffer>(m_value); |
182 | } |
183 | |
184 | const Vector<IDBKeyData>& array() const |
185 | { |
186 | ASSERT(m_type == IndexedDB::KeyType::Array); |
187 | return WTF::get<Vector<IDBKeyData>>(m_value); |
188 | } |
189 | |
190 | private: |
191 | static void isolatedCopy(const IDBKeyData& source, IDBKeyData& destination); |
192 | |
193 | IndexedDB::KeyType m_type; |
194 | Variant<Vector<IDBKeyData>, String, double, ThreadSafeDataBuffer> m_value; |
195 | |
196 | bool m_isNull { false }; |
197 | bool m_isDeletedValue { false }; |
198 | }; |
199 | |
200 | struct IDBKeyDataHash { |
201 | static unsigned hash(const IDBKeyData& a) { return a.hash(); } |
202 | static bool equal(const IDBKeyData& a, const IDBKeyData& b) { return a == b; } |
203 | static const bool safeToCompareToEmptyOrDeleted = false; |
204 | }; |
205 | |
206 | struct IDBKeyDataHashTraits : public WTF::CustomHashTraits<IDBKeyData> { |
207 | static const bool emptyValueIsZero = false; |
208 | static const bool hasIsEmptyValueFunction = true; |
209 | |
210 | static void constructDeletedValue(IDBKeyData& key) |
211 | { |
212 | new (&key) IDBKeyData; |
213 | key = IDBKeyData::deletedValue(); |
214 | } |
215 | |
216 | static bool isDeletedValue(const IDBKeyData& key) |
217 | { |
218 | return key.isDeletedValue(); |
219 | } |
220 | |
221 | static IDBKeyData emptyValue() |
222 | { |
223 | return IDBKeyData(); |
224 | } |
225 | |
226 | static bool isEmptyValue(const IDBKeyData& key) |
227 | { |
228 | return key.isNull(); |
229 | } |
230 | }; |
231 | |
232 | template<class Encoder> |
233 | void IDBKeyData::encode(Encoder& encoder) const |
234 | { |
235 | encoder << m_isNull; |
236 | if (m_isNull) |
237 | return; |
238 | |
239 | encoder.encodeEnum(m_type); |
240 | |
241 | switch (m_type) { |
242 | case IndexedDB::KeyType::Invalid: |
243 | case IndexedDB::KeyType::Max: |
244 | case IndexedDB::KeyType::Min: |
245 | break; |
246 | case IndexedDB::KeyType::Array: |
247 | encoder << WTF::get<Vector<IDBKeyData>>(m_value); |
248 | break; |
249 | case IndexedDB::KeyType::Binary: |
250 | encoder << WTF::get<ThreadSafeDataBuffer>(m_value); |
251 | break; |
252 | case IndexedDB::KeyType::String: |
253 | encoder << WTF::get<String>(m_value); |
254 | break; |
255 | case IndexedDB::KeyType::Date: |
256 | case IndexedDB::KeyType::Number: |
257 | encoder << WTF::get<double>(m_value); |
258 | break; |
259 | } |
260 | } |
261 | |
262 | template<class Decoder> |
263 | Optional<IDBKeyData> IDBKeyData::decode(Decoder& decoder) |
264 | { |
265 | IDBKeyData keyData; |
266 | if (!decoder.decode(keyData.m_isNull)) |
267 | return WTF::nullopt; |
268 | |
269 | if (keyData.m_isNull) |
270 | return keyData; |
271 | |
272 | if (!decoder.decodeEnum(keyData.m_type)) |
273 | return WTF::nullopt; |
274 | |
275 | switch (keyData.m_type) { |
276 | case IndexedDB::KeyType::Invalid: |
277 | case IndexedDB::KeyType::Max: |
278 | case IndexedDB::KeyType::Min: |
279 | break; |
280 | case IndexedDB::KeyType::Array: |
281 | keyData.m_value = Vector<IDBKeyData>(); |
282 | if (!decoder.decode(WTF::get<Vector<IDBKeyData>>(keyData.m_value))) |
283 | return WTF::nullopt; |
284 | break; |
285 | case IndexedDB::KeyType::Binary: |
286 | keyData.m_value = ThreadSafeDataBuffer(); |
287 | if (!decoder.decode(WTF::get<ThreadSafeDataBuffer>(keyData.m_value))) |
288 | return WTF::nullopt; |
289 | break; |
290 | case IndexedDB::KeyType::String: |
291 | keyData.m_value = String(); |
292 | if (!decoder.decode(WTF::get<String>(keyData.m_value))) |
293 | return WTF::nullopt; |
294 | break; |
295 | case IndexedDB::KeyType::Date: |
296 | case IndexedDB::KeyType::Number: |
297 | keyData.m_value = 0.0; |
298 | if (!decoder.decode(WTF::get<double>(keyData.m_value))) |
299 | return WTF::nullopt; |
300 | break; |
301 | } |
302 | |
303 | return keyData; |
304 | } |
305 | |
306 | using IDBKeyDataSet = StdSet<IDBKeyData>; |
307 | |
308 | } // namespace WebCore |
309 | |
310 | #endif // ENABLE(INDEXED_DATABASE) |
311 | |