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
71namespace folly {
72
73//////////////////////////////////////////////////////////////////////
74
75struct dynamic;
76struct TypeError;
77
78//////////////////////////////////////////////////////////////////////
79
80struct 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