diff options
Diffstat (limited to 'boost/beast/core/detail/type_traits.hpp')
-rw-r--r-- | boost/beast/core/detail/type_traits.hpp | 353 |
1 files changed, 353 insertions, 0 deletions
diff --git a/boost/beast/core/detail/type_traits.hpp b/boost/beast/core/detail/type_traits.hpp new file mode 100644 index 0000000000..06fbda291d --- /dev/null +++ b/boost/beast/core/detail/type_traits.hpp @@ -0,0 +1,353 @@ +// +// 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 |