Avoid copy-prone idiom "for (auto item : collection)"
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / IDBKeyData.cpp
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 #include "config.h"
27 #include "IDBKeyData.h"
28
29 #if ENABLE(INDEXED_DATABASE)
30
31 #include "KeyedCoding.h"
32
33 namespace WebCore {
34
35 IDBKeyData::IDBKeyData(const IDBKey* key)
36     : type(IDBKey::InvalidType)
37     , numberValue(0)
38     , isNull(false)
39 {
40     if (!key) {
41         isNull = true;
42         return;
43     }
44
45     type = key->type();
46     numberValue = 0;
47
48     switch (type) {
49     case IDBKey::InvalidType:
50         break;
51     case IDBKey::ArrayType:
52         for (auto& key2 : key->array())
53             arrayValue.append(IDBKeyData(key2.get()));
54         break;
55     case IDBKey::StringType:
56         stringValue = key->string();
57         break;
58     case IDBKey::DateType:
59         numberValue = key->date();
60         break;
61     case IDBKey::NumberType:
62         numberValue = key->number();
63         break;
64     case IDBKey::MaxType:
65     case IDBKey::MinType:
66         break;
67     }
68 }
69
70 PassRefPtr<IDBKey> IDBKeyData::maybeCreateIDBKey() const
71 {
72     if (isNull)
73         return nullptr;
74
75     switch (type) {
76     case IDBKey::InvalidType:
77         return IDBKey::createInvalid();
78     case IDBKey::ArrayType:
79         {
80             IDBKey::KeyArray array;
81             for (auto& keyData : arrayValue) {
82                 array.append(keyData.maybeCreateIDBKey());
83                 ASSERT(array.last());
84             }
85             return IDBKey::createArray(array);
86         }
87     case IDBKey::StringType:
88         return IDBKey::createString(stringValue);
89     case IDBKey::DateType:
90         return IDBKey::createDate(numberValue);
91     case IDBKey::NumberType:
92         return IDBKey::createNumber(numberValue);
93     case IDBKey::MaxType:
94     case IDBKey::MinType:
95         ASSERT_NOT_REACHED();
96         return nullptr;
97     }
98
99     ASSERT_NOT_REACHED();
100     return nullptr;
101 }
102
103 IDBKeyData IDBKeyData::isolatedCopy() const
104 {
105     IDBKeyData result;
106     result.type = type;
107     result.isNull = isNull;
108
109     switch (type) {
110     case IDBKey::InvalidType:
111         return result;
112     case IDBKey::ArrayType:
113         for (auto& key : arrayValue)
114             result.arrayValue.append(key.isolatedCopy());
115         return result;
116     case IDBKey::StringType:
117         result.stringValue = stringValue.isolatedCopy();
118         return result;
119     case IDBKey::DateType:
120     case IDBKey::NumberType:
121         result.numberValue = numberValue;
122         return result;
123     case IDBKey::MaxType:
124     case IDBKey::MinType:
125         return result;
126     }
127
128     ASSERT_NOT_REACHED();
129     return result;
130 }
131
132 void IDBKeyData::encode(KeyedEncoder& encoder) const
133 {
134     encoder.encodeBool("null", isNull);
135     if (isNull)
136         return;
137
138     encoder.encodeEnum("type", type);
139
140     switch (type) {
141     case IDBKey::InvalidType:
142         return;
143     case IDBKey::ArrayType:
144         encoder.encodeObjects("array", arrayValue.begin(), arrayValue.end(), [](KeyedEncoder& encoder, const IDBKeyData& key) {
145             key.encode(encoder);
146         });
147         return;
148     case IDBKey::StringType:
149         encoder.encodeString("string", stringValue);
150         return;
151     case IDBKey::DateType:
152     case IDBKey::NumberType:
153         encoder.encodeDouble("number", numberValue);
154         return;
155     case IDBKey::MaxType:
156     case IDBKey::MinType:
157         return;
158     }
159
160     ASSERT_NOT_REACHED();
161 }
162
163 bool IDBKeyData::decode(KeyedDecoder& decoder, IDBKeyData& result)
164 {
165     if (!decoder.decodeBool("null", result.isNull))
166         return false;
167
168     if (result.isNull)
169         return true;
170
171     auto enumFunction = [](int64_t value) {
172         return value == IDBKey::MaxType
173             || value == IDBKey::InvalidType
174             || value == IDBKey::ArrayType
175             || value == IDBKey::StringType
176             || value == IDBKey::DateType
177             || value == IDBKey::NumberType
178             || value == IDBKey::MinType;
179     };
180     if (!decoder.decodeVerifiedEnum("type", result.type, enumFunction))
181         return false;
182
183     if (result.type == IDBKey::InvalidType)
184         return true;
185
186     if (result.type == IDBKey::MaxType)
187         return true;
188
189     if (result.type == IDBKey::MinType)
190         return true;
191
192     if (result.type == IDBKey::StringType)
193         return decoder.decodeString("string", result.stringValue);
194
195     if (result.type == IDBKey::NumberType || result.type == IDBKey::DateType)
196         return decoder.decodeDouble("number", result.numberValue);
197
198     ASSERT(result.type == IDBKey::ArrayType);
199
200     auto arrayFunction = [](KeyedDecoder& decoder, IDBKeyData& result) {
201         return decode(decoder, result);
202     };
203     return decoder.decodeObjects("array", result.arrayValue, arrayFunction);
204 }
205
206 int IDBKeyData::compare(const IDBKeyData& other) const
207 {
208     if (type == IDBKey::InvalidType) {
209         if (other.type != IDBKey::InvalidType)
210             return -1;
211         if (other.type == IDBKey::InvalidType)
212             return 0;
213     } else if (other.type == IDBKey::InvalidType)
214         return 1;
215
216     // The IDBKey::Type enum is in reverse sort order.
217     if (type != other.type)
218         return type < other.type ? 1 : -1;
219
220     // The types are the same, so handle actual value comparison.
221     switch (type) {
222     case IDBKey::InvalidType:
223         // InvalidType should have been fully handled above
224         ASSERT_NOT_REACHED();
225         return 0;
226     case IDBKey::ArrayType:
227         for (size_t i = 0; i < arrayValue.size() && i < other.arrayValue.size(); ++i) {
228             if (int result = arrayValue[i].compare(other.arrayValue[i]))
229                 return result;
230         }
231         if (arrayValue.size() < other.arrayValue.size())
232             return -1;
233         if (arrayValue.size() > other.arrayValue.size())
234             return 1;
235         return 0;
236     case IDBKey::StringType:
237         return codePointCompare(stringValue, other.stringValue);
238     case IDBKey::DateType:
239     case IDBKey::NumberType:
240         if (numberValue == other.numberValue)
241             return 0;
242         return numberValue > other.numberValue ? 1 : -1;
243     case IDBKey::MaxType:
244     case IDBKey::MinType:
245         return 0;
246     }
247
248     ASSERT_NOT_REACHED();
249     return 0;
250 }
251
252 #ifndef NDEBUG
253 String IDBKeyData::loggingString() const
254 {
255     if (isNull)
256         return "<null>";
257
258     switch (type) {
259     case IDBKey::InvalidType:
260         return "<invalid>";
261     case IDBKey::ArrayType:
262         {
263             String result = "<array> - { ";
264             for (size_t i = 0; i < arrayValue.size(); ++i) {
265                 result.append(arrayValue[i].loggingString());
266                 if (i < arrayValue.size() - 1)
267                     result.append(", ");
268             }
269             result.append(" }");
270             return result;
271         }
272     case IDBKey::StringType:
273         return String("<string> - ") + stringValue;
274     case IDBKey::DateType:
275         return String::format("Date type - %f", numberValue);
276     case IDBKey::NumberType:
277         return String::format("<number> - %f", numberValue);
278     case IDBKey::MaxType:
279         return "<maximum>";
280     case IDBKey::MinType:
281         return "<minimum>";
282     default:
283         return String();
284     }
285     ASSERT_NOT_REACHED();
286 }
287 #endif
288
289 void IDBKeyData::setArrayValue(const Vector<IDBKeyData>& value)
290 {
291     *this = IDBKeyData();
292     arrayValue = value;
293     type = IDBKey::ArrayType;
294     isNull = false;
295 }
296
297 void IDBKeyData::setStringValue(const String& value)
298 {
299     *this = IDBKeyData();
300     stringValue = value;
301     type = IDBKey::StringType;
302     isNull = false;
303 }
304
305 void IDBKeyData::setDateValue(double value)
306 {
307     *this = IDBKeyData();
308     numberValue = value;
309     type = IDBKey::DateType;
310     isNull = false;
311 }
312
313 void IDBKeyData::setNumberValue(double value)
314 {
315     *this = IDBKeyData();
316     numberValue = value;
317     type = IDBKey::NumberType;
318     isNull = false;
319 }
320
321 }
322
323 #endif // ENABLE(INDEXED_DATABASE)