proxygen
DynamicConverter.h
Go to the documentation of this file.
1 /*
2  * Copyright 2012-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 // @author Nicholas Ormrod <njormrod@fb.com>
18 
19 #pragma once
20 
21 #include <iterator>
22 #include <type_traits>
23 
24 #include <boost/iterator/iterator_adaptor.hpp>
25 #include <boost/mpl/has_xxx.hpp>
26 
27 #include <folly/Likely.h>
28 #include <folly/Optional.h>
29 #include <folly/Traits.h>
30 #include <folly/dynamic.h>
31 
32 namespace folly {
33 template <typename T>
34 T convertTo(const dynamic&);
35 template <typename T>
36 dynamic toDynamic(const T&);
37 } // namespace folly
38 
52 namespace folly {
53 
55 // traits
56 
57 namespace dynamicconverter_detail {
58 
59 BOOST_MPL_HAS_XXX_TRAIT_DEF(value_type)
60 BOOST_MPL_HAS_XXX_TRAIT_DEF(iterator)
61 BOOST_MPL_HAS_XXX_TRAIT_DEF(mapped_type)
62 BOOST_MPL_HAS_XXX_TRAIT_DEF(key_type)
63 
64 template <typename T>
66  typedef std::reverse_iterator<typename T::iterator> some_iterator;
67  enum {
70  };
71 };
72 
73 template <typename T>
74 using class_is_container =
76 
77 template <typename T>
79 
80 template <typename T>
82 
83 template <typename T>
84 using is_map = StrictConjunction<is_range<T>, has_mapped_type<T>>;
85 
86 template <typename T>
88 
89 } // namespace dynamicconverter_detail
90 
92 // custom iterators
93 
106 namespace dynamicconverter_detail {
107 
108 template <typename T>
109 struct Dereferencer {
110  static inline void derefToCache(
111  Optional<T>* /* mem */,
112  const dynamic::const_item_iterator& /* it */) {
113  throw TypeError("array", dynamic::Type::OBJECT);
114  }
115 
116  static inline void derefToCache(
117  Optional<T>* mem,
118  const dynamic::const_iterator& it) {
119  mem->emplace(convertTo<T>(*it));
120  }
121 };
122 
123 template <typename F, typename S>
124 struct Dereferencer<std::pair<F, S>> {
125  static inline void derefToCache(
126  Optional<std::pair<F, S>>* mem,
127  const dynamic::const_item_iterator& it) {
128  mem->emplace(convertTo<F>(it->first), convertTo<S>(it->second));
129  }
130 
131  // Intentional duplication of the code in Dereferencer
132  template <typename T>
133  static inline void derefToCache(
134  Optional<T>* mem,
135  const dynamic::const_iterator& it) {
136  mem->emplace(convertTo<T>(*it));
137  }
138 };
139 
140 template <typename T, typename It>
142  : public boost::
143  iterator_adaptor<Transformer<T, It>, It, typename T::value_type> {
144  friend class boost::iterator_core_access;
145 
146  typedef typename T::value_type ttype;
147 
149 
150  void increment() {
151  ++this->base_reference();
152  cache_ = none;
153  }
154 
155  ttype& dereference() const {
156  if (!cache_) {
157  Dereferencer<ttype>::derefToCache(&cache_, this->base_reference());
158  }
159  return cache_.value();
160  }
161 
162  public:
163  explicit Transformer(const It& it) : Transformer::iterator_adaptor_(it) {}
164 };
165 
166 // conversion factory
167 template <typename T, typename It>
168 inline std::move_iterator<Transformer<T, It>> conversionIterator(const It& it) {
169  return std::make_move_iterator(Transformer<T, It>(it));
170 }
171 
172 } // namespace dynamicconverter_detail
173 
175 // DynamicConverter specializations
176 
182 // default - intentionally unimplemented
183 template <typename T, typename Enable = void>
185 
186 // boolean
187 template <>
188 struct DynamicConverter<bool> {
189  static bool convert(const dynamic& d) {
190  return d.asBool();
191  }
192 };
193 
194 // integrals
195 template <typename T>
197  T,
198  typename std::enable_if<
199  std::is_integral<T>::value && !std::is_same<T, bool>::value>::type> {
200  static T convert(const dynamic& d) {
201  return folly::to<T>(d.asInt());
202  }
203 };
204 
205 // enums
206 template <typename T>
208  T,
209  typename std::enable_if<std::is_enum<T>::value>::type> {
210  static T convert(const dynamic& d) {
211  using type = typename std::underlying_type<T>::type;
212  return static_cast<T>(DynamicConverter<type>::convert(d));
213  }
214 };
215 
216 // floating point
217 template <typename T>
219  T,
220  typename std::enable_if<std::is_floating_point<T>::value>::type> {
221  static T convert(const dynamic& d) {
222  return folly::to<T>(d.asDouble());
223  }
224 };
225 
226 // fbstring
227 template <>
229  static folly::fbstring convert(const dynamic& d) {
230  return d.asString();
231  }
232 };
233 
234 // std::string
235 template <>
237  static std::string convert(const dynamic& d) {
238  return d.asString();
239  }
240 };
241 
242 // std::pair
243 template <typename F, typename S>
244 struct DynamicConverter<std::pair<F, S>> {
245  static std::pair<F, S> convert(const dynamic& d) {
246  if (d.isArray() && d.size() == 2) {
247  return std::make_pair(convertTo<F>(d[0]), convertTo<S>(d[1]));
248  } else if (d.isObject() && d.size() == 1) {
249  auto it = d.items().begin();
250  return std::make_pair(convertTo<F>(it->first), convertTo<S>(it->second));
251  } else {
252  throw TypeError("array (size 2) or object (size 1)", d.type());
253  }
254  }
255 };
256 
257 // non-associative containers
258 template <typename C>
260  C,
261  typename std::enable_if<
262  dynamicconverter_detail::is_container<C>::value &&
263  !dynamicconverter_detail::is_associative<C>::value>::type> {
264  static C convert(const dynamic& d) {
265  if (d.isArray()) {
266  return C(
267  dynamicconverter_detail::conversionIterator<C>(d.begin()),
268  dynamicconverter_detail::conversionIterator<C>(d.end()));
269  } else if (d.isObject()) {
270  return C(
271  dynamicconverter_detail::conversionIterator<C>(d.items().begin()),
272  dynamicconverter_detail::conversionIterator<C>(d.items().end()));
273  } else {
274  throw TypeError("object or array", d.type());
275  }
276  }
277 };
278 
279 // associative containers
280 template <typename C>
282  C,
283  typename std::enable_if<
284  dynamicconverter_detail::is_container<C>::value &&
285  dynamicconverter_detail::is_associative<C>::value>::type> {
286  static C convert(const dynamic& d) {
287  C ret; // avoid direct initialization due to unordered_map's constructor
288  // causing memory corruption if the iterator throws an exception
289  if (d.isArray()) {
290  ret.insert(
291  dynamicconverter_detail::conversionIterator<C>(d.begin()),
292  dynamicconverter_detail::conversionIterator<C>(d.end()));
293  } else if (d.isObject()) {
294  ret.insert(
295  dynamicconverter_detail::conversionIterator<C>(d.items().begin()),
296  dynamicconverter_detail::conversionIterator<C>(d.items().end()));
297  } else {
298  throw TypeError("object or array", d.type());
299  }
300  return ret;
301  }
302 };
303 
305 // DynamicConstructor specializations
306 
312 // default
313 template <typename C, typename Enable = void>
315  static dynamic construct(const C& x) {
316  return dynamic(x);
317  }
318 };
319 
320 // identity
321 template <typename C>
323  C,
324  typename std::enable_if<std::is_same<C, dynamic>::value>::type> {
325  static dynamic construct(const C& x) {
326  return x;
327  }
328 };
329 
330 // maps
331 template <typename C>
333  C,
334  typename std::enable_if<
335  !std::is_same<C, dynamic>::value &&
336  dynamicconverter_detail::is_map<C>::value>::type> {
337  static dynamic construct(const C& x) {
339  for (const auto& pair : x) {
340  d.insert(toDynamic(pair.first), toDynamic(pair.second));
341  }
342  return d;
343  }
344 };
345 
346 // other ranges
347 template <typename C>
349  C,
350  typename std::enable_if<
351  !std::is_same<C, dynamic>::value &&
352  !dynamicconverter_detail::is_map<C>::value &&
353  !std::is_constructible<StringPiece, const C&>::value &&
354  dynamicconverter_detail::is_range<C>::value>::type> {
355  static dynamic construct(const C& x) {
357  for (const auto& item : x) {
358  d.push_back(toDynamic(item));
359  }
360  return d;
361  }
362 };
363 
364 // pair
365 template <typename A, typename B>
366 struct DynamicConstructor<std::pair<A, B>, void> {
367  static dynamic construct(const std::pair<A, B>& x) {
369  d.push_back(toDynamic(x.first));
370  d.push_back(toDynamic(x.second));
371  return d;
372  }
373 };
374 
375 // vector<bool>
376 template <>
377 struct DynamicConstructor<std::vector<bool>, void> {
378  static dynamic construct(const std::vector<bool>& x) {
380  // Intentionally specifying the type as bool here.
381  // std::vector<bool>'s iterators return a proxy which is a prvalue
382  // and hence cannot bind to an lvalue reference such as auto&
383  for (bool item : x) {
384  d.push_back(toDynamic(item));
385  }
386  return d;
387  }
388 };
389 
391 // implementation
392 
393 template <typename T>
394 T convertTo(const dynamic& d) {
396 }
397 
398 template <typename T>
399 dynamic toDynamic(const T& x) {
401 }
402 
403 } // namespace folly
Definition: InvokeTest.cpp:58
static ObjectMaker object()
Definition: dynamic-inl.h:240
std::move_iterator< Transformer< T, It > > conversionIterator(const It &it)
static void derefToCache(Optional< std::pair< F, S >> *mem, const dynamic::const_item_iterator &it)
static std::pair< F, S > convert(const dynamic &d)
static dynamic construct(const C &x)
T convertTo(const dynamic &)
PskType type
const int x
double asDouble() const
Definition: dynamic-inl.h:521
STL namespace.
static bool convert(const dynamic &d)
static void derefToCache(Optional< T > *mem, const dynamic::const_iterator &it)
folly::std T
bool asBool() const
Definition: dynamic-inl.h:527
static std::string convert(const dynamic &d)
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
static void derefToCache(Optional< T > *, const dynamic::const_item_iterator &)
bool isArray() const
Definition: dynamic-inl.h:498
static dynamic construct(const std::pair< A, B > &x)
std::string asString() const
Definition: dynamic-inl.h:518
static folly::fbstring convert(const dynamic &d)
void insert(K &&, V &&val)
Definition: dynamic-inl.h:853
int64_t asInt() const
Definition: dynamic-inl.h:524
Definition: Traits.h:588
void push_back(dynamic const &)
Definition: dynamic-inl.h:969
#define C(name, bit)
Definition: CpuId.h:204
static const char *const value
Definition: Conv.cpp:50
static void derefToCache(Optional< T > *mem, const dynamic::const_iterator &it)
Value & emplace(Args &&...args)
Definition: Optional.h:231
std::reverse_iterator< typename T::iterator > some_iterator
IterableProxy< const_item_iterator > items() const
Definition: dynamic-inl.h:476
const char * string
Definition: Conv.cpp:212
std::size_t size() const
Definition: dynamic.cpp:275
static void array(EmptyArrayTag)
Definition: dynamic-inl.h:233
Definition: Traits.h:577
FOLLY_CPP14_CONSTEXPR const Value & value() const &
Definition: Optional.h:268
Type type() const
Definition: dynamic-inl.h:514
const_iterator begin() const
Definition: dynamic-inl.h:432
Array::const_iterator const_iterator
Definition: dynamic.h:119
bool isObject() const
Definition: dynamic-inl.h:492
static dynamic construct(const std::vector< bool > &x)
dynamic toDynamic(const T &)
constexpr None none
Definition: Optional.h:87
const_iterator end() const
Definition: dynamic-inl.h:435