BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bslfmt_formatterintegralbase.h
Go to the documentation of this file.
1/// @file bslfmt_formatterintegralbase.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslfmt_formatterintegralbase.h -*-C++-*-
8
9#ifndef INCLUDED_BSLFMT_FORMATTERINTEGRALBASE
10#define INCLUDED_BSLFMT_FORMATTERINTEGRALBASE
11
12#include <bsls_ident.h>
13BSLS_IDENT("$Id: $")
14
15/// @defgroup bslfmt_formatterintegralbase bslfmt_formatterintegralbase
16/// @brief Provide a formatter customization for integer types
17/// @addtogroup bsl
18/// @{
19/// @addtogroup bslfmt
20/// @{
21/// @addtogroup bslfmt_formatterintegralbase
22/// @{
23///
24/// <h1> Outline </h1>
25/// * <a href="#bslfmt_formatterintegralbase-purpose"> Purpose</a>
26/// * <a href="#bslfmt_formatterintegralbase-classes"> Classes </a>
27/// * <a href="#bslfmt_formatterintegralbase-canonical-header"> Canonical Header </a>
28/// * <a href="#bslfmt_formatterintegralbase-description"> Description </a>
29///
30/// # Purpose {#bslfmt_formatterintegralbase-purpose}
31/// Provide a formatter customization for integer types
32///
33/// # Classes {#bslfmt_formatterintegralbase-classes}
34///
35/// - bslfmt::FormatterIntegralBase: base for integral formatter specializations
36///
37/// # Canonical Header {#bslfmt_formatterintegralbase-canonical-header}
38/// bsl_format.h
39///
40/// # Description {#bslfmt_formatterintegralbase-description}
41/// This component provides partial specializations of
42/// `bsl::formatter` catering for integer types.
43///
44/// This header is not intended to be included directly. Please include
45/// `<bsl_format.h>` to be able to use specializations of the `bsl::formatter`
46/// for integral types.
47///
48/// @}
49/** @} */
50/** @} */
51
52/** @addtogroup bsl
53 * @{
54 */
55/** @addtogroup bslfmt
56 * @{
57 */
58/** @addtogroup bslfmt_formatterintegralbase
59 * @{
60 */
61
62#include <bslscm_version.h>
63
64#include <bslfmt_formaterror.h>
67#include <bslfmt_padutil.h>
69
71
72#include <bsls_assert.h>
73#include <bsls_exceptionutil.h>
74#include <bsls_keyword.h>
75
76#include <limits.h> // for `std::numeric_limits`
77
78
79namespace bslfmt {
80
81 // =================================
82 // struct FormatterIntegral_Category
83 // =================================
84
85/// This struct provides a function that returns a category of the formatter in
86/// accordance with the (template parameter) `t_VALUE_TYPE`.
87///
88/// See @ref bslfmt_formatterintegralbase
89template <class t_VALUE_TYPE>
91 // CLASS METHODS
92 template <class t_CHAR>
95 category();
96};
97
98/// This is a specialization of `FormatterIntegral_Category` template for
99/// `bool`.
100template <>
102 // CLASS METHODS
103 template <class t_CHAR>
106};
107
108/// This is a specialization of `FormatterIntegral_Category` template for
109/// `void *`.
110template <>
112 // CLASS METHODS
113 template <class t_CHAR>
116};
117
118/// This is a specialization of `FormatterIntegral_Category` template for
119/// `const void *`.
120template <>
121struct FormatterIntegral_Category<const void *> {
122 // CLASS METHODS
123 template <class t_CHAR>
126};
127
128/// This is a specialization of `FormatterIntegral_Category` template for
129/// `bsl::nullptr_t`.
130template <>
131struct FormatterIntegral_Category<bsl::nullptr_t> {
132 // CLASS METHODS
133 template <class t_CHAR>
136};
137
138/// This is a specialization of `FormatterIntegral_Category` template for
139/// `char`.
140template <>
142 // CLASS METHODS
143 template <class t_CHAR>
146};
147
148/// This is a specialization of `FormatterIntegral_Category` template for
149/// `wchar_t`.
150template <>
152 // CLASS METHODS
153 template <class t_CHAR>
156};
157
158 // ============================
159 // struct FormatterIntegralBase
160 // ============================
161
162/// This struct is a base class for `bsl::formatter` specializations for
163/// integer types as well as for other types that can be represented as integer
164/// (i.e. `bool`, character and pointer types). This is a private class and
165/// should not be used directly. The formatting of variables of a certain type
166/// is performed using the corresponding classes inherited from this one.
167/// Accordingly, the auxiliary functions used are declared protected.
168///
169/// See @ref bslfmt_formatterintegralbase
170template <class t_VALUE, class t_CHAR>
172 private:
173 // PRIVATE TYPES
174
175 /// A type alias for the `StandardFormatSpecification<t_CHAR>`.
176 typedef StandardFormatSpecification<t_CHAR> Specification;
177
178 // DATA
179 Specification d_spec; // format specification.
180
181 // PRIVATE ACCESSORS
182
183 /// Return `true` if the specified `value` is in the range of representable
184 /// values for the (template parameter) `t_CHAR`, and `false` otherwise.
185 template <class t_ACTUAL_VALUE_TYPE>
186 bool isInRange(const t_ACTUAL_VALUE_TYPE& value) const;
187
188 public:
189 // MANIPULATORS
190
191 /// Parse the specified `parseContext` and return an iterator, pointing to
192 /// the beginning of the format string.
193 template <class t_PARSE_CONTEXT>
194 BSLS_KEYWORD_CONSTEXPR_CPP20 typename t_PARSE_CONTEXT::iterator parse(
195 t_PARSE_CONTEXT& parseContext);
196
197 // ACCESSORS
198
199 /// Create the prefix for output of the specified `value` and write it into
200 /// the character buffer starting a the specified `prefixStorage` and
201 /// having the specified `storageSize`. Return the address one past the
202 /// last character. Throw `bsl::format_error` if parsed format
203 /// specification is intended for non-integer type.
204 template <class t_ACTUAL_VALUE_TYPE>
205 char *formatPrefix(char *prefixStorage,
206 int storageSize,
207 t_ACTUAL_VALUE_TYPE value) const;
208
209 /// Create the string representation of the specified `value` and write it
210 /// into the character buffer starting at the specified `valueStorage` and
211 /// having the specified `storageSize`. Return the address one past the
212 /// last character. Throw `bsl::format_error` if parsed format
213 /// specification is intended for non-integer type or the `value` is not in
214 /// the range of representable values for the (template parameter) `t_CHAR`
215 /// with character type specification.
216 template <class t_ACTUAL_VALUE_TYPE>
217 t_CHAR *formatValue(t_CHAR *valueStorage,
218 int storageSize,
219 t_ACTUAL_VALUE_TYPE value) const;
220
221 /// Copy the prefix of value string representation starting at the
222 /// specified `prefixBegin` and ending at the specified `prefixEnd` as well
223 /// as representation itself starting at the specified `valueBegin` and
224 /// ending at the specified `valueEnd` to the output that the output
225 /// iterator of the `formatContext` points to. Throw `bsl::format_error`
226 /// if parsed format specification states incorrect alignment type.
227 template <class t_FORMAT_CONTEXT>
228 typename t_FORMAT_CONTEXT::iterator outputValue(
229 const char *prefixBegin,
230 const char *prefixEnd,
231 const t_CHAR *valueBegin,
232 const t_CHAR *valueEnd,
233 t_FORMAT_CONTEXT& formatContext) const;
234
235 /// Return a reference to the specification of this formatter.
237};
238
239// ============================================================================
240// INLINE DEFINITIONS
241// ============================================================================
242
243 // ---------------------------------
244 // struct FormatterIntegral_Category
245 // ---------------------------------
246
247template <class t_VALUE_TYPE>
248template <class t_CHAR>
249inline
256
257template <class t_CHAR>
258inline
265
266template <class t_CHAR>
267inline
274
275template <class t_CHAR>
276inline
280{
282}
283
284template <class t_CHAR>
285inline
292
293template <class t_CHAR>
294inline
301
302template <class t_CHAR>
303inline
310
311 // ---------------------------
312 // class FormatterIntegralBase
313 // ---------------------------
314
315template <class t_VALUE, class t_CHAR>
316template <class t_ACTUAL_VALUE_TYPE>
317inline
319 const t_ACTUAL_VALUE_TYPE& value) const
320{
321 const long double min =
322 static_cast<long double>(std::numeric_limits<t_CHAR>::min());
323 const long double max =
324 static_cast<long double>(std::numeric_limits<t_CHAR>::max());
325 const long double doubleValue = static_cast<long double>(value);
326
327 return min <= doubleValue && max >= doubleValue;
328}
329
330template <class t_VALUE, class t_CHAR>
331template <class t_PARSE_CONTEXT>
332inline
333BSLS_KEYWORD_CONSTEXPR_CPP20 typename t_PARSE_CONTEXT::iterator
335{
336 d_spec.parse(&parseContext,
338
339 if (d_spec.localeSpecificFlag()) {
341 bsl::format_error("Formatting L specifier not supported"));
342 }
343
344 if (d_spec.formatType() == Specification::e_CHARACTER_ESCAPED)
345 BSLS_THROW(bsl::format_error("Character escaping not supported"));
346
347 return parseContext.begin();
348}
349
350template <class t_VALUE, class t_CHAR>
351template <class t_ACTUAL_VALUE_TYPE>
352inline
354 char *prefixStorage,
355 int storageSize,
356 t_ACTUAL_VALUE_TYPE value) const
357{
358 BSLS_ASSERT(prefixStorage);
359 BSLS_ASSERT(4 <= storageSize);
360
361 (void) storageSize; // suppress compiler warning
362
363 char *prefixEnd = prefixStorage;
364
365 // Adding sign.
366
367 if (value >= 0) {
368 switch (d_spec.sign()) {
369 case Specification::e_SIGN_POSITIVE: {
370 *prefixEnd = '+';
371 ++prefixEnd;
372 } break;
373 case Specification::e_SIGN_SPACE: {
374 *prefixEnd = ' ';
375 ++prefixEnd;
376 } break;
377 default: {
378 // Suppress compiler warning.
379 // Specification::e_SIGN_DEFAULT
380 // Specification::e_SIGN_NEGATIVE
381 }
382 }
383 }
384 else {
385 // As we might have an alternate form that requires special prefix, we
386 // add the minus sign ourselves without relying on
387 // `NumericFormatterUtil::toChars` negative value conversion.
388
389 *prefixEnd = '-';
390 ++prefixEnd;
391 }
392
393 // Adding alternate form prefix.
394
395 {
396 const char *formatPrefix = 0;
397 int formatPrefixLength = 0;
398 switch (d_spec.formatType()) {
399 case Specification::e_INTEGRAL_BINARY: { // `b`
400 if (d_spec.alternativeFlag()) {
401 formatPrefix = "0b";
402 formatPrefixLength = 2;
403 }
404 } break;
405 case Specification::e_INTEGRAL_BINARY_UC: { // `B`
406 if (d_spec.alternativeFlag()) {
407 formatPrefix = "0B";
408 formatPrefixLength = 2;
409 }
410 } break;
411 case Specification::e_INTEGRAL_DECIMAL:
412 case Specification::e_INTEGRAL_CHARACTER: { // none or `d`
413 // No prefix.
414 } break;
415 case Specification::e_INTEGRAL_OCTAL: { // `o`
416 if (d_spec.alternativeFlag() && 0 != value) {
417 formatPrefix = "0";
418 formatPrefixLength = 1;
419 }
420 } break;
421 case Specification::e_INTEGRAL_HEX: { // `x`
422 if (d_spec.alternativeFlag()) {
423 formatPrefix = "0x";
424 formatPrefixLength = 2;
425 }
426 } break;
427 case Specification::e_INTEGRAL_HEX_UC: { // `X`
428 if (d_spec.alternativeFlag()) {
429 formatPrefix = "0X";
430 formatPrefixLength = 2;
431 }
432 } break;
433 default: {
434 BSLS_THROW(bsl::format_error("Invalid integer format type"));
435 }
436 }
437 if (formatPrefix) {
438 prefixEnd = bsl::copy(formatPrefix,
439 formatPrefix + formatPrefixLength,
440 prefixEnd);
441 }
442
443 return prefixEnd;
444 }
445}
446
447template <class t_VALUE, class t_CHAR>
448template <class t_ACTUAL_VALUE_TYPE>
449inline
451 t_CHAR *valueStorage,
452 int storageSize,
453 t_ACTUAL_VALUE_TYPE value) const
454{
455 BSLS_ASSERT(valueStorage);
456
457 typedef BloombergLP::bslalg::NumericFormatterUtil NFUtil;
458
459 (void) storageSize; // suppress compiler warning
460
461 int valueBase = 10;
462 switch (d_spec.formatType()) {
463 case Specification::e_INTEGRAL_BINARY: {
464 valueBase = 2;
465 } break;
466 case Specification::e_INTEGRAL_BINARY_UC: {
467 valueBase = 2;
468 } break;
469 case Specification::e_INTEGRAL_CHARACTER: {
470 if (isInRange(value)) {
471 *valueStorage = static_cast<t_CHAR>(value);
472 return valueStorage + 1; // RETURN
473 }
474 else {
475 BSLS_THROW(bsl::format_error("Integer value is not in the range "
476 "of character representation"));
477 }
478 } break;
479 case Specification::e_INTEGRAL_DECIMAL: {
480 // Default value (10).
481 } break;
482 case Specification::e_INTEGRAL_OCTAL: {
483 valueBase = 8;
484 } break;
485 case Specification::e_INTEGRAL_HEX: {
486 valueBase = 16;
487 } break;
488 case Specification::e_INTEGRAL_HEX_UC: {
489 valueBase = 16;
490 } break;
491 case Specification::e_POINTER_HEX: {
492 valueBase = 16;
493 } break;
494 case Specification::e_POINTER_HEX_UC: {
495 valueBase = 16;
496 } break;
497 default: {
498 BSLS_THROW(bsl::format_error("Invalid integer format type"));
499 }
500 }
501
502 // We want to make sure that we have enough space to accommodate any
503 // representation of the `value`. Binary representation takes up the most
504 // space. Unfortunately we can not use `valueBase` value her, because
505 // constant expression is required.
506
507 const int maxValueSize =
508 NFUtil::ToCharsMaxLength<t_ACTUAL_VALUE_TYPE, 2>::k_VALUE;
509 BSLS_ASSERT(maxValueSize <= storageSize);
510
511 char valueBuf[maxValueSize];
512 char *valueEnd = NFUtil::toChars(valueBuf,
513 valueBuf + maxValueSize,
514 value,
515 valueBase);
516
517 if (Specification::e_INTEGRAL_HEX_UC == d_spec.formatType() ||
518 Specification::e_POINTER_HEX_UC == d_spec.formatType()) {
519 // Unfortunately, `NumericFormatterUtil::toChars` uses only lowercase
520 // characters to represent hexadecimal numbers. So we have to
521 // additionally modify the resulting string for uppercase hexadecimal
522 // format.
523
524 BloombergLP::bslfmt::FormatterCharUtil<char>::toUpper(valueBuf,
525 valueEnd);
526 }
527
528 t_CHAR *convertedValueEnd = valueStorage;
529
530 convertedValueEnd =
531 BloombergLP::bslfmt::FormatterCharUtil<t_CHAR>::outputFromChar(
532 valueBuf,
533 valueEnd,
534 convertedValueEnd);
535
536 return convertedValueEnd;
537}
538
539template <class t_VALUE, class t_CHAR>
540template <class t_FORMAT_CONTEXT>
541inline
542typename t_FORMAT_CONTEXT::iterator
544 const char *prefixBegin,
545 const char *prefixEnd,
546 const t_CHAR *valueBegin,
547 const t_CHAR *valueEnd,
548 t_FORMAT_CONTEXT& formatContext) const
549{
550 typedef FormatterSpecificationNumericValue NumericValue;
551 typedef bsl::basic_string_view<t_CHAR> StringView;
552 typedef PadUtil<t_CHAR> PadUtil;
553
554 const Specification& parsedSpec = this->specification();
555 Specification spec(parsedSpec);
556 spec.postprocess(formatContext);
557
558 NumericValue finalWidth(spec.postprocessedWidth());
559
560 bool representAsChar = Specification::e_INTEGRAL_CHARACTER ==
561 d_spec.formatType();
562
563
564 std::ptrdiff_t leftPadFillerCopiesNum = 0;
565 std::ptrdiff_t rightPadFillerCopiesNum = 0;
566 std::ptrdiff_t zeroPadFillerCopiesNum = 0;
567
568 std::ptrdiff_t commonLength = representAsChar
569 ? 1 + (prefixEnd - prefixBegin)
570 : (valueEnd - valueBegin) +
571 (prefixEnd - prefixBegin);
572
573 // Filling the remaining space.
574 if (finalWidth.category() != NumericValue::e_DEFAULT &&
575 commonLength < finalWidth.value()) {
576 // We need to fill the remaining space.
577
579 typedef typename Spec::FormatType FormatType;
580
581 typename Spec::Alignment alignment = spec.alignment();
582
583 if (Spec::e_ALIGN_DEFAULT == alignment && spec.zeroPaddingFlag()) {
584 // Space will be filled with zeros.
585
586 zeroPadFillerCopiesNum = finalWidth.value() - commonLength;
587 }
588 else {
589 // Alignment with appropriate symbol is required.
590
591 const FormatType fType = d_spec.formatType();
592
593 PadUtil::computePadding(&leftPadFillerCopiesNum,
594 &rightPadFillerCopiesNum,
595 finalWidth,
596 commonLength,
597 alignment,
598 (Spec::e_INTEGRAL_CHARACTER == fType ||
599 Spec::e_CHARACTER_CHARACTER == fType ||
600 Spec::e_BOOLEAN_STRING == fType)
601 ? Spec::e_ALIGN_LEFT
602 : Spec::e_ALIGN_RIGHT);
603 }
604 }
605
606 // Assembling the final string.
607
608 typename t_FORMAT_CONTEXT::iterator outIterator = formatContext.out();
609
610 // left padding
611
612 const StringView pad(spec.filler(), spec.numFillerCharacters());
613 outIterator = PadUtil::pad(outIterator, leftPadFillerCopiesNum, pad);
614
615 // prefix
616
617 outIterator = FormatterCharUtil<t_CHAR>::outputFromChar(prefixBegin,
618 prefixEnd,
619 outIterator);
620
621 // zero filler
622
623 outIterator = PadUtil::pad(outIterator, zeroPadFillerCopiesNum, '0');
624
625 // value
626
627 outIterator = bsl::copy(valueBegin, valueEnd, outIterator);
628
629 // right padding
630
631 outIterator = PadUtil::pad(outIterator, rightPadFillerCopiesNum, pad);
632
633 return outIterator;
634}
635
636template <class t_VALUE, class t_CHAR>
637inline
640{
641 return d_spec;
642}
643
644
645} // close package namespace
646
647
648#endif // INCLUDED_BSLFMT_FORMATTERINTEGRALBASE
649
650// ----------------------------------------------------------------------------
651// Copyright 2025 Bloomberg Finance L.P.
652//
653// Licensed under the Apache License, Version 2.0 (the "License");
654// you may not use this file except in compliance with the License.
655// You may obtain a copy of the License at
656//
657// http://www.apache.org/licenses/LICENSE-2.0
658//
659// Unless required by applicable law or agreed to in writing, software
660// distributed under the License is distributed on an "AS IS" BASIS,
661// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
662// See the License for the specific language governing permissions and
663// limitations under the License.
664// ----------------------------- END-OF-FILE ----------------------------------
665
666/** @} */
667/** @} */
668/** @} */
Definition bslstl_stringview.h:471
Definition bslfmt_standardformatspecification.h:78
Category
Definition bslfmt_standardformatspecification.h:82
BSLS_KEYWORD_CONSTEXPR_CPP20 Alignment alignment() const
Definition bslfmt_standardformatspecification.h:691
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1976
#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 bdlat_valuetypefunctions.h:939
Definition bslfmt_enablestreamedformatter.h:130
Definition bslfmt_formattercharutil.h:138
Definition bslfmt_formatterintegralbase.h:171
BSLS_KEYWORD_CONSTEXPR_CPP20 t_PARSE_CONTEXT::iterator parse(t_PARSE_CONTEXT &parseContext)
Definition bslfmt_formatterintegralbase.h:334
t_CHAR * formatValue(t_CHAR *valueStorage, int storageSize, t_ACTUAL_VALUE_TYPE value) const
Definition bslfmt_formatterintegralbase.h:450
t_FORMAT_CONTEXT::iterator outputValue(const char *prefixBegin, const char *prefixEnd, const t_CHAR *valueBegin, const t_CHAR *valueEnd, t_FORMAT_CONTEXT &formatContext) const
Definition bslfmt_formatterintegralbase.h:543
char * formatPrefix(char *prefixStorage, int storageSize, t_ACTUAL_VALUE_TYPE value) const
Definition bslfmt_formatterintegralbase.h:353
const StandardFormatSpecification< t_CHAR > & specification() const
Return a reference to the specification of this formatter.
Definition bslfmt_formatterintegralbase.h:639
static BSLS_KEYWORD_CONSTEXPR_CPP20 StandardFormatSpecification< t_CHAR >::Category category()
Definition bslfmt_formatterintegralbase.h:90
static BSLS_KEYWORD_CONSTEXPR_CPP20 StandardFormatSpecification< t_CHAR >::Category category()
Definition bslfmt_formatterintegralbase.h:252
Definition bslfmt_formatterspecificationnumericvalue.h:100
Definition bslfmt_padutil.h:151
static void computePadding(std::ptrdiff_t *leftPadding, std::ptrdiff_t *rightPadding, const NumericValue &widthValue, std::ptrdiff_t contentWidth, Alignment alignment, Alignment defaultAlign=Enums::e_ALIGN_LEFT)
Definition bslfmt_padutil.h:352
static t_ITERATOR pad(t_ITERATOR out, std::ptrdiff_t padWidth, const bsl::string_view &filler)
Definition bslfmt_padutil.h:401