std::false_type
>::type {};
-template <typename T> struct is_associative_container
+template <typename T> struct is_map
: std::integral_constant<
bool,
is_range<T>::value && has_mapped_type<T>::value
///////////////////////////////////////////////////////////////////////////////
// DynamicConverter specializations
-template <typename T, typename Enable = void> struct DynamicConverter;
-
/**
* Each specialization of DynamicConverter has the function
- * 'static T convert(const dynamic& d);'
+ * 'static T convert(const dynamic&);'
*/
+// default - intentionally unimplemented
+template <typename T, typename Enable = void> struct DynamicConverter;
+
// boolean
template <>
struct DynamicConverter<bool> {
typename std::enable_if<std::is_integral<T>::value &&
!std::is_same<T, bool>::value>::type> {
static T convert(const dynamic& d) {
- return static_cast<T>(d.asInt());
+ return folly::to<T>(d.asInt());
}
};
struct DynamicConverter<T,
typename std::enable_if<std::is_floating_point<T>::value>::type> {
static T convert(const dynamic& d) {
- return static_cast<T>(d.asDouble());
+ return folly::to<T>(d.asDouble());
}
};
throw TypeError("object or array", d.type());
}
}
-
};
+///////////////////////////////////////////////////////////////////////////////
+// DynamicConstructor specializations
+
+/**
+ * Each specialization of DynamicConstructor has the function
+ * 'static dynamic construct(const C&);'
+ */
+
+// default
template <typename C, typename Enable = void>
struct DynamicConstructor {
static dynamic construct(const C& x) {
}
};
+// maps
template<typename C>
struct DynamicConstructor<C,
typename std::enable_if<
- dynamicconverter_detail::is_associative_container<C>::value>::type> {
+ dynamicconverter_detail::is_map<C>::value>::type> {
static dynamic construct(const C& x) {
dynamic d = dynamic::object;
for (auto& pair : x) {
}
};
+// other ranges
template<typename C>
struct DynamicConstructor<C,
typename std::enable_if<
- !dynamicconverter_detail::is_associative_container<C>::value &&
+ !dynamicconverter_detail::is_map<C>::value &&
!std::is_constructible<StringPiece, const C&>::value &&
dynamicconverter_detail::is_range<C>::value>::type> {
static dynamic construct(const C& x) {
}
};
+// pair
template<typename A, typename B>
struct DynamicConstructor<std::pair<A, B>, void> {
static dynamic construct(const std::pair<A, B>& x) {
};
///////////////////////////////////////////////////////////////////////////////
-// convertTo implementation
+// implementation
template <typename T>
T convertTo(const dynamic& d) {
EXPECT_EQ(c1t, true);
EXPECT_EQ(c2t, true);
EXPECT_EQ(c3t, true);
+
+
+ bool m1f = is_map<int>::value;
+ bool m2f = is_map<std::set<int>>::value;
+
+ bool m1t = is_map<std::map<int, int>>::value;
+
+ EXPECT_EQ(m1f, false);
+ EXPECT_EQ(m2f, false);
+ EXPECT_EQ(m1t, true);
+
+
+ bool r1f = is_range<int>::value;
+
+ bool r1t = is_range<std::set<int>>::value;
+ bool r2t = is_range<std::vector<int>>::value;
+
+ EXPECT_EQ(r1f, false);
+ EXPECT_EQ(r1t, true);
+ EXPECT_EQ(r2t, true);
}
TEST(DynamicConverter, arithmetic_types) {
auto i2 = convertTo<int64_t>(d2);
EXPECT_EQ(i2, 123456789012345);
- dynamic d3 = 123456789012345;
- auto i3 = convertTo<uint8_t>(d3);
- EXPECT_EQ(i3, 121);
-
dynamic d4 = 3.141;
auto i4 = convertTo<float>(d4);
EXPECT_EQ((int)(i4*100), 314);
}
}
+TEST(DynamicConverter, errors) {
+ const auto int32Over =
+ static_cast<int64_t>(std::numeric_limits<int32_t>().max()) + 1;
+ const auto floatOver =
+ static_cast<double>(std::numeric_limits<float>().max()) * 2;
+
+ dynamic d1 = int32Over;
+ EXPECT_THROW(convertTo<int32_t>(d1), std::range_error);
+
+ dynamic d2 = floatOver;
+ EXPECT_THROW(convertTo<float>(d2), std::range_error);
+}
+
int main(int argc, char ** argv) {
testing::InitGoogleTest(&argc, argv);
google::ParseCommandLineFlags(&argc, &argv, true);