View on GitHub
jbson
C++11/1y BSON library
traits.hpp
1 // Copyright Christian Manning 2013.
2 // Distributed under the Boost Software License, Version 1.0.
3 // (See accompanying file LICENSE_1_0.txt or copy at
4 // http://www.boost.org/LICENSE_1_0.txt)
5 
6 #ifndef JBSON_TRAITS_HPP
7 #define JBSON_TRAITS_HPP
8 
9 #include <type_traits>
10 
11 #include "./config.hpp"
12 
13 JBSON_PUSH_DISABLE_DOCUMENTATION_WARNING
14 #include <boost/range/iterator_range.hpp>
15 #include <boost/mpl/not.hpp>
16 #include <boost/mpl/and.hpp>
17 #include <boost/utility/string_ref_fwd.hpp>
18 #include <boost/tti/has_member_function.hpp>
19 #include <boost/range/metafunctions.hpp>
20 #include <boost/mpl/same_as.hpp>
21 #include <boost/mpl/apply.hpp>
22 #include <boost/mpl/and.hpp>
23 #include <boost/mpl/has_xxx.hpp>
24 #include <boost/mpl/quote.hpp>
25 #include <boost/mpl/map.hpp>
26 #include <boost/mpl/at.hpp>
27 #include <boost/mpl/find_if.hpp>
28 #include <boost/mpl/same_as.hpp>
29 JBSON_CLANG_POP_WARNINGS
30 
31 #include "../element_fwd.hpp"
32 
33 JBSON_PUSH_DISABLE_DEPRECATED_WARNING
34 
35 namespace jbson {
36 namespace detail {
37 
38 namespace mpl = boost::mpl;
39 
43 template <element_type EType> using element_type_c = std::integral_constant<element_type, EType>;
44 
53 template <typename Iterator, typename Enable = void> struct is_iterator_pointer : std::false_type {};
54 
55 #ifndef DOXYGEN_SHOULD_SKIP_THIS
56 
57 template <typename Iterator> struct is_iterator_pointer<Iterator*, bool> : std::true_type {};
58 
59 BOOST_MPL_HAS_XXX_TRAIT_DEF(iterator_type)
60 
61 // libc++, libstdc++
62 template <typename Iterator>
63 struct is_iterator_pointer<Iterator, std::enable_if_t<has_iterator_type<Iterator>::value>>
64  : mpl::or_<std::is_pointer<typename Iterator::iterator_type>,
65  std::is_constructible<Iterator, typename std::iterator_traits<Iterator>::pointer>> {};
66 
67 template <typename Iterator>
68 struct is_iterator_pointer<Iterator, std::enable_if_t<!has_iterator_type<Iterator>::value>>
69  : std::is_constructible<Iterator, typename std::iterator_traits<Iterator>::pointer> {};
70 
71 template <typename Iterator>
72 struct is_iterator_pointer<boost::iterator_range<Iterator>> : is_iterator_pointer<Iterator> {};
73 
74 #endif // DOXYGEN_SHOULD_SKIP_THIS
75 
92 template <typename Container, bool set = false> class TypeMap {
93  using container_type =
94  std::conditional_t<set, Container, boost::iterator_range<typename Container::const_iterator>>;
95  using string_type = std::conditional_t < !set && is_iterator_pointer<typename container_type::iterator>::value,
96  boost::string_ref, std::string > ;
97 
98  public:
102 #ifdef DOXYGEN_SHOULD_SKIP_THIS
103  typedef boost::mpl::map<...> map_type;
104 #else // DOXYGEN_SHOULD_SKIP_THIS
105  typedef typename mpl::map<
106  mpl::pair<element_type_c<element_type::string_element>, string_type>,
107  mpl::pair<element_type_c<element_type::boolean_element>, bool>,
108  mpl::pair<element_type_c<element_type::int32_element>, int32_t>,
109  mpl::pair<element_type_c<element_type::int64_element>, int64_t>,
110  mpl::pair<element_type_c<element_type::double_element>, double>,
111  mpl::pair<element_type_c<element_type::document_element>, basic_document<container_type, container_type>>,
112  mpl::pair<element_type_c<element_type::array_element>, basic_array<container_type, container_type>>,
113  mpl::pair<element_type_c<element_type::binary_element>, container_type>,
114  mpl::pair<element_type_c<element_type::undefined_element>, void>,
115  mpl::pair<element_type_c<element_type::oid_element>, std::array<char, 12>>,
116  mpl::pair<element_type_c<element_type::date_element>, int64_t>,
117  mpl::pair<element_type_c<element_type::null_element>, void>,
118  mpl::pair<element_type_c<element_type::regex_element>, std::tuple<string_type, string_type>>,
119  mpl::pair<element_type_c<element_type::db_pointer_element>, std::tuple<string_type, std::array<char, 12>>>,
120  mpl::pair<element_type_c<element_type::javascript_element>, string_type>,
121  mpl::pair<element_type_c<element_type::symbol_element>, string_type>,
122  mpl::pair<element_type_c<element_type::scoped_javascript_element>,
123  std::tuple<string_type, basic_document<container_type, container_type>>>,
124  mpl::pair<element_type_c<element_type::timestamp_element>, int64_t>,
125  mpl::pair<element_type_c<element_type::min_key>, void>,
126  mpl::pair<element_type_c<element_type::max_key>, void>>::type map_type;
127 #endif // DOXYGEN_SHOULD_SKIP_THIS
128 };
129 
136 template <element_type EType, typename Container>
137 using ElementTypeMap = typename mpl::at<typename TypeMap<Container>::map_type, element_type_c<EType>>::type;
138 
145 template <element_type EType, typename Container>
146 using ElementTypeMapSet = typename mpl::at<typename TypeMap<Container, true>::map_type, element_type_c<EType>>::type;
147 
148 #ifndef DOXYGEN_SHOULD_SKIP_THIS
149 BOOST_TTI_HAS_MEMBER_FUNCTION(push_back);
150 #endif
151 
155 template <typename T> struct is_iterator_range : std::false_type {};
156 
157 #ifndef DOXYGEN_SHOULD_SKIP_THIS
158 template <typename IteratorT> struct is_iterator_range<boost::iterator_range<IteratorT>> : std::true_type {};
159 #endif // DOXYGEN_SHOULD_SKIP_THIS
160 
161 BOOST_MPL_HAS_XXX_TRAIT_DEF(iterator)
162 BOOST_MPL_HAS_XXX_TRAIT_DEF(const_iterator)
163 
164 template <typename Container, typename Arg>
165 using container_has_push_back_arg_impl = has_member_function_push_back<Container, void, mpl::vector<Arg>>;
166 
167 template <typename Container> struct container_has_push_back_impl {
168  using type =
169  mpl::or_<container_has_push_back_arg_impl<Container, typename boost::range_value<Container>::type>,
170  container_has_push_back_arg_impl<Container, const typename boost::range_value<Container>::type&>>;
171 };
172 
180 template <typename Container>
182  typename mpl::eval_if<has_iterator<std::decay_t<Container>>, container_has_push_back_impl<std::decay_t<Container>>,
183  std::false_type>::type;
184 
185 #ifndef DOXYGEN_SHOULD_SKIP_THIS
186 template <typename RangeT>
187 using is_range = typename mpl::and_<has_iterator<std::decay_t<RangeT>>, has_const_iterator<std::decay_t<RangeT>>>::type;
188 #endif // DOXYGEN_SHOULD_SKIP_THIS
189 
194 template <typename RangeT, typename ElementTrait, typename RangeTrait>
195 using is_range_of = typename mpl::apply<
196  typename mpl::eval_if<is_range<RangeT>, mpl::identity<ElementTrait>, mpl::identity<mpl::always<mpl::false_>>>::type,
197  typename mpl::eval_if<is_range<RangeT>, mpl::apply<RangeTrait, std::decay_t<RangeT>>,
198  mpl::identity<void>>::type>::type;
199 
204 template <typename RangeT, typename ElementTrait>
206 
211 template <typename RangeT, typename ElementT>
213 
218 template <typename RangeT, typename ElementTrait>
220 
224 template <template <typename...> class Fun, typename...> struct quote {
226  template <typename... Args> using apply = typename Fun<Args...>::type;
227 };
228 
229 template <typename MapT, typename T>
230 using find_second =
231  typename mpl::find_if<MapT, mpl::bind<quote<std::is_same>, T, mpl::bind<mpl::quote1<mpl::second>, mpl::_1>>>::type;
232 
233 template <typename MapT, typename FunT>
234 using find_if_second =
235  typename mpl::find_if<MapT, mpl::bind<mpl::protect<FunT>, mpl::bind<mpl::quote1<mpl::second>, mpl::_1>>>::type;
236 
237 template <typename A, typename B, typename Enable = void> struct is_convertible : std::is_convertible<A, B> {};
238 
239 template <typename A, typename B>
241  A, B, std::enable_if_t<std::is_integral<std::decay_t<A>>::value&& std::is_floating_point<std::decay_t<B>>::value>>
242  : std::false_type {};
243 
244 template <typename A, typename B>
246  A, B, std::enable_if_t<std::is_integral<std::decay_t<B>>::value&& std::is_floating_point<std::decay_t<A>>::value>>
247  : std::false_type {};
248 
249 template <typename A, typename B>
251  A, B, std::enable_if_t<std::is_integral<std::decay_t<A>>::value&& std::is_integral<std::decay_t<B>>::value>>
252  : std::integral_constant<bool, (sizeof(A) < sizeof(int32_t) && sizeof(A) < sizeof(B)) || (sizeof(A) == sizeof(B))> {
253 };
254 
255 template <typename A, typename B, typename Enable = void> struct is_constructible : std::is_constructible<A, B> {};
256 
257 template <typename A, typename B>
258 struct is_constructible<
259  A, B, std::enable_if_t<std::is_arithmetic<std::decay_t<A>>::value || std::is_arithmetic<std::decay_t<B>>::value>>
260  : is_convertible<B, A> {};
261 
262 template <typename Container, typename T>
263 using is_valid_element_value_type = typename mpl::not_<std::is_same<
264  typename mpl::end<typename TypeMap<Container>::map_type>::type,
265  find_if_second<typename TypeMap<Container>::map_type, mpl::bind<quote<is_convertible>, T, mpl::_1>>>>::type;
266 
267 template <typename Container, typename T>
268 using is_valid_element_set_type = typename mpl::not_<std::is_same<
269  typename mpl::end<typename TypeMap<Container, true>::map_type>::type,
270  find_if_second<typename TypeMap<Container, true>::map_type, mpl::bind<quote<is_constructible>, mpl::_1, T>>>>::type;
271 
272 template <typename T> constexpr bool is_nothrow_swappable_impl() {
273  using std::swap;
274  return noexcept(swap(std::declval<std::decay_t<T>&>(), std::declval<std::decay_t<T>&>()));
275 }
276 
282 template <typename T> struct is_nothrow_swappable : std::integral_constant<bool, is_nothrow_swappable_impl<T>()> {};
283 
284 } // namespace detail
285 } // namespace jbson
286 
287 JBSON_POP_WARNINGS
288 
289 #endif // JBSON_TRAITS_HPP
Compile-time map. Maps element_types to C++ type for serialisation/deserialisation.
Definition: traits.hpp:92
BSON document.
Definition: document.hpp:191
boost::mpl::map<...> map_type
boost::mpl map.
Definition: traits.hpp:103
typename Fun< Args...>::type apply
apply enclosed metafunction
Definition: traits.hpp:226
is_range_of_value< RangeT, mpl::bind2< mpl::quote2< std::is_same >, ElementT, mpl::_1 >> is_range_of_same_value
Type trait to determine equivalence of the value_type of a Range.
Definition: traits.hpp:212
is_range_of< RangeT, ElementTrait, mpl::quote1< boost::range_mutable_iterator >> is_range_of_iterator
Type trait to apply a unary metafunction trait to the iterator type of a Range.
Definition: traits.hpp:219
Variadic version of boost::mpl::quoteN.
Definition: traits.hpp:224
Type trait to determine whether a type is a boost::iterator_range.
Definition: traits.hpp:155
typename mpl::eval_if< has_iterator< std::decay_t< Container >>, container_has_push_back_impl< std::decay_t< Container >>, std::false_type >::type container_has_push_back
Type trait to determine if type is a container with a push_back() function.
Definition: traits.hpp:183
typename mpl::at< typename TypeMap< Container, true >::map_type, element_type_c< EType >>::type ElementTypeMapSet
Type alias to perform boost::mpl::at on TypeMap::map_type.
Definition: traits.hpp:146
std::integral_constant< element_type, EType > element_type_c
Turns an element_type into a boost::mpl constant.
Definition: traits.hpp:43
is_range_of< RangeT, ElementTrait, mpl::quote1< boost::range_value >> is_range_of_value
Type trait to apply a unary metafunction trait to the value_type of a Range.
Definition: traits.hpp:205
typename mpl::apply< typename mpl::eval_if< is_range< RangeT >, mpl::identity< ElementTrait >, mpl::identity< mpl::always< mpl::false_ >>>::type, typename mpl::eval_if< is_range< RangeT >, mpl::apply< RangeTrait, std::decay_t< RangeT >>, mpl::identity< void >>::type >::type is_range_of
Type trait to apply a unary metafunction to the result of a Range trait in a SFINAE safe manner...
Definition: traits.hpp:198
BSON array.
Definition: document.hpp:534
typename mpl::at< typename TypeMap< Container >::map_type, element_type_c< EType >>::type ElementTypeMap
Type alias to perform boost::mpl::at on TypeMap::map_type.
Definition: traits.hpp:137
Trait to determine if an iterator is a pointer, or pointer in disguise.
Definition: traits.hpp:53