Commit 7eccc5a3 authored by Tom Jackson's avatar Tom Jackson Committed by Peter Griess

dynamic::get_ptr

Summary: For testing containment and using the value in one operation.

Test Plan: Unit tests

Reviewed By: tudorb@fb.com

FB internal diff: D986986
parent e32d53e9
...@@ -525,32 +525,53 @@ template<class K, class V> inline dynamic& dynamic::setDefault(K&& k, V&& v) { ...@@ -525,32 +525,53 @@ template<class K, class V> inline dynamic& dynamic::setDefault(K&& k, V&& v) {
std::forward<V>(v))).first->second; std::forward<V>(v))).first->second;
} }
inline dynamic const& dynamic::at(dynamic const& idx) const { inline dynamic* dynamic::get_ptr(dynamic const& idx) {
return const_cast<dynamic*>(this)->at(idx); return const_cast<dynamic*>(const_cast<dynamic const*>(this)->get_ptr(idx));
} }
inline dynamic& dynamic::at(dynamic const& idx) { inline const dynamic* dynamic::get_ptr(dynamic const& idx) const {
if (!isObject() && !isArray()) { 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()); 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 (auto* parray = get_nothrow<Array>()) {
if (idx >= parray->size()) {
throw std::out_of_range("out of range in dynamic array");
}
if (!idx.isInt()) { if (!idx.isInt()) {
throw TypeError("int64", idx.type()); throw TypeError("int64", idx.type());
} }
return (*parray)[idx.asInt()]; if (idx >= parray->size()) {
throw std::out_of_range("out of range in dynamic array");
} }
return (*parray)[idx.asInt()];
assert(get_nothrow<ObjectImpl>()); } else if (auto* pobject = get_nothrow<ObjectImpl>()) {
auto it = find(idx); auto it = pobject->find(idx);
if (it == items().end()) { if (it == pobject->end()) {
throw std::out_of_range(to<std::string>( throw std::out_of_range(to<std::string>(
"couldn't find key ", idx.asString(), " in dynamic object")); "couldn't find key ", idx.asString(), " in dynamic object"));
} }
return const_cast<dynamic&>(it->second); return it->second;
} else {
throw TypeError("object/array", type());
}
} }
inline bool dynamic::empty() const { inline bool dynamic::empty() const {
......
...@@ -316,6 +316,7 @@ public: ...@@ -316,6 +316,7 @@ public:
*/ */
const_item_iterator find(dynamic const&) const; const_item_iterator find(dynamic const&) const;
/* /*
* If this is an object, returns whether it contains a field with * If this is an object, returns whether it contains a field with
* the given name. Otherwise throws TypeError. * the given name. Otherwise throws TypeError.
...@@ -333,6 +334,20 @@ public: ...@@ -333,6 +334,20 @@ public:
dynamic const& at(dynamic const&) const; dynamic const& at(dynamic const&) const;
dynamic& at(dynamic 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. * This works for access to both objects and arrays.
* *
......
...@@ -14,12 +14,13 @@ ...@@ -14,12 +14,13 @@
* limitations under the License. * 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 <boost/next_prior.hpp>
#include <gflags/gflags.h>
#include <gtest/gtest.h>
#include "folly/Benchmark.h" #include "folly/Benchmark.h"
#include "folly/dynamic.h"
#include "folly/json.h"
using folly::dynamic; using folly::dynamic;
...@@ -271,6 +272,24 @@ TEST(Dynamic, ObjectForwarding) { ...@@ -271,6 +272,24 @@ TEST(Dynamic, ObjectForwarding) {
("key", "value1"); ("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) { int main(int argc, char** argv) {
testing::InitGoogleTest(&argc, argv); testing::InitGoogleTest(&argc, argv);
google::ParseCommandLineFlags(&argc, &argv, true); google::ParseCommandLineFlags(&argc, &argv, true);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment