X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FDynamicConverter.h;h=c486d6712801c85b6dcf94852aaefb0652039049;hb=HEAD;hp=591f55a72a9ba0600ad8239ac368e5bfada303b6;hpb=dee8a5180aa542d98d1b71c74f83a006e4627952;p=folly.git diff --git a/folly/DynamicConverter.h b/folly/DynamicConverter.h index 591f55a7..c486d671 100644 --- a/folly/DynamicConverter.h +++ b/folly/DynamicConverter.h @@ -1,5 +1,5 @@ /* - * Copyright 2016 Facebook, Inc. + * Copyright 2012-present Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,11 +18,23 @@ #pragma once +#include +#include + +#include +#include + +#include +#include +#include #include + namespace folly { - template T convertTo(const dynamic&); - template dynamic toDynamic(const T&); -} +template +T convertTo(const dynamic&); +template +dynamic toDynamic(const T&); +} // namespace folly /** * convertTo returns a well-typed representation of the input dynamic. @@ -37,13 +49,6 @@ namespace folly { * See docs/DynamicConverter.md for supported types and customization */ - -#include -#include -#include -#include -#include - namespace folly { /////////////////////////////////////////////////////////////////////////////// @@ -54,6 +59,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); +BOOST_MPL_HAS_XXX_TRAIT_DEF(key_type); template struct iterator_class_is_container { typedef std::reverse_iterator some_iterator; @@ -62,38 +68,20 @@ template struct iterator_class_is_container { }; template -using class_is_container = typename - std::conditional< - has_iterator::value, - iterator_class_is_container, - std::false_type - >::type; - -template struct class_is_range { - enum { value = has_value_type::value && - has_iterator::value }; -}; +using class_is_container = + Conjunction, iterator_class_is_container>; +template +using is_range = StrictConjunction, has_iterator>; -template struct is_container - : std::conditional< - std::is_class::value, - class_is_container, - std::false_type - >::type {}; +template +using is_container = StrictConjunction, class_is_container>; -template struct is_range - : std::conditional< - std::is_class::value, - class_is_range, - std::false_type - >::type {}; +template +using is_map = StrictConjunction, has_mapped_type>; -template struct is_map - : std::integral_constant< - bool, - is_range::value && has_mapped_type::value - > {}; +template +using is_associative = StrictConjunction, has_key_type>; } // namespace dynamicconverter_detail @@ -114,70 +102,67 @@ template struct is_map namespace dynamicconverter_detail { -template +template struct Dereferencer { static inline void derefToCache( - T* /* mem */, const dynamic::const_item_iterator& /* it */) { + Optional* /* mem */, + const dynamic::const_item_iterator& /* it */) { throw TypeError("array", dynamic::Type::OBJECT); } - static inline void derefToCache(T* mem, const dynamic::const_iterator& it) { - new (mem) T(convertTo(*it)); + static inline void derefToCache( + Optional* mem, + const dynamic::const_iterator& it) { + mem->emplace(convertTo(*it)); } }; -template +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) - ); + static inline void derefToCache( + Optional>* mem, + const dynamic::const_item_iterator& it) { + mem->emplace(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)); + static inline void derefToCache( + Optional* mem, + const dynamic::const_iterator& it) { + mem->emplace(convertTo(*it)); } }; template -class Transformer : public boost::iterator_adaptor< - Transformer, - It, - typename T::value_type - > { +class Transformer + : public boost:: + iterator_adaptor, It, typename T::value_type> { friend class boost::iterator_core_access; typedef typename T::value_type ttype; - mutable ttype cache_; - mutable bool valid_; + mutable Optional cache_; void increment() { ++this->base_reference(); - valid_ = false; + cache_ = none; } ttype& dereference() const { - if (LIKELY(!valid_)) { - cache_.~ttype(); + if (!cache_) { Dereferencer::derefToCache(&cache_, this->base_reference()); - valid_ = true; } - return cache_; + return cache_.value(); } -public: - explicit Transformer(const It& it) - : Transformer::iterator_adaptor_(it), valid_(false) {} + public: + explicit Transformer(const It& it) : Transformer::iterator_adaptor_(it) {} }; // conversion factory template -inline std::move_iterator> -conversionIterator(const It& it) { +inline std::move_iterator> conversionIterator(const It& it) { return std::make_move_iterator(Transformer(it)); } @@ -204,9 +189,10 @@ struct DynamicConverter { // integrals template -struct DynamicConverter::value && - !std::is_same::value>::type> { +struct DynamicConverter< + T, + typename std::enable_if< + std::is_integral::value && !std::is_same::value>::type> { static T convert(const dynamic& d) { return folly::to(d.asInt()); } @@ -214,8 +200,9 @@ struct DynamicConverter -struct DynamicConverter::value>::type> { +struct DynamicConverter< + T, + typename std::enable_if::value>::type> { static T convert(const dynamic& d) { using type = typename std::underlying_type::type; return static_cast(DynamicConverter::convert(d)); @@ -224,7 +211,8 @@ struct DynamicConverter -struct DynamicConverter::value>::type> { static T convert(const dynamic& d) { return folly::to(d.asDouble()); @@ -243,13 +231,13 @@ struct DynamicConverter { template <> struct DynamicConverter { static std::string convert(const dynamic& d) { - return d.asString().toStdString(); + return d.asString(); } }; // std::pair template -struct DynamicConverter> { +struct DynamicConverter> { static std::pair convert(const dynamic& d) { if (d.isArray() && d.size() == 2) { return std::make_pair(convertTo(d[0]), convertTo(d[1])); @@ -262,11 +250,13 @@ struct DynamicConverter> { } }; -// containers +// non-associative containers template -struct DynamicConverter::value>::type> { + dynamicconverter_detail::is_container::value && + !dynamicconverter_detail::is_associative::value>::type> { static C convert(const dynamic& d) { if (d.isArray()) { return C(dynamicconverter_detail::conversionIterator(d.begin()), @@ -282,6 +272,31 @@ struct DynamicConverter +struct DynamicConverter< + C, + typename std::enable_if< + dynamicconverter_detail::is_container::value && + dynamicconverter_detail::is_associative::value>::type> { + static C convert(const dynamic& d) { + C ret; // avoid direct initialization due to unordered_map's constructor + // causing memory corruption if the iterator throws an exception + if (d.isArray()) { + ret.insert( + dynamicconverter_detail::conversionIterator(d.begin()), + dynamicconverter_detail::conversionIterator(d.end())); + } else if (d.isObject()) { + ret.insert( + dynamicconverter_detail::conversionIterator(d.items().begin()), + dynamicconverter_detail::conversionIterator(d.items().end())); + } else { + throw TypeError("object or array", d.type()); + } + return ret; + } +}; + /////////////////////////////////////////////////////////////////////////////// // DynamicConstructor specializations @@ -298,14 +313,26 @@ struct DynamicConstructor { } }; +// identity +template +struct DynamicConstructor< + C, + typename std::enable_if::value>::type> { + static dynamic construct(const C& x) { + return x; + } +}; + // maps -template -struct DynamicConstructor +struct DynamicConstructor< + C, typename std::enable_if< - dynamicconverter_detail::is_map::value>::type> { + !std::is_same::value && + dynamicconverter_detail::is_map::value>::type> { static dynamic construct(const C& x) { dynamic d = dynamic::object; - for (auto& pair : x) { + for (const auto& pair : x) { d.insert(toDynamic(pair.first), toDynamic(pair.second)); } return d; @@ -313,15 +340,17 @@ struct DynamicConstructor -struct DynamicConstructor +struct DynamicConstructor< + C, typename std::enable_if< - !dynamicconverter_detail::is_map::value && - !std::is_constructible::value && - dynamicconverter_detail::is_range::value>::type> { + !std::is_same::value && + !dynamicconverter_detail::is_map::value && + !std::is_constructible::value && + dynamicconverter_detail::is_range::value>::type> { static dynamic construct(const C& x) { dynamic d = dynamic::array; - for (auto& item : x) { + for (const auto& item : x) { d.push_back(toDynamic(item)); } return d; @@ -329,7 +358,7 @@ struct DynamicConstructor +template struct DynamicConstructor, void> { static dynamic construct(const std::pair& x) { dynamic d = dynamic::array; @@ -347,7 +376,7 @@ T convertTo(const dynamic& d) { return DynamicConverter::type>::convert(d); } -template +template dynamic toDynamic(const T& x) { return DynamicConstructor::type>::construct(x); }