Commit 04c09cf0 authored by Tom Jackson's avatar Tom Jackson Committed by Sara Golemon

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
parent 1408e9d5
......@@ -22,6 +22,7 @@
#include "folly/dynamic.h"
namespace folly {
template <typename T> T convertTo(const dynamic&);
template <typename T> 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 <typename T> struct class_is_container {
typedef std::reverse_iterator<T*> some_iterator;
......@@ -59,6 +61,12 @@ template <typename T> struct class_is_container {
std::is_constructible<T, some_iterator, some_iterator>::value };
};
template <typename T> struct class_is_range {
enum { value = has_value_type<T>::value &&
has_iterator<T>::value };
};
template <typename T> struct is_container
: std::conditional<
std::is_class<T>::value,
......@@ -66,6 +74,19 @@ template <typename T> struct is_container
std::false_type
>::type {};
template <typename T> struct is_range
: std::conditional<
std::is_class<T>::value,
class_is_range<T>,
std::false_type
>::type {};
template <typename T> struct is_associative_container
: std::integral_constant<
bool,
is_range<T>::value && has_mapped_type<T>::value
> {};
} // namespace dynamicconverter_detail
///////////////////////////////////////////////////////////////////////////////
......@@ -240,6 +261,52 @@ struct DynamicConverter<C,
throw TypeError("object or array", d.type());
}
}
};
template <typename C, typename Enable = void>
struct DynamicConstructor {
static dynamic construct(const C& x) {
return dynamic(x);
}
};
template<typename C>
struct DynamicConstructor<C,
typename std::enable_if<
dynamicconverter_detail::is_associative_container<C>::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<typename C>
struct DynamicConstructor<C,
typename std::enable_if<
!dynamicconverter_detail::is_associative_container<C>::value &&
!std::is_constructible<StringPiece, const C&>::value &&
dynamicconverter_detail::is_range<C>::value>::type> {
static dynamic construct(const C& x) {
dynamic d = {};
for (auto& item : x) {
d.push_back(toDynamic(item));
}
return d;
}
};
template<typename A, typename B>
struct DynamicConstructor<std::pair<A, B>, void> {
static dynamic construct(const std::pair<A, B>& 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<typename std::remove_cv<T>::type>::convert(d);
}
template<typename T>
dynamic toDynamic(const T& x) {
return DynamicConstructor<typename std::remove_cv<T>::type>::construct(x);
}
} // namespace folly
#endif // DYNAMIC_CONVERTER_H
......
......@@ -19,8 +19,11 @@
#include "folly/DynamicConverter.h"
#include <algorithm>
#include <gtest/gtest.h>
#include <gflags/gflags.h>
#include <gtest/gtest.h>
#include <map>
#include <vector>
#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<Token> {
static Token convert(const dynamic& d) {
......@@ -276,6 +280,7 @@ template <> struct DynamicConverter<Token> {
}
};
}
TEST(DynamicConverter, example) {
dynamic d1 = dynamic::object("KIND", 2)("LEXEME", "a token");
auto i1 = convertTo<Token>(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<int> c { 1, 2, 3 };
dynamic d = { 1, 2, 3 };
EXPECT_EQ(d, toDynamic(c));
}
{
map<int, int> c { { 2, 4 }, { 3, 9 } };
dynamic d = dynamic::object(2, 4)(3, 9);
EXPECT_EQ(d, toDynamic(c));
}
{
map<string, string> c { { "a", "b" } };
dynamic d = dynamic::object("a", "b");
EXPECT_EQ(d, toDynamic(c));
}
{
map<string, pair<string, int>> c { { "a", { "b", 3 } } };
dynamic d = dynamic::object("a", dynamic { "b", 3 });
EXPECT_EQ(d, toDynamic(c));
}
{
map<string, pair<string, int>> c { { "a", { "b", 3 } } };
dynamic d = dynamic::object("a", dynamic { "b", 3 });
EXPECT_EQ(d, toDynamic(c));
}
{
vector<int> 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);
......
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