Coverage Report

Created: 2026-10-31 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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 &copy(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 &copy(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