intl/icu/source/i18n/digitlst.h

changeset 0
6474c204b198
     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

mercurial