1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/icu/source/i18n/digitlst.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,451 @@ 1.4 +/* 1.5 +****************************************************************************** 1.6 +* 1.7 +* Copyright (C) 1997-2012, International Business Machines 1.8 +* Corporation and others. All Rights Reserved. 1.9 +* 1.10 +****************************************************************************** 1.11 +* 1.12 +* File DIGITLST.H 1.13 +* 1.14 +* Modification History: 1.15 +* 1.16 +* Date Name Description 1.17 +* 02/25/97 aliu Converted from java. 1.18 +* 03/21/97 clhuang Updated per C++ implementation. 1.19 +* 04/15/97 aliu Changed MAX_COUNT to DBL_DIG. Changed Digit to char. 1.20 +* 09/09/97 aliu Adapted for exponential notation support. 1.21 +* 08/02/98 stephen Added nearest/even rounding 1.22 +* 06/29/99 stephen Made LONG_DIGITS a macro to satisfy SUN compiler 1.23 +* 07/09/99 stephen Removed kMaxCount (unused, for HP compiler) 1.24 +****************************************************************************** 1.25 +*/ 1.26 + 1.27 +#ifndef DIGITLST_H 1.28 +#define DIGITLST_H 1.29 + 1.30 +#include "unicode/uobject.h" 1.31 + 1.32 +#if !UCONFIG_NO_FORMATTING 1.33 +#include "unicode/decimfmt.h" 1.34 +#include <float.h> 1.35 +#include "decContext.h" 1.36 +#include "decNumber.h" 1.37 +#include "cmemory.h" 1.38 + 1.39 +// Decimal digits in a 64-bit int 1.40 +#define INT64_DIGITS 19 1.41 + 1.42 +typedef enum EDigitListValues { 1.43 + MAX_DBL_DIGITS = DBL_DIG, 1.44 + MAX_I64_DIGITS = INT64_DIGITS, 1.45 + MAX_DIGITS = MAX_I64_DIGITS, 1.46 + MAX_EXPONENT = DBL_DIG, 1.47 + DIGIT_PADDING = 3, 1.48 + DEFAULT_DIGITS = 40, // Initial storage size, will grow as needed. 1.49 + 1.50 + // "+." + fDigits + "e" + fDecimalAt 1.51 + MAX_DEC_DIGITS = MAX_DIGITS + DIGIT_PADDING + MAX_EXPONENT 1.52 +} EDigitListValues; 1.53 + 1.54 +U_NAMESPACE_BEGIN 1.55 + 1.56 +class CharString; 1.57 + 1.58 +// Export an explicit template instantiation of the MaybeStackHeaderAndArray that 1.59 +// is used as a data member of DigitList. 1.60 +// 1.61 +// MSVC requires this, even though it should not be necessary. 1.62 +// No direct access to the MaybeStackHeaderAndArray leaks out of the i18n library. 1.63 +// 1.64 +// Macintosh produces duplicate definition linker errors with the explicit template 1.65 +// instantiation. 1.66 +// 1.67 +#if !U_PLATFORM_IS_DARWIN_BASED 1.68 +template class U_I18N_API MaybeStackHeaderAndArray<decNumber, char, DEFAULT_DIGITS>; 1.69 +#endif 1.70 + 1.71 + 1.72 +enum EStackMode { kOnStack }; 1.73 + 1.74 +enum EFastpathBits { kFastpathOk = 1, kNoDecimal = 2 }; 1.75 + 1.76 +/** 1.77 + * Digit List is actually a Decimal Floating Point number. 1.78 + * The original implementation has been replaced by a thin wrapper onto a 1.79 + * decimal number from the decNumber library. 1.80 + * 1.81 + * The original DigitList API has been retained, to minimize the impact of 1.82 + * the change on the rest of the ICU formatting code. 1.83 + * 1.84 + * The change to decNumber enables support for big decimal numbers, and 1.85 + * allows rounding computations to be done directly in decimal, avoiding 1.86 + * extra, and inaccurate, conversions to and from doubles. 1.87 + * 1.88 + * Original DigitList comments: 1.89 + * 1.90 + * Digit List utility class. Private to DecimalFormat. Handles the transcoding 1.91 + * between numeric values and strings of characters. Only handles 1.92 + * non-negative numbers. The division of labor between DigitList and 1.93 + * DecimalFormat is that DigitList handles the radix 10 representation 1.94 + * issues; DecimalFormat handles the locale-specific issues such as 1.95 + * positive/negative, grouping, decimal point, currency, and so on. 1.96 + * <P> 1.97 + * A DigitList is really a representation of a floating point value. 1.98 + * It may be an integer value; we assume that a double has sufficient 1.99 + * precision to represent all digits of a long. 1.100 + * <P> 1.101 + * The DigitList representation consists of a string of characters, 1.102 + * which are the digits radix 10, from '0' to '9'. It also has a radix 1.103 + * 10 exponent associated with it. The value represented by a DigitList 1.104 + * object can be computed by mulitplying the fraction f, where 0 <= f < 1, 1.105 + * derived by placing all the digits of the list to the right of the 1.106 + * decimal point, by 10^exponent. 1.107 + * 1.108 + * -------- 1.109 + * 1.110 + * DigitList vs. decimalNumber: 1.111 + * 1.112 + * DigitList stores digits with the most significant first. 1.113 + * decNumber stores digits with the least significant first. 1.114 + * 1.115 + * DigitList, decimal point is before the most significant. 1.116 + * decNumber, decimal point is after the least signficant digit. 1.117 + * 1.118 + * digitList: 0.ddddd * 10 ^ exp 1.119 + * decNumber: ddddd. * 10 ^ exp 1.120 + * 1.121 + * digitList exponent = decNumber exponent + digit count 1.122 + * 1.123 + * digitList, digits are platform invariant chars, '0' - '9' 1.124 + * decNumber, digits are binary, one per byte, 0 - 9. 1.125 + * 1.126 + * (decNumber library is configurable in how digits are stored, ICU has configured 1.127 + * it this way for convenience in replacing the old DigitList implementation.) 1.128 + */ 1.129 +class U_I18N_API DigitList : public UMemory { // Declare external to make compiler happy 1.130 +public: 1.131 + 1.132 + DigitList(); 1.133 + ~DigitList(); 1.134 + 1.135 + /* copy constructor 1.136 + * @param DigitList The object to be copied. 1.137 + * @return the newly created object. 1.138 + */ 1.139 + DigitList(const DigitList&); // copy constructor 1.140 + 1.141 + /* assignment operator 1.142 + * @param DigitList The object to be copied. 1.143 + * @return the newly created object. 1.144 + */ 1.145 + DigitList& operator=(const DigitList&); // assignment operator 1.146 + 1.147 + /** 1.148 + * Return true if another object is semantically equal to this one. 1.149 + * @param other The DigitList to be compared for equality 1.150 + * @return true if another object is semantically equal to this one. 1.151 + * return false otherwise. 1.152 + */ 1.153 + UBool operator==(const DigitList& other) const; 1.154 + 1.155 + int32_t compare(const DigitList& other); 1.156 + 1.157 + 1.158 + inline UBool operator!=(const DigitList& other) const { return !operator==(other); } 1.159 + 1.160 + /** 1.161 + * Clears out the digits. 1.162 + * Use before appending them. 1.163 + * Typically, you set a series of digits with append, then at the point 1.164 + * you hit the decimal point, you set myDigitList.fDecimalAt = myDigitList.fCount; 1.165 + * then go on appending digits. 1.166 + */ 1.167 + void clear(void); 1.168 + 1.169 + /** 1.170 + * Remove, by rounding, any fractional part of the decimal number, 1.171 + * leaving an integer value. 1.172 + */ 1.173 + void toIntegralValue(); 1.174 + 1.175 + /** 1.176 + * Appends digits to the list. 1.177 + * CAUTION: this function is not recommended for new code. 1.178 + * In the original DigitList implementation, decimal numbers were 1.179 + * parsed by appending them to a digit list as they were encountered. 1.180 + * With the revamped DigitList based on decNumber, append is very 1.181 + * inefficient, and the interaction with the exponent value is confusing. 1.182 + * Best avoided. 1.183 + * TODO: remove this function once all use has been replaced. 1.184 + * TODO: describe alternative to append() 1.185 + * @param digit The digit to be appended. 1.186 + */ 1.187 + void append(char digit); 1.188 + 1.189 + /** 1.190 + * Utility routine to get the value of the digit list 1.191 + * Returns 0.0 if zero length. 1.192 + * @return the value of the digit list. 1.193 + */ 1.194 + double getDouble(void) const; 1.195 + 1.196 + /** 1.197 + * Utility routine to get the value of the digit list 1.198 + * Make sure that fitsIntoLong() is called before calling this function. 1.199 + * Returns 0 if zero length. 1.200 + * @return the value of the digit list, return 0 if it is zero length 1.201 + */ 1.202 + int32_t getLong(void) /*const*/; 1.203 + 1.204 + /** 1.205 + * Utility routine to get the value of the digit list 1.206 + * Make sure that fitsIntoInt64() is called before calling this function. 1.207 + * Returns 0 if zero length. 1.208 + * @return the value of the digit list, return 0 if it is zero length 1.209 + */ 1.210 + int64_t getInt64(void) /*const*/; 1.211 + 1.212 + /** 1.213 + * Utility routine to get the value of the digit list as a decimal string. 1.214 + */ 1.215 + void getDecimal(CharString &str, UErrorCode &status); 1.216 + 1.217 + /** 1.218 + * Return true if the number represented by this object can fit into 1.219 + * a long. 1.220 + * @param ignoreNegativeZero True if negative zero is ignored. 1.221 + * @return true if the number represented by this object can fit into 1.222 + * a long, return false otherwise. 1.223 + */ 1.224 + UBool fitsIntoLong(UBool ignoreNegativeZero) /*const*/; 1.225 + 1.226 + /** 1.227 + * Return true if the number represented by this object can fit into 1.228 + * an int64_t. 1.229 + * @param ignoreNegativeZero True if negative zero is ignored. 1.230 + * @return true if the number represented by this object can fit into 1.231 + * a long, return false otherwise. 1.232 + */ 1.233 + UBool fitsIntoInt64(UBool ignoreNegativeZero) /*const*/; 1.234 + 1.235 + /** 1.236 + * Utility routine to set the value of the digit list from a double. 1.237 + * @param source The value to be set 1.238 + */ 1.239 + void set(double source); 1.240 + 1.241 + /** 1.242 + * Utility routine to set the value of the digit list from a long. 1.243 + * If a non-zero maximumDigits is specified, no more than that number of 1.244 + * significant digits will be produced. 1.245 + * @param source The value to be set 1.246 + */ 1.247 + void set(int32_t source); 1.248 + 1.249 + /** 1.250 + * Utility routine to set the value of the digit list from an int64. 1.251 + * If a non-zero maximumDigits is specified, no more than that number of 1.252 + * significant digits will be produced. 1.253 + * @param source The value to be set 1.254 + */ 1.255 + void set(int64_t source); 1.256 + 1.257 + /** 1.258 + * Utility routine to set the value of the digit list from an int64. 1.259 + * Does not set the decnumber unless requested later 1.260 + * If a non-zero maximumDigits is specified, no more than that number of 1.261 + * significant digits will be produced. 1.262 + * @param source The value to be set 1.263 + */ 1.264 + void setInteger(int64_t source); 1.265 + 1.266 + /** 1.267 + * Utility routine to set the value of the digit list from a decimal number 1.268 + * string. 1.269 + * @param source The value to be set. The string must be nul-terminated. 1.270 + * @param fastpathBits special flags for fast parsing 1.271 + */ 1.272 + void set(const StringPiece &source, UErrorCode &status, uint32_t fastpathBits = 0); 1.273 + 1.274 + /** 1.275 + * Multiply this = this * arg 1.276 + * This digitlist will be expanded if necessary to accomodate the result. 1.277 + * @param arg the number to multiply by. 1.278 + */ 1.279 + void mult(const DigitList &arg, UErrorCode &status); 1.280 + 1.281 + /** 1.282 + * Divide this = this / arg 1.283 + */ 1.284 + void div(const DigitList &arg, UErrorCode &status); 1.285 + 1.286 + // The following functions replace direct access to the original DigitList implmentation 1.287 + // data structures. 1.288 + 1.289 + void setRoundingMode(DecimalFormat::ERoundingMode m); 1.290 + 1.291 + /** Test a number for zero. 1.292 + * @return TRUE if the number is zero 1.293 + */ 1.294 + UBool isZero(void) const; 1.295 + 1.296 + /** Test for a Nan 1.297 + * @return TRUE if the number is a NaN 1.298 + */ 1.299 + UBool isNaN(void) const {return decNumberIsNaN(fDecNumber);} 1.300 + 1.301 + UBool isInfinite() const {return decNumberIsInfinite(fDecNumber);} 1.302 + 1.303 + /** Reduce, or normalize. Removes trailing zeroes, adjusts exponent appropriately. */ 1.304 + void reduce(); 1.305 + 1.306 + /** Remove trailing fraction zeros, adjust exponent accordingly. */ 1.307 + void trim(); 1.308 + 1.309 + /** Set to zero */ 1.310 + void setToZero() {uprv_decNumberZero(fDecNumber);} 1.311 + 1.312 + /** get the number of digits in the decimal number */ 1.313 + int32_t digits() const {return fDecNumber->digits;} 1.314 + 1.315 + /** 1.316 + * Round the number to the given number of digits. 1.317 + * @param maximumDigits The maximum number of digits to be shown. 1.318 + * Upon return, count will be less than or equal to maximumDigits. 1.319 + */ 1.320 + void round(int32_t maximumDigits); 1.321 + 1.322 + void roundFixedPoint(int32_t maximumFractionDigits); 1.323 + 1.324 + /** Ensure capacity for digits. Grow the storage if it is currently less than 1.325 + * the requested size. Capacity is not reduced if it is already greater 1.326 + * than requested. 1.327 + */ 1.328 + void ensureCapacity(int32_t requestedSize, UErrorCode &status); 1.329 + 1.330 + UBool isPositive(void) const { return decNumberIsNegative(fDecNumber) == 0;} 1.331 + void setPositive(UBool s); 1.332 + 1.333 + void setDecimalAt(int32_t d); 1.334 + int32_t getDecimalAt(); 1.335 + 1.336 + void setCount(int32_t c); 1.337 + int32_t getCount() const; 1.338 + 1.339 + /** 1.340 + * Set the digit in platform (invariant) format, from '0'..'9' 1.341 + * @param i index of digit 1.342 + * @param v digit value, from '0' to '9' in platform invariant format 1.343 + */ 1.344 + void setDigit(int32_t i, char v); 1.345 + 1.346 + /** 1.347 + * Get the digit in platform (invariant) format, from '0'..'9' inclusive 1.348 + * @param i index of digit 1.349 + * @return invariant format of the digit 1.350 + */ 1.351 + char getDigit(int32_t i); 1.352 + 1.353 + 1.354 + /** 1.355 + * Get the digit's value, as an integer from 0..9 inclusive. 1.356 + * Note that internally this value is a decNumberUnit, but ICU configures it to be a uint8_t. 1.357 + * @param i index of digit 1.358 + * @return value of that digit 1.359 + */ 1.360 + uint8_t getDigitValue(int32_t i); 1.361 + 1.362 + 1.363 +private: 1.364 + /* 1.365 + * These data members are intentionally public and can be set directly. 1.366 + *<P> 1.367 + * The value represented is given by placing the decimal point before 1.368 + * fDigits[fDecimalAt]. If fDecimalAt is < 0, then leading zeros between 1.369 + * the decimal point and the first nonzero digit are implied. If fDecimalAt 1.370 + * is > fCount, then trailing zeros between the fDigits[fCount-1] and the 1.371 + * decimal point are implied. 1.372 + * <P> 1.373 + * Equivalently, the represented value is given by f * 10^fDecimalAt. Here 1.374 + * f is a value 0.1 <= f < 1 arrived at by placing the digits in fDigits to 1.375 + * the right of the decimal. 1.376 + * <P> 1.377 + * DigitList is normalized, so if it is non-zero, fDigits[0] is non-zero. We 1.378 + * don't allow denormalized numbers because our exponent is effectively of 1.379 + * unlimited magnitude. The fCount value contains the number of significant 1.380 + * digits present in fDigits[]. 1.381 + * <P> 1.382 + * Zero is represented by any DigitList with fCount == 0 or with each fDigits[i] 1.383 + * for all i <= fCount == '0'. 1.384 + * 1.385 + * int32_t fDecimalAt; 1.386 + * int32_t fCount; 1.387 + * UBool fIsPositive; 1.388 + * char *fDigits; 1.389 + * DecimalFormat::ERoundingMode fRoundingMode; 1.390 + */ 1.391 + 1.392 +public: 1.393 + decContext fContext; // public access to status flags. 1.394 + 1.395 +private: 1.396 + decNumber *fDecNumber; 1.397 + MaybeStackHeaderAndArray<decNumber, char, DEFAULT_DIGITS> fStorage; 1.398 + 1.399 + /* Cached double value corresponding to this decimal number. 1.400 + * This is an optimization for the formatting implementation, which may 1.401 + * ask for the double value multiple times. 1.402 + */ 1.403 + union DoubleOrInt64 { 1.404 + double fDouble; 1.405 + int64_t fInt64; 1.406 + } fUnion; 1.407 + enum EHave { 1.408 + kNone=0, 1.409 + kDouble, 1.410 + kInt64 1.411 + } fHave; 1.412 + 1.413 + 1.414 + 1.415 + UBool shouldRoundUp(int32_t maximumDigits) const; 1.416 + 1.417 + public: 1.418 + 1.419 + using UMemory::operator new; 1.420 + using UMemory::operator delete; 1.421 + 1.422 + /** 1.423 + * Placement new for stack usage 1.424 + * @internal 1.425 + */ 1.426 + static inline void * U_EXPORT2 operator new(size_t /*size*/, void * onStack, EStackMode /*mode*/) U_NO_THROW { return onStack; } 1.427 + 1.428 + /** 1.429 + * Placement delete for stack usage 1.430 + * @internal 1.431 + */ 1.432 + static inline void U_EXPORT2 operator delete(void * /*ptr*/, void * /*onStack*/, EStackMode /*mode*/) U_NO_THROW {} 1.433 + 1.434 + private: 1.435 + inline void internalSetDouble(double d) { 1.436 + fHave = kDouble; 1.437 + fUnion.fDouble=d; 1.438 + } 1.439 + inline void internalSetInt64(int64_t d) { 1.440 + fHave = kInt64; 1.441 + fUnion.fInt64=d; 1.442 + } 1.443 + inline void internalClear() { 1.444 + fHave = kNone; 1.445 + } 1.446 +}; 1.447 + 1.448 + 1.449 +U_NAMESPACE_END 1.450 + 1.451 +#endif // #if !UCONFIG_NO_FORMATTING 1.452 +#endif // _DIGITLST 1.453 + 1.454 +//eof