9#ifndef INCLUDED_BSLFMT_FORMATTERFLOATING
10#define INCLUDED_BSLFMT_FORMATTERFLOATING
116#include <bslscm_version.h>
150template <
class t_VALUE,
class t_CHAR>
163 static const size_t k_NO_POS = (size_t)(-1);
175 static size_t applyDefaultAlternate(
char* buf,
size_t numberLength);
184 static size_t applyFixedAlternate(
char *buf,
size_t numberLength);
195 size_t applyGeneralAlternate(
char *buf,
212 size_t applyScientificAlternate(
char expChar,
214 size_t numberLength);
222 template <
class t_FORMAT_CONTEXT>
223 typename t_FORMAT_CONTEXT::iterator alignAndCopy(
224 const char *numberBuffer,
226 t_FORMAT_CONTEXT& formatContext,
235 template <
class t_FORMAT_CONTEXT>
236 typename t_FORMAT_CONTEXT::iterator formatFixedImpl(
238 t_FORMAT_CONTEXT& formatContext,
249 template <
class t_FORMAT_CONTEXT>
250 typename t_FORMAT_CONTEXT::iterator formatDefaultImpl(
252 t_FORMAT_CONTEXT& formatContext,
261 template <
class t_FORMAT_CONTEXT>
262 typename t_FORMAT_CONTEXT::iterator formatGeneralImpl(
264 t_FORMAT_CONTEXT& formatContext,
275 template <
class t_FORMAT_CONTEXT>
276 typename t_FORMAT_CONTEXT::iterator formatHexImpl(
278 t_FORMAT_CONTEXT& formatContext,
289 template <
class t_FORMAT_CONTEXT>
290 typename t_FORMAT_CONTEXT::iterator formatHexPrecImpl(
292 t_FORMAT_CONTEXT& formatContext,
301 template <
class t_FORMAT_CONTEXT>
302 typename t_FORMAT_CONTEXT::iterator formatScientificImpl(
304 t_FORMAT_CONTEXT& formatContext,
316 template <
class t_FORMAT_CONTEXT>
317 typename t_FORMAT_CONTEXT::iterator
format(
319 t_FORMAT_CONTEXT& formatContext)
const;
327 template <
class t_PARSE_CONTEXT>
329 parse(t_PARSE_CONTEXT& parseContext);
341template <
class t_VALUE,
class t_CHAR>
351 const char lastChar = buf[numberLength - 1];
352 if (
'f' == lastChar ||
'n' == lastChar) {
358 size_t dotPos = k_NO_POS;
359 for (
size_t i = 0; i < numberLength; ++i) {
366 if (dotPos == k_NO_POS) {
370 size_t ePos = k_NO_POS;
371 for (
size_t i = 0; i < numberLength; ++i) {
378 if (k_NO_POS == ePos) {
379 buf[numberLength] =
'.';
383 memmove(buf + ePos + 1, buf + ePos, numberLength - ePos);
392template <
class t_VALUE,
class t_CHAR>
394FormatterFloating_Base<t_VALUE, t_CHAR>::applyFixedAlternate(
400 for (
size_t i = 0; i < numberLength; ++i) {
408 buf[numberLength] =
'.';
410 return ++numberLength;
413template <
class t_VALUE,
class t_CHAR>
415FormatterFloating_Base<t_VALUE, t_CHAR>::applyGeneralAlternate(
427 const char lastChar = buf[numberLength - 1];
428 if (
'f' == lastChar ||
'n' == lastChar) {
434 size_t dotPos = k_NO_POS;
435 for (
size_t i = 0; i < numberLength; ++i) {
441 size_t ePos = k_NO_POS;
442 for (
size_t i = 0; i < numberLength; ++i) {
449 if (dotPos == k_NO_POS) {
453 if (k_NO_POS == ePos) {
454 buf[numberLength] =
'.';
458 memmove(buf + ePos + 1, buf + ePos, numberLength - ePos);
466 const ptrdiff_t digits = (k_NO_POS == ePos)
469 if (precision > digits) {
470 const size_t numZeros = precision - digits;
473 if (k_NO_POS == ePos) {
475 memset(buf + numberLength,
'0', numZeros);
479 memmove(buf + ePos + numZeros,
481 numberLength - ePos);
482 memset(buf + ePos,
'0', numZeros);
485 numberLength += numZeros;
491template <
class t_VALUE,
class t_CHAR>
493FormatterFloating_Base<t_VALUE, t_CHAR>::applyScientificAlternate(
499 const char lastChar = buf[numberLength - 1];
500 if (
'f' == lastChar ||
'n' == lastChar) {
506 for (
size_t i = 0; i < numberLength; ++i) {
515 size_t expPos = k_NO_POS;
516 for (
size_t i = 0; i < numberLength; ++i) {
517 if (expChar == buf[i]) {
523 if (k_NO_POS == expPos) {
525 BSLS_THROW(bsl::format_error(
"Internal error, exponent not found"));
529 memmove(buf + expPos + 1, buf + expPos, numberLength - expPos);
532 return ++numberLength;
537template <
class t_VALUE,
class t_CHAR>
538template <
class t_FORMAT_CONTEXT>
539typename t_FORMAT_CONTEXT::iterator
540FormatterFloating_Base<t_VALUE, t_CHAR>::alignAndCopy(
541 const char *numberBuffer,
543 t_FORMAT_CONTEXT& formatContext,
544 const Specification& finalSpec)
const
546 typedef FormatterSpecificationNumericValue NumericValue;
548 typedef PadUtil<t_CHAR> PadUtil;
550 NumericValue finalWidth(finalSpec.postprocessedWidth());
552 std::ptrdiff_t leftPadFillerCopiesNum = 0;
553 std::ptrdiff_t rightPadFillerCopiesNum = 0;
554 std::ptrdiff_t zeroPadFillerCopiesNum = 0;
556 const char addSignChar = *numberBuffer ==
'-'
558 : Specification::e_SIGN_POSITIVE == finalSpec.sign()
560 : Specification::e_SIGN_SPACE == finalSpec.sign()
563 const bool hasSignChar = (addSignChar != 0);
565 if (
'-' == addSignChar) {
573 const char lastChar = numberBuffer[numberLength - 1];
574 const bool specialValue =
'f' == lastChar ||
'n' == lastChar;
576 if (finalWidth.category() != NumericValue::e_DEFAULT &&
577 numberLength + hasSignChar < static_cast<size_t>(finalWidth.value())) {
581 Specification::e_ALIGN_DEFAULT == finalSpec.alignment() &&
582 finalSpec.zeroPaddingFlag()) {
585 zeroPadFillerCopiesNum = finalWidth.value() -
586 (numberLength + hasSignChar);
592 &rightPadFillerCopiesNum,
594 numberLength + hasSignChar,
596 Specification::e_ALIGN_RIGHT);
602 typename t_FORMAT_CONTEXT::iterator outIterator = formatContext.out();
604 const StringView pad(finalSpec.filler(), finalSpec.numFillerCharacters());
605 outIterator =
PadUtil::pad(outIterator, leftPadFillerCopiesNum, pad);
608 outIterator = FormatterCharUtil<t_CHAR>::outputFromChar(
609 addSignChar, outIterator);
612 outIterator =
PadUtil::pad(outIterator, zeroPadFillerCopiesNum,
'0');
614 outIterator = FormatterCharUtil<t_CHAR>::outputFromChar(
616 numberBuffer + numberLength,
619 outIterator =
PadUtil::pad(outIterator, rightPadFillerCopiesNum, pad);
624template <
class t_VALUE,
class t_CHAR>
625template <
class t_FORMAT_CONTEXT>
626typename t_FORMAT_CONTEXT::iterator
627FormatterFloating_Base<t_VALUE, t_CHAR>::formatFixedImpl(
629 t_FORMAT_CONTEXT& formatContext,
630 const Specification& finalSpec)
const
632 typedef BloombergLP::bslalg::NumericFormatterUtil NFUtil;
635 BSLS_ASSERT(Specification::e_FLOATING_FIXED == finalSpec.formatType() ||
636 Specification::e_FLOATING_FIXED_UC == finalSpec.formatType());
639 typedef FormatterSpecificationNumericValue NumericValue;
640 const NumericValue& specPrec = finalSpec.postprocessedPrecision();
641 const int precision = (NumericValue::e_DEFAULT == specPrec.category())
646 const size_t k_STACK_BUF_LEN =
647 NFUtil::ToCharsMaxLength<t_VALUE, NFUtil::e_FIXED>::k_VALUE + 11;
648 char sbuf[k_STACK_BUF_LEN];
651 size_t bufLen = k_STACK_BUF_LEN;
654 const size_t reqdBufLen =
655 NFUtil::PrecisionMaxBufferLength<t_VALUE>::value(NFUtil::e_FIXED,
658 if (reqdBufLen > k_STACK_BUF_LEN) {
659 dbuf = allocator.
allocate(reqdBufLen);
666 dbuf ? reqdBufLen : 0);
667 char *
end = NFUtil::toChars(buf,
673 size_t numberLength =
static_cast<size_t>(
end - buf);
675 if (finalSpec.alternativeFlag()) {
676 numberLength = applyFixedAlternate(buf, numberLength);
679 return alignAndCopy(buf, numberLength, formatContext, finalSpec);
682template <
class t_VALUE,
class t_CHAR>
683template <
class t_FORMAT_CONTEXT>
684typename t_FORMAT_CONTEXT::iterator
685FormatterFloating_Base<t_VALUE, t_CHAR>::formatDefaultImpl(
687 t_FORMAT_CONTEXT& formatContext,
688 const Specification& finalSpec)
const
690 typedef BloombergLP::bslalg::NumericFormatterUtil NFUtil;
693 BSLS_ASSERT(Specification::e_FLOATING_DEFAULT == finalSpec.formatType());
696 BSLS_ASSERT(finalSpec.postprocessedPrecision().category() ==
700 char buf[NFUtil::ToCharsMaxLength<t_VALUE>::k_VALUE];
701 char *
end = NFUtil::toChars(buf,
705 size_t numberLength =
static_cast<size_t>(
end - buf);
707 if (finalSpec.alternativeFlag()) {
708 numberLength = applyDefaultAlternate(buf, numberLength);
711 return alignAndCopy(buf, numberLength, formatContext, finalSpec);
714template <
class t_VALUE,
class t_CHAR>
715template <
class t_FORMAT_CONTEXT>
716typename t_FORMAT_CONTEXT::iterator
717FormatterFloating_Base<t_VALUE, t_CHAR>::formatGeneralImpl(
719 t_FORMAT_CONTEXT& formatContext,
720 const Specification& finalSpec)
const
722 typedef BloombergLP::bslalg::NumericFormatterUtil NFUtil;
726 Specification::e_FLOATING_GENERAL == finalSpec.formatType() ||
727 Specification::e_FLOATING_GENERAL_UC == finalSpec.formatType() ||
728 Specification::e_FLOATING_DEFAULT == finalSpec.formatType());
731 typedef FormatterSpecificationNumericValue FSNVAlue;
732 const FSNVAlue& specPrec = finalSpec.postprocessedPrecision();
733 const int precision = (FSNVAlue::e_DEFAULT == specPrec.category())
738 const size_t k_STACK_BUF_LEN =
739 NFUtil::ToCharsMaxLength<t_VALUE, NFUtil::e_GENERAL>::k_VALUE + 11;
740 char sbuf[k_STACK_BUF_LEN];
743 size_t bufLen = k_STACK_BUF_LEN;
746 const size_t reqdBufLen =
747 NFUtil::PrecisionMaxBufferLength<t_VALUE>::value(NFUtil::e_GENERAL,
750 if (reqdBufLen > k_STACK_BUF_LEN) {
751 dbuf = allocator.
allocate(reqdBufLen);
758 dbuf ? reqdBufLen : 0);
759 char *
end = NFUtil::toChars(buf,
765 size_t numberLength =
static_cast<size_t>(
end - buf);
767 if (finalSpec.alternativeFlag()) {
768 numberLength = applyGeneralAlternate(buf, numberLength, precision);
771 if (Specification::e_FLOATING_GENERAL_UC == finalSpec.formatType()) {
772 BloombergLP::bslfmt::FormatterCharUtil<char>::toUpper(buf, end);
775 return alignAndCopy(buf, numberLength, formatContext, finalSpec);
778template <
class t_VALUE,
class t_CHAR>
779template <
class t_FORMAT_CONTEXT>
780typename t_FORMAT_CONTEXT::iterator
781FormatterFloating_Base<t_VALUE, t_CHAR>::formatHexImpl(
783 t_FORMAT_CONTEXT& formatContext,
784 const Specification& finalSpec)
const
786 typedef BloombergLP::bslalg::NumericFormatterUtil NFUtil;
789 BSLS_ASSERT(Specification::e_FLOATING_HEX == finalSpec.formatType() ||
790 Specification::e_FLOATING_HEX_UC == finalSpec.formatType());
793 BSLS_ASSERT(finalSpec.postprocessedPrecision().category() ==
797 char buf[NFUtil::ToCharsMaxLength<t_VALUE, NFUtil::e_HEX>::k_VALUE];
798 char *
end = NFUtil::toChars(buf,
803 size_t numberLength =
static_cast<size_t>(
end - buf);
805 if (finalSpec.alternativeFlag()) {
806 numberLength = applyScientificAlternate(
'p', buf, numberLength);
809 if (Specification::e_FLOATING_HEX_UC == finalSpec.formatType()) {
810 BloombergLP::bslfmt::FormatterCharUtil<char>::toUpper(buf, end);
813 return alignAndCopy(buf, numberLength, formatContext, finalSpec);
816template <
class t_VALUE,
class t_CHAR>
817template <
class t_FORMAT_CONTEXT>
818typename t_FORMAT_CONTEXT::iterator
819FormatterFloating_Base<t_VALUE, t_CHAR>::formatHexPrecImpl(
821 t_FORMAT_CONTEXT& formatContext,
822 const Specification& finalSpec)
const
824 typedef BloombergLP::bslalg::NumericFormatterUtil NFUtil;
827 BSLS_ASSERT(Specification::e_FLOATING_HEX == finalSpec.formatType() ||
828 Specification::e_FLOATING_HEX_UC == finalSpec.formatType());
831 BSLS_ASSERT(finalSpec.postprocessedPrecision().category() !=
835 const size_t k_STACK_BUF_LEN =
836 NFUtil::ToCharsMaxLength<t_VALUE, NFUtil::e_HEX>::k_VALUE;
837 char sbuf[k_STACK_BUF_LEN];
840 size_t bufLen = k_STACK_BUF_LEN;
843 const size_t reqdBufLen =
844 NFUtil::PrecisionMaxBufferLength<t_VALUE>::value(
846 finalSpec.postprocessedPrecision().value());
848 if (reqdBufLen > k_STACK_BUF_LEN) {
849 dbuf = allocator.
allocate(reqdBufLen);
856 dbuf ? reqdBufLen : 0);
857 char *
end = NFUtil::toChars(buf,
861 finalSpec.postprocessedPrecision().value());
863 size_t numberLength =
static_cast<size_t>(
end - buf);
865 if (finalSpec.alternativeFlag()) {
866 numberLength = applyScientificAlternate(
'p', buf, numberLength);
869 if (Specification::e_FLOATING_HEX_UC == finalSpec.formatType()) {
870 BloombergLP::bslfmt::FormatterCharUtil<char>::toUpper(buf, end);
873 return alignAndCopy(buf, numberLength, formatContext, finalSpec);
876template <
class t_VALUE,
class t_CHAR>
877template <
class t_FORMAT_CONTEXT>
878typename t_FORMAT_CONTEXT::iterator
879FormatterFloating_Base<t_VALUE, t_CHAR>::formatScientificImpl(
881 t_FORMAT_CONTEXT& formatContext,
882 const Specification& finalSpec)
const
884 typedef BloombergLP::bslalg::NumericFormatterUtil NFUtil;
888 Specification::e_FLOATING_SCIENTIFIC == finalSpec.formatType() ||
889 Specification::e_FLOATING_SCIENTIFIC_UC == finalSpec.formatType());
892 typedef FormatterSpecificationNumericValue FSNVAlue;
893 const FSNVAlue& specPrec = finalSpec.postprocessedPrecision();
894 const int precision = (FSNVAlue::e_DEFAULT == specPrec.category())
899 const size_t k_STACK_BUF_LEN =
900 NFUtil::ToCharsMaxLength<t_VALUE, NFUtil::e_SCIENTIFIC>::k_VALUE + 11;
901 char sbuf[k_STACK_BUF_LEN];
904 size_t bufLen = k_STACK_BUF_LEN;
907 const size_t reqdBufLen =
908 NFUtil::PrecisionMaxBufferLength<t_VALUE>::value(NFUtil::e_SCIENTIFIC,
911 if (reqdBufLen > k_STACK_BUF_LEN) {
912 dbuf = allocator.
allocate(reqdBufLen);
919 dbuf ? reqdBufLen : 0);
920 char *
end = NFUtil::toChars(buf,
923 NFUtil::e_SCIENTIFIC,
926 size_t numberLength =
static_cast<size_t>(
end - buf);
928 if (finalSpec.alternativeFlag()) {
929 numberLength = applyScientificAlternate(
'e', buf, numberLength);
932 if (Specification::e_FLOATING_SCIENTIFIC_UC == finalSpec.formatType()) {
933 BloombergLP::bslfmt::FormatterCharUtil<char>::toUpper(buf, end);
936 return alignAndCopy(buf, numberLength, formatContext, finalSpec);
940template <
class t_VALUE,
class t_CHAR>
941template <
class t_FORMAT_CONTEXT>
942typename t_FORMAT_CONTEXT::iterator
945 t_FORMAT_CONTEXT& formatContext)
const
952 const bool isDefaultPrecision =
956 case Specification::e_FLOATING_DEFAULT: {
957 if (isDefaultPrecision) {
958 return formatDefaultImpl(value, formatContext, finalSpec);
961 return formatGeneralImpl(value, formatContext, finalSpec);
966 case Specification::e_FLOATING_HEX_UC: {
967 if (isDefaultPrecision) {
968 return formatHexImpl(value, formatContext, finalSpec);
971 return formatHexPrecImpl(value, formatContext, finalSpec);
976 case Specification::e_FLOATING_SCIENTIFIC_UC: {
977 return formatScientificImpl(value, formatContext, finalSpec);
981 case Specification::e_FLOATING_FIXED_UC: {
982 return formatFixedImpl(value, formatContext, finalSpec);
986 case Specification::e_FLOATING_GENERAL_UC: {
987 return formatGeneralImpl(value, formatContext, finalSpec);
991 BSLS_THROW(bsl::format_error(
"Unknown format"));
996template <
class t_VALUE,
class t_CHAR>
997template <
class t_PARSE_CONTEXT>
1001 d_spec.parse(&parseContext, Specification::e_CATEGORY_FLOATING);
1003 if (d_spec.localeSpecificFlag()) {
1005 "Formatting with the L specifier is not supported"));
1008 return parseContext.begin();
1019template <
class t_CHAR>
1021: BloombergLP::bslfmt::FormatterFloating_Base<float, t_CHAR> {
1026template <
class t_CHAR>
1028: BloombergLP::bslfmt::FormatterFloating_Base<double, t_CHAR> {
1038template <
class t_CHAR>
1040 template <
class t_PARSE_CONTEXT>
1042 t_PARSE_CONTEXT& parseContext)
1046 "Formatting `long double` is not implemented yet"));
1049 template <
class t_FORMAT_CONTEXT>
1052 t_FORMAT_CONTEXT& formatContext)
const
1055 (void)formatContext;
1057 "Formatting `long double` is not implemented yet"));
Definition bslstl_stringview.h:471
Definition bslma_polymorphicallocator.h:460
BSLS_ANNOTATION_NODISCARD TYPE * allocate(std::size_t n)
Definition bslma_polymorphicallocator.h:963
Definition bslma_deallocatebytesproctor.h:272
#define BSLA_FALLTHROUGH
Definition bsla_fallthrough.h:188
#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
T::iterator end(T &container)
Definition bslstl_iterator.h:1621
Definition bslfmt_enablestreamedformatter.h:130
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