2 * Copyright 2017 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
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.
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.
30 * dynamic twelve = 12;
31 * dynamic str = "string";
32 * dynamic map = dynamic::object;
34 * map[str + "another_str"] = dynamic::array("array", "of", 4, "elements");
35 * map.insert("null_element", nullptr);
37 * assert(map[str] == 13);
39 * // Building a complex object with a sub array inline:
40 * dynamic d = dynamic::object
42 * ("key2", dynamic::array("a", "array"))
45 * Also see folly/json.h for the serialization and deserialization
48 * Additional documentation is in folly/docs/Dynamic.md.
50 * @author Jordan DeLong <delong.j@fb.com>
59 #include <type_traits>
60 #include <unordered_map>
64 #include <boost/operators.hpp>
66 #include <folly/Range.h>
67 #include <folly/Traits.h>
71 //////////////////////////////////////////////////////////////////////
76 //////////////////////////////////////////////////////////////////////
78 struct dynamic : private boost::operators<dynamic> {
88 template <class T, class Enable = void> struct NumericTypeHelper;
91 * We support direct iteration of arrays, and indirect iteration of objects.
92 * See begin(), end(), keys(), values(), and items() for more.
94 * Array iterators dereference as the elements in the array.
95 * Object key iterators dereference as the keys in the object.
96 * Object value iterators dereference as the values in the object.
97 * Object item iterators dereference as pairs of (key, value).
100 typedef std::vector<dynamic> Array;
103 typedef Array::iterator iterator;
104 typedef Array::const_iterator const_iterator;
105 typedef dynamic value_type;
107 struct const_key_iterator;
108 struct const_value_iterator;
109 struct const_item_iterator;
111 struct value_iterator;
112 struct item_iterator;
115 * Creation routines for making dynamic objects and arrays. Objects
116 * are maps from key to value (so named due to json-related origins
121 * // Make a fairly complex dynamic:
122 * dynamic d = dynamic::object("key", "value1")
123 * ("key2", dynamic::array("value",
128 * // Build an object in a few steps:
129 * dynamic d = dynamic::object;
131 * d["something_else"] = dynamic::array(1, 2, 3, nullptr);
134 struct EmptyArrayTag {};
138 static void array(EmptyArrayTag);
139 template <class... Args>
140 static dynamic array(Args&& ...args);
142 static ObjectMaker object();
143 static ObjectMaker object(dynamic, dynamic);
146 * Default constructor, initializes with nullptr.
151 * String compatibility constructors.
153 /* implicit */ dynamic(std::nullptr_t);
154 /* implicit */ dynamic(StringPiece val);
155 /* implicit */ dynamic(char const* val);
156 /* implicit */ dynamic(std::string val);
159 * This is part of the plumbing for array() and object(), above.
160 * Used to create a new array or object dynamic.
162 /* implicit */ dynamic(void (*)(EmptyArrayTag));
163 /* implicit */ dynamic(ObjectMaker (*)());
164 /* implicit */ dynamic(ObjectMaker const&) = delete;
165 /* implicit */ dynamic(ObjectMaker&&);
168 * Constructors for integral and float types.
169 * Other types are SFINAEd out with NumericTypeHelper.
171 template <class T, class NumericType = typename NumericTypeHelper<T>::type>
172 /* implicit */ dynamic(T t);
175 * Create a dynamic that is an array of the values from the supplied
178 template <class Iterator>
179 explicit dynamic(Iterator first, Iterator last);
181 dynamic(dynamic const&);
182 dynamic(dynamic&&) noexcept;
186 * "Deep" equality comparison. This will compare all the way down
187 * an object or array, and is potentially expensive.
189 bool operator==(dynamic const& o) const;
192 * For all types except object this returns the natural ordering on
193 * those types. For objects, we throw TypeError.
195 bool operator<(dynamic const& o) const;
200 * These throw TypeError when used with types or type combinations
201 * that don't support them.
203 * These functions may also throw if you use 64-bit integers with
204 * doubles when the integers are too big to fit in a double.
206 dynamic& operator+=(dynamic const&);
207 dynamic& operator-=(dynamic const&);
208 dynamic& operator*=(dynamic const&);
209 dynamic& operator/=(dynamic const&);
210 dynamic& operator%=(dynamic const&);
211 dynamic& operator|=(dynamic const&);
212 dynamic& operator&=(dynamic const&);
213 dynamic& operator^=(dynamic const&);
214 dynamic& operator++();
215 dynamic& operator--();
218 * Assignment from other dynamics. Because of the implicit conversion
219 * to dynamic from its potential types, you can use this to change the
220 * type pretty intuitively.
222 * Basic guarantee only.
224 dynamic& operator=(dynamic const&);
225 dynamic& operator=(dynamic&&) noexcept;
228 * For simple dynamics (not arrays or objects), this prints the
229 * value to an std::ostream in the expected way. Respects the
230 * formatting manipulators that have been sent to the stream
233 * If the dynamic holds an object or array, this prints them in a
234 * format very similar to JSON. (It will in fact actually be JSON
235 * as long as the dynamic validly represents a JSON object---i.e. it
236 * can't have non-string keys.)
238 friend std::ostream& operator<<(std::ostream&, dynamic const&);
241 * Returns true if this dynamic is of the specified type.
243 bool isString() const;
244 bool isObject() const;
247 bool isArray() const;
248 bool isDouble() const;
252 * Returns: isInt() || isDouble().
254 bool isNumber() const;
257 * Returns the type of this dynamic.
262 * Returns the type of this dynamic as a printable string.
264 const char* typeName() const;
267 * Extract a value while trying to convert to the specified type.
268 * Throws exceptions if we cannot convert from the real type to the
271 * Note you can only use this to access integral types or strings,
272 * since arrays and objects are generally best dealt with as a
275 std::string asString() const;
276 double asDouble() const;
277 int64_t asInt() const;
281 * Extract the value stored in this dynamic without type conversion.
283 * These will throw a TypeError if the dynamic has a different type.
285 const std::string& getString() const&;
286 double getDouble() const&;
287 int64_t getInt() const&;
288 bool getBool() const&;
289 std::string& getString() &;
290 double& getDouble() &;
293 std::string&& getString() &&;
294 double getDouble() &&;
299 * It is occasionally useful to access a string's internal pointer
300 * directly, without the type conversion of `asString()`.
302 * These will throw a TypeError if the dynamic is not a string.
304 const char* data() const&;
305 const char* data() && = delete;
306 const char* c_str() const&;
307 const char* c_str() && = delete;
308 StringPiece stringPiece() const;
311 * Returns: true if this dynamic is null, an empty array, an empty
312 * object, or an empty string.
317 * If this is an array or an object, returns the number of elements
318 * contained. If it is a string, returns the length. Otherwise
321 std::size_t size() const;
324 * You can iterate over the values of the array. Calling these on
325 * non-arrays will throw a TypeError.
327 const_iterator begin() const;
328 const_iterator end() const;
334 * Helper object returned by keys(), values(), and items().
336 template <class T> struct IterableProxy;
340 * You can iterate over the keys, values, or items (std::pair of key and
341 * value) in an object. Calling these on non-objects will throw a TypeError.
343 IterableProxy<const_key_iterator> keys() const;
344 IterableProxy<const_value_iterator> values() const;
345 IterableProxy<const_item_iterator> items() const;
346 IterableProxy<value_iterator> values();
347 IterableProxy<item_iterator> items();
350 * AssociativeContainer-style find interface for objects. Throws if
351 * this is not an object.
353 * Returns: items().end() if the key is not present, or a
354 * const_item_iterator pointing to the item.
356 const_item_iterator find(dynamic const&) const;
357 item_iterator find(dynamic const&);
360 * If this is an object, returns whether it contains a field with
361 * the given name. Otherwise throws TypeError.
363 std::size_t count(dynamic const&) const;
366 * For objects or arrays, provides access to sub-fields by index or
369 * Using these with dynamic objects that are not arrays or objects
370 * will throw a TypeError. Using an index that is out of range or
371 * object-element that's not present throws std::out_of_range.
373 dynamic const& at(dynamic const&) const&;
374 dynamic& at(dynamic const&) &;
375 dynamic&& at(dynamic const&) &&;
378 * Like 'at', above, except it returns either a pointer to the contained
379 * object or nullptr if it wasn't found. This allows a key to be tested for
380 * containment and retrieved in one operation. Example:
382 * if (auto* found = d.get_ptr(key))
385 * Using these with dynamic objects that are not arrays or objects
386 * will throw a TypeError.
388 const dynamic* get_ptr(dynamic const&) const&;
389 dynamic* get_ptr(dynamic const&) &;
390 dynamic* get_ptr(dynamic const&) && = delete;
393 * This works for access to both objects and arrays.
395 * In the case of an array, the index must be an integer, and this will throw
396 * std::out_of_range if it is less than zero or greater than size().
398 * In the case of an object, the non-const overload inserts a null
399 * value if the key isn't present. The const overload will throw
400 * std::out_of_range if the key is not present.
402 * These functions do not invalidate iterators.
404 dynamic& operator[](dynamic const&) &;
405 dynamic const& operator[](dynamic const&) const&;
406 dynamic&& operator[](dynamic const&) &&;
409 * Only defined for objects, throws TypeError otherwise.
411 * getDefault will return the value associated with the supplied key, the
412 * supplied default otherwise. setDefault will set the key to the supplied
413 * default if it is not yet set, otherwise leaving it. setDefault returns
414 * a reference to the existing value if present, the new value otherwise.
417 getDefault(const dynamic& k, const dynamic& v = dynamic::object) const&;
418 dynamic getDefault(const dynamic& k, dynamic&& v) const&;
419 dynamic getDefault(const dynamic& k, const dynamic& v = dynamic::object) &&;
420 dynamic getDefault(const dynamic& k, dynamic&& v) &&;
421 template <class K, class V>
422 dynamic& setDefault(K&& k, V&& v);
423 // MSVC 2015 Update 3 needs these extra overloads because if V were a
424 // defaulted template parameter, it causes MSVC to consider v an rvalue
425 // reference rather than a universal reference, resulting in it not being
426 // able to find the correct overload to construct a dynamic with.
428 dynamic& setDefault(K&& k, dynamic&& v);
430 dynamic& setDefault(K&& k, const dynamic& v = dynamic::object);
433 * Resizes an array so it has at n elements, using the supplied
434 * default to fill new elements. Throws TypeError if this dynamic
437 * May invalidate iterators.
441 void resize(std::size_t n, dynamic const& = nullptr);
444 * Inserts the supplied key-value pair to an object, or throws if
445 * it's not an object.
447 * Invalidates iterators.
449 template <class K, class V> void insert(K&&, V&& val);
452 * These functions merge two folly dynamic objects.
453 * The "update" and "update_missing" functions extend the object by
454 * inserting the key/value pairs of mergeObj into the current object.
455 * For update, if key is duplicated between the two objects, it
456 * will overwrite with the value of the object being inserted (mergeObj).
457 * For "update_missing", it will prefer the value in the original object
459 * The "merge" function creates a new object consisting of the key/value
460 * pairs of both mergeObj1 and mergeObj2
461 * If the key is duplicated between the two objects,
462 * it will prefer value in the second object (mergeObj2)
464 void update(const dynamic& mergeObj);
465 void update_missing(const dynamic& other);
466 static dynamic merge(const dynamic& mergeObj1, const dynamic& mergeObj2);
469 * Erase an element from a dynamic object, by key.
471 * Invalidates iterators to the element being erased.
473 * Returns the number of elements erased (i.e. 1 or 0).
475 std::size_t erase(dynamic const& key);
478 * Erase an element from a dynamic object or array, using an
479 * iterator or an iterator range.
481 * In arrays, invalidates iterators to elements after the element
482 * being erased. In objects, invalidates iterators to the elements
485 * Returns a new iterator to the first element beyond any elements
486 * removed, or end() if there are none. (The iteration order does
489 iterator erase(const_iterator it);
490 iterator erase(const_iterator first, const_iterator last);
492 const_key_iterator erase(const_key_iterator it);
493 const_key_iterator erase(const_key_iterator first, const_key_iterator last);
495 value_iterator erase(const_value_iterator it);
496 value_iterator erase(const_value_iterator first, const_value_iterator last);
498 item_iterator erase(const_item_iterator it);
499 item_iterator erase(const_item_iterator first, const_item_iterator last);
501 * Append elements to an array. If this is not an array, throws
504 * Invalidates iterators.
506 void push_back(dynamic const&);
507 void push_back(dynamic&&);
510 * Remove an element from the back of an array. If this is not an array,
513 * Does not invalidate iterators.
518 * Get a hash code. This function is called by a std::hash<>
519 * specialization, also.
521 * Throws TypeError if this is an object, array, or null.
523 std::size_t hash() const;
526 friend struct TypeError;
528 template <class T> struct TypeInfo;
529 template <class T> struct CompareOp;
530 template <class T> struct GetAddrImpl;
531 template <class T> struct PrintImpl;
533 explicit dynamic(Array&& array);
535 template <class T> T const& get() const;
536 template <class T> T& get();
537 template <class T> T* get_nothrow() & noexcept;
538 template <class T> T const* get_nothrow() const& noexcept;
539 template <class T> T* get_nothrow() && noexcept = delete;
540 template <class T> T* getAddress() noexcept;
541 template <class T> T const* getAddress() const noexcept;
543 template <class T> T asImpl() const;
545 static char const* typeName(Type);
546 void destroy() noexcept;
547 void print(std::ostream&) const;
548 void print_as_pseudo_json(std::ostream&) const; // see json.cpp
553 explicit Data() : nul(nullptr) {}
564 * Objects are placement new'd here. We have to use a char buffer
565 * because we don't know the type here (std::unordered_map<> with
566 * dynamic would be parameterizing a std:: template with an
567 * incomplete type right now). (Note that in contrast we know it
568 * is ok to do this with fbvector because we own it.)
570 std::aligned_storage<
571 sizeof(std::unordered_map<int,int>),
572 alignof(std::unordered_map<int,int>)
573 >::type objectBuffer;
577 //////////////////////////////////////////////////////////////////////
581 #include <folly/dynamic-inl.h>