summaryrefslogtreecommitdiff
path: root/deps/icu-small/source/i18n/visibledigits.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'deps/icu-small/source/i18n/visibledigits.cpp')
-rw-r--r--deps/icu-small/source/i18n/visibledigits.cpp187
1 files changed, 187 insertions, 0 deletions
diff --git a/deps/icu-small/source/i18n/visibledigits.cpp b/deps/icu-small/source/i18n/visibledigits.cpp
new file mode 100644
index 0000000000..a6cbd0fdce
--- /dev/null
+++ b/deps/icu-small/source/i18n/visibledigits.cpp
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2015, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ *
+ * file name: visibledigits.cpp
+ */
+
+#include <math.h>
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "cstring.h"
+#include "decNumber.h"
+#include "digitlst.h"
+#include "uassert.h"
+#include "visibledigits.h"
+
+static const int32_t kNegative = 1;
+static const int32_t kInfinite = 2;
+static const int32_t kNaN = 4;
+
+U_NAMESPACE_BEGIN
+
+void VisibleDigits::setNegative() {
+ fFlags |= kNegative;
+}
+
+void VisibleDigits::setNaN() {
+ fFlags |= kNaN;
+}
+
+void VisibleDigits::setInfinite() {
+ fFlags |= kInfinite;
+}
+
+void VisibleDigits::clear() {
+ fInterval.clear();
+ fDigits.clear();
+ fExponent = 0;
+ fFlags = 0;
+ fAbsIntValue = 0LL;
+ fAbsIntValueSet = FALSE;
+ fAbsDoubleValue = 0.0;
+ fAbsDoubleValueSet = FALSE;
+}
+
+UBool VisibleDigits::isNegative() const {
+ return (fFlags & kNegative);
+}
+
+UBool VisibleDigits::isNaN() const {
+ return (fFlags & kNaN);
+}
+
+UBool VisibleDigits::isInfinite() const {
+ return (fFlags & kInfinite);
+}
+
+int32_t VisibleDigits::getDigitByExponent(int32_t digitPos) const {
+ if (digitPos < fExponent || digitPos >= fExponent + fDigits.length()) {
+ return 0;
+ }
+ const char *ptr = fDigits.data();
+ return ptr[digitPos - fExponent];
+}
+
+UBool VisibleDigits::isOverMaxDigits() const {
+ return (fExponent + fDigits.length() > fInterval.getMostSignificantExclusive());
+}
+
+UBool VisibleDigits::isNaNOrInfinity() const {
+ return (fFlags & (kInfinite | kNaN)) != 0;
+}
+
+double VisibleDigits::computeAbsDoubleValue() const {
+ // Take care of NaN and infinity
+ if (isNaN()) {
+ return uprv_getNaN();
+ }
+ if (isInfinite()) {
+ return uprv_getInfinity();
+ }
+
+ // stack allocate a decNumber to hold MAX_DBL_DIGITS+3 significant digits
+ char rawNumber[sizeof(decNumber) + MAX_DBL_DIGITS+3];
+ decNumber *numberPtr = (decNumber *) rawNumber;
+
+ int32_t mostSig = fInterval.getMostSignificantExclusive();
+ int32_t mostSigNonZero = fExponent + fDigits.length();
+ int32_t end = mostSig > mostSigNonZero ? mostSigNonZero : mostSig;
+ int32_t leastSig = fInterval.getLeastSignificantInclusive();
+ int32_t start = leastSig > fExponent ? leastSig : fExponent;
+ if (end <= start) {
+ return 0.0;
+ }
+ if (start < end - (MAX_DBL_DIGITS+3)) {
+ start = end - (MAX_DBL_DIGITS+3);
+ }
+ uint8_t *pos = numberPtr->lsu;
+ const char *src = &(fDigits.data()[start - fExponent]);
+ for (int32_t i = start; i < end; ++i) {
+ *pos++ = (uint8_t) (*src++);
+ }
+ numberPtr->exponent = start;
+ numberPtr->bits = 0;
+ numberPtr->digits = end - start;
+ char str[MAX_DBL_DIGITS+18];
+ uprv_decNumberToString(numberPtr, str);
+ U_ASSERT(uprv_strlen(str) < MAX_DBL_DIGITS+18);
+ char decimalSeparator = DigitList::getStrtodDecimalSeparator();
+ if (decimalSeparator != '.') {
+ char *decimalPt = strchr(str, '.');
+ if (decimalPt != NULL) {
+ *decimalPt = decimalSeparator;
+ }
+ }
+ char *unused = NULL;
+ return uprv_strtod(str, &unused);
+}
+
+void VisibleDigits::getFixedDecimal(
+ double &source, int64_t &intValue, int64_t &f, int64_t &t, int32_t &v, UBool &hasIntValue) const {
+ source = 0.0;
+ intValue = 0;
+ f = 0;
+ t = 0;
+ v = 0;
+ hasIntValue = FALSE;
+ if (isNaNOrInfinity()) {
+ return;
+ }
+
+ // source
+ if (fAbsDoubleValueSet) {
+ source = fAbsDoubleValue;
+ } else {
+ source = computeAbsDoubleValue();
+ }
+
+ // visible decimal digits
+ v = fInterval.getFracDigitCount();
+
+ // intValue
+
+ // If we initialized from an int64 just use that instead of
+ // calculating
+ if (fAbsIntValueSet) {
+ intValue = fAbsIntValue;
+ } else {
+ int32_t startPos = fInterval.getMostSignificantExclusive();
+ if (startPos > 18) {
+ startPos = 18;
+ }
+ // process the integer digits
+ for (int32_t i = startPos - 1; i >= 0; --i) {
+ intValue = intValue * 10LL + getDigitByExponent(i);
+ }
+ if (intValue == 0LL && startPos > 0) {
+ intValue = 100000000000000000LL;
+ }
+ }
+
+ // f (decimal digits)
+ // skip over any leading 0's in fraction digits.
+ int32_t idx = -1;
+ for (; idx >= -v && getDigitByExponent(idx) == 0; --idx);
+
+ // Only process up to first 18 non zero fraction digits for decimalDigits
+ // since that is all we can fit into an int64.
+ for (int32_t i = idx; i >= -v && i > idx - 18; --i) {
+ f = f * 10LL + getDigitByExponent(i);
+ }
+
+ // If we have no decimal digits, we don't have an integer value
+ hasIntValue = (f == 0LL);
+
+ // t (decimal digits without trailing zeros)
+ t = f;
+ while (t > 0 && t % 10LL == 0) {
+ t /= 10;
+ }
+}
+
+U_NAMESPACE_END
+#endif /* #if !UCONFIG_NO_FORMATTING */