From: Christopher Berner Date: Fri, 7 Dec 2012 21:38:28 +0000 (-0800) Subject: Add converter for containers of pairs X-Git-Tag: v0.22.0~1114 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=333ed393c83190fc6935837c3e61e4f9bc38e2bc;p=folly.git Add converter for containers of pairs Summary: Add specialized dynamic converter for containers of pairs, which can convert from a list of pairs, or from a object Test Plan: added a unit test Reviewed By: njormrod@fb.com FB internal diff: D650730 --- diff --git a/folly/DynamicConverter.h b/folly/DynamicConverter.h index b36a56cd..7068d88e 100644 --- a/folly/DynamicConverter.h +++ b/folly/DynamicConverter.h @@ -50,15 +50,8 @@ namespace folly { namespace dynamicconverter_detail { BOOST_MPL_HAS_XXX_TRAIT_DEF(value_type); -BOOST_MPL_HAS_XXX_TRAIT_DEF(key_type); -BOOST_MPL_HAS_XXX_TRAIT_DEF(mapped_type); BOOST_MPL_HAS_XXX_TRAIT_DEF(iterator); -template struct map_container_has_correct_types - : std::is_same::type, - typename T::mapped_type>, - typename T::value_type> {}; - template struct class_is_container { typedef std::reverse_iterator some_iterator; enum { value = has_value_type::value && @@ -66,13 +59,6 @@ template struct class_is_container { std::is_constructible::value }; }; -template struct container_is_map - : std::conditional< - has_key_type::value && has_mapped_type::value, - map_container_has_correct_types, - std::false_type - >::type {}; - template struct is_container : std::conditional< std::is_class::value, @@ -80,13 +66,6 @@ template struct is_container std::false_type >::type {}; -template struct is_map_container - : std::conditional< - is_container::value, - container_is_map, - std::false_type - >::type {}; - } // namespace dynamicconverter_detail /////////////////////////////////////////////////////////////////////////////// @@ -106,16 +85,33 @@ template struct is_map_container namespace dynamicconverter_detail { -template -inline void -derefToCache(std::pair* mem, const dynamic::const_item_iterator& it) { - new (mem) std::pair(convertTo(it->first), convertTo(it->second)); -} +template +struct Dereferencer { + static inline void + derefToCache(T* mem, const dynamic::const_item_iterator& it) { + throw TypeError("array", dynamic::Type::OBJECT); + } -template -inline void derefToCache(T* mem, const dynamic::const_iterator& it) { - new (mem) T(convertTo(*it)); -} + static inline void derefToCache(T* mem, const dynamic::const_iterator& it) { + new (mem) T(convertTo(*it)); + } +}; + +template +struct Dereferencer> { + static inline void + derefToCache(std::pair* mem, const dynamic::const_item_iterator& it) { + new (mem) std::pair( + convertTo(it->first), convertTo(it->second) + ); + } + + // Intentional duplication of the code in Dereferencer + template + static inline void derefToCache(T* mem, const dynamic::const_iterator& it) { + new (mem) T(convertTo(*it)); + } +}; template class Transformer : public boost::iterator_adaptor< @@ -138,7 +134,7 @@ class Transformer : public boost::iterator_adaptor< ttype& dereference() const { if (LIKELY(!valid_)) { cache_.~ttype(); - derefToCache(&cache_, this->base_reference()); + Dereferencer::derefToCache(&cache_, this->base_reference()); valid_ = true; } return cache_; @@ -226,44 +222,26 @@ struct DynamicConverter> { } }; -// map containers +// containers template struct DynamicConverter::value>::type> { + dynamicconverter_detail::is_container::value>::type> { static C convert(const dynamic& d) { - if (LIKELY(d.isObject())) { + if (d.isArray()) { + return C(dynamicconverter_detail::conversionIterator(d.begin()), + dynamicconverter_detail::conversionIterator(d.end())); + } else if (d.isObject()) { return C(dynamicconverter_detail::conversionIterator (d.items().begin()), dynamicconverter_detail::conversionIterator (d.items().end())); - } else if (d.isArray()) { - return C(dynamicconverter_detail::conversionIterator(d.begin()), - dynamicconverter_detail::conversionIterator(d.end())); } else { throw TypeError("object or array", d.type()); } } }; -// non-map containers -template -struct DynamicConverter::value && - !dynamicconverter_detail::is_map_container::value - >::type - > { - static C convert(const dynamic& d) { - if (LIKELY(d.isArray())) { - return C(dynamicconverter_detail::conversionIterator(d.begin()), - dynamicconverter_detail::conversionIterator(d.end())); - } else { - throw TypeError("array", d.type()); - } - } -}; - /////////////////////////////////////////////////////////////////////////////// // convertTo implementation diff --git a/folly/test/DynamicConverterTest.cpp b/folly/test/DynamicConverterTest.cpp index 0dd06671..47e87dc0 100644 --- a/folly/test/DynamicConverterTest.cpp +++ b/folly/test/DynamicConverterTest.cpp @@ -41,19 +41,6 @@ TEST(DynamicConverter, template_metaprogramming) { EXPECT_EQ(c1t, true); EXPECT_EQ(c2t, true); EXPECT_EQ(c3t, true); - - bool m1f = is_map_container::value; - bool m2f = is_map_container>::value; - bool m3f = is_map_container>::value; - - bool m1t = is_map_container>::value; - bool m2t = is_map_container>::value; - - EXPECT_EQ(m1f, false); - EXPECT_EQ(m2f, false); - EXPECT_EQ(m3f, false); - EXPECT_EQ(m1t, true); - EXPECT_EQ(m2t, true); } TEST(DynamicConverter, arithmetic_types) { @@ -153,6 +140,13 @@ TEST(DynamicConverter, map_keyed_by_string) { EXPECT_EQ(i2, i2b); } +TEST(DynamicConverter, map_to_vector_of_pairs) { + dynamic d1 = dynamic::object("1", "one")("2", "two"); + auto i1 = convertTo>>(d1); + decltype(i1) i1b = { { "1", "one" }, { "2", "two" } }; + EXPECT_EQ(i1, i1b); +} + TEST(DynamicConverter, nested_containers) { dynamic d1 = { { 1 }, { }, { 2, 3 } }; auto i1 = convertTo>>(d1);