7 #include <GenericNumberFormat.h>
9 #include <UnicodeChar.h>
17 // constants (more below the helper classes)
19 static const int kMaxIntDigitCount
= 20; // int64: 19 + sign, uint64: 20
20 static const int kMaxFloatDigitCount
= DBL_DIG
+ 2;
21 // double: mantissa precision + 2
27 BGenericNumberFormat::Symbol::Symbol(const char *symbol
)
36 BGenericNumberFormat::Symbol::~Symbol()
43 BGenericNumberFormat::Symbol::SetTo(const char *symbol
)
53 this->symbol
= strdup(symbol
);
56 length
= strlen(this->symbol
);
57 char_count
= BUnicodeChar::UTF8StringLength(this->symbol
);
63 // SpecialNumberSymbols
64 struct BGenericNumberFormat::SpecialNumberSymbols
{
66 const Symbol
*infinity
;
67 const Symbol
*negative_infinity
;
72 class BGenericNumberFormat::GroupingInfo
{
84 GroupingInfo(const char **separators
, int32 separatorCount
,
85 const size_t *sizes
, int32 sizeCount
)
93 SetTo(separators
, separatorCount
, sizes
, sizeCount
);
101 status_t
SetTo(const char **separators
, int32 separatorCount
,
102 const size_t *sizes
, int32 sizeCount
)
107 if ((!separators
&& separatorCount
<= 0)
108 || (!sizes
&& sizeCount
<= 0))
111 fSeparators
= new(nothrow
) Symbol
[separatorCount
];
112 fSizes
= new(nothrow
) int32
[sizeCount
];
113 fSumSizes
= new(nothrow
) int32
[sizeCount
];
114 fSumSeparators
= new(nothrow
) Symbol
*[separatorCount
];
115 if (!fSeparators
|| !fSizes
|| !fSumSizes
|| !fSumSeparators
) {
119 fSeparatorCount
= separatorCount
;
120 fSizeCount
= sizeCount
;
122 for (int i
= 0; i
< separatorCount
; i
++) {
123 status_t error
= fSeparators
[i
].SetTo(separators
[i
]);
129 // sizes and sum arrays
131 for (int32 i
= 0; i
< sizeCount
; i
++) {
132 fSizes
[i
] = (int32
)sizes
[i
];
133 sumSize
+= fSizes
[i
];
134 fSumSizes
[i
] = sumSize
;
135 fSumSeparators
[i
] = &fSeparators
[min(i
, fSeparatorCount
)];
143 delete[] fSeparators
;
156 if (fSumSeparators
) {
157 delete[] fSumSeparators
;
158 fSumSeparators
= NULL
;
162 const Symbol
*SeparatorForDigit(int32 position
) const
164 for (int i
= fSizeCount
- 1; i
>= 0; i
--) {
165 if (fSumSizes
[i
] <= position
) {
166 if (fSumSizes
[i
] == position
167 || (i
== fSizeCount
- 1
168 && (position
- fSumSizes
[i
]) % fSizes
[i
] == 0)) {
169 return fSumSeparators
[i
];
179 int32 fSeparatorCount
;
183 Symbol
**fSumSeparators
;
188 class BGenericNumberFormat::SignSymbols
{
194 fNoForcePlusPrefix(),
202 SignSymbols(const char *plusPrefix
, const char *minusPrefix
,
203 const char *padPlusPrefix
, const char *noForcePlusPrefix
,
204 const char *plusSuffix
, const char *minusSuffix
,
205 const char *padPlusSuffix
, const char *noForcePlusSuffix
)
206 : fPlusPrefix(plusPrefix
),
207 fMinusPrefix(minusPrefix
),
208 fPadPlusPrefix(padPlusPrefix
),
209 fNoForcePlusPrefix(noForcePlusPrefix
),
210 fPlusSuffix(plusSuffix
),
211 fMinusSuffix(minusSuffix
),
212 fPadPlusSuffix(padPlusSuffix
),
213 fNoForcePlusSuffix(noForcePlusSuffix
)
221 status_t
SetTo(const char *plusPrefix
, const char *minusPrefix
,
222 const char *padPlusPrefix
, const char *noForcePlusPrefix
,
223 const char *plusSuffix
, const char *minusSuffix
,
224 const char *padPlusSuffix
, const char *noForcePlusSuffix
)
226 status_t error
= B_OK
;
228 error
= fPlusPrefix
.SetTo(plusPrefix
);
230 error
= fMinusPrefix
.SetTo(minusPrefix
);
232 error
= fPadPlusPrefix
.SetTo(noForcePlusPrefix
);
234 error
= fNoForcePlusPrefix
.SetTo(noForcePlusPrefix
);
236 error
= fPlusSuffix
.SetTo(plusSuffix
);
238 error
= fMinusSuffix
.SetTo(minusSuffix
);
240 error
= fPadPlusSuffix
.SetTo(noForcePlusSuffix
);
242 error
= fNoForcePlusSuffix
.SetTo(noForcePlusSuffix
);
251 fMinusPrefix
.Unset();
252 fNoForcePlusPrefix
.Unset();
253 fPadPlusPrefix
.Unset();
255 fMinusSuffix
.Unset();
256 fNoForcePlusSuffix
.Unset();
257 fPadPlusSuffix
.Unset();
260 const Symbol
*PlusPrefix() const
265 const Symbol
*MinusPrefix() const
267 return &fMinusPrefix
;
270 const Symbol
*PadPlusPrefix() const
272 return &fPadPlusPrefix
;
275 const Symbol
*NoForcePlusPrefix() const
277 return &fNoForcePlusPrefix
;
280 const Symbol
*PlusSuffix() const
285 const Symbol
*MinusSuffix() const
287 return &fMinusSuffix
;
290 const Symbol
*PadPlusSuffix() const
292 return &fPadPlusSuffix
;
295 const Symbol
*NoForcePlusSuffix() const
297 return &fNoForcePlusSuffix
;
303 Symbol fPadPlusPrefix
;
304 Symbol fNoForcePlusPrefix
;
307 Symbol fPadPlusSuffix
;
308 Symbol fNoForcePlusSuffix
;
313 class BGenericNumberFormat::BufferWriter
{
315 BufferWriter(char *buffer
= NULL
, int32 bufferSize
= 0)
317 SetTo(buffer
, bufferSize
);
320 void SetTo(char *buffer
= NULL
, int32 bufferSize
= 0)
323 fBufferSize
= bufferSize
;
326 fDryRun
= (!fBuffer
|| (fBufferSize
== 0));
331 int32
StringLength() const
336 int32
CharCount() const
341 bool IsOverflow() const
343 return (fPosition
>= fBufferSize
);
346 void Append(const char *bytes
, size_t length
, size_t charCount
)
348 int32 newPosition
= fPosition
+ length
;
349 fDryRun
|= (newPosition
>= fBufferSize
);
350 if (!fDryRun
&& length
> 0) {
351 memcpy(fBuffer
+ fPosition
, bytes
, length
);
352 fBuffer
[newPosition
] = '\0';
354 fPosition
= newPosition
;
355 fCharCount
+= charCount
;
358 void Append(const Symbol
&symbol
)
360 Append(symbol
.symbol
, symbol
.length
, symbol
.char_count
);
363 void Append(const Symbol
*symbol
)
369 void Append(char c
, int32 count
) // ASCII 128 chars only!
373 int32 newPosition
= fPosition
+ count
;
374 fDryRun
|= (newPosition
>= fBufferSize
);
375 if (!fDryRun
&& count
> 0) {
376 memset(fBuffer
+ fPosition
, c
, count
);
377 fBuffer
[newPosition
] = '\0';
379 fPosition
= newPosition
;
383 void Append(const Symbol
&symbol
, int32 count
)
387 int32 bytes
= count
* symbol
.length
;
388 int32 newPosition
= fPosition
+ bytes
;
389 fDryRun
|= (newPosition
>= fBufferSize
);
390 if (!fDryRun
&& count
> 0) {
391 for (int i
= 0; i
< count
* symbol
.length
; i
++)
392 fBuffer
[i
] = symbol
.symbol
[i
% symbol
.length
];
393 fBuffer
[newPosition
] = '\0';
395 fPosition
= newPosition
;
396 fCharCount
+= count
* symbol
.char_count
;
399 void Append(const Symbol
*symbol
, int32 count
)
402 Append(*symbol
, count
);
417 const BGenericNumberFormat::Symbol
418 BGenericNumberFormat::kDefaultDigitSymbols
[] = {
419 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
422 // decimal separator symbol
423 const BGenericNumberFormat::Symbol
424 BGenericNumberFormat::kDefaultFractionSeparator
= ".";
426 // grouping separator symbols
427 static const char *kDefaultGroupingSeparators
[] = { "," };
428 static const int32 kDefaultGroupingSeparatorCount
429 = sizeof(kDefaultGroupingSeparators
) / sizeof(const char*);
430 static const char *kNoGroupingSeparators
[] = { NULL
}; // to please mwcc
431 static const int32 kNoGroupingSeparatorCount
= 0;
434 static const size_t kDefaultGroupingSizes
[] = { 3 };
435 static const int32 kDefaultGroupingSizeCount
436 = sizeof(kDefaultGroupingSizes
) / sizeof(size_t);
437 static const size_t kNoGroupingSizes
[] = { 0 }; // to please mwcc
438 static const int32 kNoGroupingSizeCount
= 0;
441 const BGenericNumberFormat::GroupingInfo
442 BGenericNumberFormat::kDefaultGroupingInfo(
443 kDefaultGroupingSeparators
, kDefaultGroupingSeparatorCount
,
444 kDefaultGroupingSizes
, kDefaultGroupingSizeCount
446 const BGenericNumberFormat::GroupingInfo
447 BGenericNumberFormat::kNoGroupingInfo(
448 kNoGroupingSeparators
, kNoGroupingSeparatorCount
,
449 kNoGroupingSizes
, kNoGroupingSizeCount
453 const BGenericNumberFormat::Symbol
454 BGenericNumberFormat::kDefaultExponentSymbol
= "e";
455 const BGenericNumberFormat::Symbol
456 BGenericNumberFormat::kDefaultUpperCaseExponentSymbol
= "E";
459 const BGenericNumberFormat::Symbol
460 BGenericNumberFormat::kDefaultNaNSymbol
= "NaN";
461 const BGenericNumberFormat::Symbol
462 BGenericNumberFormat::kDefaultUpperCaseNaNSymbol
= "NaN";
465 const BGenericNumberFormat::Symbol
466 BGenericNumberFormat::kDefaultInfinitySymbol
= "infinity";
467 const BGenericNumberFormat::Symbol
468 BGenericNumberFormat::kDefaultUpperCaseInfinitySymbol
= "INFINITY";
470 // negative infinity symbol
471 const BGenericNumberFormat::Symbol
472 BGenericNumberFormat::kDefaultNegativeInfinitySymbol
= "-infinity";
473 const BGenericNumberFormat::Symbol
474 BGenericNumberFormat::kDefaultUpperCaseNegativeInfinitySymbol
= "-INFINITY";
477 const BGenericNumberFormat::SignSymbols
478 BGenericNumberFormat::kDefaultSignSymbols(
479 "+", "-", " ", "", // prefixes
480 "", "", "", "" // suffixes
483 // mantissa sign symbols
484 const BGenericNumberFormat::SignSymbols
485 BGenericNumberFormat::kDefaultMantissaSignSymbols(
486 "", "", "", "", // prefixes
487 "", "", "", "" // suffixes
490 // exponent sign symbols
491 const BGenericNumberFormat::SignSymbols
492 BGenericNumberFormat::kDefaultExponentSignSymbols(
493 "+", "-", " ", "", // prefixes
494 "", "", "", "" // suffixes
499 class BGenericNumberFormat::Integer
{
501 Integer(int64 number
)
503 fNegative(number
< 0)
506 Init(0ULL - (uint64
)number
);
511 Integer(uint64 number
)
518 int DigitCount() const
523 bool IsNegative() const
528 char *ToString(char *str
) const
530 if (fDigitCount
== 0) {
533 } else if (fNegative
) {
535 for (int i
= 0; i
< fDigitCount
; i
++)
536 str
[i
+ 1] = '0' + fDigits
[fDigitCount
- i
- 1];
537 str
[fDigitCount
+ 1] = '\0';
539 for (int i
= 0; i
< fDigitCount
; i
++)
540 str
[i
] = '0' + fDigits
[fDigitCount
- i
- 1];
541 str
[fDigitCount
] = '\0';
546 void Format(BufferWriter
&writer
, const Symbol
*digitSymbols
,
547 const SignSymbols
*signSymbols
,
548 number_format_sign_policy signPolicy
,
549 const GroupingInfo
*groupingInfo
, int32 minDigits
) const
551 const Symbol
*suffix
= NULL
;
554 writer
.Append(signSymbols
->MinusPrefix());
555 suffix
= signSymbols
->MinusSuffix();
557 switch (signPolicy
) {
558 case B_USE_NEGATIVE_SIGN_ONLY
:
559 writer
.Append(signSymbols
->NoForcePlusPrefix());
560 suffix
= signSymbols
->NoForcePlusSuffix();
562 case B_USE_SPACE_FOR_POSITIVE_SIGN
:
563 writer
.Append(signSymbols
->PadPlusPrefix());
564 suffix
= signSymbols
->PadPlusSuffix();
566 case B_USE_POSITIVE_SIGN
:
567 writer
.Append(signSymbols
->PlusPrefix());
568 suffix
= signSymbols
->PlusSuffix();
573 if (fDigitCount
== 0 && minDigits
< 1) {
574 // special case for zero and less the one minimal digit
575 writer
.Append(digitSymbols
[0]);
577 // not zero or at least one minimal digit
580 // pad with zeros up to minDigits
581 int32 digitCount
= max(fDigitCount
, minDigits
);
582 for (int i
= minDigits
- 1; i
>= fDigitCount
; i
--) {
583 if (i
!= digitCount
- 1)
584 writer
.Append(groupingInfo
->SeparatorForDigit(i
));
585 writer
.Append(digitSymbols
[0]);
588 for (int i
= fDigitCount
- 1; i
>= 0; i
--) {
589 if (i
!= digitCount
- 1)
590 writer
.Append(groupingInfo
->SeparatorForDigit(i
));
591 writer
.Append(digitSymbols
[fDigits
[i
]]);
595 // pad with zeros up to minDigits
596 if (fDigitCount
< minDigits
)
597 writer
.Append(digitSymbols
, minDigits
- fDigitCount
);
599 for (int i
= fDigitCount
- 1; i
>= 0; i
--)
600 writer
.Append(digitSymbols
[fDigits
[i
]]);
604 writer
.Append(suffix
);
608 void Init(uint64 number
)
612 fDigits
[fDigitCount
] = number
% 10;
619 uchar fDigits
[kMaxIntDigitCount
];
626 class BGenericNumberFormat::Float
{
629 : fNegative(signbit(number
)),
630 fClass(fpclassify(number
)),
634 // filter special cases
649 // We start with an exponent great enough to make
650 // number / 10^fExponent < 10. It may even be < 1 or 0.1.
651 // We simply cut those digits later.
652 fExponent
= (int)ceil(log10(number
));
653 int shiftBy
= kMaxFloatDigitCount
- fExponent
- 1;
654 // We don't multiply with 10^shiftBy not in one go, since for
655 // subnormal numbers 10^shiftBy will not be representable. Maybe
656 // also for normal numbers close to the limit -- so don't risk
657 // anything, for the time being. TODO: Optimize later.
658 double mantissa
= number
* pow(10, shiftBy
/ 2);
659 mantissa
*= pow(10, shiftBy
- shiftBy
/ 2);
660 // get the mantissa's digits -- we drop trailing zeros
661 int32 firstNonNull
= -1;
662 for (int i
= 0; i
< kMaxFloatDigitCount
; i
++) {
663 char digit
= (char)fmod(mantissa
, 10);
664 if (firstNonNull
< 0 && digit
> 0)
666 if (firstNonNull
>= 0)
667 fDigits
[i
- firstNonNull
] = digit
;
670 if (firstNonNull
>= 0)
671 fDigitCount
= kMaxFloatDigitCount
- firstNonNull
;
674 // drop leading zeros
675 while (fDigitCount
> 0 && fDigits
[fDigitCount
- 1] == 0) {
679 // due to rounding effects we may end up with zero: switch to its
680 // canaonical representation then
681 if (fDigitCount
== 0) {
688 void Format(BufferWriter
&writer
, const Symbol
*digitSymbols
,
689 const SpecialNumberSymbols
*specialNumbers
,
690 const Symbol
*fractionSeparator
,
691 const Symbol
*exponentSymbol
,
692 const SignSymbols
*signSymbols
,
693 const SignSymbols
*mantissaSignSymbols
,
694 const SignSymbols
*exponentSignSymbols
,
695 float_format_type formatType
,
696 number_format_sign_policy signPolicy
,
697 const GroupingInfo
*groupingInfo
,
698 int32 minIntegerDigits
, int32 minFractionDigits
,
699 int32 maxFractionDigits
, bool forceFractionSeparator
,
700 bool keepTrailingFractionZeros
) const
702 // deal with special numbers
705 writer
.Append(specialNumbers
->nan
);
709 writer
.Append(specialNumbers
->negative_infinity
);
711 writer
.Append(specialNumbers
->infinity
);
718 // format according to the specified format type
719 bool scientific
= false;
720 switch (formatType
) {
721 case B_FIXED_POINT_FLOAT_FORMAT
:
723 case B_SCIENTIFIC_FLOAT_FORMAT
:
726 case B_AUTO_FLOAT_FORMAT
:
727 // the criterion printf() uses:
728 scientific
= (fExponent
>= maxFractionDigits
732 // finally invoke the respective method that does the formatting
734 FormatScientific(writer
, digitSymbols
, fractionSeparator
,
735 exponentSymbol
, signSymbols
, mantissaSignSymbols
,
736 exponentSignSymbols
, signPolicy
, minIntegerDigits
,
737 minFractionDigits
, maxFractionDigits
,
738 forceFractionSeparator
, keepTrailingFractionZeros
);
740 FormatFixedPoint(writer
, digitSymbols
, fractionSeparator
,
741 signSymbols
, mantissaSignSymbols
, signPolicy
, groupingInfo
,
742 minIntegerDigits
, minFractionDigits
, maxFractionDigits
,
743 forceFractionSeparator
, keepTrailingFractionZeros
);
747 void FormatScientific(BufferWriter
&writer
, const Symbol
*digitSymbols
,
748 const Symbol
*fractionSeparator
,
749 const Symbol
*exponentSymbol
,
750 const SignSymbols
*signSymbols
,
751 const SignSymbols
*mantissaSignSymbols
,
752 const SignSymbols
*exponentSignSymbols
,
753 number_format_sign_policy signPolicy
,
754 int32 minIntegerDigits
, int32 minFractionDigits
,
755 int32 maxFractionDigits
, bool forceFractionSeparator
,
756 bool keepTrailingFractionZeros
) const
758 const Symbol
*suffix
= NULL
;
759 const Symbol
*mantissaSuffix
= NULL
;
762 writer
.Append(signSymbols
->MinusPrefix());
763 writer
.Append(mantissaSignSymbols
->MinusPrefix());
764 suffix
= signSymbols
->MinusSuffix();
765 mantissaSuffix
= mantissaSignSymbols
->MinusSuffix();
767 switch (signPolicy
) {
768 case B_USE_NEGATIVE_SIGN_ONLY
:
769 writer
.Append(signSymbols
->NoForcePlusPrefix());
770 writer
.Append(mantissaSignSymbols
->NoForcePlusPrefix());
771 suffix
= signSymbols
->NoForcePlusSuffix();
773 = mantissaSignSymbols
->NoForcePlusSuffix();
775 case B_USE_SPACE_FOR_POSITIVE_SIGN
:
776 writer
.Append(signSymbols
->PadPlusPrefix());
777 writer
.Append(mantissaSignSymbols
->PadPlusPrefix());
778 suffix
= signSymbols
->PadPlusSuffix();
779 mantissaSuffix
= mantissaSignSymbols
->PadPlusSuffix();
781 case B_USE_POSITIVE_SIGN
:
782 writer
.Append(signSymbols
->PlusPrefix());
783 writer
.Append(mantissaSignSymbols
->PlusPrefix());
784 suffix
= signSymbols
->PlusSuffix();
785 mantissaSuffix
= mantissaSignSymbols
->PlusSuffix();
790 int32 exponent
= fExponent
;
791 char digits
[kMaxFloatDigitCount
];
792 int32 integerDigits
= max(minIntegerDigits
, 1L);
794 = max(fDigitCount
- integerDigits
, minFractionDigits
);
795 fractionDigits
= min(fractionDigits
, maxFractionDigits
);
797 = _Round(digits
, integerDigits
+ fractionDigits
, exponent
);
798 fractionDigits
= digitCount
- integerDigits
;
799 if (keepTrailingFractionZeros
)
800 fractionDigits
= max(fractionDigits
, minFractionDigits
);
801 fractionDigits
= min(fractionDigits
, maxFractionDigits
);
804 int32 existingIntegerDigits
= min(integerDigits
, digitCount
);
805 for (int i
= 0; i
< existingIntegerDigits
; i
++)
806 writer
.Append(digitSymbols
[(int)digits
[digitCount
- i
- 1]]);
807 // pad with zeros to get the desired number of integer digits
808 if (existingIntegerDigits
< integerDigits
) {
809 writer
.Append(digitSymbols
,
810 integerDigits
- existingIntegerDigits
);
812 // unless the number is 0, adjust the exponent
813 if (!_IsZero(digits
, digitCount
))
814 exponent
-= integerDigits
- 1;
816 if (fractionDigits
> 0 || forceFractionSeparator
)
817 writer
.Append(fractionSeparator
);
818 int32 existingFractionDigits
819 = min(digitCount
- integerDigits
, fractionDigits
);
820 for (int i
= existingFractionDigits
- 1; i
>= 0; i
--)
821 writer
.Append(digitSymbols
[(int)digits
[i
]]);
822 // pad with zeros to get the desired number of fraction digits
823 if (fractionDigits
> existingFractionDigits
) {
824 writer
.Append(digitSymbols
,
825 fractionDigits
- existingFractionDigits
);
827 writer
.Append(mantissaSuffix
);
829 writer
.Append(exponentSymbol
);
831 Integer(static_cast<int64
>(exponent
)).Format(writer
, digitSymbols
,
832 exponentSignSymbols
, B_USE_POSITIVE_SIGN
, &kNoGroupingInfo
, 2);
834 writer
.Append(suffix
);
837 void FormatFixedPoint(BufferWriter
&writer
, const Symbol
*digitSymbols
,
838 const Symbol
*fractionSeparator
,
839 const SignSymbols
*signSymbols
,
840 const SignSymbols
*mantissaSignSymbols
,
841 number_format_sign_policy signPolicy
,
842 const GroupingInfo
*groupingInfo
,
843 int32 minIntegerDigits
, int32 minFractionDigits
,
844 int32 maxFractionDigits
, bool forceFractionSeparator
,
845 bool keepTrailingFractionZeros
) const
847 const Symbol
*suffix
= NULL
;
848 const Symbol
*mantissaSuffix
= NULL
;
851 writer
.Append(signSymbols
->MinusPrefix());
852 writer
.Append(mantissaSignSymbols
->MinusPrefix());
853 suffix
= signSymbols
->MinusSuffix();
854 mantissaSuffix
= mantissaSignSymbols
->MinusSuffix();
856 switch (signPolicy
) {
857 case B_USE_NEGATIVE_SIGN_ONLY
:
858 writer
.Append(signSymbols
->NoForcePlusPrefix());
859 writer
.Append(mantissaSignSymbols
->NoForcePlusPrefix());
860 suffix
= signSymbols
->NoForcePlusSuffix();
862 = mantissaSignSymbols
->NoForcePlusSuffix();
864 case B_USE_SPACE_FOR_POSITIVE_SIGN
:
865 writer
.Append(signSymbols
->PadPlusPrefix());
866 writer
.Append(mantissaSignSymbols
->PadPlusPrefix());
867 suffix
= signSymbols
->PadPlusSuffix();
868 mantissaSuffix
= mantissaSignSymbols
->PadPlusSuffix();
870 case B_USE_POSITIVE_SIGN
:
871 writer
.Append(signSymbols
->PlusPrefix());
872 writer
.Append(mantissaSignSymbols
->PlusPrefix());
873 suffix
= signSymbols
->PlusSuffix();
874 mantissaSuffix
= mantissaSignSymbols
->PlusSuffix();
879 int32 exponent
= fExponent
;
880 char digits
[kMaxFloatDigitCount
];
881 int32 integerDigits
= max(minIntegerDigits
, exponent
+ 1L);
883 = max(fDigitCount
- integerDigits
, minFractionDigits
);
884 fractionDigits
= min(fractionDigits
, maxFractionDigits
);
886 = _Round(digits
, integerDigits
+ fractionDigits
, exponent
);
887 fractionDigits
= digitCount
- integerDigits
;
888 if (keepTrailingFractionZeros
)
889 fractionDigits
= max(fractionDigits
, minFractionDigits
);
890 fractionDigits
= min(fractionDigits
, maxFractionDigits
);
892 int32 existingIntegerDigits
= min(integerDigits
, exponent
+ 1);
893 existingIntegerDigits
= max(existingIntegerDigits
, 0L);
896 // pad with zeros up to minDigits
897 for (int i
= integerDigits
- 1;
898 i
>= existingIntegerDigits
;
900 if (i
!= integerDigits
- 1)
901 writer
.Append(groupingInfo
->SeparatorForDigit(i
));
902 writer
.Append(digitSymbols
[0]);
905 for (int i
= existingIntegerDigits
- 1; i
>= 0; i
--) {
906 if (i
!= integerDigits
- 1)
907 writer
.Append(groupingInfo
->SeparatorForDigit(i
));
908 writer
.Append(digitSymbols
[(int)digits
[
909 digitCount
- existingIntegerDigits
+ i
]]);
913 // pad with zeros to get the desired number of integer digits
914 if (existingIntegerDigits
< integerDigits
) {
915 writer
.Append(digitSymbols
[0],
916 integerDigits
- existingIntegerDigits
);
919 for (int i
= 0; i
< existingIntegerDigits
; i
++) {
921 digitSymbols
[(int)digits
[digitCount
- i
- 1]]);
925 if (fractionDigits
> 0 || forceFractionSeparator
)
926 writer
.Append(fractionSeparator
);
927 int32 existingFractionDigits
928 = min(digitCount
- existingIntegerDigits
, fractionDigits
);
929 for (int i
= existingFractionDigits
- 1; i
>= 0; i
--)
930 writer
.Append(digitSymbols
[(int)digits
[i
]]);
931 // pad with zeros to get the desired number of fraction digits
932 if (fractionDigits
> existingFractionDigits
) {
933 writer
.Append(digitSymbols
,
934 fractionDigits
- existingFractionDigits
);
937 writer
.Append(mantissaSuffix
);
938 writer
.Append(suffix
);
942 int32
_Round(char *digits
, int32 count
, int32
&exponent
) const
944 if (count
> fDigitCount
)
946 int firstNonNull
= -1;
947 // TODO: Non-hardcoded base-independent rounding.
949 if (count
< fDigitCount
)
950 carry
= (fDigits
[fDigitCount
- count
- 1] >= 5);
951 for (int i
= 0; i
< count
; i
++) {
952 char digit
= fDigits
[fDigitCount
- count
+ i
];
955 if (digit
== 10) // == base
960 if (firstNonNull
< 0 && digit
> 0)
962 if (firstNonNull
>= 0)
963 digits
[i
- firstNonNull
] = digit
;
965 if (firstNonNull
< 0) {
977 count
-= firstNonNull
;
981 static bool _IsZero(const char *digits
, int32 digitCount
)
983 return (digitCount
== 1 && digits
[0] == 0);
990 char fDigits
[kMaxFloatDigitCount
];
996 BGenericNumberFormat::BGenericNumberFormat()
997 : fIntegerParameters(),
1000 fFractionSeparator(NULL
),
1001 fGroupingInfo(NULL
),
1002 fExponentSymbol(NULL
),
1003 fUpperCaseExponentSymbol(NULL
),
1005 fUpperCaseNaNSymbol(NULL
),
1006 fInfinitySymbol(NULL
),
1007 fUpperCaseInfinitySymbol(NULL
),
1008 fNegativeInfinitySymbol(NULL
),
1009 fUpperCaseNegativeInfinitySymbol(NULL
),
1011 fMantissaSignSymbols(NULL
),
1012 fExponentSignSymbols(NULL
)
1017 BGenericNumberFormat::~BGenericNumberFormat()
1019 delete fSignSymbols
;
1020 delete fMantissaSignSymbols
;
1021 delete fExponentSignSymbols
;
1026 BGenericNumberFormat::FormatInteger(
1027 const BIntegerFormatParameters
*parameters
, int64 number
, BString
*buffer
,
1028 format_field_position
*positions
, int32 positionCount
, int32
*fieldCount
,
1029 bool allFieldPositions
) const
1033 char localBuffer
[1024];
1034 status_t error
= FormatInteger(parameters
, number
, localBuffer
,
1035 sizeof(localBuffer
), positions
, positionCount
, fieldCount
,
1037 if (error
== B_OK
) {
1038 buffer
->Append(localBuffer
);
1039 // TODO: Check, if the allocation succeeded.
1046 BGenericNumberFormat::FormatInteger(
1047 const BIntegerFormatParameters
*parameters
, uint64 number
, BString
*buffer
,
1048 format_field_position
*positions
, int32 positionCount
, int32
*fieldCount
,
1049 bool allFieldPositions
) const
1053 char localBuffer
[1024];
1054 status_t error
= FormatInteger(parameters
, number
, localBuffer
,
1055 sizeof(localBuffer
), positions
, positionCount
, fieldCount
,
1057 if (error
== B_OK
) {
1058 buffer
->Append(localBuffer
);
1059 // TODO: Check, if the allocation succeeded.
1066 BGenericNumberFormat::FormatInteger(
1067 const BIntegerFormatParameters
*parameters
, int64 number
, char *buffer
,
1068 size_t bufferSize
, format_field_position
*positions
, int32 positionCount
,
1069 int32
*fieldCount
, bool allFieldPositions
) const
1071 Integer
integer(number
);
1072 return FormatInteger(parameters
, integer
, buffer
, bufferSize
, positions
,
1073 positionCount
, fieldCount
, allFieldPositions
);
1078 BGenericNumberFormat::FormatInteger(
1079 const BIntegerFormatParameters
*parameters
, uint64 number
, char *buffer
,
1080 size_t bufferSize
, format_field_position
*positions
, int32 positionCount
,
1081 int32
*fieldCount
, bool allFieldPositions
) const
1083 Integer
integer(number
);
1084 return FormatInteger(parameters
, integer
, buffer
, bufferSize
, positions
,
1085 positionCount
, fieldCount
, allFieldPositions
);
1090 BGenericNumberFormat::FormatFloat(const BFloatFormatParameters
*parameters
,
1091 double number
, BString
*buffer
, format_field_position
*positions
,
1092 int32 positionCount
, int32
*fieldCount
, bool allFieldPositions
) const
1096 // TODO: How to ensure that this is enough?
1097 char localBuffer
[1024];
1098 status_t error
= FormatFloat(parameters
, number
, localBuffer
,
1099 sizeof(localBuffer
), positions
, positionCount
, fieldCount
,
1101 if (error
== B_OK
) {
1102 buffer
->Append(localBuffer
);
1103 // TODO: Check, if the allocation succeeded.
1110 BGenericNumberFormat::FormatFloat(const BFloatFormatParameters
*parameters
,
1111 double number
, char *buffer
, size_t bufferSize
,
1112 format_field_position
*positions
, int32 positionCount
, int32
*fieldCount
,
1113 bool allFieldPositions
) const
1115 // TODO: Check parameters.
1117 parameters
= DefaultFloatFormatParameters();
1118 if (bufferSize
<= parameters
->FormatWidth())
1120 Float
floatNumber(number
);
1121 // prepare some parameters
1122 const GroupingInfo
*groupingInfo
= NULL
;
1123 if (parameters
->UseGrouping())
1124 groupingInfo
= GetGroupingInfo();
1125 bool upperCase
= parameters
->UseUpperCase();
1126 SpecialNumberSymbols specialSymbols
;
1127 GetSpecialNumberSymbols(upperCase
, &specialSymbols
);
1128 // compute the length of the formatted string
1129 BufferWriter writer
;
1130 floatNumber
.Format(writer
, DigitSymbols(), &specialSymbols
,
1131 FractionSeparator(), ExponentSymbol(), GetSignSymbols(),
1132 MantissaSignSymbols(), ExponentSignSymbols(),
1133 parameters
->FloatFormatType(), parameters
->SignPolicy(), groupingInfo
,
1134 parameters
->MinimalIntegerDigits(), parameters
->MinimalFractionDigits(),
1135 parameters
->MaximalFractionDigits(),
1136 parameters
->AlwaysUseFractionSeparator(),
1137 parameters
->KeepTrailingFractionZeros());
1138 int32 stringLength
= writer
.StringLength();
1139 int32 charCount
= writer
.CharCount();
1140 // consider alignment and check the available space in the buffer
1141 int32 padding
= max(0L, (int32
)parameters
->FormatWidth() - charCount
);
1142 // TODO: Padding with zeros.
1143 if ((int32
)bufferSize
<= stringLength
+ padding
)
1145 // prepare for writing
1146 writer
.SetTo(buffer
, bufferSize
);
1147 // write padding for right field alignment
1148 if (parameters
->Alignment() == B_ALIGN_FORMAT_RIGHT
&& padding
> 0)
1149 writer
.Append(' ', padding
);
1151 floatNumber
.Format(writer
, DigitSymbols(), &specialSymbols
,
1152 FractionSeparator(), ExponentSymbol(), GetSignSymbols(),
1153 MantissaSignSymbols(), ExponentSignSymbols(),
1154 parameters
->FloatFormatType(), parameters
->SignPolicy(), groupingInfo
,
1155 parameters
->MinimalIntegerDigits(), parameters
->MinimalFractionDigits(),
1156 parameters
->MaximalFractionDigits(),
1157 parameters
->AlwaysUseFractionSeparator(),
1158 parameters
->KeepTrailingFractionZeros());
1159 // write padding for left field alignment
1160 if (parameters
->Alignment() == B_ALIGN_FORMAT_LEFT
&& padding
> 0)
1161 writer
.Append(' ', padding
);
1165 // SetDefaultIntegerFormatParameters
1167 BGenericNumberFormat::SetDefaultIntegerFormatParameters(
1168 const BIntegerFormatParameters
*parameters
)
1172 fIntegerParameters
= *parameters
;
1176 // DefaultIntegerFormatParameters
1177 BIntegerFormatParameters
*
1178 BGenericNumberFormat::DefaultIntegerFormatParameters()
1180 return &fIntegerParameters
;
1183 // DefaultIntegerFormatParameters
1184 const BIntegerFormatParameters
*
1185 BGenericNumberFormat::DefaultIntegerFormatParameters() const
1187 return &fIntegerParameters
;
1190 // SetDefaultFloatFormatParameters
1192 BGenericNumberFormat::SetDefaultFloatFormatParameters(
1193 const BFloatFormatParameters
*parameters
)
1197 fFloatParameters
= *parameters
;
1201 // DefaultFloatFormatParameters
1202 BFloatFormatParameters
*
1203 BGenericNumberFormat::DefaultFloatFormatParameters()
1205 return &fFloatParameters
;
1208 // DefaultFloatFormatParameters
1209 const BFloatFormatParameters
*
1210 BGenericNumberFormat::DefaultFloatFormatParameters() const
1212 return &fFloatParameters
;
1217 BGenericNumberFormat::SetDigitSymbols(const char **digits
)
1221 for (int i
= 0; i
< 10; i
++) {
1227 if (fDigitSymbols
) {
1228 delete[] fDigitSymbols
;
1229 fDigitSymbols
= NULL
;
1233 fDigitSymbols
= new(nothrow
) Symbol
[10];
1236 for (int i
= 0; i
< 10; i
++) {
1237 status_t error
= fDigitSymbols
[i
].SetTo(digits
[i
]);
1238 if (error
!= B_OK
) {
1239 SetDigitSymbols(NULL
);
1247 // SetFractionSeparator
1249 BGenericNumberFormat::SetFractionSeparator(const char *decimalSeparator
)
1251 return _SetSymbol(&fFractionSeparator
, decimalSeparator
);
1256 BGenericNumberFormat::SetGroupingInfo(const char **groupingSeparators
,
1257 size_t separatorCount
, size_t *groupingSizes
, size_t sizeCount
)
1260 if (groupingSeparators
&& separatorCount
> 0 && groupingSizes
1262 for (int i
= 0; i
< (int)separatorCount
; i
++) {
1263 if (!groupingSeparators
[i
])
1268 if (fGroupingInfo
) {
1269 delete fGroupingInfo
;
1270 fGroupingInfo
= NULL
;
1273 if (groupingSeparators
&& separatorCount
> 0 && groupingSizes
1275 fGroupingInfo
= new GroupingInfo
;
1278 status_t error
= fGroupingInfo
->SetTo(groupingSeparators
,
1279 separatorCount
, groupingSizes
, sizeCount
);
1280 if (error
!= B_OK
) {
1281 delete fGroupingInfo
;
1282 fGroupingInfo
= NULL
;
1289 // SetExponentSymbol
1291 BGenericNumberFormat::SetExponentSymbol(const char *exponentSymbol
,
1292 const char *upperCaseExponentSymbol
)
1294 status_t error
= _SetSymbol(&fExponentSymbol
, exponentSymbol
);
1296 error
= _SetSymbol(&fUpperCaseExponentSymbol
, upperCaseExponentSymbol
);
1298 SetExponentSymbol(NULL
, NULL
);
1302 // SetSpecialNumberSymbols
1304 BGenericNumberFormat::SetSpecialNumberSymbols(const char *nan
,
1305 const char *infinity
, const char *negativeInfinity
,
1306 const char *upperCaseNaN
, const char *upperCaseInfinity
,
1307 const char *upperCaseNegativeInfinity
)
1309 status_t error
= _SetSymbol(&fNaNSymbol
, nan
);
1311 error
= _SetSymbol(&fInfinitySymbol
, infinity
);
1313 error
= _SetSymbol(&fNegativeInfinitySymbol
, negativeInfinity
);
1315 error
= _SetSymbol(&fUpperCaseNaNSymbol
, upperCaseNaN
);
1317 error
= _SetSymbol(&fUpperCaseInfinitySymbol
, upperCaseInfinity
);
1318 if (error
== B_OK
) {
1319 error
= _SetSymbol(&fUpperCaseNegativeInfinitySymbol
,
1320 upperCaseNegativeInfinity
);
1323 SetSpecialNumberSymbols(NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1329 BGenericNumberFormat::SetSignSymbols(const char *plusPrefix
,
1330 const char *minusPrefix
, const char *padPlusPrefix
,
1331 const char *noForcePlusPrefix
, const char *plusSuffix
,
1332 const char *minusSuffix
, const char *padPlusSuffix
,
1333 const char *noForcePlusSuffix
)
1335 if (!fSignSymbols
) {
1336 fSignSymbols
= new(nothrow
) SignSymbols
;
1340 return fSignSymbols
->SetTo(plusPrefix
, minusPrefix
, padPlusPrefix
,
1341 noForcePlusPrefix
, plusSuffix
, minusSuffix
, padPlusSuffix
,
1345 // SetMantissaSignSymbols
1347 BGenericNumberFormat::SetMantissaSignSymbols(const char *plusPrefix
,
1348 const char *minusPrefix
, const char *padPlusPrefix
,
1349 const char *noForcePlusPrefix
, const char *plusSuffix
,
1350 const char *minusSuffix
, const char *padPlusSuffix
,
1351 const char *noForcePlusSuffix
)
1353 if (!fMantissaSignSymbols
) {
1354 fMantissaSignSymbols
= new(nothrow
) SignSymbols
;
1355 if (!fMantissaSignSymbols
)
1358 return fMantissaSignSymbols
->SetTo(plusPrefix
, minusPrefix
, padPlusPrefix
,
1359 noForcePlusPrefix
, plusSuffix
, minusSuffix
, padPlusSuffix
,
1363 // SetExponentSignSymbols
1365 BGenericNumberFormat::SetExponentSignSymbols(const char *plusPrefix
,
1366 const char *minusPrefix
, const char *plusSuffix
, const char *minusSuffix
)
1368 if (!fExponentSignSymbols
) {
1369 fExponentSignSymbols
= new(nothrow
) SignSymbols
;
1370 if (!fExponentSignSymbols
)
1373 return fExponentSignSymbols
->SetTo(plusPrefix
, minusPrefix
, plusPrefix
,
1374 plusPrefix
, plusSuffix
, minusSuffix
, plusSuffix
, plusSuffix
);
1379 BGenericNumberFormat::FormatInteger(
1380 const BIntegerFormatParameters
*parameters
, const Integer
&integer
,
1381 char *buffer
, size_t bufferSize
, format_field_position
*positions
,
1382 int32 positionCount
, int32
*fieldCount
, bool allFieldPositions
) const
1384 // TODO: Check parameters.
1386 parameters
= DefaultIntegerFormatParameters();
1387 if (bufferSize
<= parameters
->FormatWidth())
1389 // prepare some parameters
1390 const GroupingInfo
*groupingInfo
= NULL
;
1391 if (parameters
->UseGrouping())
1392 groupingInfo
= GetGroupingInfo();
1393 // compute the length of the formatted string
1394 BufferWriter writer
;
1395 integer
.Format(writer
, DigitSymbols(),
1396 GetSignSymbols(), parameters
->SignPolicy(), groupingInfo
,
1397 parameters
->MinimalIntegerDigits());
1398 int32 stringLength
= writer
.StringLength();
1399 int32 charCount
= writer
.CharCount();
1400 // consider alignment and check the available space in the buffer
1401 int32 padding
= max(0L, (int32
)parameters
->FormatWidth() - charCount
);
1402 // TODO: Padding with zeros.
1403 if ((int32
)bufferSize
<= stringLength
+ padding
)
1405 // prepare for writing
1406 writer
.SetTo(buffer
, bufferSize
);
1407 // write padding for right field alignment
1408 if (parameters
->Alignment() == B_ALIGN_FORMAT_RIGHT
&& padding
> 0)
1409 writer
.Append(' ', padding
);
1411 integer
.Format(writer
, DigitSymbols(),
1412 GetSignSymbols(), parameters
->SignPolicy(), groupingInfo
,
1413 parameters
->MinimalIntegerDigits());
1414 // write padding for left field alignment
1415 if (parameters
->Alignment() == B_ALIGN_FORMAT_LEFT
&& padding
> 0)
1416 writer
.Append(' ', padding
);
1421 const BGenericNumberFormat::Symbol
*
1422 BGenericNumberFormat::DigitSymbols() const
1424 return (fDigitSymbols
? fDigitSymbols
: kDefaultDigitSymbols
);
1427 // FractionSeparator
1428 const BGenericNumberFormat::Symbol
*
1429 BGenericNumberFormat::FractionSeparator() const
1431 return (fFractionSeparator
? fFractionSeparator
1432 : &kDefaultFractionSeparator
);
1436 const BGenericNumberFormat::GroupingInfo
*
1437 BGenericNumberFormat::GetGroupingInfo() const
1439 return (fGroupingInfo
? fGroupingInfo
: &kDefaultGroupingInfo
);
1443 const BGenericNumberFormat::Symbol
*
1444 BGenericNumberFormat::ExponentSymbol(bool upperCase
) const
1446 if (fExponentSymbol
) {
1447 return (upperCase
&& fUpperCaseExponentSymbol
? fUpperCaseExponentSymbol
1450 return (upperCase
? &kDefaultUpperCaseExponentSymbol
1451 : &kDefaultExponentSymbol
);
1455 const BGenericNumberFormat::Symbol
*
1456 BGenericNumberFormat::NaNSymbol(bool upperCase
) const
1459 return (upperCase
&& fUpperCaseNaNSymbol
? fUpperCaseNaNSymbol
1462 return (upperCase
? &kDefaultUpperCaseNaNSymbol
1463 : &kDefaultNaNSymbol
);
1467 const BGenericNumberFormat::Symbol
*
1468 BGenericNumberFormat::InfinitySymbol(bool upperCase
) const
1470 if (fInfinitySymbol
) {
1471 return (upperCase
&& fUpperCaseInfinitySymbol
? fUpperCaseInfinitySymbol
1474 return (upperCase
? &kDefaultUpperCaseInfinitySymbol
1475 : &kDefaultInfinitySymbol
);
1478 // NegativeInfinitySymbol
1479 const BGenericNumberFormat::Symbol
*
1480 BGenericNumberFormat::NegativeInfinitySymbol(bool upperCase
) const
1482 if (fNegativeInfinitySymbol
) {
1483 return (upperCase
&& fUpperCaseNegativeInfinitySymbol
1484 ? fUpperCaseNegativeInfinitySymbol
: fNegativeInfinitySymbol
);
1486 return (upperCase
? &kDefaultUpperCaseNegativeInfinitySymbol
1487 : &kDefaultNegativeInfinitySymbol
);
1490 // GetSpecialNumberSymbols
1492 BGenericNumberFormat::GetSpecialNumberSymbols(bool upperCase
,
1493 SpecialNumberSymbols
*symbols
) const
1495 symbols
->nan
= NaNSymbol(upperCase
);
1496 symbols
->infinity
= InfinitySymbol(upperCase
);
1497 symbols
->negative_infinity
= NegativeInfinitySymbol(upperCase
);
1501 const BGenericNumberFormat::SignSymbols
*
1502 BGenericNumberFormat::GetSignSymbols() const
1504 return (fSignSymbols
? fSignSymbols
: &kDefaultSignSymbols
);
1507 // MantissaSignSymbols
1508 const BGenericNumberFormat::SignSymbols
*
1509 BGenericNumberFormat::MantissaSignSymbols() const
1511 return (fMantissaSignSymbols
? fMantissaSignSymbols
1512 : &kDefaultMantissaSignSymbols
);
1515 // ExponentSignSymbols
1516 const BGenericNumberFormat::SignSymbols
*
1517 BGenericNumberFormat::ExponentSignSymbols() const
1519 return (fExponentSignSymbols
? fExponentSignSymbols
1520 : &kDefaultExponentSignSymbols
);
1525 BGenericNumberFormat::_SetSymbol(Symbol
**symbol
, const char *str
)
1528 // no symbol -- unset old
1534 // allocate if not existing
1536 *symbol
= new(nothrow
) Symbol
;
1541 status_t error
= (*symbol
)->SetTo(str
);
1542 if (error
!= B_OK
) {