Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 485 lines (428 sloc) 14.345 kB
27494a2 @jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored
1 /*
2 * Copyright 2012 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"] = { "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", { "a", "array" })
43 * ;
44 *
45 * Also see folly/json.h for the serialization and deserialization
46 * functions for JSON.
47 *
48 * Note: dynamic is not DefaultConstructible. Rationale:
49 *
50 * - The intuitive thing to initialize a defaulted dynamic to would
51 * be nullptr.
52 *
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
56 * empty array.
57 *
58 * Additional documentation is in folly/docs/Dynamic.md.
59 *
60 * @author Jordan DeLong <delong.j@fb.com>
61 */
62
63 #ifndef FOLLY_DYNAMIC_H_
64 #define FOLLY_DYNAMIC_H_
65
66 #include <unordered_map>
67 #include <memory>
68 #include <string>
69 #include <utility>
70 #include <ostream>
71 #include <type_traits>
72 #include <initializer_list>
192cff5 @andrewjcg folly::dynamic: use std::vector instead of folly::fbvector
andrewjcg authored
73 #include <vector>
27494a2 @jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored
74 #include <cstdint>
75 #include <boost/operators.hpp>
76
77 #include "folly/Traits.h"
78 #include "folly/FBString.h"
79
80 namespace folly {
81
82 //////////////////////////////////////////////////////////////////////
83
84 struct dynamic;
85 struct TypeError;
86
87 //////////////////////////////////////////////////////////////////////
88
89 struct dynamic : private boost::operators<dynamic> {
90 enum Type {
91 NULLT,
92 ARRAY,
93 BOOL,
94 DOUBLE,
95 INT64,
96 OBJECT,
97 STRING,
98 };
99
100 /*
101 * We support direct iteration of arrays, and indirect iteration of objects.
102 * See begin(), end(), keys(), values(), and items() for more.
103 *
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).
108 */
109 private:
192cff5 @andrewjcg folly::dynamic: use std::vector instead of folly::fbvector
andrewjcg authored
110 typedef std::vector<dynamic> Array;
27494a2 @jdelong Pull from FB rev 63ce89e2f2301e6bba44a111cc7d4218022156f6
jdelong authored
111 public:
112 typedef Array::const_iterator const_iterator;
113 struct const_key_iterator;
114 struct const_value_iterator;
115 struct const_item_iterator;
116
117 /*
118 * Creation routines for making dynamic objects. Objects are maps
119 * from key to value (so named due to json-related origins here).
120 *
121 * Example:
122 *
123 * // Make a fairly complex dynamic:
124 * dynamic d = dynamic::object("key", "value1")
125 * ("key2", { "value", "with", 4, "words" });
126 *
127 * // Build an object in a few steps:
128 * dynamic d = dynamic::object;
129 * d["key"] = 12;
130 * d["something_else"] = { 1, 2, 3, nullptr };
131 */
132 private:
133 struct ObjectMaker;
134
135 public:
136 template<class... Args> static ObjectMaker object(Args&&...);
137
138 /*
139 * String compatibility constructors.
140 */
141 /* implicit */ dynamic(char const* val);
142 /* implicit */ dynamic(std::string const& val);
143
144 /*
145 * This is part of the plumbing for object(), above. Used to create
146 * a new object dynamic.
147 */
148 /* implicit */ dynamic(ObjectMaker (*)());
149 /* implicit */ dynamic(ObjectMaker const&) = delete;
150 /* implicit */ dynamic(ObjectMaker&&);
151
152 /*
153 * Create a new array from an initializer list.
154 *
155 * For example:
156 *
157 * dynamic v = { 1, 2, 3, "foo" };
158 */
159 /* implicit */ dynamic(std::initializer_list<dynamic> il);
160
161 /*
162 * Conversion constructors from most of the other types.
163 */
164 template<class T> /* implicit */ dynamic(T t);
165
166 /*
167 * Create a dynamic that is an array of the values from the supplied
168 * iterator range.
169 */
170 template<class Iterator> dynamic(Iterator first, Iterator last);
171
172 dynamic(dynamic const&);
173 dynamic(dynamic&&);
174 ~dynamic();
175
176 /*
177 * "Deep" equality comparison. This will compare all the way down
178 * an object or array, and is potentially expensive.
179 */
180 bool operator==(dynamic const& o) const;
181
182 /*
183 * For all types except object this returns the natural ordering on
184 * those types. For objects, we throw TypeError.
185 */
186 bool operator<(dynamic const& o) const;
187
188 /*
189 * General operators.
190 *
191 * These throw TypeError when used with types or type combinations
192 * that don't support them.
193 *
194 * These functions may also throw if you use 64-bit integers with
195 * doubles when the integers are too big to fit in a double.
196 */
197 dynamic& operator+=(dynamic const&);
198 dynamic& operator-=(dynamic const&);
199 dynamic& operator*=(dynamic const&);
200 dynamic& operator/=(dynamic const&);
201 dynamic& operator%=(dynamic const&);
202 dynamic& operator|=(dynamic const&);
203 dynamic& operator&=(dynamic const&);
204 dynamic& operator^=(dynamic const&);
205 dynamic& operator++();
206 dynamic& operator--();
207
208 /*
209 * Assignment from other dynamics. Because of the implicit conversion
210 * to dynamic from its potential types, you can use this to change the
211 * type pretty intuitively.
212 *
213 * Basic guarantee only.
214 */
215 dynamic& operator=(dynamic const&);
216 dynamic& operator=(dynamic&&);
217
218 /*
219 * For simple dynamics (not arrays or objects), this prints the
220 * value to an std::ostream in the expected way. Respects the
221 * formatting manipulators that have been sent to the stream
222 * already.
223 *
224 * If the dynamic holds an object or array, this prints them in a
225 * format very similar to JSON. (It will in fact actually be JSON
226 * as long as the dynamic validly represents a JSON object---i.e. it
227 * can't have non-string keys.)
228 */
229 friend std::ostream& operator<<(std::ostream&, dynamic const&);
230
231 /*
232 * Returns true if this dynamic is of the specified type.
233 */
234 bool isString() const;
235 bool isObject() const;
236 bool isBool() const;
237 bool isNull() const;
238 bool isArray() const;
239 bool isDouble() const;
240 bool isInt() const;
241
242 /*
243 * Returns: isInt() || isDouble().
244 */
245 bool isNumber() const;
246
247 /*
248 * Returns the type of this dynamic.
249 */
250 Type type() const;
251
252 /*
253 * Extract a value while trying to convert to the specified type.
254 * Throws exceptions if we cannot convert from the real type to the
255 * requested type.
256 *
257 * Note you can only use this to access integral types or strings,
258 * since arrays and objects are generally best delt with as a
259 * dynamic.
260 */
261 fbstring asString() const;
262 double asDouble() const;
263 int64_t asInt() const;
264 bool asBool() const;
265
266 /*
267 * Returns: true if this dynamic is null, an empty array, an empty
268 * object, or an empty string.
269 */
270 bool empty() const;
271
272 /*
273 * If this is an array or an object, returns the number of elements
274 * contained. If it is a string, returns the length. Otherwise
275 * throws TypeError.
276 */
277 std::size_t size() const;
278
279 /*
280 * You can iterate over the values of the array. Calling these on
281 * non-arrays will throw a TypeError.
282 */
283 const_iterator begin() const;
284 const_iterator end() const;
285
286 private:
287 /*
288 * Helper object returned by keys(), values(), and items().
289 */
290 template <class T> struct IterableProxy;
291
292 public:
293 /*
294 * You can iterate over the keys, values, or items (std::pair of key and
295 * value) in an object. Calling these on non-objects will throw a TypeError.
296 */
297 IterableProxy<const_key_iterator> keys() const;
298 IterableProxy<const_value_iterator> values() const;
299 IterableProxy<const_item_iterator> items() const;
300
301 /*
302 * AssociativeContainer-style find interface for objects. Throws if
303 * this is not an object.
304 *
305 * Returns: end() if the key is not present, or an iterator pointing
306 * to the item.
307 */
308 const_item_iterator find(dynamic const&) const;
309
310 /*
311 * If this is an object, returns whether it contains a field with
312 * the given name. Otherwise throws TypeError.
313 */
314 std::size_t count(dynamic const&) const;
315
316 /*
317 * For objects or arrays, provides access to sub-fields by index or
318 * field name.
319 *
320 * Using these with dynamic objects that are not arrays or objects
321 * will throw a TypeError. Using an index that is out of range or
322 * object-element that's not present throws std::out_of_range.
323 */
324 dynamic const& at(dynamic const&) const;
325 dynamic& at(dynamic const&);
326
327 /*
328 * This works for access to both objects and arrays.
329 *
330 * In the case of an array, the index must be an integer, and this will throw
331 * std::out_of_range if it is less than zero or greater than size().
332 *
333 * In the case of an object, the non-const overload inserts a null
334 * value if the key isn't present. The const overload will throw
335 * std::out_of_range if the key is not present.
336 *
337 * These functions do not invalidate iterators.
338 */
339 dynamic& operator[](dynamic const&);
340 dynamic const& operator[](dynamic const&) const;
341
342 /*
343 * Only defined for objects, throws TypeError otherwise.
344 *
345 * getDefault will return the value associated with the supplied key, the
346 * supplied default otherwise. setDefault will set the key to the supplied
347 * default if it is not yet set, otherwise leaving it. setDefault returns
348 * a reference to the existing value if present, the new value otherwise.
349 */
350 dynamic
351 getDefault(const dynamic& k, const dynamic& v = dynamic::object) const;
352 dynamic&& getDefault(const dynamic& k, dynamic&& v) const;
353 template<class K, class V = dynamic>
354 dynamic& setDefault(K&& k, V&& v = dynamic::object);
355
356 /*
357 * Resizes an array so it has at n elements, using the supplied
358 * default to fill new elements. Throws TypeError if this dynamic
359 * is not an array.
360 *
361 * May invalidate iterators.
362 *
363 * Post: size() == n
364 */
365 void resize(std::size_t n, dynamic const& = nullptr);
366
367 /*
368 * Inserts the supplied key-value pair to an object, or throws if
369 * it's not an object.
370 *
371 * Invalidates iterators.
372 */
373 template<class K, class V> void insert(K&&, V&& val);
374
375 /*
376 * Erase an element from a dynamic object, by key.
377 *
378 * Invalidates iterators to the element being erased.
379 *
380 * Returns the number of elements erased (i.e. 1 or 0).
381 */
382 std::size_t erase(dynamic const& key);
383
384 /*
385 * Erase an element from a dynamic object or array, using an
386 * iterator or an iterator range.
387 *
388 * In arrays, invalidates iterators to elements after the element
389 * being erased. In objects, invalidates iterators to the elements
390 * being erased.
391 *
392 * Returns a new iterator to the first element beyond any elements
393 * removed, or end() if there are none. (The iteration order does
394 * not change.)
395 */
396 const_iterator erase(const_iterator it);
397 const_iterator erase(const_iterator first, const_iterator last);
398
399 const_key_iterator erase(const_key_iterator it);
400 const_key_iterator erase(const_key_iterator first, const_key_iterator last);
401
402 const_value_iterator erase(const_value_iterator it);
403 const_value_iterator erase(const_value_iterator first,
404 const_value_iterator last);
405
406 const_item_iterator erase(const_item_iterator it);
407 const_item_iterator erase(const_item_iterator first,
408 const_item_iterator last);
409 /*
410 * Append elements to an array. If this is not an array, throws
411 * TypeError.
412 *
413 * Invalidates iterators.
414 */
415 void push_back(dynamic const&);
416 void push_back(dynamic&&);
417
418 /*
419 * Get a hash code. This function is called by a std::hash<>
420 * specialization, also.
421 *
422 * Throws TypeError if this is an object, array, or null.
423 */
424 std::size_t hash() const;
425
426 private:
427 friend struct TypeError;
428 struct ObjectImpl;
429 struct ObjectMaker;
430 template<class T> struct TypeInfo;
431 template<class T> struct CompareOp;
432 template<class T> struct GetAddrImpl;
433 template<class T> struct PrintImpl;
434
435 template<class T> T const& get() const;
436 template<class T> T& get();
437 template<class T> T* get_nothrow();
438 template<class T> T const* get_nothrow() const;
439 template<class T> T* getAddress();
440 template<class T> T const* getAddress() const;
441
442 template<class T> T asImpl() const;
443
444 static char const* typeName(Type);
445 void destroy();
446 void print(std::ostream&) const;
447 void print_as_pseudo_json(std::ostream&) const; // see json.cpp
448
449 private:
450 Type type_;
451 union Data {
452 explicit Data() : nul(nullptr) {}
453 ~Data() {}
454
455 // XXX: gcc does an ICE if we use std::nullptr_t instead of void*
456 // here. See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50361
457 void* nul;
458 Array array;
459 bool boolean;
460 double doubl;
461 int64_t integer;
462 fbstring string;
463
464 /*
465 * Objects are placement new'd here. We have to use a char buffer
466 * because we don't know the type here (std::unordered_map<> with
467 * dynamic would be parameterizing a std:: template with an
468 * incomplete type right now). (Note that in contrast we know it
469 * is ok to do this with fbvector because we own it.)
470 */
471 typename std::aligned_storage<
472 sizeof(std::unordered_map<int,int>),
473 alignof(std::unordered_map<int,int>)
474 >::type objectBuffer;
475 } u_;
476 };
477
478 //////////////////////////////////////////////////////////////////////
479
480 }
481
482 #include "folly/dynamic-inl.h"
483
484 #endif
Something went wrong with that request. Please try again.