2 // Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 // Official repository: https://github.com/boostorg/beast
10 #ifndef BOOST_BEAST_DETAIL_TYPE_TRAITS_HPP
11 #define BOOST_BEAST_DETAIL_TYPE_TRAITS_HPP
13 #include <boost/beast/core/error.hpp>
14 #include <boost/asio/buffer.hpp>
17 #include <type_traits>
36 using void_t = typename make_void<Ts...>::type;
50 template<class U0, class U1, class... Us>
55 max_sizeof<U0>() > max_sizeof<U1, Us...>() ?
56 max_sizeof<U0>() : max_sizeof<U1, Us...>();
66 template<class U0, class U1, class... Us>
71 max_alignof<U0>() > max_alignof<U1, Us...>() ?
72 max_alignof<U0>() : max_alignof<U1, Us...>();
75 template<unsigned N, class T, class... Tn>
76 struct repeat_tuple_impl
78 using type = typename repeat_tuple_impl<
79 N - 1, T, T, Tn...>::type;
82 template<class T, class... Tn>
83 struct repeat_tuple_impl<0, T, Tn...>
85 using type = std::tuple<T, Tn...>;
88 template<unsigned N, class T>
92 typename repeat_tuple_impl<N-1, T>::type;
96 struct repeat_tuple<0, T>
98 using type = std::tuple<>;
101 template<class R, class C, class ...A>
103 is_invocable_test(C&& c, int, A&& ...a)
104 -> decltype(std::is_convertible<
105 decltype(c(std::forward<A>(a)...)), R>::value ||
106 std::is_same<R, void>::value,
109 template<class R, class C, class ...A>
111 is_invocable_test(C&& c, long, A&& ...a);
113 /** Metafunction returns `true` if F callable as R(A...)
118 is_invocable<T, void(std::string)>
122 template<class C, class F>
123 struct is_invocable : std::false_type
127 template<class C, class R, class ...A>
128 struct is_invocable<C, R(A...)>
129 : decltype(is_invocable_test<R>(
130 std::declval<C>(), 1, std::declval<A>()...))
136 template<class T, class E, class = void>
137 struct is_contiguous_container: std::false_type {};
139 template<class T, class E>
140 struct is_contiguous_container<T, E, void_t<
142 std::declval<std::size_t&>() = std::declval<T const&>().size(),
143 std::declval<E*&>() = std::declval<T&>().data(),
145 typename std::enable_if<
147 typename std::remove_cv<E>::type,
148 typename std::remove_cv<
149 typename std::remove_pointer<
150 decltype(std::declval<T&>().data())
154 >::type>>: std::true_type
158 struct unwidest_unsigned;
161 struct unwidest_unsigned<U0>
166 template<class U0, class... UN>
167 struct unwidest_unsigned<U0, UN...>
169 BOOST_STATIC_ASSERT(std::is_unsigned<U0>::value);
170 using type = typename std::conditional<
171 (sizeof(U0) < sizeof(typename unwidest_unsigned<UN...>::type)),
172 U0, typename unwidest_unsigned<UN...>::type>::type;
176 struct widest_unsigned;
179 struct widest_unsigned<U0>
184 template<class U0, class... UN>
185 struct widest_unsigned<U0, UN...>
187 BOOST_STATIC_ASSERT(std::is_unsigned<U0>::value);
188 using type = typename std::conditional<
189 (sizeof(U0) > sizeof(typename widest_unsigned<UN...>::type)),
190 U0, typename widest_unsigned<UN...>::type>::type;
199 BOOST_STATIC_ASSERT(std::is_unsigned<U>::value);
203 template<class U0, class U1, class... UN>
206 typename unwidest_unsigned<U0, U1, UN...>::type
207 min_all(U0 u0, U1 u1, UN... un)
210 typename unwidest_unsigned<U0, U1, UN...>::type;
212 static_cast<type>(min_all(u0, un...)) :
213 static_cast<type>(min_all(u1, un...));
222 BOOST_STATIC_ASSERT(std::is_unsigned<U>::value);
226 template<class U0, class U1, class... UN>
229 typename widest_unsigned<U0, U1, UN...>::type
230 max_all(U0 u0, U1 u1, UN... un)
232 return u0 > u1? max_all(u0, un...) : max_all(u1, un...);
235 //------------------------------------------------------------------------------
241 // Types that meet the requirements,
242 // for use with std::declval only.
243 template<class BufferType>
244 struct BufferSequence
246 using value_type = BufferType;
247 using const_iterator = BufferType const*;
249 BufferSequence(BufferSequence const&) = default;
250 const_iterator begin() const noexcept;
251 const_iterator end() const noexcept;
253 using ConstBufferSequence =
254 BufferSequence<boost::asio::const_buffer>;
255 using MutableBufferSequence =
256 BufferSequence<boost::asio::mutable_buffer>;
258 template<class B1, class... Bn>
259 struct is_all_const_buffer_sequence
260 : std::integral_constant<bool,
261 boost::asio::is_const_buffer_sequence<B1>::value &&
262 is_all_const_buffer_sequence<Bn...>::value>
267 struct is_all_const_buffer_sequence<B>
268 : boost::asio::is_const_buffer_sequence<B>
272 template<class... Bn>
273 struct common_buffers_type
275 using type = typename std::conditional<
276 std::is_convertible<std::tuple<Bn...>,
277 typename repeat_tuple<sizeof...(Bn),
278 boost::asio::mutable_buffer>::type>::value,
279 boost::asio::mutable_buffer,
280 boost::asio::const_buffer>::type;
284 struct buffer_sequence_iterator
286 using type = decltype(
287 boost::asio::buffer_sequence_begin(
288 std::declval<B const&>()));
291 // Types that meet the requirements,
292 // for use with std::declval only.
295 StreamHandler(StreamHandler const&) = default;
296 void operator()(error_code ec, std::size_t);
298 using ReadHandler = StreamHandler;
299 using WriteHandler = StreamHandler;
301 template<class Buffers>
302 class buffers_range_adapter
307 using value_type = typename std::conditional<
308 std::is_convertible<typename std::iterator_traits<
309 typename buffer_sequence_iterator<Buffers>::type>::value_type,
310 boost::asio::const_buffer>::value,
311 boost::asio::const_buffer,
312 boost::asio::mutable_buffer>::type;
314 /* VFALCO This isn't right, because range-for will pick up the iterator's
315 value_type which might not be const_buffer or mutable_buffer. We
316 need to declare our own iterator wrapper that converts the underlying
317 iterator's value_type to const_buffer or mutable_buffer so that
318 range-for sees one of those types.
320 using const_iterator = typename
321 buffer_sequence_iterator<Buffers>::type;
324 buffers_range_adapter(Buffers const& b)
330 begin() const noexcept
332 return boost::asio::buffer_sequence_begin(b_);
338 return boost::asio::buffer_sequence_end(b_);
342 template<class Buffers>
343 buffers_range_adapter<Buffers>
344 buffers_range(Buffers const& buffers)
346 return buffers_range_adapter<Buffers>{buffers};