6 #ifndef JBSON_TRAITS_HPP
7 #define JBSON_TRAITS_HPP
11 #include "./config.hpp"
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
31 #include "../element_fwd.hpp"
33 JBSON_PUSH_DISABLE_DEPRECATED_WARNING
38 namespace mpl = boost::mpl;
43 template <element_type EType>
using element_type_c = std::integral_constant<element_type, EType>;
55 #ifndef DOXYGEN_SHOULD_SKIP_THIS
57 template <
typename Iterator>
struct is_iterator_pointer<Iterator*,
bool> : std::true_type {};
59 BOOST_MPL_HAS_XXX_TRAIT_DEF(iterator_type)
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>> {};
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> {};
71 template <
typename Iterator>
72 struct is_iterator_pointer<boost::iterator_range<Iterator>> : is_iterator_pointer<Iterator> {};
74 #endif // DOXYGEN_SHOULD_SKIP_THIS
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 > ;
102 #ifdef DOXYGEN_SHOULD_SKIP_THIS
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>,
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
136 template <element_type EType,
typename Container>
145 template <element_type EType,
typename Container>
148 #ifndef DOXYGEN_SHOULD_SKIP_THIS
149 BOOST_TTI_HAS_MEMBER_FUNCTION(push_back);
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
161 BOOST_MPL_HAS_XXX_TRAIT_DEF(iterator)
162 BOOST_MPL_HAS_XXX_TRAIT_DEF(const_iterator)
164 template <typename Container, typename Arg>
165 using container_has_push_back_arg_impl = has_member_function_push_back<Container,
void, mpl::vector<Arg>>;
167 template <typename Container> struct container_has_push_back_impl {
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&>>;
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;
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
194 template <
typename RangeT,
typename ElementTrait,
typename RangeTrait>
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;
204 template <
typename RangeT,
typename ElementTrait>
211 template <
typename RangeT,
typename ElementT>
218 template <
typename RangeT,
typename ElementTrait>
224 template <
template <
typename...>
class Fun,
typename...>
struct quote {
226 template <
typename... Args>
using apply =
typename Fun<Args...>::type;
229 template <
typename MapT,
typename T>
231 typename mpl::find_if<MapT, mpl::bind<quote<std::is_same>, T, mpl::bind<mpl::quote1<mpl::second>, mpl::_1>>>::type;
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;
237 template <
typename A,
typename B,
typename Enable =
void>
struct is_convertible : std::is_convertible<A, B> {};
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 {};
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 {};
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))> {
255 template <typename A, typename B, typename Enable = void> struct is_constructible : std::is_constructible<A, B> {};
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> {};
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;
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;
272 template <typename T> constexpr bool is_nothrow_swappable_impl() {
274 return noexcept(swap(std::declval<std::decay_t<T>&>(), std::declval<std::decay_t<T>&>()));
282 template <typename T> struct is_nothrow_swappable : std::integral_constant<bool, is_nothrow_swappable_impl<T>()> {};
Compile-time map. Maps element_types to C++ type for serialisation/deserialisation.
boost::mpl::map<...> map_type
boost::mpl map.
typename Fun< Args...>::type apply
apply enclosed metafunction
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.
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.
Variadic version of boost::mpl::quoteN.
Type trait to determine whether a type is a boost::iterator_range.
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.
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.
std::integral_constant< element_type, EType > element_type_c
Turns an element_type into a boost::mpl constant.
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.
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...
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.
Trait to determine if an iterator is a pointer, or pointer in disguise.