Small readability improvements
[folly.git] / folly / dynamic-inl.h
index 92cd67ef794dc011e6c2fd55c9ec4d8b0ee67494..204d48f91f7af271f92f58e995a4f6cc2efe8973 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2013 Facebook, Inc.
+ * Copyright 2014 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -260,6 +260,12 @@ inline dynamic::dynamic(ObjectMaker (*)())
   new (getAddress<ObjectImpl>()) ObjectImpl();
 }
 
+inline dynamic::dynamic(StringPiece s)
+  : type_(STRING)
+{
+  new (&u_.string) fbstring(s.data(), s.size());
+}
+
 inline dynamic::dynamic(char const* s)
   : type_(STRING)
 {
@@ -272,6 +278,18 @@ inline dynamic::dynamic(std::string const& s)
   new (&u_.string) fbstring(s);
 }
 
+inline dynamic::dynamic(fbstring const& s)
+  : type_(STRING)
+{
+  new (&u_.string) fbstring(s);
+}
+
+inline dynamic::dynamic(fbstring&& s)
+  : type_(STRING)
+{
+  new (&u_.string) fbstring(std::move(s));
+}
+
 inline dynamic::dynamic(std::initializer_list<dynamic> il)
   : type_(ARRAY)
 {
@@ -325,6 +343,7 @@ inline dynamic::const_iterator dynamic::end() const {
 template <class It>
 struct dynamic::IterableProxy {
   typedef It const_iterator;
+  typedef typename It::value_type value_type;
 
   /* implicit */ IterableProxy(const dynamic::ObjectImpl* o) : o_(o) { }
 
@@ -373,6 +392,9 @@ inline double   dynamic::asDouble() const { return asImpl<double>(); }
 inline int64_t  dynamic::asInt()    const { return asImpl<int64_t>(); }
 inline bool     dynamic::asBool()   const { return asImpl<bool>(); }
 
+inline const char* dynamic::data()  const { return get<fbstring>().data();  }
+inline const char* dynamic::c_str() const { return get<fbstring>().c_str(); }
+
 template<class T>
 struct dynamic::CompareOp {
   static bool comp(T const& a, T const& b) { return a < b; }
@@ -524,33 +546,53 @@ template<class K, class V> inline dynamic& dynamic::setDefault(K&& k, V&& v) {
                                    std::forward<V>(v))).first->second;
 }
 
-inline dynamic const& dynamic::at(dynamic const& idx) const {
-  return const_cast<dynamic*>(this)->at(idx);
+inline dynamic* dynamic::get_ptr(dynamic const& idx) {
+  return const_cast<dynamic*>(const_cast<dynamic const*>(this)->get_ptr(idx));
 }
 
-inline dynamic& dynamic::at(dynamic const& idx) {
-  if (!isObject() && !isArray()) {
+inline const dynamic* dynamic::get_ptr(dynamic const& idx) const {
+  if (auto* parray = get_nothrow<Array>()) {
+    if (!idx.isInt()) {
+      throw TypeError("int64", idx.type());
+    }
+    if (idx >= parray->size()) {
+      return nullptr;
+    }
+    return &(*parray)[idx.asInt()];
+  } else if (auto* pobject = get_nothrow<ObjectImpl>()) {
+    auto it = pobject->find(idx);
+    if (it == pobject->end()) {
+      return nullptr;
+    }
+    return &it->second;
+  } else {
     throw TypeError("object/array", type());
   }
+}
 
+inline dynamic& dynamic::at(dynamic const& idx) {
+  return const_cast<dynamic&>(const_cast<dynamic const*>(this)->at(idx));
+}
+
+inline dynamic const& dynamic::at(dynamic const& idx) const {
   if (auto* parray = get_nothrow<Array>()) {
-    if (idx >= parray->size()) {
-      throw std::out_of_range("out of range in dynamic array");
-    }
     if (!idx.isInt()) {
       throw TypeError("int64", idx.type());
     }
+    if (idx >= parray->size()) {
+      throw std::out_of_range("out of range in dynamic array");
+    }
     return (*parray)[idx.asInt()];
+  } else if (auto* pobject = get_nothrow<ObjectImpl>()) {
+    auto it = pobject->find(idx);
+    if (it == pobject->end()) {
+      throw std::out_of_range(to<std::string>(
+          "couldn't find key ", idx.asString(), " in dynamic object"));
+    }
+    return it->second;
+  } else {
+    throw TypeError("object/array", type());
   }
-
-  auto* pobj = get_nothrow<ObjectImpl>();
-  assert(pobj);
-  auto it = find(idx);
-  if (it == items().end()) {
-    throw std::out_of_range(to<std::string>(
-        "couldn't find key ", idx.asString(), " in dynamic object"));
-  }
-  return const_cast<dynamic&>(it->second);
 }
 
 inline bool dynamic::empty() const {
@@ -883,7 +925,52 @@ class FormatValue<dynamic> {
   const dynamic& val_;
 };
 
-}
+template <class V>
+class FormatValue<detail::DefaultValueWrapper<dynamic, V>> {
+ public:
+  explicit FormatValue(
+      const detail::DefaultValueWrapper<dynamic, V>& val)
+    : val_(val) { }
+
+  template <class FormatCallback>
+  void format(FormatArg& arg, FormatCallback& cb) const {
+    auto& c = val_.container;
+    switch (c.type()) {
+    case dynamic::NULLT:
+    case dynamic::BOOL:
+    case dynamic::INT64:
+    case dynamic::STRING:
+    case dynamic::DOUBLE:
+      FormatValue<dynamic>(c).format(arg, cb);
+      break;
+    case dynamic::ARRAY:
+      {
+        int key = arg.splitIntKey();
+        if (key >= 0 && key < c.size()) {
+          FormatValue<dynamic>(c.at(key)).format(arg, cb);
+        } else{
+          FormatValue<V>(val_.defaultValue).format(arg, cb);
+        }
+      }
+      break;
+    case dynamic::OBJECT:
+      {
+        auto pos = c.find(arg.splitKey());
+        if (pos != c.items().end()) {
+          FormatValue<dynamic>(pos->second).format(arg, cb);
+        } else {
+          FormatValue<V>(val_.defaultValue).format(arg, cb);
+        }
+      }
+      break;
+    }
+  }
+
+ private:
+  const detail::DefaultValueWrapper<dynamic, V>& val_;
+};
+
+}  // namespaces
 
 #undef FB_DYNAMIC_APPLY