1b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*
2b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru******************************************************************************
3f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius*   Copyright (C) 1997-2014, International Business Machines
4b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*   Corporation and others.  All Rights Reserved.
5b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru******************************************************************************
6b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*   file name:  nfsubs.cpp
7b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*   encoding:   US-ASCII
8b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*   tab size:   8 (not used)
9b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*   indentation:4
10b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*
11b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru* Modification history
12b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru* Date        Name      Comments
13b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru* 10/11/2001  Doug      Ported from ICU4J
14b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*/
15b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1627f654740f2a26ad62a5c155af9199af9e69b889claireho#include <stdio.h>
1754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius#include "utypeinfo.h"  // for 'typeid' to work
1827f654740f2a26ad62a5c155af9199af9e69b889claireho
19b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "nfsubs.h"
20b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "digitlst.h"
21b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
22b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#if U_HAVE_RBNF
23b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
24b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic const UChar gLessThan = 0x003c;
25b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic const UChar gEquals = 0x003d;
26b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic const UChar gGreaterThan = 0x003e;
27b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic const UChar gPercent = 0x0025;
28b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic const UChar gPound = 0x0023;
29b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic const UChar gZero = 0x0030;
30b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic const UChar gSpace = 0x0020;
31b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
32b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic const UChar gEqualsEquals[] =
33b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
34b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    0x3D, 0x3D, 0
35b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}; /* "==" */
36b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic const UChar gGreaterGreaterGreaterThan[] =
37b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
38b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    0x3E, 0x3E, 0x3E, 0
39b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}; /* ">>>" */
40b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic const UChar gGreaterGreaterThan[] =
41b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
42b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    0x3E, 0x3E, 0
43b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}; /* ">>" */
44b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
45b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_NAMESPACE_BEGIN
46b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
47b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruclass SameValueSubstitution : public NFSubstitution {
48b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querupublic:
49b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    SameValueSubstitution(int32_t pos,
50b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const NFRuleSet* ruleset,
51b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const RuleBasedNumberFormat* formatter,
52b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const UnicodeString& description,
53b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        UErrorCode& status);
54103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    virtual ~SameValueSubstitution();
55b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
56b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual int64_t transformNumber(int64_t number) const { return number; }
57b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual double transformNumber(double number) const { return number; }
58b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual double composeRuleValue(double newRuleValue, double /*oldRuleValue*/) const { return newRuleValue; }
59b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual double calcUpperBound(double oldUpperBound) const { return oldUpperBound; }
60b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual UChar tokenChar() const { return (UChar)0x003d; } // '='
61b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
62b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querupublic:
63b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    static UClassID getStaticClassID(void);
64b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual UClassID getDynamicClassID(void) const;
65b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru};
66b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
67103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusSameValueSubstitution::~SameValueSubstitution() {}
68103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
69b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruclass MultiplierSubstitution : public NFSubstitution {
70b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    double divisor;
71b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int64_t ldivisor;
72b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
73b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querupublic:
74b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    MultiplierSubstitution(int32_t _pos,
75b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        double _divisor,
76b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const NFRuleSet* _ruleSet,
77b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const RuleBasedNumberFormat* formatter,
78b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const UnicodeString& description,
79b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        UErrorCode& status)
80b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        : NFSubstitution(_pos, _ruleSet, formatter, description, status), divisor(_divisor)
81b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    {
82b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        ldivisor = util64_fromDouble(divisor);
83b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (divisor == 0) {
84b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            status = U_PARSE_ERROR;
85b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
86b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
87103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    virtual ~MultiplierSubstitution();
88b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
89b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual void setDivisor(int32_t radix, int32_t exponent, UErrorCode& status) {
90b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        divisor = uprv_pow(radix, exponent);
91b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        ldivisor = util64_fromDouble(divisor);
92b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
93b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if(divisor == 0) {
94b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            status = U_PARSE_ERROR;
95b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
96b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
97b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
98b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual UBool operator==(const NFSubstitution& rhs) const;
99b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
100b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual int64_t transformNumber(int64_t number) const {
101b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return number / ldivisor;
102b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
103b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
104b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual double transformNumber(double number) const {
105b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (getRuleSet()) {
106b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return uprv_floor(number / divisor);
107b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else {
108b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return number/divisor;
109b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
110b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
111b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
112b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual double composeRuleValue(double newRuleValue, double /*oldRuleValue*/) const {
113b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return newRuleValue * divisor;
114b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
115b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
116b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual double calcUpperBound(double /*oldUpperBound*/) const { return divisor; }
117b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
118b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual UChar tokenChar() const { return (UChar)0x003c; } // '<'
119b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
120b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querupublic:
121b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    static UClassID getStaticClassID(void);
122b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual UClassID getDynamicClassID(void) const;
123b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru};
124b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
125103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusMultiplierSubstitution::~MultiplierSubstitution() {}
126103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
127b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruclass ModulusSubstitution : public NFSubstitution {
128b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    double divisor;
129b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int64_t  ldivisor;
130b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const NFRule* ruleToUse;
131b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querupublic:
132b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    ModulusSubstitution(int32_t pos,
133b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        double _divisor,
134b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const NFRule* rulePredecessor,
135b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const NFRuleSet* ruleSet,
136b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const RuleBasedNumberFormat* formatter,
137b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const UnicodeString& description,
138b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        UErrorCode& status);
139103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    virtual ~ModulusSubstitution();
140b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
141b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual void setDivisor(int32_t radix, int32_t exponent, UErrorCode& status) {
142b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        divisor = uprv_pow(radix, exponent);
143b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        ldivisor = util64_fromDouble(divisor);
144b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
145b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (divisor == 0) {
146b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            status = U_PARSE_ERROR;
147b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
148b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
149b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
150b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual UBool operator==(const NFSubstitution& rhs) const;
151b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
152f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    virtual void doSubstitution(int64_t number, UnicodeString& toInsertInto, int32_t pos, UErrorCode& status) const;
153f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    virtual void doSubstitution(double number, UnicodeString& toInsertInto, int32_t pos, UErrorCode& status) const;
154b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
155b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual int64_t transformNumber(int64_t number) const { return number % ldivisor; }
156b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual double transformNumber(double number) const { return uprv_fmod(number, divisor); }
157b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
158b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual UBool doParse(const UnicodeString& text,
159b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        ParsePosition& parsePosition,
160b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        double baseValue,
161b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        double upperBound,
162b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        UBool lenientParse,
163b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        Formattable& result) const;
164b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
165b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual double composeRuleValue(double newRuleValue, double oldRuleValue) const {
166b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return oldRuleValue - uprv_fmod(oldRuleValue, divisor) + newRuleValue;
167b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
168b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
169b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual double calcUpperBound(double /*oldUpperBound*/) const { return divisor; }
170b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
171b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual UBool isModulusSubstitution() const { return TRUE; }
172b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
173b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual UChar tokenChar() const { return (UChar)0x003e; } // '>'
174b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
175103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius	virtual void toString(UnicodeString& result) const;
176103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
177b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querupublic:
178b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    static UClassID getStaticClassID(void);
179b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual UClassID getDynamicClassID(void) const;
180b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru};
181b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
182103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusModulusSubstitution::~ModulusSubstitution() {}
183103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
184b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruclass IntegralPartSubstitution : public NFSubstitution {
185b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querupublic:
186b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    IntegralPartSubstitution(int32_t _pos,
187b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const NFRuleSet* _ruleSet,
188b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const RuleBasedNumberFormat* formatter,
189b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const UnicodeString& description,
190b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        UErrorCode& status)
191b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        : NFSubstitution(_pos, _ruleSet, formatter, description, status) {}
192103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    virtual ~IntegralPartSubstitution();
193b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
194b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual int64_t transformNumber(int64_t number) const { return number; }
195b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual double transformNumber(double number) const { return uprv_floor(number); }
196b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual double composeRuleValue(double newRuleValue, double oldRuleValue) const { return newRuleValue + oldRuleValue; }
197b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual double calcUpperBound(double /*oldUpperBound*/) const { return DBL_MAX; }
198b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual UChar tokenChar() const { return (UChar)0x003c; } // '<'
199b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
200b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querupublic:
201b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    static UClassID getStaticClassID(void);
202b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual UClassID getDynamicClassID(void) const;
203b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru};
204b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
205103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusIntegralPartSubstitution::~IntegralPartSubstitution() {}
206103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
207b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruclass FractionalPartSubstitution : public NFSubstitution {
208b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UBool byDigits;
209b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UBool useSpaces;
210b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    enum { kMaxDecimalDigits = 8 };
211b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querupublic:
212b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    FractionalPartSubstitution(int32_t pos,
213b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const NFRuleSet* ruleSet,
214b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const RuleBasedNumberFormat* formatter,
215b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const UnicodeString& description,
216b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        UErrorCode& status);
217103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    virtual ~FractionalPartSubstitution();
218b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
219b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual UBool operator==(const NFSubstitution& rhs) const;
220b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
221f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    virtual void doSubstitution(double number, UnicodeString& toInsertInto, int32_t pos, UErrorCode& status) const;
222f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    virtual void doSubstitution(int64_t /*number*/, UnicodeString& /*toInsertInto*/, int32_t /*_pos*/, UErrorCode& /*status*/) const {}
223b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual int64_t transformNumber(int64_t /*number*/) const { return 0; }
224b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual double transformNumber(double number) const { return number - uprv_floor(number); }
225b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
226b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual UBool doParse(const UnicodeString& text,
227b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        ParsePosition& parsePosition,
228b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        double baseValue,
229b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        double upperBound,
230b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        UBool lenientParse,
231b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        Formattable& result) const;
232b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
233b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual double composeRuleValue(double newRuleValue, double oldRuleValue) const { return newRuleValue + oldRuleValue; }
234b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual double calcUpperBound(double /*oldUpperBound*/) const { return 0.0; }
235b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual UChar tokenChar() const { return (UChar)0x003e; } // '>'
236b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
237b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querupublic:
238b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    static UClassID getStaticClassID(void);
239b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual UClassID getDynamicClassID(void) const;
240b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru};
241b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
242103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusFractionalPartSubstitution::~FractionalPartSubstitution() {}
243103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
244b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruclass AbsoluteValueSubstitution : public NFSubstitution {
245b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querupublic:
246b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    AbsoluteValueSubstitution(int32_t _pos,
247b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const NFRuleSet* _ruleSet,
248b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const RuleBasedNumberFormat* formatter,
249b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const UnicodeString& description,
250b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        UErrorCode& status)
251b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        : NFSubstitution(_pos, _ruleSet, formatter, description, status) {}
252103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    virtual ~AbsoluteValueSubstitution();
253b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
254b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual int64_t transformNumber(int64_t number) const { return number >= 0 ? number : -number; }
255b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual double transformNumber(double number) const { return uprv_fabs(number); }
256b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual double composeRuleValue(double newRuleValue, double /*oldRuleValue*/) const { return -newRuleValue; }
257b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual double calcUpperBound(double /*oldUpperBound*/) const { return DBL_MAX; }
258b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual UChar tokenChar() const { return (UChar)0x003e; } // '>'
259b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
260b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querupublic:
261b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    static UClassID getStaticClassID(void);
262b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual UClassID getDynamicClassID(void) const;
263b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru};
264b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
265103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusAbsoluteValueSubstitution::~AbsoluteValueSubstitution() {}
266103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
267b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruclass NumeratorSubstitution : public NFSubstitution {
268b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    double denominator;
269b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int64_t ldenominator;
270b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UBool withZeros;
271b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querupublic:
272b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    static inline UnicodeString fixdesc(const UnicodeString& desc) {
273b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (desc.endsWith(LTLT, 2)) {
274b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            UnicodeString result(desc, 0, desc.length()-1);
275b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return result;
276b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
277b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return desc;
278b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
279b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    NumeratorSubstitution(int32_t _pos,
280b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        double _denominator,
281b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const NFRuleSet* _ruleSet,
282b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const RuleBasedNumberFormat* formatter,
283b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const UnicodeString& description,
284b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        UErrorCode& status)
285b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        : NFSubstitution(_pos, _ruleSet, formatter, fixdesc(description), status), denominator(_denominator)
286b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    {
287b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        ldenominator = util64_fromDouble(denominator);
288b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        withZeros = description.endsWith(LTLT, 2);
289b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
290103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    virtual ~NumeratorSubstitution();
291b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
292b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual UBool operator==(const NFSubstitution& rhs) const;
293b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
294b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual int64_t transformNumber(int64_t number) const { return number * ldenominator; }
295b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual double transformNumber(double number) const { return uprv_round(number * denominator); }
296b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
297f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    virtual void doSubstitution(int64_t /*number*/, UnicodeString& /*toInsertInto*/, int32_t /*_pos*/, UErrorCode& /*status*/) const {}
298f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    virtual void doSubstitution(double number, UnicodeString& toInsertInto, int32_t pos, UErrorCode& status) const;
299b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual UBool doParse(const UnicodeString& text,
300b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        ParsePosition& parsePosition,
301b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        double baseValue,
302b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        double upperBound,
303b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        UBool /*lenientParse*/,
304b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        Formattable& result) const;
305b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
306b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual double composeRuleValue(double newRuleValue, double oldRuleValue) const { return newRuleValue / oldRuleValue; }
307b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual double calcUpperBound(double /*oldUpperBound*/) const { return denominator; }
308b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual UChar tokenChar() const { return (UChar)0x003c; } // '<'
309b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruprivate:
310b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    static const UChar LTLT[2];
311b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
312b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querupublic:
313b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    static UClassID getStaticClassID(void);
314b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual UClassID getDynamicClassID(void) const;
315b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru};
316b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
317103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusNumeratorSubstitution::~NumeratorSubstitution() {}
318103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
319b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruclass NullSubstitution : public NFSubstitution {
320b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querupublic:
321b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    NullSubstitution(int32_t _pos,
322b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const NFRuleSet* _ruleSet,
323b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const RuleBasedNumberFormat* formatter,
324b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const UnicodeString& description,
325b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        UErrorCode& status)
326b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        : NFSubstitution(_pos, _ruleSet, formatter, description, status) {}
327103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    virtual ~NullSubstitution();
328b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
329b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual void toString(UnicodeString& /*result*/) const {}
330f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    virtual void doSubstitution(double /*number*/, UnicodeString& /*toInsertInto*/, int32_t /*_pos*/, UErrorCode& /*status*/) const {}
331f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    virtual void doSubstitution(int64_t /*number*/, UnicodeString& /*toInsertInto*/, int32_t /*_pos*/, UErrorCode& /*status*/) const {}
332b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual int64_t transformNumber(int64_t /*number*/) const { return 0; }
333b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual double transformNumber(double /*number*/) const { return 0; }
334b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual UBool doParse(const UnicodeString& /*text*/,
335b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        ParsePosition& /*parsePosition*/,
336b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        double baseValue,
337b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        double /*upperBound*/,
338b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        UBool /*lenientParse*/,
339b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        Formattable& result) const
340b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    { result.setDouble(baseValue); return TRUE; }
341b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual double composeRuleValue(double /*newRuleValue*/, double /*oldRuleValue*/) const { return 0.0; } // never called
342b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual double calcUpperBound(double /*oldUpperBound*/) const { return 0; } // never called
343b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual UBool isNullSubstitution() const { return TRUE; }
344b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual UChar tokenChar() const { return (UChar)0x0020; } // ' ' never called
345b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
346b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querupublic:
347b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    static UClassID getStaticClassID(void);
348b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    virtual UClassID getDynamicClassID(void) const;
349b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru};
350b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
351103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusNullSubstitution::~NullSubstitution() {}
352103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
353b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruNFSubstitution*
354b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruNFSubstitution::makeSubstitution(int32_t pos,
355b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                 const NFRule* rule,
356b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                 const NFRule* predecessor,
357b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                 const NFRuleSet* ruleSet,
358b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                 const RuleBasedNumberFormat* formatter,
359b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                 const UnicodeString& description,
360b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                 UErrorCode& status)
361b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
362b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // if the description is empty, return a NullSubstitution
363b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (description.length() == 0) {
364b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return new NullSubstitution(pos, ruleSet, formatter, description, status);
365b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
366b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
367b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    switch (description.charAt(0)) {
368b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // if the description begins with '<'...
369b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    case gLessThan:
370b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // throw an exception if the rule is a negative number
371b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // rule
372b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (rule->getBaseValue() == NFRule::kNegativeNumberRule) {
373b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            // throw new IllegalArgumentException("<< not allowed in negative-number rule");
374b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            status = U_PARSE_ERROR;
375b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return NULL;
376b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
377b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
378b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // if the rule is a fraction rule, return an
379b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // IntegralPartSubstitution
380b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        else if (rule->getBaseValue() == NFRule::kImproperFractionRule
381b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            || rule->getBaseValue() == NFRule::kProperFractionRule
382b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            || rule->getBaseValue() == NFRule::kMasterRule) {
383b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return new IntegralPartSubstitution(pos, ruleSet, formatter, description, status);
384b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
385b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
386b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // if the rule set containing the rule is a fraction
387b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // rule set, return a NumeratorSubstitution
388b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        else if (ruleSet->isFractionRuleSet()) {
389b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return new NumeratorSubstitution(pos, (double)rule->getBaseValue(),
390b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                formatter->getDefaultRuleSet(), formatter, description, status);
391b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
392b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
393b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // otherwise, return a MultiplierSubstitution
394b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        else {
395b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return new MultiplierSubstitution(pos, rule->getDivisor(), ruleSet,
396b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                formatter, description, status);
397b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
398b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
399b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // if the description begins with '>'...
400b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    case gGreaterThan:
401b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // if the rule is a negative-number rule, return
402b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // an AbsoluteValueSubstitution
403b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (rule->getBaseValue() == NFRule::kNegativeNumberRule) {
404b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return new AbsoluteValueSubstitution(pos, ruleSet, formatter, description, status);
405b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
406b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
407b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // if the rule is a fraction rule, return a
408b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // FractionalPartSubstitution
409b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        else if (rule->getBaseValue() == NFRule::kImproperFractionRule
410b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            || rule->getBaseValue() == NFRule::kProperFractionRule
411b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            || rule->getBaseValue() == NFRule::kMasterRule) {
412b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return new FractionalPartSubstitution(pos, ruleSet, formatter, description, status);
413b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
414b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
415b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // if the rule set owning the rule is a fraction rule set,
416b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // throw an exception
417b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        else if (ruleSet->isFractionRuleSet()) {
418b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            // throw new IllegalArgumentException(">> not allowed in fraction rule set");
419b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            status = U_PARSE_ERROR;
420b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return NULL;
421b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
422b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
423b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // otherwise, return a ModulusSubstitution
424b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        else {
425b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return new ModulusSubstitution(pos, rule->getDivisor(), predecessor,
426b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                ruleSet, formatter, description, status);
427b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
428b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
429b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // if the description begins with '=', always return a
430b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // SameValueSubstitution
431b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    case gEquals:
432b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return new SameValueSubstitution(pos, ruleSet, formatter, description, status);
433b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
434b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // and if it's anything else, throw an exception
435b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    default:
436b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // throw new IllegalArgumentException("Illegal substitution character");
437b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        status = U_PARSE_ERROR;
438b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
439b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return NULL;
440b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
441b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
442b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruNFSubstitution::NFSubstitution(int32_t _pos,
443b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                               const NFRuleSet* _ruleSet,
444b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                               const RuleBasedNumberFormat* formatter,
445b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                               const UnicodeString& description,
446b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                               UErrorCode& status)
447b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                               : pos(_pos), ruleSet(NULL), numberFormat(NULL)
448b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
449b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // the description should begin and end with the same character.
450b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // If it doesn't that's a syntax error.  Otherwise,
451b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // makeSubstitution() was the only thing that needed to know
452b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // about these characters, so strip them off
453b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UnicodeString workingDescription(description);
454b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (description.length() >= 2
455b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        && description.charAt(0) == description.charAt(description.length() - 1))
456b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    {
457b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        workingDescription.remove(description.length() - 1, 1);
458b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        workingDescription.remove(0, 1);
459b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
460b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    else if (description.length() != 0) {
461b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // throw new IllegalArgumentException("Illegal substitution syntax");
462b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        status = U_PARSE_ERROR;
463b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return;
464b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
465b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
466b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // if the description was just two paired token characters
467b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // (i.e., "<<" or ">>"), it uses the rule set it belongs to to
468b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // format its result
469b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (workingDescription.length() == 0) {
470b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        this->ruleSet = _ruleSet;
471b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
472b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // if the description contains a rule set name, that's the rule
473b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // set we use to format the result: get a reference to the
474b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // names rule set
475b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    else if (workingDescription.charAt(0) == gPercent) {
476b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        this->ruleSet = formatter->findRuleSet(workingDescription, status);
477b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
478b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // if the description begins with 0 or #, treat it as a
479b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // DecimalFormat pattern, and initialize a DecimalFormat with
480b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // that pattern (then set it to use the DecimalFormatSymbols
481b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // belonging to our formatter)
482b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    else if (workingDescription.charAt(0) == gPound || workingDescription.charAt(0) ==gZero) {
483b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        DecimalFormatSymbols* sym = formatter->getDecimalFormatSymbols();
484b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (!sym) {
485b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            status = U_MISSING_RESOURCE_ERROR;
486b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return;
487b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
488b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        this->numberFormat = new DecimalFormat(workingDescription, *sym, status);
489b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        /* test for NULL */
490b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (this->numberFormat == 0) {
491b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            status = U_MEMORY_ALLOCATION_ERROR;
492b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return;
493b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
494b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (U_FAILURE(status)) {
495b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            delete (DecimalFormat*)this->numberFormat;
496b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            this->numberFormat = NULL;
497b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return;
498b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
499b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // this->numberFormat->setDecimalFormatSymbols(formatter->getDecimalFormatSymbols());
500b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
501b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // if the description is ">>>", this substitution bypasses the
502b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // usual rule-search process and always uses the rule that precedes
503b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // it in its own rule set's rule list (this is used for place-value
504b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // notations: formats where you want to see a particular part of
505b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // a number even when it's 0)
506b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    else if (workingDescription.charAt(0) == gGreaterThan) {
507b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // this causes problems when >>> is used in a frationalPartSubstitution
508b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // this->ruleSet = NULL;
509b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        this->ruleSet = _ruleSet;
510b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        this->numberFormat = NULL;
511b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
512b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // and of the description is none of these things, it's a syntax error
513b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    else {
514b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // throw new IllegalArgumentException("Illegal substitution syntax");
515b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        status = U_PARSE_ERROR;
516b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
517b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
518b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
519b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruNFSubstitution::~NFSubstitution()
520b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
521b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  // cast away const
522b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  delete (NumberFormat*)numberFormat; numberFormat = NULL;
523b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
524b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
525b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
526b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Set's the substitution's divisor.  Used by NFRule.setBaseValue().
527b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * A no-op for all substitutions except multiplier and modulus
528b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * substitutions.
529b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param radix The radix of the divisor
530b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param exponent The exponent of the divisor
531b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
532b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid
533b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruNFSubstitution::setDivisor(int32_t /*radix*/, int32_t /*exponent*/, UErrorCode& /*status*/) {
534b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  // a no-op for all substitutions except multiplier and modulus substitutions
535b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
536b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
537b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
538b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//-----------------------------------------------------------------------
539b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// boilerplate
540b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//-----------------------------------------------------------------------
541b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
542b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUOBJECT_DEFINE_RTTI_IMPLEMENTATION(NFSubstitution)
543b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
544b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
545b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Compares two substitutions for equality
546b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param The substitution to compare this one to
547b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @return true if the two substitutions are functionally equivalent
548b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
549b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUBool
550b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruNFSubstitution::operator==(const NFSubstitution& rhs) const
551b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
552b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  // compare class and all of the fields all substitutions have
553b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  // in common
554b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  // this should be called by subclasses before their own equality tests
55527f654740f2a26ad62a5c155af9199af9e69b889claireho  return typeid(*this) == typeid(rhs)
556b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  && pos == rhs.pos
557b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  && (ruleSet == NULL) == (rhs.ruleSet == NULL)
558b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  // && ruleSet == rhs.ruleSet causes circularity, other checks to make instead?
559b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  && (numberFormat == NULL
560b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru      ? (rhs.numberFormat == NULL)
561b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru      : (*numberFormat == *rhs.numberFormat));
562b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
563b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
564b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
565b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Returns a textual description of the substitution
566b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @return A textual description of the substitution.  This might
567b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * not be identical to the description it was created from, but
568b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * it'll produce the same result.
569b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
570b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid
571b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruNFSubstitution::toString(UnicodeString& text) const
572b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
573b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  // use tokenChar() to get the character at the beginning and
574b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  // end of the substitutin token.  In between them will go
575b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  // either the name of the rule set it uses, or the pattern of
576b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  // the DecimalFormat it uses
577b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  text.remove();
578b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  text.append(tokenChar());
579b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
580b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  UnicodeString temp;
581b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  if (ruleSet != NULL) {
582b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    ruleSet->getName(temp);
583b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  } else if (numberFormat != NULL) {
584b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    numberFormat->toPattern(temp);
585b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  }
586b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  text.append(temp);
587b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  text.append(tokenChar());
588b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
589b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
590b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//-----------------------------------------------------------------------
591b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// formatting
592b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//-----------------------------------------------------------------------
593b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
594b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
595b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Performs a mathematical operation on the number, formats it using
596b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * either ruleSet or decimalFormat, and inserts the result into
597b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * toInsertInto.
598b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param number The number being formatted.
599b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param toInsertInto The string we insert the result into
600b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param pos The position in toInsertInto where the owning rule's
601b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * rule text begins (this value is added to this substitution's
602b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * position to determine exactly where to insert the new text)
603b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
604b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid
605f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusNFSubstitution::doSubstitution(int64_t number, UnicodeString& toInsertInto, int32_t _pos, UErrorCode& status) const
606b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
607b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (ruleSet != NULL) {
608b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // perform a transformation on the number that is dependent
609b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // on the type of substitution this is, then just call its
610b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // rule set's format() method to format the result
611f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        ruleSet->format(transformNumber(number), toInsertInto, _pos + this->pos, status);
612b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else if (numberFormat != NULL) {
613b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // or perform the transformation on the number (preserving
614b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // the result's fractional part if the formatter it set
615b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // to show it), then use that formatter's format() method
616b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // to format the result
617b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        double numberToFormat = transformNumber((double)number);
618b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (numberFormat->getMaximumFractionDigits() == 0) {
619b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            numberToFormat = uprv_floor(numberToFormat);
620b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
621b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
622b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        UnicodeString temp;
623f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        numberFormat->format(numberToFormat, temp, status);
624b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        toInsertInto.insert(_pos + this->pos, temp);
625b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
626b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
627b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
628b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
629b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Performs a mathematical operation on the number, formats it using
630b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * either ruleSet or decimalFormat, and inserts the result into
631b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * toInsertInto.
632b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param number The number being formatted.
633b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param toInsertInto The string we insert the result into
634b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param pos The position in toInsertInto where the owning rule's
635b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * rule text begins (this value is added to this substitution's
636b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * position to determine exactly where to insert the new text)
637b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
638b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid
639f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusNFSubstitution::doSubstitution(double number, UnicodeString& toInsertInto, int32_t _pos, UErrorCode& status) const {
640b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // perform a transformation on the number being formatted that
641b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // is dependent on the type of substitution this is
642b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    double numberToFormat = transformNumber(number);
643b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
644b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // if the result is an integer, from here on out we work in integer
645b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // space (saving time and memory and preserving accuracy)
646b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (numberToFormat == uprv_floor(numberToFormat) && ruleSet != NULL) {
647f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        ruleSet->format(util64_fromDouble(numberToFormat), toInsertInto, _pos + this->pos, status);
648b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
649b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // if the result isn't an integer, then call either our rule set's
650b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // format() method or our DecimalFormat's format() method to
651b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // format the result
652b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else {
653b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (ruleSet != NULL) {
654f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius            ruleSet->format(numberToFormat, toInsertInto, _pos + this->pos, status);
655b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else if (numberFormat != NULL) {
656b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            UnicodeString temp;
657b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            numberFormat->format(numberToFormat, temp);
658b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            toInsertInto.insert(_pos + this->pos, temp);
659b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
660b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
661b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
662b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
663b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
664b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    //-----------------------------------------------------------------------
665b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // parsing
666b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    //-----------------------------------------------------------------------
667b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
668b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#ifdef RBNF_DEBUG
669b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include <stdio.h>
670b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#endif
671b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
672b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
673b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Parses a string using the rule set or DecimalFormat belonging
674b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * to this substitution.  If there's a match, a mathematical
675b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * operation (the inverse of the one used in formatting) is
676b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * performed on the result of the parse and the value passed in
677b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * and returned as the result.  The parse position is updated to
678b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * point to the first unmatched character in the string.
679b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param text The string to parse
680b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param parsePosition On entry, ignored, but assumed to be 0.
681b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * On exit, this is updated to point to the first unmatched
682b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * character (or 0 if the substitution didn't match)
683b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param baseValue A partial parse result that should be
684b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * combined with the result of this parse
685b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param upperBound When searching the rule set for a rule
686b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * matching the string passed in, only rules with base values
687b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * lower than this are considered
688b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param lenientParse If true and matching against rules fails,
689b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * the substitution will also try matching the text against
690b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * numerals using a default-costructed NumberFormat.  If false,
691b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * no extra work is done.  (This value is false whenever the
692b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * formatter isn't in lenient-parse mode, but is also false
693b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * under some conditions even when the formatter _is_ in
694b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * lenient-parse mode.)
695b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @return If there's a match, this is the result of composing
696b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * baseValue with whatever was returned from matching the
697b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * characters.  This will be either a Long or a Double.  If there's
698b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * no match this is new Long(0) (not null), and parsePosition
699b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * is left unchanged.
700b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
701b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUBool
702b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruNFSubstitution::doParse(const UnicodeString& text,
703b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        ParsePosition& parsePosition,
704b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        double baseValue,
705b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        double upperBound,
706b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        UBool lenientParse,
707b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        Formattable& result) const
708b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
709b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#ifdef RBNF_DEBUG
710b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    fprintf(stderr, "<nfsubs> %x bv: %g ub: %g\n", this, baseValue, upperBound);
711b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#endif
712b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // figure out the highest base value a rule can have and match
713b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // the text being parsed (this varies according to the type of
714b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // substitutions: multiplier, modulus, and numerator substitutions
715b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // restrict the search to rules with base values lower than their
716b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // own; same-value substitutions leave the upper bound wherever
717b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // it was, and the others allow any rule to match
718b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    upperBound = calcUpperBound(upperBound);
719b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
720b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // use our rule set to parse the text.  If that fails and
721b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // lenient parsing is enabled (this is always false if the
722b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // formatter's lenient-parsing mode is off, but it may also
723b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // be false even when the formatter's lenient-parse mode is
724b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // on), then also try parsing the text using a default-
725b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // constructed NumberFormat
726b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (ruleSet != NULL) {
727b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        ruleSet->parse(text, parsePosition, upperBound, result);
728b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (lenientParse && !ruleSet->isFractionRuleSet() && parsePosition.getIndex() == 0) {
729b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            UErrorCode status = U_ZERO_ERROR;
730b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            NumberFormat* fmt = NumberFormat::createInstance(status);
731b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (U_SUCCESS(status)) {
732b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                fmt->parse(text, result, parsePosition);
733b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
734b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            delete fmt;
735b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
736b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
737b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // ...or use our DecimalFormat to parse the text
738b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else if (numberFormat != NULL) {
739b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        numberFormat->parse(text, result, parsePosition);
740b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
741b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
742b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // if the parse was successful, we've already advanced the caller's
743b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // parse position (this is the one function that doesn't have one
744b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // of its own).  Derive a parse result and return it as a Long,
745b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // if possible, or a Double
746b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (parsePosition.getIndex() != 0) {
747b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        UErrorCode status = U_ZERO_ERROR;
748b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        double tempResult = result.getDouble(status);
749b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
750b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // composeRuleValue() produces a full parse result from
751b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // the partial parse result passed to this function from
752b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // the caller (this is either the owning rule's base value
753b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // or the partial result obtained from composing the
754b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // owning rule's base value with its other substitution's
755b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // parse result) and the partial parse result obtained by
756b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // matching the substitution (which will be the same value
757b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // the caller would get by parsing just this part of the
758b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // text with RuleBasedNumberFormat.parse() ).  How the two
759b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // values are used to derive the full parse result depends
760b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // on the types of substitutions: For a regular rule, the
761b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // ultimate result is its multiplier substitution's result
762b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // times the rule's divisor (or the rule's base value) plus
763b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // the modulus substitution's result (which will actually
764b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // supersede part of the rule's base value).  For a negative-
765b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // number rule, the result is the negative of its substitution's
766b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // result.  For a fraction rule, it's the sum of its two
767b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // substitution results.  For a rule in a fraction rule set,
768b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // it's the numerator substitution's result divided by
769b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // the rule's base value.  Results from same-value substitutions
770b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // propagate back upard, and null substitutions don't affect
771b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // the result.
772b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        tempResult = composeRuleValue(tempResult, baseValue);
773b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        result.setDouble(tempResult);
774b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return TRUE;
775b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // if the parse was UNsuccessful, return 0
776b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else {
777b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        result.setLong(0);
778b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return FALSE;
779b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
780b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
781b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
782b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUBool
783b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruNFSubstitution::isNullSubstitution() const {
784b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return FALSE;
785b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
786b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
787b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /**
788b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru     * Returns true if this is a modulus substitution.  (We didn't do this
789b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru     * with instanceof partially because it causes source files to
790b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru     * proliferate and partially because we have to port this to C++.)
791b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru     * @return true if this object is an instance of ModulusSubstitution
792b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru     */
793b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUBool
794b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruNFSubstitution::isModulusSubstitution() const {
795b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return FALSE;
796b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
797b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
798b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//===================================================================
799b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// SameValueSubstitution
800b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//===================================================================
801b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
802b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
803b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * A substitution that passes the value passed to it through unchanged.
804b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Represented by == in rule descriptions.
805b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
806b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruSameValueSubstitution::SameValueSubstitution(int32_t _pos,
807b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        const NFRuleSet* _ruleSet,
808b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        const RuleBasedNumberFormat* formatter,
809b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        const UnicodeString& description,
810b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        UErrorCode& status)
811b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru: NFSubstitution(_pos, _ruleSet, formatter, description, status)
812b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
813103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    if (0 == description.compare(gEqualsEquals, 2)) {
814b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // throw new IllegalArgumentException("== is not a legal token");
815b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        status = U_PARSE_ERROR;
816b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
817b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
818b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
819b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUOBJECT_DEFINE_RTTI_IMPLEMENTATION(SameValueSubstitution)
820b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
821b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//===================================================================
822b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// MultiplierSubstitution
823b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//===================================================================
824b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
825b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUOBJECT_DEFINE_RTTI_IMPLEMENTATION(MultiplierSubstitution)
826b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
827b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUBool MultiplierSubstitution::operator==(const NFSubstitution& rhs) const
828b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
829b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return NFSubstitution::operator==(rhs) &&
830b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        divisor == ((const MultiplierSubstitution*)&rhs)->divisor;
831b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
832b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
833b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
834b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//===================================================================
835b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// ModulusSubstitution
836b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//===================================================================
837b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
838b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
839b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * A substitution that divides the number being formatted by the its rule's
840b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * divisor and formats the remainder.  Represented by "&gt;&gt;" in a
841b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * regular rule.
842b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
843b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruModulusSubstitution::ModulusSubstitution(int32_t _pos,
844b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                         double _divisor,
845b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                         const NFRule* predecessor,
846b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                         const NFRuleSet* _ruleSet,
847b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                         const RuleBasedNumberFormat* formatter,
848b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                         const UnicodeString& description,
849b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                         UErrorCode& status)
850b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru : NFSubstitution(_pos, _ruleSet, formatter, description, status)
851b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru , divisor(_divisor)
852b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru , ruleToUse(NULL)
853b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
854b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  ldivisor = util64_fromDouble(_divisor);
855b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
856b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  // the owning rule's divisor controls the behavior of this
857b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  // substitution: rather than keeping a backpointer to the rule,
858b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  // we keep a copy of the divisor
859b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
860b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  if (ldivisor == 0) {
861b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru      status = U_PARSE_ERROR;
862b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  }
863b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
864103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius  if (0 == description.compare(gGreaterGreaterGreaterThan, 3)) {
865b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // the >>> token doesn't alter how this substituion calculates the
866b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // values it uses for formatting and parsing, but it changes
867b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // what's done with that value after it's obtained: >>> short-
868b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // circuits the rule-search process and goes straight to the
869b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // specified rule to format the substitution value
870b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    ruleToUse = predecessor;
871b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  }
872b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
873b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
874b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUOBJECT_DEFINE_RTTI_IMPLEMENTATION(ModulusSubstitution)
875b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
876b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUBool ModulusSubstitution::operator==(const NFSubstitution& rhs) const
877b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
878b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  return NFSubstitution::operator==(rhs) &&
879b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  divisor == ((const ModulusSubstitution*)&rhs)->divisor &&
880b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  ruleToUse == ((const ModulusSubstitution*)&rhs)->ruleToUse;
881b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
882b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
883b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//-----------------------------------------------------------------------
884b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// formatting
885b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//-----------------------------------------------------------------------
886b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
887b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
888b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
889b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * If this is a &gt;&gt;&gt; substitution, use ruleToUse to fill in
890b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * the substitution.  Otherwise, just use the superclass function.
891b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param number The number being formatted
892b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @toInsertInto The string to insert the result of this substitution
893b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * into
894b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param pos The position of the rule text in toInsertInto
895b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
896b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid
897f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusModulusSubstitution::doSubstitution(int64_t number, UnicodeString& toInsertInto, int32_t _pos, UErrorCode& status) const
898b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
899b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // if this isn't a >>> substitution, just use the inherited version
900b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // of this function (which uses either a rule set or a DecimalFormat
901b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // to format its substitution value)
902b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (ruleToUse == NULL) {
903f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        NFSubstitution::doSubstitution(number, toInsertInto, _pos, status);
904b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
905b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // a >>> substitution goes straight to a particular rule to
906b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // format the substitution value
907b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else {
908b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        int64_t numberToFormat = transformNumber(number);
909f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        ruleToUse->doFormat(numberToFormat, toInsertInto, _pos + getPos(), status);
910b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
911b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
912b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
913b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
914b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru* If this is a &gt;&gt;&gt; substitution, use ruleToUse to fill in
915b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru* the substitution.  Otherwise, just use the superclass function.
916b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru* @param number The number being formatted
917b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru* @toInsertInto The string to insert the result of this substitution
918b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru* into
919b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru* @param pos The position of the rule text in toInsertInto
920b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*/
921b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid
922f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusModulusSubstitution::doSubstitution(double number, UnicodeString& toInsertInto, int32_t _pos, UErrorCode& status) const
923b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
924b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // if this isn't a >>> substitution, just use the inherited version
925b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // of this function (which uses either a rule set or a DecimalFormat
926b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // to format its substitution value)
927b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (ruleToUse == NULL) {
928f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        NFSubstitution::doSubstitution(number, toInsertInto, _pos, status);
929b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
930b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // a >>> substitution goes straight to a particular rule to
931b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // format the substitution value
932b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else {
933b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        double numberToFormat = transformNumber(number);
934b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
935f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        ruleToUse->doFormat(numberToFormat, toInsertInto, _pos + getPos(), status);
936b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
937b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
938b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
939b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//-----------------------------------------------------------------------
940b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// parsing
941b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//-----------------------------------------------------------------------
942b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
943b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
944b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * If this is a &gt;&gt;&gt; substitution, match only against ruleToUse.
945b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Otherwise, use the superclass function.
946b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param text The string to parse
947b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param parsePosition Ignored on entry, updated on exit to point to
948b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * the first unmatched character.
949b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param baseValue The partial parse result prior to calling this
950b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * routine.
951b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
952b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUBool
953b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruModulusSubstitution::doParse(const UnicodeString& text,
954b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                             ParsePosition& parsePosition,
955b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                             double baseValue,
956b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                             double upperBound,
957b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                             UBool lenientParse,
958b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                             Formattable& result) const
959b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
960b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // if this isn't a >>> substitution, we can just use the
961b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // inherited parse() routine to do the parsing
962b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (ruleToUse == NULL) {
963b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return NFSubstitution::doParse(text, parsePosition, baseValue, upperBound, lenientParse, result);
964b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
965b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // but if it IS a >>> substitution, we have to do it here: we
966b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // use the specific rule's doParse() method, and then we have to
967b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // do some of the other work of NFRuleSet.parse()
968b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else {
969b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        ruleToUse->doParse(text, parsePosition, FALSE, upperBound, result);
970b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
971b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (parsePosition.getIndex() != 0) {
972b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            UErrorCode status = U_ZERO_ERROR;
973b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            double tempResult = result.getDouble(status);
974b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            tempResult = composeRuleValue(tempResult, baseValue);
975b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            result.setDouble(tempResult);
976b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
977b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
978b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return TRUE;
979b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
980b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
981103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius/**
982103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius * Returns a textual description of the substitution
983103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius * @return A textual description of the substitution.  This might
984103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius * not be identical to the description it was created from, but
985103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius * it'll produce the same result.
986103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius */
987103e9ffba2cba345d0078eb8b8db33249f81840aCraig Corneliusvoid
988103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusModulusSubstitution::toString(UnicodeString& text) const
989103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius{
990103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius  // use tokenChar() to get the character at the beginning and
991103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius  // end of the substitutin token.  In between them will go
992103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius  // either the name of the rule set it uses, or the pattern of
993103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius  // the DecimalFormat it uses
994b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
995103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius  if ( ruleToUse != NULL ) { // Must have been a >>> substitution.
996103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius      text.remove();
997103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius      text.append(tokenChar());
998103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius      text.append(tokenChar());
999103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius      text.append(tokenChar());
1000103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius  } else { // Otherwise just use the super-class function.
1001103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius	  NFSubstitution::toString(text);
1002103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius  }
1003103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius}
1004b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//===================================================================
1005b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// IntegralPartSubstitution
1006b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//===================================================================
1007b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1008b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUOBJECT_DEFINE_RTTI_IMPLEMENTATION(IntegralPartSubstitution)
1009b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1010b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1011b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//===================================================================
1012b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// FractionalPartSubstitution
1013b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//===================================================================
1014b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1015b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1016b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /**
1017b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru     * Constructs a FractionalPartSubstitution.  This object keeps a flag
1018b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru     * telling whether it should format by digits or not.  In addition,
1019b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru     * it marks the rule set it calls (if any) as a fraction rule set.
1020b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru     */
1021b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruFractionalPartSubstitution::FractionalPartSubstitution(int32_t _pos,
1022b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                             const NFRuleSet* _ruleSet,
1023b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                             const RuleBasedNumberFormat* formatter,
1024b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                             const UnicodeString& description,
1025b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                             UErrorCode& status)
1026b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru : NFSubstitution(_pos, _ruleSet, formatter, description, status)
1027b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru , byDigits(FALSE)
1028b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru , useSpaces(TRUE)
1029b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1030b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
1031b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // akk, ruleSet can change in superclass constructor
1032103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    if (0 == description.compare(gGreaterGreaterThan, 2) ||
1033103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        0 == description.compare(gGreaterGreaterGreaterThan, 3) ||
1034b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        _ruleSet == getRuleSet()) {
1035b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        byDigits = TRUE;
1036103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        if (0 == description.compare(gGreaterGreaterGreaterThan, 3)) {
1037b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            useSpaces = FALSE;
1038b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1039b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else {
1040b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // cast away const
1041b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        ((NFRuleSet*)getRuleSet())->makeIntoFractionRuleSet();
1042b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1043b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1044b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1045b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//-----------------------------------------------------------------------
1046b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// formatting
1047b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//-----------------------------------------------------------------------
1048b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1049b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
1050b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * If in "by digits" mode, fills in the substitution one decimal digit
1051b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * at a time using the rule set containing this substitution.
1052b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Otherwise, uses the superclass function.
1053b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param number The number being formatted
1054b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param toInsertInto The string to insert the result of formatting
1055b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * the substitution into
1056b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param pos The position of the owning rule's rule text in
1057b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * toInsertInto
1058b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
1059b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid
1060f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusFractionalPartSubstitution::doSubstitution(double number, UnicodeString& toInsertInto,
1061f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius                                           int32_t _pos, UErrorCode& status) const
1062b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
1063b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  // if we're not in "byDigits" mode, just use the inherited
1064b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  // doSubstitution() routine
1065b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  if (!byDigits) {
1066f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    NFSubstitution::doSubstitution(number, toInsertInto, _pos, status);
1067b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1068b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // if we're in "byDigits" mode, transform the value into an integer
1069b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // by moving the decimal point eight places to the right and
1070b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // pulling digits off the right one at a time, formatting each digit
1071b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // as an integer using this substitution's owning rule set
1072b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // (this is slower, but more accurate, than doing it from the
1073b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // other end)
1074b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  } else {
1075b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    //          int32_t numberToFormat = (int32_t)uprv_round(transformNumber(number) * uprv_pow(10, kMaxDecimalDigits));
1076b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    //          // this flag keeps us from formatting trailing zeros.  It starts
1077b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    //          // out false because we're pulling from the right, and switches
1078b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    //          // to true the first time we encounter a non-zero digit
1079b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    //          UBool doZeros = FALSE;
1080b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    //          for (int32_t i = 0; i < kMaxDecimalDigits; i++) {
1081b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    //              int64_t digit = numberToFormat % 10;
1082b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    //              if (digit != 0 || doZeros) {
1083b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    //                  if (doZeros && useSpaces) {
1084b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    //                      toInsertInto.insert(_pos + getPos(), gSpace);
1085b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    //                  }
1086b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    //                  doZeros = TRUE;
1087b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    //                  getRuleSet()->format(digit, toInsertInto, _pos + getPos());
1088b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    //              }
1089b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    //              numberToFormat /= 10;
1090b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    //          }
1091b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1092b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    DigitList dl;
109350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    dl.set(number);
109450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    dl.roundFixedPoint(20);     // round to 20 fraction digits.
109550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    dl.reduce();                // Removes any trailing zeros.
1096b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1097b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UBool pad = FALSE;
109850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    for (int32_t didx = dl.getCount()-1; didx>=dl.getDecimalAt(); didx--) {
109950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho      // Loop iterates over fraction digits, starting with the LSD.
110050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho      //   include both real digits from the number, and zeros
110150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho      //   to the left of the MSD but to the right of the decimal point.
1102b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru      if (pad && useSpaces) {
1103b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        toInsertInto.insert(_pos + getPos(), gSpace);
1104b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru      } else {
1105b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        pad = TRUE;
1106b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru      }
110750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho      int64_t digit = didx>=0 ? dl.getDigit(didx) - '0' : 0;
1108f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius      getRuleSet()->format(digit, toInsertInto, _pos + getPos(), status);
1109b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1110b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1111b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (!pad) {
1112b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru      // hack around lack of precision in digitlist. if we would end up with
1113b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru      // "foo point" make sure we add a " zero" to the end.
1114f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius      getRuleSet()->format((int64_t)0, toInsertInto, _pos + getPos(), status);
1115b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1116b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  }
1117b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1118b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1119b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//-----------------------------------------------------------------------
1120b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// parsing
1121b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//-----------------------------------------------------------------------
1122b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1123b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
1124b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * If in "by digits" mode, parses the string as if it were a string
1125b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * of individual digits; otherwise, uses the superclass function.
1126b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param text The string to parse
1127b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param parsePosition Ignored on entry, but updated on exit to point
1128b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * to the first unmatched character
1129b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param baseValue The partial parse result prior to entering this
1130b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * function
1131b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param upperBound Only consider rules with base values lower than
1132b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * this when filling in the substitution
1133b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param lenientParse If true, try matching the text as numerals if
1134b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * matching as words doesn't work
1135b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @return If the match was successful, the current partial parse
1136b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * result; otherwise new Long(0).  The result is either a Long or
1137b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * a Double.
1138b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
1139b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1140b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUBool
1141b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruFractionalPartSubstitution::doParse(const UnicodeString& text,
1142b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                ParsePosition& parsePosition,
1143b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                double baseValue,
1144b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                double /*upperBound*/,
1145b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                UBool lenientParse,
1146b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                Formattable& resVal) const
1147b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
1148b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // if we're not in byDigits mode, we can just use the inherited
1149b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // doParse()
1150b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (!byDigits) {
1151b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return NFSubstitution::doParse(text, parsePosition, baseValue, 0, lenientParse, resVal);
1152b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1153b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // if we ARE in byDigits mode, parse the text one digit at a time
1154b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // using this substitution's owning rule set (we do this by setting
1155b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // upperBound to 10 when calling doParse() ) until we reach
1156b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // nonmatching text
1157b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else {
1158b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        UnicodeString workText(text);
1159b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        ParsePosition workPos(1);
1160b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        double result = 0;
1161b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        int32_t digit;
1162b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//          double p10 = 0.1;
1163b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1164b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        DigitList dl;
1165b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        NumberFormat* fmt = NULL;
1166b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        while (workText.length() > 0 && workPos.getIndex() != 0) {
1167b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            workPos.setIndex(0);
1168b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            Formattable temp;
1169b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            getRuleSet()->parse(workText, workPos, 10, temp);
1170b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            UErrorCode status = U_ZERO_ERROR;
1171b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            digit = temp.getLong(status);
1172b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//            digit = temp.getType() == Formattable::kLong ?
1173b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//               temp.getLong() :
1174b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//            (int32_t)temp.getDouble();
1175b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1176b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (lenientParse && workPos.getIndex() == 0) {
1177b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (!fmt) {
1178b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    status = U_ZERO_ERROR;
1179b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    fmt = NumberFormat::createInstance(status);
1180b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    if (U_FAILURE(status)) {
1181b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        delete fmt;
1182b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        fmt = NULL;
1183b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    }
1184b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
1185b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (fmt) {
1186b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    fmt->parse(workText, temp, workPos);
1187b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    digit = temp.getLong(status);
1188b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
1189b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
1190b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1191b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (workPos.getIndex() != 0) {
1192b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                dl.append((char)('0' + digit));
1193b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//                  result += digit * p10;
1194b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//                  p10 /= 10;
1195b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                parsePosition.setIndex(parsePosition.getIndex() + workPos.getIndex());
1196b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                workText.removeBetween(0, workPos.getIndex());
1197b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                while (workText.length() > 0 && workText.charAt(0) == gSpace) {
1198b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    workText.removeBetween(0, 1);
1199b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    parsePosition.setIndex(parsePosition.getIndex() + 1);
1200b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
1201b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
1202b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1203b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        delete fmt;
1204b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
120550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        result = dl.getCount() == 0 ? 0 : dl.getDouble();
1206b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        result = composeRuleValue(result, baseValue);
1207b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        resVal.setDouble(result);
1208b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return TRUE;
1209b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1210b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1211b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1212b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUBool
1213b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruFractionalPartSubstitution::operator==(const NFSubstitution& rhs) const
1214b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
1215b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  return NFSubstitution::operator==(rhs) &&
1216b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  ((const FractionalPartSubstitution*)&rhs)->byDigits == byDigits;
1217b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1218b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1219b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUOBJECT_DEFINE_RTTI_IMPLEMENTATION(FractionalPartSubstitution)
1220b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1221b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1222b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//===================================================================
1223b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// AbsoluteValueSubstitution
1224b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//===================================================================
1225b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1226b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUOBJECT_DEFINE_RTTI_IMPLEMENTATION(AbsoluteValueSubstitution)
1227b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1228b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//===================================================================
1229b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// NumeratorSubstitution
1230b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//===================================================================
1231b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1232b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid
1233f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusNumeratorSubstitution::doSubstitution(double number, UnicodeString& toInsertInto, int32_t apos, UErrorCode& status) const {
1234b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // perform a transformation on the number being formatted that
1235b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // is dependent on the type of substitution this is
1236b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1237b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    double numberToFormat = transformNumber(number);
1238b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int64_t longNF = util64_fromDouble(numberToFormat);
1239b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1240b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const NFRuleSet* aruleSet = getRuleSet();
1241b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (withZeros && aruleSet != NULL) {
1242b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // if there are leading zeros in the decimal expansion then emit them
1243b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        int64_t nf =longNF;
1244b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        int32_t len = toInsertInto.length();
1245b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        while ((nf *= 10) < denominator) {
1246b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            toInsertInto.insert(apos + getPos(), gSpace);
1247f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius            aruleSet->format((int64_t)0, toInsertInto, apos + getPos(), status);
1248b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1249b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        apos += toInsertInto.length() - len;
1250b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1251b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1252b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // if the result is an integer, from here on out we work in integer
1253b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // space (saving time and memory and preserving accuracy)
1254b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (numberToFormat == longNF && aruleSet != NULL) {
1255f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        aruleSet->format(longNF, toInsertInto, apos + getPos(), status);
1256b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1257b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // if the result isn't an integer, then call either our rule set's
1258b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // format() method or our DecimalFormat's format() method to
1259b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // format the result
1260b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else {
1261b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (aruleSet != NULL) {
1262f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius            aruleSet->format(numberToFormat, toInsertInto, apos + getPos(), status);
1263b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else {
1264b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            UnicodeString temp;
1265b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            getNumberFormat()->format(numberToFormat, temp, status);
1266b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            toInsertInto.insert(apos + getPos(), temp);
1267b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1268b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1269b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1270b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1271b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUBool
1272b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruNumeratorSubstitution::doParse(const UnicodeString& text,
1273b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                               ParsePosition& parsePosition,
1274b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                               double baseValue,
1275b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                               double upperBound,
1276b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                               UBool /*lenientParse*/,
1277b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                               Formattable& result) const
1278b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
1279b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // we don't have to do anything special to do the parsing here,
1280b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // but we have to turn lenient parsing off-- if we leave it on,
1281b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // it SERIOUSLY messes up the algorithm
1282b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1283b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // if withZeros is true, we need to count the zeros
1284b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // and use that to adjust the parse result
1285b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UErrorCode status = U_ZERO_ERROR;
1286b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t zeroCount = 0;
1287b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UnicodeString workText(text);
1288b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1289b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (withZeros) {
1290b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        ParsePosition workPos(1);
1291b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        Formattable temp;
1292b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1293b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        while (workText.length() > 0 && workPos.getIndex() != 0) {
1294b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            workPos.setIndex(0);
1295b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            getRuleSet()->parse(workText, workPos, 1, temp); // parse zero or nothing at all
1296b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (workPos.getIndex() == 0) {
1297b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                // we failed, either there were no more zeros, or the number was formatted with digits
1298b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                // either way, we're done
1299b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                break;
1300b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
1301b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1302b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            ++zeroCount;
1303b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            parsePosition.setIndex(parsePosition.getIndex() + workPos.getIndex());
1304b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            workText.remove(0, workPos.getIndex());
1305b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            while (workText.length() > 0 && workText.charAt(0) == gSpace) {
1306b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                workText.remove(0, 1);
1307b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                parsePosition.setIndex(parsePosition.getIndex() + 1);
1308b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
1309b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1310b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1311b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        workText = text;
1312b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        workText.remove(0, (int32_t)parsePosition.getIndex());
1313b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        parsePosition.setIndex(0);
1314b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1315b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1316b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // we've parsed off the zeros, now let's parse the rest from our current position
1317b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    NFSubstitution::doParse(workText, parsePosition, withZeros ? 1 : baseValue, upperBound, FALSE, result);
1318b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1319b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (withZeros) {
1320b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // any base value will do in this case.  is there a way to
1321b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // force this to not bother trying all the base values?
1322b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1323b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // compute the 'effective' base and prescale the value down
1324b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        int64_t n = result.getLong(status); // force conversion!
1325b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        int64_t d = 1;
1326b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        int32_t pow = 0;
1327b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        while (d <= n) {
1328b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            d *= 10;
1329b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            ++pow;
1330b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1331b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // now add the zeros
1332b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        while (zeroCount > 0) {
1333b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            d *= 10;
1334b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            --zeroCount;
1335b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1336b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // d is now our true denominator
1337b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        result.setDouble((double)n/(double)d);
1338b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1339b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1340b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return TRUE;
1341b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1342b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1343b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUBool
1344b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruNumeratorSubstitution::operator==(const NFSubstitution& rhs) const
1345b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
1346b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return NFSubstitution::operator==(rhs) &&
1347b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        denominator == ((const NumeratorSubstitution*)&rhs)->denominator;
1348b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1349b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1350b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUOBJECT_DEFINE_RTTI_IMPLEMENTATION(NumeratorSubstitution)
1351b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1352b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruconst UChar NumeratorSubstitution::LTLT[] = { 0x003c, 0x003c };
1353b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1354b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//===================================================================
1355b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// NullSubstitution
1356b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//===================================================================
1357b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1358b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUOBJECT_DEFINE_RTTI_IMPLEMENTATION(NullSubstitution)
1359b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1360b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_NAMESPACE_END
1361b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1362b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/* U_HAVE_RBNF */
1363b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#endif
1364b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1365