proxygen
dynamic-inl.h
Go to the documentation of this file.
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 #pragma once
17 
18 #include <functional>
19 
20 #include <folly/CPortability.h>
21 #include <folly/Conv.h>
22 #include <folly/Format.h>
23 #include <folly/Likely.h>
24 #include <folly/detail/Iterators.h>
25 #include <folly/lang/Exception.h>
26 
27 namespace folly {
28 namespace detail {
29 struct DynamicHasher {
30  using is_transparent = void;
31 
32  size_t operator()(dynamic const& d) const {
33  return d.hash();
34  }
35 
36  template <typename T>
38  operator()(T const& val) const {
39  // keep consistent with dynamic::hash() for strings
40  return Hash()(static_cast<StringPiece>(val));
41  }
42 };
43 
45  using is_transparent = void;
46 
47  bool operator()(const dynamic& lhs, const dynamic& rhs) const {
48  return std::equal_to<dynamic>()(lhs, rhs);
49  }
50 
51  // Dynamic objects contains a map<dynamic, dynamic>. At least one of the
52  // operands should be a dynamic. Hence, an operator() where both operands are
53  // convertible to StringPiece is unnecessary.
54  template <typename A, typename B>
55  std::enable_if_t<
58  bool>
59  operator()(A const& lhs, B const& rhs) const = delete;
60 
61  template <typename A>
63  A const& lhs,
64  dynamic const& rhs) const {
65  return FOLLY_LIKELY(rhs.type() == dynamic::Type::STRING) &&
66  std::equal_to<StringPiece>()(lhs, rhs.stringPiece());
67  }
68 
69  template <typename B>
71  dynamic const& lhs,
72  B const& rhs) const {
73  return FOLLY_LIKELY(lhs.type() == dynamic::Type::STRING) &&
74  std::equal_to<StringPiece>()(lhs.stringPiece(), rhs);
75  }
76 };
77 } // namespace detail
78 } // namespace folly
79 
81 
82 namespace std {
83 
84 template <>
85 struct hash<::folly::dynamic> {
86  size_t operator()(::folly::dynamic const& d) const {
87  return d.hash();
88  }
89 };
90 
91 } // namespace std
92 
94 
95 // This is a higher-order preprocessor macro to aid going from runtime
96 // types to the compile time type system.
97 #define FB_DYNAMIC_APPLY(type, apply) \
98  do { \
99  switch ((type)) { \
100  case NULLT: \
101  apply(std::nullptr_t); \
102  break; \
103  case ARRAY: \
104  apply(Array); \
105  break; \
106  case BOOL: \
107  apply(bool); \
108  break; \
109  case DOUBLE: \
110  apply(double); \
111  break; \
112  case INT64: \
113  apply(int64_t); \
114  break; \
115  case OBJECT: \
116  apply(ObjectImpl); \
117  break; \
118  case STRING: \
119  apply(std::string); \
120  break; \
121  default: \
122  CHECK(0); \
123  abort(); \
124  } \
125  } while (0)
126 
128 
129 namespace folly {
130 
131 struct FOLLY_EXPORT TypeError : std::runtime_error {
132  explicit TypeError(const std::string& expected, dynamic::Type actual);
133  explicit TypeError(
134  const std::string& expected,
135  dynamic::Type actual1,
136  dynamic::Type actual2);
137  // TODO: noexcept calculation required through gcc-v4.9; remove once upgrading
138  // to gcc-v5.
139  TypeError(const TypeError&) noexcept(
141  TypeError& operator=(const TypeError&) noexcept(
143  TypeError(TypeError&&) noexcept(
145  TypeError& operator=(TypeError&&) noexcept(
147  ~TypeError() override;
148 };
149 
151 
152 namespace detail {
153 
154 // This helper is used in destroy() to be able to run destructors on
155 // types like "int64_t" without a compiler error.
156 struct Destroy {
157  template <class T>
158  static void destroy(T* t) {
159  t->~T();
160  }
161 };
162 
163 /*
164  * Helper for implementing numeric conversions in operators on
165  * numbers. Just promotes to double when one of the arguments is
166  * double, or throws if either is not a numeric type.
167  */
168 template <template <class> class Op>
169 dynamic numericOp(dynamic const& a, dynamic const& b) {
170  if (!a.isNumber() || !b.isNumber()) {
171  throw_exception<TypeError>("numeric", a.type(), b.type());
172  }
173  if (a.type() != b.type()) {
174  auto& integ = a.isInt() ? a : b;
175  auto& nonint = a.isInt() ? b : a;
176  return Op<double>()(to<double>(integ.asInt()), nonint.asDouble());
177  }
178  if (a.isDouble()) {
179  return Op<double>()(a.asDouble(), b.asDouble());
180  }
181  return Op<int64_t>()(a.asInt(), b.asInt());
182 }
183 
184 } // namespace detail
185 
187 
188 /*
189  * We're doing this instead of a simple member typedef to avoid the
190  * undefined behavior of parameterizing F14NodeMap<> with an
191  * incomplete type.
192  *
193  * Note: Later we may add separate order tracking here (a multi-index
194  * type of thing.)
195  */
197  dynamic,
198  dynamic,
199  detail::DynamicHasher,
200  detail::DynamicKeyEqual> {};
201 
203 
204 // Helper object for creating objects conveniently. See object and
205 // the dynamic::dynamic(ObjectMaker&&) ctor.
207  friend struct dynamic;
208 
209  explicit ObjectMaker() : val_(dynamic::object) {}
210  explicit ObjectMaker(dynamic key, dynamic val) : val_(dynamic::object) {
211  val_.insert(std::move(key), std::move(val));
212  }
213 
214  // Make sure no one tries to save one of these into an lvalue with
215  // auto or anything like that.
216  ObjectMaker(ObjectMaker&&) = default;
217  ObjectMaker(ObjectMaker const&) = delete;
218  ObjectMaker& operator=(ObjectMaker const&) = delete;
219  ObjectMaker& operator=(ObjectMaker&&) = delete;
220 
221  // This returns an rvalue-reference instead of an lvalue-reference
222  // to allow constructs like this to moved instead of copied:
223  // dynamic a = dynamic::object("a", "b")("c", "d")
225  val_.insert(std::move(key), std::move(val));
226  return std::move(*this);
227  }
228 
229  private:
231 };
232 
234 
235 template <class... Args>
236 inline dynamic dynamic::array(Args&&... args) {
237  return dynamic(Array{std::forward<Args>(args)...});
238 }
239 
241  return ObjectMaker();
242 }
244  return ObjectMaker(std::move(a), std::move(b));
245 }
246 
248 
250  dynamic::item_iterator,
251  dynamic::ObjectImpl::iterator,
252  std::pair<dynamic const, dynamic>,
253  std::forward_iterator_tag> {
256  dynamic::ObjectImpl::iterator,
257  std::pair<dynamic const, dynamic>,
258  std::forward_iterator_tag>;
259  /* implicit */ item_iterator(dynamic::ObjectImpl::iterator b) : Super(b) {}
260 
262 };
263 
265  dynamic::value_iterator,
266  dynamic::ObjectImpl::iterator,
267  dynamic,
268  std::forward_iterator_tag> {
271  dynamic::ObjectImpl::iterator,
272  dynamic,
273  std::forward_iterator_tag>;
274  /* implicit */ value_iterator(dynamic::ObjectImpl::iterator b) : Super(b) {}
275 
277 
278  dynamic& dereference() const {
279  return base()->second;
280  }
281 };
282 
285  dynamic::const_item_iterator,
286  dynamic::ObjectImpl::const_iterator,
287  std::pair<dynamic const, dynamic> const,
288  std::forward_iterator_tag> {
291  dynamic::ObjectImpl::const_iterator,
292  std::pair<dynamic const, dynamic> const,
293  std::forward_iterator_tag>;
294  /* implicit */ const_item_iterator(dynamic::ObjectImpl::const_iterator b)
295  : Super(b) {}
297  : Super(i.base()) {}
298  /* implicit */ const_item_iterator(item_iterator i) : Super(i.base()) {}
299 
301 };
302 
304  dynamic::const_key_iterator,
305  dynamic::ObjectImpl::const_iterator,
306  dynamic const,
307  std::forward_iterator_tag> {
310  dynamic::ObjectImpl::const_iterator,
311  dynamic const,
312  std::forward_iterator_tag>;
313  /* implicit */ const_key_iterator(dynamic::ObjectImpl::const_iterator b)
314  : Super(b) {}
315 
317 
318  dynamic const& dereference() const {
319  return base()->first;
320  }
321 };
322 
324  dynamic::const_value_iterator,
325  dynamic::ObjectImpl::const_iterator,
326  dynamic const,
327  std::forward_iterator_tag> {
330  dynamic::ObjectImpl::const_iterator,
331  dynamic const,
332  std::forward_iterator_tag>;
333  /* implicit */ const_value_iterator(dynamic::ObjectImpl::const_iterator b)
334  : Super(b) {}
335  /* implicit */ const_value_iterator(value_iterator i) : Super(i.base()) {}
336  /* implicit */ const_value_iterator(dynamic::ObjectImpl::iterator i)
337  : Super(i) {}
338 
340 
341  dynamic const& dereference() const {
342  return base()->second;
343  }
344 };
345 
347 
349 
350 inline dynamic::dynamic(std::nullptr_t) : type_(NULLT) {}
351 
353  new (&u_.array) Array();
354 }
355 
357  new (getAddress<ObjectImpl>()) ObjectImpl();
358 }
359 
361  new (&u_.string) std::string(s.data(), s.size());
362 }
363 
364 inline dynamic::dynamic(char const* s) : type_(STRING) {
365  new (&u_.string) std::string(s);
366 }
367 
369  new (&u_.string) std::string(std::move(s));
370 }
371 
373  new (getAddress<ObjectImpl>())
374  ObjectImpl(std::move(*maker.val_.getAddress<ObjectImpl>()));
375 }
376 
377 inline dynamic::dynamic(dynamic const& o) : type_(NULLT) {
378  *this = o;
379 }
380 
382  *this = std::move(o);
383 }
384 
386  destroy();
387 }
388 
389 // Integral types except bool convert to int64_t, float types to double.
390 template <class T>
392  T,
393  typename std::enable_if<std::is_integral<T>::value>::type> {
394  static_assert(
395  !kIsObjC || sizeof(T) > sizeof(char),
396  "char-sized types are ambiguous in objc; cast to bool or wider type");
397  using type = int64_t;
398 };
399 template <>
401  using type = bool;
402 };
403 template <>
405  using type = double;
406 };
407 template <>
409  using type = double;
410 };
411 
412 inline dynamic::dynamic(std::vector<bool>::reference b)
413  : dynamic(static_cast<bool>(b)) {}
415  : dynamic(static_cast<bool>(b)) {}
416 
417 template <
418  class T,
419  class NumericType /* = typename NumericTypeHelper<T>::type */>
422  new (getAddress<NumericType>()) NumericType(NumericType(t));
423 }
424 
425 template <class Iterator>
426 dynamic::dynamic(Iterator first, Iterator last) : type_(ARRAY) {
427  new (&u_.array) Array(first, last);
428 }
429 
431 
433  return get<Array>().begin();
434 }
436  return get<Array>().end();
437 }
438 
440  return get<Array>().begin();
441 }
443  return get<Array>().end();
444 }
445 
446 template <class It>
448  typedef It iterator;
449  typedef typename It::value_type value_type;
450  typedef typename It::object_type object_type;
451 
452  /* implicit */ IterableProxy(object_type* o) : o_(o) {}
453 
454  It begin() const {
455  return o_->begin();
456  }
457 
458  It end() const {
459  return o_->end();
460  }
461 
462  private:
463  object_type* o_;
464 };
465 
467  const {
468  return &(get<ObjectImpl>());
469 }
470 
472  const {
473  return &(get<ObjectImpl>());
474 }
475 
477  const {
478  return &(get<ObjectImpl>());
479 }
480 
482  return &(get<ObjectImpl>());
483 }
484 
486  return &(get<ObjectImpl>());
487 }
488 
489 inline bool dynamic::isString() const {
490  return get_nothrow<std::string>() != nullptr;
491 }
492 inline bool dynamic::isObject() const {
493  return get_nothrow<ObjectImpl>() != nullptr;
494 }
495 inline bool dynamic::isBool() const {
496  return get_nothrow<bool>() != nullptr;
497 }
498 inline bool dynamic::isArray() const {
499  return get_nothrow<Array>() != nullptr;
500 }
501 inline bool dynamic::isDouble() const {
502  return get_nothrow<double>() != nullptr;
503 }
504 inline bool dynamic::isInt() const {
505  return get_nothrow<int64_t>() != nullptr;
506 }
507 inline bool dynamic::isNull() const {
508  return get_nothrow<std::nullptr_t>() != nullptr;
509 }
510 inline bool dynamic::isNumber() const {
511  return isInt() || isDouble();
512 }
513 
514 inline dynamic::Type dynamic::type() const {
515  return type_;
516 }
517 
519  return asImpl<std::string>();
520 }
521 inline double dynamic::asDouble() const {
522  return asImpl<double>();
523 }
524 inline int64_t dynamic::asInt() const {
525  return asImpl<int64_t>();
526 }
527 inline bool dynamic::asBool() const {
528  return asImpl<bool>();
529 }
530 
532  return get<std::string>();
533 }
534 inline double dynamic::getDouble() const& {
535  return get<double>();
536 }
538  return get<int64_t>();
539 }
540 inline bool dynamic::getBool() const& {
541  return get<bool>();
542 }
543 
545  return get<std::string>();
546 }
547 inline double& dynamic::getDouble() & {
548  return get<double>();
549 }
551  return get<int64_t>();
552 }
553 inline bool& dynamic::getBool() & {
554  return get<bool>();
555 }
556 
557 inline std::string&& dynamic::getString() && {
558  return std::move(get<std::string>());
559 }
560 inline double dynamic::getDouble() && {
561  return get<double>();
562 }
563 inline int64_t dynamic::getInt() && {
564  return get<int64_t>();
565 }
566 inline bool dynamic::getBool() && {
567  return get<bool>();
568 }
569 
570 inline const char* dynamic::data() const& {
571  return get<std::string>().data();
572 }
573 inline const char* dynamic::c_str() const& {
574  return get<std::string>().c_str();
575 }
577  return get<std::string>();
578 }
579 
580 template <class T>
582  static bool comp(T const& a, T const& b) {
583  return a < b;
584  }
585 };
586 template <>
588  static bool comp(ObjectImpl const&, ObjectImpl const&) {
589  // This code never executes; it is just here for the compiler.
590  return false;
591  }
592 };
593 template <>
594 struct dynamic::CompareOp<std::nullptr_t> {
595  static bool comp(std::nullptr_t const&, std::nullptr_t const&) {
596  return true;
597  }
598 };
599 
601  if (type() == STRING && o.type() == STRING) {
602  *getAddress<std::string>() += *o.getAddress<std::string>();
603  return *this;
604  }
605  *this = detail::numericOp<std::plus>(*this, o);
606  return *this;
607 }
608 
610  *this = detail::numericOp<std::minus>(*this, o);
611  return *this;
612 }
613 
615  *this = detail::numericOp<std::multiplies>(*this, o);
616  return *this;
617 }
618 
620  *this = detail::numericOp<std::divides>(*this, o);
621  return *this;
622 }
623 
624 #define FB_DYNAMIC_INTEGER_OP(op) \
625  inline dynamic& dynamic::operator op(dynamic const& o) { \
626  if (!isInt() || !o.isInt()) { \
627  throw_exception<TypeError>("int64", type(), o.type()); \
628  } \
629  *getAddress<int64_t>() op o.asInt(); \
630  return *this; \
631  }
632 
637 
638 #undef FB_DYNAMIC_INTEGER_OP
639 
641  ++get<int64_t>();
642  return *this;
643 }
644 
646  --get<int64_t>();
647  return *this;
648 }
649 
650 template <typename K>
652  K&& idx) const& {
653  return at(std::forward<K>(idx));
654 }
655 
656 template <typename K>
658  K&& idx) & {
659  if (!isObject() && !isArray()) {
660  throw_exception<TypeError>("object/array", type());
661  }
662  if (isArray()) {
663  return at(std::forward<K>(idx));
664  }
665  auto& obj = get<ObjectImpl>();
666  auto ret = obj.emplace(std::forward<K>(idx), nullptr);
667  return ret.first->second;
668 }
669 
670 template <typename K>
672  K&& idx) && {
673  return std::move((*this)[std::forward<K>(idx)]);
674 }
675 
676 inline dynamic const& dynamic::operator[](StringPiece k) const& {
677  return at(k);
678 }
679 
681  return std::move((*this)[k]);
682 }
683 
684 template <typename K>
686  K&& k,
687  const dynamic& v) const& {
688  auto& obj = get<ObjectImpl>();
689  auto it = obj.find(std::forward<K>(k));
690  return it == obj.end() ? v : it->second;
691 }
692 
693 template <typename K>
695  K&& k,
696  dynamic&& v) const& {
697  auto& obj = get<ObjectImpl>();
698  auto it = obj.find(std::forward<K>(k));
699  // Avoid clang bug with ternary
700  if (it == obj.end()) {
701  return std::move(v);
702  } else {
703  return it->second;
704  }
705 }
706 
707 template <typename K>
709  K&& k,
710  const dynamic& v) && {
711  auto& obj = get<ObjectImpl>();
712  auto it = obj.find(std::forward<K>(k));
713  // Avoid clang bug with ternary
714  if (it == obj.end()) {
715  return v;
716  } else {
717  return std::move(it->second);
718  }
719 }
720 
721 template <typename K>
723  K&& k,
724  dynamic&& v) && {
725  auto& obj = get<ObjectImpl>();
726  auto it = obj.find(std::forward<K>(k));
727  return std::move(it == obj.end() ? v : it->second);
728 }
729 
730 template <typename K, typename V>
732  K&& k,
733  V&& v) {
734  auto& obj = get<ObjectImpl>();
735  return obj.emplace(std::forward<K>(k), std::forward<V>(v)).first->second;
736 }
737 
738 template <typename K>
740  K&& k,
741  dynamic&& v) {
742  auto& obj = get<ObjectImpl>();
743  return obj.emplace(std::forward<K>(k), std::move(v)).first->second;
744 }
745 
746 template <typename K>
748  K&& k,
749  const dynamic& v) {
750  auto& obj = get<ObjectImpl>();
751  return obj.emplace(std::forward<K>(k), v).first->second;
752 }
753 
754 template <typename V>
756  auto& obj = get<ObjectImpl>();
757  return obj.emplace(k, std::forward<V>(v)).first->second;
758 }
759 
761  auto& obj = get<ObjectImpl>();
762  return obj.emplace(k, std::move(v)).first->second;
763 }
764 
766  auto& obj = get<ObjectImpl>();
767  return obj.emplace(k, v).first->second;
768 }
769 
770 template <typename K>
772  K&& k) const& {
773  return get_ptrImpl(std::forward<K>(k));
774 }
775 
776 template <typename K>
778  K&& idx) & {
779  return const_cast<dynamic*>(const_cast<dynamic const*>(this)->get_ptr(idx));
780 }
781 
783  return const_cast<dynamic*>(const_cast<dynamic const*>(this)->get_ptr(idx));
784 }
785 
786 inline dynamic* dynamic::get_ptr(json_pointer const& jsonPtr) & {
787  return const_cast<dynamic*>(
788  const_cast<dynamic const*>(this)->get_ptr(jsonPtr));
789 }
790 
791 template <typename K>
793  K&& k) const& {
794  return atImpl(std::forward<K>(k));
795 }
796 
797 template <typename K>
799  return const_cast<dynamic&>(const_cast<dynamic const*>(this)->at(idx));
800 }
801 
802 template <typename K>
804  return std::move(at(idx));
805 }
806 
808  return const_cast<dynamic&>(const_cast<dynamic const*>(this)->at(idx));
809 }
810 
811 inline dynamic&& dynamic::at(StringPiece idx) && {
812  return std::move(at(idx));
813 }
814 
815 inline bool dynamic::empty() const {
816  if (isNull()) {
817  return true;
818  }
819  return !size();
820 }
821 
822 template <typename K>
824 dynamic::find(K&& key) const {
825  return get<ObjectImpl>().find(std::forward<K>(key));
826 }
827 
828 template <typename K>
830 dynamic::find(K&& key) {
831  return get<ObjectImpl>().find(std::forward<K>(key));
832 }
833 
835  return get<ObjectImpl>().find(key);
836 }
837 
839  return get<ObjectImpl>().find(key);
840 }
841 
842 template <typename K>
844  K&& key) const {
845  return find(std::forward<K>(key)) != items().end() ? 1u : 0u;
846 }
847 
848 inline std::size_t dynamic::count(StringPiece key) const {
849  return find(key) != items().end() ? 1u : 0u;
850 }
851 
852 template <class K, class V>
853 inline void dynamic::insert(K&& key, V&& val) {
854  auto& obj = get<ObjectImpl>();
855  obj[std::forward<K>(key)] = std::forward<V>(val);
856 }
857 
858 inline void dynamic::update(const dynamic& mergeObj) {
859  if (!isObject() || !mergeObj.isObject()) {
860  throw_exception<TypeError>("object", type(), mergeObj.type());
861  }
862 
863  for (const auto& pair : mergeObj.items()) {
864  (*this)[pair.first] = pair.second;
865  }
866 }
867 
868 inline void dynamic::update_missing(const dynamic& mergeObj1) {
869  if (!isObject() || !mergeObj1.isObject()) {
870  throw_exception<TypeError>("object", type(), mergeObj1.type());
871  }
872 
873  // Only add if not already there
874  for (const auto& pair : mergeObj1.items()) {
875  if ((*this).find(pair.first) == (*this).items().end()) {
876  (*this)[pair.first] = pair.second;
877  }
878  }
879 }
880 
881 inline void dynamic::merge_patch(const dynamic& patch) {
882  auto& self = *this;
883  if (!patch.isObject()) {
884  self = patch;
885  return;
886  }
887  // if we are not an object, erase all contents, reset to object
888  if (!isObject()) {
889  self = object;
890  }
891  for (const auto& pair : patch.items()) {
892  if (pair.second.isNull()) {
893  // if name could be found in current object, remove it
894  auto it = self.find(pair.first);
895  if (it != self.items().end()) {
896  self.erase(it);
897  }
898  } else {
899  self[pair.first].merge_patch(pair.second);
900  }
901  }
902 }
903 
905  const dynamic& mergeObj1,
906  const dynamic& mergeObj2) {
907  // No checks on type needed here because they are done in update_missing
908  // Note that we do update_missing here instead of update() because
909  // it will prevent the extra writes that would occur with update()
910  auto ret = mergeObj2;
911  ret.update_missing(mergeObj1);
912  return ret;
913 }
914 
915 template <typename K>
917  K&& key) {
918  auto& obj = get<ObjectImpl>();
919  return obj.erase(std::forward<K>(key));
920 }
921 inline std::size_t dynamic::erase(StringPiece key) {
922  auto& obj = get<ObjectImpl>();
923  return obj.erase(key);
924 }
925 
927  auto& arr = get<Array>();
928  // std::vector doesn't have an erase method that works on const iterators,
929  // even though the standard says it should, so this hack converts to a
930  // non-const iterator before calling erase.
931  return get<Array>().erase(arr.begin() + (it - arr.begin()));
932 }
933 
935  return const_key_iterator(get<ObjectImpl>().erase(it.base()));
936 }
937 
940  const_key_iterator last) {
941  return const_key_iterator(get<ObjectImpl>().erase(first.base(), last.base()));
942 }
943 
945  return value_iterator(get<ObjectImpl>().erase(it.base()));
946 }
947 
950  const_value_iterator last) {
951  return value_iterator(get<ObjectImpl>().erase(first.base(), last.base()));
952 }
953 
955  return item_iterator(get<ObjectImpl>().erase(it.base()));
956 }
957 
960  const_item_iterator last) {
961  return item_iterator(get<ObjectImpl>().erase(first.base(), last.base()));
962 }
963 
964 inline void dynamic::resize(std::size_t sz, dynamic const& c) {
965  auto& arr = get<Array>();
966  arr.resize(sz, c);
967 }
968 
969 inline void dynamic::push_back(dynamic const& v) {
970  auto& arr = get<Array>();
971  arr.push_back(v);
972 }
973 
974 inline void dynamic::push_back(dynamic&& v) {
975  auto& arr = get<Array>();
976  arr.push_back(std::move(v));
977 }
978 
979 inline void dynamic::pop_back() {
980  auto& arr = get<Array>();
981  arr.pop_back();
982 }
983 
985 
987  new (&u_.array) Array(std::move(r));
988 }
989 
990 #define FOLLY_DYNAMIC_DEC_TYPEINFO(T, str, val) \
991  template <> \
992  struct dynamic::TypeInfo<T> { \
993  static constexpr const char* name = str; \
994  static constexpr dynamic::Type type = val; \
995  }; \
996  //
997 
1005 
1006 #undef FOLLY_DYNAMIC_DEC_TYPEINFO
1007 
1008 template <class T>
1010  switch (type()) {
1011  case INT64:
1012  return to<T>(*get_nothrow<int64_t>());
1013  case DOUBLE:
1014  return to<T>(*get_nothrow<double>());
1015  case BOOL:
1016  return to<T>(*get_nothrow<bool>());
1017  case STRING:
1018  return to<T>(*get_nothrow<std::string>());
1019  default:
1020  throw_exception<TypeError>("int/double/bool/string", type());
1021  }
1022 }
1023 
1024 // Return a T* to our type, or null if we're not that type.
1025 // clang-format off
1026 template <class T>
1028  if (type_ != TypeInfo<T>::type) {
1029  return nullptr;
1030  }
1031  return getAddress<T>();
1032 }
1033 // clang-format on
1034 
1035 template <class T>
1037  return const_cast<dynamic*>(this)->get_nothrow<T>();
1038 }
1039 
1040 // Return T* for where we can put a T, without type checking. (Memory
1041 // might be uninitialized, even.)
1042 template <class T>
1044  return GetAddrImpl<T>::get(u_);
1045 }
1046 
1047 template <class T>
1049  return const_cast<dynamic*>(this)->getAddress<T>();
1050 }
1051 
1052 template <class T>
1054 template <>
1055 struct dynamic::GetAddrImpl<std::nullptr_t> {
1056  static std::nullptr_t* get(Data& d) noexcept {
1057  return &d.nul;
1058  }
1059 };
1060 template <>
1062  static Array* get(Data& d) noexcept {
1063  return &d.array;
1064  }
1065 };
1066 template <>
1067 struct dynamic::GetAddrImpl<bool> {
1068  static bool* get(Data& d) noexcept {
1069  return &d.boolean;
1070  }
1071 };
1072 template <>
1073 struct dynamic::GetAddrImpl<int64_t> {
1074  static int64_t* get(Data& d) noexcept {
1075  return &d.integer;
1076  }
1077 };
1078 template <>
1079 struct dynamic::GetAddrImpl<double> {
1080  static double* get(Data& d) noexcept {
1081  return &d.doubl;
1082  }
1083 };
1084 template <>
1085 struct dynamic::GetAddrImpl<std::string> {
1086  static std::string* get(Data& d) noexcept {
1087  return &d.string;
1088  }
1089 };
1090 template <>
1091 struct dynamic::GetAddrImpl<dynamic::ObjectImpl> {
1092  static_assert(
1093  sizeof(ObjectImpl) <= sizeof(Data::objectBuffer),
1094  "In your implementation, F14NodeMap<> apparently takes different"
1095  " amount of space depending on its template parameters. This is "
1096  "weird. Make objectBuffer bigger if you want to compile dynamic.");
1097 
1098  static ObjectImpl* get(Data& d) noexcept {
1099  void* data = &d.objectBuffer;
1100  return static_cast<ObjectImpl*>(data);
1101  }
1102 };
1103 
1104 template <class T>
1106  if (auto* p = get_nothrow<T>()) {
1107  return *p;
1108  }
1109  throw_exception<TypeError>(TypeInfo<T>::name, type());
1110 }
1111 
1112 template <class T>
1113 T const& dynamic::get() const {
1114  return const_cast<dynamic*>(this)->get<T>();
1115 }
1116 
1118 
1119 /*
1120  * Helper for implementing operator<<. Throws if the type shouldn't
1121  * support it.
1122  */
1123 template <class T>
1125  static void print(dynamic const&, std::ostream& out, T const& t) {
1126  out << t;
1127  }
1128 };
1129 // Otherwise, null, being (void*)0, would print as 0.
1130 template <>
1131 struct dynamic::PrintImpl<std::nullptr_t> {
1132  static void
1133  print(dynamic const& /* d */, std::ostream& out, std::nullptr_t const&) {
1134  out << "null";
1135  }
1136 };
1137 template <>
1138 struct dynamic::PrintImpl<dynamic::ObjectImpl> {
1139  static void
1140  print(dynamic const& d, std::ostream& out, dynamic::ObjectImpl const&) {
1141  d.print_as_pseudo_json(out);
1142  }
1143 };
1144 template <>
1145 struct dynamic::PrintImpl<dynamic::Array> {
1146  static void
1147  print(dynamic const& d, std::ostream& out, dynamic::Array const&) {
1148  d.print_as_pseudo_json(out);
1149  }
1150 };
1151 
1152 inline void dynamic::print(std::ostream& out) const {
1153 #define FB_X(T) PrintImpl<T>::print(*this, out, *getAddress<T>())
1155 #undef FB_X
1156 }
1157 
1158 inline std::ostream& operator<<(std::ostream& out, dynamic const& d) {
1159  d.print(out);
1160  return out;
1161 }
1162 
1164 
1165 // Secialization of FormatValue so dynamic objects can be formatted
1166 template <>
1168  public:
1169  explicit FormatValue(const dynamic& val) : val_(val) {}
1170 
1171  template <class FormatCallback>
1172  void format(FormatArg& arg, FormatCallback& cb) const {
1173  switch (val_.type()) {
1174  case dynamic::NULLT:
1175  FormatValue<std::nullptr_t>(nullptr).format(arg, cb);
1176  break;
1177  case dynamic::BOOL:
1178  FormatValue<bool>(val_.asBool()).format(arg, cb);
1179  break;
1180  case dynamic::INT64:
1181  FormatValue<int64_t>(val_.asInt()).format(arg, cb);
1182  break;
1183  case dynamic::STRING:
1184  FormatValue<std::string>(val_.asString()).format(arg, cb);
1185  break;
1186  case dynamic::DOUBLE:
1187  FormatValue<double>(val_.asDouble()).format(arg, cb);
1188  break;
1189  case dynamic::ARRAY:
1190  FormatValue(val_.at(arg.splitIntKey())).format(arg, cb);
1191  break;
1192  case dynamic::OBJECT:
1193  FormatValue(val_.at(arg.splitKey().toString())).format(arg, cb);
1194  break;
1195  }
1196  }
1197 
1198  private:
1199  const dynamic& val_;
1200 };
1201 
1202 template <class V>
1204  public:
1206  : val_(val) {}
1207 
1208  template <class FormatCallback>
1209  void format(FormatArg& arg, FormatCallback& cb) const {
1210  auto& c = val_.container;
1211  switch (c.type()) {
1212  case dynamic::NULLT:
1213  case dynamic::BOOL:
1214  case dynamic::INT64:
1215  case dynamic::STRING:
1216  case dynamic::DOUBLE:
1217  FormatValue<dynamic>(c).format(arg, cb);
1218  break;
1219  case dynamic::ARRAY: {
1220  int key = arg.splitIntKey();
1221  if (key >= 0 && size_t(key) < c.size()) {
1222  FormatValue<dynamic>(c.at(key)).format(arg, cb);
1223  } else {
1224  FormatValue<V>(val_.defaultValue).format(arg, cb);
1225  }
1226  break;
1227  }
1228  case dynamic::OBJECT: {
1229  auto pos = c.find(arg.splitKey());
1230  if (pos != c.items().end()) {
1231  FormatValue<dynamic>(pos->second).format(arg, cb);
1232  } else {
1233  FormatValue<V>(val_.defaultValue).format(arg, cb);
1234  }
1235  break;
1236  }
1237  }
1238  }
1239 
1240  private:
1242 };
1243 
1244 } // namespace folly
1245 
1246 #undef FB_DYNAMIC_APPLY
dynamic & dereference() const
Definition: dynamic-inl.h:278
IterableProxy< const_value_iterator > values() const
Definition: dynamic-inl.h:471
const_key_iterator(dynamic::ObjectImpl::const_iterator b)
Definition: dynamic-inl.h:313
const char * data() const &
Definition: dynamic-inl.h:570
static ObjectMaker object()
Definition: dynamic-inl.h:240
std::vector< dynamic > Array
Definition: dynamic.h:90
void * object
Definition: AtFork.cpp:32
StringPiece stringPiece() const
Definition: dynamic-inl.h:576
IfIsNonStringDynamicConvertible< K, dynamic > getDefault(K &&k, const dynamic &v=dynamic::object) const &
Definition: dynamic-inl.h:685
#define FB_X(T)
static bool comp(ObjectImpl const &, ObjectImpl const &)
Definition: dynamic-inl.h:588
auto v
std::unique_ptr< int > A
dynamic const & atImpl(dynamic const &) const &
Definition: dynamic.cpp:169
T const & get() const
Definition: dynamic-inl.h:1113
char b
double getDouble() const &
Definition: dynamic-inl.h:534
#define FOLLY_DYNAMIC_DEC_TYPEINFO(T, str, val)
Definition: dynamic-inl.h:990
item_iterator(dynamic::ObjectImpl::iterator b)
Definition: dynamic-inl.h:259
static bool comp(T const &a, T const &b)
Definition: dynamic-inl.h:582
dynamic & operator/=(dynamic const &)
Definition: dynamic-inl.h:619
std::enable_if_t< std::is_convertible< A, StringPiece >::value, bool > operator()(A const &lhs, dynamic const &rhs) const
Definition: dynamic-inl.h:62
I const & base() const
Definition: Iterators.h:184
std::aligned_storage< sizeof(F14NodeMap< int, int >), alignof(F14NodeMap< int, int >)>::type objectBuffer
Definition: dynamic.h:709
#define FB_DYNAMIC_INTEGER_OP(op)
Definition: dynamic-inl.h:624
static void print(dynamic const &d, std::ostream &out, dynamic::Array const &)
Definition: dynamic-inl.h:1147
Array::iterator iterator
Definition: dynamic.h:118
~dynamic() noexcept
Definition: dynamic-inl.h:385
T * getAddress() noexcept
Definition: dynamic-inl.h:1043
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
size_t operator()(::folly::dynamic const &d) const
Definition: dynamic-inl.h:86
double asDouble() const
Definition: dynamic-inl.h:521
FormatValue(const dynamic &val)
Definition: dynamic-inl.h:1169
std::enable_if_t< !std::is_convertible< K, StringPiece >::value &&std::is_convertible< K, dynamic >::value, T > IfIsNonStringDynamicConvertible
Definition: dynamic.h:371
STL namespace.
constexpr size_type size() const
Definition: Range.h:431
double val
Definition: String.cpp:273
IfIsNonStringDynamicConvertible< K, std::size_t > count(K &&) const
Definition: dynamic-inl.h:843
StringPiece splitKey()
Definition: FormatArg.h:222
void destroy() noexcept
Definition: dynamic.cpp:330
bool operator()(const dynamic &lhs, const dynamic &rhs) const
Definition: dynamic-inl.h:47
const std::string & getString() const &
Definition: dynamic-inl.h:531
const_item_iterator(dynamic::ObjectImpl::const_iterator b)
Definition: dynamic-inl.h:294
union folly::dynamic::Data u_
folly::std T
bool asBool() const
Definition: dynamic-inl.h:527
internal::ArgsMatcher< InnerMatcher > Args(const InnerMatcher &matcher)
static bool comp(std::nullptr_t const &, std::nullptr_t const &)
Definition: dynamic-inl.h:595
std::size_t hash() const
Definition: dynamic.cpp:294
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
#define FOLLY_EXPORT
Definition: CPortability.h:133
IfIsNonStringDynamicConvertible< K, dynamic & > setDefault(K &&k, V &&v)
Definition: dynamic-inl.h:731
requires E e noexcept(noexcept(s.error(std::move(e))))
const_value_iterator(value_iterator i)
Definition: dynamic-inl.h:335
#define nullptr
Definition: http_parser.c:41
static void print(dynamic const &d, std::ostream &out, dynamic::ObjectImpl const &)
Definition: dynamic-inl.h:1140
const_value_iterator(dynamic::ObjectImpl::const_iterator b)
Definition: dynamic-inl.h:333
#define STRING
bool isBool() const
Definition: dynamic-inl.h:495
#define FB_DYNAMIC_APPLY(type, apply)
Definition: dynamic-inl.h:97
bool isArray() const
Definition: dynamic-inl.h:498
bool isNumber() const
Definition: dynamic-inl.h:510
FOLLY_PUSH_WARNING RHS rhs
Definition: Traits.h:649
static dynamic merge(const dynamic &mergeObj1, const dynamic &mergeObj2)
Definition: dynamic-inl.h:904
IfIsNonStringDynamicConvertible< K, dynamic & > operator[](K &&)&
Definition: dynamic-inl.h:657
dynamic const & dereference() const
Definition: dynamic-inl.h:318
const dynamic * get_ptrImpl(dynamic const &) const &
Definition: dynamic.cpp:243
int64_t getInt() const &
Definition: dynamic-inl.h:537
bool isNull() const
Definition: dynamic-inl.h:507
bool empty() const
Definition: dynamic-inl.h:815
std::string asString() const
Definition: dynamic-inl.h:518
bool isString() const
Definition: dynamic-inl.h:489
dynamic & operator--()
Definition: dynamic-inl.h:645
std::string string
Definition: dynamic.h:698
constexpr Iter data() const
Definition: Range.h:446
ObjectMaker(dynamic key, dynamic val)
Definition: dynamic-inl.h:210
void insert(K &&, V &&val)
Definition: dynamic-inl.h:853
void format(FormatArg &arg, FormatCallback &cb) const
Definition: dynamic-inl.h:1209
int64_t asInt() const
Definition: dynamic-inl.h:524
IfIsNonStringDynamicConvertible< K, const_item_iterator > find(K &&) const
Definition: dynamic-inl.h:824
char a
void print_as_pseudo_json(std::ostream &) const
Definition: json.cpp:930
void push_back(dynamic const &)
Definition: dynamic-inl.h:969
static const char *const value
Definition: Conv.cpp:50
const_value_iterator(dynamic::ObjectImpl::iterator i)
Definition: dynamic-inl.h:336
IfIsNonStringDynamicConvertible< K, std::size_t > erase(K &&)
Definition: dynamic-inl.h:916
dynamic const & dereference() const
Definition: dynamic-inl.h:341
dynamic & operator*=(dynamic const &)
Definition: dynamic-inl.h:614
IterableProxy< const_key_iterator > keys() const
Definition: dynamic-inl.h:466
#define FOLLY_LIKELY(x)
Definition: Likely.h:35
std::string toString() const
Definition: Range.h:594
dynamic & operator+=(dynamic const &)
Definition: dynamic-inl.h:600
dynamic & operator-=(dynamic const &)
Definition: dynamic-inl.h:609
void update(const dynamic &mergeObj)
Definition: dynamic-inl.h:858
T asImpl() const
Definition: dynamic-inl.h:1009
IterableProxy< const_item_iterator > items() const
Definition: dynamic-inl.h:476
const char * string
Definition: Conv.cpp:212
static void print(dynamic const &, std::ostream &out, std::nullptr_t const &)
Definition: dynamic-inl.h:1133
std::size_t size() const
Definition: dynamic.cpp:275
static void print(dynamic const &, std::ostream &out, T const &t)
Definition: dynamic-inl.h:1125
void format(FormatArg &arg, FormatCallback &cb) const
Definition: dynamic-inl.h:1172
static void array(EmptyArrayTag)
Definition: dynamic-inl.h:233
static set< string > s
const
Definition: upload.py:398
value_iterator(dynamic::ObjectImpl::iterator b)
Definition: dynamic-inl.h:274
Definition: Traits.h:577
bool getBool() const &
Definition: dynamic-inl.h:540
bool isInt() const
Definition: dynamic-inl.h:504
Formatter< false, Args... > format(StringPiece fmt, Args &&...args)
Definition: Format.h:271
IfIsNonStringDynamicConvertible< K, dynamic const & > at(K &&) const &
Definition: dynamic-inl.h:792
const detail::DefaultValueWrapper< dynamic, V > & val_
Definition: dynamic-inl.h:1241
IterableProxy(object_type *o)
Definition: dynamic-inl.h:452
std::enable_if_t< std::is_convertible< T, StringPiece >::value, size_t > operator()(T const &val) const
Definition: dynamic-inl.h:38
Type type() const
Definition: dynamic-inl.h:514
dynamic::ObjectImpl const object_type
Definition: dynamic-inl.h:316
std::conditional_t< std::is_same< std::vector< bool >::const_reference, bool >::value, VectorBoolConstRefFake, std::vector< bool >::const_reference > VectorBoolConstRefCtorType
Definition: dynamic.h:115
friend std::ostream & operator<<(std::ostream &, dynamic const &)
Definition: dynamic-inl.h:1158
constexpr auto kIsObjC
Definition: Portability.h:349
std::enable_if_t< std::is_convertible< B, StringPiece >::value, bool > operator()(dynamic const &lhs, B const &rhs) const
Definition: dynamic-inl.h:70
dynamic::ObjectImpl const object_type
Definition: dynamic-inl.h:339
void update_missing(const dynamic &other)
Definition: dynamic-inl.h:868
const_iterator begin() const
Definition: dynamic-inl.h:432
Array::const_iterator const_iterator
Definition: dynamic.h:119
PUSHMI_INLINE_VAR constexpr detail::get_fn< T > get
Definition: submit.h:391
static void destroy(T *t)
Definition: dynamic-inl.h:158
dynamic::ObjectImpl const object_type
Definition: dynamic-inl.h:300
char c
void merge_patch(const dynamic &patch)
Definition: dynamic-inl.h:881
KeyT k
bool isObject() const
Definition: dynamic-inl.h:492
bool isDouble() const
Definition: dynamic-inl.h:501
dynamic numericOp(dynamic const &a, dynamic const &b)
Definition: dynamic-inl.h:169
void print(std::ostream &) const
Definition: dynamic-inl.h:1152
void resize(std::size_t n, dynamic const &=nullptr)
Definition: dynamic-inl.h:964
T * get_nothrow()&noexcept
Definition: dynamic-inl.h:1027
dynamic & operator++()
Definition: dynamic-inl.h:640
const_item_iterator(const_item_iterator const &i)
Definition: dynamic-inl.h:296
size_t operator()(dynamic const &d) const
Definition: dynamic-inl.h:32
FormatValue(const detail::DefaultValueWrapper< dynamic, V > &val)
Definition: dynamic-inl.h:1205
const_iterator end() const
Definition: dynamic-inl.h:435
const dynamic * get_ptr(json_pointer const &) const &
Definition: dynamic.cpp:371
ObjectMaker && operator()(dynamic key, dynamic val)
Definition: dynamic-inl.h:224
constexpr detail::First first
Definition: Base-inl.h:2553
const char * c_str() const &
Definition: dynamic-inl.h:573