include/boost/capy/buffers/string_dynamic_buffer.hpp

100.0% Lines (53/53) 100.0% Functions (10/10)
Line TLA Hits 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_STRING_DYNAMIC_BUFFER_HPP
11 #define BOOST_CAPY_BUFFERS_STRING_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 #include <string>
17
18 namespace boost {
19 namespace capy {
20
21 /** A dynamic buffer backed by a `std::basic_string`.
22
23 This adapter wraps an externally-owned string and
24 exposes it through the @ref DynamicBuffer interface.
25 Readable bytes occupy the front of the string; writable
26 bytes are appended by `prepare` and made readable by
27 `commit`.
28
29 @note The wrapped string must outlive this adapter.
30 Calls to `prepare`, `commit`, and `consume`
31 invalidate previously returned buffer views.
32
33 @par Thread Safety
34 Distinct objects: Safe.
35 Shared objects: Unsafe.
36
37 @par Example
38 @code
39 std::string s;
40 auto buf = dynamic_buffer( s, 4096 );
41 auto mb = buf.prepare( 100 );
42 // fill mb with data...
43 buf.commit( 100 );
44 // buf.data() now has 100 readable bytes
45 buf.consume( 50 );
46 @endcode
47
48 @tparam CharT The character type.
49 @tparam Traits The character traits type.
50 @tparam Allocator The allocator type.
51
52 @see DynamicBuffer, string_dynamic_buffer, dynamic_buffer
53 */
54 template<
55 class CharT,
56 class Traits = std::char_traits<CharT>,
57 class Allocator = std::allocator<CharT>>
58 class basic_string_dynamic_buffer
59 {
60 std::basic_string<
61 CharT, Traits, Allocator>* s_;
62 std::size_t max_size_;
63
64 std::size_t in_size_ = 0;
65 std::size_t out_size_ = 0;
66
67 public:
68 /// Indicates this is a DynamicBuffer adapter over external storage.
69 using is_dynamic_buffer_adapter = void;
70
71 /// The underlying string type.
72 using string_type = std::basic_string<
73 CharT, Traits, Allocator>;
74
75 /// The ConstBufferSequence type for readable bytes.
76 using const_buffers_type = const_buffer;
77
78 /// The MutableBufferSequence type for writable bytes.
79 using mutable_buffers_type = mutable_buffer;
80
81 /// Destroy the buffer.
82 ~basic_string_dynamic_buffer() = default;
83
84 /// Construct by moving from another buffer.
85 266x basic_string_dynamic_buffer(
86 basic_string_dynamic_buffer&& other) noexcept
87 266x : s_(other.s_)
88 266x , max_size_(other.max_size_)
89 266x , in_size_(other.in_size_)
90 266x , out_size_(other.out_size_)
91 {
92 266x other.s_ = nullptr;
93 266x }
94
95 /** Construct from an existing string.
96
97 @param s Pointer to the string to wrap. Must
98 remain valid for the lifetime of this object.
99 @param max_size Optional upper bound on the number
100 of bytes the buffer may hold.
101 */
102 explicit
103 427x basic_string_dynamic_buffer(
104 string_type* s,
105 std::size_t max_size =
106 std::size_t(-1)) noexcept
107 427x : s_(s)
108 427x , max_size_(
109 427x max_size > s_->max_size()
110 427x ? s_->max_size()
111 427x : max_size)
112 {
113 427x if(s_->size() > max_size_)
114 1x s_->resize(max_size_);
115 427x in_size_ = s_->size();
116 427x }
117
118 /// Copy assignment is deleted.
119 basic_string_dynamic_buffer& operator=(
120 basic_string_dynamic_buffer const&) = delete;
121
122 /// Return the number of readable bytes.
123 std::size_t
124 1280x size() const noexcept
125 {
126 1280x return in_size_;
127 }
128
129 /// Return the maximum number of bytes the buffer can hold.
130 std::size_t
131 410x max_size() const noexcept
132 {
133 410x return max_size_;
134 }
135
136 /// Return the number of writable bytes without reallocation.
137 std::size_t
138 2x capacity() const noexcept
139 {
140 2x if(s_->capacity() <= max_size_)
141 1x return s_->capacity() - in_size_;
142 1x return max_size_ - in_size_;
143 }
144
145 /// Return a buffer sequence representing the readable bytes.
146 const_buffers_type
147 387x data() const noexcept
148 {
149 387x return const_buffers_type(
150 774x s_->data(), in_size_);
151 }
152
153 /** Prepare writable space of at least `n` bytes.
154
155 Invalidates iterators and references returned by
156 previous calls to `data` and `prepare`.
157
158 @throws std::invalid_argument if `n` exceeds
159 available space.
160
161 @param n The number of bytes to prepare.
162
163 @return A mutable buffer of exactly `n` bytes.
164 */
165 mutable_buffers_type
166 533x prepare(std::size_t n)
167 {
168 // n exceeds available space
169 533x if(n > max_size_ - in_size_)
170 1x detail::throw_invalid_argument();
171
172 532x if( s_->size() < in_size_ + n)
173 531x s_->resize(in_size_ + n);
174 532x out_size_ = n;
175 532x return mutable_buffers_type(
176 1064x &(*s_)[in_size_], out_size_);
177 }
178
179 /** Move bytes from the writable to the readable area.
180
181 Invalidates iterators and references returned by
182 previous calls to `data` and `prepare`.
183
184 @param n The number of bytes to commit. Clamped
185 to the size of the writable area.
186 */
187 434x void commit(std::size_t n) noexcept
188 {
189 434x if(n < out_size_)
190 242x in_size_ += n;
191 else
192 192x in_size_ += out_size_;
193 434x out_size_ = 0;
194 434x s_->resize(in_size_);
195 434x }
196
197 /** Remove bytes from the beginning of the readable area.
198
199 Invalidates iterators and references returned by
200 previous calls to `data` and `prepare`.
201
202 @param n The number of bytes to consume. Clamped
203 to the number of readable bytes.
204 */
205 168x void consume(std::size_t n) noexcept
206 {
207 168x if(n < in_size_)
208 {
209 3x s_->erase(0, n);
210 3x in_size_ -= n;
211 }
212 else
213 {
214 165x s_->clear();
215 165x in_size_ = 0;
216 }
217 168x out_size_ = 0;
218 168x }
219 };
220
221 /// A dynamic buffer using `std::string`.
222 using string_dynamic_buffer = basic_string_dynamic_buffer<char>;
223
224 /** Create a dynamic buffer from a string.
225
226 @param s The string to wrap.
227 @param max_size Optional maximum size limit.
228 @return A string_dynamic_buffer wrapping the string.
229 */
230 template<class CharT, class Traits, class Allocator>
231 basic_string_dynamic_buffer<CharT, Traits, Allocator>
232 132x dynamic_buffer(
233 std::basic_string<CharT, Traits, Allocator>& s,
234 std::size_t max_size = std::size_t(-1))
235 {
236 132x return basic_string_dynamic_buffer<CharT, Traits, Allocator>(&s, max_size);
237 }
238
239 } // capy
240 } // boost
241
242 #endif
243