BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bdlt_formatter.h
Go to the documentation of this file.
1/// @file bdlt_formatter.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlt_formatter.h -*-C++-*-
8#ifndef INCLUDED_BDLT_FORMATTER
9#define INCLUDED_BDLT_FORMATTER
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlt_formatter bdlt_formatter
15/// @brief Provide a standard compliant `format` implementation.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlt
19/// @{
20/// @addtogroup bdlt_formatter
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlt_formatter-purpose"> Purpose</a>
25/// * <a href="#bdlt_formatter-classes"> Classes </a>
26/// * <a href="#bdlt_formatter-description"> Description </a>
27/// * <a href="#bdlt_formatter-usage"> Usage </a>
28///
29/// # Purpose {#bdlt_formatter-purpose}
30/// Provide a standard compliant `format` implementation.
31///
32/// # Classes {#bdlt_formatter-classes}
33///
34/// - bdlt::Formatter: `class` for parsing specs and formatting variables.
35///
36/// # Description {#bdlt_formatter-description}
37/// This component provides a class template, `Formatter` that is
38/// configured with a `tt_SPECIFIER_FORMATTER` template class. Each type that
39/// is to be formatted has its own specifier formatter class, and the specifier
40/// class does most of the work of formatting the output for the type. The
41/// `t_CHAR` template parameter is always to be `char` or `wchar_t`.
42///
43/// ## Usage {#bdlt_formatter-usage}
44///
45///
46/// @}
47/** @} */
48/** @} */
49
50/** @addtogroup bdl
51 * @{
52 */
53/** @addtogroup bdlt
54 * @{
55 */
56/** @addtogroup bdlt_formatter
57 * @{
58 */
59
60#include <bdlscm_version.h>
61
62#include <bdlt_formatutil.h>
64
65#include <bslfmt_format.h>
67#include <bslfmt_padutil.h>
68
69#include <bslmf_assert.h>
70#include <bslmf_issame.h>
71
72#include <bsls_assert.h>
73#include <bsls_exceptionutil.h>
74#include <bsls_keyword.h>
75
76
77namespace bdlt {
78
79 // =========
80 // Formatter
81 // =========
82
83template <template<typename> class tt_SPECIFIER_FORMATTER, class t_CHAR>
84class Formatter {
87
88 // PRIVATE TYPES
92 typedef bsl::ptrdiff_t ptrdiff_t;
93
94 private:
95 // DATA
96 mutable Spec d_spec;
97 // Specification parser. Mutable because we modify it in the `format`
98 // accessor.
99
100 Literal_SpecifierFormatter<t_CHAR> d_literalFormatter;
101 // Formatter for literal characters.
102
103 mutable tt_SPECIFIER_FORMATTER<t_CHAR> d_specifierFormatter;
104 // Custom formatter for the type being formatted.
105
106 int d_literalWidth;
107 // Number of characters in the parsed spec after the first '%' that are
108 // not in '%'-sequences. They will be written to output without
109 // modification.
110
111 bsl::size_t d_numModifiers;
112 // Number of modifiers at the start of the spec.
113
114 // PRIVATE ACCESSORS
115
116 /// Parse modifiers at the beginning of the specified `*spec`. Throw an
117 /// instance of `bsl::format_error` if an unrecognized modifier character
118 /// is encountered before either the first '%' or the end of `*spec`.
119 BSLS_KEYWORD_CONSTEXPR_CPP20 void parseModifiers(StringView *spec);
120
121 public:
122 // CREATORS
123
124 /// Default-construct an object.
126 Formatter();
127
128 // MANIPULATORS
129
130 /// Parse the input and arguments specified by `context` and return an
131 /// iterator pointing after the end of parsed input.
132 template <class t_PARSE_CONTEXT>
133 BSLS_KEYWORD_CONSTEXPR_CPP20 typename t_PARSE_CONTEXT::iterator parse(
134 t_PARSE_CONTEXT& context);
135
136 // ACCESSORS
137
138 /// Write the output to `formatContext.out()` and return the output
139 /// iterator after the output is done.
140 template <class t_FORMAT_CONTEXT, class t_VALUE>
141 typename t_FORMAT_CONTEXT::iterator format(
142 const t_VALUE& value,
143 t_FORMAT_CONTEXT& formatContext) const;
144};
145
146 // ---------
147 // Formatter
148 // ---------
149
150// PRIVATE ACCESSORS
151template <template<typename> class tt_SPECIFIER_FORMATTER, class t_CHAR>
154 parseModifiers(StringView *spec)
155{
156 while (!spec->empty() && t_CHAR('%') != spec->front()) {
157 if (!d_specifierFormatter.parseNextModifier(spec)) {
158 BSLS_THROW(bsl::format_error("Illegal modifier"));
159 }
160
161 ++d_numModifiers;
162 }
163}
164
165// CREATORS
166template <template<typename> class tt_SPECIFIER_FORMATTER, class t_CHAR>
169: d_spec()
170, d_literalFormatter()
171, d_specifierFormatter()
172, d_literalWidth(0)
173, d_numModifiers(0)
174{}
175
176// MANIPULATORS
177template <template<typename> class tt_SPECIFIER_FORMATTER, class t_CHAR>
178template <class t_PARSE_CONTEXT>
180typename t_PARSE_CONTEXT::iterator
182{
183 typedef typename Spec::Sections Sections;
184 const Sections sections = static_cast<Sections>(
185 Spec::e_SECTIONS_WIDTH | Spec::e_SECTIONS_FILL_ALIGN |
186 Spec::e_SECTIONS_REMAINING_SPEC |
187 d_specifierFormatter.extraSections());
188
189 d_spec.parse(&context, sections);
190
191 StringView spec = d_spec.remainingSpec();
192 parseModifiers(&spec);
193
194 if (spec.empty()) {
195 d_specifierFormatter.parseDefault();
196 }
197 else {
198 if (spec.front() != t_CHAR('%')) {
199 BSLS_THROW(bsl::format_error(
200 "Format string must start with a '%'"));
201 }
202
203 while (!spec.empty()) {
204 const t_CHAR c = spec.front();
205 spec.remove_prefix(1);
206
207 if (t_CHAR('%') == c) {
208 if (spec.empty()) {
209 BSLS_THROW(bsl::format_error("Incomplete '%' sequence"));
210 }
211
212 if (!d_specifierFormatter.parseNextSpecifier(&spec) &&
213 !d_literalFormatter. parseNextSpecifier(&spec)) {
214 BSLS_THROW(bsl::format_error(
215 "Unrecognized format specifier"));
216 }
217 }
218 else {
219 ++d_literalWidth;
220 }
221 }
222 }
223
224 return context.begin();
225}
226
227// ACCESSORS
228
229template <template<typename> class tt_SPECIFIER_FORMATTER, class t_CHAR>
230template <class t_FORMAT_CONTEXT, class t_VALUE>
231typename t_FORMAT_CONTEXT::iterator
233 const t_VALUE& value,
234 t_FORMAT_CONTEXT& formatContext) const
235{
237 typename t_FORMAT_CONTEXT::char_type>::value));
238
239 d_spec.postprocess(formatContext);
240 StringView spec = d_spec.remainingSpec().substr(d_numModifiers);
241
242 d_specifierFormatter.postprocess(d_spec);
243
244 const ptrdiff_t contentWidth = d_literalWidth +
245 d_literalFormatter.totalWidth() +
246 d_specifierFormatter.totalWidth(value);
247
248 ptrdiff_t leftPadding, rightPadding;
249 PadUtil::computePadding(&leftPadding,
250 &rightPadding,
251 d_spec.postprocessedWidth(),
252 contentWidth,
253 d_spec.alignment());
254 StringView filler(d_spec.filler(), d_spec.numFillerCharacters());
255
256 typename t_FORMAT_CONTEXT::iterator outIt = formatContext.out();
257
258 outIt = PadUtil::pad(outIt, leftPadding, filler);
259
260 if (spec.empty()) {
261 outIt = d_specifierFormatter.formatDefault(outIt, value);
262 }
263 else {
264 BSLS_ASSERT(t_CHAR('%') == spec.front());
265
266 while (!spec.empty()) {
267 const t_CHAR c = spec.front();
268 spec.remove_prefix(1);
269
270 if (c == t_CHAR('%')) {
271 BSLS_ASSERT(!spec.empty());
272
273 if (!d_specifierFormatter.formatNextSpecifier(
274 &spec, &outIt, value) &&
275 !d_literalFormatter.formatNextSpecifier(&spec, &outIt)) {
277 "unrecognized format specifier");
278 }
279 }
280 else {
281 *outIt++ = c;
282 }
283 }
284 }
285
286 outIt = PadUtil::pad(outIt, rightPadding, filler);
287
288 return outIt;
289}
290
291} // close namespace bdlt
292
293
294#endif
295
296// ----------------------------------------------------------------------------
297// Copyright 2025 Bloomberg Finance L.P.
298//
299// Licensed under the Apache License, Version 2.0 (the "License");
300// you may not use this file except in compliance with the License.
301// You may obtain a copy of the License at
302//
303// http://www.apache.org/licenses/LICENSE-2.0
304//
305// Unless required by applicable law or agreed to in writing, software
306// distributed under the License is distributed on an "AS IS" BASIS,
307// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
308// See the License for the specific language governing permissions and
309// limitations under the License.
310// ----------------------------- END-OF-FILE ----------------------------------
311
312/** @} */
313/** @} */
314/** @} */
Definition bdlt_formatter.h:84
BSLS_KEYWORD_CONSTEXPR_CPP20 Formatter()
Default-construct an object.
Definition bdlt_formatter.h:168
t_FORMAT_CONTEXT::iterator format(const t_VALUE &value, t_FORMAT_CONTEXT &formatContext) const
Definition bdlt_formatter.h:232
BSLS_KEYWORD_CONSTEXPR_CPP20 t_PARSE_CONTEXT::iterator parse(t_PARSE_CONTEXT &context)
Definition bdlt_formatter.h:181
Definition bdlt_literal_specifierformatter.h:87
Definition bslstl_stringview.h:471
BSLS_KEYWORD_CONSTEXPR_CPP14 basic_string_view substr(size_type position=0, size_type numChars=npos) const
Definition bslstl_stringview.h:2027
BSLS_KEYWORD_CONSTEXPR_CPP14 const_reference front() const
Definition bslstl_stringview.h:1966
BSLS_KEYWORD_CONSTEXPR_CPP14 void remove_prefix(size_type numChars)
Definition bslstl_stringview.h:1800
BSLS_KEYWORD_CONSTEXPR bool empty() const BSLS_KEYWORD_NOEXCEPT
Return true if this view has length 0, and false otherwise.
Definition bslstl_stringview.h:1931
Definition bslfmt_formatspecificationparser.h:151
#define BSLMF_ASSERT(expr)
Definition bslmf_assert.h:231
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1976
#define BSLS_ASSERT_INVOKE_NORETURN(X)
Definition bsls_assert.h:2101
#define BSLS_THROW(X)
Definition bsls_exceptionutil.h:374
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
#define BSLS_KEYWORD_CONSTEXPR_CPP20
Definition bsls_keyword.h:645
Definition bbldc_basicisma30360.h:112
Definition bslmf_issame.h:146
Sections
Definition bslfmt_formatspecificationparser.h:128
Definition bslfmt_padutil.h:151