summaryrefslogtreecommitdiff
path: root/deps/icu-small/source/i18n/digitlst.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'deps/icu-small/source/i18n/digitlst.cpp')
-rw-r--r--deps/icu-small/source/i18n/digitlst.cpp1143
1 files changed, 0 insertions, 1143 deletions
diff --git a/deps/icu-small/source/i18n/digitlst.cpp b/deps/icu-small/source/i18n/digitlst.cpp
deleted file mode 100644
index 37760defd7..0000000000
--- a/deps/icu-small/source/i18n/digitlst.cpp
+++ /dev/null
@@ -1,1143 +0,0 @@
-// © 2016 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html
-/*
-**********************************************************************
-* Copyright (C) 1997-2015, International Business Machines
-* Corporation and others. All Rights Reserved.
-**********************************************************************
-*
-* File DIGITLST.CPP
-*
-* Modification History:
-*
-* Date Name Description
-* 03/21/97 clhuang Converted from java.
-* 03/21/97 clhuang Implemented with new APIs.
-* 03/27/97 helena Updated to pass the simple test after code review.
-* 03/31/97 aliu Moved isLONG_MIN to here, and fixed it.
-* 04/15/97 aliu Changed MAX_COUNT to DBL_DIG. Changed Digit to char.
-* Reworked representation by replacing fDecimalAt
-* with fExponent.
-* 04/16/97 aliu Rewrote set() and getDouble() to use sprintf/atof
-* to do digit conversion.
-* 09/09/97 aliu Modified for exponential notation support.
-* 08/02/98 stephen Added nearest/even rounding
-* Fixed bug in fitsIntoLong
-******************************************************************************
-*/
-
-#if defined(__CYGWIN__) && !defined(_GNU_SOURCE)
-#define _GNU_SOURCE
-#endif
-
-#include "digitlst.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-#include "unicode/putil.h"
-#include "charstr.h"
-#include "cmemory.h"
-#include "cstring.h"
-#include "mutex.h"
-#include "putilimp.h"
-#include "uassert.h"
-#include "digitinterval.h"
-#include "ucln_in.h"
-#include "umutex.h"
-#include "double-conversion.h"
-#include <stdlib.h>
-#include <limits.h>
-#include <string.h>
-#include <stdio.h>
-#include <limits>
-
-using icu::double_conversion::DoubleToStringConverter;
-
-#if !defined(U_USE_STRTOD_L)
-# if U_PLATFORM_USES_ONLY_WIN32_API
-# define U_USE_STRTOD_L 1
-# define U_HAVE_XLOCALE_H 0
-# elif defined(U_HAVE_STRTOD_L)
-# define U_USE_STRTOD_L U_HAVE_STRTOD_L
-# else
-# define U_USE_STRTOD_L 0
-# endif
-#endif
-
-#if U_USE_STRTOD_L
-# if U_HAVE_XLOCALE_H
-# include <xlocale.h>
-# else
-# include <locale.h>
-# endif
-#endif
-
-// ***************************************************************************
-// class DigitList
-// A wrapper onto decNumber.
-// Used to be standalone.
-// ***************************************************************************
-
-/**
- * This is the zero digit. The base for the digits returned by getDigit()
- * Note that it is the platform invariant digit, and is not Unicode.
- */
-#define kZero '0'
-
-
-/* Only for 32 bit numbers. Ignore the negative sign. */
-//static const char LONG_MIN_REP[] = "2147483648";
-//static const char I64_MIN_REP[] = "9223372036854775808";
-
-
-U_NAMESPACE_BEGIN
-
-// -------------------------------------
-// default constructor
-
-DigitList::DigitList()
-{
- uprv_decContextDefault(&fContext, DEC_INIT_BASE);
- fContext.traps = 0;
- uprv_decContextSetRounding(&fContext, DEC_ROUND_HALF_EVEN);
- fContext.digits = fStorage.getCapacity();
-
- fDecNumber = fStorage.getAlias();
- uprv_decNumberZero(fDecNumber);
-
- internalSetDouble(0.0);
-}
-
-// -------------------------------------
-
-DigitList::~DigitList()
-{
-}
-
-// -------------------------------------
-// copy constructor
-
-DigitList::DigitList(const DigitList &other)
-{
- fDecNumber = fStorage.getAlias();
- *this = other;
-}
-
-
-// -------------------------------------
-// assignment operator
-
-DigitList&
-DigitList::operator=(const DigitList& other)
-{
- if (this != &other)
- {
- uprv_memcpy(&fContext, &other.fContext, sizeof(decContext));
-
- if (other.fStorage.getCapacity() > fStorage.getCapacity()) {
- fDecNumber = fStorage.resize(other.fStorage.getCapacity());
- }
- // Always reset the fContext.digits, even if fDecNumber was not reallocated,
- // because above we copied fContext from other.fContext.
- fContext.digits = fStorage.getCapacity();
- uprv_decNumberCopy(fDecNumber, other.fDecNumber);
-
- {
- // fDouble is lazily created and cached.
- // Avoid potential races with that happening with other.fDouble
- // while we are doing the assignment.
- Mutex mutex;
-
- if(other.fHave==kDouble) {
- fUnion.fDouble = other.fUnion.fDouble;
- }
- fHave = other.fHave;
- }
- }
- return *this;
-}
-
-// -------------------------------------
-// operator == (does not exactly match the old DigitList function)
-
-UBool
-DigitList::operator==(const DigitList& that) const
-{
- if (this == &that) {
- return TRUE;
- }
- decNumber n; // Has space for only a none digit value.
- decContext c;
- uprv_decContextDefault(&c, DEC_INIT_BASE);
- c.digits = 1;
- c.traps = 0;
-
- uprv_decNumberCompare(&n, this->fDecNumber, that.fDecNumber, &c);
- UBool result = decNumberIsZero(&n);
- return result;
-}
-
-// -------------------------------------
-// comparison function. Returns
-// Not Comparable : -2
-// < : -1
-// == : 0
-// > : +1
-int32_t DigitList::compare(const DigitList &other) {
- decNumber result;
- int32_t savedDigits = fContext.digits;
- fContext.digits = 1;
- uprv_decNumberCompare(&result, this->fDecNumber, other.fDecNumber, &fContext);
- fContext.digits = savedDigits;
- if (decNumberIsZero(&result)) {
- return 0;
- } else if (decNumberIsSpecial(&result)) {
- return -2;
- } else if (result.bits & DECNEG) {
- return -1;
- } else {
- return 1;
- }
-}
-
-
-// -------------------------------------
-// Reduce - remove trailing zero digits.
-void
-DigitList::reduce() {
- uprv_decNumberReduce(fDecNumber, fDecNumber, &fContext);
-}
-
-
-// -------------------------------------
-// trim - remove trailing fraction zero digits.
-void
-DigitList::trim() {
- uprv_decNumberTrim(fDecNumber);
-}
-
-// -------------------------------------
-// Resets the digit list; sets all the digits to zero.
-
-void
-DigitList::clear()
-{
- uprv_decNumberZero(fDecNumber);
- uprv_decContextSetRounding(&fContext, DEC_ROUND_HALF_EVEN);
- internalSetDouble(0.0);
-}
-
-
-/**
- * Formats a int64_t number into a base 10 string representation, and NULL terminates it.
- * @param number The number to format
- * @param outputStr The string to output to. Must be at least MAX_DIGITS+2 in length (21),
- * to hold the longest int64_t value.
- * @return the number of digits written, not including the sign.
- */
-static int32_t
-formatBase10(int64_t number, char *outputStr) {
- // The number is output backwards, starting with the LSD.
- // Fill the buffer from the far end. After the number is complete,
- // slide the string contents to the front.
-
- const int32_t MAX_IDX = MAX_DIGITS+2;
- int32_t destIdx = MAX_IDX;
- outputStr[--destIdx] = 0;
-
- int64_t n = number;
- if (number < 0) { // Negative numbers are slightly larger than a postive
- outputStr[--destIdx] = (char)(-(n % 10) + kZero);
- n /= -10;
- }
- do {
- outputStr[--destIdx] = (char)(n % 10 + kZero);
- n /= 10;
- } while (n > 0);
-
- if (number < 0) {
- outputStr[--destIdx] = '-';
- }
-
- // Slide the number to the start of the output str
- U_ASSERT(destIdx >= 0);
- int32_t length = MAX_IDX - destIdx;
- uprv_memmove(outputStr, outputStr+MAX_IDX-length, length);
-
- return length;
-}
-
-
-// -------------------------------------
-//
-// setRoundingMode()
-// For most modes, the meaning and names are the same between the decNumber library
-// (which DigitList follows) and the ICU Formatting Rounding Mode values.
-// The flag constants are different, however.
-//
-// Note that ICU's kRoundingUnnecessary is not implemented directly by DigitList.
-// This mode, inherited from Java, means that numbers that would not format exactly
-// will return an error when formatting is attempted.
-
-void
-DigitList::setRoundingMode(DecimalFormat::ERoundingMode m) {
- enum rounding r;
-
- switch (m) {
- case DecimalFormat::kRoundCeiling: r = DEC_ROUND_CEILING; break;
- case DecimalFormat::kRoundFloor: r = DEC_ROUND_FLOOR; break;
- case DecimalFormat::kRoundDown: r = DEC_ROUND_DOWN; break;
- case DecimalFormat::kRoundUp: r = DEC_ROUND_UP; break;
- case DecimalFormat::kRoundHalfEven: r = DEC_ROUND_HALF_EVEN; break;
- case DecimalFormat::kRoundHalfDown: r = DEC_ROUND_HALF_DOWN; break;
- case DecimalFormat::kRoundHalfUp: r = DEC_ROUND_HALF_UP; break;
- case DecimalFormat::kRoundUnnecessary: r = DEC_ROUND_HALF_EVEN; break;
- default:
- // TODO: how to report the problem?
- // Leave existing mode unchanged.
- r = uprv_decContextGetRounding(&fContext);
- }
- uprv_decContextSetRounding(&fContext, r);
-
-}
-
-
-// -------------------------------------
-
-void
-DigitList::setPositive(UBool s) {
- if (s) {
- fDecNumber->bits &= ~DECNEG;
- } else {
- fDecNumber->bits |= DECNEG;
- }
- internalClear();
-}
-// -------------------------------------
-
-void
-DigitList::setDecimalAt(int32_t d) {
- U_ASSERT((fDecNumber->bits & DECSPECIAL) == 0); // Not Infinity or NaN
- U_ASSERT(d-1>-999999999);
- U_ASSERT(d-1< 999999999);
- int32_t adjustedDigits = fDecNumber->digits;
- if (decNumberIsZero(fDecNumber)) {
- // Account for difference in how zero is represented between DigitList & decNumber.
- adjustedDigits = 0;
- }
- fDecNumber->exponent = d - adjustedDigits;
- internalClear();
-}
-
-int32_t
-DigitList::getDecimalAt() {
- U_ASSERT((fDecNumber->bits & DECSPECIAL) == 0); // Not Infinity or NaN
- if (decNumberIsZero(fDecNumber) || ((fDecNumber->bits & DECSPECIAL) != 0)) {
- return fDecNumber->exponent; // Exponent should be zero for these cases.
- }
- return fDecNumber->exponent + fDecNumber->digits;
-}
-
-void
-DigitList::setCount(int32_t c) {
- U_ASSERT(c <= fContext.digits);
- if (c == 0) {
- // For a value of zero, DigitList sets all fields to zero, while
- // decNumber keeps one digit (with that digit being a zero)
- c = 1;
- fDecNumber->lsu[0] = 0;
- }
- fDecNumber->digits = c;
- internalClear();
-}
-
-int32_t
-DigitList::getCount() const {
- if (decNumberIsZero(fDecNumber) && fDecNumber->exponent==0) {
- // The extra test for exponent==0 is needed because parsing sometimes appends
- // zero digits. It's bogus, decimalFormatter parsing needs to be cleaned up.
- return 0;
- } else {
- return fDecNumber->digits;
- }
-}
-
-void
-DigitList::setDigit(int32_t i, char v) {
- int32_t count = fDecNumber->digits;
- U_ASSERT(i<count);
- U_ASSERT(v>='0' && v<='9');
- v &= 0x0f;
- fDecNumber->lsu[count-i-1] = v;
- internalClear();
-}
-
-char
-DigitList::getDigit(int32_t i) {
- int32_t count = fDecNumber->digits;
- U_ASSERT(i<count);
- return fDecNumber->lsu[count-i-1] + '0';
-}
-
-// copied from DigitList::getDigit()
-uint8_t
-DigitList::getDigitValue(int32_t i) {
- int32_t count = fDecNumber->digits;
- U_ASSERT(i<count);
- return fDecNumber->lsu[count-i-1];
-}
-
-// -------------------------------------
-// Appends the digit to the digit list if it's not out of scope.
-// Ignores the digit, otherwise.
-//
-// This function is horribly inefficient to implement with decNumber because
-// the digits are stored least significant first, which requires moving all
-// existing digits down one to make space for the new one to be appended.
-//
-void
-DigitList::append(char digit)
-{
- U_ASSERT(digit>='0' && digit<='9');
- // Ignore digits which exceed the precision we can represent
- // And don't fix for larger precision. Fix callers instead.
- if (decNumberIsZero(fDecNumber)) {
- // Zero needs to be special cased because of the difference in the way
- // that the old DigitList and decNumber represent it.
- // digit cout was zero for digitList, is one for decNumber
- fDecNumber->lsu[0] = digit & 0x0f;
- fDecNumber->digits = 1;
- fDecNumber->exponent--; // To match the old digit list implementation.
- } else {
- int32_t nDigits = fDecNumber->digits;
- if (nDigits < fContext.digits) {
- int i;
- for (i=nDigits; i>0; i--) {
- fDecNumber->lsu[i] = fDecNumber->lsu[i-1];
- }
- fDecNumber->lsu[0] = digit & 0x0f;
- fDecNumber->digits++;
- // DigitList emulation - appending doesn't change the magnitude of existing
- // digits. With decNumber's decimal being after the
- // least signficant digit, we need to adjust the exponent.
- fDecNumber->exponent--;
- }
- }
- internalClear();
-}
-
-// -------------------------------------
-
-/**
- * Currently, getDouble() depends on strtod() to do its conversion.
- *
- * WARNING!!
- * This is an extremely costly function. ~1/2 of the conversion time
- * can be linked to this function.
- */
-double
-DigitList::getDouble() const
-{
- {
- Mutex mutex;
- if (fHave == kDouble) {
- return fUnion.fDouble;
- }
- }
-
- double tDouble = 0.0;
- if (isZero()) {
- tDouble = 0.0;
- if (decNumberIsNegative(fDecNumber)) {
- tDouble /= -1;
- }
- } else if (isInfinite()) {
- if (std::numeric_limits<double>::has_infinity) {
- tDouble = std::numeric_limits<double>::infinity();
- } else {
- tDouble = std::numeric_limits<double>::max();
- }
- if (!isPositive()) {
- tDouble = -tDouble; //this was incorrectly "-fDouble" originally.
- }
- } else {
- MaybeStackArray<char, MAX_DBL_DIGITS+18> s;
- // Note: 14 is a magic constant from the decNumber library documentation,
- // the max number of extra characters beyond the number of digits
- // needed to represent the number in string form. Add a few more
- // for the additional digits we retain.
-
- // Round down to appx. double precision, if the number is longer than that.
- // Copy the number first, so that we don't modify the original.
- if (getCount() > MAX_DBL_DIGITS + 3) {
- DigitList numToConvert(*this);
- numToConvert.reduce(); // Removes any trailing zeros, so that digit count is good.
- numToConvert.round(MAX_DBL_DIGITS+3);
- uprv_decNumberToString(numToConvert.fDecNumber, s.getAlias());
- // TODO: how many extra digits should be included for an accurate conversion?
- } else {
- uprv_decNumberToString(this->fDecNumber, s.getAlias());
- }
- U_ASSERT(uprv_strlen(&s[0]) < MAX_DBL_DIGITS+18);
-
- char *end = NULL;
- tDouble = decimalStrToDouble(s.getAlias(), &end);
- }
- {
- Mutex mutex;
- DigitList *nonConstThis = const_cast<DigitList *>(this);
- nonConstThis->internalSetDouble(tDouble);
- }
- return tDouble;
-}
-
-#if U_USE_STRTOD_L && U_PLATFORM_USES_ONLY_WIN32_API
-# define locale_t _locale_t
-# define freelocale _free_locale
-# define strtod_l _strtod_l
-#endif
-
-#if U_USE_STRTOD_L
-static locale_t gCLocale = (locale_t)0;
-#endif
-static icu::UInitOnce gCLocaleInitOnce = U_INITONCE_INITIALIZER;
-
-U_CDECL_BEGIN
-// Cleanup callback func
-static UBool U_CALLCONV digitList_cleanup(void)
-{
-#if U_USE_STRTOD_L
- if (gCLocale != (locale_t)0) {
- freelocale(gCLocale);
- }
-#endif
- return TRUE;
-}
-// C Locale initialization func
-static void U_CALLCONV initCLocale(void) {
- ucln_i18n_registerCleanup(UCLN_I18N_DIGITLIST, digitList_cleanup);
-#if U_USE_STRTOD_L
-# if U_PLATFORM_USES_ONLY_WIN32_API
- gCLocale = _create_locale(LC_ALL, "C");
-# else
- gCLocale = newlocale(LC_ALL_MASK, "C", (locale_t)0);
-# endif
-#endif
-}
-U_CDECL_END
-
-double
-DigitList::decimalStrToDouble(char *decstr, char **end) {
- umtx_initOnce(gCLocaleInitOnce, &initCLocale);
-#if U_USE_STRTOD_L
- return strtod_l(decstr, end, gCLocale);
-#else
- char *decimalPt = strchr(decstr, '.');
- if (decimalPt) {
- // We need to know the decimal separator character that will be used with strtod().
- // Depends on the C runtime global locale.
- // Most commonly is '.'
- char rep[MAX_DIGITS];
- sprintf(rep, "%+1.1f", 1.0);
- *decimalPt = rep[2];
- }
- return uprv_strtod(decstr, end);
-#endif
-}
-
-// -------------------------------------
-
-/**
- * convert this number to an int32_t. Round if there is a fractional part.
- * Return zero if the number cannot be represented.
- */
-int32_t DigitList::getLong() /*const*/
-{
- int32_t result = 0;
- if (getUpperExponent() > 10) {
- // Overflow, absolute value too big.
- return result;
- }
- if (fDecNumber->exponent != 0) {
- // Force to an integer, with zero exponent, rounding if necessary.
- // (decNumberToInt32 will only work if the exponent is exactly zero.)
- DigitList copy(*this);
- DigitList zero;
- uprv_decNumberQuantize(copy.fDecNumber, copy.fDecNumber, zero.fDecNumber, &fContext);
- result = uprv_decNumberToInt32(copy.fDecNumber, &fContext);
- } else {
- result = uprv_decNumberToInt32(fDecNumber, &fContext);
- }
- return result;
-}
-
-
-/**
- * convert this number to an int64_t. Truncate if there is a fractional part.
- * Return zero if the number cannot be represented.
- */
-int64_t DigitList::getInt64() /*const*/ {
- // TODO: fast conversion if fHave == fDouble
-
- // Truncate if non-integer.
- // Return 0 if out of range.
- // Range of in64_t is -9223372036854775808 to 9223372036854775807 (19 digits)
- //
- if (getUpperExponent() > 19) {
- // Overflow, absolute value too big.
- return 0;
- }
-
- // The number of integer digits may differ from the number of digits stored
- // in the decimal number.
- // for 12.345 numIntDigits = 2, number->digits = 5
- // for 12E4 numIntDigits = 6, number->digits = 2
- // The conversion ignores the fraction digits in the first case,
- // and fakes up extra zero digits in the second.
- // TODO: It would be faster to store a table of powers of ten to multiply by
- // instead of looping over zero digits, multiplying each time.
-
- int32_t numIntDigits = getUpperExponent();
- uint64_t value = 0;
- for (int32_t i = 0; i < numIntDigits; i++) {
- // Loop is iterating over digits starting with the most significant.
- // Numbers are stored with the least significant digit at index zero.
- int32_t digitIndex = fDecNumber->digits - i - 1;
- int32_t v = (digitIndex >= 0) ? fDecNumber->lsu[digitIndex] : 0;
- value = value * (uint64_t)10 + (uint64_t)v;
- }
-
- if (decNumberIsNegative(fDecNumber)) {
- value = ~value;
- value += 1;
- }
- int64_t svalue = (int64_t)value;
-
- // Check overflow. It's convenient that the MSD is 9 only on overflow, the amount of
- // overflow can't wrap too far. The test will also fail -0, but
- // that does no harm; the right answer is 0.
- if (numIntDigits == 19) {
- if (( decNumberIsNegative(fDecNumber) && svalue>0) ||
- (!decNumberIsNegative(fDecNumber) && svalue<0)) {
- svalue = 0;
- }
- }
-
- return svalue;
-}
-
-
-/**
- * Return a string form of this number.
- * Format is as defined by the decNumber library, for interchange of
- * decimal numbers.
- */
-void DigitList::getDecimal(CharString &str, UErrorCode &status) {
- if (U_FAILURE(status)) {
- return;
- }
-
- // A decimal number in string form can, worst case, be 14 characters longer
- // than the number of digits. So says the decNumber library doc.
- int32_t maxLength = fDecNumber->digits + 14;
- int32_t capacity = 0;
- char *buffer = str.clear().getAppendBuffer(maxLength, 0, capacity, status);
- if (U_FAILURE(status)) {
- return; // Memory allocation error on growing the string.
- }
- U_ASSERT(capacity >= maxLength);
- uprv_decNumberToString(this->fDecNumber, buffer);
- U_ASSERT((int32_t)uprv_strlen(buffer) <= maxLength);
- str.append(buffer, -1, status);
-}
-
-/**
- * Return true if this is an integer value that can be held
- * by an int32_t type.
- */
-UBool
-DigitList::fitsIntoLong(UBool ignoreNegativeZero) /*const*/
-{
- if (decNumberIsSpecial(this->fDecNumber)) {
- // NaN or Infinity. Does not fit in int32.
- return FALSE;
- }
- uprv_decNumberTrim(this->fDecNumber);
- if (fDecNumber->exponent < 0) {
- // Number contains fraction digits.
- return FALSE;
- }
- if (decNumberIsZero(this->fDecNumber) && !ignoreNegativeZero &&
- (fDecNumber->bits & DECNEG) != 0) {
- // Negative Zero, not ingored. Cannot represent as a long.
- return FALSE;
- }
- if (getUpperExponent() < 10) {
- // The number is 9 or fewer digits.
- // The max and min int32 are 10 digts, so this number fits.
- // This is the common case.
- return TRUE;
- }
-
- // TODO: Should cache these constants; construction is relatively costly.
- // But not of huge consequence; they're only needed for 10 digit ints.
- UErrorCode status = U_ZERO_ERROR;
- DigitList min32; min32.set("-2147483648", status);
- if (this->compare(min32) < 0) {
- return FALSE;
- }
- DigitList max32; max32.set("2147483647", status);
- if (this->compare(max32) > 0) {
- return FALSE;
- }
- if (U_FAILURE(status)) {
- return FALSE;
- }
- return true;
-}
-
-
-
-/**
- * Return true if the number represented by this object can fit into
- * a long.
- */
-UBool
-DigitList::fitsIntoInt64(UBool ignoreNegativeZero) /*const*/
-{
- if (decNumberIsSpecial(this->fDecNumber)) {
- // NaN or Infinity. Does not fit in int32.
- return FALSE;
- }
- uprv_decNumberTrim(this->fDecNumber);
- if (fDecNumber->exponent < 0) {
- // Number contains fraction digits.
- return FALSE;
- }
- if (decNumberIsZero(this->fDecNumber) && !ignoreNegativeZero &&
- (fDecNumber->bits & DECNEG) != 0) {
- // Negative Zero, not ingored. Cannot represent as a long.
- return FALSE;
- }
- if (getUpperExponent() < 19) {
- // The number is 18 or fewer digits.
- // The max and min int64 are 19 digts, so this number fits.
- // This is the common case.
- return TRUE;
- }
-
- // TODO: Should cache these constants; construction is relatively costly.
- // But not of huge consequence; they're only needed for 19 digit ints.
- UErrorCode status = U_ZERO_ERROR;
- DigitList min64; min64.set("-9223372036854775808", status);
- if (this->compare(min64) < 0) {
- return FALSE;
- }
- DigitList max64; max64.set("9223372036854775807", status);
- if (this->compare(max64) > 0) {
- return FALSE;
- }
- if (U_FAILURE(status)) {
- return FALSE;
- }
- return true;
-}
-
-
-// -------------------------------------
-
-void
-DigitList::set(int32_t source)
-{
- set((int64_t)source);
- internalSetDouble(source);
-}
-
-// -------------------------------------
-/**
- * Set an int64, via decnumber
- */
-void
-DigitList::set(int64_t source)
-{
- char str[MAX_DIGITS+2]; // Leave room for sign and trailing nul.
- formatBase10(source, str);
- U_ASSERT(uprv_strlen(str) < sizeof(str));
-
- uprv_decNumberFromString(fDecNumber, str, &fContext);
- internalSetDouble(static_cast<double>(source));
-}
-
-// -------------------------------------
-/**
- * Set the DigitList from a decimal number string.
- *
- * The incoming string _must_ be nul terminated, even though it is arriving
- * as a StringPiece because that is what the decNumber library wants.
- * We can get away with this for an internal function; it would not
- * be acceptable for a public API.
- */
-void
-DigitList::set(StringPiece source, UErrorCode &status, uint32_t /*fastpathBits*/) {
- if (U_FAILURE(status)) {
- return;
- }
-
-#if 0
- if(fastpathBits==(kFastpathOk|kNoDecimal)) {
- int32_t size = source.size();
- const char *data = source.data();
- int64_t r = 0;
- int64_t m = 1;
- // fast parse
- while(size>0) {
- char ch = data[--size];
- if(ch=='+') {
- break;
- } else if(ch=='-') {
- r = -r;
- break;
- } else {
- int64_t d = ch-'0';
- //printf("CH[%d]=%c, %d, *=%d\n", size,ch, (int)d, (int)m);
- r+=(d)*m;
- m *= 10;
- }
- }
- //printf("R=%d\n", r);
- set(r);
- } else
-#endif
- {
- // Figure out a max number of digits to use during the conversion, and
- // resize the number up if necessary.
- int32_t numDigits = source.length();
- if (numDigits > fContext.digits) {
- // fContext.digits == fStorage.getCapacity()
- decNumber *t = fStorage.resize(numDigits, fStorage.getCapacity());
- if (t == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- fDecNumber = t;
- fContext.digits = numDigits;
- }
-
- fContext.status = 0;
- uprv_decNumberFromString(fDecNumber, source.data(), &fContext);
- if ((fContext.status & DEC_Conversion_syntax) != 0) {
- status = U_DECIMAL_NUMBER_SYNTAX_ERROR;
- }
- }
- internalClear();
-}
-
-/**
- * Set the digit list to a representation of the given double value.
- * This method supports both fixed-point and exponential notation.
- * @param source Value to be converted.
- */
-void
-DigitList::set(double source)
-{
- // for now, simple implementation; later, do proper IEEE stuff
- char rep[MAX_DIGITS + 8]; // Extra space for '+', '.', e+NNN, and '\0' (actually +8 is enough)
-
- // Generate a representation of the form /[+-][0-9].[0-9]+e[+-][0-9]+/
- // Can also generate /[+-]nan/ or /[+-]inf/
- // TODO: Use something other than sprintf() here, since it's behavior is somewhat platform specific.
- // That is why infinity is special cased here.
- if (uprv_isInfinite(source)) {
- if (uprv_isNegativeInfinity(source)) {
- uprv_strcpy(rep,"-inf"); // Handle negative infinity
- } else {
- uprv_strcpy(rep,"inf");
- }
- } else if (uprv_isNaN(source)) {
- uprv_strcpy(rep, "NaN");
- } else {
- bool sign;
- int32_t length;
- int32_t point;
- DoubleToStringConverter::DoubleToAscii(
- source,
- DoubleToStringConverter::DtoaMode::SHORTEST,
- 0,
- rep + 1,
- sizeof(rep),
- &sign,
- &length,
- &point
- );
-
- // Convert the raw buffer into a string for decNumber
- int32_t power = point - length;
- if (sign) {
- rep[0] = '-';
- } else {
- rep[0] = '0';
- }
- length++;
- rep[length++] = 'E';
- if (power < 0) {
- rep[length++] = '-';
- power = -power;
- } else {
- rep[length++] = '+';
- }
- if (power < 10) {
- rep[length++] = power + '0';
- } else if (power < 100) {
- rep[length++] = (power / 10) + '0';
- rep[length++] = (power % 10) + '0';
- } else {
- U_ASSERT(power < 1000);
- rep[length + 2] = (power % 10) + '0';
- power /= 10;
- rep[length + 1] = (power % 10) + '0';
- power /= 10;
- rep[length] = power + '0';
- length += 3;
- }
- rep[length++] = 0;
- }
- U_ASSERT(uprv_strlen(rep) < sizeof(rep));
-
- // uprv_decNumberFromString() will parse the string expecting '.' as a
- // decimal separator, however sprintf() can use ',' in certain locales.
- // Overwrite a ',' with '.' here before proceeding.
- char *decimalSeparator = strchr(rep, ',');
- if (decimalSeparator != NULL) {
- *decimalSeparator = '.';
- }
-
- // Create a decNumber from the string.
- uprv_decNumberFromString(fDecNumber, rep, &fContext);
- uprv_decNumberTrim(fDecNumber);
- internalSetDouble(source);
-}
-
-// -------------------------------------
-
-/*
- * Multiply
- * The number will be expanded if need be to retain full precision.
- * In practice, for formatting, multiply is by 10, 100 or 1000, so more digits
- * will not be required for this use.
- */
-void
-DigitList::mult(const DigitList &other, UErrorCode &status) {
- if (U_FAILURE(status)) {
- return;
- }
- fContext.status = 0;
- int32_t requiredDigits = this->digits() + other.digits();
- if (requiredDigits > fContext.digits) {
- reduce(); // Remove any trailing zeros
- int32_t requiredDigits = this->digits() + other.digits();
- ensureCapacity(requiredDigits, status);
- }
- uprv_decNumberMultiply(fDecNumber, fDecNumber, other.fDecNumber, &fContext);
- internalClear();
-}
-
-// -------------------------------------
-
-/*
- * Divide
- * The number will _not_ be expanded for inexact results.
- * TODO: probably should expand some, for rounding increments that
- * could add a few digits, e.g. .25, but not expand arbitrarily.
- */
-void
-DigitList::div(const DigitList &other, UErrorCode &status) {
- if (U_FAILURE(status)) {
- return;
- }
- uprv_decNumberDivide(fDecNumber, fDecNumber, other.fDecNumber, &fContext);
- internalClear();
-}
-
-// -------------------------------------
-
-/*
- * ensureCapacity. Grow the digit storage for the number if it's less than the requested
- * amount. Never reduce it. Available size is kept in fContext.digits.
- */
-void
-DigitList::ensureCapacity(int32_t requestedCapacity, UErrorCode &status) {
- if (U_FAILURE(status)) {
- return;
- }
- if (requestedCapacity <= 0) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return;
- }
- if (requestedCapacity > DEC_MAX_DIGITS) {
- // Don't report an error for requesting too much.
- // Arithemetic Results will be rounded to what can be supported.
- // At 999,999,999 max digits, exceeding the limit is not too likely!
- requestedCapacity = DEC_MAX_DIGITS;
- }
- if (requestedCapacity > fContext.digits) {
- decNumber *newBuffer = fStorage.resize(requestedCapacity, fStorage.getCapacity());
- if (newBuffer == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- fContext.digits = requestedCapacity;
- fDecNumber = newBuffer;
- }
-}
-
-// -------------------------------------
-
-/**
- * Round the representation to the given number of digits.
- * @param maximumDigits The maximum number of digits to be shown.
- * Upon return, count will be less than or equal to maximumDigits.
- */
-void
-DigitList::round(int32_t maximumDigits)
-{
- reduce();
- if (maximumDigits >= fDecNumber->digits) {
- return;
- }
- int32_t savedDigits = fContext.digits;
- fContext.digits = maximumDigits;
- uprv_decNumberPlus(fDecNumber, fDecNumber, &fContext);
- fContext.digits = savedDigits;
- uprv_decNumberTrim(fDecNumber);
- reduce();
- internalClear();
-}
-
-
-void
-DigitList::roundFixedPoint(int32_t maximumFractionDigits) {
- reduce(); // Remove trailing zeros.
- if (fDecNumber->exponent >= -maximumFractionDigits) {
- return;
- }
- decNumber scale; // Dummy decimal number, but with the desired number of
- uprv_decNumberZero(&scale); // fraction digits.
- scale.exponent = -maximumFractionDigits;
- scale.lsu[0] = 1;
-
- uprv_decNumberQuantize(fDecNumber, fDecNumber, &scale, &fContext);
- reduce();
- internalClear();
-}
-
-// -------------------------------------
-
-void
-DigitList::toIntegralValue() {
- uprv_decNumberToIntegralValue(fDecNumber, fDecNumber, &fContext);
-}
-
-
-// -------------------------------------
-UBool
-DigitList::isZero() const
-{
- return decNumberIsZero(fDecNumber);
-}
-
-// -------------------------------------
-int32_t
-DigitList::getUpperExponent() const {
- return fDecNumber->digits + fDecNumber->exponent;
-}
-
-DigitInterval &
-DigitList::getSmallestInterval(DigitInterval &result) const {
- result.setLeastSignificantInclusive(fDecNumber->exponent);
- result.setMostSignificantExclusive(getUpperExponent());
- return result;
-}
-
-uint8_t
-DigitList::getDigitByExponent(int32_t exponent) const {
- int32_t idx = exponent - fDecNumber->exponent;
- if (idx < 0 || idx >= fDecNumber->digits) {
- return 0;
- }
- return fDecNumber->lsu[idx];
-}
-
-void
-DigitList::appendDigitsTo(CharString &str, UErrorCode &status) const {
- str.append((const char *) fDecNumber->lsu, fDecNumber->digits, status);
-}
-
-void
-DigitList::roundAtExponent(int32_t exponent, int32_t maxSigDigits) {
- reduce();
- if (maxSigDigits < fDecNumber->digits) {
- int32_t minExponent = getUpperExponent() - maxSigDigits;
- if (exponent < minExponent) {
- exponent = minExponent;
- }
- }
- if (exponent <= fDecNumber->exponent) {
- return;
- }
- int32_t digits = getUpperExponent() - exponent;
- if (digits > 0) {
- round(digits);
- } else {
- roundFixedPoint(-exponent);
- }
-}
-
-void
-DigitList::quantize(const DigitList &quantity, UErrorCode &status) {
- if (U_FAILURE(status)) {
- return;
- }
- div(quantity, status);
- roundAtExponent(0);
- mult(quantity, status);
- reduce();
-}
-
-int32_t
-DigitList::getScientificExponent(
- int32_t minIntDigitCount, int32_t exponentMultiplier) const {
- // The exponent for zero is always zero.
- if (isZero()) {
- return 0;
- }
- int32_t intDigitCount = getUpperExponent();
- int32_t exponent;
- if (intDigitCount >= minIntDigitCount) {
- int32_t maxAdjustment = intDigitCount - minIntDigitCount;
- exponent = (maxAdjustment / exponentMultiplier) * exponentMultiplier;
- } else {
- int32_t minAdjustment = minIntDigitCount - intDigitCount;
- exponent = ((minAdjustment + exponentMultiplier - 1) / exponentMultiplier) * -exponentMultiplier;
- }
- return exponent;
-}
-
-int32_t
-DigitList::toScientific(
- int32_t minIntDigitCount, int32_t exponentMultiplier) {
- int32_t exponent = getScientificExponent(
- minIntDigitCount, exponentMultiplier);
- shiftDecimalRight(-exponent);
- return exponent;
-}
-
-void
-DigitList::shiftDecimalRight(int32_t n) {
- fDecNumber->exponent += n;
- internalClear();
-}
-
-U_NAMESPACE_END
-#endif // #if !UCONFIG_NO_FORMATTING
-
-//eof