DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (31ec81b5d7bb)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451
/*
******************************************************************************
*
*   Copyright (C) 1997-2012, International Business Machines
*   Corporation and others.  All Rights Reserved.
*
******************************************************************************
*
* File DIGITLST.H
*
* Modification History:
*
*   Date        Name        Description
*   02/25/97    aliu        Converted from java.
*   03/21/97    clhuang     Updated per C++ implementation.
*   04/15/97    aliu        Changed MAX_COUNT to DBL_DIG.  Changed Digit to char.
*   09/09/97    aliu        Adapted for exponential notation support.
*   08/02/98    stephen     Added nearest/even rounding
*   06/29/99    stephen     Made LONG_DIGITS a macro to satisfy SUN compiler
*   07/09/99    stephen     Removed kMaxCount (unused, for HP compiler)
******************************************************************************
*/
 
#ifndef DIGITLST_H
#define DIGITLST_H
 
#include "unicode/uobject.h"

#if !UCONFIG_NO_FORMATTING
#include "unicode/decimfmt.h"
#include <float.h>
#include "decContext.h"
#include "decNumber.h"
#include "cmemory.h"

// Decimal digits in a 64-bit int
#define INT64_DIGITS 19

typedef enum EDigitListValues {
    MAX_DBL_DIGITS = DBL_DIG,
    MAX_I64_DIGITS = INT64_DIGITS,
    MAX_DIGITS = MAX_I64_DIGITS,
    MAX_EXPONENT = DBL_DIG,
    DIGIT_PADDING = 3,
    DEFAULT_DIGITS = 40,   // Initial storage size, will grow as needed.

     // "+." + fDigits + "e" + fDecimalAt
    MAX_DEC_DIGITS = MAX_DIGITS + DIGIT_PADDING + MAX_EXPONENT
} EDigitListValues;

U_NAMESPACE_BEGIN

class CharString;

// Export an explicit template instantiation of the MaybeStackHeaderAndArray that
//    is used as a data member of DigitList.
//
//    MSVC requires this, even though it should not be necessary. 
//    No direct access to the MaybeStackHeaderAndArray leaks out of the i18n library.
//
//    Macintosh produces duplicate definition linker errors with the explicit template
//    instantiation.
//
#if !U_PLATFORM_IS_DARWIN_BASED
template class U_I18N_API MaybeStackHeaderAndArray<decNumber, char, DEFAULT_DIGITS>;
#endif


enum EStackMode { kOnStack };

enum EFastpathBits { kFastpathOk = 1, kNoDecimal = 2 };

/**
 * Digit List is actually a Decimal Floating Point number.
 * The original implementation has been replaced by a thin wrapper onto a 
 * decimal number from the decNumber library.
 *
 * The original DigitList API has been retained, to minimize the impact of
 * the change on the rest of the ICU formatting code.
 *
 * The change to decNumber enables support for big decimal numbers, and
 * allows rounding computations to be done directly in decimal, avoiding
 * extra, and inaccurate, conversions to and from doubles.
 *
 * Original DigitList comments:
 *
 * Digit List utility class. Private to DecimalFormat.  Handles the transcoding
 * between numeric values and strings of characters.  Only handles
 * non-negative numbers.  The division of labor between DigitList and
 * DecimalFormat is that DigitList handles the radix 10 representation
 * issues; DecimalFormat handles the locale-specific issues such as
 * positive/negative, grouping, decimal point, currency, and so on.
 * <P>
 * A DigitList is really a representation of a floating point value.
 * It may be an integer value; we assume that a double has sufficient
 * precision to represent all digits of a long.
 * <P>
 * The DigitList representation consists of a string of characters,
 * which are the digits radix 10, from '0' to '9'.  It also has a radix
 * 10 exponent associated with it.  The value represented by a DigitList
 * object can be computed by mulitplying the fraction f, where 0 <= f < 1,
 * derived by placing all the digits of the list to the right of the
 * decimal point, by 10^exponent.
 *
 * --------
 *
 * DigitList vs. decimalNumber:
 *
 *    DigitList stores digits with the most significant first.
 *    decNumber stores digits with the least significant first.
 *
 *    DigitList, decimal point is before the most significant.
 *    decNumber, decimal point is after the least signficant digit.
 *
 *       digitList:    0.ddddd * 10 ^ exp
 *       decNumber:    ddddd. * 10 ^ exp
 *
 *       digitList exponent = decNumber exponent + digit count
 *
 *    digitList, digits are platform invariant chars, '0' - '9'
 *    decNumber, digits are binary, one per byte, 0 - 9.
 *
 *       (decNumber library is configurable in how digits are stored, ICU has configured
 *        it this way for convenience in replacing the old DigitList implementation.)
 */
class U_I18N_API DigitList : public UMemory { // Declare external to make compiler happy
public:

    DigitList();
    ~DigitList();

    /* copy constructor
     * @param DigitList The object to be copied.
     * @return the newly created object. 
     */
    DigitList(const DigitList&); // copy constructor

    /* assignment operator
     * @param DigitList The object to be copied.
     * @return the newly created object.
     */
    DigitList& operator=(const DigitList&);  // assignment operator

    /**
     * Return true if another object is semantically equal to this one.
     * @param other The DigitList to be compared for equality
     * @return true if another object is semantically equal to this one.
     * return false otherwise.
     */
    UBool operator==(const DigitList& other) const;

    int32_t  compare(const DigitList& other);


    inline UBool operator!=(const DigitList& other) const { return !operator==(other); }

    /**
     * Clears out the digits.
     * Use before appending them.
     * Typically, you set a series of digits with append, then at the point
     * you hit the decimal point, you set myDigitList.fDecimalAt = myDigitList.fCount;
     * then go on appending digits.
     */
    void clear(void);

    /**
     *  Remove, by rounding, any fractional part of the decimal number,
     *  leaving an integer value.
     */
    void toIntegralValue();
    
    /**
     * Appends digits to the list. 
     *    CAUTION:  this function is not recommended for new code.
     *              In the original DigitList implementation, decimal numbers were
     *              parsed by appending them to a digit list as they were encountered.
     *              With the revamped DigitList based on decNumber, append is very
     *              inefficient, and the interaction with the exponent value is confusing.
     *              Best avoided.
     *              TODO:  remove this function once all use has been replaced.
     *              TODO:  describe alternative to append()
     * @param digit The digit to be appended.
     */
    void append(char digit);

    /**
     * Utility routine to get the value of the digit list
     * Returns 0.0 if zero length.
     * @return the value of the digit list.
     */
    double getDouble(void) const;

    /**
     * Utility routine to get the value of the digit list
     * Make sure that fitsIntoLong() is called before calling this function.
     * Returns 0 if zero length.
     * @return the value of the digit list, return 0 if it is zero length
     */
    int32_t getLong(void) /*const*/;

    /**
     * Utility routine to get the value of the digit list
     * Make sure that fitsIntoInt64() is called before calling this function.
     * Returns 0 if zero length.
     * @return the value of the digit list, return 0 if it is zero length
     */
    int64_t getInt64(void) /*const*/;

    /**
     *  Utility routine to get the value of the digit list as a decimal string.
     */
    void getDecimal(CharString &str, UErrorCode &status);

    /**
     * Return true if the number represented by this object can fit into
     * a long.
     * @param ignoreNegativeZero True if negative zero is ignored.
     * @return true if the number represented by this object can fit into
     * a long, return false otherwise.
     */
    UBool fitsIntoLong(UBool ignoreNegativeZero) /*const*/;

    /**
     * Return true if the number represented by this object can fit into
     * an int64_t.
     * @param ignoreNegativeZero True if negative zero is ignored.
     * @return true if the number represented by this object can fit into
     * a long, return false otherwise.
     */
    UBool fitsIntoInt64(UBool ignoreNegativeZero) /*const*/;

    /**
     * Utility routine to set the value of the digit list from a double.
     * @param source The value to be set
     */
    void set(double source);

    /**
     * Utility routine to set the value of the digit list from a long.
     * If a non-zero maximumDigits is specified, no more than that number of
     * significant digits will be produced.
     * @param source The value to be set
     */
    void set(int32_t source);

    /**
     * Utility routine to set the value of the digit list from an int64.
     * If a non-zero maximumDigits is specified, no more than that number of
     * significant digits will be produced.
     * @param source The value to be set
     */
    void set(int64_t source);

    /**
     * Utility routine to set the value of the digit list from an int64.
     * Does not set the decnumber unless requested later
     * If a non-zero maximumDigits is specified, no more than that number of
     * significant digits will be produced.
     * @param source The value to be set
     */
    void setInteger(int64_t source);

   /**
     * Utility routine to set the value of the digit list from a decimal number
     * string.
     * @param source The value to be set.  The string must be nul-terminated.
     * @param fastpathBits special flags for fast parsing
     */
    void set(const StringPiece &source, UErrorCode &status, uint32_t fastpathBits = 0);

    /**
     * Multiply    this = this * arg
     *    This digitlist will be expanded if necessary to accomodate the result.
     *  @param arg  the number to multiply by.
     */
    void mult(const DigitList &arg, UErrorCode &status);

    /**
     *   Divide    this = this / arg
     */
    void div(const DigitList &arg, UErrorCode &status);

    //  The following functions replace direct access to the original DigitList implmentation
    //  data structures.

    void setRoundingMode(DecimalFormat::ERoundingMode m); 

    /** Test a number for zero.
     * @return  TRUE if the number is zero
     */
    UBool isZero(void) const;

    /** Test for a Nan
     * @return  TRUE if the number is a NaN
     */
    UBool isNaN(void) const {return decNumberIsNaN(fDecNumber);}

    UBool isInfinite() const {return decNumberIsInfinite(fDecNumber);}

    /**  Reduce, or normalize.  Removes trailing zeroes, adjusts exponent appropriately. */
    void     reduce();

    /**  Remove trailing fraction zeros, adjust exponent accordingly. */
    void     trim();

    /** Set to zero */
    void     setToZero() {uprv_decNumberZero(fDecNumber);}

    /** get the number of digits in the decimal number */
    int32_t  digits() const {return fDecNumber->digits;}

    /**
     * Round the number 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 round(int32_t maximumDigits);

    void roundFixedPoint(int32_t maximumFractionDigits);

    /** Ensure capacity for digits.  Grow the storage if it is currently less than
     *      the requested size.   Capacity is not reduced if it is already greater
     *      than requested.
     */
    void  ensureCapacity(int32_t  requestedSize, UErrorCode &status); 

    UBool    isPositive(void) const { return decNumberIsNegative(fDecNumber) == 0;}
    void     setPositive(UBool s); 

    void     setDecimalAt(int32_t d);
    int32_t  getDecimalAt();

    void     setCount(int32_t c);
    int32_t  getCount() const;
    
    /**
     * Set the digit in platform (invariant) format, from '0'..'9'
     * @param i index of digit
     * @param v digit value, from '0' to '9' in platform invariant format
     */
    void     setDigit(int32_t i, char v);

    /**
     * Get the digit in platform (invariant) format, from '0'..'9' inclusive
     * @param i index of digit
     * @return invariant format of the digit
     */
    char     getDigit(int32_t i);


    /**
     * Get the digit's value, as an integer from 0..9 inclusive.
     * Note that internally this value is a decNumberUnit, but ICU configures it to be a uint8_t.
     * @param i index of digit
     * @return value of that digit
     */
    uint8_t     getDigitValue(int32_t i);


private:
    /*
     * These data members are intentionally public and can be set directly.
     *<P>
     * The value represented is given by placing the decimal point before
     * fDigits[fDecimalAt].  If fDecimalAt is < 0, then leading zeros between
     * the decimal point and the first nonzero digit are implied.  If fDecimalAt
     * is > fCount, then trailing zeros between the fDigits[fCount-1] and the
     * decimal point are implied.
     * <P>
     * Equivalently, the represented value is given by f * 10^fDecimalAt.  Here
     * f is a value 0.1 <= f < 1 arrived at by placing the digits in fDigits to
     * the right of the decimal.
     * <P>
     * DigitList is normalized, so if it is non-zero, fDigits[0] is non-zero.  We
     * don't allow denormalized numbers because our exponent is effectively of
     * unlimited magnitude.  The fCount value contains the number of significant
     * digits present in fDigits[].
     * <P>
     * Zero is represented by any DigitList with fCount == 0 or with each fDigits[i]
     * for all i <= fCount == '0'.
     *
     * int32_t                         fDecimalAt;
     * int32_t                         fCount;
     * UBool                           fIsPositive;
     * char                            *fDigits;
     * DecimalFormat::ERoundingMode    fRoundingMode;
     */

public:
    decContext    fContext;   // public access to status flags.  

private:
    decNumber     *fDecNumber;
    MaybeStackHeaderAndArray<decNumber, char, DEFAULT_DIGITS>  fStorage;

    /* Cached double value corresponding to this decimal number.
     * This is an optimization for the formatting implementation, which may
     * ask for the double value multiple times.
     */
    union DoubleOrInt64 {
      double        fDouble;
      int64_t       fInt64;
    } fUnion;
    enum EHave {
      kNone=0,
      kDouble,
      kInt64
    } fHave;



    UBool shouldRoundUp(int32_t maximumDigits) const;

 public:

    using UMemory::operator new;
    using UMemory::operator delete;

    /**
     * Placement new for stack usage
     * @internal
     */
    static inline void * U_EXPORT2 operator new(size_t /*size*/, void * onStack, EStackMode  /*mode*/) U_NO_THROW { return onStack; }

    /**
     * Placement delete for stack usage
     * @internal
     */
    static inline void U_EXPORT2 operator delete(void * /*ptr*/, void * /*onStack*/, EStackMode /*mode*/)  U_NO_THROW {}

 private:
    inline void internalSetDouble(double d) {
      fHave = kDouble;
      fUnion.fDouble=d;
    }
    inline void internalSetInt64(int64_t d) {
      fHave = kInt64;
      fUnion.fInt64=d;
    }
    inline void internalClear() {
      fHave = kNone;
    }
};


U_NAMESPACE_END

#endif // #if !UCONFIG_NO_FORMATTING
#endif // _DIGITLST

//eof