1 | /* |
2 | * Copyright 2011-present Facebook, Inc. |
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 | /** |
18 | * This is a runtime dynamically typed value. It holds types from a |
19 | * specific predetermined set of types (ints, bools, arrays, etc). In |
20 | * particular, it can be used as a convenient in-memory representation |
21 | * for complete json objects. |
22 | * |
23 | * In general you can try to use these objects as if they were the |
24 | * type they represent (although in some cases with a slightly less |
25 | * complete interface than the raw type), and it'll just throw a |
26 | * TypeError if it is used in an illegal way. |
27 | * |
28 | * Some examples: |
29 | * |
30 | * dynamic twelve = 12; |
31 | * dynamic str = "string"; |
32 | * dynamic map = dynamic::object; |
33 | * map[str] = twelve; |
34 | * map[str + "another_str"] = dynamic::array("array", "of", 4, "elements"); |
35 | * map.insert("null_element", nullptr); |
36 | * ++map[str]; |
37 | * assert(map[str] == 13); |
38 | * |
39 | * // Building a complex object with a sub array inline: |
40 | * dynamic d = dynamic::object |
41 | * ("key", "value") |
42 | * ("key2", dynamic::array("a", "array")) |
43 | * ; |
44 | * |
45 | * Also see folly/json.h for the serialization and deserialization |
46 | * functions for JSON. |
47 | * |
48 | * Additional documentation is in folly/docs/Dynamic.md. |
49 | * |
50 | * @author Jordan DeLong <delong.j@fb.com> |
51 | */ |
52 | |
53 | #pragma once |
54 | |
55 | #include <cstdint> |
56 | #include <memory> |
57 | #include <ostream> |
58 | #include <string> |
59 | #include <type_traits> |
60 | #include <utility> |
61 | #include <vector> |
62 | |
63 | #include <boost/operators.hpp> |
64 | |
65 | #include <folly/Expected.h> |
66 | #include <folly/Range.h> |
67 | #include <folly/Traits.h> |
68 | #include <folly/container/F14Map.h> |
69 | #include <folly/json_pointer.h> |
70 | |
71 | namespace folly { |
72 | |
73 | ////////////////////////////////////////////////////////////////////// |
74 | |
75 | struct dynamic; |
76 | struct TypeError; |
77 | |
78 | ////////////////////////////////////////////////////////////////////// |
79 | |
80 | struct dynamic : private boost::operators<dynamic> { |
81 | enum Type { |
82 | NULLT, |
83 | ARRAY, |
84 | BOOL, |
85 | DOUBLE, |
86 | INT64, |
87 | OBJECT, |
88 | STRING, |
89 | }; |
90 | template <class T, class Enable = void> |
91 | struct NumericTypeHelper; |
92 | |
93 | /* |
94 | * We support direct iteration of arrays, and indirect iteration of objects. |
95 | * See begin(), end(), keys(), values(), and items() for more. |
96 | * |
97 | * Array iterators dereference as the elements in the array. |
98 | * Object key iterators dereference as the keys in the object. |
99 | * Object value iterators dereference as the values in the object. |
100 | * Object item iterators dereference as pairs of (key, value). |
101 | */ |
102 | private: |
103 | typedef std::vector<dynamic> Array; |
104 | |
105 | /* |
106 | * Violating spec, std::vector<bool>::const_reference is not bool in libcpp: |
107 | * http://howardhinnant.github.io/onvectorbool.html |
108 | * |
109 | * This is used to add a public ctor which is only enabled under libcpp taking |
110 | * std::vector<bool>::const_reference without using the preprocessor. |
111 | */ |
112 | struct VectorBoolConstRefFake : std::false_type {}; |
113 | using VectorBoolConstRefCtorType = std::conditional_t< |
114 | std::is_same<std::vector<bool>::const_reference, bool>::value, |
115 | VectorBoolConstRefFake, |
116 | std::vector<bool>::const_reference>; |
117 | |
118 | public: |
119 | typedef Array::iterator iterator; |
120 | typedef Array::const_iterator const_iterator; |
121 | typedef dynamic value_type; |
122 | |
123 | struct const_key_iterator; |
124 | struct const_value_iterator; |
125 | struct const_item_iterator; |
126 | |
127 | struct value_iterator; |
128 | struct item_iterator; |
129 | |
130 | /* |
131 | * Creation routines for making dynamic objects and arrays. Objects |
132 | * are maps from key to value (so named due to json-related origins |
133 | * here). |
134 | * |
135 | * Example: |
136 | * |
137 | * // Make a fairly complex dynamic: |
138 | * dynamic d = dynamic::object("key", "value1") |
139 | * ("key2", dynamic::array("value", |
140 | * "with", |
141 | * 4, |
142 | * "words")); |
143 | * |
144 | * // Build an object in a few steps: |
145 | * dynamic d = dynamic::object; |
146 | * d["key"] = 12; |
147 | * d["something_else"] = dynamic::array(1, 2, 3, nullptr); |
148 | */ |
149 | private: |
150 | struct EmptyArrayTag {}; |
151 | struct ObjectMaker; |
152 | |
153 | public: |
154 | static void array(EmptyArrayTag); |
155 | template <class... Args> |
156 | static dynamic array(Args&&... args); |
157 | |
158 | static ObjectMaker object(); |
159 | static ObjectMaker object(dynamic, dynamic); |
160 | |
161 | /** |
162 | * Default constructor, initializes with nullptr. |
163 | */ |
164 | dynamic(); |
165 | |
166 | /* |
167 | * String compatibility constructors. |
168 | */ |
169 | /* implicit */ dynamic(std::nullptr_t); |
170 | /* implicit */ dynamic(StringPiece val); |
171 | /* implicit */ dynamic(char const* val); |
172 | /* implicit */ dynamic(std::string val); |
173 | |
174 | /* |
175 | * This is part of the plumbing for array() and object(), above. |
176 | * Used to create a new array or object dynamic. |
177 | */ |
178 | /* implicit */ dynamic(void (*)(EmptyArrayTag)); |
179 | /* implicit */ dynamic(ObjectMaker (*)()); |
180 | /* implicit */ dynamic(ObjectMaker const&) = delete; |
181 | /* implicit */ dynamic(ObjectMaker&&); |
182 | |
183 | /* |
184 | * Constructors for integral and float types. |
185 | * Other types are SFINAEd out with NumericTypeHelper. |
186 | */ |
187 | template <class T, class NumericType = typename NumericTypeHelper<T>::type> |
188 | /* implicit */ dynamic(T t); |
189 | |
190 | /* |
191 | * If v is vector<bool>, v[idx] is a proxy object implicitly convertible to |
192 | * bool. Calling a function f(dynamic) with f(v[idx]) would require a double |
193 | * implicit conversion (reference -> bool -> dynamic) which is not allowed, |
194 | * hence we explicitly accept the reference proxy. |
195 | */ |
196 | /* implicit */ dynamic(std::vector<bool>::reference val); |
197 | /* implicit */ dynamic(VectorBoolConstRefCtorType val); |
198 | |
199 | /* |
200 | * Create a dynamic that is an array of the values from the supplied |
201 | * iterator range. |
202 | */ |
203 | template <class Iterator> |
204 | explicit dynamic(Iterator first, Iterator last); |
205 | |
206 | dynamic(dynamic const&); |
207 | dynamic(dynamic&&) noexcept; |
208 | ~dynamic() noexcept; |
209 | |
210 | /* |
211 | * "Deep" equality comparison. This will compare all the way down |
212 | * an object or array, and is potentially expensive. |
213 | */ |
214 | bool operator==(dynamic const& o) const; |
215 | |
216 | /* |
217 | * For all types except object this returns the natural ordering on |
218 | * those types. For objects, we throw TypeError. |
219 | */ |
220 | bool operator<(dynamic const& o) const; |
221 | |
222 | /* |
223 | * General operators. |
224 | * |
225 | * These throw TypeError when used with types or type combinations |
226 | * that don't support them. |
227 | * |
228 | * These functions may also throw if you use 64-bit integers with |
229 | * doubles when the integers are too big to fit in a double. |
230 | */ |
231 | dynamic& operator+=(dynamic const&); |
232 | dynamic& operator-=(dynamic const&); |
233 | dynamic& operator*=(dynamic const&); |
234 | dynamic& operator/=(dynamic const&); |
235 | dynamic& operator%=(dynamic const&); |
236 | dynamic& operator|=(dynamic const&); |
237 | dynamic& operator&=(dynamic const&); |
238 | dynamic& operator^=(dynamic const&); |
239 | dynamic& operator++(); |
240 | dynamic& operator--(); |
241 | |
242 | /* |
243 | * Assignment from other dynamics. Because of the implicit conversion |
244 | * to dynamic from its potential types, you can use this to change the |
245 | * type pretty intuitively. |
246 | * |
247 | * Basic guarantee only. |
248 | */ |
249 | dynamic& operator=(dynamic const&); |
250 | dynamic& operator=(dynamic&&) noexcept; |
251 | |
252 | /* |
253 | * For simple dynamics (not arrays or objects), this prints the |
254 | * value to an std::ostream in the expected way. Respects the |
255 | * formatting manipulators that have been sent to the stream |
256 | * already. |
257 | * |
258 | * If the dynamic holds an object or array, this prints them in a |
259 | * format very similar to JSON. (It will in fact actually be JSON |
260 | * as long as the dynamic validly represents a JSON object---i.e. it |
261 | * can't have non-string keys.) |
262 | */ |
263 | friend std::ostream& operator<<(std::ostream&, dynamic const&); |
264 | |
265 | /* |
266 | * Returns true if this dynamic is of the specified type. |
267 | */ |
268 | bool isString() const; |
269 | bool isObject() const; |
270 | bool isBool() const; |
271 | bool isNull() const; |
272 | bool isArray() const; |
273 | bool isDouble() const; |
274 | bool isInt() const; |
275 | |
276 | /* |
277 | * Returns: isInt() || isDouble(). |
278 | */ |
279 | bool isNumber() const; |
280 | |
281 | /* |
282 | * Returns the type of this dynamic. |
283 | */ |
284 | Type type() const; |
285 | |
286 | /* |
287 | * Returns the type of this dynamic as a printable string. |
288 | */ |
289 | const char* typeName() const; |
290 | |
291 | /* |
292 | * Extract a value while trying to convert to the specified type. |
293 | * Throws exceptions if we cannot convert from the real type to the |
294 | * requested type. |
295 | * |
296 | * Note you can only use this to access integral types or strings, |
297 | * since arrays and objects are generally best dealt with as a |
298 | * dynamic. |
299 | */ |
300 | std::string asString() const; |
301 | double asDouble() const; |
302 | int64_t asInt() const; |
303 | bool asBool() const; |
304 | |
305 | /* |
306 | * Extract the value stored in this dynamic without type conversion. |
307 | * |
308 | * These will throw a TypeError if the dynamic has a different type. |
309 | */ |
310 | const std::string& getString() const&; |
311 | double getDouble() const&; |
312 | int64_t getInt() const&; |
313 | bool getBool() const&; |
314 | std::string& getString() &; |
315 | double& getDouble() &; |
316 | int64_t& getInt() &; |
317 | bool& getBool() &; |
318 | std::string&& getString() &&; |
319 | double getDouble() &&; |
320 | int64_t getInt() &&; |
321 | bool getBool() &&; |
322 | |
323 | /* |
324 | * It is occasionally useful to access a string's internal pointer |
325 | * directly, without the type conversion of `asString()`. |
326 | * |
327 | * These will throw a TypeError if the dynamic is not a string. |
328 | */ |
329 | const char* data() const&; |
330 | const char* data() && = delete; |
331 | const char* c_str() const&; |
332 | const char* c_str() && = delete; |
333 | StringPiece stringPiece() const; |
334 | |
335 | /* |
336 | * Returns: true if this dynamic is null, an empty array, an empty |
337 | * object, or an empty string. |
338 | */ |
339 | bool empty() const; |
340 | |
341 | /* |
342 | * If this is an array or an object, returns the number of elements |
343 | * contained. If it is a string, returns the length. Otherwise |
344 | * throws TypeError. |
345 | */ |
346 | std::size_t size() const; |
347 | |
348 | /* |
349 | * You can iterate over the values of the array. Calling these on |
350 | * non-arrays will throw a TypeError. |
351 | */ |
352 | const_iterator begin() const; |
353 | const_iterator end() const; |
354 | iterator begin(); |
355 | iterator end(); |
356 | |
357 | private: |
358 | /* |
359 | * Helper object returned by keys(), values(), and items(). |
360 | */ |
361 | template <class T> |
362 | struct IterableProxy; |
363 | |
364 | /* |
365 | * Helper for heterogeneous lookup and mutation on objects: at(), find(), |
366 | * count(), erase(), operator[] |
367 | */ |
368 | template <typename K, typename T> |
369 | using IfIsNonStringDynamicConvertible = std::enable_if_t< |
370 | !std::is_convertible<K, StringPiece>::value && |
371 | std::is_convertible<K, dynamic>::value, |
372 | T>; |
373 | |
374 | template <typename K, typename T> |
375 | using IfNotIterator = |
376 | std::enable_if_t<!std::is_convertible<K, iterator>::value, T>; |
377 | |
378 | public: |
379 | /* |
380 | * You can iterate over the keys, values, or items (std::pair of key and |
381 | * value) in an object. Calling these on non-objects will throw a TypeError. |
382 | */ |
383 | IterableProxy<const_key_iterator> keys() const; |
384 | IterableProxy<const_value_iterator> values() const; |
385 | IterableProxy<const_item_iterator> items() const; |
386 | IterableProxy<value_iterator> values(); |
387 | IterableProxy<item_iterator> items(); |
388 | |
389 | /* |
390 | * AssociativeContainer-style find interface for objects. Throws if |
391 | * this is not an object. |
392 | * |
393 | * Returns: items().end() if the key is not present, or a |
394 | * const_item_iterator pointing to the item. |
395 | */ |
396 | template <typename K> |
397 | IfIsNonStringDynamicConvertible<K, const_item_iterator> find(K&&) const; |
398 | template <typename K> |
399 | IfIsNonStringDynamicConvertible<K, item_iterator> find(K&&); |
400 | |
401 | const_item_iterator find(StringPiece) const; |
402 | item_iterator find(StringPiece); |
403 | |
404 | /* |
405 | * If this is an object, returns whether it contains a field with |
406 | * the given name. Otherwise throws TypeError. |
407 | */ |
408 | template <typename K> |
409 | IfIsNonStringDynamicConvertible<K, std::size_t> count(K&&) const; |
410 | |
411 | std::size_t count(StringPiece) const; |
412 | |
413 | /* |
414 | * For objects or arrays, provides access to sub-fields by index or |
415 | * field name. |
416 | * |
417 | * Using these with dynamic objects that are not arrays or objects |
418 | * will throw a TypeError. Using an index that is out of range or |
419 | * object-element that's not present throws std::out_of_range. |
420 | */ |
421 | private: |
422 | dynamic const& atImpl(dynamic const&) const&; |
423 | |
424 | public: |
425 | template <typename K> |
426 | IfIsNonStringDynamicConvertible<K, dynamic const&> at(K&&) const&; |
427 | template <typename K> |
428 | IfIsNonStringDynamicConvertible<K, dynamic&> at(K&&) &; |
429 | template <typename K> |
430 | IfIsNonStringDynamicConvertible<K, dynamic&&> at(K&&) &&; |
431 | |
432 | dynamic const& at(StringPiece) const&; |
433 | dynamic& at(StringPiece) &; |
434 | dynamic&& at(StringPiece) &&; |
435 | |
436 | /* |
437 | * Locate element using JSON pointer, per RFC 6901 |
438 | */ |
439 | |
440 | enum class json_pointer_resolution_error_code : uint8_t { |
441 | other = 0, |
442 | // key not found in object |
443 | key_not_found, |
444 | // array index out of bounds |
445 | index_out_of_bounds, |
446 | // special index "-" requesting append |
447 | append_requested, |
448 | // indexes in arrays must be numeric |
449 | index_not_numeric, |
450 | // indexes in arrays should not have leading zero |
451 | index_has_leading_zero, |
452 | // element not subscribable, i.e. neither object or array |
453 | element_not_object_or_array, |
454 | // hit document boundary, but pointer not exhausted yet |
455 | json_pointer_out_of_bounds, |
456 | }; |
457 | |
458 | template <typename Dynamic> |
459 | struct json_pointer_resolution_error { |
460 | // error code encountered while resolving JSON pointer |
461 | json_pointer_resolution_error_code error_code{}; |
462 | // index of the JSON pointer's token that caused the error |
463 | size_t index{0}; |
464 | // Last correctly resolved element in object. You can use it, |
465 | // for example, to add last element to the array |
466 | Dynamic* context{nullptr}; |
467 | }; |
468 | |
469 | template <typename Dynamic> |
470 | struct json_pointer_resolved_value { |
471 | // parent element of the value in dynamic, if exist |
472 | Dynamic* parent{nullptr}; |
473 | // pointer to the value itself |
474 | Dynamic* value{nullptr}; |
475 | // if parent isObject, this is the key in object to get value |
476 | StringPiece parent_key; |
477 | // if parent isArray, this is the index in array to get value |
478 | size_t parent_index{0}; |
479 | }; |
480 | |
481 | // clang-format off |
482 | template <typename Dynamic> |
483 | using resolved_json_pointer = Expected< |
484 | json_pointer_resolved_value<Dynamic>, |
485 | json_pointer_resolution_error<Dynamic>>; |
486 | |
487 | resolved_json_pointer<dynamic const> |
488 | try_get_ptr(json_pointer const&) const&; |
489 | resolved_json_pointer<dynamic> |
490 | try_get_ptr(json_pointer const&) &; |
491 | resolved_json_pointer<dynamic const> |
492 | try_get_ptr(json_pointer const&) const&& = delete; |
493 | resolved_json_pointer<dynamic const> |
494 | try_get_ptr(json_pointer const&) && = delete; |
495 | // clang-format on |
496 | |
497 | /* |
498 | * The following versions return nullptr if element could not be located. |
499 | * Throws if pointer does not match the shape of the document, e.g. uses |
500 | * string to index in array. |
501 | */ |
502 | const dynamic* get_ptr(json_pointer const&) const&; |
503 | dynamic* get_ptr(json_pointer const&) &; |
504 | const dynamic* get_ptr(json_pointer const&) const&& = delete; |
505 | dynamic* get_ptr(json_pointer const&) && = delete; |
506 | |
507 | /* |
508 | * Like 'at', above, except it returns either a pointer to the contained |
509 | * object or nullptr if it wasn't found. This allows a key to be tested for |
510 | * containment and retrieved in one operation. Example: |
511 | * |
512 | * if (auto* found = d.get_ptr(key)) |
513 | * // use *found; |
514 | * |
515 | * Using these with dynamic objects that are not arrays or objects |
516 | * will throw a TypeError. |
517 | */ |
518 | private: |
519 | const dynamic* get_ptrImpl(dynamic const&) const&; |
520 | |
521 | public: |
522 | template <typename K> |
523 | IfIsNonStringDynamicConvertible<K, const dynamic*> get_ptr(K&&) const&; |
524 | template <typename K> |
525 | IfIsNonStringDynamicConvertible<K, dynamic*> get_ptr(K&&) &; |
526 | template <typename K> |
527 | IfIsNonStringDynamicConvertible<K, dynamic*> get_ptr(K&&) && = delete; |
528 | |
529 | const dynamic* get_ptr(StringPiece) const&; |
530 | dynamic* get_ptr(StringPiece) &; |
531 | dynamic* get_ptr(StringPiece) && = delete; |
532 | |
533 | /* |
534 | * This works for access to both objects and arrays. |
535 | * |
536 | * In the case of an array, the index must be an integer, and this |
537 | * will throw std::out_of_range if it is less than zero or greater |
538 | * than size(). |
539 | * |
540 | * In the case of an object, the non-const overload inserts a null |
541 | * value if the key isn't present. The const overload will throw |
542 | * std::out_of_range if the key is not present. |
543 | * |
544 | * These functions do not invalidate iterators except when a null value |
545 | * is inserted into an object as described above. |
546 | */ |
547 | template <typename K> |
548 | IfIsNonStringDynamicConvertible<K, dynamic&> operator[](K&&) &; |
549 | template <typename K> |
550 | IfIsNonStringDynamicConvertible<K, dynamic const&> operator[](K&&) const&; |
551 | template <typename K> |
552 | IfIsNonStringDynamicConvertible<K, dynamic&&> operator[](K&&) &&; |
553 | |
554 | dynamic& operator[](StringPiece) &; |
555 | dynamic const& operator[](StringPiece) const&; |
556 | dynamic&& operator[](StringPiece) &&; |
557 | |
558 | /* |
559 | * Only defined for objects, throws TypeError otherwise. |
560 | * |
561 | * getDefault will return the value associated with the supplied key, the |
562 | * supplied default otherwise. setDefault will set the key to the supplied |
563 | * default if it is not yet set, otherwise leaving it. setDefault returns |
564 | * a reference to the existing value if present, the new value otherwise. |
565 | */ |
566 | template <typename K> |
567 | IfIsNonStringDynamicConvertible<K, dynamic> getDefault( |
568 | K&& k, |
569 | const dynamic& v = dynamic::object) const&; |
570 | template <typename K> |
571 | IfIsNonStringDynamicConvertible<K, dynamic> getDefault(K&& k, dynamic&& v) |
572 | const&; |
573 | template <typename K> |
574 | IfIsNonStringDynamicConvertible<K, dynamic> getDefault( |
575 | K&& k, |
576 | const dynamic& v = dynamic::object) &&; |
577 | template <typename K> |
578 | IfIsNonStringDynamicConvertible<K, dynamic> getDefault(K&& k, dynamic&& v) &&; |
579 | |
580 | dynamic getDefault(StringPiece k, const dynamic& v = dynamic::object) const&; |
581 | dynamic getDefault(StringPiece k, dynamic&& v) const&; |
582 | dynamic getDefault(StringPiece k, const dynamic& v = dynamic::object) &&; |
583 | dynamic getDefault(StringPiece k, dynamic&& v) &&; |
584 | |
585 | template <typename K, typename V> |
586 | IfIsNonStringDynamicConvertible<K, dynamic&> setDefault(K&& k, V&& v); |
587 | template <typename V> |
588 | dynamic& setDefault(StringPiece k, V&& v); |
589 | // MSVC 2015 Update 3 needs these extra overloads because if V were a |
590 | // defaulted template parameter, it causes MSVC to consider v an rvalue |
591 | // reference rather than a universal reference, resulting in it not being |
592 | // able to find the correct overload to construct a dynamic with. |
593 | template <typename K> |
594 | IfIsNonStringDynamicConvertible<K, dynamic&> setDefault(K&& k, dynamic&& v); |
595 | template <typename K> |
596 | IfIsNonStringDynamicConvertible<K, dynamic&> setDefault( |
597 | K&& k, |
598 | const dynamic& v = dynamic::object); |
599 | |
600 | dynamic& setDefault(StringPiece k, dynamic&& v); |
601 | dynamic& setDefault(StringPiece k, const dynamic& v = dynamic::object); |
602 | |
603 | /* |
604 | * Resizes an array so it has at n elements, using the supplied |
605 | * default to fill new elements. Throws TypeError if this dynamic |
606 | * is not an array. |
607 | * |
608 | * May invalidate iterators. |
609 | * |
610 | * Post: size() == n |
611 | */ |
612 | void resize(std::size_t n, dynamic const& = nullptr); |
613 | |
614 | /* |
615 | * Inserts the supplied key-value pair to an object, or throws if |
616 | * it's not an object. If the key already exists, insert will overwrite the |
617 | * value, i.e., similar to insert_or_assign. |
618 | * |
619 | * Invalidates iterators. |
620 | */ |
621 | template <class K, class V> |
622 | IfNotIterator<K, void> insert(K&&, V&& val); |
623 | |
624 | /* |
625 | * Inserts the supplied value into array, or throw if not array |
626 | * Shifts existing values in the array to the right |
627 | * |
628 | * Invalidates iterators. |
629 | */ |
630 | template <class T> |
631 | iterator insert(const_iterator pos, T&& value); |
632 | |
633 | /* |
634 | * These functions merge two folly dynamic objects. |
635 | * The "update" and "update_missing" functions extend the object by |
636 | * inserting the key/value pairs of mergeObj into the current object. |
637 | * For update, if key is duplicated between the two objects, it |
638 | * will overwrite with the value of the object being inserted (mergeObj). |
639 | * For "update_missing", it will prefer the value in the original object |
640 | * |
641 | * The "merge" function creates a new object consisting of the key/value |
642 | * pairs of both mergeObj1 and mergeObj2 |
643 | * If the key is duplicated between the two objects, |
644 | * it will prefer value in the second object (mergeObj2) |
645 | */ |
646 | void update(const dynamic& mergeObj); |
647 | void update_missing(const dynamic& other); |
648 | static dynamic merge(const dynamic& mergeObj1, const dynamic& mergeObj2); |
649 | |
650 | /* |
651 | * Implement recursive version of RFC7386: JSON merge patch. This modifies |
652 | * the current object. |
653 | */ |
654 | void merge_patch(const dynamic& patch); |
655 | |
656 | /* |
657 | * Computes JSON merge patch (RFC7386) needed to mutate from source to target |
658 | */ |
659 | static dynamic merge_diff(const dynamic& source, const dynamic& target); |
660 | |
661 | /* |
662 | * Erase an element from a dynamic object, by key. |
663 | * |
664 | * Invalidates iterators to the element being erased. |
665 | * |
666 | * Returns the number of elements erased (i.e. 1 or 0). |
667 | */ |
668 | template <typename K> |
669 | IfIsNonStringDynamicConvertible<K, std::size_t> erase(K&&); |
670 | |
671 | std::size_t erase(StringPiece); |
672 | |
673 | /* |
674 | * Erase an element from a dynamic object or array, using an |
675 | * iterator or an iterator range. |
676 | * |
677 | * In arrays, invalidates iterators to elements after the element |
678 | * being erased. In objects, invalidates iterators to the elements |
679 | * being erased. |
680 | * |
681 | * Returns a new iterator to the first element beyond any elements |
682 | * removed, or end() if there are none. (The iteration order does |
683 | * not change.) |
684 | */ |
685 | iterator erase(const_iterator it); |
686 | iterator erase(const_iterator first, const_iterator last); |
687 | |
688 | const_key_iterator erase(const_key_iterator it); |
689 | const_key_iterator erase(const_key_iterator first, const_key_iterator last); |
690 | |
691 | value_iterator erase(const_value_iterator it); |
692 | value_iterator erase(const_value_iterator first, const_value_iterator last); |
693 | |
694 | item_iterator erase(const_item_iterator it); |
695 | item_iterator erase(const_item_iterator first, const_item_iterator last); |
696 | /* |
697 | * Append elements to an array. If this is not an array, throws |
698 | * TypeError. |
699 | * |
700 | * Invalidates iterators. |
701 | */ |
702 | void push_back(dynamic const&); |
703 | void push_back(dynamic&&); |
704 | |
705 | /* |
706 | * Remove an element from the back of an array. If this is not an array, |
707 | * throws TypeError. |
708 | * |
709 | * Does not invalidate iterators. |
710 | */ |
711 | void pop_back(); |
712 | |
713 | /* |
714 | * Get a hash code. This function is called by a std::hash<> |
715 | * specialization, also. |
716 | * |
717 | * Throws TypeError if this is an object, array, or null. |
718 | */ |
719 | std::size_t hash() const; |
720 | |
721 | private: |
722 | friend struct TypeError; |
723 | struct ObjectImpl; |
724 | template <class T> |
725 | struct TypeInfo; |
726 | template <class T> |
727 | struct CompareOp; |
728 | template <class T> |
729 | struct GetAddrImpl; |
730 | template <class T> |
731 | struct PrintImpl; |
732 | |
733 | explicit dynamic(Array&& array); |
734 | |
735 | template <class T> |
736 | T const& get() const; |
737 | template <class T> |
738 | T& get(); |
739 | // clang-format off |
740 | template <class T> |
741 | T* get_nothrow() & noexcept; |
742 | // clang-format on |
743 | template <class T> |
744 | T const* get_nothrow() const& noexcept; |
745 | // clang-format off |
746 | template <class T> |
747 | T* get_nothrow() && noexcept = delete; |
748 | // clang-format on |
749 | template <class T> |
750 | T* getAddress() noexcept; |
751 | template <class T> |
752 | T const* getAddress() const noexcept; |
753 | |
754 | template <class T> |
755 | T asImpl() const; |
756 | |
757 | static char const* typeName(Type); |
758 | void destroy() noexcept; |
759 | void print(std::ostream&) const; |
760 | void print_as_pseudo_json(std::ostream&) const; // see json.cpp |
761 | |
762 | private: |
763 | Type type_; |
764 | union Data { |
765 | explicit Data() : nul(nullptr) {} |
766 | ~Data() {} |
767 | |
768 | std::nullptr_t nul; |
769 | Array array; |
770 | bool boolean; |
771 | double doubl; |
772 | int64_t integer; |
773 | std::string string; |
774 | |
775 | /* |
776 | * Objects are placement new'd here. We have to use a char buffer |
777 | * because we don't know the type here (F14NodeMap<> with |
778 | * dynamic would be parameterizing a std:: template with an |
779 | * incomplete type right now). (Note that in contrast we know it |
780 | * is ok to do this with fbvector because we own it.) |
781 | */ |
782 | aligned_storage_for_t<F14NodeMap<int, int>> objectBuffer; |
783 | } u_; |
784 | }; |
785 | |
786 | ////////////////////////////////////////////////////////////////////// |
787 | |
788 | } // namespace folly |
789 | |
790 | #include <folly/dynamic-inl.h> |
791 | |