From 04c09cf0f89fe94ccd3ae71ca5c9470fe8a3371c Mon Sep 17 00:00:00 2001 From: Tom Jackson Date: Tue, 23 Apr 2013 10:02:07 -0700 Subject: [PATCH] toDynamic(T) Summary: It only makes sense to be able to go the other direction, too. Test Plan: Unit tests Reviewed By: delong.j@fb.com FB internal diff: D785282 --- folly/DynamicConverter.h | 72 +++++++++++++++++++++++++++++ folly/test/DynamicConverterTest.cpp | 51 +++++++++++++++++++- 2 files changed, 122 insertions(+), 1 deletion(-) diff --git a/folly/DynamicConverter.h b/folly/DynamicConverter.h index 3455f64d..2c3d2c1d 100644 --- a/folly/DynamicConverter.h +++ b/folly/DynamicConverter.h @@ -22,6 +22,7 @@ #include "folly/dynamic.h" namespace folly { template T convertTo(const dynamic&); + template dynamic toDynamic(const T&); } /** @@ -51,6 +52,7 @@ namespace dynamicconverter_detail { BOOST_MPL_HAS_XXX_TRAIT_DEF(value_type); BOOST_MPL_HAS_XXX_TRAIT_DEF(iterator); +BOOST_MPL_HAS_XXX_TRAIT_DEF(mapped_type); template struct class_is_container { typedef std::reverse_iterator some_iterator; @@ -59,6 +61,12 @@ template struct class_is_container { std::is_constructible::value }; }; +template struct class_is_range { + enum { value = has_value_type::value && + has_iterator::value }; +}; + + template struct is_container : std::conditional< std::is_class::value, @@ -66,6 +74,19 @@ template struct is_container std::false_type >::type {}; +template struct is_range + : std::conditional< + std::is_class::value, + class_is_range, + std::false_type + >::type {}; + +template struct is_associative_container + : std::integral_constant< + bool, + is_range::value && has_mapped_type::value + > {}; + } // namespace dynamicconverter_detail /////////////////////////////////////////////////////////////////////////////// @@ -240,6 +261,52 @@ struct DynamicConverter +struct DynamicConstructor { + static dynamic construct(const C& x) { + return dynamic(x); + } +}; + +template +struct DynamicConstructor::value>::type> { + static dynamic construct(const C& x) { + dynamic d = dynamic::object; + for (auto& pair : x) { + d.insert(toDynamic(pair.first), toDynamic(pair.second)); + } + return d; + } +}; + +template +struct DynamicConstructor::value && + !std::is_constructible::value && + dynamicconverter_detail::is_range::value>::type> { + static dynamic construct(const C& x) { + dynamic d = {}; + for (auto& item : x) { + d.push_back(toDynamic(item)); + } + return d; + } +}; + +template +struct DynamicConstructor, void> { + static dynamic construct(const std::pair& x) { + dynamic d = {}; + d.push_back(toDynamic(x.first)); + d.push_back(toDynamic(x.second)); + return d; + } }; /////////////////////////////////////////////////////////////////////////////// @@ -250,6 +317,11 @@ T convertTo(const dynamic& d) { return DynamicConverter::type>::convert(d); } +template +dynamic toDynamic(const T& x) { + return DynamicConstructor::type>::construct(x); +} + } // namespace folly #endif // DYNAMIC_CONVERTER_H diff --git a/folly/test/DynamicConverterTest.cpp b/folly/test/DynamicConverterTest.cpp index 83c95b18..c94a00c6 100644 --- a/folly/test/DynamicConverterTest.cpp +++ b/folly/test/DynamicConverterTest.cpp @@ -19,8 +19,11 @@ #include "folly/DynamicConverter.h" #include -#include #include +#include +#include +#include + #include "folly/Benchmark.h" using namespace folly; @@ -267,6 +270,7 @@ struct Token { explicit Token(int kind, const fbstring& lexeme) : kind_(kind), lexeme_(lexeme) {} }; + namespace folly { template <> struct DynamicConverter { static Token convert(const dynamic& d) { @@ -276,6 +280,7 @@ template <> struct DynamicConverter { } }; } + TEST(DynamicConverter, example) { dynamic d1 = dynamic::object("KIND", 2)("LEXEME", "a token"); auto i1 = convertTo(d1); @@ -283,6 +288,50 @@ TEST(DynamicConverter, example) { EXPECT_EQ(i1.lexeme_, "a token"); } +TEST(DynamicConverter, construct) { + using std::vector; + using std::map; + using std::pair; + using std::string; + { + vector c { 1, 2, 3 }; + dynamic d = { 1, 2, 3 }; + EXPECT_EQ(d, toDynamic(c)); + } + + { + map c { { 2, 4 }, { 3, 9 } }; + dynamic d = dynamic::object(2, 4)(3, 9); + EXPECT_EQ(d, toDynamic(c)); + } + + { + map c { { "a", "b" } }; + dynamic d = dynamic::object("a", "b"); + EXPECT_EQ(d, toDynamic(c)); + } + + { + map> c { { "a", { "b", 3 } } }; + dynamic d = dynamic::object("a", dynamic { "b", 3 }); + EXPECT_EQ(d, toDynamic(c)); + } + + { + map> c { { "a", { "b", 3 } } }; + dynamic d = dynamic::object("a", dynamic { "b", 3 }); + EXPECT_EQ(d, toDynamic(c)); + } + + { + vector vi { 2, 3, 4, 5 }; + auto c = std::make_pair(makeRange(vi.begin(), vi.begin() + 3), + makeRange(vi.begin() + 1, vi.begin() + 4)); + dynamic d = { { 2, 3, 4 }, { 3, 4, 5 } }; + EXPECT_EQ(d, toDynamic(c)); + } +} + int main(int argc, char ** argv) { testing::InitGoogleTest(&argc, argv); google::ParseCommandLineFlags(&argc, &argv, true); -- 2.34.1