boost/beast/core/detail/type_traits.hpp
// // Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // Official repository: https://github.com/boostorg/beast // #ifndef BOOST_BEAST_DETAIL_TYPE_TRAITS_HPP #define BOOST_BEAST_DETAIL_TYPE_TRAITS_HPP #include <boost/beast/core/error.hpp> #include <boost/asio/buffer.hpp> #include <iterator> #include <tuple> #include <type_traits> #include <string> #include <utility> namespace boost { namespace beast { namespace detail { // // utilities // template<class... Ts> struct make_void { using type = void; }; template<class... Ts> using void_t = typename make_void<Ts...>::type; template<class T> inline void accept_rv(T){} template<class U> std::size_t constexpr max_sizeof() { return sizeof(U); } template<class U0, class U1, class... Us> std::size_t constexpr max_sizeof() { return max_sizeof<U0>() > max_sizeof<U1, Us...>() ? max_sizeof<U0>() : max_sizeof<U1, Us...>(); } template<class U> std::size_t constexpr max_alignof() { return alignof(U); } template<class U0, class U1, class... Us> std::size_t constexpr max_alignof() { return max_alignof<U0>() > max_alignof<U1, Us...>() ? max_alignof<U0>() : max_alignof<U1, Us...>(); } template<unsigned N, class T, class... Tn> struct repeat_tuple_impl { using type = typename repeat_tuple_impl< N - 1, T, T, Tn...>::type; }; template<class T, class... Tn> struct repeat_tuple_impl<0, T, Tn...> { using type = std::tuple<T, Tn...>; }; template<unsigned N, class T> struct repeat_tuple { using type = typename repeat_tuple_impl<N-1, T>::type; }; template<class T> struct repeat_tuple<0, T> { using type = std::tuple<>; }; template<class R, class C, class ...A> auto is_invocable_test(C&& c, int, A&& ...a) -> decltype(std::is_convertible< decltype(c(std::forward<A>(a)...)), R>::value || std::is_same<R, void>::value, std::true_type()); template<class R, class C, class ...A> std::false_type is_invocable_test(C&& c, long, A&& ...a); /** Metafunction returns `true` if F callable as R(A...) Example: @code is_invocable<T, void(std::string)> @endcode */ /** @{ */ template<class C, class F> struct is_invocable : std::false_type { }; template<class C, class R, class ...A> struct is_invocable<C, R(A...)> : decltype(is_invocable_test<R>( std::declval<C>(), 1, std::declval<A>()...)) { }; /** @} */ // for span template<class T, class E, class = void> struct is_contiguous_container: std::false_type {}; template<class T, class E> struct is_contiguous_container<T, E, void_t< decltype( std::declval<std::size_t&>() = std::declval<T const&>().size(), std::declval<E*&>() = std::declval<T&>().data(), (void)0), typename std::enable_if< std::is_same< typename std::remove_cv<E>::type, typename std::remove_cv< typename std::remove_pointer< decltype(std::declval<T&>().data()) >::type >::type >::value >::type>>: std::true_type {}; template<class...> struct unwidest_unsigned; template<class U0> struct unwidest_unsigned<U0> { using type = U0; }; template<class U0, class... UN> struct unwidest_unsigned<U0, UN...> { BOOST_STATIC_ASSERT(std::is_unsigned<U0>::value); using type = typename std::conditional< (sizeof(U0) < sizeof(typename unwidest_unsigned<UN...>::type)), U0, typename unwidest_unsigned<UN...>::type>::type; }; template<class...> struct widest_unsigned; template<class U0> struct widest_unsigned<U0> { using type = U0; }; template<class U0, class... UN> struct widest_unsigned<U0, UN...> { BOOST_STATIC_ASSERT(std::is_unsigned<U0>::value); using type = typename std::conditional< (sizeof(U0) > sizeof(typename widest_unsigned<UN...>::type)), U0, typename widest_unsigned<UN...>::type>::type; }; template<class U> inline constexpr U min_all(U u) { BOOST_STATIC_ASSERT(std::is_unsigned<U>::value); return u; } template<class U0, class U1, class... UN> inline constexpr typename unwidest_unsigned<U0, U1, UN...>::type min_all(U0 u0, U1 u1, UN... un) { using type = typename unwidest_unsigned<U0, U1, UN...>::type; return u0 < u1 ? static_cast<type>(min_all(u0, un...)) : static_cast<type>(min_all(u1, un...)); } template<class U> inline constexpr U max_all(U u) { BOOST_STATIC_ASSERT(std::is_unsigned<U>::value); return u; } template<class U0, class U1, class... UN> inline constexpr typename widest_unsigned<U0, U1, UN...>::type max_all(U0 u0, U1 u1, UN... un) { return u0 > u1? max_all(u0, un...) : max_all(u1, un...); } //------------------------------------------------------------------------------ // // buffer concepts // // Types that meet the requirements, // for use with std::declval only. template<class BufferType> struct BufferSequence { using value_type = BufferType; using const_iterator = BufferType const*; ~BufferSequence(); BufferSequence(BufferSequence const&) = default; const_iterator begin() const noexcept; const_iterator end() const noexcept; }; using ConstBufferSequence = BufferSequence<boost::asio::const_buffer>; using MutableBufferSequence = BufferSequence<boost::asio::mutable_buffer>; template<class B1, class... Bn> struct is_all_const_buffer_sequence : std::integral_constant<bool, boost::asio::is_const_buffer_sequence<B1>::value && is_all_const_buffer_sequence<Bn...>::value> { }; template<class B> struct is_all_const_buffer_sequence<B> : boost::asio::is_const_buffer_sequence<B> { }; template<class... Bn> struct common_buffers_type { using type = typename std::conditional< std::is_convertible<std::tuple<Bn...>, typename repeat_tuple<sizeof...(Bn), boost::asio::mutable_buffer>::type>::value, boost::asio::mutable_buffer, boost::asio::const_buffer>::type; }; template<class B> struct buffer_sequence_iterator { using type = decltype( boost::asio::buffer_sequence_begin( std::declval<B const&>())); }; // Types that meet the requirements, // for use with std::declval only. struct StreamHandler { StreamHandler(StreamHandler const&) = default; void operator()(error_code ec, std::size_t); }; using ReadHandler = StreamHandler; using WriteHandler = StreamHandler; template<class Buffers> class buffers_range_adapter { Buffers const& b_; public: using value_type = typename std::conditional< std::is_convertible<typename std::iterator_traits< typename buffer_sequence_iterator<Buffers>::type>::value_type, boost::asio::const_buffer>::value, boost::asio::const_buffer, boost::asio::mutable_buffer>::type; /* VFALCO This isn't right, because range-for will pick up the iterator's value_type which might not be const_buffer or mutable_buffer. We need to declare our own iterator wrapper that converts the underlying iterator's value_type to const_buffer or mutable_buffer so that range-for sees one of those types. */ using const_iterator = typename buffer_sequence_iterator<Buffers>::type; explicit buffers_range_adapter(Buffers const& b) : b_(b) { } const_iterator begin() const noexcept { return boost::asio::buffer_sequence_begin(b_); } const_iterator end() const noexcept { return boost::asio::buffer_sequence_end(b_); } }; template<class Buffers> buffers_range_adapter<Buffers> buffers_range(Buffers const& buffers) { return buffers_range_adapter<Buffers>{buffers}; } } // detail } // beast } // boost #endif