react-native-windows 0.68.10 → 0.68.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,1411 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
#pragma once
|
|
18
|
+
|
|
19
|
+
#include <functional>
|
|
20
|
+
|
|
21
|
+
#include <folly/CPortability.h>
|
|
22
|
+
#include <folly/Conv.h>
|
|
23
|
+
#include <folly/Format.h>
|
|
24
|
+
#include <folly/Likely.h>
|
|
25
|
+
#include <folly/detail/Iterators.h>
|
|
26
|
+
#include <folly/lang/Exception.h>
|
|
27
|
+
|
|
28
|
+
namespace folly {
|
|
29
|
+
namespace detail {
|
|
30
|
+
|
|
31
|
+
struct DynamicHasher {
|
|
32
|
+
using is_transparent = void;
|
|
33
|
+
|
|
34
|
+
size_t operator()(dynamic const& d) const { return d.hash(); }
|
|
35
|
+
|
|
36
|
+
template <typename T>
|
|
37
|
+
std::enable_if_t<std::is_convertible<T, StringPiece>::value, size_t>
|
|
38
|
+
operator()(T const& val) const {
|
|
39
|
+
// keep consistent with dynamic::hash() for strings
|
|
40
|
+
return Hash()(static_cast<StringPiece>(val));
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
struct DynamicKeyEqual {
|
|
45
|
+
using is_transparent = void;
|
|
46
|
+
|
|
47
|
+
bool operator()(const dynamic& lhs, const dynamic& rhs) const {
|
|
48
|
+
return std::equal_to<dynamic>()(lhs, rhs);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Dynamic objects contains a map<dynamic, dynamic>. At least one of the
|
|
52
|
+
// operands should be a dynamic. Hence, an operator() where both operands are
|
|
53
|
+
// convertible to StringPiece is unnecessary.
|
|
54
|
+
template <typename A, typename B>
|
|
55
|
+
std::enable_if_t<
|
|
56
|
+
std::is_convertible<A, StringPiece>::value &&
|
|
57
|
+
std::is_convertible<B, StringPiece>::value,
|
|
58
|
+
bool>
|
|
59
|
+
operator()(A const& lhs, B const& rhs) const = delete;
|
|
60
|
+
|
|
61
|
+
template <typename A>
|
|
62
|
+
std::enable_if_t<std::is_convertible<A, StringPiece>::value, bool> operator()(
|
|
63
|
+
A const& lhs, dynamic const& rhs) const {
|
|
64
|
+
return FOLLY_LIKELY(rhs.type() == dynamic::Type::STRING) &&
|
|
65
|
+
std::equal_to<StringPiece>()(lhs, rhs.stringPiece());
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
template <typename B>
|
|
69
|
+
std::enable_if_t<std::is_convertible<B, StringPiece>::value, bool> operator()(
|
|
70
|
+
dynamic const& lhs, B const& rhs) const {
|
|
71
|
+
return FOLLY_LIKELY(lhs.type() == dynamic::Type::STRING) &&
|
|
72
|
+
std::equal_to<StringPiece>()(lhs.stringPiece(), rhs);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
} // namespace detail
|
|
76
|
+
} // namespace folly
|
|
77
|
+
|
|
78
|
+
//////////////////////////////////////////////////////////////////////
|
|
79
|
+
|
|
80
|
+
namespace std {
|
|
81
|
+
|
|
82
|
+
template <>
|
|
83
|
+
struct hash<::folly::dynamic> {
|
|
84
|
+
size_t operator()(::folly::dynamic const& d) const { return d.hash(); }
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
} // namespace std
|
|
88
|
+
|
|
89
|
+
//////////////////////////////////////////////////////////////////////
|
|
90
|
+
|
|
91
|
+
// This is a higher-order preprocessor macro to aid going from runtime
|
|
92
|
+
// types to the compile time type system.
|
|
93
|
+
#define FB_DYNAMIC_APPLY(type, apply) \
|
|
94
|
+
do { \
|
|
95
|
+
switch ((type)) { \
|
|
96
|
+
case NULLT: \
|
|
97
|
+
apply(std::nullptr_t); \
|
|
98
|
+
break; \
|
|
99
|
+
case ARRAY: \
|
|
100
|
+
apply(Array); \
|
|
101
|
+
break; \
|
|
102
|
+
case BOOL: \
|
|
103
|
+
apply(bool); \
|
|
104
|
+
break; \
|
|
105
|
+
case DOUBLE: \
|
|
106
|
+
apply(double); \
|
|
107
|
+
break; \
|
|
108
|
+
case INT64: \
|
|
109
|
+
apply(int64_t); \
|
|
110
|
+
break; \
|
|
111
|
+
case OBJECT: \
|
|
112
|
+
apply(ObjectImpl); \
|
|
113
|
+
break; \
|
|
114
|
+
case STRING: \
|
|
115
|
+
apply(std::string); \
|
|
116
|
+
break; \
|
|
117
|
+
default: \
|
|
118
|
+
abort(); \
|
|
119
|
+
} \
|
|
120
|
+
} while (0)
|
|
121
|
+
|
|
122
|
+
//////////////////////////////////////////////////////////////////////
|
|
123
|
+
|
|
124
|
+
namespace folly {
|
|
125
|
+
|
|
126
|
+
struct FOLLY_EXPORT TypeError : std::runtime_error {
|
|
127
|
+
explicit TypeError(const std::string& expected, dynamic::Type actual);
|
|
128
|
+
explicit TypeError(
|
|
129
|
+
const std::string& expected,
|
|
130
|
+
dynamic::Type actual1,
|
|
131
|
+
dynamic::Type actual2);
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
//////////////////////////////////////////////////////////////////////
|
|
135
|
+
|
|
136
|
+
namespace detail {
|
|
137
|
+
|
|
138
|
+
// This helper is used in destroy() to be able to run destructors on
|
|
139
|
+
// types like "int64_t" without a compiler error.
|
|
140
|
+
struct Destroy {
|
|
141
|
+
template <class T>
|
|
142
|
+
static void destroy(T* t) {
|
|
143
|
+
t->~T();
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
/*
|
|
148
|
+
* Helper for implementing numeric conversions in operators on
|
|
149
|
+
* numbers. Just promotes to double when one of the arguments is
|
|
150
|
+
* double, or throws if either is not a numeric type.
|
|
151
|
+
*/
|
|
152
|
+
template <template <class> class Op>
|
|
153
|
+
dynamic numericOp(dynamic const& a, dynamic const& b) {
|
|
154
|
+
if (!a.isNumber() || !b.isNumber()) {
|
|
155
|
+
throw_exception<TypeError>("numeric", a.type(), b.type());
|
|
156
|
+
}
|
|
157
|
+
if (a.isDouble() || b.isDouble()) {
|
|
158
|
+
return Op<double>()(a.asDouble(), b.asDouble());
|
|
159
|
+
}
|
|
160
|
+
return Op<int64_t>()(a.asInt(), b.asInt());
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
} // namespace detail
|
|
164
|
+
|
|
165
|
+
//////////////////////////////////////////////////////////////////////
|
|
166
|
+
|
|
167
|
+
/*
|
|
168
|
+
* We're doing this instead of a simple member typedef to avoid the
|
|
169
|
+
* undefined behavior of parameterizing F14NodeMap<> with an
|
|
170
|
+
* incomplete type.
|
|
171
|
+
*
|
|
172
|
+
* Note: Later we may add separate order tracking here (a multi-index
|
|
173
|
+
* type of thing.)
|
|
174
|
+
*/
|
|
175
|
+
struct dynamic::ObjectImpl : F14NodeMap<
|
|
176
|
+
dynamic,
|
|
177
|
+
dynamic,
|
|
178
|
+
detail::DynamicHasher,
|
|
179
|
+
detail::DynamicKeyEqual> {};
|
|
180
|
+
|
|
181
|
+
//////////////////////////////////////////////////////////////////////
|
|
182
|
+
|
|
183
|
+
// Helper object for creating objects conveniently. See object and
|
|
184
|
+
// the dynamic::dynamic(ObjectMaker&&) ctor.
|
|
185
|
+
struct dynamic::ObjectMaker {
|
|
186
|
+
friend struct dynamic;
|
|
187
|
+
|
|
188
|
+
explicit ObjectMaker() : val_(dynamic::object) {}
|
|
189
|
+
explicit ObjectMaker(dynamic key, dynamic val) : val_(dynamic::object) {
|
|
190
|
+
val_.insert(std::move(key), std::move(val));
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Make sure no one tries to save one of these into an lvalue with
|
|
194
|
+
// auto or anything like that.
|
|
195
|
+
ObjectMaker(ObjectMaker&&) = default;
|
|
196
|
+
ObjectMaker(ObjectMaker const&) = delete;
|
|
197
|
+
ObjectMaker& operator=(ObjectMaker const&) = delete;
|
|
198
|
+
ObjectMaker& operator=(ObjectMaker&&) = delete;
|
|
199
|
+
|
|
200
|
+
// This returns an rvalue-reference instead of an lvalue-reference
|
|
201
|
+
// to allow constructs like this to moved instead of copied:
|
|
202
|
+
// dynamic a = dynamic::object("a", "b")("c", "d")
|
|
203
|
+
ObjectMaker&& operator()(dynamic key, dynamic val) {
|
|
204
|
+
val_.insert(std::move(key), std::move(val));
|
|
205
|
+
return std::move(*this);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
private:
|
|
209
|
+
dynamic val_;
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
inline void dynamic::array(EmptyArrayTag) {}
|
|
213
|
+
|
|
214
|
+
template <class... Args>
|
|
215
|
+
inline dynamic dynamic::array(Args&&... args) {
|
|
216
|
+
return dynamic(Array{std::forward<Args>(args)...});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
inline dynamic::ObjectMaker dynamic::object() {
|
|
220
|
+
return ObjectMaker();
|
|
221
|
+
}
|
|
222
|
+
inline dynamic::ObjectMaker dynamic::object(dynamic a, dynamic b) {
|
|
223
|
+
return ObjectMaker(std::move(a), std::move(b));
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
//////////////////////////////////////////////////////////////////////
|
|
227
|
+
|
|
228
|
+
struct dynamic::item_iterator : detail::IteratorAdaptor<
|
|
229
|
+
dynamic::item_iterator,
|
|
230
|
+
dynamic::ObjectImpl::iterator,
|
|
231
|
+
std::pair<dynamic const, dynamic>,
|
|
232
|
+
std::forward_iterator_tag> {
|
|
233
|
+
using Super = detail::IteratorAdaptor<
|
|
234
|
+
dynamic::item_iterator,
|
|
235
|
+
dynamic::ObjectImpl::iterator,
|
|
236
|
+
std::pair<dynamic const, dynamic>,
|
|
237
|
+
std::forward_iterator_tag>;
|
|
238
|
+
/* implicit */ item_iterator(dynamic::ObjectImpl::iterator b) : Super(b) {}
|
|
239
|
+
|
|
240
|
+
using object_type = dynamic::ObjectImpl;
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
struct dynamic::value_iterator : detail::IteratorAdaptor<
|
|
244
|
+
dynamic::value_iterator,
|
|
245
|
+
dynamic::ObjectImpl::iterator,
|
|
246
|
+
dynamic,
|
|
247
|
+
std::forward_iterator_tag> {
|
|
248
|
+
using Super = detail::IteratorAdaptor<
|
|
249
|
+
dynamic::value_iterator,
|
|
250
|
+
dynamic::ObjectImpl::iterator,
|
|
251
|
+
dynamic,
|
|
252
|
+
std::forward_iterator_tag>;
|
|
253
|
+
/* implicit */ value_iterator(dynamic::ObjectImpl::iterator b) : Super(b) {}
|
|
254
|
+
|
|
255
|
+
using object_type = dynamic::ObjectImpl;
|
|
256
|
+
|
|
257
|
+
dynamic& dereference() const { return base()->second; }
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
struct dynamic::const_item_iterator
|
|
261
|
+
: detail::IteratorAdaptor<
|
|
262
|
+
dynamic::const_item_iterator,
|
|
263
|
+
dynamic::ObjectImpl::const_iterator,
|
|
264
|
+
std::pair<dynamic const, dynamic> const,
|
|
265
|
+
std::forward_iterator_tag> {
|
|
266
|
+
using Super = detail::IteratorAdaptor<
|
|
267
|
+
dynamic::const_item_iterator,
|
|
268
|
+
dynamic::ObjectImpl::const_iterator,
|
|
269
|
+
std::pair<dynamic const, dynamic> const,
|
|
270
|
+
std::forward_iterator_tag>;
|
|
271
|
+
/* implicit */ const_item_iterator(dynamic::ObjectImpl::const_iterator b)
|
|
272
|
+
: Super(b) {}
|
|
273
|
+
/* implicit */ const_item_iterator(const_item_iterator const& i)
|
|
274
|
+
: Super(i.base()) {}
|
|
275
|
+
/* implicit */ const_item_iterator(item_iterator i) : Super(i.base()) {}
|
|
276
|
+
|
|
277
|
+
using object_type = dynamic::ObjectImpl const;
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
struct dynamic::const_key_iterator : detail::IteratorAdaptor<
|
|
281
|
+
dynamic::const_key_iterator,
|
|
282
|
+
dynamic::ObjectImpl::const_iterator,
|
|
283
|
+
dynamic const,
|
|
284
|
+
std::forward_iterator_tag> {
|
|
285
|
+
using Super = detail::IteratorAdaptor<
|
|
286
|
+
dynamic::const_key_iterator,
|
|
287
|
+
dynamic::ObjectImpl::const_iterator,
|
|
288
|
+
dynamic const,
|
|
289
|
+
std::forward_iterator_tag>;
|
|
290
|
+
/* implicit */ const_key_iterator(dynamic::ObjectImpl::const_iterator b)
|
|
291
|
+
: Super(b) {}
|
|
292
|
+
|
|
293
|
+
using object_type = dynamic::ObjectImpl const;
|
|
294
|
+
|
|
295
|
+
dynamic const& dereference() const { return base()->first; }
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
struct dynamic::const_value_iterator : detail::IteratorAdaptor<
|
|
299
|
+
dynamic::const_value_iterator,
|
|
300
|
+
dynamic::ObjectImpl::const_iterator,
|
|
301
|
+
dynamic const,
|
|
302
|
+
std::forward_iterator_tag> {
|
|
303
|
+
using Super = detail::IteratorAdaptor<
|
|
304
|
+
dynamic::const_value_iterator,
|
|
305
|
+
dynamic::ObjectImpl::const_iterator,
|
|
306
|
+
dynamic const,
|
|
307
|
+
std::forward_iterator_tag>;
|
|
308
|
+
/* implicit */ const_value_iterator(dynamic::ObjectImpl::const_iterator b)
|
|
309
|
+
: Super(b) {}
|
|
310
|
+
/* implicit */ const_value_iterator(value_iterator i) : Super(i.base()) {}
|
|
311
|
+
/* implicit */ const_value_iterator(dynamic::ObjectImpl::iterator i)
|
|
312
|
+
: Super(i) {}
|
|
313
|
+
|
|
314
|
+
using object_type = dynamic::ObjectImpl const;
|
|
315
|
+
|
|
316
|
+
dynamic const& dereference() const { return base()->second; }
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
//////////////////////////////////////////////////////////////////////
|
|
320
|
+
|
|
321
|
+
inline dynamic::dynamic() : dynamic(nullptr) {}
|
|
322
|
+
|
|
323
|
+
inline dynamic::dynamic(std::nullptr_t) : type_(NULLT) {}
|
|
324
|
+
|
|
325
|
+
inline dynamic::dynamic(void (*)(EmptyArrayTag)) : type_(ARRAY) {
|
|
326
|
+
new (&u_.array) Array();
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
inline dynamic::dynamic(ObjectMaker (*)()) : type_(OBJECT) {
|
|
330
|
+
new (getAddress<ObjectImpl>()) ObjectImpl();
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
inline dynamic::dynamic(char const* s) : type_(STRING) {
|
|
334
|
+
new (&u_.string) std::string(s);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
inline dynamic::dynamic(std::string s) : type_(STRING) {
|
|
338
|
+
new (&u_.string) std::string(std::move(s));
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
template <typename Stringish, typename>
|
|
342
|
+
inline dynamic::dynamic(Stringish&& s) : type_(STRING) {
|
|
343
|
+
new (&u_.string) std::string(s.data(), s.size());
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
inline dynamic::dynamic(ObjectMaker&& maker) : type_(OBJECT) {
|
|
347
|
+
new (getAddress<ObjectImpl>())
|
|
348
|
+
ObjectImpl(std::move(*maker.val_.getAddress<ObjectImpl>()));
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
inline dynamic::dynamic(dynamic const& o) : type_(NULLT) {
|
|
352
|
+
*this = o;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
inline dynamic::dynamic(dynamic&& o) noexcept : type_(NULLT) {
|
|
356
|
+
*this = std::move(o);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
inline dynamic::~dynamic() noexcept {
|
|
360
|
+
destroy();
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// Integral types except bool convert to int64_t, float types to double.
|
|
364
|
+
template <class T>
|
|
365
|
+
struct dynamic::NumericTypeHelper<
|
|
366
|
+
T,
|
|
367
|
+
typename std::enable_if<std::is_integral<T>::value>::type> {
|
|
368
|
+
static_assert(
|
|
369
|
+
!kIsObjC || sizeof(T) > sizeof(char),
|
|
370
|
+
"char-sized types are ambiguous in objc; cast to bool or wider type");
|
|
371
|
+
using type = int64_t;
|
|
372
|
+
};
|
|
373
|
+
template <>
|
|
374
|
+
struct dynamic::NumericTypeHelper<bool> {
|
|
375
|
+
using type = bool;
|
|
376
|
+
};
|
|
377
|
+
template <>
|
|
378
|
+
struct dynamic::NumericTypeHelper<float> {
|
|
379
|
+
using type = double;
|
|
380
|
+
};
|
|
381
|
+
template <>
|
|
382
|
+
struct dynamic::NumericTypeHelper<double> {
|
|
383
|
+
using type = double;
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
inline dynamic::dynamic(std::vector<bool>::reference b)
|
|
387
|
+
: dynamic(static_cast<bool>(b)) {}
|
|
388
|
+
inline dynamic::dynamic(VectorBoolConstRefCtorType b)
|
|
389
|
+
: dynamic(static_cast<bool>(b)) {}
|
|
390
|
+
|
|
391
|
+
template <
|
|
392
|
+
class T,
|
|
393
|
+
class NumericType /* = typename NumericTypeHelper<T>::type */>
|
|
394
|
+
dynamic::dynamic(T t) {
|
|
395
|
+
type_ = TypeInfo<NumericType>::type;
|
|
396
|
+
new (getAddress<NumericType>()) NumericType(NumericType(t));
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
template <class Iterator>
|
|
400
|
+
dynamic::dynamic(Iterator first, Iterator last) : type_(ARRAY) {
|
|
401
|
+
new (&u_.array) Array(first, last);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
//////////////////////////////////////////////////////////////////////
|
|
405
|
+
|
|
406
|
+
inline dynamic::const_iterator dynamic::begin() const {
|
|
407
|
+
return get<Array>().begin();
|
|
408
|
+
}
|
|
409
|
+
inline dynamic::const_iterator dynamic::end() const {
|
|
410
|
+
return get<Array>().end();
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
inline dynamic::iterator dynamic::begin() {
|
|
414
|
+
return get<Array>().begin();
|
|
415
|
+
}
|
|
416
|
+
inline dynamic::iterator dynamic::end() {
|
|
417
|
+
return get<Array>().end();
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
template <class It>
|
|
421
|
+
struct dynamic::IterableProxy {
|
|
422
|
+
typedef It iterator;
|
|
423
|
+
typedef typename It::value_type value_type;
|
|
424
|
+
typedef typename It::object_type object_type;
|
|
425
|
+
|
|
426
|
+
/* implicit */ IterableProxy(object_type* o) : o_(o) {}
|
|
427
|
+
|
|
428
|
+
It begin() const { return o_->begin(); }
|
|
429
|
+
|
|
430
|
+
It end() const { return o_->end(); }
|
|
431
|
+
|
|
432
|
+
private:
|
|
433
|
+
object_type* o_;
|
|
434
|
+
};
|
|
435
|
+
|
|
436
|
+
inline dynamic::IterableProxy<dynamic::const_key_iterator> dynamic::keys()
|
|
437
|
+
const {
|
|
438
|
+
return &(get<ObjectImpl>());
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
inline dynamic::IterableProxy<dynamic::const_value_iterator> dynamic::values()
|
|
442
|
+
const {
|
|
443
|
+
return &(get<ObjectImpl>());
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
inline dynamic::IterableProxy<dynamic::const_item_iterator> dynamic::items()
|
|
447
|
+
const {
|
|
448
|
+
return &(get<ObjectImpl>());
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
inline dynamic::IterableProxy<dynamic::value_iterator> dynamic::values() {
|
|
452
|
+
return &(get<ObjectImpl>());
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
inline dynamic::IterableProxy<dynamic::item_iterator> dynamic::items() {
|
|
456
|
+
return &(get<ObjectImpl>());
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
inline bool dynamic::isString() const {
|
|
460
|
+
return get_nothrow<std::string>() != nullptr;
|
|
461
|
+
}
|
|
462
|
+
inline bool dynamic::isObject() const {
|
|
463
|
+
return get_nothrow<ObjectImpl>() != nullptr;
|
|
464
|
+
}
|
|
465
|
+
inline bool dynamic::isBool() const {
|
|
466
|
+
return get_nothrow<bool>() != nullptr;
|
|
467
|
+
}
|
|
468
|
+
inline bool dynamic::isArray() const {
|
|
469
|
+
return get_nothrow<Array>() != nullptr;
|
|
470
|
+
}
|
|
471
|
+
inline bool dynamic::isDouble() const {
|
|
472
|
+
return get_nothrow<double>() != nullptr;
|
|
473
|
+
}
|
|
474
|
+
inline bool dynamic::isInt() const {
|
|
475
|
+
return get_nothrow<int64_t>() != nullptr;
|
|
476
|
+
}
|
|
477
|
+
inline bool dynamic::isNull() const {
|
|
478
|
+
return get_nothrow<std::nullptr_t>() != nullptr;
|
|
479
|
+
}
|
|
480
|
+
inline bool dynamic::isNumber() const {
|
|
481
|
+
return isInt() || isDouble();
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
inline dynamic::Type dynamic::type() const {
|
|
485
|
+
return type_;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
inline std::string dynamic::asString() const {
|
|
489
|
+
return asImpl<std::string>();
|
|
490
|
+
}
|
|
491
|
+
inline double dynamic::asDouble() const {
|
|
492
|
+
return asImpl<double>();
|
|
493
|
+
}
|
|
494
|
+
inline int64_t dynamic::asInt() const {
|
|
495
|
+
return asImpl<int64_t>();
|
|
496
|
+
}
|
|
497
|
+
inline bool dynamic::asBool() const {
|
|
498
|
+
return asImpl<bool>();
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
inline const std::string& dynamic::getString() const& {
|
|
502
|
+
return get<std::string>();
|
|
503
|
+
}
|
|
504
|
+
inline double dynamic::getDouble() const& {
|
|
505
|
+
return get<double>();
|
|
506
|
+
}
|
|
507
|
+
inline int64_t dynamic::getInt() const& {
|
|
508
|
+
return get<int64_t>();
|
|
509
|
+
}
|
|
510
|
+
inline bool dynamic::getBool() const& {
|
|
511
|
+
return get<bool>();
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
inline std::string& dynamic::getString() & {
|
|
515
|
+
return get<std::string>();
|
|
516
|
+
}
|
|
517
|
+
inline double& dynamic::getDouble() & {
|
|
518
|
+
return get<double>();
|
|
519
|
+
}
|
|
520
|
+
inline int64_t& dynamic::getInt() & {
|
|
521
|
+
return get<int64_t>();
|
|
522
|
+
}
|
|
523
|
+
inline bool& dynamic::getBool() & {
|
|
524
|
+
return get<bool>();
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
inline std::string&& dynamic::getString() && {
|
|
528
|
+
return std::move(get<std::string>());
|
|
529
|
+
}
|
|
530
|
+
inline double dynamic::getDouble() && {
|
|
531
|
+
return get<double>();
|
|
532
|
+
}
|
|
533
|
+
inline int64_t dynamic::getInt() && {
|
|
534
|
+
return get<int64_t>();
|
|
535
|
+
}
|
|
536
|
+
inline bool dynamic::getBool() && {
|
|
537
|
+
return get<bool>();
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
inline const char* dynamic::c_str() const& {
|
|
541
|
+
return get<std::string>().c_str();
|
|
542
|
+
}
|
|
543
|
+
inline StringPiece dynamic::stringPiece() const {
|
|
544
|
+
return get<std::string>();
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
template <class T>
|
|
548
|
+
struct dynamic::CompareOp {
|
|
549
|
+
static bool comp(T const& a, T const& b) { return a < b; }
|
|
550
|
+
};
|
|
551
|
+
template <>
|
|
552
|
+
struct dynamic::CompareOp<dynamic::ObjectImpl> {
|
|
553
|
+
static bool comp(ObjectImpl const&, ObjectImpl const&) {
|
|
554
|
+
// This code never executes; it is just here for the compiler.
|
|
555
|
+
return false;
|
|
556
|
+
}
|
|
557
|
+
};
|
|
558
|
+
template <>
|
|
559
|
+
struct dynamic::CompareOp<std::nullptr_t> {
|
|
560
|
+
static bool comp(std::nullptr_t const&, std::nullptr_t const&) {
|
|
561
|
+
return true;
|
|
562
|
+
}
|
|
563
|
+
};
|
|
564
|
+
|
|
565
|
+
inline dynamic& dynamic::operator+=(dynamic const& o) {
|
|
566
|
+
if (type() == STRING && o.type() == STRING) {
|
|
567
|
+
*getAddress<std::string>() += *o.getAddress<std::string>();
|
|
568
|
+
return *this;
|
|
569
|
+
}
|
|
570
|
+
*this = detail::numericOp<std::plus>(*this, o);
|
|
571
|
+
return *this;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
inline dynamic& dynamic::operator-=(dynamic const& o) {
|
|
575
|
+
*this = detail::numericOp<std::minus>(*this, o);
|
|
576
|
+
return *this;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
inline dynamic& dynamic::operator*=(dynamic const& o) {
|
|
580
|
+
*this = detail::numericOp<std::multiplies>(*this, o);
|
|
581
|
+
return *this;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
inline dynamic& dynamic::operator/=(dynamic const& o) {
|
|
585
|
+
*this = detail::numericOp<std::divides>(*this, o);
|
|
586
|
+
return *this;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
#define FB_DYNAMIC_INTEGER_OP(op) \
|
|
590
|
+
inline dynamic& dynamic::operator op(dynamic const& o) { \
|
|
591
|
+
if (!isInt() || !o.isInt()) { \
|
|
592
|
+
throw_exception<TypeError>("int64", type(), o.type()); \
|
|
593
|
+
} \
|
|
594
|
+
*getAddress<int64_t>() op o.asInt(); \
|
|
595
|
+
return *this; \
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
FB_DYNAMIC_INTEGER_OP(%=)
|
|
599
|
+
FB_DYNAMIC_INTEGER_OP(|=)
|
|
600
|
+
FB_DYNAMIC_INTEGER_OP(&=)
|
|
601
|
+
FB_DYNAMIC_INTEGER_OP(^=)
|
|
602
|
+
|
|
603
|
+
#undef FB_DYNAMIC_INTEGER_OP
|
|
604
|
+
|
|
605
|
+
inline dynamic& dynamic::operator++() {
|
|
606
|
+
++get<int64_t>();
|
|
607
|
+
return *this;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
inline dynamic& dynamic::operator--() {
|
|
611
|
+
--get<int64_t>();
|
|
612
|
+
return *this;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
template <typename K>
|
|
616
|
+
dynamic::IfIsNonStringDynamicConvertible<K, dynamic const&> dynamic::operator[](
|
|
617
|
+
K&& idx) const& {
|
|
618
|
+
return at(std::forward<K>(idx));
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
template <typename K>
|
|
622
|
+
dynamic::IfIsNonStringDynamicConvertible<K, dynamic&> dynamic::operator[](
|
|
623
|
+
K&& idx) & {
|
|
624
|
+
if (!isObject() && !isArray()) {
|
|
625
|
+
throw_exception<TypeError>("object/array", type());
|
|
626
|
+
}
|
|
627
|
+
if (isArray()) {
|
|
628
|
+
return at(std::forward<K>(idx));
|
|
629
|
+
}
|
|
630
|
+
auto& obj = get<ObjectImpl>();
|
|
631
|
+
auto ret = obj.emplace(std::forward<K>(idx), nullptr);
|
|
632
|
+
return ret.first->second;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
template <typename K>
|
|
636
|
+
dynamic::IfIsNonStringDynamicConvertible<K, dynamic&&> dynamic::operator[](
|
|
637
|
+
K&& idx) && {
|
|
638
|
+
return std::move((*this)[std::forward<K>(idx)]);
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
inline dynamic const& dynamic::operator[](StringPiece k) const& {
|
|
642
|
+
return at(k);
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
inline dynamic&& dynamic::operator[](StringPiece k) && {
|
|
646
|
+
return std::move((*this)[k]);
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
template <typename K>
|
|
650
|
+
dynamic::IfIsNonStringDynamicConvertible<K, dynamic> dynamic::getDefault(
|
|
651
|
+
K&& k, const dynamic& v) const& {
|
|
652
|
+
auto& obj = get<ObjectImpl>();
|
|
653
|
+
auto it = obj.find(std::forward<K>(k));
|
|
654
|
+
return it == obj.end() ? v : it->second;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
template <typename K>
|
|
658
|
+
dynamic::IfIsNonStringDynamicConvertible<K, dynamic> dynamic::getDefault(
|
|
659
|
+
K&& k, dynamic&& v) const& {
|
|
660
|
+
auto& obj = get<ObjectImpl>();
|
|
661
|
+
auto it = obj.find(std::forward<K>(k));
|
|
662
|
+
// Avoid clang bug with ternary
|
|
663
|
+
if (it == obj.end()) {
|
|
664
|
+
return std::move(v);
|
|
665
|
+
} else {
|
|
666
|
+
return it->second;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
template <typename K>
|
|
671
|
+
dynamic::IfIsNonStringDynamicConvertible<K, dynamic> dynamic::getDefault(
|
|
672
|
+
K&& k, const dynamic& v) && {
|
|
673
|
+
auto& obj = get<ObjectImpl>();
|
|
674
|
+
auto it = obj.find(std::forward<K>(k));
|
|
675
|
+
// Avoid clang bug with ternary
|
|
676
|
+
if (it == obj.end()) {
|
|
677
|
+
return v;
|
|
678
|
+
} else {
|
|
679
|
+
return std::move(it->second);
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
template <typename K>
|
|
684
|
+
dynamic::IfIsNonStringDynamicConvertible<K, dynamic> dynamic::getDefault(
|
|
685
|
+
K&& k, dynamic&& v) && {
|
|
686
|
+
auto& obj = get<ObjectImpl>();
|
|
687
|
+
auto it = obj.find(std::forward<K>(k));
|
|
688
|
+
return std::move(it == obj.end() ? v : it->second);
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
template <typename K, typename V>
|
|
692
|
+
dynamic::IfIsNonStringDynamicConvertible<K, dynamic&> dynamic::setDefault(
|
|
693
|
+
K&& k, V&& v) {
|
|
694
|
+
auto& obj = get<ObjectImpl>();
|
|
695
|
+
return obj.emplace(std::forward<K>(k), std::forward<V>(v)).first->second;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
template <typename K>
|
|
699
|
+
dynamic::IfIsNonStringDynamicConvertible<K, dynamic&> dynamic::setDefault(
|
|
700
|
+
K&& k, dynamic&& v) {
|
|
701
|
+
auto& obj = get<ObjectImpl>();
|
|
702
|
+
return obj.emplace(std::forward<K>(k), std::move(v)).first->second;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
template <typename K>
|
|
706
|
+
dynamic::IfIsNonStringDynamicConvertible<K, dynamic&> dynamic::setDefault(
|
|
707
|
+
K&& k, const dynamic& v) {
|
|
708
|
+
auto& obj = get<ObjectImpl>();
|
|
709
|
+
return obj.emplace(std::forward<K>(k), v).first->second;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
template <typename V>
|
|
713
|
+
dynamic& dynamic::setDefault(StringPiece k, V&& v) {
|
|
714
|
+
auto& obj = get<ObjectImpl>();
|
|
715
|
+
return obj.emplace(k, std::forward<V>(v)).first->second;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
inline dynamic& dynamic::setDefault(StringPiece k, dynamic&& v) {
|
|
719
|
+
auto& obj = get<ObjectImpl>();
|
|
720
|
+
return obj.emplace(k, std::move(v)).first->second;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
inline dynamic& dynamic::setDefault(StringPiece k, const dynamic& v) {
|
|
724
|
+
auto& obj = get<ObjectImpl>();
|
|
725
|
+
return obj.emplace(k, v).first->second;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
template <typename K>
|
|
729
|
+
dynamic::IfIsNonStringDynamicConvertible<K, dynamic const*> dynamic::get_ptr(
|
|
730
|
+
K&& k) const& {
|
|
731
|
+
return get_ptrImpl(std::forward<K>(k));
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
template <typename K>
|
|
735
|
+
dynamic::IfIsNonStringDynamicConvertible<K, dynamic*> dynamic::get_ptr(
|
|
736
|
+
K&& idx) & {
|
|
737
|
+
return const_cast<dynamic*>(const_cast<dynamic const*>(this)->get_ptr(idx));
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
inline dynamic* dynamic::get_ptr(StringPiece idx) & {
|
|
741
|
+
return const_cast<dynamic*>(const_cast<dynamic const*>(this)->get_ptr(idx));
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
// clang-format off
|
|
745
|
+
inline
|
|
746
|
+
dynamic::resolved_json_pointer<dynamic>
|
|
747
|
+
dynamic::try_get_ptr(json_pointer const& jsonPtr) & {
|
|
748
|
+
auto ret = const_cast<dynamic const*>(this)->try_get_ptr(jsonPtr);
|
|
749
|
+
if (ret.hasValue()) {
|
|
750
|
+
return json_pointer_resolved_value<dynamic>{
|
|
751
|
+
const_cast<dynamic*>(ret.value().parent),
|
|
752
|
+
const_cast<dynamic*>(ret.value().value),
|
|
753
|
+
ret.value().parent_key, ret.value().parent_index};
|
|
754
|
+
} else {
|
|
755
|
+
return makeUnexpected(
|
|
756
|
+
json_pointer_resolution_error<dynamic>{
|
|
757
|
+
ret.error().error_code,
|
|
758
|
+
ret.error().index,
|
|
759
|
+
const_cast<dynamic*>(ret.error().context)}
|
|
760
|
+
);
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
// clang-format on
|
|
764
|
+
|
|
765
|
+
inline dynamic* dynamic::get_ptr(json_pointer const& jsonPtr) & {
|
|
766
|
+
return const_cast<dynamic*>(
|
|
767
|
+
const_cast<dynamic const*>(this)->get_ptr(jsonPtr));
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
template <typename K>
|
|
771
|
+
dynamic::IfIsNonStringDynamicConvertible<K, dynamic const&> dynamic::at(
|
|
772
|
+
K&& k) const& {
|
|
773
|
+
return atImpl(std::forward<K>(k));
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
template <typename K>
|
|
777
|
+
dynamic::IfIsNonStringDynamicConvertible<K, dynamic&> dynamic::at(K&& idx) & {
|
|
778
|
+
return const_cast<dynamic&>(const_cast<dynamic const*>(this)->at(idx));
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
template <typename K>
|
|
782
|
+
dynamic::IfIsNonStringDynamicConvertible<K, dynamic&&> dynamic::at(K&& idx) && {
|
|
783
|
+
return std::move(at(idx));
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
inline dynamic& dynamic::at(StringPiece idx) & {
|
|
787
|
+
return const_cast<dynamic&>(const_cast<dynamic const*>(this)->at(idx));
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
inline dynamic&& dynamic::at(StringPiece idx) && {
|
|
791
|
+
return std::move(at(idx));
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
inline bool dynamic::empty() const {
|
|
795
|
+
if (isNull()) {
|
|
796
|
+
return true;
|
|
797
|
+
}
|
|
798
|
+
return !size();
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
template <typename K>
|
|
802
|
+
dynamic::IfIsNonStringDynamicConvertible<K, dynamic::const_item_iterator>
|
|
803
|
+
dynamic::find(K&& key) const {
|
|
804
|
+
return get<ObjectImpl>().find(std::forward<K>(key));
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
template <typename K>
|
|
808
|
+
dynamic::IfIsNonStringDynamicConvertible<K, dynamic::item_iterator>
|
|
809
|
+
dynamic::find(K&& key) {
|
|
810
|
+
return get<ObjectImpl>().find(std::forward<K>(key));
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
inline dynamic::const_item_iterator dynamic::find(StringPiece key) const {
|
|
814
|
+
return get<ObjectImpl>().find(key);
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
inline dynamic::item_iterator dynamic::find(StringPiece key) {
|
|
818
|
+
return get<ObjectImpl>().find(key);
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
template <typename K>
|
|
822
|
+
dynamic::IfIsNonStringDynamicConvertible<K, std::size_t> dynamic::count(
|
|
823
|
+
K&& key) const {
|
|
824
|
+
return find(std::forward<K>(key)) != items().end() ? 1u : 0u;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
inline std::size_t dynamic::count(StringPiece key) const {
|
|
828
|
+
return find(key) != items().end() ? 1u : 0u;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
template <class K, class V>
|
|
832
|
+
inline dynamic::IfNotIterator<K, void> dynamic::insert(K&& key, V&& val) {
|
|
833
|
+
auto& obj = get<ObjectImpl>();
|
|
834
|
+
obj[std::forward<K>(key)] = std::forward<V>(val);
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
template <class T>
|
|
838
|
+
inline dynamic::iterator dynamic::insert(const_iterator pos, T&& value) {
|
|
839
|
+
auto& arr = get<Array>();
|
|
840
|
+
return arr.insert(pos, std::forward<T>(value));
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
inline void dynamic::update(const dynamic& mergeObj) {
|
|
844
|
+
if (!isObject() || !mergeObj.isObject()) {
|
|
845
|
+
throw_exception<TypeError>("object", type(), mergeObj.type());
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
for (const auto& pair : mergeObj.items()) {
|
|
849
|
+
(*this)[pair.first] = pair.second;
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
inline void dynamic::update_missing(const dynamic& mergeObj1) {
|
|
854
|
+
if (!isObject() || !mergeObj1.isObject()) {
|
|
855
|
+
throw_exception<TypeError>("object", type(), mergeObj1.type());
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
// Only add if not already there
|
|
859
|
+
for (const auto& pair : mergeObj1.items()) {
|
|
860
|
+
if ((*this).find(pair.first) == (*this).items().end()) {
|
|
861
|
+
(*this)[pair.first] = pair.second;
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
inline void dynamic::merge_patch(const dynamic& patch) {
|
|
867
|
+
auto& self = *this;
|
|
868
|
+
if (!patch.isObject()) {
|
|
869
|
+
self = patch;
|
|
870
|
+
return;
|
|
871
|
+
}
|
|
872
|
+
// if we are not an object, erase all contents, reset to object
|
|
873
|
+
if (!isObject()) {
|
|
874
|
+
self = object;
|
|
875
|
+
}
|
|
876
|
+
for (const auto& pair : patch.items()) {
|
|
877
|
+
if (pair.second.isNull()) {
|
|
878
|
+
// if name could be found in current object, remove it
|
|
879
|
+
auto it = self.find(pair.first);
|
|
880
|
+
if (it != self.items().end()) {
|
|
881
|
+
self.erase(it);
|
|
882
|
+
}
|
|
883
|
+
} else {
|
|
884
|
+
self[pair.first].merge_patch(pair.second);
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
inline dynamic dynamic::merge(
|
|
890
|
+
const dynamic& mergeObj1, const dynamic& mergeObj2) {
|
|
891
|
+
// No checks on type needed here because they are done in update_missing
|
|
892
|
+
// Note that we do update_missing here instead of update() because
|
|
893
|
+
// it will prevent the extra writes that would occur with update()
|
|
894
|
+
auto ret = mergeObj2;
|
|
895
|
+
ret.update_missing(mergeObj1);
|
|
896
|
+
return ret;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
template <typename K>
|
|
900
|
+
dynamic::IfIsNonStringDynamicConvertible<K, std::size_t> dynamic::erase(
|
|
901
|
+
K&& key) {
|
|
902
|
+
auto& obj = get<ObjectImpl>();
|
|
903
|
+
return obj.erase(std::forward<K>(key));
|
|
904
|
+
}
|
|
905
|
+
inline std::size_t dynamic::erase(StringPiece key) {
|
|
906
|
+
auto& obj = get<ObjectImpl>();
|
|
907
|
+
return obj.erase(key);
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
inline dynamic::iterator dynamic::erase(const_iterator it) {
|
|
911
|
+
auto& arr = get<Array>();
|
|
912
|
+
// std::vector doesn't have an erase method that works on const iterators,
|
|
913
|
+
// even though the standard says it should, so this hack converts to a
|
|
914
|
+
// non-const iterator before calling erase.
|
|
915
|
+
return get<Array>().erase(arr.begin() + (it - arr.begin()));
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
inline dynamic::const_key_iterator dynamic::erase(const_key_iterator it) {
|
|
919
|
+
return const_key_iterator(get<ObjectImpl>().erase(it.base()));
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
inline dynamic::const_key_iterator dynamic::erase(
|
|
923
|
+
const_key_iterator first, const_key_iterator last) {
|
|
924
|
+
return const_key_iterator(get<ObjectImpl>().erase(first.base(), last.base()));
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
inline dynamic::value_iterator dynamic::erase(const_value_iterator it) {
|
|
928
|
+
return value_iterator(get<ObjectImpl>().erase(it.base()));
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
inline dynamic::value_iterator dynamic::erase(
|
|
932
|
+
const_value_iterator first, const_value_iterator last) {
|
|
933
|
+
return value_iterator(get<ObjectImpl>().erase(first.base(), last.base()));
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
inline dynamic::item_iterator dynamic::erase(const_item_iterator it) {
|
|
937
|
+
return item_iterator(get<ObjectImpl>().erase(it.base()));
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
inline dynamic::item_iterator dynamic::erase(
|
|
941
|
+
const_item_iterator first, const_item_iterator last) {
|
|
942
|
+
return item_iterator(get<ObjectImpl>().erase(first.base(), last.base()));
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
inline void dynamic::resize(std::size_t sz, dynamic const& c) {
|
|
946
|
+
auto& arr = get<Array>();
|
|
947
|
+
arr.resize(sz, c);
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
inline void dynamic::push_back(dynamic const& v) {
|
|
951
|
+
auto& arr = get<Array>();
|
|
952
|
+
arr.push_back(v);
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
inline void dynamic::push_back(dynamic&& v) {
|
|
956
|
+
auto& arr = get<Array>();
|
|
957
|
+
arr.push_back(std::move(v));
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
inline void dynamic::pop_back() {
|
|
961
|
+
auto& arr = get<Array>();
|
|
962
|
+
arr.pop_back();
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
inline const dynamic& dynamic::back() const {
|
|
966
|
+
auto& arr = get<Array>();
|
|
967
|
+
return arr.back();
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
//////////////////////////////////////////////////////////////////////
|
|
971
|
+
|
|
972
|
+
inline dynamic::dynamic(Array&& r) : type_(ARRAY) {
|
|
973
|
+
new (&u_.array) Array(std::move(r));
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
#define FOLLY_DYNAMIC_DEC_TYPEINFO(T, val) \
|
|
977
|
+
template <> \
|
|
978
|
+
struct dynamic::TypeInfo<T> { \
|
|
979
|
+
static const char* const name; \
|
|
980
|
+
static constexpr dynamic::Type type = val; \
|
|
981
|
+
}; \
|
|
982
|
+
//
|
|
983
|
+
|
|
984
|
+
FOLLY_DYNAMIC_DEC_TYPEINFO(std::nullptr_t, dynamic::NULLT)
|
|
985
|
+
FOLLY_DYNAMIC_DEC_TYPEINFO(bool, dynamic::BOOL)
|
|
986
|
+
FOLLY_DYNAMIC_DEC_TYPEINFO(std::string, dynamic::STRING)
|
|
987
|
+
FOLLY_DYNAMIC_DEC_TYPEINFO(dynamic::Array, dynamic::ARRAY)
|
|
988
|
+
FOLLY_DYNAMIC_DEC_TYPEINFO(double, dynamic::DOUBLE)
|
|
989
|
+
FOLLY_DYNAMIC_DEC_TYPEINFO(int64_t, dynamic::INT64)
|
|
990
|
+
FOLLY_DYNAMIC_DEC_TYPEINFO(dynamic::ObjectImpl, dynamic::OBJECT)
|
|
991
|
+
|
|
992
|
+
#undef FOLLY_DYNAMIC_DEC_TYPEINFO
|
|
993
|
+
|
|
994
|
+
template <class T>
|
|
995
|
+
T dynamic::asImpl() const {
|
|
996
|
+
switch (type()) {
|
|
997
|
+
case INT64:
|
|
998
|
+
return to<T>(*get_nothrow<int64_t>());
|
|
999
|
+
case DOUBLE:
|
|
1000
|
+
return to<T>(*get_nothrow<double>());
|
|
1001
|
+
case BOOL:
|
|
1002
|
+
return to<T>(*get_nothrow<bool>());
|
|
1003
|
+
case STRING:
|
|
1004
|
+
return to<T>(*get_nothrow<std::string>());
|
|
1005
|
+
case NULLT:
|
|
1006
|
+
case ARRAY:
|
|
1007
|
+
case OBJECT:
|
|
1008
|
+
default:
|
|
1009
|
+
throw_exception<TypeError>("int/double/bool/string", type());
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
// Return a T* to our type, or null if we're not that type.
|
|
1014
|
+
// clang-format off
|
|
1015
|
+
template <class T>
|
|
1016
|
+
T* dynamic::get_nothrow() & noexcept {
|
|
1017
|
+
if (type_ != TypeInfo<T>::type) {
|
|
1018
|
+
return nullptr;
|
|
1019
|
+
}
|
|
1020
|
+
return getAddress<T>();
|
|
1021
|
+
}
|
|
1022
|
+
// clang-format on
|
|
1023
|
+
|
|
1024
|
+
template <class T>
|
|
1025
|
+
T const* dynamic::get_nothrow() const& noexcept {
|
|
1026
|
+
return const_cast<dynamic*>(this)->get_nothrow<T>();
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
// Return T* for where we can put a T, without type checking. (Memory
|
|
1030
|
+
// might be uninitialized, even.)
|
|
1031
|
+
template <class T>
|
|
1032
|
+
T* dynamic::getAddress() noexcept {
|
|
1033
|
+
return GetAddrImpl<T>::get(u_);
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
template <class T>
|
|
1037
|
+
T const* dynamic::getAddress() const noexcept {
|
|
1038
|
+
return const_cast<dynamic*>(this)->getAddress<T>();
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
template <class T>
|
|
1042
|
+
struct dynamic::GetAddrImpl {};
|
|
1043
|
+
template <>
|
|
1044
|
+
struct dynamic::GetAddrImpl<std::nullptr_t> {
|
|
1045
|
+
static std::nullptr_t* get(Data& d) noexcept { return &d.nul; }
|
|
1046
|
+
};
|
|
1047
|
+
template <>
|
|
1048
|
+
struct dynamic::GetAddrImpl<dynamic::Array> {
|
|
1049
|
+
static Array* get(Data& d) noexcept { return &d.array; }
|
|
1050
|
+
};
|
|
1051
|
+
template <>
|
|
1052
|
+
struct dynamic::GetAddrImpl<bool> {
|
|
1053
|
+
static bool* get(Data& d) noexcept { return &d.boolean; }
|
|
1054
|
+
};
|
|
1055
|
+
template <>
|
|
1056
|
+
struct dynamic::GetAddrImpl<int64_t> {
|
|
1057
|
+
static int64_t* get(Data& d) noexcept { return &d.integer; }
|
|
1058
|
+
};
|
|
1059
|
+
template <>
|
|
1060
|
+
struct dynamic::GetAddrImpl<double> {
|
|
1061
|
+
static double* get(Data& d) noexcept { return &d.doubl; }
|
|
1062
|
+
};
|
|
1063
|
+
template <>
|
|
1064
|
+
struct dynamic::GetAddrImpl<std::string> {
|
|
1065
|
+
static std::string* get(Data& d) noexcept { return &d.string; }
|
|
1066
|
+
};
|
|
1067
|
+
template <>
|
|
1068
|
+
struct dynamic::GetAddrImpl<dynamic::ObjectImpl> {
|
|
1069
|
+
static_assert(
|
|
1070
|
+
sizeof(ObjectImpl) <= sizeof(Data::objectBuffer),
|
|
1071
|
+
"In your implementation, F14NodeMap<> apparently takes different"
|
|
1072
|
+
" amount of space depending on its template parameters. This is "
|
|
1073
|
+
"weird. Make objectBuffer bigger if you want to compile dynamic.");
|
|
1074
|
+
|
|
1075
|
+
static ObjectImpl* get(Data& d) noexcept {
|
|
1076
|
+
void* data = &d.objectBuffer;
|
|
1077
|
+
return static_cast<ObjectImpl*>(data);
|
|
1078
|
+
}
|
|
1079
|
+
};
|
|
1080
|
+
|
|
1081
|
+
// [Win - Forked to avoid using exported data across the dll boundary. Using exported data prevents the ability to
|
|
1082
|
+
// delay load the dll We can remove this, once react-native-win32 stops exporting folly (gets entirely onto the ABI
|
|
1083
|
+
// interface)
|
|
1084
|
+
template <class T>
|
|
1085
|
+
T &dynamic::get() {
|
|
1086
|
+
if (auto *p = get_nothrow<T>()) {
|
|
1087
|
+
return *p;
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
switch (type()) {
|
|
1091
|
+
case dynamic::NULLT:
|
|
1092
|
+
throw_exception<TypeError>("null", dynamic::NULLT);
|
|
1093
|
+
break;
|
|
1094
|
+
case dynamic::BOOL:
|
|
1095
|
+
throw_exception<TypeError>("boolean", dynamic::BOOL);
|
|
1096
|
+
break;
|
|
1097
|
+
case dynamic::STRING:
|
|
1098
|
+
throw_exception<TypeError>("string", dynamic::STRING);
|
|
1099
|
+
break;
|
|
1100
|
+
case dynamic::ARRAY:
|
|
1101
|
+
throw_exception<TypeError>("array", dynamic::ARRAY);
|
|
1102
|
+
break;
|
|
1103
|
+
case dynamic::DOUBLE:
|
|
1104
|
+
throw_exception<TypeError>("double", dynamic::DOUBLE);
|
|
1105
|
+
break;
|
|
1106
|
+
case dynamic::INT64:
|
|
1107
|
+
throw_exception<TypeError>("int64", dynamic::INT64);
|
|
1108
|
+
break;
|
|
1109
|
+
case dynamic::OBJECT:
|
|
1110
|
+
throw_exception<TypeError>("object", dynamic::OBJECT);
|
|
1111
|
+
break;
|
|
1112
|
+
default:
|
|
1113
|
+
throw_exception<TypeError>("never", dynamic::OBJECT);
|
|
1114
|
+
break;
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
// Win]
|
|
1118
|
+
|
|
1119
|
+
template <class T>
|
|
1120
|
+
T const& dynamic::get() const {
|
|
1121
|
+
return const_cast<dynamic*>(this)->get<T>();
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
//////////////////////////////////////////////////////////////////////
|
|
1125
|
+
|
|
1126
|
+
/*
|
|
1127
|
+
* Helper for implementing operator<<. Throws if the type shouldn't
|
|
1128
|
+
* support it.
|
|
1129
|
+
*/
|
|
1130
|
+
template <class T>
|
|
1131
|
+
struct dynamic::PrintImpl {
|
|
1132
|
+
static void print(dynamic const&, std::ostream& out, T const& t) { out << t; }
|
|
1133
|
+
};
|
|
1134
|
+
// Otherwise, null, being (void*)0, would print as 0.
|
|
1135
|
+
template <>
|
|
1136
|
+
struct dynamic::PrintImpl<std::nullptr_t> {
|
|
1137
|
+
static void print(
|
|
1138
|
+
dynamic const& /* d */, std::ostream& out, std::nullptr_t const&) {
|
|
1139
|
+
out << "null";
|
|
1140
|
+
}
|
|
1141
|
+
};
|
|
1142
|
+
template <>
|
|
1143
|
+
struct dynamic::PrintImpl<dynamic::ObjectImpl> {
|
|
1144
|
+
static void print(
|
|
1145
|
+
dynamic const& d, std::ostream& out, dynamic::ObjectImpl const&) {
|
|
1146
|
+
d.print_as_pseudo_json(out);
|
|
1147
|
+
}
|
|
1148
|
+
};
|
|
1149
|
+
template <>
|
|
1150
|
+
struct dynamic::PrintImpl<dynamic::Array> {
|
|
1151
|
+
static void print(
|
|
1152
|
+
dynamic const& d, std::ostream& out, dynamic::Array const&) {
|
|
1153
|
+
d.print_as_pseudo_json(out);
|
|
1154
|
+
}
|
|
1155
|
+
};
|
|
1156
|
+
|
|
1157
|
+
inline void dynamic::print(std::ostream& out) const {
|
|
1158
|
+
#define FB_X(T) PrintImpl<T>::print(*this, out, *getAddress<T>())
|
|
1159
|
+
FB_DYNAMIC_APPLY(type_, FB_X);
|
|
1160
|
+
#undef FB_X
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
inline std::ostream& operator<<(std::ostream& out, dynamic const& d) {
|
|
1164
|
+
d.print(out);
|
|
1165
|
+
return out;
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
//////////////////////////////////////////////////////////////////////
|
|
1169
|
+
|
|
1170
|
+
inline const_dynamic_view::const_dynamic_view(dynamic const& d) noexcept
|
|
1171
|
+
: d_(&d) {}
|
|
1172
|
+
|
|
1173
|
+
inline const_dynamic_view::const_dynamic_view(dynamic const* d) noexcept
|
|
1174
|
+
: d_(d) {}
|
|
1175
|
+
|
|
1176
|
+
inline const_dynamic_view::operator bool() const noexcept {
|
|
1177
|
+
return !empty();
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
inline bool const_dynamic_view::empty() const noexcept {
|
|
1181
|
+
return d_ == nullptr;
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
inline void const_dynamic_view::reset() noexcept {
|
|
1185
|
+
d_ = nullptr;
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
template <typename Key, typename... Keys>
|
|
1189
|
+
inline const_dynamic_view const_dynamic_view::descend(
|
|
1190
|
+
Key const& key, Keys const&... keys) const noexcept {
|
|
1191
|
+
return descend_(key, keys...);
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
template <typename Key1, typename Key2, typename... Keys>
|
|
1195
|
+
inline dynamic const* const_dynamic_view::descend_(
|
|
1196
|
+
Key1 const& key1, Key2 const& key2, Keys const&... keys) const noexcept {
|
|
1197
|
+
if (!d_) {
|
|
1198
|
+
return nullptr;
|
|
1199
|
+
}
|
|
1200
|
+
return const_dynamic_view{descend_unchecked_(key1)}.descend_(key2, keys...);
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
template <typename Key>
|
|
1204
|
+
inline dynamic const* const_dynamic_view::descend_(
|
|
1205
|
+
Key const& key) const noexcept {
|
|
1206
|
+
if (!d_) {
|
|
1207
|
+
return nullptr;
|
|
1208
|
+
}
|
|
1209
|
+
return descend_unchecked_(key);
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
template <typename Key>
|
|
1213
|
+
inline dynamic::IfIsNonStringDynamicConvertible<Key, dynamic const*>
|
|
1214
|
+
const_dynamic_view::descend_unchecked_(Key const& key) const noexcept {
|
|
1215
|
+
if (auto* parray = d_->get_nothrow<dynamic::Array>()) {
|
|
1216
|
+
if /* constexpr */ (!std::is_integral<Key>::value) {
|
|
1217
|
+
return nullptr;
|
|
1218
|
+
}
|
|
1219
|
+
if (key < 0 || key >= parray->size()) {
|
|
1220
|
+
return nullptr;
|
|
1221
|
+
}
|
|
1222
|
+
return &(*parray)[size_t(key)];
|
|
1223
|
+
} else if (auto* pobject = d_->get_nothrow<dynamic::ObjectImpl>()) {
|
|
1224
|
+
auto it = pobject->find(key);
|
|
1225
|
+
if (it == pobject->end()) {
|
|
1226
|
+
return nullptr;
|
|
1227
|
+
}
|
|
1228
|
+
return &it->second;
|
|
1229
|
+
}
|
|
1230
|
+
return nullptr;
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
inline dynamic const* const_dynamic_view::descend_unchecked_(
|
|
1234
|
+
folly::StringPiece key) const noexcept {
|
|
1235
|
+
if (auto* pobject = d_->get_nothrow<dynamic::ObjectImpl>()) {
|
|
1236
|
+
auto it = pobject->find(key);
|
|
1237
|
+
if (it == pobject->end()) {
|
|
1238
|
+
return nullptr;
|
|
1239
|
+
}
|
|
1240
|
+
return &it->second;
|
|
1241
|
+
}
|
|
1242
|
+
return nullptr;
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
inline dynamic const_dynamic_view::value_or(dynamic&& val) const {
|
|
1246
|
+
if (d_) {
|
|
1247
|
+
return *d_;
|
|
1248
|
+
}
|
|
1249
|
+
return std::move(val);
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
template <typename T, typename... Args>
|
|
1253
|
+
inline T const_dynamic_view::get_copy(Args&&... args) const {
|
|
1254
|
+
if (auto* v = (d_ ? d_->get_nothrow<T>() : nullptr)) {
|
|
1255
|
+
return *v;
|
|
1256
|
+
}
|
|
1257
|
+
return T(std::forward<Args>(args)...);
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
inline std::string const_dynamic_view::string_or(char const* val) const {
|
|
1261
|
+
return get_copy<std::string>(val);
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
inline std::string const_dynamic_view::string_or(std::string val) const {
|
|
1265
|
+
return get_copy<std::string>(std::move(val));
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
// Specialized version for StringPiece, FixedString, and other types which are
|
|
1269
|
+
// not convertible to std::string, but can construct one from .data and .size
|
|
1270
|
+
// to std::string. Will not trigger a copy unless data and size require it.
|
|
1271
|
+
template <typename Stringish, typename>
|
|
1272
|
+
inline std::string const_dynamic_view::string_or(Stringish&& val) const {
|
|
1273
|
+
return get_copy(val.data(), val.size());
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
inline double const_dynamic_view::double_or(double val) const noexcept {
|
|
1277
|
+
return get_copy<double>(val);
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
inline int64_t const_dynamic_view::int_or(int64_t val) const noexcept {
|
|
1281
|
+
return get_copy<int64_t>(val);
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
inline bool const_dynamic_view::bool_or(bool val) const noexcept {
|
|
1285
|
+
return get_copy<bool>(val);
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
inline dynamic_view::dynamic_view(dynamic& d) noexcept
|
|
1289
|
+
: const_dynamic_view(d) {}
|
|
1290
|
+
|
|
1291
|
+
template <typename Key, typename... Keys>
|
|
1292
|
+
inline dynamic_view dynamic_view::descend(
|
|
1293
|
+
Key const& key, Keys const&... keys) const noexcept {
|
|
1294
|
+
if (auto* child = const_dynamic_view::descend_(key, keys...)) {
|
|
1295
|
+
return *const_cast<dynamic*>(child);
|
|
1296
|
+
}
|
|
1297
|
+
return {};
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
inline dynamic dynamic_view::move_value_or(dynamic&& val) noexcept {
|
|
1301
|
+
if (d_) {
|
|
1302
|
+
return std::move(*const_cast<dynamic*>(d_));
|
|
1303
|
+
}
|
|
1304
|
+
return std::move(val);
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
template <typename T, typename... Args>
|
|
1308
|
+
inline T dynamic_view::get_move(Args&&... args) {
|
|
1309
|
+
if (auto* v = (d_ ? const_cast<dynamic*>(d_)->get_nothrow<T>() : nullptr)) {
|
|
1310
|
+
return std::move(*v);
|
|
1311
|
+
}
|
|
1312
|
+
return T(std::forward<Args>(args)...);
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
inline std::string dynamic_view::move_string_or(char const* val) {
|
|
1316
|
+
return get_move<std::string>(val);
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
inline std::string dynamic_view::move_string_or(std::string val) noexcept {
|
|
1320
|
+
return get_move<std::string>(std::move(val));
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
template <typename Stringish, typename>
|
|
1324
|
+
inline std::string dynamic_view::move_string_or(Stringish&& val) {
|
|
1325
|
+
return get_move<std::string>(val.begin(), val.end());
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
//////////////////////////////////////////////////////////////////////
|
|
1329
|
+
|
|
1330
|
+
// Secialization of FormatValue so dynamic objects can be formatted
|
|
1331
|
+
template <>
|
|
1332
|
+
class FormatValue<dynamic> {
|
|
1333
|
+
public:
|
|
1334
|
+
explicit FormatValue(const dynamic& val) : val_(val) {}
|
|
1335
|
+
|
|
1336
|
+
template <class FormatCallback>
|
|
1337
|
+
void format(FormatArg& arg, FormatCallback& cb) const {
|
|
1338
|
+
switch (val_.type()) {
|
|
1339
|
+
case dynamic::NULLT:
|
|
1340
|
+
FormatValue<std::nullptr_t>(nullptr).format(arg, cb);
|
|
1341
|
+
break;
|
|
1342
|
+
case dynamic::BOOL:
|
|
1343
|
+
FormatValue<bool>(val_.asBool()).format(arg, cb);
|
|
1344
|
+
break;
|
|
1345
|
+
case dynamic::INT64:
|
|
1346
|
+
FormatValue<int64_t>(val_.asInt()).format(arg, cb);
|
|
1347
|
+
break;
|
|
1348
|
+
case dynamic::STRING:
|
|
1349
|
+
FormatValue<std::string>(val_.asString()).format(arg, cb);
|
|
1350
|
+
break;
|
|
1351
|
+
case dynamic::DOUBLE:
|
|
1352
|
+
FormatValue<double>(val_.asDouble()).format(arg, cb);
|
|
1353
|
+
break;
|
|
1354
|
+
case dynamic::ARRAY:
|
|
1355
|
+
FormatValue(val_.at(arg.splitIntKey())).format(arg, cb);
|
|
1356
|
+
break;
|
|
1357
|
+
case dynamic::OBJECT:
|
|
1358
|
+
FormatValue(val_.at(arg.splitKey().toString())).format(arg, cb);
|
|
1359
|
+
break;
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
private:
|
|
1364
|
+
const dynamic& val_;
|
|
1365
|
+
};
|
|
1366
|
+
|
|
1367
|
+
template <class V>
|
|
1368
|
+
class FormatValue<detail::DefaultValueWrapper<dynamic, V>> {
|
|
1369
|
+
public:
|
|
1370
|
+
explicit FormatValue(const detail::DefaultValueWrapper<dynamic, V>& val)
|
|
1371
|
+
: val_(val) {}
|
|
1372
|
+
|
|
1373
|
+
template <class FormatCallback>
|
|
1374
|
+
void format(FormatArg& arg, FormatCallback& cb) const {
|
|
1375
|
+
auto& c = val_.container;
|
|
1376
|
+
switch (c.type()) {
|
|
1377
|
+
case dynamic::NULLT:
|
|
1378
|
+
case dynamic::BOOL:
|
|
1379
|
+
case dynamic::INT64:
|
|
1380
|
+
case dynamic::STRING:
|
|
1381
|
+
case dynamic::DOUBLE:
|
|
1382
|
+
FormatValue<dynamic>(c).format(arg, cb);
|
|
1383
|
+
break;
|
|
1384
|
+
case dynamic::ARRAY: {
|
|
1385
|
+
int key = arg.splitIntKey();
|
|
1386
|
+
if (key >= 0 && size_t(key) < c.size()) {
|
|
1387
|
+
FormatValue<dynamic>(c.at(key)).format(arg, cb);
|
|
1388
|
+
} else {
|
|
1389
|
+
FormatValue<V>(val_.defaultValue).format(arg, cb);
|
|
1390
|
+
}
|
|
1391
|
+
break;
|
|
1392
|
+
}
|
|
1393
|
+
case dynamic::OBJECT: {
|
|
1394
|
+
auto pos = c.find(arg.splitKey());
|
|
1395
|
+
if (pos != c.items().end()) {
|
|
1396
|
+
FormatValue<dynamic>(pos->second).format(arg, cb);
|
|
1397
|
+
} else {
|
|
1398
|
+
FormatValue<V>(val_.defaultValue).format(arg, cb);
|
|
1399
|
+
}
|
|
1400
|
+
break;
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
private:
|
|
1406
|
+
const detail::DefaultValueWrapper<dynamic, V>& val_;
|
|
1407
|
+
};
|
|
1408
|
+
|
|
1409
|
+
} // namespace folly
|
|
1410
|
+
|
|
1411
|
+
#undef FB_DYNAMIC_APPLY
|