From: Tom Jackson Date: Fri, 27 Sep 2013 00:12:38 +0000 (-0700) Subject: dynamic::get_ptr X-Git-Tag: v0.22.0~862 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=7eccc5a30a8c37d9202754712a5f51549f611944;p=folly.git 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 --- diff --git a/folly/dynamic-inl.h b/folly/dynamic-inl.h index bae776a2..1893f051 100644 --- a/folly/dynamic-inl.h +++ b/folly/dynamic-inl.h @@ -525,32 +525,53 @@ template inline dynamic& dynamic::setDefault(K&& k, V&& v) { std::forward(v))).first->second; } -inline dynamic const& dynamic::at(dynamic const& idx) const { - return const_cast(this)->at(idx); +inline dynamic* dynamic::get_ptr(dynamic const& idx) { + return const_cast(const_cast(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()) { + if (!idx.isInt()) { + throw TypeError("int64", idx.type()); + } + if (idx >= parray->size()) { + return nullptr; + } + return &(*parray)[idx.asInt()]; + } else if (auto* pobject = get_nothrow()) { + 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(const_cast(this)->at(idx)); +} + +inline dynamic const& dynamic::at(dynamic const& idx) const { if (auto* parray = get_nothrow()) { - 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()) { + auto it = pobject->find(idx); + if (it == pobject->end()) { + throw std::out_of_range(to( + "couldn't find key ", idx.asString(), " in dynamic object")); + } + return it->second; + } else { + throw TypeError("object/array", type()); } - - assert(get_nothrow()); - auto it = find(idx); - if (it == items().end()) { - throw std::out_of_range(to( - "couldn't find key ", idx.asString(), " in dynamic object")); - } - return const_cast(it->second); } inline bool dynamic::empty() const { diff --git a/folly/dynamic.h b/folly/dynamic.h index 3a1193f3..41680543 100644 --- a/folly/dynamic.h +++ b/folly/dynamic.h @@ -316,6 +316,7 @@ public: */ 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. @@ -333,6 +334,20 @@ public: 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. * diff --git a/folly/test/DynamicTest.cpp b/folly/test/DynamicTest.cpp index f97ad5f9..163c6d35 100644 --- a/folly/test/DynamicTest.cpp +++ b/folly/test/DynamicTest.cpp @@ -14,12 +14,13 @@ * limitations under the License. */ -#include "folly/dynamic.h" -#include "folly/json.h" -#include -#include #include +#include +#include + #include "folly/Benchmark.h" +#include "folly/dynamic.h" +#include "folly/json.h" using folly::dynamic; @@ -271,6 +272,24 @@ TEST(Dynamic, ObjectForwarding) { ("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);