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 /**
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 <folly/Expected.h>
64 #include <folly/Range.h>
65 #include <folly/Traits.h>
66 #include <folly/container/F14Map.h>
67 #include <folly/json_pointer.h>
68
69 namespace folly {
70
71 //////////////////////////////////////////////////////////////////////
72
73 struct const_dynamic_view;
74 struct dynamic;
75 struct dynamic_view;
76 struct TypeError;
77
78 //////////////////////////////////////////////////////////////////////
79
80 namespace dynamic_detail {
81 template <typename T>
82 using detect_construct_string = decltype(std::string(
83 FOLLY_DECLVAL(T const&).data(), FOLLY_DECLVAL(T const&).size()));
84 }
85
86 struct dynamic {
87 enum Type {
88 NULLT,
89 ARRAY,
90 BOOL,
91 DOUBLE,
92 INT64,
93 OBJECT,
94 STRING,
95 };
96 template <class T, class Enable = void>
97 struct NumericTypeHelper;
98
99 /*
100 * We support direct iteration of arrays, and indirect iteration of objects.
101 * See begin(), end(), keys(), values(), and items() for more.
102 *
103 * Array iterators dereference as the elements in the array.
104 * Object key iterators dereference as the keys in the object.
105 * Object value iterators dereference as the values in the object.
106 * Object item iterators dereference as pairs of (key, value).
107 */
108 private:
109 typedef std::vector<dynamic> Array;
110
111 /*
112 * Violating spec, std::vector<bool>::const_reference is not bool in libcpp:
113 * http://howardhinnant.github.io/onvectorbool.html
114 *
115 * This is used to add a public ctor which is only enabled under libcpp taking
116 * std::vector<bool>::const_reference without using the preprocessor.
117 */
118 struct VectorBoolConstRefFake : std::false_type {};
119 using VectorBoolConstRefCtorType = std::conditional_t<
120 std::is_same<std::vector<bool>::const_reference, bool>::value,
121 VectorBoolConstRefFake,
122 std::vector<bool>::const_reference>;
123
124 public:
125 typedef Array::iterator iterator;
126 typedef Array::const_iterator const_iterator;
127 typedef dynamic value_type;
128
129 struct const_key_iterator;
130 struct const_value_iterator;
131 struct const_item_iterator;
132
133 struct value_iterator;
134 struct item_iterator;
135
136 /*
137 * Creation routines for making dynamic objects and arrays. Objects
138 * are maps from key to value (so named due to json-related origins
139 * here).
140 *
141 * Example:
142 *
143 * // Make a fairly complex dynamic:
144 * dynamic d = dynamic::object("key", "value1")
145 * ("key2", dynamic::array("value",
146 * "with",
147 * 4,
148 * "words"));
149 *
150 * // Build an object in a few steps:
151 * dynamic d = dynamic::object;
152 * d["key"] = 12;
153 * d["something_else"] = dynamic::array(1, 2, 3, nullptr);
154 */
155 private:
156 struct EmptyArrayTag {};
157 struct ObjectMaker;
158
159 public:
160 static void array(EmptyArrayTag);
161 template <class... Args>
162 static dynamic array(Args&&... args);
163
164 static ObjectMaker object();
165 static ObjectMaker object(dynamic, dynamic);
166
167 /**
168 * Default constructor, initializes with nullptr.
169 */
170 dynamic();
171
172 /*
173 * String compatibility constructors.
174 */
175 /* implicit */ dynamic(std::nullptr_t);
176 /* implicit */ dynamic(char const* val);
177 /* implicit */ dynamic(std::string val);
178 template <
179 typename Stringish,
180 typename = std::enable_if_t<
181 is_detected_v<dynamic_detail::detect_construct_string, Stringish>>>
182 /* implicit */ dynamic(Stringish&& s);
183
184 /*
185 * This is part of the plumbing for array() and object(), above.
186 * Used to create a new array or object dynamic.
187 */
188 /* implicit */ dynamic(void (*)(EmptyArrayTag));
189 /* implicit */ dynamic(ObjectMaker (*)());
190 /* implicit */ dynamic(ObjectMaker const&) = delete;
191 /* implicit */ dynamic(ObjectMaker&&);
192
193 /*
194 * Constructors for integral and float types.
195 * Other types are SFINAEd out with NumericTypeHelper.
196 */
197 template <class T, class NumericType = typename NumericTypeHelper<T>::type>
198 /* implicit */ dynamic(T t);
199
200 /*
201 * If v is vector<bool>, v[idx] is a proxy object implicitly convertible to
202 * bool. Calling a function f(dynamic) with f(v[idx]) would require a double
203 * implicit conversion (reference -> bool -> dynamic) which is not allowed,
204 * hence we explicitly accept the reference proxy.
205 */
206 /* implicit */ dynamic(std::vector<bool>::reference val);
207 /* implicit */ dynamic(VectorBoolConstRefCtorType val);
208
209 /*
210 * Create a dynamic that is an array of the values from the supplied
211 * iterator range.
212 */
213 template <class Iterator>
214 explicit dynamic(Iterator first, Iterator last);
215
216 dynamic(dynamic const&);
217 dynamic(dynamic&&) noexcept;
218 ~dynamic() noexcept;
219
220 /*
221 * "Deep" equality comparison. This will compare all the way down
222 * an object or array, and is potentially expensive.
223 */
224 friend bool operator==(dynamic const& a, dynamic const& b);
225 friend bool operator!=(dynamic const& a, dynamic const& b) {
226 return !(a == b);
227 }
228
229 /*
230 * For all types except object this returns the natural ordering on
231 * those types. For objects, we throw TypeError.
232 */
233 friend bool operator<(dynamic const& a, dynamic const& b);
234 friend bool operator>(dynamic const& a, dynamic const& b) { return b < a; }
235 friend bool operator<=(dynamic const& a, dynamic const& b) {
236 return !(b < a);
237 }
238 friend bool operator>=(dynamic const& a, dynamic const& b) {
239 return !(a < b);
240 }
241
242 /*
243 * General operators.
244 *
245 * These throw TypeError when used with types or type combinations
246 * that don't support them.
247 *
248 * These functions may also throw if you use 64-bit integers with
249 * doubles when the integers are too big to fit in a double.
250 */
251 dynamic& operator+=(dynamic const&);
252 dynamic& operator-=(dynamic const&);
253 dynamic& operator*=(dynamic const&);
254 dynamic& operator/=(dynamic const&);
255 dynamic& operator%=(dynamic const&);
256 dynamic& operator|=(dynamic const&);
257 dynamic& operator&=(dynamic const&);
258 dynamic& operator^=(dynamic const&);
259 dynamic& operator++();
260 dynamic& operator--();
261
262 friend dynamic operator+(dynamic const& a, dynamic const& b) {
263 return std::move(copy(a) += b);
264 }
265 friend dynamic operator-(dynamic const& a, dynamic const& b) {
266 return std::move(copy(a) -= b);
267 }
268 friend dynamic operator*(dynamic const& a, dynamic const& b) {
269 return std::move(copy(a) *= b);
270 }
271 friend dynamic operator/(dynamic const& a, dynamic const& b) {
272 return std::move(copy(a) /= b);
273 }
274 friend dynamic operator%(dynamic const& a, dynamic const& b) {
275 return std::move(copy(a) %= b);
276 }
277 friend dynamic operator|(dynamic const& a, dynamic const& b) {
278 return std::move(copy(a) |= b);
279 }
280 friend dynamic operator&(dynamic const& a, dynamic const& b) {
281 return std::move(copy(a) &= b);
282 }
283 friend dynamic operator^(dynamic const& a, dynamic const& b) {
284 return std::move(copy(a) ^= b);
285 }
286
287 friend dynamic operator+(dynamic&& a, dynamic const& b) {
288 return std::move(a += b);
289 }
290
291 dynamic operator++(int) {
292 auto self = *this;
293 return ++*this, self;
294 }
295 dynamic operator--(int) {
296 auto self = *this;
297 return --*this, self;
298 }
299
300 /*
301 * Assignment from other dynamics. Because of the implicit conversion
302 * to dynamic from its potential types, you can use this to change the
303 * type pretty intuitively.
304 *
305 * Basic guarantee only.
306 */
307 dynamic& operator=(dynamic const&);
308 dynamic& operator=(dynamic&&) noexcept;
309
310 /*
311 * For simple dynamics (not arrays or objects), this prints the
312 * value to an std::ostream in the expected way. Respects the
313 * formatting manipulators that have been sent to the stream
314 * already.
315 *
316 * If the dynamic holds an object or array, this prints them in a
317 * format very similar to JSON. (It will in fact actually be JSON
318 * as long as the dynamic validly represents a JSON object---i.e. it
319 * can't have non-string keys.)
320 */
321 friend std::ostream& operator<<(std::ostream&, dynamic const&);
322
323 /*
324 * Returns true if this dynamic is of the specified type.
325 */
326 bool isString() const;
327 bool isObject() const;
328 bool isBool() const;
329 bool isNull() const;
330 bool isArray() const;
331 bool isDouble() const;
332 bool isInt() const;
333
334 /*
335 * Returns: isInt() || isDouble().
336 */
337 bool isNumber() const;
338
339 /*
340 * Returns the type of this dynamic.
341 */
342 Type type() const;
343
344 /*
345 * Returns the type of this dynamic as a printable string.
346 */
347 const char* typeName() const;
348
349 /*
350 * Extract a value while trying to convert to the specified type.
351 * Throws exceptions if we cannot convert from the real type to the
352 * requested type.
353 *
354 * Note you can only use this to access integral types or strings,
355 * since arrays and objects are generally best dealt with as a
356 * dynamic.
357 */
358 std::string asString() const;
359 double asDouble() const;
360 int64_t asInt() const;
361 bool asBool() const;
362
363 /*
364 * Extract the value stored in this dynamic without type conversion.
365 *
366 * These will throw a TypeError if the dynamic has a different type.
367 */
368 const std::string& getString() const&;
369 double getDouble() const&;
370 int64_t getInt() const&;
371 bool getBool() const&;
372 std::string& getString() &;
373 double& getDouble() &;
374 int64_t& getInt() &;
375 bool& getBool() &;
376 std::string&& getString() &&;
377 double getDouble() &&;
378 int64_t getInt() &&;
379 bool getBool() &&;
380
381 /*
382 * It is occasionally useful to access a string's internal pointer
383 * directly, without the type conversion of `asString()`.
384 *
385 * These will throw a TypeError if the dynamic is not a string.
386 */
387 const char* c_str() const&;
388 const char* c_str() && = delete;
389 StringPiece stringPiece() const;
390
391 /*
392 * Returns: true if this dynamic is null, an empty array, an empty
393 * object, or an empty string.
394 */
395 bool empty() const;
396
397 /*
398 * If this is an array or an object, returns the number of elements
399 * contained. If it is a string, returns the length. Otherwise
400 * throws TypeError.
401 */
402 std::size_t size() const;
403
404 /*
405 * You can iterate over the values of the array. Calling these on
406 * non-arrays will throw a TypeError.
407 */
408 const_iterator begin() const;
409 const_iterator end() const;
410 iterator begin();
411 iterator end();
412
413 private:
414 /*
415 * Helper object returned by keys(), values(), and items().
416 */
417 template <class T>
418 struct IterableProxy;
419
420 /*
421 * Helper for heterogeneous lookup and mutation on objects: at(), find(),
422 * count(), erase(), operator[]
423 */
424 template <typename K, typename T>
425 using IfIsNonStringDynamicConvertible = std::enable_if_t<
426 !std::is_convertible<K, StringPiece>::value &&
427 std::is_convertible<K, dynamic>::value,
428 T>;
429
430 template <typename K, typename T>
431 using IfNotIterator =
432 std::enable_if_t<!std::is_convertible<K, iterator>::value, T>;
433
434 public:
435 /*
436 * You can iterate over the keys, values, or items (std::pair of key and
437 * value) in an object. Calling these on non-objects will throw a TypeError.
438 */
439 IterableProxy<const_key_iterator> keys() const;
440 IterableProxy<const_value_iterator> values() const;
441 IterableProxy<const_item_iterator> items() const;
442 IterableProxy<value_iterator> values();
443 IterableProxy<item_iterator> items();
444
445 /*
446 * AssociativeContainer-style find interface for objects. Throws if
447 * this is not an object.
448 *
449 * Returns: items().end() if the key is not present, or a
450 * const_item_iterator pointing to the item.
451 */
452 template <typename K>
453 IfIsNonStringDynamicConvertible<K, const_item_iterator> find(K&&) const;
454 template <typename K>
455 IfIsNonStringDynamicConvertible<K, item_iterator> find(K&&);
456
457 const_item_iterator find(StringPiece) const;
458 item_iterator find(StringPiece);
459
460 /*
461 * If this is an object, returns whether it contains a field with
462 * the given name. Otherwise throws TypeError.
463 */
464 template <typename K>
465 IfIsNonStringDynamicConvertible<K, std::size_t> count(K&&) const;
466
467 std::size_t count(StringPiece) const;
468
469 /*
470 * For objects or arrays, provides access to sub-fields by index or
471 * field name.
472 *
473 * Using these with dynamic objects that are not arrays or objects
474 * will throw a TypeError. Using an index that is out of range or
475 * object-element that's not present throws std::out_of_range.
476 */
477 private:
478 dynamic const& atImpl(dynamic const&) const&;
479
480 public:
481 template <typename K>
482 IfIsNonStringDynamicConvertible<K, dynamic const&> at(K&&) const&;
483 template <typename K>
484 IfIsNonStringDynamicConvertible<K, dynamic&> at(K&&) &;
485 template <typename K>
486 IfIsNonStringDynamicConvertible<K, dynamic&&> at(K&&) &&;
487
488 dynamic const& at(StringPiece) const&;
489 dynamic& at(StringPiece) &;
490 dynamic&& at(StringPiece) &&;
491
492 /*
493 * Locate element using JSON pointer, per RFC 6901
494 */
495
496 enum class json_pointer_resolution_error_code : uint8_t {
497 other = 0,
498 // key not found in object
499 key_not_found,
500 // array index out of bounds
501 index_out_of_bounds,
502 // special index "-" requesting append
503 append_requested,
504 // indexes in arrays must be numeric
505 index_not_numeric,
506 // indexes in arrays should not have leading zero
507 index_has_leading_zero,
508 // element not subscribable, i.e. neither object or array
509 element_not_object_or_array,
510 // hit document boundary, but pointer not exhausted yet
511 json_pointer_out_of_bounds,
512 };
513
514 template <typename Dynamic>
515 struct json_pointer_resolution_error {
516 // error code encountered while resolving JSON pointer
517 json_pointer_resolution_error_code error_code{};
518 // index of the JSON pointer's token that caused the error
519 size_t index{0};
520 // Last correctly resolved element in object. You can use it,
521 // for example, to add last element to the array
522 Dynamic* context{nullptr};
523 };
524
525 template <typename Dynamic>
526 struct json_pointer_resolved_value {
527 // parent element of the value in dynamic, if exist
528 Dynamic* parent{nullptr};
529 // pointer to the value itself
530 Dynamic* value{nullptr};
531 // if parent isObject, this is the key in object to get value
532 StringPiece parent_key;
533 // if parent isArray, this is the index in array to get value
534 size_t parent_index{0};
535 };
536
537 // clang-format off
538 template <typename Dynamic>
539 using resolved_json_pointer = Expected<
540 json_pointer_resolved_value<Dynamic>,
541 json_pointer_resolution_error<Dynamic>>;
542
543 resolved_json_pointer<dynamic const>
544 try_get_ptr(json_pointer const&) const&;
545 resolved_json_pointer<dynamic>
546 try_get_ptr(json_pointer const&) &;
547 resolved_json_pointer<dynamic const>
548 try_get_ptr(json_pointer const&) const&& = delete;
549 resolved_json_pointer<dynamic const>
550 try_get_ptr(json_pointer const&) && = delete;
551 // clang-format on
552
553 /*
554 * The following versions return nullptr if element could not be located.
555 * Throws if pointer does not match the shape of the document, e.g. uses
556 * string to index in array.
557 */
558 const dynamic* get_ptr(json_pointer const&) const&;
559 dynamic* get_ptr(json_pointer const&) &;
560 const dynamic* get_ptr(json_pointer const&) const&& = delete;
561 dynamic* get_ptr(json_pointer const&) && = delete;
562
563 /*
564 * Like 'at', above, except it returns either a pointer to the contained
565 * object or nullptr if it wasn't found. This allows a key to be tested for
566 * containment and retrieved in one operation. Example:
567 *
568 * if (auto* found = d.get_ptr(key))
569 * // use *found;
570 *
571 * Using these with dynamic objects that are not arrays or objects
572 * will throw a TypeError.
573 */
574 private:
575 const dynamic* get_ptrImpl(dynamic const&) const&;
576
577 public:
578 template <typename K>
579 IfIsNonStringDynamicConvertible<K, const dynamic*> get_ptr(K&&) const&;
580 template <typename K>
581 IfIsNonStringDynamicConvertible<K, dynamic*> get_ptr(K&&) &;
582 template <typename K>
583 IfIsNonStringDynamicConvertible<K, dynamic*> get_ptr(K&&) && = delete;
584
585 const dynamic* get_ptr(StringPiece) const&;
586 dynamic* get_ptr(StringPiece) &;
587 dynamic* get_ptr(StringPiece) && = delete;
588
589 /*
590 * This works for access to both objects and arrays.
591 *
592 * In the case of an array, the index must be an integer, and this
593 * will throw std::out_of_range if it is less than zero or greater
594 * than size().
595 *
596 * In the case of an object, the non-const overload inserts a null
597 * value if the key isn't present. The const overload will throw
598 * std::out_of_range if the key is not present.
599 *
600 * These functions do not invalidate iterators except when a null value
601 * is inserted into an object as described above.
602 */
603 template <typename K>
604 IfIsNonStringDynamicConvertible<K, dynamic&> operator[](K&&) &;
605 template <typename K>
606 IfIsNonStringDynamicConvertible<K, dynamic const&> operator[](K&&) const&;
607 template <typename K>
608 IfIsNonStringDynamicConvertible<K, dynamic&&> operator[](K&&) &&;
609
610 dynamic& operator[](StringPiece) &;
611 dynamic const& operator[](StringPiece) const&;
612 dynamic&& operator[](StringPiece) &&;
613
614 /*
615 * Only defined for objects, throws TypeError otherwise.
616 *
617 * getDefault will return the value associated with the supplied key, the
618 * supplied default otherwise. setDefault will set the key to the supplied
619 * default if it is not yet set, otherwise leaving it. setDefault returns
620 * a reference to the existing value if present, the new value otherwise.
621 */
622 template <typename K>
623 IfIsNonStringDynamicConvertible<K, dynamic> getDefault(
624 K&& k, const dynamic& v = dynamic::object) const&;
625 template <typename K>
626 IfIsNonStringDynamicConvertible<K, dynamic> getDefault(
627 K&& k, dynamic&& v) const&;
628 template <typename K>
629 IfIsNonStringDynamicConvertible<K, dynamic> getDefault(
630 K&& k, const dynamic& v = dynamic::object) &&;
631 template <typename K>
632 IfIsNonStringDynamicConvertible<K, dynamic> getDefault(K&& k, dynamic&& v) &&;
633
634 dynamic getDefault(StringPiece k, const dynamic& v = dynamic::object) const&;
635 dynamic getDefault(StringPiece k, dynamic&& v) const&;
636 dynamic getDefault(StringPiece k, const dynamic& v = dynamic::object) &&;
637 dynamic getDefault(StringPiece k, dynamic&& v) &&;
638
639 template <typename K, typename V>
640 IfIsNonStringDynamicConvertible<K, dynamic&> setDefault(K&& k, V&& v);
641 template <typename V>
642 dynamic& setDefault(StringPiece k, V&& v);
643 // MSVC 2015 Update 3 needs these extra overloads because if V were a
644 // defaulted template parameter, it causes MSVC to consider v an rvalue
645 // reference rather than a universal reference, resulting in it not being
646 // able to find the correct overload to construct a dynamic with.
647 template <typename K>
648 IfIsNonStringDynamicConvertible<K, dynamic&> setDefault(K&& k, dynamic&& v);
649 template <typename K>
650 IfIsNonStringDynamicConvertible<K, dynamic&> setDefault(
651 K&& k, const dynamic& v = dynamic::object);
652
653 dynamic& setDefault(StringPiece k, dynamic&& v);
654 dynamic& setDefault(StringPiece k, const dynamic& v = dynamic::object);
655
656 /*
657 * Resizes an array so it has at n elements, using the supplied
658 * default to fill new elements. Throws TypeError if this dynamic
659 * is not an array.
660 *
661 * May invalidate iterators.
662 *
663 * Post: size() == n
664 */
665 void resize(std::size_t n, dynamic const& = nullptr);
666
667 /*
668 * Inserts the supplied key-value pair to an object, or throws if
669 * it's not an object. If the key already exists, insert will overwrite the
670 * value, i.e., similar to insert_or_assign.
671 *
672 * Invalidates iterators.
673 */
674 template <class K, class V>
675 IfNotIterator<K, void> insert(K&&, V&& val);
676
677 /*
678 * Inserts the supplied value into array, or throw if not array
679 * Shifts existing values in the array to the right
680 *
681 * Invalidates iterators.
682 */
683 template <class T>
684 iterator insert(const_iterator pos, T&& value);
685
686 /*
687 * These functions merge two folly dynamic objects.
688 * The "update" and "update_missing" functions extend the object by
689 * inserting the key/value pairs of mergeObj into the current object.
690 * For update, if key is duplicated between the two objects, it
691 * will overwrite with the value of the object being inserted (mergeObj).
692 * For "update_missing", it will prefer the value in the original object
693 *
694 * The "merge" function creates a new object consisting of the key/value
695 * pairs of both mergeObj1 and mergeObj2
696 * If the key is duplicated between the two objects,
697 * it will prefer value in the second object (mergeObj2)
698 */
699 void update(const dynamic& mergeObj);
700 void update_missing(const dynamic& other);
701 static dynamic merge(const dynamic& mergeObj1, const dynamic& mergeObj2);
702
703 /*
704 * Implement recursive version of RFC7386: JSON merge patch. This modifies
705 * the current object.
706 */
707 void merge_patch(const dynamic& patch);
708
709 /*
710 * Computes JSON merge patch (RFC7386) needed to mutate from source to target
711 */
712 static dynamic merge_diff(const dynamic& source, const dynamic& target);
713
714 /*
715 * Erase an element from a dynamic object, by key.
716 *
717 * Invalidates iterators to the element being erased.
718 *
719 * Returns the number of elements erased (i.e. 1 or 0).
720 */
721 template <typename K>
722 IfIsNonStringDynamicConvertible<K, std::size_t> erase(K&&);
723
724 std::size_t erase(StringPiece);
725
726 /*
727 * Erase an element from a dynamic object or array, using an
728 * iterator or an iterator range.
729 *
730 * In arrays, invalidates iterators to elements after the element
731 * being erased. In objects, invalidates iterators to the elements
732 * being erased.
733 *
734 * Returns a new iterator to the first element beyond any elements
735 * removed, or end() if there are none. (The iteration order does
736 * not change.)
737 */
738 iterator erase(const_iterator it);
739 iterator erase(const_iterator first, const_iterator last);
740
741 const_key_iterator erase(const_key_iterator it);
742 const_key_iterator erase(const_key_iterator first, const_key_iterator last);
743
744 value_iterator erase(const_value_iterator it);
745 value_iterator erase(const_value_iterator first, const_value_iterator last);
746
747 item_iterator erase(const_item_iterator it);
748 item_iterator erase(const_item_iterator first, const_item_iterator last);
749 /*
750 * Append elements to an array. If this is not an array, throws
751 * TypeError.
752 *
753 * Invalidates iterators.
754 */
755 void push_back(dynamic const&);
756 void push_back(dynamic&&);
757
758 /*
759 * Remove an element from the back of an array. If this is not an array,
760 * throws TypeError.
761 *
762 * Does not invalidate iterators.
763 */
764 void pop_back();
765
766 /*
767 * Return reference to the last element in an array. If this is not
768 * an array, throws TypeError.
769 */
770 const dynamic& back() const;
771
772 /*
773 * Get a hash code. This function is called by a std::hash<>
774 * specialization, also.
775 *
776 * Throws TypeError if this is an object, array, or null.
777 */
778 std::size_t hash() const;
779
780 private:
781 friend struct const_dynamic_view;
782 friend struct dynamic_view;
783 friend struct TypeError;
784 struct ObjectImpl;
785 template <class T>
786 struct TypeInfo;
787 template <class T>
788 struct CompareOp;
789 template <class T>
790 struct GetAddrImpl;
791 template <class T>
792 struct PrintImpl;
793
794 explicit dynamic(Array&& array);
795
796 template <class T>
797 T const& get() const;
798 template <class T>
799 T& get();
800 // clang-format off
801 template <class T>
802 T* get_nothrow() & noexcept;
803 // clang-format on
804 template <class T>
805 T const* get_nothrow() const& noexcept;
806 // clang-format off
807 template <class T>
808 T* get_nothrow() && noexcept = delete;
809 // clang-format on
810 template <class T>
811 T* getAddress() noexcept;
812 template <class T>
813 T const* getAddress() const noexcept;
814
815 template <class T>
816 T asImpl() const;
817
818 static char const* typeName(Type);
819 void destroy() noexcept;
820 void print(std::ostream&) const;
821 void print_as_pseudo_json(std::ostream&) const; // see json.cpp
822
823 private:
824 Type type_;
825 union Data {
Data()826 explicit Data() : nul(nullptr) {}
~Data()827 ~Data() {}
828
829 std::nullptr_t nul;
830 Array array;
831 bool boolean;
832 double doubl;
833 int64_t integer;
834 std::string string;
835
836 /*
837 * Objects are placement new'd here. We have to use a char buffer
838 * because we don't know the type here (F14NodeMap<> with
839 * dynamic would be parameterizing a std:: template with an
840 * incomplete type right now). (Note that in contrast we know it
841 * is ok to do this with fbvector because we own it.)
842 */
843 aligned_storage_for_t<F14NodeMap<int, int>> objectBuffer;
844 } u_;
845 };
846
847 //////////////////////////////////////////////////////////////////////
848
849 /**
850 * This is a helper class for traversing an instance of dynamic and accessing
851 * the values within without risking throwing an exception. The primary use case
852 * is to help write cleaner code when using dynamic instances without strict
853 * schemas - eg. where keys may be missing, or present but with null values,
854 * when expecting non-null values.
855 *
856 * Some examples:
857 *
858 * dynamic twelve = 12;
859 * dynamic str = "string";
860 * dynamic map = dynamic::object("str", str)("twelve", 12);
861 *
862 * dynamic_view view{map};
863 * assert(view.descend("str").string_or("bad") == "string");
864 * assert(view.descend("twelve").int_or(-1) == 12);
865 * assert(view.descend("zzz").string_or("aaa") == "aaa");
866 *
867 * dynamic wrapper = dynamic::object("child", map);
868 * dynamic_view wrapper_view{wrapper};
869 *
870 * assert(wrapper_view.descend("child", "str").string_or("bad") == "string");
871 * assert(wrapper_view.descend("wrong", 0, "huh").value_or(nullptr).isNull());
872 */
873 struct const_dynamic_view {
874 // Empty view.
875 const_dynamic_view() noexcept = default;
876
877 // Basic view constructor. Creates a view of the referenced dynamic.
878 /* implicit */ const_dynamic_view(dynamic const& d) noexcept;
879
880 const_dynamic_view(const_dynamic_view const&) noexcept = default;
881 const_dynamic_view& operator=(const_dynamic_view const&) noexcept = default;
882
883 // Allow conversion from mutable to immutable view.
884 /* implicit */ const_dynamic_view(dynamic_view& view) noexcept;
885 /* implicit */ const_dynamic_view& operator=(dynamic_view& view) noexcept;
886
887 // Never view a temporary.
888 explicit const_dynamic_view(dynamic&&) = delete;
889
890 // Returns true if this view is backed by a valid dynamic, false otherwise.
891 explicit operator bool() const noexcept;
892
893 // Returns true if this view is not backed by a dynamic, false otherwise.
894 bool empty() const noexcept;
895
896 // Resets the view to a default constructed state not backed by any dynamic.
897 void reset() noexcept;
898
899 // Traverse a dynamic by repeatedly applying operator[].
900 // If all keys are valid, then the returned view will be backed by the
901 // accessed dynamic, otherwise it will be empty.
902 template <typename Key, typename... Keys>
903 const_dynamic_view descend(
904 Key const& key, Keys const&... keys) const noexcept;
905
906 // Untyped accessor. Returns a copy of the viewed dynamic, or the default
907 // value given if this view is empty, or a null dynamic otherwise.
908 dynamic value_or(dynamic&& val = nullptr) const;
909
910 // The following accessors provide a read-only exception-safe API for
911 // accessing the underlying viewed dynamic. Unlike the main dynamic APIs,
912 // these follow a stricter contract, which also requires a caller-provided
913 // default argument.
914 // - TypeError will not be thrown. primitive accessors further are marked
915 // noexcept.
916 // - No type conversions are performed. If the viewed dynamic does not match
917 // the requested type, the default argument is returned instead.
918 // - If the view is empty, the default argument is returned instead.
919 std::string string_or(char const* val) const;
920 std::string string_or(std::string val) const;
921 template <
922 typename Stringish,
923 typename = std::enable_if_t<
924 is_detected_v<dynamic_detail::detect_construct_string, Stringish>>>
925 std::string string_or(Stringish&& val) const;
926
927 double double_or(double val) const noexcept;
928
929 int64_t int_or(int64_t val) const noexcept;
930
931 bool bool_or(bool val) const noexcept;
932
933 protected:
934 /* implicit */ const_dynamic_view(dynamic const* d) noexcept;
935
936 template <typename Key1, typename Key2, typename... Keys>
937 dynamic const* descend_(
938 Key1 const& key1, Key2 const& key2, Keys const&... keys) const noexcept;
939 template <typename Key>
940 dynamic const* descend_(Key const& key) const noexcept;
941 template <typename Key>
942 dynamic::IfIsNonStringDynamicConvertible<Key, dynamic const*>
943 descend_unchecked_(Key const& key) const noexcept;
944 dynamic const* descend_unchecked_(StringPiece key) const noexcept;
945
946 dynamic const* d_ = nullptr;
947
948 // Internal helper method for accessing a value by a type.
949 template <typename T, typename... Args>
950 T get_copy(Args&&... args) const;
951 };
952
953 struct dynamic_view : public const_dynamic_view {
954 // Empty view.
955 dynamic_view() noexcept = default;
956
957 // dynamic_view can be used to view non-const dynamics only.
958 /* implicit */ dynamic_view(dynamic& d) noexcept;
959
960 dynamic_view(dynamic_view const&) noexcept = default;
961 dynamic_view& operator=(dynamic_view const&) noexcept = default;
962
963 // dynamic_view can not view const dynamics.
964 explicit dynamic_view(dynamic const&) = delete;
965 // dynamic_view can not be initialized from a const_dynamic_view
966 explicit dynamic_view(const_dynamic_view const&) = delete;
967
968 // Like const_dynamic_view, but returns a dynamic_view.
969 template <typename Key, typename... Keys>
970 dynamic_view descend(Key const& key, Keys const&... keys) const noexcept;
971
972 // dynamic_view provides APIs which can mutably access the backed dynamic.
973 // 'mutably access' in this case means extracting the viewed dynamic or
974 // value to omit unnecessary copies. It does not mean writing through to
975 // the backed dynamic - this is still just a view, not a mutator.
976
977 // Moves the viewed dynamic into the returned value via std::move. If the view
978 // is not backed by a dynamic, returns a provided default, or a null dynamic.
979 // Postconditions for the backed dynamic are the same as for any dynamic that
980 // is moved-from. this->empty() == false.
981 dynamic move_value_or(dynamic&& val = nullptr) noexcept;
982
983 // Specific optimization for strings which can allocate, unlike the other
984 // scalar types. If the viewed dynamic is a string, the string value is
985 // std::move'd to initialize a new instance which is returned.
986 std::string move_string_or(std::string val) noexcept;
987 std::string move_string_or(char const* val);
988 template <
989 typename Stringish,
990 typename = std::enable_if_t<
991 is_detected_v<dynamic_detail::detect_construct_string, Stringish>>>
992 std::string move_string_or(Stringish&& val);
993
994 private:
995 template <typename T, typename... Args>
996 T get_move(Args&&... args);
997 };
998
999 // A helper method which returns a contextually-correct dynamic_view for the
1000 // given view. If passed a dynamic const&, returns a const_dynamic_view, and
1001 // if passed a dynamic&, returns a dynamic_view.
make_dynamic_view(dynamic const & d)1002 inline auto make_dynamic_view(dynamic const& d) {
1003 return const_dynamic_view{d};
1004 }
1005
make_dynamic_view(dynamic & d)1006 inline auto make_dynamic_view(dynamic& d) {
1007 return dynamic_view{d};
1008 }
1009
1010 auto make_dynamic_view(dynamic&&) = delete;
1011
1012 //////////////////////////////////////////////////////////////////////
1013
1014 } // namespace folly
1015
1016 #include <folly/dynamic-inl.h>
1017