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());
}
-
- assert(get_nothrow<ObjectImpl>());
- 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 {
*/
const_item_iterator find(dynamic const&) const;
+
/*
* If this is an object, returns whether it contains a field with
* the given name. Otherwise throws TypeError.
dynamic const& at(dynamic const&) const;
dynamic& at(dynamic const&);
+ /*
+ * Like 'at', above, except it returns either a pointer to the contained
+ * object or nullptr if it wasn't found. This allows a key to be tested for
+ * containment and retrieved in one operation. Example:
+ *
+ * if (auto* found = d.get_ptr(key))
+ * // use *found;
+ *
+ * Using these with dynamic objects that are not arrays or objects
+ * will throw a TypeError.
+ */
+ const dynamic* get_ptr(dynamic const&) const;
+ dynamic* get_ptr(dynamic const&);
+
/*
* This works for access to both objects and arrays.
*
* limitations under the License.
*/
-#include "folly/dynamic.h"
-#include "folly/json.h"
-#include <gtest/gtest.h>
-#include <gflags/gflags.h>
#include <boost/next_prior.hpp>
+#include <gflags/gflags.h>
+#include <gtest/gtest.h>
+
#include "folly/Benchmark.h"
+#include "folly/dynamic.h"
+#include "folly/json.h"
using folly::dynamic;
("key", "value1");
}
+TEST(Dynamic, GetPtr) {
+ dynamic array = { 1, 2, "three" };
+ EXPECT_TRUE(array.get_ptr(0));
+ EXPECT_FALSE(array.get_ptr(3));
+ EXPECT_EQ(dynamic("three"), *array.get_ptr(2));
+ const dynamic& carray = array;
+ EXPECT_EQ(dynamic("three"), *carray.get_ptr(2));
+
+ dynamic object = dynamic::object("one", 1)("two", 2);
+ EXPECT_TRUE(object.get_ptr("one"));
+ EXPECT_FALSE(object.get_ptr("three"));
+ EXPECT_EQ(dynamic(2), *object.get_ptr("two"));
+ *object.get_ptr("one") = 11;
+ EXPECT_EQ(dynamic(11), *object.get_ptr("one"));
+ const dynamic& cobject = object;
+ EXPECT_EQ(dynamic(2), *cobject.get_ptr("two"));
+}
+
int main(int argc, char** argv) {
testing::InitGoogleTest(&argc, argv);
google::ParseCommandLineFlags(&argc, &argv, true);