1/*
2******************************************************************************
3*
4*   Copyright (C) 1997-2013, 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*/
23
24#ifndef DIGITLST_H
25#define DIGITLST_H
26
27#include "unicode/uobject.h"
28
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"
35
36// Decimal digits in a 64-bit int
37#define INT64_DIGITS 19
38
39typedef 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.
46
47     // "+." + fDigits + "e" + fDecimalAt
48    MAX_DEC_DIGITS = MAX_DIGITS + DIGIT_PADDING + MAX_EXPONENT
49} EDigitListValues;
50
51U_NAMESPACE_BEGIN
52
53class CharString;
54
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
65template class U_I18N_API MaybeStackHeaderAndArray<decNumber, char, DEFAULT_DIGITS>;
66#endif
67
68
69enum EStackMode { kOnStack };
70
71enum EFastpathBits { kFastpathOk = 1, kNoDecimal = 2 };
72
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 */
126class U_I18N_API DigitList : public UMemory { // Declare external to make compiler happy
127public:
128
129    DigitList();
130    ~DigitList();
131
132    /* copy constructor
133     * @param DigitList The object to be copied.
134     * @return the newly created object.
135     */
136    DigitList(const DigitList&); // copy constructor
137
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
143
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;
151
152    int32_t  compare(const DigitList& other);
153
154
155    inline UBool operator!=(const DigitList& other) const { return !operator==(other); }
156
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);
165
166    /**
167     *  Remove, by rounding, any fractional part of the decimal number,
168     *  leaving an integer value.
169     */
170    void toIntegralValue();
171
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);
185
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;
192
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*/;
200
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*/;
208
209    /**
210     *  Utility routine to get the value of the digit list as a decimal string.
211     */
212    void getDecimal(CharString &str, UErrorCode &status);
213
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*/;
222
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*/;
231
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);
237
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);
245
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);
253
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);
262
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);
270
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);
277
278    /**
279     *   Divide    this = this / arg
280     */
281    void div(const DigitList &arg, UErrorCode &status);
282
283    //  The following functions replace direct access to the original DigitList implmentation
284    //  data structures.
285
286    void setRoundingMode(DecimalFormat::ERoundingMode m);
287
288    /** Test a number for zero.
289     * @return  TRUE if the number is zero
290     */
291    UBool isZero(void) const;
292
293    /** Test for a Nan
294     * @return  TRUE if the number is a NaN
295     */
296    UBool isNaN(void) const {return decNumberIsNaN(fDecNumber);}
297
298    UBool isInfinite() const {return decNumberIsInfinite(fDecNumber);}
299
300    /**  Reduce, or normalize.  Removes trailing zeroes, adjusts exponent appropriately. */
301    void     reduce();
302
303    /**  Remove trailing fraction zeros, adjust exponent accordingly. */
304    void     trim();
305
306    /** Set to zero */
307    void     setToZero() {uprv_decNumberZero(fDecNumber);}
308
309    /** get the number of digits in the decimal number */
310    int32_t  digits() const {return fDecNumber->digits;}
311
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);
318
319    void roundFixedPoint(int32_t maximumFractionDigits);
320
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);
326
327    UBool    isPositive(void) const { return decNumberIsNegative(fDecNumber) == 0;}
328    void     setPositive(UBool s);
329
330    void     setDecimalAt(int32_t d);
331    int32_t  getDecimalAt();
332
333    void     setCount(int32_t c);
334    int32_t  getCount() const;
335
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);
342
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);
349
350
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);
358
359
360private:
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     */
388
389public:
390    decContext    fContext;   // public access to status flags.
391
392private:
393    decNumber     *fDecNumber;
394    MaybeStackHeaderAndArray<decNumber, char, DEFAULT_DIGITS>  fStorage;
395
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;
409
410
411
412    UBool shouldRoundUp(int32_t maximumDigits) const;
413
414 public:
415
416#if U_OVERRIDE_CXX_ALLOCATION
417    using UMemory::operator new;
418    using UMemory::operator delete;
419#else
420    static inline void * U_EXPORT2 operator new(size_t size) U_NO_THROW { return ::operator new(size); };
421    static inline void U_EXPORT2 operator delete(void *ptr )  U_NO_THROW { ::operator delete(ptr); };
422#endif
423
424    /**
425     * Placement new for stack usage
426     * @internal
427     */
428    static inline void * U_EXPORT2 operator new(size_t /*size*/, void * onStack, EStackMode  /*mode*/) U_NO_THROW { return onStack; }
429
430    /**
431     * Placement delete for stack usage
432     * @internal
433     */
434    static inline void U_EXPORT2 operator delete(void * /*ptr*/, void * /*onStack*/, EStackMode /*mode*/)  U_NO_THROW {}
435
436 private:
437    inline void internalSetDouble(double d) {
438      fHave = kDouble;
439      fUnion.fDouble=d;
440    }
441    inline void internalSetInt64(int64_t d) {
442      fHave = kInt64;
443      fUnion.fInt64=d;
444    }
445    inline void internalClear() {
446      fHave = kNone;
447    }
448};
449
450
451U_NAMESPACE_END
452
453#endif // #if !UCONFIG_NO_FORMATTING
454#endif // _DIGITLST
455
456//eof
457