Bug 1528152 [wpt PR 15381] - Quirks: move vertical-align-in-quirks.html to historical...
[gecko.git] / storage / Variant.h
blobe9a0a85746a7aec0aaa23e652d9bc35e7d3eb7ef
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_storage_Variant_h__
8 #define mozilla_storage_Variant_h__
10 #include <utility>
12 #include "nsIVariant.h"
13 #include "nsMemory.h"
14 #include "nsString.h"
15 #include "nsTArray.h"
17 #define VARIANT_BASE_IID \
18 { /* 78888042-0fa3-4f7a-8b19-7996f99bf1aa */ \
19 0x78888042, 0x0fa3, 0x4f7a, { \
20 0x8b, 0x19, 0x79, 0x96, 0xf9, 0x9b, 0xf1, 0xaa \
21 } \
24 /**
25 * This class is used by the storage module whenever an nsIVariant needs to be
26 * returned. We provide traits for the basic sqlite types to make use easier.
27 * The following types map to the indicated sqlite type:
28 * int64_t -> INTEGER (use IntegerVariant)
29 * double -> FLOAT (use FloatVariant)
30 * nsString -> TEXT (use TextVariant)
31 * nsCString -> TEXT (use UTF8TextVariant)
32 * uint8_t[] -> BLOB (use BlobVariant)
33 * nullptr -> NULL (use NullVariant)
35 * The kvstore component also reuses this class as a common implementation
36 * of a simple threadsafe variant for the storage of primitive values only.
37 * The BooleanVariant type has been introduced for kvstore use cases and should
38 * be enhanced to provide full boolean variant support for mozStorage.
40 * Bug 1494102 tracks that work.
43 namespace mozilla {
44 namespace storage {
46 ////////////////////////////////////////////////////////////////////////////////
47 //// Base Class
49 class Variant_base : public nsIVariant {
50 public:
51 NS_DECL_THREADSAFE_ISUPPORTS
52 NS_DECL_NSIVARIANT
53 NS_DECLARE_STATIC_IID_ACCESSOR(VARIANT_BASE_IID)
55 protected:
56 virtual ~Variant_base() {}
59 NS_DEFINE_STATIC_IID_ACCESSOR(Variant_base, VARIANT_BASE_IID)
61 ////////////////////////////////////////////////////////////////////////////////
62 //// Traits
64 /**
65 * Generics
68 template <typename DataType>
69 struct variant_traits {
70 static inline uint16_t type() { return nsIDataType::VTYPE_EMPTY; }
73 template <typename DataType, bool Adopting = false>
74 struct variant_storage_traits {
75 typedef DataType ConstructorType;
76 typedef DataType StorageType;
77 static inline void storage_conversion(const ConstructorType aData,
78 StorageType *_storage) {
79 *_storage = aData;
82 static inline void destroy(const StorageType &_storage) {}
85 #define NO_CONVERSION return NS_ERROR_CANNOT_CONVERT_DATA;
87 template <typename DataType, bool Adopting = false>
88 struct variant_boolean_traits {
89 typedef typename variant_storage_traits<DataType, Adopting>::StorageType
90 StorageType;
91 static inline nsresult asBool(const StorageType &, bool *) { NO_CONVERSION }
94 template <typename DataType, bool Adopting = false>
95 struct variant_integer_traits {
96 typedef typename variant_storage_traits<DataType, Adopting>::StorageType
97 StorageType;
98 static inline nsresult asInt32(const StorageType &, int32_t *) {
99 NO_CONVERSION
101 static inline nsresult asInt64(const StorageType &, int64_t *) {
102 NO_CONVERSION
106 template <typename DataType, bool Adopting = false>
107 struct variant_float_traits {
108 typedef typename variant_storage_traits<DataType, Adopting>::StorageType
109 StorageType;
110 static inline nsresult asDouble(const StorageType &, double *) {
111 NO_CONVERSION
115 template <typename DataType, bool Adopting = false>
116 struct variant_text_traits {
117 typedef typename variant_storage_traits<DataType, Adopting>::StorageType
118 StorageType;
119 static inline nsresult asUTF8String(const StorageType &, nsACString &) {
120 NO_CONVERSION
122 static inline nsresult asString(const StorageType &, nsAString &) {
123 NO_CONVERSION
127 template <typename DataType, bool Adopting = false>
128 struct variant_blob_traits {
129 typedef typename variant_storage_traits<DataType, Adopting>::StorageType
130 StorageType;
131 static inline nsresult asArray(const StorageType &, uint16_t *, uint32_t *,
132 void **) {
133 NO_CONVERSION
137 #undef NO_CONVERSION
140 * BOOLEAN type
143 template <>
144 struct variant_traits<bool> {
145 static inline uint16_t type() { return nsIDataType::VTYPE_BOOL; }
147 template <>
148 struct variant_boolean_traits<bool> {
149 static inline nsresult asBool(bool aValue, bool *_result) {
150 *_result = aValue;
151 return NS_OK;
154 // NB: It might be worth also providing conversions to int types.
156 // NB: It'd be nice to implement asBool conversions for 0 and 1, too.
157 // That would let us clean up some conversions in Places, such as:
158 // https://searchfox.org/mozilla-central/rev/0640ea80fbc8d48f8b197cd363e2535c95a15eb3/toolkit/components/places/SQLFunctions.cpp#564-565
159 // https://searchfox.org/mozilla-central/rev/0640ea80fbc8d48f8b197cd363e2535c95a15eb3/toolkit/components/places/SQLFunctions.cpp#1057
160 // https://searchfox.org/mozilla-central/rev/0640ea80fbc8d48f8b197cd363e2535c95a15eb3/toolkit/components/places/nsNavHistory.cpp#3189
164 * INTEGER types
167 template <>
168 struct variant_traits<int64_t> {
169 static inline uint16_t type() { return nsIDataType::VTYPE_INT64; }
171 template <>
172 struct variant_integer_traits<int64_t> {
173 static inline nsresult asInt32(int64_t aValue, int32_t *_result) {
174 if (aValue > INT32_MAX || aValue < INT32_MIN)
175 return NS_ERROR_CANNOT_CONVERT_DATA;
177 *_result = static_cast<int32_t>(aValue);
178 return NS_OK;
180 static inline nsresult asInt64(int64_t aValue, int64_t *_result) {
181 *_result = aValue;
182 return NS_OK;
185 // xpcvariant just calls get double for integers...
186 template <>
187 struct variant_float_traits<int64_t> {
188 static inline nsresult asDouble(int64_t aValue, double *_result) {
189 *_result = double(aValue);
190 return NS_OK;
195 * FLOAT types
198 template <>
199 struct variant_traits<double> {
200 static inline uint16_t type() { return nsIDataType::VTYPE_DOUBLE; }
202 template <>
203 struct variant_float_traits<double> {
204 static inline nsresult asDouble(double aValue, double *_result) {
205 *_result = aValue;
206 return NS_OK;
211 * TEXT types
214 template <>
215 struct variant_traits<nsString> {
216 static inline uint16_t type() { return nsIDataType::VTYPE_ASTRING; }
218 template <>
219 struct variant_storage_traits<nsString> {
220 typedef const nsAString &ConstructorType;
221 typedef nsString StorageType;
222 static inline void storage_conversion(ConstructorType aText,
223 StorageType *_outData) {
224 *_outData = aText;
226 static inline void destroy(const StorageType &_outData) {}
228 template <>
229 struct variant_text_traits<nsString> {
230 static inline nsresult asUTF8String(const nsString &aValue,
231 nsACString &_result) {
232 CopyUTF16toUTF8(aValue, _result);
233 return NS_OK;
235 static inline nsresult asString(const nsString &aValue, nsAString &_result) {
236 _result = aValue;
237 return NS_OK;
241 template <>
242 struct variant_traits<nsCString> {
243 static inline uint16_t type() { return nsIDataType::VTYPE_UTF8STRING; }
245 template <>
246 struct variant_storage_traits<nsCString> {
247 typedef const nsACString &ConstructorType;
248 typedef nsCString StorageType;
249 static inline void storage_conversion(ConstructorType aText,
250 StorageType *_outData) {
251 *_outData = aText;
253 static inline void destroy(const StorageType &aData) {}
255 template <>
256 struct variant_text_traits<nsCString> {
257 static inline nsresult asUTF8String(const nsCString &aValue,
258 nsACString &_result) {
259 _result = aValue;
260 return NS_OK;
262 static inline nsresult asString(const nsCString &aValue, nsAString &_result) {
263 CopyUTF8toUTF16(aValue, _result);
264 return NS_OK;
269 * BLOB types
272 template <>
273 struct variant_traits<uint8_t[]> {
274 static inline uint16_t type() { return nsIDataType::VTYPE_ARRAY; }
276 template <>
277 struct variant_storage_traits<uint8_t[], false> {
278 typedef std::pair<const void *, int> ConstructorType;
279 typedef FallibleTArray<uint8_t> StorageType;
280 static inline void storage_conversion(ConstructorType aBlob,
281 StorageType *_outData) {
282 _outData->Clear();
283 (void)_outData->AppendElements(static_cast<const uint8_t *>(aBlob.first),
284 aBlob.second, fallible);
286 static inline void destroy(const StorageType &_outData) {}
288 template <>
289 struct variant_storage_traits<uint8_t[], true> {
290 typedef std::pair<uint8_t *, int> ConstructorType;
291 typedef std::pair<uint8_t *, int> StorageType;
292 static inline void storage_conversion(ConstructorType aBlob,
293 StorageType *_outData) {
294 *_outData = aBlob;
296 static inline void destroy(StorageType &aData) {
297 if (aData.first) {
298 free(aData.first);
299 aData.first = nullptr;
303 template <>
304 struct variant_blob_traits<uint8_t[], false> {
305 static inline nsresult asArray(FallibleTArray<uint8_t> &aData,
306 uint16_t *_type, uint32_t *_size,
307 void **_result) {
308 // For empty blobs, we return nullptr.
309 if (aData.Length() == 0) {
310 *_result = nullptr;
311 *_type = nsIDataType::VTYPE_UINT8;
312 *_size = 0;
313 return NS_OK;
316 // Otherwise, we copy the array.
317 *_result = moz_xmemdup(aData.Elements(), aData.Length() * sizeof(uint8_t));
319 // Set type and size
320 *_type = nsIDataType::VTYPE_UINT8;
321 *_size = aData.Length();
322 return NS_OK;
326 template <>
327 struct variant_blob_traits<uint8_t[], true> {
328 static inline nsresult asArray(std::pair<uint8_t *, int> &aData,
329 uint16_t *_type, uint32_t *_size,
330 void **_result) {
331 // For empty blobs, we return nullptr.
332 if (aData.second == 0) {
333 *_result = nullptr;
334 *_type = nsIDataType::VTYPE_UINT8;
335 *_size = 0;
336 return NS_OK;
339 // Otherwise, transfer the data out.
340 *_result = aData.first;
341 aData.first = nullptr;
342 MOZ_ASSERT(*_result); // We asked for it twice, better not use adopting!
344 // Set type and size
345 *_type = nsIDataType::VTYPE_UINT8;
346 *_size = aData.second;
347 return NS_OK;
352 * nullptr type
355 class NullVariant : public Variant_base {
356 public:
357 uint16_t GetDataType() override { return nsIDataType::VTYPE_EMPTY; }
359 NS_IMETHOD GetAsAUTF8String(nsACString &_str) override {
360 // Return a void string.
361 _str.SetIsVoid(true);
362 return NS_OK;
365 NS_IMETHOD GetAsAString(nsAString &_str) override {
366 // Return a void string.
367 _str.SetIsVoid(true);
368 return NS_OK;
372 ////////////////////////////////////////////////////////////////////////////////
373 //// Template Implementation
375 template <typename DataType, bool Adopting = false>
376 class Variant final : public Variant_base {
377 ~Variant() { variant_storage_traits<DataType, Adopting>::destroy(mData); }
379 public:
380 explicit Variant(
381 const typename variant_storage_traits<DataType, Adopting>::ConstructorType
382 aData) {
383 variant_storage_traits<DataType, Adopting>::storage_conversion(aData,
384 &mData);
387 uint16_t GetDataType() override { return variant_traits<DataType>::type(); }
389 NS_IMETHOD GetAsBool(bool *_boolean) override {
390 return variant_boolean_traits<DataType, Adopting>::asBool(mData, _boolean);
393 NS_IMETHOD GetAsInt32(int32_t *_integer) override {
394 return variant_integer_traits<DataType, Adopting>::asInt32(mData, _integer);
397 NS_IMETHOD GetAsInt64(int64_t *_integer) override {
398 return variant_integer_traits<DataType, Adopting>::asInt64(mData, _integer);
401 NS_IMETHOD GetAsDouble(double *_double) override {
402 return variant_float_traits<DataType, Adopting>::asDouble(mData, _double);
405 NS_IMETHOD GetAsAUTF8String(nsACString &_str) override {
406 return variant_text_traits<DataType, Adopting>::asUTF8String(mData, _str);
409 NS_IMETHOD GetAsAString(nsAString &_str) override {
410 return variant_text_traits<DataType, Adopting>::asString(mData, _str);
413 NS_IMETHOD GetAsArray(uint16_t *_type, nsIID *, uint32_t *_size,
414 void **_data) override {
415 return variant_blob_traits<DataType, Adopting>::asArray(mData, _type, _size,
416 _data);
419 private:
420 typename variant_storage_traits<DataType, Adopting>::StorageType mData;
423 ////////////////////////////////////////////////////////////////////////////////
424 //// Handy typedefs! Use these for the right mapping.
426 // Currently, BooleanVariant is only useful for kvstore.
427 // Bug 1494102 tracks implementing full boolean variant support for mozStorage.
428 typedef Variant<bool> BooleanVariant;
430 typedef Variant<int64_t> IntegerVariant;
431 typedef Variant<double> FloatVariant;
432 typedef Variant<nsString> TextVariant;
433 typedef Variant<nsCString> UTF8TextVariant;
434 typedef Variant<uint8_t[], false> BlobVariant;
435 typedef Variant<uint8_t[], true> AdoptedBlobVariant;
437 } // namespace storage
438 } // namespace mozilla
440 #include "Variant_inl.h"
442 #endif // mozilla_storage_Variant_h__