intl/icu/source/i18n/digitlst.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial