Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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 /**
17 * This class is used by the storage module whenever an nsIVariant needs to be
18 * returned. We provide traits for the basic sqlite types to make use easier.
19 * The following types map to the indicated sqlite type:
20 * int64_t -> INTEGER (use IntegerVariant)
21 * double -> FLOAT (use FloatVariant)
22 * nsString -> TEXT (use TextVariant)
23 * nsCString -> TEXT (use UTF8TextVariant)
24 * uint8_t[] -> BLOB (use BlobVariant)
25 * nullptr -> NULL (use NullVariant)
26 */
28 namespace mozilla {
29 namespace storage {
31 ////////////////////////////////////////////////////////////////////////////////
32 //// Base Class
34 class Variant_base : public nsIVariant
35 {
36 public:
37 NS_DECL_THREADSAFE_ISUPPORTS
38 NS_DECL_NSIVARIANT
40 protected:
41 virtual ~Variant_base() { }
42 };
44 ////////////////////////////////////////////////////////////////////////////////
45 //// Traits
47 /**
48 * Generics
49 */
51 template <typename DataType>
52 struct variant_traits
53 {
54 static inline uint16_t type() { return nsIDataType::VTYPE_EMPTY; }
55 };
57 template <typename DataType, bool Adopting=false>
58 struct variant_storage_traits
59 {
60 typedef DataType ConstructorType;
61 typedef DataType StorageType;
62 static inline void storage_conversion(const ConstructorType aData, StorageType* _storage)
63 {
64 *_storage = aData;
65 }
67 static inline void destroy(const StorageType& _storage)
68 { }
69 };
71 #define NO_CONVERSION return NS_ERROR_CANNOT_CONVERT_DATA;
73 template <typename DataType, bool Adopting=false>
74 struct variant_integer_traits
75 {
76 typedef typename variant_storage_traits<DataType, Adopting>::StorageType StorageType;
77 static inline nsresult asInt32(const StorageType &, int32_t *) { NO_CONVERSION }
78 static inline nsresult asInt64(const StorageType &, int64_t *) { NO_CONVERSION }
79 };
81 template <typename DataType, bool Adopting=false>
82 struct variant_float_traits
83 {
84 typedef typename variant_storage_traits<DataType, Adopting>::StorageType StorageType;
85 static inline nsresult asDouble(const StorageType &, double *) { NO_CONVERSION }
86 };
88 template <typename DataType, bool Adopting=false>
89 struct variant_text_traits
90 {
91 typedef typename variant_storage_traits<DataType, Adopting>::StorageType StorageType;
92 static inline nsresult asUTF8String(const StorageType &, nsACString &) { NO_CONVERSION }
93 static inline nsresult asString(const StorageType &, nsAString &) { NO_CONVERSION }
94 };
96 template <typename DataType, bool Adopting=false>
97 struct variant_blob_traits
98 {
99 typedef typename variant_storage_traits<DataType, Adopting>::StorageType StorageType;
100 static inline nsresult asArray(const StorageType &, uint16_t *, uint32_t *, void **)
101 { NO_CONVERSION }
102 };
104 #undef NO_CONVERSION
106 /**
107 * INTEGER types
108 */
110 template < >
111 struct variant_traits<int64_t>
112 {
113 static inline uint16_t type() { return nsIDataType::VTYPE_INT64; }
114 };
115 template < >
116 struct variant_integer_traits<int64_t>
117 {
118 static inline nsresult asInt32(int64_t aValue,
119 int32_t *_result)
120 {
121 if (aValue > INT32_MAX || aValue < INT32_MIN)
122 return NS_ERROR_CANNOT_CONVERT_DATA;
124 *_result = static_cast<int32_t>(aValue);
125 return NS_OK;
126 }
127 static inline nsresult asInt64(int64_t aValue,
128 int64_t *_result)
129 {
130 *_result = aValue;
131 return NS_OK;
132 }
133 };
134 // xpcvariant just calls get double for integers...
135 template < >
136 struct variant_float_traits<int64_t>
137 {
138 static inline nsresult asDouble(int64_t aValue,
139 double *_result)
140 {
141 *_result = double(aValue);
142 return NS_OK;
143 }
144 };
146 /**
147 * FLOAT types
148 */
150 template < >
151 struct variant_traits<double>
152 {
153 static inline uint16_t type() { return nsIDataType::VTYPE_DOUBLE; }
154 };
155 template < >
156 struct variant_float_traits<double>
157 {
158 static inline nsresult asDouble(double aValue,
159 double *_result)
160 {
161 *_result = aValue;
162 return NS_OK;
163 }
164 };
166 /**
167 * TEXT types
168 */
170 template < >
171 struct variant_traits<nsString>
172 {
173 static inline uint16_t type() { return nsIDataType::VTYPE_ASTRING; }
174 };
175 template < >
176 struct variant_storage_traits<nsString>
177 {
178 typedef const nsAString & ConstructorType;
179 typedef nsString StorageType;
180 static inline void storage_conversion(ConstructorType aText, StorageType* _outData)
181 {
182 *_outData = aText;
183 }
184 static inline void destroy(const StorageType& _outData)
185 { }
186 };
187 template < >
188 struct variant_text_traits<nsString>
189 {
190 static inline nsresult asUTF8String(const nsString &aValue,
191 nsACString &_result)
192 {
193 CopyUTF16toUTF8(aValue, _result);
194 return NS_OK;
195 }
196 static inline nsresult asString(const nsString &aValue,
197 nsAString &_result)
198 {
199 _result = aValue;
200 return NS_OK;
201 }
202 };
204 template < >
205 struct variant_traits<nsCString>
206 {
207 static inline uint16_t type() { return nsIDataType::VTYPE_UTF8STRING; }
208 };
209 template < >
210 struct variant_storage_traits<nsCString>
211 {
212 typedef const nsACString & ConstructorType;
213 typedef nsCString StorageType;
214 static inline void storage_conversion(ConstructorType aText, StorageType* _outData)
215 {
216 *_outData = aText;
217 }
218 static inline void destroy(const StorageType &aData)
219 { }
220 };
221 template < >
222 struct variant_text_traits<nsCString>
223 {
224 static inline nsresult asUTF8String(const nsCString &aValue,
225 nsACString &_result)
226 {
227 _result = aValue;
228 return NS_OK;
229 }
230 static inline nsresult asString(const nsCString &aValue,
231 nsAString &_result)
232 {
233 CopyUTF8toUTF16(aValue, _result);
234 return NS_OK;
235 }
236 };
238 /**
239 * BLOB types
240 */
242 template < >
243 struct variant_traits<uint8_t[]>
244 {
245 static inline uint16_t type() { return nsIDataType::VTYPE_ARRAY; }
246 };
247 template < >
248 struct variant_storage_traits<uint8_t[], false>
249 {
250 typedef std::pair<const void *, int> ConstructorType;
251 typedef FallibleTArray<uint8_t> StorageType;
252 static inline void storage_conversion(ConstructorType aBlob, StorageType* _outData)
253 {
254 _outData->Clear();
255 _outData->SetCapacity(aBlob.second);
256 (void)_outData->AppendElements(static_cast<const uint8_t *>(aBlob.first),
257 aBlob.second);
258 }
259 static inline void destroy(const StorageType& _outData)
260 { }
261 };
262 template < >
263 struct variant_storage_traits<uint8_t[], true>
264 {
265 typedef std::pair<uint8_t *, int> ConstructorType;
266 typedef std::pair<uint8_t *, int> StorageType;
267 static inline void storage_conversion(ConstructorType aBlob, StorageType* _outData)
268 {
269 *_outData = aBlob;
270 }
271 static inline void destroy(StorageType &aData)
272 {
273 if (aData.first) {
274 NS_Free(aData.first);
275 aData.first = nullptr;
276 }
277 }
278 };
279 template < >
280 struct variant_blob_traits<uint8_t[], false>
281 {
282 static inline nsresult asArray(FallibleTArray<uint8_t> &aData,
283 uint16_t *_type,
284 uint32_t *_size,
285 void **_result)
286 {
287 // For empty blobs, we return nullptr.
288 if (aData.Length() == 0) {
289 *_result = nullptr;
290 *_type = nsIDataType::VTYPE_UINT8;
291 *_size = 0;
292 return NS_OK;
293 }
295 // Otherwise, we copy the array.
296 *_result = nsMemory::Clone(aData.Elements(), aData.Length() * sizeof(uint8_t));
297 NS_ENSURE_TRUE(*_result, NS_ERROR_OUT_OF_MEMORY);
299 // Set type and size
300 *_type = nsIDataType::VTYPE_UINT8;
301 *_size = aData.Length();
302 return NS_OK;
303 }
304 };
306 template < >
307 struct variant_blob_traits<uint8_t[], true>
308 {
309 static inline nsresult asArray(std::pair<uint8_t *, int> &aData,
310 uint16_t *_type,
311 uint32_t *_size,
312 void **_result)
313 {
314 // For empty blobs, we return nullptr.
315 if (aData.second == 0) {
316 *_result = nullptr;
317 *_type = nsIDataType::VTYPE_UINT8;
318 *_size = 0;
319 return NS_OK;
320 }
322 // Otherwise, transfer the data out.
323 *_result = aData.first;
324 aData.first = nullptr;
325 MOZ_ASSERT(*_result); // We asked for it twice, better not use adopting!
327 // Set type and size
328 *_type = nsIDataType::VTYPE_UINT8;
329 *_size = aData.second;
330 return NS_OK;
331 }
332 };
334 /**
335 * nullptr type
336 */
338 class NullVariant : public Variant_base
339 {
340 public:
341 NS_IMETHOD GetDataType(uint16_t *_type)
342 {
343 NS_ENSURE_ARG_POINTER(_type);
344 *_type = nsIDataType::VTYPE_EMPTY;
345 return NS_OK;
346 }
348 NS_IMETHOD GetAsAUTF8String(nsACString &_str)
349 {
350 // Return a void string.
351 _str.Truncate(0);
352 _str.SetIsVoid(true);
353 return NS_OK;
354 }
356 NS_IMETHOD GetAsAString(nsAString &_str)
357 {
358 // Return a void string.
359 _str.Truncate(0);
360 _str.SetIsVoid(true);
361 return NS_OK;
362 }
363 };
365 ////////////////////////////////////////////////////////////////////////////////
366 //// Template Implementation
368 template <typename DataType, bool Adopting=false>
369 class Variant : public Variant_base
370 {
371 ~Variant()
372 {
373 variant_storage_traits<DataType, Adopting>::destroy(mData);
374 }
376 public:
377 Variant(const typename variant_storage_traits<DataType, Adopting>::ConstructorType aData)
378 {
379 variant_storage_traits<DataType, Adopting>::storage_conversion(aData, &mData);
380 }
382 NS_IMETHOD GetDataType(uint16_t *_type)
383 {
384 *_type = variant_traits<DataType>::type();
385 return NS_OK;
386 }
387 NS_IMETHOD GetAsInt32(int32_t *_integer)
388 {
389 return variant_integer_traits<DataType, Adopting>::asInt32(mData, _integer);
390 }
392 NS_IMETHOD GetAsInt64(int64_t *_integer)
393 {
394 return variant_integer_traits<DataType, Adopting>::asInt64(mData, _integer);
395 }
397 NS_IMETHOD GetAsDouble(double *_double)
398 {
399 return variant_float_traits<DataType, Adopting>::asDouble(mData, _double);
400 }
402 NS_IMETHOD GetAsAUTF8String(nsACString &_str)
403 {
404 return variant_text_traits<DataType, Adopting>::asUTF8String(mData, _str);
405 }
407 NS_IMETHOD GetAsAString(nsAString &_str)
408 {
409 return variant_text_traits<DataType, Adopting>::asString(mData, _str);
410 }
412 NS_IMETHOD GetAsArray(uint16_t *_type,
413 nsIID *,
414 uint32_t *_size,
415 void **_data)
416 {
417 return variant_blob_traits<DataType, Adopting>::asArray(mData, _type, _size, _data);
418 }
420 private:
421 typename variant_storage_traits<DataType, Adopting>::StorageType mData;
422 };
424 ////////////////////////////////////////////////////////////////////////////////
425 //// Handy typedefs! Use these for the right mapping.
427 typedef Variant<int64_t> IntegerVariant;
428 typedef Variant<double> FloatVariant;
429 typedef Variant<nsString> TextVariant;
430 typedef Variant<nsCString> UTF8TextVariant;
431 typedef Variant<uint8_t[], false> BlobVariant;
432 typedef Variant<uint8_t[], true> AdoptedBlobVariant;
434 } // namespace storage
435 } // namespace mozilla
437 #include "Variant_inl.h"
439 #endif // mozilla_storage_Variant_h__