Line data Source code
1 : //
2 : // Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com)
3 : //
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)
6 : //
7 : // Official repository: https://github.com/cppalliance/buffers
8 : //
9 :
10 : #ifndef BOOST_BUFFERS_DYNAMIC_BUFFER_HPP
11 : #define BOOST_BUFFERS_DYNAMIC_BUFFER_HPP
12 :
13 : #include <boost/buffers/detail/config.hpp>
14 : #include <boost/buffers/buffer.hpp>
15 : #include <boost/core/span.hpp>
16 : #include <cstdlib>
17 :
18 : namespace boost {
19 : namespace buffers {
20 :
21 : /** Determine if T is a DynamicBuffer
22 : */
23 : template<
24 : class T,
25 : class = void>
26 : struct is_dynamic_buffer : std::false_type {};
27 :
28 : template<class T>
29 : struct is_dynamic_buffer<
30 : T, detail::void_t<decltype(
31 : std::declval<std::size_t&>() = std::declval<T const&>().size(),
32 : std::declval<std::size_t&>() = std::declval<T const&>().max_size(),
33 : std::declval<std::size_t&>() = std::declval<T const&>().capacity(),
34 : std::declval<T&>().commit(std::declval<std::size_t>()),
35 : std::declval<T&>().consume(std::declval<std::size_t>())
36 : )
37 : ,typename std::enable_if<
38 : is_const_buffer_sequence<typename T::const_buffers_type>::value &&
39 : is_mutable_buffer_sequence<typename T::mutable_buffers_type>::value
40 : >::type
41 : ,typename std::enable_if<
42 : std::is_same<decltype(
43 : std::declval<T const&>().data()),
44 : typename T::const_buffers_type>::value
45 : && std::is_same<decltype(
46 : std::declval<T&>().prepare(
47 : std::declval<std::size_t>())),
48 : typename T::mutable_buffers_type>::value
49 : >::type
50 : > > : std::true_type
51 : {
52 : };
53 :
54 : /** An abstract, type-erased dynamic buffer.
55 : */
56 : struct BOOST_SYMBOL_VISIBLE
57 : any_dynamic_buffer
58 : {
59 : using const_buffers_type = span<const_buffer const>;
60 : using mutable_buffers_type = span<mutable_buffer const>;
61 :
62 4096 : virtual ~any_dynamic_buffer() = default;
63 : virtual std::size_t size() const = 0;
64 : virtual std::size_t max_size() const = 0;
65 : virtual std::size_t capacity() const = 0;
66 : virtual const_buffers_type data() const = 0;
67 : virtual mutable_buffers_type prepare(std::size_t) = 0;
68 : virtual void commit(std::size_t) = 0;
69 : virtual void consume(std::size_t) = 0;
70 : };
71 :
72 : //-----------------------------------------------
73 :
74 : /** A type-erased dynamic buffer.
75 : */
76 : template<
77 : class DynamicBuffer,
78 : std::size_t N = 8>
79 : class any_dynamic_buffer_impl
80 : : public any_dynamic_buffer
81 : {
82 : DynamicBuffer b_;
83 : const_buffer data_[N];
84 : mutable_buffer out_[N];
85 : std::size_t data_len_ = 0;
86 : std::size_t out_len_ = 0;
87 :
88 : template<class ConstBufferSequence, class BufferType>
89 : static
90 : std::size_t
91 34880 : unroll(
92 : ConstBufferSequence const& bs,
93 : BufferType* dest,
94 : std::size_t len)
95 : {
96 34880 : std::size_t i = 0;
97 34880 : auto const end_ = end(bs);
98 104640 : for(auto it = begin(bs); it != end_; ++it)
99 : {
100 69760 : dest[i++] = *it;
101 69760 : if(i == len)
102 0 : break;
103 : }
104 34880 : return i;
105 : }
106 :
107 : public:
108 : template<class DynamicBuffer_>
109 : explicit
110 4096 : any_dynamic_buffer_impl(
111 : DynamicBuffer_&& b)
112 4096 : : b_(std::forward<DynamicBuffer_>(b))
113 : {
114 4096 : }
115 :
116 : DynamicBuffer&
117 : buffer() noexcept
118 : {
119 : return b_;
120 : }
121 :
122 : DynamicBuffer const&
123 : buffer() const noexcept
124 : {
125 : return b_;
126 : }
127 :
128 : std::size_t
129 0 : size() const override
130 : {
131 0 : return b_.size();
132 : }
133 :
134 : std::size_t
135 0 : max_size() const override
136 : {
137 0 : return b_.max_size();
138 : }
139 :
140 : std::size_t
141 0 : capacity() const override
142 : {
143 0 : return b_.capacity();
144 : }
145 :
146 : const_buffers_type
147 12288 : data() const override
148 : {
149 24576 : return const_buffers_type(
150 12288 : data_, data_len_);
151 : }
152 :
153 : auto
154 11792 : prepare(
155 : std::size_t n) ->
156 : mutable_buffers_type override
157 : {
158 11792 : out_len_ = unroll(
159 11792 : b_.prepare(n), out_, N);
160 23584 : return mutable_buffers_type(
161 11792 : out_, out_len_);
162 : }
163 :
164 : void
165 11792 : commit(
166 : std::size_t n) override
167 : {
168 11792 : b_.commit(n);
169 11792 : data_len_ = unroll(
170 11792 : b_.data(), data_, N);
171 11792 : }
172 :
173 : void
174 11296 : consume(
175 : std::size_t n) override
176 : {
177 11296 : b_.consume(n);
178 11296 : data_len_ = unroll(
179 11296 : b_.data(), data_, N);
180 11296 : }
181 : };
182 :
183 : template<
184 : class DynamicBuffer
185 : , class = typename std::enable_if<
186 : is_dynamic_buffer<
187 : typename std::decay<DynamicBuffer>::type
188 : >::value>::type
189 : >
190 : auto
191 4096 : make_any(DynamicBuffer&& b) ->
192 : any_dynamic_buffer_impl<typename
193 : std::decay<DynamicBuffer>::type>
194 : {
195 : return any_dynamic_buffer_impl<typename
196 : std::decay<DynamicBuffer>::type>(
197 4096 : std::forward<DynamicBuffer>(b));
198 : }
199 :
200 : } // buffers
201 : } // boost
202 :
203 : #endif
|