1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/storage/src/Variant.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,439 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ : 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef mozilla_storage_Variant_h__ 1.11 +#define mozilla_storage_Variant_h__ 1.12 + 1.13 +#include <utility> 1.14 + 1.15 +#include "nsIVariant.h" 1.16 +#include "nsString.h" 1.17 +#include "nsTArray.h" 1.18 + 1.19 +/** 1.20 + * This class is used by the storage module whenever an nsIVariant needs to be 1.21 + * returned. We provide traits for the basic sqlite types to make use easier. 1.22 + * The following types map to the indicated sqlite type: 1.23 + * int64_t -> INTEGER (use IntegerVariant) 1.24 + * double -> FLOAT (use FloatVariant) 1.25 + * nsString -> TEXT (use TextVariant) 1.26 + * nsCString -> TEXT (use UTF8TextVariant) 1.27 + * uint8_t[] -> BLOB (use BlobVariant) 1.28 + * nullptr -> NULL (use NullVariant) 1.29 + */ 1.30 + 1.31 +namespace mozilla { 1.32 +namespace storage { 1.33 + 1.34 +//////////////////////////////////////////////////////////////////////////////// 1.35 +//// Base Class 1.36 + 1.37 +class Variant_base : public nsIVariant 1.38 +{ 1.39 +public: 1.40 + NS_DECL_THREADSAFE_ISUPPORTS 1.41 + NS_DECL_NSIVARIANT 1.42 + 1.43 +protected: 1.44 + virtual ~Variant_base() { } 1.45 +}; 1.46 + 1.47 +//////////////////////////////////////////////////////////////////////////////// 1.48 +//// Traits 1.49 + 1.50 +/** 1.51 + * Generics 1.52 + */ 1.53 + 1.54 +template <typename DataType> 1.55 +struct variant_traits 1.56 +{ 1.57 + static inline uint16_t type() { return nsIDataType::VTYPE_EMPTY; } 1.58 +}; 1.59 + 1.60 +template <typename DataType, bool Adopting=false> 1.61 +struct variant_storage_traits 1.62 +{ 1.63 + typedef DataType ConstructorType; 1.64 + typedef DataType StorageType; 1.65 + static inline void storage_conversion(const ConstructorType aData, StorageType* _storage) 1.66 + { 1.67 + *_storage = aData; 1.68 + } 1.69 + 1.70 + static inline void destroy(const StorageType& _storage) 1.71 + { } 1.72 +}; 1.73 + 1.74 +#define NO_CONVERSION return NS_ERROR_CANNOT_CONVERT_DATA; 1.75 + 1.76 +template <typename DataType, bool Adopting=false> 1.77 +struct variant_integer_traits 1.78 +{ 1.79 + typedef typename variant_storage_traits<DataType, Adopting>::StorageType StorageType; 1.80 + static inline nsresult asInt32(const StorageType &, int32_t *) { NO_CONVERSION } 1.81 + static inline nsresult asInt64(const StorageType &, int64_t *) { NO_CONVERSION } 1.82 +}; 1.83 + 1.84 +template <typename DataType, bool Adopting=false> 1.85 +struct variant_float_traits 1.86 +{ 1.87 + typedef typename variant_storage_traits<DataType, Adopting>::StorageType StorageType; 1.88 + static inline nsresult asDouble(const StorageType &, double *) { NO_CONVERSION } 1.89 +}; 1.90 + 1.91 +template <typename DataType, bool Adopting=false> 1.92 +struct variant_text_traits 1.93 +{ 1.94 + typedef typename variant_storage_traits<DataType, Adopting>::StorageType StorageType; 1.95 + static inline nsresult asUTF8String(const StorageType &, nsACString &) { NO_CONVERSION } 1.96 + static inline nsresult asString(const StorageType &, nsAString &) { NO_CONVERSION } 1.97 +}; 1.98 + 1.99 +template <typename DataType, bool Adopting=false> 1.100 +struct variant_blob_traits 1.101 +{ 1.102 + typedef typename variant_storage_traits<DataType, Adopting>::StorageType StorageType; 1.103 + static inline nsresult asArray(const StorageType &, uint16_t *, uint32_t *, void **) 1.104 + { NO_CONVERSION } 1.105 +}; 1.106 + 1.107 +#undef NO_CONVERSION 1.108 + 1.109 +/** 1.110 + * INTEGER types 1.111 + */ 1.112 + 1.113 +template < > 1.114 +struct variant_traits<int64_t> 1.115 +{ 1.116 + static inline uint16_t type() { return nsIDataType::VTYPE_INT64; } 1.117 +}; 1.118 +template < > 1.119 +struct variant_integer_traits<int64_t> 1.120 +{ 1.121 + static inline nsresult asInt32(int64_t aValue, 1.122 + int32_t *_result) 1.123 + { 1.124 + if (aValue > INT32_MAX || aValue < INT32_MIN) 1.125 + return NS_ERROR_CANNOT_CONVERT_DATA; 1.126 + 1.127 + *_result = static_cast<int32_t>(aValue); 1.128 + return NS_OK; 1.129 + } 1.130 + static inline nsresult asInt64(int64_t aValue, 1.131 + int64_t *_result) 1.132 + { 1.133 + *_result = aValue; 1.134 + return NS_OK; 1.135 + } 1.136 +}; 1.137 +// xpcvariant just calls get double for integers... 1.138 +template < > 1.139 +struct variant_float_traits<int64_t> 1.140 +{ 1.141 + static inline nsresult asDouble(int64_t aValue, 1.142 + double *_result) 1.143 + { 1.144 + *_result = double(aValue); 1.145 + return NS_OK; 1.146 + } 1.147 +}; 1.148 + 1.149 +/** 1.150 + * FLOAT types 1.151 + */ 1.152 + 1.153 +template < > 1.154 +struct variant_traits<double> 1.155 +{ 1.156 + static inline uint16_t type() { return nsIDataType::VTYPE_DOUBLE; } 1.157 +}; 1.158 +template < > 1.159 +struct variant_float_traits<double> 1.160 +{ 1.161 + static inline nsresult asDouble(double aValue, 1.162 + double *_result) 1.163 + { 1.164 + *_result = aValue; 1.165 + return NS_OK; 1.166 + } 1.167 +}; 1.168 + 1.169 +/** 1.170 + * TEXT types 1.171 + */ 1.172 + 1.173 +template < > 1.174 +struct variant_traits<nsString> 1.175 +{ 1.176 + static inline uint16_t type() { return nsIDataType::VTYPE_ASTRING; } 1.177 +}; 1.178 +template < > 1.179 +struct variant_storage_traits<nsString> 1.180 +{ 1.181 + typedef const nsAString & ConstructorType; 1.182 + typedef nsString StorageType; 1.183 + static inline void storage_conversion(ConstructorType aText, StorageType* _outData) 1.184 + { 1.185 + *_outData = aText; 1.186 + } 1.187 + static inline void destroy(const StorageType& _outData) 1.188 + { } 1.189 +}; 1.190 +template < > 1.191 +struct variant_text_traits<nsString> 1.192 +{ 1.193 + static inline nsresult asUTF8String(const nsString &aValue, 1.194 + nsACString &_result) 1.195 + { 1.196 + CopyUTF16toUTF8(aValue, _result); 1.197 + return NS_OK; 1.198 + } 1.199 + static inline nsresult asString(const nsString &aValue, 1.200 + nsAString &_result) 1.201 + { 1.202 + _result = aValue; 1.203 + return NS_OK; 1.204 + } 1.205 +}; 1.206 + 1.207 +template < > 1.208 +struct variant_traits<nsCString> 1.209 +{ 1.210 + static inline uint16_t type() { return nsIDataType::VTYPE_UTF8STRING; } 1.211 +}; 1.212 +template < > 1.213 +struct variant_storage_traits<nsCString> 1.214 +{ 1.215 + typedef const nsACString & ConstructorType; 1.216 + typedef nsCString StorageType; 1.217 + static inline void storage_conversion(ConstructorType aText, StorageType* _outData) 1.218 + { 1.219 + *_outData = aText; 1.220 + } 1.221 + static inline void destroy(const StorageType &aData) 1.222 + { } 1.223 +}; 1.224 +template < > 1.225 +struct variant_text_traits<nsCString> 1.226 +{ 1.227 + static inline nsresult asUTF8String(const nsCString &aValue, 1.228 + nsACString &_result) 1.229 + { 1.230 + _result = aValue; 1.231 + return NS_OK; 1.232 + } 1.233 + static inline nsresult asString(const nsCString &aValue, 1.234 + nsAString &_result) 1.235 + { 1.236 + CopyUTF8toUTF16(aValue, _result); 1.237 + return NS_OK; 1.238 + } 1.239 +}; 1.240 + 1.241 +/** 1.242 + * BLOB types 1.243 + */ 1.244 + 1.245 +template < > 1.246 +struct variant_traits<uint8_t[]> 1.247 +{ 1.248 + static inline uint16_t type() { return nsIDataType::VTYPE_ARRAY; } 1.249 +}; 1.250 +template < > 1.251 +struct variant_storage_traits<uint8_t[], false> 1.252 +{ 1.253 + typedef std::pair<const void *, int> ConstructorType; 1.254 + typedef FallibleTArray<uint8_t> StorageType; 1.255 + static inline void storage_conversion(ConstructorType aBlob, StorageType* _outData) 1.256 + { 1.257 + _outData->Clear(); 1.258 + _outData->SetCapacity(aBlob.second); 1.259 + (void)_outData->AppendElements(static_cast<const uint8_t *>(aBlob.first), 1.260 + aBlob.second); 1.261 + } 1.262 + static inline void destroy(const StorageType& _outData) 1.263 + { } 1.264 +}; 1.265 +template < > 1.266 +struct variant_storage_traits<uint8_t[], true> 1.267 +{ 1.268 + typedef std::pair<uint8_t *, int> ConstructorType; 1.269 + typedef std::pair<uint8_t *, int> StorageType; 1.270 + static inline void storage_conversion(ConstructorType aBlob, StorageType* _outData) 1.271 + { 1.272 + *_outData = aBlob; 1.273 + } 1.274 + static inline void destroy(StorageType &aData) 1.275 + { 1.276 + if (aData.first) { 1.277 + NS_Free(aData.first); 1.278 + aData.first = nullptr; 1.279 + } 1.280 + } 1.281 +}; 1.282 +template < > 1.283 +struct variant_blob_traits<uint8_t[], false> 1.284 +{ 1.285 + static inline nsresult asArray(FallibleTArray<uint8_t> &aData, 1.286 + uint16_t *_type, 1.287 + uint32_t *_size, 1.288 + void **_result) 1.289 + { 1.290 + // For empty blobs, we return nullptr. 1.291 + if (aData.Length() == 0) { 1.292 + *_result = nullptr; 1.293 + *_type = nsIDataType::VTYPE_UINT8; 1.294 + *_size = 0; 1.295 + return NS_OK; 1.296 + } 1.297 + 1.298 + // Otherwise, we copy the array. 1.299 + *_result = nsMemory::Clone(aData.Elements(), aData.Length() * sizeof(uint8_t)); 1.300 + NS_ENSURE_TRUE(*_result, NS_ERROR_OUT_OF_MEMORY); 1.301 + 1.302 + // Set type and size 1.303 + *_type = nsIDataType::VTYPE_UINT8; 1.304 + *_size = aData.Length(); 1.305 + return NS_OK; 1.306 + } 1.307 +}; 1.308 + 1.309 +template < > 1.310 +struct variant_blob_traits<uint8_t[], true> 1.311 +{ 1.312 + static inline nsresult asArray(std::pair<uint8_t *, int> &aData, 1.313 + uint16_t *_type, 1.314 + uint32_t *_size, 1.315 + void **_result) 1.316 + { 1.317 + // For empty blobs, we return nullptr. 1.318 + if (aData.second == 0) { 1.319 + *_result = nullptr; 1.320 + *_type = nsIDataType::VTYPE_UINT8; 1.321 + *_size = 0; 1.322 + return NS_OK; 1.323 + } 1.324 + 1.325 + // Otherwise, transfer the data out. 1.326 + *_result = aData.first; 1.327 + aData.first = nullptr; 1.328 + MOZ_ASSERT(*_result); // We asked for it twice, better not use adopting! 1.329 + 1.330 + // Set type and size 1.331 + *_type = nsIDataType::VTYPE_UINT8; 1.332 + *_size = aData.second; 1.333 + return NS_OK; 1.334 + } 1.335 +}; 1.336 + 1.337 +/** 1.338 + * nullptr type 1.339 + */ 1.340 + 1.341 +class NullVariant : public Variant_base 1.342 +{ 1.343 +public: 1.344 + NS_IMETHOD GetDataType(uint16_t *_type) 1.345 + { 1.346 + NS_ENSURE_ARG_POINTER(_type); 1.347 + *_type = nsIDataType::VTYPE_EMPTY; 1.348 + return NS_OK; 1.349 + } 1.350 + 1.351 + NS_IMETHOD GetAsAUTF8String(nsACString &_str) 1.352 + { 1.353 + // Return a void string. 1.354 + _str.Truncate(0); 1.355 + _str.SetIsVoid(true); 1.356 + return NS_OK; 1.357 + } 1.358 + 1.359 + NS_IMETHOD GetAsAString(nsAString &_str) 1.360 + { 1.361 + // Return a void string. 1.362 + _str.Truncate(0); 1.363 + _str.SetIsVoid(true); 1.364 + return NS_OK; 1.365 + } 1.366 +}; 1.367 + 1.368 +//////////////////////////////////////////////////////////////////////////////// 1.369 +//// Template Implementation 1.370 + 1.371 +template <typename DataType, bool Adopting=false> 1.372 +class Variant : public Variant_base 1.373 +{ 1.374 + ~Variant() 1.375 + { 1.376 + variant_storage_traits<DataType, Adopting>::destroy(mData); 1.377 + } 1.378 + 1.379 +public: 1.380 + Variant(const typename variant_storage_traits<DataType, Adopting>::ConstructorType aData) 1.381 + { 1.382 + variant_storage_traits<DataType, Adopting>::storage_conversion(aData, &mData); 1.383 + } 1.384 + 1.385 + NS_IMETHOD GetDataType(uint16_t *_type) 1.386 + { 1.387 + *_type = variant_traits<DataType>::type(); 1.388 + return NS_OK; 1.389 + } 1.390 + NS_IMETHOD GetAsInt32(int32_t *_integer) 1.391 + { 1.392 + return variant_integer_traits<DataType, Adopting>::asInt32(mData, _integer); 1.393 + } 1.394 + 1.395 + NS_IMETHOD GetAsInt64(int64_t *_integer) 1.396 + { 1.397 + return variant_integer_traits<DataType, Adopting>::asInt64(mData, _integer); 1.398 + } 1.399 + 1.400 + NS_IMETHOD GetAsDouble(double *_double) 1.401 + { 1.402 + return variant_float_traits<DataType, Adopting>::asDouble(mData, _double); 1.403 + } 1.404 + 1.405 + NS_IMETHOD GetAsAUTF8String(nsACString &_str) 1.406 + { 1.407 + return variant_text_traits<DataType, Adopting>::asUTF8String(mData, _str); 1.408 + } 1.409 + 1.410 + NS_IMETHOD GetAsAString(nsAString &_str) 1.411 + { 1.412 + return variant_text_traits<DataType, Adopting>::asString(mData, _str); 1.413 + } 1.414 + 1.415 + NS_IMETHOD GetAsArray(uint16_t *_type, 1.416 + nsIID *, 1.417 + uint32_t *_size, 1.418 + void **_data) 1.419 + { 1.420 + return variant_blob_traits<DataType, Adopting>::asArray(mData, _type, _size, _data); 1.421 + } 1.422 + 1.423 +private: 1.424 + typename variant_storage_traits<DataType, Adopting>::StorageType mData; 1.425 +}; 1.426 + 1.427 +//////////////////////////////////////////////////////////////////////////////// 1.428 +//// Handy typedefs! Use these for the right mapping. 1.429 + 1.430 +typedef Variant<int64_t> IntegerVariant; 1.431 +typedef Variant<double> FloatVariant; 1.432 +typedef Variant<nsString> TextVariant; 1.433 +typedef Variant<nsCString> UTF8TextVariant; 1.434 +typedef Variant<uint8_t[], false> BlobVariant; 1.435 +typedef Variant<uint8_t[], true> AdoptedBlobVariant; 1.436 + 1.437 +} // namespace storage 1.438 +} // namespace mozilla 1.439 + 1.440 +#include "Variant_inl.h" 1.441 + 1.442 +#endif // mozilla_storage_Variant_h__