intl/icu/source/i18n/digitlst.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /*
michael@0 2 ******************************************************************************
michael@0 3 *
michael@0 4 * Copyright (C) 1997-2012, International Business Machines
michael@0 5 * Corporation and others. All Rights Reserved.
michael@0 6 *
michael@0 7 ******************************************************************************
michael@0 8 *
michael@0 9 * File DIGITLST.H
michael@0 10 *
michael@0 11 * Modification History:
michael@0 12 *
michael@0 13 * Date Name Description
michael@0 14 * 02/25/97 aliu Converted from java.
michael@0 15 * 03/21/97 clhuang Updated per C++ implementation.
michael@0 16 * 04/15/97 aliu Changed MAX_COUNT to DBL_DIG. Changed Digit to char.
michael@0 17 * 09/09/97 aliu Adapted for exponential notation support.
michael@0 18 * 08/02/98 stephen Added nearest/even rounding
michael@0 19 * 06/29/99 stephen Made LONG_DIGITS a macro to satisfy SUN compiler
michael@0 20 * 07/09/99 stephen Removed kMaxCount (unused, for HP compiler)
michael@0 21 ******************************************************************************
michael@0 22 */
michael@0 23
michael@0 24 #ifndef DIGITLST_H
michael@0 25 #define DIGITLST_H
michael@0 26
michael@0 27 #include "unicode/uobject.h"
michael@0 28
michael@0 29 #if !UCONFIG_NO_FORMATTING
michael@0 30 #include "unicode/decimfmt.h"
michael@0 31 #include <float.h>
michael@0 32 #include "decContext.h"
michael@0 33 #include "decNumber.h"
michael@0 34 #include "cmemory.h"
michael@0 35
michael@0 36 // Decimal digits in a 64-bit int
michael@0 37 #define INT64_DIGITS 19
michael@0 38
michael@0 39 typedef enum EDigitListValues {
michael@0 40 MAX_DBL_DIGITS = DBL_DIG,
michael@0 41 MAX_I64_DIGITS = INT64_DIGITS,
michael@0 42 MAX_DIGITS = MAX_I64_DIGITS,
michael@0 43 MAX_EXPONENT = DBL_DIG,
michael@0 44 DIGIT_PADDING = 3,
michael@0 45 DEFAULT_DIGITS = 40, // Initial storage size, will grow as needed.
michael@0 46
michael@0 47 // "+." + fDigits + "e" + fDecimalAt
michael@0 48 MAX_DEC_DIGITS = MAX_DIGITS + DIGIT_PADDING + MAX_EXPONENT
michael@0 49 } EDigitListValues;
michael@0 50
michael@0 51 U_NAMESPACE_BEGIN
michael@0 52
michael@0 53 class CharString;
michael@0 54
michael@0 55 // Export an explicit template instantiation of the MaybeStackHeaderAndArray that
michael@0 56 // is used as a data member of DigitList.
michael@0 57 //
michael@0 58 // MSVC requires this, even though it should not be necessary.
michael@0 59 // No direct access to the MaybeStackHeaderAndArray leaks out of the i18n library.
michael@0 60 //
michael@0 61 // Macintosh produces duplicate definition linker errors with the explicit template
michael@0 62 // instantiation.
michael@0 63 //
michael@0 64 #if !U_PLATFORM_IS_DARWIN_BASED
michael@0 65 template class U_I18N_API MaybeStackHeaderAndArray<decNumber, char, DEFAULT_DIGITS>;
michael@0 66 #endif
michael@0 67
michael@0 68
michael@0 69 enum EStackMode { kOnStack };
michael@0 70
michael@0 71 enum EFastpathBits { kFastpathOk = 1, kNoDecimal = 2 };
michael@0 72
michael@0 73 /**
michael@0 74 * Digit List is actually a Decimal Floating Point number.
michael@0 75 * The original implementation has been replaced by a thin wrapper onto a
michael@0 76 * decimal number from the decNumber library.
michael@0 77 *
michael@0 78 * The original DigitList API has been retained, to minimize the impact of
michael@0 79 * the change on the rest of the ICU formatting code.
michael@0 80 *
michael@0 81 * The change to decNumber enables support for big decimal numbers, and
michael@0 82 * allows rounding computations to be done directly in decimal, avoiding
michael@0 83 * extra, and inaccurate, conversions to and from doubles.
michael@0 84 *
michael@0 85 * Original DigitList comments:
michael@0 86 *
michael@0 87 * Digit List utility class. Private to DecimalFormat. Handles the transcoding
michael@0 88 * between numeric values and strings of characters. Only handles
michael@0 89 * non-negative numbers. The division of labor between DigitList and
michael@0 90 * DecimalFormat is that DigitList handles the radix 10 representation
michael@0 91 * issues; DecimalFormat handles the locale-specific issues such as
michael@0 92 * positive/negative, grouping, decimal point, currency, and so on.
michael@0 93 * <P>
michael@0 94 * A DigitList is really a representation of a floating point value.
michael@0 95 * It may be an integer value; we assume that a double has sufficient
michael@0 96 * precision to represent all digits of a long.
michael@0 97 * <P>
michael@0 98 * The DigitList representation consists of a string of characters,
michael@0 99 * which are the digits radix 10, from '0' to '9'. It also has a radix
michael@0 100 * 10 exponent associated with it. The value represented by a DigitList
michael@0 101 * object can be computed by mulitplying the fraction f, where 0 <= f < 1,
michael@0 102 * derived by placing all the digits of the list to the right of the
michael@0 103 * decimal point, by 10^exponent.
michael@0 104 *
michael@0 105 * --------
michael@0 106 *
michael@0 107 * DigitList vs. decimalNumber:
michael@0 108 *
michael@0 109 * DigitList stores digits with the most significant first.
michael@0 110 * decNumber stores digits with the least significant first.
michael@0 111 *
michael@0 112 * DigitList, decimal point is before the most significant.
michael@0 113 * decNumber, decimal point is after the least signficant digit.
michael@0 114 *
michael@0 115 * digitList: 0.ddddd * 10 ^ exp
michael@0 116 * decNumber: ddddd. * 10 ^ exp
michael@0 117 *
michael@0 118 * digitList exponent = decNumber exponent + digit count
michael@0 119 *
michael@0 120 * digitList, digits are platform invariant chars, '0' - '9'
michael@0 121 * decNumber, digits are binary, one per byte, 0 - 9.
michael@0 122 *
michael@0 123 * (decNumber library is configurable in how digits are stored, ICU has configured
michael@0 124 * it this way for convenience in replacing the old DigitList implementation.)
michael@0 125 */
michael@0 126 class U_I18N_API DigitList : public UMemory { // Declare external to make compiler happy
michael@0 127 public:
michael@0 128
michael@0 129 DigitList();
michael@0 130 ~DigitList();
michael@0 131
michael@0 132 /* copy constructor
michael@0 133 * @param DigitList The object to be copied.
michael@0 134 * @return the newly created object.
michael@0 135 */
michael@0 136 DigitList(const DigitList&); // copy constructor
michael@0 137
michael@0 138 /* assignment operator
michael@0 139 * @param DigitList The object to be copied.
michael@0 140 * @return the newly created object.
michael@0 141 */
michael@0 142 DigitList& operator=(const DigitList&); // assignment operator
michael@0 143
michael@0 144 /**
michael@0 145 * Return true if another object is semantically equal to this one.
michael@0 146 * @param other The DigitList to be compared for equality
michael@0 147 * @return true if another object is semantically equal to this one.
michael@0 148 * return false otherwise.
michael@0 149 */
michael@0 150 UBool operator==(const DigitList& other) const;
michael@0 151
michael@0 152 int32_t compare(const DigitList& other);
michael@0 153
michael@0 154
michael@0 155 inline UBool operator!=(const DigitList& other) const { return !operator==(other); }
michael@0 156
michael@0 157 /**
michael@0 158 * Clears out the digits.
michael@0 159 * Use before appending them.
michael@0 160 * Typically, you set a series of digits with append, then at the point
michael@0 161 * you hit the decimal point, you set myDigitList.fDecimalAt = myDigitList.fCount;
michael@0 162 * then go on appending digits.
michael@0 163 */
michael@0 164 void clear(void);
michael@0 165
michael@0 166 /**
michael@0 167 * Remove, by rounding, any fractional part of the decimal number,
michael@0 168 * leaving an integer value.
michael@0 169 */
michael@0 170 void toIntegralValue();
michael@0 171
michael@0 172 /**
michael@0 173 * Appends digits to the list.
michael@0 174 * CAUTION: this function is not recommended for new code.
michael@0 175 * In the original DigitList implementation, decimal numbers were
michael@0 176 * parsed by appending them to a digit list as they were encountered.
michael@0 177 * With the revamped DigitList based on decNumber, append is very
michael@0 178 * inefficient, and the interaction with the exponent value is confusing.
michael@0 179 * Best avoided.
michael@0 180 * TODO: remove this function once all use has been replaced.
michael@0 181 * TODO: describe alternative to append()
michael@0 182 * @param digit The digit to be appended.
michael@0 183 */
michael@0 184 void append(char digit);
michael@0 185
michael@0 186 /**
michael@0 187 * Utility routine to get the value of the digit list
michael@0 188 * Returns 0.0 if zero length.
michael@0 189 * @return the value of the digit list.
michael@0 190 */
michael@0 191 double getDouble(void) const;
michael@0 192
michael@0 193 /**
michael@0 194 * Utility routine to get the value of the digit list
michael@0 195 * Make sure that fitsIntoLong() is called before calling this function.
michael@0 196 * Returns 0 if zero length.
michael@0 197 * @return the value of the digit list, return 0 if it is zero length
michael@0 198 */
michael@0 199 int32_t getLong(void) /*const*/;
michael@0 200
michael@0 201 /**
michael@0 202 * Utility routine to get the value of the digit list
michael@0 203 * Make sure that fitsIntoInt64() is called before calling this function.
michael@0 204 * Returns 0 if zero length.
michael@0 205 * @return the value of the digit list, return 0 if it is zero length
michael@0 206 */
michael@0 207 int64_t getInt64(void) /*const*/;
michael@0 208
michael@0 209 /**
michael@0 210 * Utility routine to get the value of the digit list as a decimal string.
michael@0 211 */
michael@0 212 void getDecimal(CharString &str, UErrorCode &status);
michael@0 213
michael@0 214 /**
michael@0 215 * Return true if the number represented by this object can fit into
michael@0 216 * a long.
michael@0 217 * @param ignoreNegativeZero True if negative zero is ignored.
michael@0 218 * @return true if the number represented by this object can fit into
michael@0 219 * a long, return false otherwise.
michael@0 220 */
michael@0 221 UBool fitsIntoLong(UBool ignoreNegativeZero) /*const*/;
michael@0 222
michael@0 223 /**
michael@0 224 * Return true if the number represented by this object can fit into
michael@0 225 * an int64_t.
michael@0 226 * @param ignoreNegativeZero True if negative zero is ignored.
michael@0 227 * @return true if the number represented by this object can fit into
michael@0 228 * a long, return false otherwise.
michael@0 229 */
michael@0 230 UBool fitsIntoInt64(UBool ignoreNegativeZero) /*const*/;
michael@0 231
michael@0 232 /**
michael@0 233 * Utility routine to set the value of the digit list from a double.
michael@0 234 * @param source The value to be set
michael@0 235 */
michael@0 236 void set(double source);
michael@0 237
michael@0 238 /**
michael@0 239 * Utility routine to set the value of the digit list from a long.
michael@0 240 * If a non-zero maximumDigits is specified, no more than that number of
michael@0 241 * significant digits will be produced.
michael@0 242 * @param source The value to be set
michael@0 243 */
michael@0 244 void set(int32_t source);
michael@0 245
michael@0 246 /**
michael@0 247 * Utility routine to set the value of the digit list from an int64.
michael@0 248 * If a non-zero maximumDigits is specified, no more than that number of
michael@0 249 * significant digits will be produced.
michael@0 250 * @param source The value to be set
michael@0 251 */
michael@0 252 void set(int64_t source);
michael@0 253
michael@0 254 /**
michael@0 255 * Utility routine to set the value of the digit list from an int64.
michael@0 256 * Does not set the decnumber unless requested later
michael@0 257 * If a non-zero maximumDigits is specified, no more than that number of
michael@0 258 * significant digits will be produced.
michael@0 259 * @param source The value to be set
michael@0 260 */
michael@0 261 void setInteger(int64_t source);
michael@0 262
michael@0 263 /**
michael@0 264 * Utility routine to set the value of the digit list from a decimal number
michael@0 265 * string.
michael@0 266 * @param source The value to be set. The string must be nul-terminated.
michael@0 267 * @param fastpathBits special flags for fast parsing
michael@0 268 */
michael@0 269 void set(const StringPiece &source, UErrorCode &status, uint32_t fastpathBits = 0);
michael@0 270
michael@0 271 /**
michael@0 272 * Multiply this = this * arg
michael@0 273 * This digitlist will be expanded if necessary to accomodate the result.
michael@0 274 * @param arg the number to multiply by.
michael@0 275 */
michael@0 276 void mult(const DigitList &arg, UErrorCode &status);
michael@0 277
michael@0 278 /**
michael@0 279 * Divide this = this / arg
michael@0 280 */
michael@0 281 void div(const DigitList &arg, UErrorCode &status);
michael@0 282
michael@0 283 // The following functions replace direct access to the original DigitList implmentation
michael@0 284 // data structures.
michael@0 285
michael@0 286 void setRoundingMode(DecimalFormat::ERoundingMode m);
michael@0 287
michael@0 288 /** Test a number for zero.
michael@0 289 * @return TRUE if the number is zero
michael@0 290 */
michael@0 291 UBool isZero(void) const;
michael@0 292
michael@0 293 /** Test for a Nan
michael@0 294 * @return TRUE if the number is a NaN
michael@0 295 */
michael@0 296 UBool isNaN(void) const {return decNumberIsNaN(fDecNumber);}
michael@0 297
michael@0 298 UBool isInfinite() const {return decNumberIsInfinite(fDecNumber);}
michael@0 299
michael@0 300 /** Reduce, or normalize. Removes trailing zeroes, adjusts exponent appropriately. */
michael@0 301 void reduce();
michael@0 302
michael@0 303 /** Remove trailing fraction zeros, adjust exponent accordingly. */
michael@0 304 void trim();
michael@0 305
michael@0 306 /** Set to zero */
michael@0 307 void setToZero() {uprv_decNumberZero(fDecNumber);}
michael@0 308
michael@0 309 /** get the number of digits in the decimal number */
michael@0 310 int32_t digits() const {return fDecNumber->digits;}
michael@0 311
michael@0 312 /**
michael@0 313 * Round the number to the given number of digits.
michael@0 314 * @param maximumDigits The maximum number of digits to be shown.
michael@0 315 * Upon return, count will be less than or equal to maximumDigits.
michael@0 316 */
michael@0 317 void round(int32_t maximumDigits);
michael@0 318
michael@0 319 void roundFixedPoint(int32_t maximumFractionDigits);
michael@0 320
michael@0 321 /** Ensure capacity for digits. Grow the storage if it is currently less than
michael@0 322 * the requested size. Capacity is not reduced if it is already greater
michael@0 323 * than requested.
michael@0 324 */
michael@0 325 void ensureCapacity(int32_t requestedSize, UErrorCode &status);
michael@0 326
michael@0 327 UBool isPositive(void) const { return decNumberIsNegative(fDecNumber) == 0;}
michael@0 328 void setPositive(UBool s);
michael@0 329
michael@0 330 void setDecimalAt(int32_t d);
michael@0 331 int32_t getDecimalAt();
michael@0 332
michael@0 333 void setCount(int32_t c);
michael@0 334 int32_t getCount() const;
michael@0 335
michael@0 336 /**
michael@0 337 * Set the digit in platform (invariant) format, from '0'..'9'
michael@0 338 * @param i index of digit
michael@0 339 * @param v digit value, from '0' to '9' in platform invariant format
michael@0 340 */
michael@0 341 void setDigit(int32_t i, char v);
michael@0 342
michael@0 343 /**
michael@0 344 * Get the digit in platform (invariant) format, from '0'..'9' inclusive
michael@0 345 * @param i index of digit
michael@0 346 * @return invariant format of the digit
michael@0 347 */
michael@0 348 char getDigit(int32_t i);
michael@0 349
michael@0 350
michael@0 351 /**
michael@0 352 * Get the digit's value, as an integer from 0..9 inclusive.
michael@0 353 * Note that internally this value is a decNumberUnit, but ICU configures it to be a uint8_t.
michael@0 354 * @param i index of digit
michael@0 355 * @return value of that digit
michael@0 356 */
michael@0 357 uint8_t getDigitValue(int32_t i);
michael@0 358
michael@0 359
michael@0 360 private:
michael@0 361 /*
michael@0 362 * These data members are intentionally public and can be set directly.
michael@0 363 *<P>
michael@0 364 * The value represented is given by placing the decimal point before
michael@0 365 * fDigits[fDecimalAt]. If fDecimalAt is < 0, then leading zeros between
michael@0 366 * the decimal point and the first nonzero digit are implied. If fDecimalAt
michael@0 367 * is > fCount, then trailing zeros between the fDigits[fCount-1] and the
michael@0 368 * decimal point are implied.
michael@0 369 * <P>
michael@0 370 * Equivalently, the represented value is given by f * 10^fDecimalAt. Here
michael@0 371 * f is a value 0.1 <= f < 1 arrived at by placing the digits in fDigits to
michael@0 372 * the right of the decimal.
michael@0 373 * <P>
michael@0 374 * DigitList is normalized, so if it is non-zero, fDigits[0] is non-zero. We
michael@0 375 * don't allow denormalized numbers because our exponent is effectively of
michael@0 376 * unlimited magnitude. The fCount value contains the number of significant
michael@0 377 * digits present in fDigits[].
michael@0 378 * <P>
michael@0 379 * Zero is represented by any DigitList with fCount == 0 or with each fDigits[i]
michael@0 380 * for all i <= fCount == '0'.
michael@0 381 *
michael@0 382 * int32_t fDecimalAt;
michael@0 383 * int32_t fCount;
michael@0 384 * UBool fIsPositive;
michael@0 385 * char *fDigits;
michael@0 386 * DecimalFormat::ERoundingMode fRoundingMode;
michael@0 387 */
michael@0 388
michael@0 389 public:
michael@0 390 decContext fContext; // public access to status flags.
michael@0 391
michael@0 392 private:
michael@0 393 decNumber *fDecNumber;
michael@0 394 MaybeStackHeaderAndArray<decNumber, char, DEFAULT_DIGITS> fStorage;
michael@0 395
michael@0 396 /* Cached double value corresponding to this decimal number.
michael@0 397 * This is an optimization for the formatting implementation, which may
michael@0 398 * ask for the double value multiple times.
michael@0 399 */
michael@0 400 union DoubleOrInt64 {
michael@0 401 double fDouble;
michael@0 402 int64_t fInt64;
michael@0 403 } fUnion;
michael@0 404 enum EHave {
michael@0 405 kNone=0,
michael@0 406 kDouble,
michael@0 407 kInt64
michael@0 408 } fHave;
michael@0 409
michael@0 410
michael@0 411
michael@0 412 UBool shouldRoundUp(int32_t maximumDigits) const;
michael@0 413
michael@0 414 public:
michael@0 415
michael@0 416 using UMemory::operator new;
michael@0 417 using UMemory::operator delete;
michael@0 418
michael@0 419 /**
michael@0 420 * Placement new for stack usage
michael@0 421 * @internal
michael@0 422 */
michael@0 423 static inline void * U_EXPORT2 operator new(size_t /*size*/, void * onStack, EStackMode /*mode*/) U_NO_THROW { return onStack; }
michael@0 424
michael@0 425 /**
michael@0 426 * Placement delete for stack usage
michael@0 427 * @internal
michael@0 428 */
michael@0 429 static inline void U_EXPORT2 operator delete(void * /*ptr*/, void * /*onStack*/, EStackMode /*mode*/) U_NO_THROW {}
michael@0 430
michael@0 431 private:
michael@0 432 inline void internalSetDouble(double d) {
michael@0 433 fHave = kDouble;
michael@0 434 fUnion.fDouble=d;
michael@0 435 }
michael@0 436 inline void internalSetInt64(int64_t d) {
michael@0 437 fHave = kInt64;
michael@0 438 fUnion.fInt64=d;
michael@0 439 }
michael@0 440 inline void internalClear() {
michael@0 441 fHave = kNone;
michael@0 442 }
michael@0 443 };
michael@0 444
michael@0 445
michael@0 446 U_NAMESPACE_END
michael@0 447
michael@0 448 #endif // #if !UCONFIG_NO_FORMATTING
michael@0 449 #endif // _DIGITLST
michael@0 450
michael@0 451 //eof

mercurial