X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FDynamicConverter.h;h=e63bf842666c58ad6d19db25b262cfd736e13a6a;hb=b3aabafd2d5306d85105bcdb55b2c2422628ecaa;hp=2f0a1205888e9b15e1b1e98f61cca9abfb636add;hpb=981ed98473314f0e3df5e0c4d47c8574d9523289;p=folly.git diff --git a/folly/DynamicConverter.h b/folly/DynamicConverter.h index 2f0a1205..e63bf842 100644 --- a/folly/DynamicConverter.h +++ b/folly/DynamicConverter.h @@ -1,5 +1,5 @@ /* - * Copyright 2012 Facebook, Inc. + * Copyright 2017 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,12 +16,22 @@ // @author Nicholas Ormrod -#ifndef DYNAMIC_CONVERTER_H -#define DYNAMIC_CONVERTER_H +#pragma once + +#include +#include + +#include +#include + +#include +#include +#include +#include -#include "folly/dynamic.h" namespace folly { template T convertTo(const dynamic&); + template dynamic toDynamic(const T&); } /** @@ -29,18 +39,14 @@ namespace folly { * * Example: * - * dynamic d = { { 1, 2, 3 }, { 4, 5 } }; // a vector of vector of int + * dynamic d = dynamic::array( + * dynamic::array(1, 2, 3), + * dynamic::array(4, 5)); // a vector of vector of int * auto vvi = convertTo>>(d); * * See docs/DynamicConverter.md for supported types and customization */ - -#include -#include -#include -#include "folly/Likely.h" - namespace folly { /////////////////////////////////////////////////////////////////////////////// @@ -49,42 +55,31 @@ 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); +BOOST_MPL_HAS_XXX_TRAIT_DEF(mapped_type); +BOOST_MPL_HAS_XXX_TRAIT_DEF(key_type); -template struct map_container_has_correct_types - : std::is_same::type, - typename T::mapped_type>, - typename T::value_type> {}; - -template struct class_is_container { - struct dummy {}; +template struct iterator_class_is_container { + typedef std::reverse_iterator some_iterator; enum { value = has_value_type::value && - has_iterator::value && - std::is_constructible::value }; + 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, - class_is_container, - std::false_type - >::type {}; - -template struct is_map_container - : std::conditional< - is_container::value, - container_is_map, - std::false_type - >::type {}; +template +using class_is_container = + Conjunction, iterator_class_is_container>; + +template +using is_range = StrictConjunction, has_iterator>; + +template +using is_container = StrictConjunction, class_is_container>; + +template +using is_map = StrictConjunction, has_mapped_type>; + +template +using is_associative = StrictConjunction, has_key_type>; } // namespace dynamicconverter_detail @@ -105,53 +100,67 @@ template struct is_map_container namespace dynamicconverter_detail { +template +struct Dereferencer { + static inline void derefToCache( + Optional* /* mem */, + const dynamic::const_item_iterator& /* it */) { + throw TypeError("array", dynamic::Type::OBJECT); + } + + static inline void derefToCache( + Optional* mem, + const dynamic::const_iterator& it) { + mem->emplace(convertTo(*it)); + } +}; + template -inline void -derefToCache(std::pair* mem, const dynamic::const_item_iterator& it) { - new (mem) std::pair(convertTo(it->first), convertTo(it->second)); -} +struct Dereferencer> { + static inline void derefToCache( + Optional>* mem, + const dynamic::const_item_iterator& it) { + mem->emplace(convertTo(it->first), convertTo(it->second)); + } -template -inline void derefToCache(T* mem, const dynamic::const_iterator& it) { - new (mem) T(convertTo(*it)); -} + // Intentional duplication of the code in Dereferencer + template + 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(); - derefToCache(&cache_, this->base_reference()); - valid_ = true; + if (!cache_) { + Dereferencer::derefToCache(&cache_, this->base_reference()); } - 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 -static inline std::move_iterator> -conversionIterator(const It& it) { +inline std::move_iterator> conversionIterator(const It& it) { return std::make_move_iterator(Transformer(it)); } @@ -160,13 +169,14 @@ conversionIterator(const It& it) { /////////////////////////////////////////////////////////////////////////////// // DynamicConverter specializations -template struct DynamicConverter; - /** * Each specialization of DynamicConverter has the function - * 'static T convert(const dynamic& d);' + * 'static T convert(const dynamic&);' */ +// default - intentionally unimplemented +template struct DynamicConverter; + // boolean template <> struct DynamicConverter { @@ -177,20 +187,33 @@ 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()); + } +}; + +// enums +template +struct DynamicConverter< + T, + typename std::enable_if::value>::type> { static T convert(const dynamic& d) { - return static_cast(d.asInt()); + using type = typename std::underlying_type::type; + return static_cast(DynamicConverter::convert(d)); } }; // floating point template -struct DynamicConverter::value>::type> { static T convert(const dynamic& d) { - return static_cast(d.asDouble()); + return folly::to(d.asDouble()); } }; @@ -206,13 +229,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])); @@ -225,53 +248,135 @@ struct DynamicConverter> { } }; -// map 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 (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 +// associative containers template -struct DynamicConverter::value && - !dynamicconverter_detail::is_map_container::value - >::type - > { +struct DynamicConverter< + C, + typename std::enable_if< + dynamicconverter_detail::is_container::value && + dynamicconverter_detail::is_associative::value>::type> { static C convert(const dynamic& d) { - if (LIKELY(d.isArray())) { - return C(dynamicconverter_detail::conversionIterator(d.begin()), - dynamicconverter_detail::conversionIterator(d.end())); + 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("array", d.type()); + throw TypeError("object or array", d.type()); + } + return ret; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// DynamicConstructor specializations + +/** + * Each specialization of DynamicConstructor has the function + * 'static dynamic construct(const C&);' + */ + +// default +template +struct DynamicConstructor { + static dynamic construct(const C& x) { + return dynamic(x); + } +}; + +// identity +template +struct DynamicConstructor< + C, + typename std::enable_if::value>::type> { + static dynamic construct(const C& x) { + return x; + } +}; + +// maps +template +struct DynamicConstructor< + C, + typename std::enable_if< + !std::is_same::value && + dynamicconverter_detail::is_map::value>::type> { + static dynamic construct(const C& x) { + dynamic d = dynamic::object; + for (const auto& pair : x) { + d.insert(toDynamic(pair.first), toDynamic(pair.second)); + } + return d; + } +}; + +// other ranges +template +struct DynamicConstructor< + C, + typename std::enable_if< + !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 (const auto& item : x) { + d.push_back(toDynamic(item)); } + return d; + } +}; + +// pair +template +struct DynamicConstructor, void> { + static dynamic construct(const std::pair& x) { + dynamic d = dynamic::array; + d.push_back(toDynamic(x.first)); + d.push_back(toDynamic(x.second)); + return d; } }; /////////////////////////////////////////////////////////////////////////////// -// convertTo implementation +// implementation template T convertTo(const dynamic& d) { return DynamicConverter::type>::convert(d); } -} // namespace folly - -#endif // DYNAMIC_CONVERTER_H +template +dynamic toDynamic(const T& x) { + return DynamicConstructor::type>::construct(x); +} +} // namespace folly