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