2 * Copyright 2014 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"] = { "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", { "a", "array" })
45 * Also see folly/json.h for the serialization and deserialization
48 * Note: dynamic is not DefaultConstructible. Rationale:
50 * - The intuitive thing to initialize a defaulted dynamic to would
53 * - However, the expression dynamic d = {} is required to call the
54 * default constructor by the standard, which is confusing
55 * behavior for dynamic unless the default constructor creates an
58 * Additional documentation is in folly/docs/Dynamic.md.
60 * @author Jordan DeLong <delong.j@fb.com>
63 #ifndef FOLLY_DYNAMIC_H_
64 #define FOLLY_DYNAMIC_H_
66 #include <unordered_map>
71 #include <type_traits>
72 #include <initializer_list>
75 #include <boost/operators.hpp>
77 #include "folly/Traits.h"
78 #include "folly/FBString.h"
82 //////////////////////////////////////////////////////////////////////
87 //////////////////////////////////////////////////////////////////////
89 struct dynamic : private boost::operators<dynamic> {
101 * We support direct iteration of arrays, and indirect iteration of objects.
102 * See begin(), end(), keys(), values(), and items() for more.
104 * Array iterators dereference as the elements in the array.
105 * Object key iterators dereference as the keys in the object.
106 * Object value iterators dereference as the values in the object.
107 * Object item iterators dereference as pairs of (key, value).
110 typedef std::vector<dynamic> Array;
112 typedef Array::const_iterator const_iterator;
113 typedef dynamic value_type;
114 struct const_key_iterator;
115 struct const_value_iterator;
116 struct const_item_iterator;
119 * Creation routines for making dynamic objects. Objects are maps
120 * from key to value (so named due to json-related origins here).
124 * // Make a fairly complex dynamic:
125 * dynamic d = dynamic::object("key", "value1")
126 * ("key2", { "value", "with", 4, "words" });
128 * // Build an object in a few steps:
129 * dynamic d = dynamic::object;
131 * d["something_else"] = { 1, 2, 3, nullptr };
137 static ObjectMaker object();
138 static ObjectMaker object(dynamic&&, dynamic&&);
139 static ObjectMaker object(dynamic const&, dynamic&&);
140 static ObjectMaker object(dynamic&&, dynamic const&);
141 static ObjectMaker object(dynamic const&, dynamic const&);
144 * String compatibility constructors.
146 /* implicit */ dynamic(char const* val);
147 /* implicit */ dynamic(std::string const& val);
150 * This is part of the plumbing for object(), above. Used to create
151 * a new object dynamic.
153 /* implicit */ dynamic(ObjectMaker (*)());
154 /* implicit */ dynamic(ObjectMaker const&) = delete;
155 /* implicit */ dynamic(ObjectMaker&&);
158 * Create a new array from an initializer list.
162 * dynamic v = { 1, 2, 3, "foo" };
164 /* implicit */ dynamic(std::initializer_list<dynamic> il);
167 * Conversion constructors from most of the other types.
169 template<class T> /* implicit */ dynamic(T t);
172 * Create a dynamic that is an array of the values from the supplied
175 template<class Iterator> dynamic(Iterator first, Iterator last);
177 dynamic(dynamic const&);
182 * "Deep" equality comparison. This will compare all the way down
183 * an object or array, and is potentially expensive.
185 bool operator==(dynamic const& o) const;
188 * For all types except object this returns the natural ordering on
189 * those types. For objects, we throw TypeError.
191 bool operator<(dynamic const& o) const;
196 * These throw TypeError when used with types or type combinations
197 * that don't support them.
199 * These functions may also throw if you use 64-bit integers with
200 * doubles when the integers are too big to fit in a double.
202 dynamic& operator+=(dynamic const&);
203 dynamic& operator-=(dynamic const&);
204 dynamic& operator*=(dynamic const&);
205 dynamic& operator/=(dynamic const&);
206 dynamic& operator%=(dynamic const&);
207 dynamic& operator|=(dynamic const&);
208 dynamic& operator&=(dynamic const&);
209 dynamic& operator^=(dynamic const&);
210 dynamic& operator++();
211 dynamic& operator--();
214 * Assignment from other dynamics. Because of the implicit conversion
215 * to dynamic from its potential types, you can use this to change the
216 * type pretty intuitively.
218 * Basic guarantee only.
220 dynamic& operator=(dynamic const&);
221 dynamic& operator=(dynamic&&);
224 * For simple dynamics (not arrays or objects), this prints the
225 * value to an std::ostream in the expected way. Respects the
226 * formatting manipulators that have been sent to the stream
229 * If the dynamic holds an object or array, this prints them in a
230 * format very similar to JSON. (It will in fact actually be JSON
231 * as long as the dynamic validly represents a JSON object---i.e. it
232 * can't have non-string keys.)
234 friend std::ostream& operator<<(std::ostream&, dynamic const&);
237 * Returns true if this dynamic is of the specified type.
239 bool isString() const;
240 bool isObject() const;
243 bool isArray() const;
244 bool isDouble() const;
248 * Returns: isInt() || isDouble().
250 bool isNumber() const;
253 * Returns the type of this dynamic.
258 * Returns the type of this dynamic as a printable string.
260 const char* typeName() const;
263 * Extract a value while trying to convert to the specified type.
264 * Throws exceptions if we cannot convert from the real type to the
267 * Note you can only use this to access integral types or strings,
268 * since arrays and objects are generally best dealt with as a
271 fbstring asString() const;
272 double asDouble() const;
273 int64_t asInt() const;
277 * It is occasionally useful to access a string's internal pointer
278 * directly, without the type conversion of `asString()`.
280 * These will throw a TypeError if the dynamic is not a string.
282 const char* data() const;
283 const char* c_str() const;
286 * Returns: true if this dynamic is null, an empty array, an empty
287 * object, or an empty string.
292 * If this is an array or an object, returns the number of elements
293 * contained. If it is a string, returns the length. Otherwise
296 std::size_t size() const;
299 * You can iterate over the values of the array. Calling these on
300 * non-arrays will throw a TypeError.
302 const_iterator begin() const;
303 const_iterator end() const;
307 * Helper object returned by keys(), values(), and items().
309 template <class T> struct IterableProxy;
313 * You can iterate over the keys, values, or items (std::pair of key and
314 * value) in an object. Calling these on non-objects will throw a TypeError.
316 IterableProxy<const_key_iterator> keys() const;
317 IterableProxy<const_value_iterator> values() const;
318 IterableProxy<const_item_iterator> items() const;
321 * AssociativeContainer-style find interface for objects. Throws if
322 * this is not an object.
324 * Returns: items().end() if the key is not present, or a
325 * const_item_iterator pointing to the item.
327 const_item_iterator find(dynamic const&) const;
331 * If this is an object, returns whether it contains a field with
332 * the given name. Otherwise throws TypeError.
334 std::size_t count(dynamic const&) const;
337 * For objects or arrays, provides access to sub-fields by index or
340 * Using these with dynamic objects that are not arrays or objects
341 * will throw a TypeError. Using an index that is out of range or
342 * object-element that's not present throws std::out_of_range.
344 dynamic const& at(dynamic const&) const;
345 dynamic& at(dynamic const&);
348 * Like 'at', above, except it returns either a pointer to the contained
349 * object or nullptr if it wasn't found. This allows a key to be tested for
350 * containment and retrieved in one operation. Example:
352 * if (auto* found = d.get_ptr(key))
355 * Using these with dynamic objects that are not arrays or objects
356 * will throw a TypeError.
358 const dynamic* get_ptr(dynamic const&) const;
359 dynamic* get_ptr(dynamic const&);
362 * This works for access to both objects and arrays.
364 * In the case of an array, the index must be an integer, and this will throw
365 * std::out_of_range if it is less than zero or greater than size().
367 * In the case of an object, the non-const overload inserts a null
368 * value if the key isn't present. The const overload will throw
369 * std::out_of_range if the key is not present.
371 * These functions do not invalidate iterators.
373 dynamic& operator[](dynamic const&);
374 dynamic const& operator[](dynamic const&) const;
377 * Only defined for objects, throws TypeError otherwise.
379 * getDefault will return the value associated with the supplied key, the
380 * supplied default otherwise. setDefault will set the key to the supplied
381 * default if it is not yet set, otherwise leaving it. setDefault returns
382 * a reference to the existing value if present, the new value otherwise.
385 getDefault(const dynamic& k, const dynamic& v = dynamic::object) const;
386 dynamic&& getDefault(const dynamic& k, dynamic&& v) const;
387 template<class K, class V = dynamic>
388 dynamic& setDefault(K&& k, V&& v = dynamic::object);
391 * Resizes an array so it has at n elements, using the supplied
392 * default to fill new elements. Throws TypeError if this dynamic
395 * May invalidate iterators.
399 void resize(std::size_t n, dynamic const& = nullptr);
402 * Inserts the supplied key-value pair to an object, or throws if
403 * it's not an object.
405 * Invalidates iterators.
407 template<class K, class V> void insert(K&&, V&& val);
410 * Erase an element from a dynamic object, by key.
412 * Invalidates iterators to the element being erased.
414 * Returns the number of elements erased (i.e. 1 or 0).
416 std::size_t erase(dynamic const& key);
419 * Erase an element from a dynamic object or array, using an
420 * iterator or an iterator range.
422 * In arrays, invalidates iterators to elements after the element
423 * being erased. In objects, invalidates iterators to the elements
426 * Returns a new iterator to the first element beyond any elements
427 * removed, or end() if there are none. (The iteration order does
430 const_iterator erase(const_iterator it);
431 const_iterator erase(const_iterator first, const_iterator last);
433 const_key_iterator erase(const_key_iterator it);
434 const_key_iterator erase(const_key_iterator first, const_key_iterator last);
436 const_value_iterator erase(const_value_iterator it);
437 const_value_iterator erase(const_value_iterator first,
438 const_value_iterator last);
440 const_item_iterator erase(const_item_iterator it);
441 const_item_iterator erase(const_item_iterator first,
442 const_item_iterator last);
444 * Append elements to an array. If this is not an array, throws
447 * Invalidates iterators.
449 void push_back(dynamic const&);
450 void push_back(dynamic&&);
453 * Remove an element from the back of an array. If this is not an array,
456 * Does not invalidate iterators.
461 * Get a hash code. This function is called by a std::hash<>
462 * specialization, also.
464 * Throws TypeError if this is an object, array, or null.
466 std::size_t hash() const;
469 friend struct TypeError;
471 template<class T> struct TypeInfo;
472 template<class T> struct CompareOp;
473 template<class T> struct GetAddrImpl;
474 template<class T> struct PrintImpl;
476 template<class T> T const& get() const;
477 template<class T> T& get();
478 template<class T> T* get_nothrow();
479 template<class T> T const* get_nothrow() const;
480 template<class T> T* getAddress();
481 template<class T> T const* getAddress() const;
483 template<class T> T asImpl() const;
485 static char const* typeName(Type);
487 void print(std::ostream&) const;
488 void print_as_pseudo_json(std::ostream&) const; // see json.cpp
493 explicit Data() : nul(nullptr) {}
496 // XXX: gcc does an ICE if we use std::nullptr_t instead of void*
497 // here. See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50361
506 * Objects are placement new'd here. We have to use a char buffer
507 * because we don't know the type here (std::unordered_map<> with
508 * dynamic would be parameterizing a std:: template with an
509 * incomplete type right now). (Note that in contrast we know it
510 * is ok to do this with fbvector because we own it.)
512 typename std::aligned_storage<
513 sizeof(std::unordered_map<int,int>),
514 alignof(std::unordered_map<int,int>)
515 >::type objectBuffer;
519 //////////////////////////////////////////////////////////////////////
523 #include "folly/dynamic-inl.h"