Coverage Report

Created: 2026-02-10 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/trafficserver/lib/swoc/include/swoc/bwf_ex.h
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0
2
// Copyright Apache Software Foundation 2019
3
/** @file
4
5
    BufferWriter formatters for types in the std namespace.
6
 */
7
8
#pragma once
9
10
#include <array>
11
#include <string_view>
12
13
#include "swoc/swoc_version.h"
14
#include "swoc/bwf_base.h"
15
#include "swoc/swoc_meta.h"
16
17
namespace swoc { inline namespace SWOC_VERSION_NS {
18
namespace bwf {
19
using namespace swoc::literals; // enable ""sv
20
21
/** Output @a text @a n times.
22
 *
23
 */
24
struct Pattern {
25
  int _n;                 ///< # of instances of @a pattern.
26
  std::string_view _text; ///< output text.
27
};
28
29
/** Format wrapper for @c errno.
30
 * This stores a copy of the argument or @c errno if an argument isn't provided. The output
31
 * is then formatted with the short, long, and numeric value of @c errno. If the format specifier
32
 * is type 'd' then just the numeric value is printed.
33
 */
34
struct Errno {
35
  int _e; ///< Errno value.
36
37
  /// Construct wrapper, default to current @c errno
38
0
  explicit Errno(int e = errno) : _e(e) {}
39
};
40
41
/** Format wrapper for time stamps.
42
 * If the time isn't provided, the current epoch time is used. If the format string isn't
43
 * provided a format like "2017 Jun 29 14:11:29" is used.
44
 */
45
struct Date {
46
  /// Default format
47
  static constexpr std::string_view DEFAULT_FORMAT{"%Y %b %d %H:%M:%S"_sv};
48
  time_t _epoch;         ///< The time.
49
  std::string_view _fmt; ///< Data format.
50
51
  /** Constructor.
52
   *
53
   * @param t The timestamp.
54
   * @param fmt Timestamp format.
55
   */
56
0
  Date(time_t t, std::string_view fmt = DEFAULT_FORMAT) : _epoch(t), _fmt(fmt) {}
57
58
  /// Default construct using current time with optional format.
59
  Date(std::string_view fmt = DEFAULT_FORMAT);
60
};
61
62
namespace detail {
63
// Special case conversions - these handle nullptr because the @c std::string_view spec is stupid.
64
inline std::string_view
65
0
FirstOfConverter(std::nullptr_t) {
66
0
  return std::string_view{};
67
0
}
68
69
inline std::string_view
70
0
FirstOfConverter(char const *s) {
71
0
  return std::string_view{s ? s : ""};
72
0
}
73
74
// Otherwise do any compliant conversion.
75
template <typename T>
76
std::string_view
77
FirstOfConverter(T &&t) {
78
  return t;
79
}
80
} // namespace detail
81
82
/// Print the first of a list of strings that is not an empty string.
83
/// All arguments must be convertible to @c std::string_view.
84
template <typename... Args>
85
std::string_view
86
FirstOf(Args &&...args) {
87
  std::array<std::string_view, sizeof...(args)> strings{{detail::FirstOfConverter(args)...}};
88
  for (auto &s : strings) {
89
    if (!s.empty())
90
      return s;
91
  }
92
  return std::string_view{};
93
}
94
95
/** Wrapper for a sub-text, where the @a args are output according to @a fmt.
96
 *
97
 * @tparam Args Argument types.
98
 */
99
template <typename... Args> struct SubText {
100
  using arg_pack = std::tuple<Args...>; ///< The pack of arguments for format string.
101
  TextView _fmt;                        ///< Format string. If empty, do not generate output.
102
  arg_pack _args;                       ///< Arguments to format string.
103
104
  /// Construct with a specific @a fmt and @a args.
105
0
  SubText(TextView const &fmt, arg_pack const &args) : _fmt(fmt), _args(args){};
Unexecuted instantiation: swoc::_1_5_15::bwf::SubText<char const* const&>::SubText(swoc::_1_5_15::TextView const&, std::__1::tuple<char const* const&> const&)
Unexecuted instantiation: swoc::_1_5_15::bwf::SubText<swoc::_1_5_15::TextView&>::SubText(swoc::_1_5_15::TextView const&, std::__1::tuple<swoc::_1_5_15::TextView&> const&)
Unexecuted instantiation: swoc::_1_5_15::bwf::SubText<swoc::_1_5_15::Errata::Severity, swoc::_1_5_15::TextView&>::SubText(swoc::_1_5_15::TextView const&, std::__1::tuple<swoc::_1_5_15::Errata::Severity, swoc::_1_5_15::TextView&> const&)
106
107
  /// Check for output not enabled.
108
  bool operator!() const;
109
110
  /// Check for output enabled.
111
  explicit operator bool() const;
112
};
113
114
template <typename... Args> SubText<Args...>::operator bool() const {
115
  return !_fmt.empty();
116
}
117
118
template <typename... Args>
119
bool
120
SubText<Args...>::operator!() const {
121
  return _fmt.empty();
122
}
123
124
/** Optional printing wrapper.
125
 *
126
 * @tparam Args Arguments for output.
127
 * @param flag Generate output flag.
128
 * @param fmt Format for output and args.
129
 * @param args The arguments.
130
 * @return A wrapper for the optional text.
131
 *
132
 * This function is passed a @a flag, a printing format @a fmt, and a set of arguments @a args to
133
 * be used by the format. Output is generated if @a flag is @c true, otherwise the empty string
134
 * (no output) is generated. For example, if in a function there was a flag to determine if an
135
 * extra tag with delimiters, e.g. "[tag]", was to be generated, this could be done with
136
 *
137
 * @code
138
 *   w.print("Some other text{}.", bwf::If(flag, " [{}]", tag));
139
 * @endcode
140
 *
141
 * @internal To disambiguate overloads, this is enabled only if there is at least one argument
142
 * to be passed to the format string.
143
 */
144
template <typename... Args>
145
SubText<Args...>
146
0
If(bool flag, TextView const &fmt, Args &&...args) {
147
0
  return SubText<Args...>(flag ? fmt : TextView{}, std::forward_as_tuple(args...));
148
0
}
Unexecuted instantiation: swoc::_1_5_15::bwf::SubText<char const* const&> swoc::_1_5_15::bwf::If<char const* const&>(bool, swoc::_1_5_15::TextView const&, char const* const&)
Unexecuted instantiation: swoc::_1_5_15::bwf::SubText<swoc::_1_5_15::TextView&> swoc::_1_5_15::bwf::If<swoc::_1_5_15::TextView&>(bool, swoc::_1_5_15::TextView const&, swoc::_1_5_15::TextView&)
Unexecuted instantiation: swoc::_1_5_15::bwf::SubText<swoc::_1_5_15::Errata::Severity, swoc::_1_5_15::TextView&> swoc::_1_5_15::bwf::If<swoc::_1_5_15::Errata::Severity, swoc::_1_5_15::TextView&>(bool, swoc::_1_5_15::TextView const&, swoc::_1_5_15::Errata::Severity&&, swoc::_1_5_15::TextView&)
149
150
namespace detail {
151
// @a T has the @c empty() method.
152
template <typename T>
153
auto
154
Optional(meta::CaseTag<2>, TextView fmt, T &&t) -> decltype(void(t.empty()), meta::TypeFunc<SubText<T>>()) {
155
  return SubText<T>(t.empty() ? TextView{} : fmt, std::forward_as_tuple(t));
156
}
157
158
// @a T is convertible to @c bool.
159
template <typename T>
160
auto
161
Optional(meta::CaseTag<1>, TextView fmt, T &&t) -> decltype(bool(t), meta::TypeFunc<SubText<T>>()) {
162
  return SubText<T>(bool(t) ? fmt : TextView{}, std::forward_as_tuple(t));
163
}
164
165
// @a T is not optional, always print.
166
template <typename T>
167
auto
168
Optional(meta::CaseTag<0>, TextView fmt, T &&t) -> SubText<T> {
169
  return SubText<T>(fmt, std::forward_as_tuple(t));
170
}
171
} // namespace detail
172
173
/** Simplified optional text wrapper.
174
 *
175
 * @tparam ARG the type of the (single) argument.
176
 * @param fmt Format string.
177
 * @param arg The single argument to the format string and predicate.
178
 * @return An optional text wrapper.
179
 *
180
 * This generates output iff @a arg is not empty. @a fmt is required to take only a single
181
 * argument, which will be @a arg. This is a convenience overload, to handle the common case
182
 * where the argument and the conditional are the same. The argument must have one of the
183
 * following properties in order to serve as the conditional. These are checked in order.
184
 *
185
 * - The @c empty() method which returns @c true if the argument is empty and should not be printed.
186
 *   This handles the case of C++ string types.
187
 *
188
 * - Conversion to @c bool which is @c false if the argument should not be printed. This covers the
189
 *   case of pointers.
190
 *
191
 * As an example, if an output function had three strings @a alpha, @a bravo, and
192
 * @a charlie, each of which could be null, which should be output with space separators,
193
 * this would be
194
 * @code
195
 * w.print("Leading text{}{}{}.", Optional(" {}", alpha)
196
 *                              , Optional(" {}", bravo)
197
 *                              , Optional(" {}", charlie));
198
 * @endcode
199
 *
200
 * Because of the property handling, these strings can be C styles strings ( @c char* ) or C++
201
 * string types (such as @c std::string_view ).
202
 *
203
 */
204
template <typename ARG>
205
SubText<ARG>
206
Optional(TextView fmt, ARG &&arg) {
207
  return detail::Optional(meta::CaseArg, fmt, std::forward<ARG>(arg));
208
}
209
210
/** Convert from ASCII hexadecimal to raw bytes.
211
 *
212
 * E.g. if the source span contains "4576696c20446176652052756c7a" then "Evil Dave Rulz" is the output.
213
 * For format specifier support, on lhe max width is used. Any @c MemSpan compatible class can be used
214
 * as the target, including @c std::string and @c std::string_view.
215
 *
216
 * @code
217
 *   void f(std::string const& str) {
218
 *     w.print("{}", bwf::UnHex(str));
219
 *     // ...
220
 * @endcode
221
 */
222
struct UnHex {
223
0
  UnHex(MemSpan<void const> const &span) : _span(span) {}
224
  MemSpan<void const> _span; ///< Source span.
225
};
226
} // namespace bwf
227
228
/** Repeatedly output a pattern.
229
 *
230
 * @param w Output.
231
 * @param spec Format specifier.
232
 * @param pattern Output patterning.
233
 * @return @a w
234
 *
235
 * The @a pattern contains the count and text to output.
236
 */
237
BufferWriter &bwformat(BufferWriter &w, bwf::Spec const &spec, bwf::Pattern const &pattern);
238
239
/** Format an integer as an @c errno value.
240
 *
241
 * @param w Output.
242
 * @param spec Format specifier.
243
 * @param e Error code.
244
 * @return @a w
245
 */
246
BufferWriter &bwformat(BufferWriter &w, bwf::Spec const &spec, bwf::Errno const &e);
247
248
/** Format a timestamp wrapped in a @c Date.
249
 *
250
 * @param w Output.
251
 * @param spec Format specifier.
252
 * @param date Timestamp.
253
 * @return @a w
254
 */
255
BufferWriter &bwformat(BufferWriter &w, bwf::Spec const &spec, bwf::Date const &date);
256
257
BufferWriter &bwformat(BufferWriter &w, bwf::Spec const &spec, bwf::UnHex const &obj);
258
259
/** Output a nested formatted string.
260
 *
261
 * @tparam Args Argument pack for @a subtext.
262
 * @param w Output
263
 * @param subtext Format string and arguments.
264
 * @return @a w
265
 *
266
 * This supports a nested format string and arguments inside another format string. This is most often useful
267
 * if one of the formats is fixed or pre-compiled.
268
 *
269
 * @code
270
 * bwformat(w, "Line {} offset {} with data {}.", line_no, line_off, bwf::SubText("alpha {} bravo {}", alpha, bravo"));
271
 * @endcode
272
 *
273
 * @see bwf::Subtext
274
 */
275
template <typename... Args>
276
BufferWriter &
277
0
bwformat(BufferWriter &w, bwf::Spec const &, bwf::SubText<Args...> const &subtext) {
278
0
  if (!subtext._fmt.empty()) {
279
0
    w.print_v(subtext._fmt, subtext._args);
280
0
  }
281
0
  return w;
282
0
}
Unexecuted instantiation: swoc::_1_5_15::BufferWriter& swoc::_1_5_15::bwformat<char const* const&>(swoc::_1_5_15::BufferWriter&, swoc::_1_5_15::bwf::Spec const&, swoc::_1_5_15::bwf::SubText<char const* const&> const&)
Unexecuted instantiation: swoc::_1_5_15::BufferWriter& swoc::_1_5_15::bwformat<swoc::_1_5_15::TextView&>(swoc::_1_5_15::BufferWriter&, swoc::_1_5_15::bwf::Spec const&, swoc::_1_5_15::bwf::SubText<swoc::_1_5_15::TextView&> const&)
Unexecuted instantiation: swoc::_1_5_15::BufferWriter& swoc::_1_5_15::bwformat<swoc::_1_5_15::Errata::Severity, swoc::_1_5_15::TextView&>(swoc::_1_5_15::BufferWriter&, swoc::_1_5_15::bwf::Spec const&, swoc::_1_5_15::bwf::SubText<swoc::_1_5_15::Errata::Severity, swoc::_1_5_15::TextView&> const&)
283
284
}} // namespace swoc::SWOC_VERSION_NS