Backed out changeset d94f12d0e000 (bug 1850948) for causing memory related assertion...
[gecko.git] / storage / Variant.h
blob420ca94b94cf2e1f4fce1252d5d8c66b9be434bc
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 "nsString.h"
14 #include "nsTArray.h"
16 #define VARIANT_BASE_IID \
17 { /* 78888042-0fa3-4f7a-8b19-7996f99bf1aa */ \
18 0x78888042, 0x0fa3, 0x4f7a, { \
19 0x8b, 0x19, 0x79, 0x96, 0xf9, 0x9b, 0xf1, 0xaa \
20 } \
23 /**
24 * This class is used by the storage module whenever an nsIVariant needs to be
25 * returned. We provide traits for the basic sqlite types to make use easier.
26 * The following types map to the indicated sqlite type:
27 * int64_t -> INTEGER (use IntegerVariant)
28 * double -> FLOAT (use FloatVariant)
29 * nsString -> TEXT (use TextVariant)
30 * nsCString -> TEXT (use UTF8TextVariant)
31 * uint8_t[] -> BLOB (use BlobVariant)
32 * nullptr -> NULL (use NullVariant)
34 * The kvstore component also reuses this class as a common implementation
35 * of a simple threadsafe variant for the storage of primitive values only.
36 * The BooleanVariant type has been introduced for kvstore use cases and should
37 * be enhanced to provide full boolean variant support for mozStorage.
39 * Bug 1494102 tracks that work.
42 namespace mozilla {
43 namespace storage {
45 ////////////////////////////////////////////////////////////////////////////////
46 //// Base Class
48 class Variant_base : public nsIVariant {
49 public:
50 NS_DECL_THREADSAFE_ISUPPORTS
51 NS_DECL_NSIVARIANT
52 NS_DECLARE_STATIC_IID_ACCESSOR(VARIANT_BASE_IID)
54 protected:
55 virtual ~Variant_base() = default;
58 NS_DEFINE_STATIC_IID_ACCESSOR(Variant_base, VARIANT_BASE_IID)
60 ////////////////////////////////////////////////////////////////////////////////
61 //// Traits
63 /**
64 * Generics
67 template <typename DataType>
68 struct variant_traits {
69 static inline uint16_t type() { return nsIDataType::VTYPE_EMPTY; }
72 template <typename DataType, bool Adopting = false>
73 struct variant_storage_traits {
74 typedef DataType ConstructorType;
75 typedef DataType StorageType;
76 static inline void storage_conversion(const ConstructorType aData,
77 StorageType* _storage) {
78 *_storage = aData;
81 static inline void destroy(const StorageType& _storage) {}
84 #define NO_CONVERSION return NS_ERROR_CANNOT_CONVERT_DATA;
86 template <typename DataType, bool Adopting = false>
87 struct variant_boolean_traits {
88 typedef typename variant_storage_traits<DataType, Adopting>::StorageType
89 StorageType;
90 static inline nsresult asBool(const StorageType&, bool*) { NO_CONVERSION }
93 template <typename DataType, bool Adopting = false>
94 struct variant_integer_traits {
95 typedef typename variant_storage_traits<DataType, Adopting>::StorageType
96 StorageType;
97 static inline nsresult asInt32(const StorageType&, int32_t*) { NO_CONVERSION }
98 static inline nsresult asInt64(const StorageType&, int64_t*) { NO_CONVERSION }
101 template <typename DataType, bool Adopting = false>
102 struct variant_float_traits {
103 typedef typename variant_storage_traits<DataType, Adopting>::StorageType
104 StorageType;
105 static inline nsresult asDouble(const StorageType&, double*) { NO_CONVERSION }
108 template <typename DataType, bool Adopting = false>
109 struct variant_text_traits {
110 typedef typename variant_storage_traits<DataType, Adopting>::StorageType
111 StorageType;
112 static inline nsresult asUTF8String(const StorageType&, nsACString&) {
113 NO_CONVERSION
115 static inline nsresult asString(const StorageType&, nsAString&) {
116 NO_CONVERSION
120 template <typename DataType, bool Adopting = false>
121 struct variant_blob_traits {
122 typedef typename variant_storage_traits<DataType, Adopting>::StorageType
123 StorageType;
124 static inline nsresult asArray(const StorageType&, uint16_t*, uint32_t*,
125 void**) {
126 NO_CONVERSION
130 #undef NO_CONVERSION
133 * BOOLEAN type
136 template <>
137 struct variant_traits<bool> {
138 static inline uint16_t type() { return nsIDataType::VTYPE_BOOL; }
140 template <>
141 struct variant_boolean_traits<bool> {
142 static inline nsresult asBool(bool aValue, bool* _result) {
143 *_result = aValue;
144 return NS_OK;
147 // NB: It might be worth also providing conversions to int types.
149 // NB: It'd be nice to implement asBool conversions for 0 and 1, too.
150 // That would let us clean up some conversions in Places, such as:
151 // https://searchfox.org/mozilla-central/rev/0640ea80fbc8d48f8b197cd363e2535c95a15eb3/toolkit/components/places/SQLFunctions.cpp#564-565
152 // https://searchfox.org/mozilla-central/rev/0640ea80fbc8d48f8b197cd363e2535c95a15eb3/toolkit/components/places/SQLFunctions.cpp#1057
153 // https://searchfox.org/mozilla-central/rev/0640ea80fbc8d48f8b197cd363e2535c95a15eb3/toolkit/components/places/nsNavHistory.cpp#3189
157 * INTEGER types
160 template <>
161 struct variant_traits<int64_t> {
162 static inline uint16_t type() { return nsIDataType::VTYPE_INT64; }
164 template <>
165 struct variant_integer_traits<int64_t> {
166 static inline nsresult asInt32(int64_t aValue, int32_t* _result) {
167 if (aValue > INT32_MAX || aValue < INT32_MIN)
168 return NS_ERROR_CANNOT_CONVERT_DATA;
170 *_result = static_cast<int32_t>(aValue);
171 return NS_OK;
173 static inline nsresult asInt64(int64_t aValue, int64_t* _result) {
174 *_result = aValue;
175 return NS_OK;
178 // xpcvariant just calls get double for integers...
179 template <>
180 struct variant_float_traits<int64_t> {
181 static inline nsresult asDouble(int64_t aValue, double* _result) {
182 *_result = double(aValue);
183 return NS_OK;
188 * FLOAT types
191 template <>
192 struct variant_traits<double> {
193 static inline uint16_t type() { return nsIDataType::VTYPE_DOUBLE; }
195 template <>
196 struct variant_float_traits<double> {
197 static inline nsresult asDouble(double aValue, double* _result) {
198 *_result = aValue;
199 return NS_OK;
204 * TEXT types
207 template <>
208 struct variant_traits<nsString> {
209 static inline uint16_t type() { return nsIDataType::VTYPE_ASTRING; }
211 template <>
212 struct variant_storage_traits<nsString> {
213 typedef const nsAString& ConstructorType;
214 typedef nsString StorageType;
215 static inline void storage_conversion(ConstructorType aText,
216 StorageType* _outData) {
217 *_outData = aText;
219 static inline void destroy(const StorageType& _outData) {}
221 template <>
222 struct variant_text_traits<nsString> {
223 static inline nsresult asUTF8String(const nsString& aValue,
224 nsACString& _result) {
225 CopyUTF16toUTF8(aValue, _result);
226 return NS_OK;
228 static inline nsresult asString(const nsString& aValue, nsAString& _result) {
229 _result = aValue;
230 return NS_OK;
234 template <>
235 struct variant_traits<nsCString> {
236 static inline uint16_t type() { return nsIDataType::VTYPE_UTF8STRING; }
238 template <>
239 struct variant_storage_traits<nsCString> {
240 typedef const nsACString& ConstructorType;
241 typedef nsCString StorageType;
242 static inline void storage_conversion(ConstructorType aText,
243 StorageType* _outData) {
244 *_outData = aText;
246 static inline void destroy(const StorageType& aData) {}
248 template <>
249 struct variant_text_traits<nsCString> {
250 static inline nsresult asUTF8String(const nsCString& aValue,
251 nsACString& _result) {
252 _result = aValue;
253 return NS_OK;
255 static inline nsresult asString(const nsCString& aValue, nsAString& _result) {
256 CopyUTF8toUTF16(aValue, _result);
257 return NS_OK;
262 * BLOB types
265 template <>
266 struct variant_traits<uint8_t[]> {
267 static inline uint16_t type() { return nsIDataType::VTYPE_ARRAY; }
269 template <>
270 struct variant_storage_traits<uint8_t[], false> {
271 typedef std::pair<const void*, int> ConstructorType;
272 typedef FallibleTArray<uint8_t> StorageType;
273 static inline void storage_conversion(ConstructorType aBlob,
274 StorageType* _outData) {
275 _outData->Clear();
276 (void)_outData->AppendElements(static_cast<const uint8_t*>(aBlob.first),
277 aBlob.second, fallible);
279 static inline void destroy(const StorageType& _outData) {}
281 template <>
282 struct variant_storage_traits<uint8_t[], true> {
283 typedef std::pair<uint8_t*, int> ConstructorType;
284 typedef std::pair<uint8_t*, int> StorageType;
285 static inline void storage_conversion(ConstructorType aBlob,
286 StorageType* _outData) {
287 *_outData = aBlob;
289 static inline void destroy(StorageType& aData) {
290 if (aData.first) {
291 free(aData.first);
292 aData.first = nullptr;
296 template <>
297 struct variant_blob_traits<uint8_t[], false> {
298 static inline nsresult asArray(FallibleTArray<uint8_t>& aData,
299 uint16_t* _type, uint32_t* _size,
300 void** _result) {
301 // For empty blobs, we return nullptr.
302 if (aData.Length() == 0) {
303 *_result = nullptr;
304 *_type = nsIDataType::VTYPE_UINT8;
305 *_size = 0;
306 return NS_OK;
309 // Otherwise, we copy the array.
310 *_result = moz_xmemdup(aData.Elements(), aData.Length() * sizeof(uint8_t));
312 // Set type and size
313 *_type = nsIDataType::VTYPE_UINT8;
314 *_size = aData.Length();
315 return NS_OK;
319 template <>
320 struct variant_blob_traits<uint8_t[], true> {
321 static inline nsresult asArray(std::pair<uint8_t*, int>& aData,
322 uint16_t* _type, uint32_t* _size,
323 void** _result) {
324 // For empty blobs, we return nullptr.
325 if (aData.second == 0) {
326 *_result = nullptr;
327 *_type = nsIDataType::VTYPE_UINT8;
328 *_size = 0;
329 return NS_OK;
332 // Otherwise, transfer the data out.
333 *_result = aData.first;
334 aData.first = nullptr;
335 MOZ_ASSERT(*_result); // We asked for it twice, better not use adopting!
337 // Set type and size
338 *_type = nsIDataType::VTYPE_UINT8;
339 *_size = aData.second;
340 return NS_OK;
345 * nullptr type
348 class NullVariant : public Variant_base {
349 public:
350 uint16_t GetDataType() override { return nsIDataType::VTYPE_EMPTY; }
352 NS_IMETHOD GetAsAUTF8String(nsACString& _str) override {
353 // Return a void string.
354 _str.SetIsVoid(true);
355 return NS_OK;
358 NS_IMETHOD GetAsAString(nsAString& _str) override {
359 // Return a void string.
360 _str.SetIsVoid(true);
361 return NS_OK;
365 ////////////////////////////////////////////////////////////////////////////////
366 //// Template Implementation
368 template <typename DataType, bool Adopting = false>
369 class Variant final : public Variant_base {
370 ~Variant() { variant_storage_traits<DataType, Adopting>::destroy(mData); }
372 public:
373 explicit Variant(
374 const typename variant_storage_traits<DataType, Adopting>::ConstructorType
375 aData) {
376 variant_storage_traits<DataType, Adopting>::storage_conversion(aData,
377 &mData);
380 uint16_t GetDataType() override { return variant_traits<DataType>::type(); }
382 NS_IMETHOD GetAsBool(bool* _boolean) override {
383 return variant_boolean_traits<DataType, Adopting>::asBool(mData, _boolean);
386 NS_IMETHOD GetAsInt32(int32_t* _integer) override {
387 return variant_integer_traits<DataType, Adopting>::asInt32(mData, _integer);
390 NS_IMETHOD GetAsInt64(int64_t* _integer) override {
391 return variant_integer_traits<DataType, Adopting>::asInt64(mData, _integer);
394 NS_IMETHOD GetAsDouble(double* _double) override {
395 return variant_float_traits<DataType, Adopting>::asDouble(mData, _double);
398 NS_IMETHOD GetAsAUTF8String(nsACString& _str) override {
399 return variant_text_traits<DataType, Adopting>::asUTF8String(mData, _str);
402 NS_IMETHOD GetAsAString(nsAString& _str) override {
403 return variant_text_traits<DataType, Adopting>::asString(mData, _str);
406 NS_IMETHOD GetAsArray(uint16_t* _type, nsIID*, uint32_t* _size,
407 void** _data) override {
408 return variant_blob_traits<DataType, Adopting>::asArray(mData, _type, _size,
409 _data);
412 private:
413 typename variant_storage_traits<DataType, Adopting>::StorageType mData;
416 ////////////////////////////////////////////////////////////////////////////////
417 //// Handy typedefs! Use these for the right mapping.
419 // Currently, BooleanVariant is only useful for kvstore.
420 // Bug 1494102 tracks implementing full boolean variant support for mozStorage.
421 typedef Variant<bool> BooleanVariant;
423 typedef Variant<int64_t> IntegerVariant;
424 typedef Variant<double> FloatVariant;
425 typedef Variant<nsString> TextVariant;
426 typedef Variant<nsCString> UTF8TextVariant;
427 typedef Variant<uint8_t[], false> BlobVariant;
428 typedef Variant<uint8_t[], true> AdoptedBlobVariant;
430 } // namespace storage
431 } // namespace mozilla
433 #include "Variant_inl.h"
435 #endif // mozilla_storage_Variant_h__