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/capy
8 : //
9 :
10 : #ifndef BOOST_CAPY_BUFFERS_FLAT_DYNAMIC_BUFFER_HPP
11 : #define BOOST_CAPY_BUFFERS_FLAT_DYNAMIC_BUFFER_HPP
12 :
13 : #include <boost/capy/detail/config.hpp>
14 : #include <boost/capy/buffers.hpp>
15 : #include <boost/capy/detail/except.hpp>
16 :
17 : namespace boost {
18 : namespace capy {
19 :
20 : /** A fixed-capacity linear buffer satisfying DynamicBuffer.
21 :
22 : This class provides a contiguous buffer with fixed capacity
23 : determined at construction. Buffer sequences returned from
24 : @ref data and @ref prepare always contain exactly one element,
25 : making it suitable for APIs requiring contiguous memory.
26 :
27 : @par Example
28 : @code
29 : char storage[1024];
30 : flat_dynamic_buffer fb( storage, sizeof( storage ) );
31 :
32 : // Write data
33 : auto mb = fb.prepare( 100 );
34 : std::memcpy( mb.data(), "hello", 5 );
35 : fb.commit( 5 );
36 :
37 : // Read data
38 : auto data = fb.data();
39 : // process data...
40 : fb.consume( 5 );
41 : @endcode
42 :
43 : @par Thread Safety
44 : Distinct objects: Safe.
45 : Shared objects: Unsafe.
46 :
47 : @see circular_dynamic_buffer, string_dynamic_buffer
48 : */
49 : class flat_dynamic_buffer
50 : {
51 : unsigned char* data_ = nullptr;
52 : std::size_t cap_ = 0;
53 : std::size_t in_pos_ = 0;
54 : std::size_t in_size_ = 0;
55 : std::size_t out_size_ = 0;
56 :
57 : public:
58 : /// Indicates this is a DynamicBuffer adapter over external storage.
59 : using is_dynamic_buffer_adapter = void;
60 :
61 : /// The ConstBufferSequence type for readable bytes.
62 : using const_buffers_type = const_buffer;
63 :
64 : /// The MutableBufferSequence type for writable bytes.
65 : using mutable_buffers_type = mutable_buffer;
66 :
67 : /// Construct an empty flat buffer with zero capacity.
68 : flat_dynamic_buffer() = default;
69 :
70 : /** Construct a flat buffer over existing storage.
71 :
72 : @param data Pointer to the storage.
73 : @param capacity Size of the storage in bytes.
74 : @param initial_size Number of bytes already present as
75 : readable. Must not exceed @p capacity.
76 :
77 : @throws std::invalid_argument if initial_size > capacity.
78 : */
79 223 : flat_dynamic_buffer(
80 : void* data,
81 : std::size_t capacity,
82 : std::size_t initial_size = 0)
83 223 : : data_(static_cast<
84 : unsigned char*>(data))
85 223 : , cap_(capacity)
86 223 : , in_size_(initial_size)
87 : {
88 223 : if(in_size_ > cap_)
89 1 : detail::throw_invalid_argument();
90 222 : }
91 :
92 : /// Copy constructor.
93 : flat_dynamic_buffer(
94 : flat_dynamic_buffer const&) = default;
95 :
96 : /// Copy assignment.
97 : flat_dynamic_buffer& operator=(
98 : flat_dynamic_buffer const&) = default;
99 :
100 : /// Return the number of readable bytes.
101 : std::size_t
102 856 : size() const noexcept
103 : {
104 856 : return in_size_;
105 : }
106 :
107 : /// Return the maximum number of bytes the buffer can hold.
108 : std::size_t
109 10 : max_size() const noexcept
110 : {
111 10 : return cap_;
112 : }
113 :
114 : /// Return the number of writable bytes without reallocation.
115 : std::size_t
116 238 : capacity() const noexcept
117 : {
118 238 : return cap_ - (in_pos_ + in_size_);
119 : }
120 :
121 : /// Return a buffer sequence representing the readable bytes.
122 : const_buffers_type
123 161 : data() const noexcept
124 : {
125 322 : return const_buffers_type(
126 161 : data_ + in_pos_, in_size_);
127 : }
128 :
129 : /** Return a buffer sequence for writing.
130 :
131 : Invalidates buffer sequences previously obtained
132 : from @ref prepare.
133 :
134 : @param n The desired number of writable bytes.
135 :
136 : @return A mutable buffer sequence of size @p n.
137 :
138 : @throws std::invalid_argument if `n > capacity()`.
139 : */
140 : mutable_buffers_type
141 197 : prepare(std::size_t n)
142 : {
143 197 : if( n > capacity() )
144 3 : detail::throw_invalid_argument();
145 :
146 194 : out_size_ = n;
147 388 : return mutable_buffers_type(
148 194 : data_ + in_pos_ + in_size_, n);
149 : }
150 :
151 : /** Move bytes from the output to the input sequence.
152 :
153 : Invalidates buffer sequences previously obtained
154 : from @ref prepare. Buffer sequences from @ref data
155 : remain valid.
156 :
157 : @param n The number of bytes to commit. If greater
158 : than the prepared size, all prepared bytes
159 : are committed.
160 : */
161 : void
162 160 : commit(
163 : std::size_t n) noexcept
164 : {
165 160 : if(n < out_size_)
166 15 : in_size_ += n;
167 : else
168 145 : in_size_ += out_size_;
169 160 : out_size_ = 0;
170 160 : }
171 :
172 : /** Remove bytes from the beginning of the input sequence.
173 :
174 : Invalidates buffer sequences previously obtained
175 : from @ref data. Buffer sequences from @ref prepare
176 : remain valid.
177 :
178 : @param n The number of bytes to consume. If greater
179 : than @ref size(), all readable bytes are consumed.
180 : */
181 : void
182 180 : consume(
183 : std::size_t n) noexcept
184 : {
185 180 : if(n < in_size_)
186 : {
187 15 : in_pos_ += n;
188 15 : in_size_ -= n;
189 : }
190 : else
191 : {
192 165 : in_pos_ = 0;
193 165 : in_size_ = 0;
194 : }
195 180 : }
196 : };
197 :
198 : } // capy
199 : } // boost
200 :
201 : #endif
|