2 // Copyright (c) 2016-2019 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_IMPL_BUFFERS_CAT_HPP
11 #define BOOST_BEAST_IMPL_BUFFERS_CAT_HPP
13 #include <boost/beast/core/detail/tuple.hpp>
14 #include <boost/beast/core/detail/variant.hpp>
15 #include <boost/asio/buffer.hpp>
25 template<class Buffer>
26 class buffers_cat_view<Buffer>
30 using value_type = buffers_type<Buffer>;
32 using const_iterator = buffers_iterator_type<Buffer>;
35 buffers_cat_view(Buffer const& buffer)
43 return net::buffer_sequence_begin(buffer_);
49 return net::buffer_sequence_end(buffer_);
53 #if defined(_MSC_VER) && ! defined(__clang__)
54 # define BOOST_BEAST_UNREACHABLE() __assume(false)
55 # define BOOST_BEAST_UNREACHABLE_RETURN(v) __assume(false)
57 # define BOOST_BEAST_UNREACHABLE() __builtin_unreachable()
58 # define BOOST_BEAST_UNREACHABLE_RETURN(v) \
59 do { __builtin_unreachable(); return v; } while(false)
62 #ifdef BOOST_BEAST_TESTS
64 #define BOOST_BEAST_LOGIC_ERROR(s) \
66 BOOST_THROW_EXCEPTION(std::logic_error((s))); \
67 BOOST_BEAST_UNREACHABLE(); \
70 #define BOOST_BEAST_LOGIC_ERROR_RETURN(v, s) \
72 BOOST_THROW_EXCEPTION(std::logic_error(s)); \
73 BOOST_BEAST_UNREACHABLE_RETURN(v); \
78 #define BOOST_BEAST_LOGIC_ERROR(s) \
80 BOOST_ASSERT_MSG(false, s); \
81 BOOST_BEAST_UNREACHABLE(); \
84 #define BOOST_BEAST_LOGIC_ERROR_RETURN(v, s) \
86 BOOST_ASSERT_MSG(false, (s)); \
87 BOOST_BEAST_UNREACHABLE_RETURN(v); \
94 struct buffers_cat_view_iterator_base
98 char unused = 0; // make g++8 happy
103 BOOST_BEAST_LOGIC_ERROR_RETURN({},
104 "Dereferencing a one-past-the-end iterator");
107 operator bool() const noexcept
116 template<class... Bn>
117 class buffers_cat_view<Bn...>::const_iterator
118 : private detail::buffers_cat_view_iterator_base
120 // VFALCO The logic to skip empty sequences fails
121 // if there is just one buffer in the list.
122 static_assert(sizeof...(Bn) >= 2,
123 "A minimum of two sequences are required");
125 detail::tuple<Bn...> const* bn_ = nullptr;
127 buffers_iterator_type<Bn>..., past_end> it_{};
129 friend class buffers_cat_view<Bn...>;
131 template<std::size_t I>
132 using C = std::integral_constant<std::size_t, I>;
135 using value_type = typename
136 buffers_cat_view<Bn...>::value_type;
137 using pointer = value_type const*;
138 using reference = value_type;
139 using difference_type = std::ptrdiff_t;
140 using iterator_category =
141 std::bidirectional_iterator_tag;
143 const_iterator() = default;
144 const_iterator(const_iterator const& other) = default;
145 const_iterator& operator=(
146 const_iterator const& other) = default;
149 operator==(const_iterator const& other) const;
152 operator!=(const_iterator const& other) const
154 return ! (*this == other);
161 operator->() const = delete;
177 detail::tuple<Bn...> const& bn,
181 detail::tuple<Bn...> const& bn,
186 const_iterator const& self;
189 operator()(mp11::mp_size_t<0>)
191 BOOST_BEAST_LOGIC_ERROR_RETURN({},
192 "Dereferencing a default-constructed iterator");
196 reference operator()(I)
198 return *self.it_.template get<I::value>();
204 const_iterator& self;
207 operator()(mp11::mp_size_t<0>)
209 BOOST_BEAST_LOGIC_ERROR(
210 "Incrementing a default-constructed iterator");
213 template<std::size_t I>
215 operator()(mp11::mp_size_t<I>)
217 ++self.it_.template get<I>();
218 next(mp11::mp_size_t<I>{});
221 template<std::size_t I>
223 next(mp11::mp_size_t<I>)
225 auto& it = self.it_.template get<I>();
228 if (it == net::buffer_sequence_end(
229 detail::get<I-1>(*self.bn_)))
231 if(net::const_buffer(*it).size() > 0)
235 self.it_.template emplace<I+1>(
236 net::buffer_sequence_begin(
237 detail::get<I>(*self.bn_)));
238 next(mp11::mp_size_t<I+1>{});
242 operator()(mp11::mp_size_t<sizeof...(Bn)>)
244 auto constexpr I = sizeof...(Bn);
245 ++self.it_.template get<I>();
246 next(mp11::mp_size_t<I>{});
250 next(mp11::mp_size_t<sizeof...(Bn)>)
252 auto constexpr I = sizeof...(Bn);
253 auto& it = self.it_.template get<I>();
256 if (it == net::buffer_sequence_end(
257 detail::get<I-1>(*self.bn_)))
259 if(net::const_buffer(*it).size() > 0)
264 self.it_.template emplace<I+1>();
268 operator()(mp11::mp_size_t<sizeof...(Bn)+1>)
270 BOOST_BEAST_LOGIC_ERROR(
271 "Incrementing a one-past-the-end iterator");
277 const_iterator& self;
280 operator()(mp11::mp_size_t<0>)
282 BOOST_BEAST_LOGIC_ERROR(
283 "Decrementing a default-constructed iterator");
287 operator()(mp11::mp_size_t<1>)
289 auto constexpr I = 1;
291 auto& it = self.it_.template get<I>();
294 if(it == net::buffer_sequence_begin(
295 detail::get<I-1>(*self.bn_)))
297 BOOST_BEAST_LOGIC_ERROR(
298 "Decrementing an iterator to the beginning");
301 if(net::const_buffer(*it).size() > 0)
306 template<std::size_t I>
308 operator()(mp11::mp_size_t<I>)
310 auto& it = self.it_.template get<I>();
313 if(it == net::buffer_sequence_begin(
314 detail::get<I-1>(*self.bn_)))
317 if(net::const_buffer(*it).size() > 0)
320 self.it_.template emplace<I-1>(
321 net::buffer_sequence_end(
322 detail::get<I-2>(*self.bn_)));
323 (*this)(mp11::mp_size_t<I-1>{});
327 operator()(mp11::mp_size_t<sizeof...(Bn)+1>)
329 auto constexpr I = sizeof...(Bn)+1;
330 self.it_.template emplace<I-1>(
331 net::buffer_sequence_end(
332 detail::get<I-2>(*self.bn_)));
333 (*this)(mp11::mp_size_t<I-1>{});
338 //------------------------------------------------------------------------------
340 template<class... Bn>
341 buffers_cat_view<Bn...>::
344 detail::tuple<Bn...> const& bn,
349 it_.template emplace<sizeof...(Bn)+1>();
352 template<class... Bn>
353 buffers_cat_view<Bn...>::
356 detail::tuple<Bn...> const& bn,
360 it_.template emplace<1>(
361 net::buffer_sequence_begin(
362 detail::get<0>(*bn_)));
363 increment{*this}.next(
364 mp11::mp_size_t<1>{});
367 template<class... Bn>
369 buffers_cat_view<Bn...>::
371 operator==(const_iterator const& other) const
373 return bn_ == other.bn_ && it_ == other.it_;
376 template<class... Bn>
378 buffers_cat_view<Bn...>::
383 return mp11::mp_with_index<
389 template<class... Bn>
391 buffers_cat_view<Bn...>::
403 template<class... Bn>
405 buffers_cat_view<Bn...>::
415 template<class... Bn>
417 buffers_cat_view<Bn...>::
429 template<class... Bn>
431 buffers_cat_view<Bn...>::
441 //------------------------------------------------------------------------------
443 template<class... Bn>
444 buffers_cat_view<Bn...>::
445 buffers_cat_view(Bn const&... bn)
451 template<class... Bn>
453 buffers_cat_view<Bn...>::begin() const ->
456 return const_iterator{bn_, std::false_type{}};
459 template<class... Bn>
461 buffers_cat_view<Bn...>::end() const->
464 return const_iterator{bn_, std::true_type{}};