/src/trafficserver/lib/swoc/include/swoc/BufferWriter.h
Line | Count | Source |
1 | | // SPDX-License-Identifier: Apache-2.0 |
2 | | // Copyright Apache Software Foundation 2019 |
3 | | /** @file |
4 | | |
5 | | Utilities for generating character sequences in buffers. |
6 | | */ |
7 | | |
8 | | #pragma once |
9 | | |
10 | | #include <cstdlib> |
11 | | #include <utility> |
12 | | #include <cstring> |
13 | | #include <vector> |
14 | | #include <string> |
15 | | #include <iosfwd> |
16 | | #include <string_view> |
17 | | |
18 | | #include "swoc/swoc_version.h" |
19 | | #include "swoc/TextView.h" |
20 | | #include "swoc/MemSpan.h" |
21 | | #include "swoc/bwf_fwd.h" |
22 | | |
23 | | namespace swoc { inline namespace SWOC_VERSION_NS { |
24 | | |
25 | | /** Wrapper for operations on a buffer. |
26 | | * |
27 | | * This maintains information about the size and amount in use of the buffer, preventing data |
28 | | * overruns. In all cases, methods that write to the buffer clip the input to the size of the |
29 | | * remaining buffer space. The @c error method can be used to detect such clipping. The theoretical |
30 | | * size of the buffer is also tracked such that if there is not enough buffer space, the amount |
31 | | * needed can be determined by the method @c extent. |
32 | | * |
33 | | * @note This is a protocol class, concrete subclasses implement the functionality. |
34 | | */ |
35 | | class BufferWriter { |
36 | | public: |
37 | | /** Write @a c to the buffer. |
38 | | * |
39 | | * @param c Character to write. |
40 | | * @return @a this. |
41 | | */ |
42 | | virtual BufferWriter &write(char c) = 0; |
43 | | |
44 | | /** Write @a length bytes starting at @a data to the buffer. |
45 | | * |
46 | | * @param data Source data. |
47 | | * @param length Number of bytes in the source data. |
48 | | * @return @a this. |
49 | | * |
50 | | * @internal This uses the single character write to output the data. It is presumed concrete |
51 | | * subclasses will override this method to use more efficient mechanisms, dependent on the type of |
52 | | * output buffer. |
53 | | */ |
54 | | virtual BufferWriter &write(void const *data, size_t length); |
55 | | |
56 | | /** Write data to the buffer. |
57 | | * |
58 | | * @param span Data source. |
59 | | * @return @a this |
60 | | * |
61 | | * Data from @a span is written directly to the buffer, and clipped to the size of the buffer. |
62 | | * |
63 | | * @internal The char poointer overloads protect this method in order to protect against including |
64 | | * the terminal nul in the destination buffer. |
65 | | */ |
66 | | BufferWriter &write(MemSpan<void const> span); |
67 | | |
68 | | /// @return Pointer to first byte in buffer. |
69 | | virtual const char *data() const = 0; |
70 | | |
71 | | /// Get the error state. |
72 | | /// @return @c true if in an error state, @c false if not. |
73 | | virtual bool error() const = 0; |
74 | | |
75 | | /** Address of the first unused byte in the output buffer. |
76 | | |
77 | | The address is fragile and calls to non-const methods can invalidate it. |
78 | | |
79 | | @return Address of the next output byte, or @c nullptr if there is no remaining capacity. |
80 | | */ |
81 | | virtual char *aux_data(); |
82 | | |
83 | | /// @return The number of bytes that can be successfully written to this buffer. |
84 | | virtual size_t capacity() const = 0; |
85 | | |
86 | | /// @return Number of characters written to the buffer, including those discarded. |
87 | | virtual size_t extent() const = 0; |
88 | | |
89 | | /// @return Number of bytes of valid (used) data in the buffer. |
90 | | size_t size() const; |
91 | | |
92 | | /// @return The number of bytes which have not yet been written. |
93 | | size_t remaining() const; |
94 | | |
95 | | /** A memory span of the unused bytes. |
96 | | * |
97 | | * @return A span of the unused bytes. |
98 | | * |
99 | | * This is a convenience method that is identical to |
100 | | * @code |
101 | | * BufferWriter w; |
102 | | * // ... |
103 | | * MemSpan<char>{ w.aux_data(), w.remaining() }; |
104 | | * @endcode |
105 | | */ |
106 | | MemSpan<char> aux_span(); |
107 | | |
108 | | /** Increase the extent by @a n bytes. |
109 | | * |
110 | | * @param n Number of bytes. |
111 | | * @return @c true if the commit is final, @c false if it should be retried. |
112 | | * |
113 | | * This is used to add data written in the @c aux_data to the written data in the buffer. |
114 | | * |
115 | | * The return value should be @c true unless the write operation proceeding the call to @c commit |
116 | | * along with the @c commit call should be retried. That is only reasonable if some state in the |
117 | | * concrete implementation has changed to make success possible on the next try. Generally this |
118 | | * will be because the implementation increased capacity. |
119 | | * |
120 | | * @internal Concrete subclasses @b must override this in a way consistent with the specific buffer type. |
121 | | */ |
122 | | virtual bool commit(size_t n) = 0; |
123 | | |
124 | | /** Decrease the extent by @a n. |
125 | | * |
126 | | * @param n Number of bytes to remove from the extent. |
127 | | * @return @a this. |
128 | | * |
129 | | * The buffer content is unchanged, only the extent value is adjusted. This effectively discards |
130 | | * @a n bytes of already written data. |
131 | | */ |
132 | | virtual BufferWriter &discard(size_t n) = 0; |
133 | | |
134 | | /// Reduce the capacity by @a n bytes |
135 | | /// If the capacity is reduced below the current @c size the instance goes in to an error state. |
136 | | /// @see restore |
137 | | /// @return @c *this |
138 | | virtual BufferWriter &restrict(size_t n) = 0; |
139 | | |
140 | | /// Restore @a n bytes of capacity. |
141 | | /// If there is an error condition, this function clears it and sets the extent to the size. It |
142 | | /// then increases the capacity by n characters. |
143 | | /// @note This does not make the internal buffer size larger. It can only restore capacity earlier |
144 | | /// removed by @c restrict. |
145 | | /// @see restrict |
146 | | virtual BufferWriter &restore(size_t n) = 0; |
147 | | |
148 | | /** Copy data from one part of the buffer to another. |
149 | | * |
150 | | * The copy is guaranteed to be correct even if the @a src and @a dst overlap. The regions are |
151 | | * clipped by the current extent. That is, bytes cannot be copied to nor from unwritten buffer. |
152 | | * If the extent is currently more than the capacity, the copy is performed as if the buffer |
153 | | * existed and then clipped to the actual buffer space. |
154 | | * |
155 | | * @param dst Offset of the first by to copy onto. |
156 | | * @param src Offset of the first byte to copy from. |
157 | | * @param n Number of bytes to copy. |
158 | | * @return @c *this |
159 | | * |
160 | | * @internal This is used to perform justification for formatting. |
161 | | */ |
162 | | virtual BufferWriter ©(size_t dst, size_t src, size_t n) = 0; |
163 | | |
164 | | // Force virtual destructor. |
165 | | virtual ~BufferWriter(); |
166 | | |
167 | | /** Formatted output to the buffer. |
168 | | * |
169 | | * @tparam Args Types of the format arguments. |
170 | | * @param fmt Format string to control formatted output. |
171 | | * @param args Parameters for the format string. |
172 | | * @return @a this. |
173 | | * |
174 | | * The format string is Python style. |
175 | | * See http://docs.solidwallofcode.com/libswoc/code/BW_Format.en.html for further information. |
176 | | * |
177 | | * @note This must be declared here, but the implementation is in @c bwf_base.h. That file does |
178 | | * not need to be included if formatted output is not used. |
179 | | */ |
180 | | template <typename... Args> BufferWriter &print(const TextView &fmt, Args &&...args); |
181 | | |
182 | | /** Formatted output to the buffer. |
183 | | * |
184 | | * @tparam Args Types of the arguments for formatting. |
185 | | * @param fmt Format string. |
186 | | * @param args The format arguments in a tuple. |
187 | | * @return @a this |
188 | | * |
189 | | * This is the equivalent of the "va..." form for printing. Alternate front ends to formatted |
190 | | * output should gather their formatting arguments into a tuple, usually using |
191 | | * @c std::forward_as_tuple(). |
192 | | */ |
193 | | template <typename... Args> BufferWriter &print_v(const TextView &fmt, const std::tuple<Args...> &args); |
194 | | |
195 | | /** Formatted output to the buffer. |
196 | | * |
197 | | * @tparam Args Types of the format input parameters. |
198 | | * @param fmt Pre-condensed format. |
199 | | * @param args Arguments for the format string. |
200 | | * @return @a this. |
201 | | */ |
202 | | template <typename... Args> BufferWriter &print(const bwf::Format &fmt, Args &&...args); |
203 | | |
204 | | /** Formatted output to the buffer. |
205 | | * |
206 | | * @tparam Args Types of the parameter for formatting. |
207 | | * @param fmt Pre-condensed format string. |
208 | | * @param args The format parameters in a tuple. |
209 | | * @return @a this |
210 | | * |
211 | | * This is the equivalent of the "va..." form for printing. Alternate front ends to formatted |
212 | | * output should gather their formatting arguments into a tuple, usually using |
213 | | * @c std::forward_as_tuple(). |
214 | | */ |
215 | | template <typename... Args> BufferWriter &print_v(const bwf::Format &fmt, const std::tuple<Args...> &args); |
216 | | |
217 | | /** Write formatted output of @a args to @a this buffer. |
218 | | * |
219 | | * @tparam Binding Type for the name binding instance. |
220 | | * @tparam Extractor Format extractor type. |
221 | | * @param names Name set for specifier names. |
222 | | * @param ex Format processor instance, which parse the format piecewise. |
223 | | * @param args The format parameters. |
224 | | * |
225 | | * @a Extractor must have at least two methods |
226 | | * - A conversion to @c bool that indicates if there is data left. |
227 | | * - A function of the signature <tt>bool ex(std::string_view& lit, bwf::Spec & spec)</tt> |
228 | | * |
229 | | * The latter must return whether a specifier was parsed, while filling in @a lit and @a spec |
230 | | * as appropriate for the next chunk of format string. No literal is represented by a empty |
231 | | * @a lit. |
232 | | * |
233 | | * The name binding must have a function operator that takes two arguments, a @c BufferWriter& |
234 | | * and a format specifier @c bwf::Spec. It is expected to generate output to the @c BufferWriter |
235 | | * instance based on data in the format specifier (which contains, among other things, the |
236 | | * name which caused the binding to be invoked). |
237 | | * |
238 | | * @note This is the base implementation, all of the other variants are wrappers for this. |
239 | | * |
240 | | * @see NameBinding |
241 | | */ |
242 | | template <typename Binding, typename Extractor> |
243 | | BufferWriter &print_nfv(Binding &&names, Extractor &&ex, bwf::ArgPack const &args); |
244 | | |
245 | | /** Write formatted output of @a args to @a this buffer. |
246 | | * |
247 | | * @tparam Binding Name binding functor. |
248 | | * @tparam Extractor Format processor type. |
249 | | * @param names Name set for specifier names. |
250 | | * @param ex Format processor instance, which parse the format piecewise. |
251 | | * |
252 | | * @note This is primarily an internal convenience for certain situations where a format parameter |
253 | | * tuple is not needed and difficult to create. |
254 | | */ |
255 | | template <typename Binding, typename Extractor> BufferWriter &print_nfv(Binding const &names, Extractor &&ex); |
256 | | |
257 | | /** Write formatted output to @a this buffer. |
258 | | * |
259 | | * @param names Name set for specifier names. |
260 | | * @param fmt Format string. |
261 | | * |
262 | | * This is intended to be use with context name binding where @a names has the bindings and the |
263 | | * format string @a fmt contains only references to those names, not to any arguments. |
264 | | */ |
265 | | template <typename Binding> BufferWriter &print_n(Binding const &names, TextView const &fmt); |
266 | | |
267 | | /** Write formattted data. |
268 | | * |
269 | | * @tparam T Data type. |
270 | | * @param spec Format specifier. |
271 | | * @param t Instance to print. |
272 | | * @return @a this |
273 | | * |
274 | | * Essentially this forwards @a t to @c bwformat. |
275 | | */ |
276 | | template <typename T> BufferWriter &format(bwf::Spec const &spec, T &&t); |
277 | | |
278 | | /** Write formattted data. |
279 | | * |
280 | | * @tparam T Data type. |
281 | | * @param spec Format specifier. |
282 | | * @param t Instance to print. |
283 | | * @return @a this |
284 | | * |
285 | | * Essentially this forwards @a t to @c bwformat. |
286 | | */ |
287 | | template <typename T> BufferWriter &format(bwf::Spec const &spec, T const &t); |
288 | | |
289 | | /** IO stream operator. |
290 | | * |
291 | | * @param stream Output stream. |
292 | | * @return @a stream |
293 | | * |
294 | | * Write the buffer contents to @a stream. |
295 | | */ |
296 | | virtual std::ostream &operator>>(std::ostream &stream) const = 0; |
297 | | }; |
298 | | |
299 | | /** A concrete @c BufferWriter class for a fixed buffer. |
300 | | * |
301 | | */ |
302 | | class FixedBufferWriter : public BufferWriter { |
303 | | using super_type = BufferWriter; |
304 | | using self_type = FixedBufferWriter; |
305 | | |
306 | | public: |
307 | | /** Construct a buffer writer on a fixed @a buffer of size @a capacity. |
308 | | |
309 | | If writing goes past the end of the buffer, the excess is dropped. |
310 | | */ |
311 | | FixedBufferWriter(char *buffer, size_t capacity); |
312 | | |
313 | | /// Construct using the memory @a span as the buffer. |
314 | | FixedBufferWriter(MemSpan<void> const &span); |
315 | | |
316 | | /// Construct using the memory @a span as the buffer. |
317 | | FixedBufferWriter(MemSpan<char> const &span); |
318 | | |
319 | | /** Constructor an empty buffer with no capacity. |
320 | | * This can be useful to measure the extent of the output before allocating memory. |
321 | | */ |
322 | | FixedBufferWriter(std::nullptr_t); |
323 | | |
324 | | FixedBufferWriter(const FixedBufferWriter &) = delete; |
325 | | |
326 | | FixedBufferWriter &operator=(const FixedBufferWriter &) = delete; |
327 | | |
328 | | /// Move constructor. |
329 | | FixedBufferWriter(FixedBufferWriter &&that); |
330 | | |
331 | | /// Move assignment. |
332 | | FixedBufferWriter &operator=(FixedBufferWriter &&that); |
333 | | |
334 | | /// Reset buffer. |
335 | | self_type &assign(MemSpan<char> const &span); |
336 | | |
337 | | /// Write a single character @a c to the buffer. |
338 | | FixedBufferWriter &write(char c) override; |
339 | | |
340 | | /// Write @a length bytes, starting at @a data, to the buffer. |
341 | | FixedBufferWriter &write(const void *data, size_t length) override; |
342 | | |
343 | | // Bring in non-overridden methods. |
344 | | using super_type::write; |
345 | | |
346 | | /// @return The start of the buffer. |
347 | | const char *data() const override; |
348 | | |
349 | | /// @return @c true if output has been discarded, @a false otherwise. |
350 | | bool error() const override; |
351 | | |
352 | | /// @return Start of the unused buffer, or @c nullptr is there is no remaining unwritten space. |
353 | | char *aux_data() override; |
354 | | |
355 | | /// Get the total capacity of the output buffer. |
356 | | size_t capacity() const override; |
357 | | |
358 | | /// Get the total output sent to the writer. |
359 | | size_t extent() const override; |
360 | | |
361 | | /// Advance the used part of the output buffer. |
362 | | bool commit(size_t n) override; |
363 | | |
364 | | /// Drop @a n characters from the end of the buffer. |
365 | | self_type &discard(size_t n) override; |
366 | | |
367 | | /// Reduce the capacity by @a n. |
368 | | self_type &restrict(size_t n) override; |
369 | | |
370 | | /// Restore @a n bytes of the capacity. |
371 | | self_type &restore(size_t n) override; |
372 | | |
373 | | /// Copy data in the buffer. |
374 | | FixedBufferWriter ©(size_t dst, size_t src, size_t n) override; |
375 | | |
376 | | /// Erase the buffer, reset to empty (no valid data). |
377 | | /// This is a convenience for reusing a buffer. For instance |
378 | | /// @code |
379 | | /// bw.clear().print("....."); // clear old data and print new data. |
380 | | /// @endcode |
381 | | /// This is equivalent to @c w.discard(w.size()) but clearer for that case. |
382 | | self_type &clear(); |
383 | | |
384 | | self_type &detach(); |
385 | | |
386 | | /// @return The used part of the buffer as a @c std::string_view. |
387 | | swoc::TextView view() const; |
388 | | |
389 | | /// Provide a @c string_view of all successfully written characters as a user conversion. |
390 | | operator std::string_view() const; |
391 | | |
392 | | /// Provide a @c string_view of all successfully written characters as a user conversion. |
393 | | operator swoc::TextView() const; |
394 | | |
395 | | /// Output the buffer contents to the @a stream. |
396 | | std::ostream &operator>>(std::ostream &stream) const override; |
397 | | |
398 | | /// @cond COVARY |
399 | | template <typename... Rest> self_type &print(TextView fmt, Rest &&...rest); |
400 | | |
401 | | template <typename... Args> self_type &print_v(TextView fmt, std::tuple<Args...> const &args); |
402 | | |
403 | | template <typename... Args> self_type &print(bwf::Format const &fmt, Args &&...args); |
404 | | |
405 | | template <typename... Args> self_type &print_v(bwf::Format const &fmt, std::tuple<Args...> const &args); |
406 | | /// @endcond |
407 | | |
408 | | protected: |
409 | | // Used for derived classes where we don't want to throw exceptions. |
410 | | FixedBufferWriter(char *buffer, size_t capacity, bool noexcept_flag) noexcept; |
411 | | |
412 | | char *const _buffer; ///< Output buffer. |
413 | | size_t _capacity; ///< Size of output buffer. |
414 | | size_t _attempted = 0; ///< Number of characters written, including those discarded due error condition. |
415 | | }; |
416 | | |
417 | | /** A @c BufferWriter that has an internal buffer. |
418 | | * |
419 | | * @tparam N Number of bytes in internal buffer. |
420 | | * |
421 | | * The buffer is part of the class instance and is therefore allocated from the same memory pool |
422 | | * as the object. E.g, if this is declared as a local variable the buffer is on the stack. |
423 | | * |
424 | | * This was written to make code such as |
425 | | * @code |
426 | | * char buff[1024]; |
427 | | * FixedBufferWriter w(buff, sizeof(buff)); |
428 | | * @endcode |
429 | | * simpler as |
430 | | * @code |
431 | | * LocalBufferWriter<1024> w; |
432 | | * @endcode |
433 | | * |
434 | | * This also makes it possible to use inside expressions and other stream operations without concern |
435 | | * about having to previously declare the storage. E.g. |
436 | | * @code |
437 | | * create_note(LocalBufferWriter<256>().print("Note {}", idx).view()); |
438 | | * @endcode |
439 | | */ |
440 | | template <size_t N> class LocalBufferWriter : public FixedBufferWriter { |
441 | | using self_type = LocalBufferWriter; |
442 | | using super_type = FixedBufferWriter; |
443 | | |
444 | | public: |
445 | | /// Construct an empty writer. |
446 | | LocalBufferWriter() noexcept; |
447 | | |
448 | | LocalBufferWriter(const LocalBufferWriter &that) = delete; |
449 | | |
450 | | LocalBufferWriter &operator=(const LocalBufferWriter &that) = delete; |
451 | | |
452 | | protected: |
453 | | char _arr[N]; ///< output buffer. |
454 | | }; |
455 | | |
456 | | // --------------- Implementation -------------------- |
457 | | |
458 | 1.59k | inline BufferWriter::~BufferWriter() {} |
459 | | |
460 | | inline BufferWriter & |
461 | 0 | BufferWriter::write(const void *data, size_t length) { |
462 | 0 | const char *d = static_cast<const char *>(data); |
463 | |
|
464 | 0 | while (length--) { |
465 | 0 | this->write(*(d++)); |
466 | 0 | } |
467 | 0 | return *this; |
468 | 0 | } |
469 | | |
470 | | #if 0 |
471 | | inline BufferWriter & |
472 | | BufferWriter::write(const std::string_view &sv) { |
473 | | return this->write(sv.data(), sv.size()); |
474 | | } |
475 | | #endif |
476 | | |
477 | | inline BufferWriter & |
478 | 2.28k | BufferWriter::write(MemSpan<void const> span) { |
479 | 2.28k | return this->write(span.data(), span.size()); |
480 | 2.28k | } |
481 | | |
482 | | inline char * |
483 | 0 | BufferWriter::aux_data() { |
484 | 0 | return nullptr; |
485 | 0 | } |
486 | | |
487 | | inline size_t |
488 | 1.82k | BufferWriter::size() const { |
489 | 1.82k | return std::min(this->extent(), this->capacity()); |
490 | 1.82k | } |
491 | | |
492 | | inline size_t |
493 | 1.14k | BufferWriter::remaining() const { |
494 | 1.14k | return this->capacity() - this->size(); |
495 | 1.14k | } |
496 | | |
497 | | // --- FixedBufferWriter --- |
498 | 1.14k | inline FixedBufferWriter::FixedBufferWriter(char *buffer, size_t capacity) : _buffer(buffer), _capacity(capacity) { |
499 | 1.14k | if (_capacity != 0 && buffer == nullptr) { |
500 | 0 | throw(std::invalid_argument{"FixedBufferWriter created with null buffer and non-zero size."}); |
501 | 1.14k | }; |
502 | 1.14k | } |
503 | | |
504 | 456 | inline FixedBufferWriter::FixedBufferWriter(char *buffer, size_t capacity, bool /* noexcept_flag */) noexcept : _buffer(buffer), _capacity(capacity) { |
505 | 456 | } |
506 | | |
507 | | inline FixedBufferWriter::FixedBufferWriter(MemSpan<void> const &span) |
508 | | : _buffer{static_cast<char *>(span.data())}, _capacity{span.size()} {} |
509 | | |
510 | 0 | inline FixedBufferWriter::FixedBufferWriter(MemSpan<char> const &span) : _buffer{span.begin()}, _capacity{span.size()} {} |
511 | | |
512 | 0 | inline FixedBufferWriter::FixedBufferWriter(std::nullptr_t) : _buffer(nullptr), _capacity(0) {} |
513 | | |
514 | | inline FixedBufferWriter::self_type & |
515 | 0 | FixedBufferWriter::detach() { |
516 | 0 | const_cast<char *&>(_buffer) = nullptr; |
517 | 0 | _capacity = 0; |
518 | 0 | _attempted = 0; |
519 | 0 | return *this; |
520 | 0 | } |
521 | | |
522 | | inline FixedBufferWriter::FixedBufferWriter(FixedBufferWriter &&that) |
523 | | : _buffer(that._buffer), _capacity(that._capacity), _attempted(that._attempted) { |
524 | | that.detach(); |
525 | | } |
526 | | |
527 | | inline FixedBufferWriter::self_type & |
528 | 0 | FixedBufferWriter::assign(MemSpan<char> const &span) { |
529 | 0 | const_cast<char *&>(_buffer) = span.data(); |
530 | 0 | _capacity = span.size(); |
531 | 0 | _attempted = 0; |
532 | 0 | return *this; |
533 | 0 | } |
534 | | |
535 | | inline FixedBufferWriter & |
536 | 0 | FixedBufferWriter::operator=(FixedBufferWriter &&that) { |
537 | 0 | const_cast<char *&>(_buffer) = that._buffer; |
538 | 0 | _capacity = that._capacity; |
539 | 0 | _attempted = that._attempted; |
540 | 0 | that.detach(); |
541 | 0 | return *this; |
542 | 0 | } |
543 | | |
544 | | inline FixedBufferWriter & |
545 | 456 | FixedBufferWriter::write(char c) { |
546 | 456 | if (_attempted < _capacity) { |
547 | 456 | _buffer[_attempted] = c; |
548 | 456 | } |
549 | 456 | ++_attempted; |
550 | | |
551 | 456 | return *this; |
552 | 456 | } |
553 | | |
554 | | inline FixedBufferWriter & |
555 | 2.28k | FixedBufferWriter::write(const void *data, size_t length) { |
556 | 2.28k | const size_t newSize = _attempted + length; |
557 | | |
558 | 2.28k | if (_buffer) { |
559 | 2.28k | if (newSize <= _capacity) { |
560 | 2.28k | std::memcpy(_buffer + _attempted, data, length); |
561 | 2.28k | } else if (_attempted < _capacity) { |
562 | 0 | std::memcpy(_buffer + _attempted, data, _capacity - _attempted); |
563 | 0 | } |
564 | 2.28k | } |
565 | 2.28k | _attempted = newSize; |
566 | | |
567 | 2.28k | return *this; |
568 | 2.28k | } |
569 | | |
570 | | /// Return the output buffer. |
571 | | inline const char * |
572 | 0 | FixedBufferWriter::data() const { |
573 | 0 | return _buffer; |
574 | 0 | } |
575 | | |
576 | | inline bool |
577 | 1.59k | FixedBufferWriter::error() const { |
578 | 1.59k | return _attempted > _capacity; |
579 | 1.59k | } |
580 | | |
581 | | inline char * |
582 | 1.36k | FixedBufferWriter::aux_data() { |
583 | 1.36k | return error() ? nullptr : _buffer + _attempted; |
584 | 1.36k | } |
585 | | |
586 | | inline bool |
587 | 1.36k | FixedBufferWriter::commit(size_t n) { |
588 | 1.36k | _attempted += n; |
589 | | |
590 | 1.36k | return true; |
591 | 1.36k | } |
592 | | |
593 | | inline size_t |
594 | 2.96k | FixedBufferWriter::capacity() const { |
595 | 2.96k | return _capacity; |
596 | 2.96k | } |
597 | | |
598 | | inline size_t |
599 | 5.24k | FixedBufferWriter::extent() const { |
600 | 5.24k | return _attempted; |
601 | 5.24k | } |
602 | | |
603 | 228 | inline auto FixedBufferWriter::restrict(size_t n) -> self_type & { |
604 | 228 | if (n > _capacity) { |
605 | 0 | throw(std::invalid_argument{"FixedBufferWriter restrict value more than capacity"}); |
606 | 0 | } |
607 | 228 | _capacity -= n; |
608 | 228 | return *this; |
609 | 228 | } |
610 | | |
611 | | inline auto |
612 | 228 | FixedBufferWriter::restore(size_t n) -> self_type & { |
613 | 228 | if (error()) { |
614 | 0 | _attempted = _capacity; |
615 | 0 | } |
616 | 228 | _capacity += n; |
617 | 228 | return *this; |
618 | 228 | } |
619 | | |
620 | | inline auto |
621 | 0 | FixedBufferWriter::discard(size_t n) -> self_type & { |
622 | 0 | _attempted -= std::min(_attempted, n); |
623 | 0 | return *this; |
624 | 0 | } |
625 | | |
626 | | inline auto |
627 | 0 | FixedBufferWriter::clear() -> self_type & { |
628 | 0 | _attempted = 0; |
629 | 0 | return *this; |
630 | 0 | } |
631 | | |
632 | | inline auto |
633 | 0 | FixedBufferWriter::copy(size_t dst, size_t src, size_t n) -> self_type & { |
634 | 0 | auto limit = std::min<size_t>(_capacity, _attempted); // max offset of region possible. |
635 | 0 | MemSpan<char> src_span{_buffer + src, std::min(limit, src + n)}; |
636 | 0 | MemSpan<char> dst_span{_buffer + dst, std::min(limit, dst + n)}; |
637 | 0 | std::memmove(dst_span.data(), src_span.data(), std::min(dst_span.size(), src_span.size())); |
638 | 0 | return *this; |
639 | 0 | } |
640 | | |
641 | | inline swoc::TextView |
642 | 456 | FixedBufferWriter::view() const { |
643 | 456 | return {_buffer, size()}; |
644 | 456 | } |
645 | | |
646 | 0 | inline FixedBufferWriter::operator std::string_view() const { |
647 | 0 | return this->view(); |
648 | 0 | } |
649 | | |
650 | 0 | inline FixedBufferWriter::operator swoc::TextView() const { |
651 | 0 | return this->view(); |
652 | 0 | } |
653 | | |
654 | | // --- LocalBufferWriter --- |
655 | 456 | template <size_t N> LocalBufferWriter<N>::LocalBufferWriter() noexcept : super_type(_arr, N, true) {}swoc::_1_5_15::LocalBufferWriter<1024ul>::LocalBufferWriter() Line | Count | Source | 655 | 228 | template <size_t N> LocalBufferWriter<N>::LocalBufferWriter() noexcept : super_type(_arr, N, true) {} |
Unexecuted instantiation: swoc::_1_5_15::LocalBufferWriter<128ul>::LocalBufferWriter() swoc::_1_5_15::LocalBufferWriter<48ul>::LocalBufferWriter() Line | Count | Source | 655 | 228 | template <size_t N> LocalBufferWriter<N>::LocalBufferWriter() noexcept : super_type(_arr, N, true) {} |
Unexecuted instantiation: swoc::_1_5_15::LocalBufferWriter<2048ul>::LocalBufferWriter() Unexecuted instantiation: swoc::_1_5_15::LocalBufferWriter<256ul>::LocalBufferWriter() Unexecuted instantiation: swoc::_1_5_15::LocalBufferWriter<10240ul>::LocalBufferWriter() Unexecuted instantiation: swoc::_1_5_15::LocalBufferWriter<4096ul>::LocalBufferWriter() |
656 | | |
657 | | }} // namespace swoc::SWOC_VERSION_NS |
658 | | |
659 | | /// @cond NOT_DOCUMENTED |
660 | | namespace std { |
661 | | inline ostream & |
662 | 0 | operator<<(ostream &s, swoc::BufferWriter const &w) { |
663 | 0 | return w >> s; |
664 | 0 | } |
665 | | } // end namespace std |
666 | | /// @endcond |