]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/i18n/decimfmt.cpp
ICU-531.48.tar.gz
[apple/icu.git] / icuSources / i18n / decimfmt.cpp
index 7eccdf40d2cdc9f8d84e13fbb8357c8de7239c80..207abaf7613fa2bbcddf214e698fef5a29fe671c 100644 (file)
@@ -1,6 +1,6 @@
 /*
 *******************************************************************************
-* Copyright (C) 1997-2012, International Business Machines Corporation and    *
+* Copyright (C) 1997-2014, International Business Machines Corporation and    *
 * others. All Rights Reserved.                                                *
 *******************************************************************************
 *
 #include <math.h>
 #include "hash.h"
 #include "decfmtst.h"
+#include "dcfmtimp.h"
+#include "plurrule_impl.h"
+#include "decimalformatpattern.h"
+
+/*
+ * On certain platforms, round is a macro defined in math.h
+ * This undefine is to avoid conflict between the macro and
+ * the function defined below.
+ */
+#ifdef round
+#undef round
+#endif
 
 
 U_NAMESPACE_BEGIN
 
+#ifdef FMT_DEBUG
+#include <stdio.h>
+static void _debugout(const char *f, int l, const UnicodeString& s) {
+    char buf[2000];
+    s.extract((int32_t) 0, s.length(), buf, "utf-8");
+    printf("%s:%d: %s\n", f,l, buf);
+}
+#define debugout(x) _debugout(__FILE__,__LINE__,x)
+#define debug(x) printf("%s:%d: %s\n", __FILE__,__LINE__, x);
+static const UnicodeString dbg_null("<NULL>","");
+#define DEREFSTR(x)   ((x!=NULL)?(*x):(dbg_null))
+#else
+#define debugout(x)
+#define debug(x)
+#endif
+
+
+
+/* == Fastpath calculation. ==
+ */
+#if UCONFIG_FORMAT_FASTPATHS_49
+inline DecimalFormatInternal& internalData(uint8_t *reserved) {
+  return *reinterpret_cast<DecimalFormatInternal*>(reserved);
+}
+inline const DecimalFormatInternal& internalData(const uint8_t *reserved) {
+  return *reinterpret_cast<const DecimalFormatInternal*>(reserved);
+}
+#else
+#endif
+
 /* For currency parsing purose,
  * Need to remember all prefix patterns and suffix patterns of
  * every currency format pattern,
@@ -101,6 +143,15 @@ struct AffixPatternsForCurrency : public UMemory {
                posSuffixPatternForCurrency = posSuffix;
                patternType = type;
        }
+#ifdef FMT_DEBUG
+  void dump() const  {
+    debugout( UnicodeString("AffixPatternsForCurrency( -=\"") +
+              negPrefixPatternForCurrency + (UnicodeString)"\"/\"" +
+              negSuffixPatternForCurrency + (UnicodeString)"\" +=\"" + 
+              posPrefixPatternForCurrency + (UnicodeString)"\"/\"" + 
+              posSuffixPatternForCurrency + (UnicodeString)"\" )");
+  }
+#endif
 };
 
 /* affix for currency formatting when the currency sign in the pattern
@@ -128,6 +179,15 @@ struct AffixesForCurrency : public UMemory {
                posPrefixForCurrency = posPrefix;
                posSuffixForCurrency = posSuffix;
        }
+#ifdef FMT_DEBUG
+  void dump() const {
+    debugout( UnicodeString("AffixesForCurrency( -=\"") +
+              negPrefixForCurrency + (UnicodeString)"\"/\"" +
+              negSuffixForCurrency + (UnicodeString)"\" +=\"" + 
+              posPrefixForCurrency + (UnicodeString)"\"/\"" + 
+              posSuffixForCurrency + (UnicodeString)"\" )");
+  }
+#endif
 };
 
 U_CDECL_BEGIN
@@ -176,21 +236,6 @@ U_CALLCONV decimfmtAffixPatternValueComparator(UHashTok val1, UHashTok val2) {
 U_CDECL_END
 
 
-//#define FMT_DEBUG
-
-#ifdef FMT_DEBUG
-#include <stdio.h>
-static void debugout(UnicodeString s) {
-    char buf[2000];
-    s.extract((int32_t) 0, s.length(), buf);
-    printf("%s\n", buf);
-}
-#define debug(x) printf("%s\n", x);
-#else
-#define debugout(x)
-#define debug(x)
-#endif
-
 
 
 // *****************************************************************************
@@ -238,11 +283,33 @@ static const char fgLatn[]="latn";
 static const char fgPatterns[]="patterns";
 static const char fgDecimalFormat[]="decimalFormat";
 static const char fgCurrencyFormat[]="currencyFormat";
+
 static const UChar fgTripleCurrencySign[] = {0xA4, 0xA4, 0xA4, 0};
 
 inline int32_t _min(int32_t a, int32_t b) { return (a<b) ? a : b; }
 inline int32_t _max(int32_t a, int32_t b) { return (a<b) ? b : a; }
 
+static void copyString(const UnicodeString& src, UBool isBogus, UnicodeString *& dest, UErrorCode &status) {
+    if (U_FAILURE(status)) {
+        return;
+    }
+    if (isBogus) {
+        delete dest;
+        dest = NULL;
+    } else {
+        if (dest != NULL) {
+            *dest = src;
+        } else {
+            dest = new UnicodeString(src);
+            if (dest == NULL) {
+                status = U_MEMORY_ALLOCATION_ERROR;
+                return;
+            }
+        }
+    }
+}
+
+
 //------------------------------------------------------------------------------
 // Constructs a DecimalFormat instance in the default locale.
 
@@ -320,6 +387,8 @@ DecimalFormat::DecimalFormat(const UnicodeString& pattern,
 // Common DecimalFormat initialization.
 //    Put all fields of an uninitialized object into a known state.
 //    Common code, shared by all constructors.
+//    Can not fail. Leave the object in good enough shape that the destructor
+//    or assignment operator can run successfully.
 void
 DecimalFormat::init() {
     fPosPrefixPattern = 0;
@@ -328,6 +397,7 @@ DecimalFormat::init() {
     fNegSuffixPattern = 0;
     fCurrencyChoice = 0;
     fMultiplier = NULL;
+    fScale = 0;
     fGroupingSize = 0;
     fGroupingSize2 = 0;
     fDecimalSeparatorAlwaysShown = FALSE;
@@ -338,17 +408,28 @@ DecimalFormat::init() {
     fUseExponentialNotation = FALSE;
     fMinExponentDigits = 0;
     fExponentSignAlwaysShown = FALSE;
+    fBoolFlags.clear();
     fRoundingIncrement = 0;
     fRoundingMode = kRoundHalfEven;
     fPad = 0;
     fFormatWidth = 0;
     fPadPosition = kPadBeforePrefix;
     fStyle = UNUM_DECIMAL;
-    fCurrencySignCount = 0;
+    fCurrencySignCount = fgCurrencySignCountZero;
     fAffixPatternsForCurrency = NULL;
     fAffixesForCurrency = NULL;
     fPluralAffixesForCurrency = NULL;
     fCurrencyPluralInfo = NULL;
+#if UCONFIG_HAVE_PARSEALLINPUT
+    fParseAllInput = UNUM_MAYBE;
+#endif
+
+#if UCONFIG_FORMAT_FASTPATHS_49
+    DecimalFormatInternal &data = internalData(fReserved);
+    data.fFastFormatStatus=kFastpathUNKNOWN; // don't try to calculate the fastpath until later.
+    data.fFastParseStatus=kFastpathUNKNOWN; // don't try to calculate the fastpath until later.
+#endif
+    fStaticSets = NULL;
 }
 
 //------------------------------------------------------------------------------
@@ -357,7 +438,7 @@ DecimalFormat::init() {
 // created instance owns the symbols.
 
 void
-DecimalFormat::construct(UErrorCode&             status,
+DecimalFormat::construct(UErrorCode&            status,
                          UParseError&           parseErr,
                          const UnicodeString*   pattern,
                          DecimalFormatSymbols*  symbolsToAdopt)
@@ -382,12 +463,15 @@ DecimalFormat::construct(UErrorCode&             status,
     if (fSymbols == NULL)
     {
         fSymbols = new DecimalFormatSymbols(Locale::getDefault(), status);
-        /* test for NULL */
         if (fSymbols == 0) {
             status = U_MEMORY_ALLOCATION_ERROR;
             return;
         }
     }
+    fStaticSets = DecimalFormatStaticSets::getStaticSets(status);
+    if (U_FAILURE(status)) {
+        return;
+    }
     UErrorCode nsStatus = U_ZERO_ERROR;
     NumberingSystem *ns = NumberingSystem::createInstance(nsStatus);
     if (U_FAILURE(nsStatus)) {
@@ -486,9 +570,15 @@ DecimalFormat::construct(UErrorCode&             status,
 
     // If it was a currency format, apply the appropriate rounding by
     // resetting the currency. NOTE: this copies fCurrency on top of itself.
-    if (fCurrencySignCount > fgCurrencySignCountZero) {
+    if (fCurrencySignCount != fgCurrencySignCountZero) {
         setCurrencyInternally(getCurrency(), status);
     }
+#if UCONFIG_FORMAT_FASTPATHS_49
+    DecimalFormatInternal &data = internalData(fReserved);
+    data.fFastFormatStatus = kFastpathNO; // allow it to be calculated
+    data.fFastParseStatus = kFastpathNO; // allow it to be calculated
+    handleChanged();
+#endif
 }
 
 
@@ -661,14 +751,25 @@ DecimalFormat::DecimalFormat(const DecimalFormat &source) :
 //------------------------------------------------------------------------------
 // assignment operator
 
-static void _copy_us_ptr(UnicodeString** pdest, const UnicodeString* source) {
+template <class T>
+static void _copy_ptr(T** pdest, const T* source) {
     if (source == NULL) {
         delete *pdest;
         *pdest = NULL;
     } else if (*pdest == NULL) {
-        *pdest = new UnicodeString(*source);
+        *pdest = new T(*source);
     } else {
-        **pdest  = *source;
+        **pdest = *source;
+    }
+}
+
+template <class T>
+static void _clone_ptr(T** pdest, const T* source) {
+    delete *pdest;
+    if (source == NULL) {
+        *pdest = NULL;
+    } else {
+        *pdest = static_cast<T*>(source->clone());
     }
 }
 
@@ -676,34 +777,28 @@ DecimalFormat&
 DecimalFormat::operator=(const DecimalFormat& rhs)
 {
     if(this != &rhs) {
+        UErrorCode status = U_ZERO_ERROR;
         NumberFormat::operator=(rhs);
+        fStaticSets     = DecimalFormatStaticSets::getStaticSets(status);
         fPositivePrefix = rhs.fPositivePrefix;
         fPositiveSuffix = rhs.fPositiveSuffix;
         fNegativePrefix = rhs.fNegativePrefix;
         fNegativeSuffix = rhs.fNegativeSuffix;
-        _copy_us_ptr(&fPosPrefixPattern, rhs.fPosPrefixPattern);
-        _copy_us_ptr(&fPosSuffixPattern, rhs.fPosSuffixPattern);
-        _copy_us_ptr(&fNegPrefixPattern, rhs.fNegPrefixPattern);
-        _copy_us_ptr(&fNegSuffixPattern, rhs.fNegSuffixPattern);
-        if (rhs.fCurrencyChoice == 0) {
-            delete fCurrencyChoice;
-            fCurrencyChoice = 0;
-        } else {
-            fCurrencyChoice = (ChoiceFormat*) rhs.fCurrencyChoice->clone();
-        }
+        _copy_ptr(&fPosPrefixPattern, rhs.fPosPrefixPattern);
+        _copy_ptr(&fPosSuffixPattern, rhs.fPosSuffixPattern);
+        _copy_ptr(&fNegPrefixPattern, rhs.fNegPrefixPattern);
+        _copy_ptr(&fNegSuffixPattern, rhs.fNegSuffixPattern);
+        _clone_ptr(&fCurrencyChoice, rhs.fCurrencyChoice);
         setRoundingIncrement(rhs.getRoundingIncrement());
         fRoundingMode = rhs.fRoundingMode;
         setMultiplier(rhs.getMultiplier());
         fGroupingSize = rhs.fGroupingSize;
         fGroupingSize2 = rhs.fGroupingSize2;
         fDecimalSeparatorAlwaysShown = rhs.fDecimalSeparatorAlwaysShown;
-        if(fSymbols == NULL) {
-            fSymbols = new DecimalFormatSymbols(*rhs.fSymbols);
-        } else {
-            *fSymbols = *rhs.fSymbols;
-        }
+        _copy_ptr(&fSymbols, rhs.fSymbols);
         fUseExponentialNotation = rhs.fUseExponentialNotation;
         fExponentSignAlwaysShown = rhs.fExponentSignAlwaysShown;
+        fBoolFlags = rhs.fBoolFlags;
         /*Bertrand A. D. Update 98.03.17*/
         fCurrencySignCount = rhs.fCurrencySignCount;
         /*end of Update*/
@@ -719,30 +814,31 @@ DecimalFormat::operator=(const DecimalFormat& rhs)
         fUseSignificantDigits = rhs.fUseSignificantDigits;
         fFormatPattern = rhs.fFormatPattern;
         fStyle = rhs.fStyle;
-        fCurrencySignCount = rhs.fCurrencySignCount;
-        if (rhs.fCurrencyPluralInfo) {
-            delete fCurrencyPluralInfo;
-            fCurrencyPluralInfo = rhs.fCurrencyPluralInfo->clone();
-        }
+        _clone_ptr(&fCurrencyPluralInfo, rhs.fCurrencyPluralInfo);
+        deleteHashForAffixPattern();
         if (rhs.fAffixPatternsForCurrency) {
             UErrorCode status = U_ZERO_ERROR;
-            deleteHashForAffixPattern();
             fAffixPatternsForCurrency = initHashForAffixPattern(status);
             copyHashForAffixPattern(rhs.fAffixPatternsForCurrency,
                                     fAffixPatternsForCurrency, status);
         }
+        deleteHashForAffix(fAffixesForCurrency);
         if (rhs.fAffixesForCurrency) {
             UErrorCode status = U_ZERO_ERROR;
-            deleteHashForAffix(fAffixesForCurrency);
             fAffixesForCurrency = initHashForAffixPattern(status);
             copyHashForAffix(rhs.fAffixesForCurrency, fAffixesForCurrency, status);
         }
+        deleteHashForAffix(fPluralAffixesForCurrency);
         if (rhs.fPluralAffixesForCurrency) {
             UErrorCode status = U_ZERO_ERROR;
-            deleteHashForAffix(fPluralAffixesForCurrency);
             fPluralAffixesForCurrency = initHashForAffixPattern(status);
             copyHashForAffix(rhs.fPluralAffixesForCurrency, fPluralAffixesForCurrency, status);
         }
+#if UCONFIG_FORMAT_FASTPATHS_49
+        DecimalFormatInternal &data    = internalData(fReserved);
+        const DecimalFormatInternal &rhsData = internalData(rhs.fReserved);
+        data = rhsData;
+#endif
     }
     return *this;
 }
@@ -831,6 +927,10 @@ DecimalFormat::operator==(const Format& that) const
         if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
         debug("Rounding Increment !=");
               }
+    if (fRoundingMode != other->fRoundingMode) {
+        if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+        printf("Rounding Mode %d != %d", (int)fRoundingMode, (int)other->fRoundingMode);
+    }
     if (getMultiplier() != other->getMultiplier()) {
         if (first) { printf("[ "); first = FALSE; }
         printf("Multiplier %ld != %ld", getMultiplier(), other->getMultiplier());
@@ -845,16 +945,25 @@ DecimalFormat::operator==(const Format& that) const
     }
     if (fDecimalSeparatorAlwaysShown != other->fDecimalSeparatorAlwaysShown) {
         if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
-        printf("Dec Sep Always %d != %d", fDecimalSeparatorAlwaysShown, other->fDecimalSeparatorAlwaysShown);
+        printf("fDecimalSeparatorAlwaysShown %d != %d", fDecimalSeparatorAlwaysShown, other->fDecimalSeparatorAlwaysShown);
     }
     if (fUseExponentialNotation != other->fUseExponentialNotation) {
         if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
-        debug("Use Exp !=");
+        debug("fUseExponentialNotation !=");
+    }
+    if (fUseExponentialNotation &&
+        fMinExponentDigits != other->fMinExponentDigits) {
+        if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+        debug("fMinExponentDigits !=");
     }
-    if (!(!fUseExponentialNotation ||
-          fMinExponentDigits != other->fMinExponentDigits)) {
+    if (fUseExponentialNotation &&
+        fExponentSignAlwaysShown != other->fExponentSignAlwaysShown) {
         if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
-        debug("Exp Digits !=");
+        debug("fExponentSignAlwaysShown !=");
+    }
+    if (fBoolFlags.getAll() != other->fBoolFlags.getAll()) {
+        if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+        debug("fBoolFlags !=");
     }
     if (*fSymbols != *(other->fSymbols)) {
         if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
@@ -862,16 +971,41 @@ DecimalFormat::operator==(const Format& that) const
     }
     // TODO Add debug stuff for significant digits here
     if (fUseSignificantDigits != other->fUseSignificantDigits) {
+        if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
         debug("fUseSignificantDigits !=");
     }
     if (fUseSignificantDigits &&
         fMinSignificantDigits != other->fMinSignificantDigits) {
+        if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
         debug("fMinSignificantDigits !=");
     }
     if (fUseSignificantDigits &&
         fMaxSignificantDigits != other->fMaxSignificantDigits) {
+        if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
         debug("fMaxSignificantDigits !=");
     }
+    if (fFormatWidth != other->fFormatWidth) {
+        if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+        debug("fFormatWidth !=");
+    }
+    if (fPad != other->fPad) {
+        if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+        debug("fPad !=");
+    }
+    if (fPadPosition != other->fPadPosition) {
+        if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+        debug("fPadPosition !=");
+    }
+    if (fStyle == UNUM_CURRENCY_PLURAL &&
+        fStyle != other->fStyle)
+        if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+        debug("fStyle !=");
+    }
+    if (fStyle == UNUM_CURRENCY_PLURAL &&
+        fFormatPattern != other->fFormatPattern) {
+        if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+        debug("fFormatPattern !=");
+    }
 
     if (!first) { printf(" ]"); }
     if (fCurrencySignCount != other->fCurrencySignCount) {
@@ -897,46 +1031,68 @@ DecimalFormat::operator==(const Format& that) const
     }
 #endif
 
-    return (NumberFormat::operator==(that) &&
-            ((fCurrencySignCount == fgCurrencySignCountInPluralFormat) ?
-            (fAffixPatternsForCurrency->equals(*other->fAffixPatternsForCurrency)) :
-            (((fPosPrefixPattern == other->fPosPrefixPattern && // both null
-              fPositivePrefix == other->fPositivePrefix)
-             || (fPosPrefixPattern != 0 && other->fPosPrefixPattern != 0 &&
-                 *fPosPrefixPattern  == *other->fPosPrefixPattern)) &&
-            ((fPosSuffixPattern == other->fPosSuffixPattern && // both null
-              fPositiveSuffix == other->fPositiveSuffix)
-             || (fPosSuffixPattern != 0 && other->fPosSuffixPattern != 0 &&
-                 *fPosSuffixPattern  == *other->fPosSuffixPattern)) &&
-            ((fNegPrefixPattern == other->fNegPrefixPattern && // both null
-              fNegativePrefix == other->fNegativePrefix)
-             || (fNegPrefixPattern != 0 && other->fNegPrefixPattern != 0 &&
-                 *fNegPrefixPattern  == *other->fNegPrefixPattern)) &&
-            ((fNegSuffixPattern == other->fNegSuffixPattern && // both null
-              fNegativeSuffix == other->fNegativeSuffix)
-             || (fNegSuffixPattern != 0 && other->fNegSuffixPattern != 0 &&
-                 *fNegSuffixPattern  == *other->fNegSuffixPattern)))) &&
-            ((fRoundingIncrement == other->fRoundingIncrement) // both null
-             || (fRoundingIncrement != NULL &&
-                 other->fRoundingIncrement != NULL &&
-                 *fRoundingIncrement == *other->fRoundingIncrement)) &&
+    return (
+        NumberFormat::operator==(that) &&
+
+        ((fCurrencySignCount == fgCurrencySignCountInPluralFormat) ?
+        (fAffixPatternsForCurrency->equals(*other->fAffixPatternsForCurrency)) :
+        (((fPosPrefixPattern == other->fPosPrefixPattern && // both null
+          fPositivePrefix == other->fPositivePrefix)
+         || (fPosPrefixPattern != 0 && other->fPosPrefixPattern != 0 &&
+             *fPosPrefixPattern  == *other->fPosPrefixPattern)) &&
+        ((fPosSuffixPattern == other->fPosSuffixPattern && // both null
+          fPositiveSuffix == other->fPositiveSuffix)
+         || (fPosSuffixPattern != 0 && other->fPosSuffixPattern != 0 &&
+             *fPosSuffixPattern  == *other->fPosSuffixPattern)) &&
+        ((fNegPrefixPattern == other->fNegPrefixPattern && // both null
+          fNegativePrefix == other->fNegativePrefix)
+         || (fNegPrefixPattern != 0 && other->fNegPrefixPattern != 0 &&
+             *fNegPrefixPattern  == *other->fNegPrefixPattern)) &&
+        ((fNegSuffixPattern == other->fNegSuffixPattern && // both null
+          fNegativeSuffix == other->fNegativeSuffix)
+         || (fNegSuffixPattern != 0 && other->fNegSuffixPattern != 0 &&
+             *fNegSuffixPattern  == *other->fNegSuffixPattern)))) &&
+
+        ((fRoundingIncrement == other->fRoundingIncrement) // both null
+         || (fRoundingIncrement != NULL &&
+             other->fRoundingIncrement != NULL &&
+             *fRoundingIncrement == *other->fRoundingIncrement)) &&
+
+        fRoundingMode == other->fRoundingMode &&
         getMultiplier() == other->getMultiplier() &&
         fGroupingSize == other->fGroupingSize &&
         fGroupingSize2 == other->fGroupingSize2 &&
         fDecimalSeparatorAlwaysShown == other->fDecimalSeparatorAlwaysShown &&
         fUseExponentialNotation == other->fUseExponentialNotation &&
+
         (!fUseExponentialNotation ||
-         fMinExponentDigits == other->fMinExponentDigits) &&
+            (fMinExponentDigits == other->fMinExponentDigits && fExponentSignAlwaysShown == other->fExponentSignAlwaysShown)) &&
+
+        fBoolFlags.getAll() == other->fBoolFlags.getAll() &&
         *fSymbols == *(other->fSymbols) &&
         fUseSignificantDigits == other->fUseSignificantDigits &&
+
         (!fUseSignificantDigits ||
-         (fMinSignificantDigits == other->fMinSignificantDigits &&
-          fMaxSignificantDigits == other->fMaxSignificantDigits)) &&
+            (fMinSignificantDigits == other->fMinSignificantDigits && fMaxSignificantDigits == other->fMaxSignificantDigits)) &&
+
+        fFormatWidth == other->fFormatWidth &&
+        fPad == other->fPad &&
+        fPadPosition == other->fPadPosition &&
+
+        (fStyle != UNUM_CURRENCY_PLURAL ||
+            (fStyle == other->fStyle && fFormatPattern == other->fFormatPattern)) &&
+
         fCurrencySignCount == other->fCurrencySignCount &&
+
         ((fCurrencyPluralInfo == other->fCurrencyPluralInfo &&
           fCurrencyPluralInfo == NULL) ||
          (fCurrencyPluralInfo != NULL && other->fCurrencyPluralInfo != NULL &&
-         *fCurrencyPluralInfo == *(other->fCurrencyPluralInfo))));
+         *fCurrencyPluralInfo == *(other->fCurrencyPluralInfo)))
+
+        // depending on other settings we may also need to compare
+        // fCurrencyChoice (mostly deprecated?),
+        // fAffixesForCurrency & fPluralAffixesForCurrency (only relevant in some cases)
+        );
 }
 
 //------------------------------------------------------------------------------
@@ -947,6 +1103,163 @@ DecimalFormat::clone() const
     return new DecimalFormat(*this);
 }
 
+
+FixedDecimal
+DecimalFormat::getFixedDecimal(double number, UErrorCode &status) const {
+    FixedDecimal result;
+
+    if (U_FAILURE(status)) {
+        return result;
+    }
+
+    if (uprv_isNaN(number) || uprv_isPositiveInfinity(fabs(number))) {
+        // For NaN and Infinity the state of the formatter is ignored.
+        result.init(number);
+        return result;
+    }
+
+    if (fMultiplier == NULL && fScale == 0 && fRoundingIncrement == 0 && areSignificantDigitsUsed() == FALSE &&
+            result.quickInit(number) && result.visibleDecimalDigitCount <= getMaximumFractionDigits()) {
+        // Fast Path. Construction of an exact FixedDecimal directly from the double, without passing
+        //   through a DigitList, was successful, and the formatter is doing nothing tricky with rounding.
+        // printf("getFixedDecimal(%g): taking fast path.\n", number);
+        result.adjustForMinFractionDigits(getMinimumFractionDigits());
+    } else {
+        // Slow path. Create a DigitList, and have this formatter round it according to the
+        //     requirements of the format, and fill the fixedDecimal from that.
+        DigitList digits;
+        digits.set(number);
+        result = getFixedDecimal(digits, status);
+    }
+    return result;
+}
+
+// MSVC optimizer bug? 
+// turn off optimization as it causes different behavior in the int64->double->int64 conversion
+#if defined (_MSC_VER)
+#pragma optimize ( "", off )
+#endif
+FixedDecimal
+DecimalFormat::getFixedDecimal(const Formattable &number, UErrorCode &status) const {
+    if (U_FAILURE(status)) {
+        return FixedDecimal();
+    }
+    if (!number.isNumeric()) {
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        return FixedDecimal();
+    }
+
+    DigitList *dl = number.getDigitList();
+    if (dl != NULL) {
+        DigitList clonedDL(*dl);
+        return getFixedDecimal(clonedDL, status);
+    }
+
+    Formattable::Type type = number.getType();
+    if (type == Formattable::kDouble || type == Formattable::kLong) { 
+        return getFixedDecimal(number.getDouble(status), status);
+    }
+
+    if (type == Formattable::kInt64) {
+        // "volatile" here is a workaround to avoid optimization issues.
+        volatile double fdv = number.getDouble(status);
+        // Note: conversion of int64_t -> double rounds with some compilers to
+        //       values beyond what can be represented as a 64 bit int. Subsequent
+        //       testing or conversion with int64_t produces bad results.
+        //       So filter the problematic values, route them to DigitList.
+        if (fdv != (double)U_INT64_MAX && fdv != (double)U_INT64_MIN &&
+                number.getInt64() == (int64_t)fdv) {
+            return getFixedDecimal(number.getDouble(status), status);
+        }
+    }
+
+    // The only case left is type==int64_t, with a value with more digits than a double can represent.
+    // Any formattable originating as a big decimal will have had a pre-existing digit list.
+    // Any originating as a double or int32 will have been handled as a double.
+
+    U_ASSERT(type == Formattable::kInt64);
+    DigitList digits;
+    digits.set(number.getInt64());
+    return getFixedDecimal(digits, status);
+}
+// end workaround MSVC optimizer bug
+#if defined (_MSC_VER)
+#pragma optimize ( "", on )
+#endif
+
+
+// Create a fixed decimal from a DigitList.
+//    The digit list may be modified.
+//    Internal function only.
+FixedDecimal
+DecimalFormat::getFixedDecimal(DigitList &number, UErrorCode &status) const {
+    // Round the number according to the requirements of this Format.
+    FixedDecimal result;
+    _round(number, number, result.isNegative, status);
+
+    // The int64_t fields in FixedDecimal can easily overflow.
+    // In deciding what to discard in this event, consider that fixedDecimal
+    //   is being used only with PluralRules, and those rules mostly look at least significant
+    //   few digits of the integer part, and whether the fraction part is zero or not.
+    // 
+    // So, in case of overflow when filling in the fields of the FixedDecimal object,
+    //    for the integer part, discard the most significant digits.
+    //    for the fraction part, discard the least significant digits,
+    //                           don't truncate the fraction value to zero.
+    // For simplicity, the int64_t fields are limited to 18 decimal digits, even
+    // though they could hold most (but not all) 19 digit values.
+
+    // Integer Digits.
+    int32_t di = number.getDecimalAt()-18;  // Take at most 18 digits.
+    if (di < 0) {
+        di = 0;
+    }
+    result.intValue = 0;
+    for (; di<number.getDecimalAt(); di++) {
+        result.intValue = result.intValue * 10 + (number.getDigit(di) & 0x0f);
+    }
+    if (result.intValue == 0 && number.getDecimalAt()-18 > 0) {
+        // The number is something like 100000000000000000000000.
+        // More than 18 digits integer digits, but the least significant 18 are all zero.
+        // We don't want to return zero as the int part, but want to keep zeros
+        //   for several of the least significant digits.
+        result.intValue = 100000000000000000LL;
+    }
+    
+    // Fraction digits.
+    result.decimalDigits = result.decimalDigitsWithoutTrailingZeros = result.visibleDecimalDigitCount = 0;
+    for (di = number.getDecimalAt(); di < number.getCount(); di++) {
+        result.visibleDecimalDigitCount++;
+        if (result.decimalDigits <  100000000000000000LL) {
+                   //              9223372036854775807    Largest 64 bit signed integer
+            int32_t digitVal = number.getDigit(di) & 0x0f;  // getDigit() returns a char, '0'-'9'.
+            result.decimalDigits = result.decimalDigits * 10 + digitVal;
+            if (digitVal > 0) {
+                result.decimalDigitsWithoutTrailingZeros = result.decimalDigits;
+            }
+        }
+    }
+
+    result.hasIntegerValue = (result.decimalDigits == 0);
+
+    // Trailing fraction zeros. The format specification may require more trailing
+    //    zeros than the numeric value. Add any such on now.
+
+    int32_t minFractionDigits;
+    if (areSignificantDigitsUsed()) {
+        minFractionDigits = getMinimumSignificantDigits() - number.getDecimalAt();
+        if (minFractionDigits < 0) {
+            minFractionDigits = 0;
+        }
+    } else {
+        minFractionDigits = getMinimumFractionDigits();
+    }
+    result.adjustForMinFractionDigits(minFractionDigits);
+
+    return result;
+}
+
+
 //------------------------------------------------------------------------------
 
 UnicodeString&
@@ -957,6 +1270,15 @@ DecimalFormat::format(int32_t number,
     return format((int64_t)number, appendTo, fieldPosition);
 }
 
+UnicodeString&
+DecimalFormat::format(int32_t number,
+                      UnicodeString& appendTo,
+                      FieldPosition& fieldPosition,
+                      UErrorCode& status) const
+{
+    return format((int64_t)number, appendTo, fieldPosition, status);
+}
+
 UnicodeString&
 DecimalFormat::format(int32_t number,
                       UnicodeString& appendTo,
@@ -966,6 +1288,73 @@ DecimalFormat::format(int32_t number,
     return format((int64_t)number, appendTo, posIter, status);
 }
 
+
+#if UCONFIG_FORMAT_FASTPATHS_49
+void DecimalFormat::handleChanged() {
+  DecimalFormatInternal &data = internalData(fReserved);
+
+  if(data.fFastFormatStatus == kFastpathUNKNOWN || data.fFastParseStatus == kFastpathUNKNOWN) {
+    return; // still constructing. Wait.
+  }
+
+  data.fFastParseStatus = data.fFastFormatStatus = kFastpathNO;
+
+#if UCONFIG_HAVE_PARSEALLINPUT
+  if(fParseAllInput == UNUM_NO) {
+    debug("No Parse fastpath: fParseAllInput==UNUM_NO");
+  } else 
+#endif
+  if (fFormatWidth!=0) {
+      debug("No Parse fastpath: fFormatWidth");
+  } else if(fPositivePrefix.length()>0) {
+    debug("No Parse fastpath: positive prefix");
+  } else if(fPositiveSuffix.length()>0) {
+    debug("No Parse fastpath: positive suffix");
+  } else if(fNegativePrefix.length()>1 
+            || ((fNegativePrefix.length()==1) && (fNegativePrefix.charAt(0)!=0x002D))) {
+    debug("No Parse fastpath: negative prefix that isn't '-'");
+  } else if(fNegativeSuffix.length()>0) {
+    debug("No Parse fastpath: negative suffix");
+  } else {
+    data.fFastParseStatus = kFastpathYES;
+    debug("parse fastpath: YES");
+  }
+  
+  if (fGroupingSize!=0 && isGroupingUsed()) {
+    debug("No format fastpath: fGroupingSize!=0 and grouping is used");
+#ifdef FMT_DEBUG
+    printf("groupingsize=%d\n", fGroupingSize);
+#endif
+  } else if(fGroupingSize2!=0 && isGroupingUsed()) {
+    debug("No format fastpath: fGroupingSize2!=0");
+  } else if(fUseExponentialNotation) {
+    debug("No format fastpath: fUseExponentialNotation");
+  } else if(fFormatWidth!=0) {
+    debug("No format fastpath: fFormatWidth!=0");
+  } else if(fMinSignificantDigits!=1) {
+    debug("No format fastpath: fMinSignificantDigits!=1");
+  } else if(fMultiplier!=NULL) {
+    debug("No format fastpath: fMultiplier!=NULL");
+  } else if(fScale!=0) {
+    debug("No format fastpath: fScale!=0");
+  } else if(0x0030 != getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0)) {
+    debug("No format fastpath: 0x0030 != getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0)");
+  } else if(fDecimalSeparatorAlwaysShown) {
+    debug("No format fastpath: fDecimalSeparatorAlwaysShown");
+  } else if(getMinimumFractionDigits()>0) {
+    debug("No format fastpath: fMinFractionDigits>0");
+  } else if(fCurrencySignCount != fgCurrencySignCountZero) {
+    debug("No format fastpath: fCurrencySignCount != fgCurrencySignCountZero");
+  } else if(fRoundingIncrement!=0) {
+    debug("No format fastpath: fRoundingIncrement!=0");
+  } else {
+    data.fFastFormatStatus = kFastpathYES;
+    debug("format:kFastpathYES!");
+  }
+
+
+}
+#endif
 //------------------------------------------------------------------------------
 
 UnicodeString&
@@ -973,8 +1362,19 @@ DecimalFormat::format(int64_t number,
                       UnicodeString& appendTo,
                       FieldPosition& fieldPosition) const
 {
+    UErrorCode status = U_ZERO_ERROR; /* ignored */
     FieldPositionOnlyHandler handler(fieldPosition);
-    return _format(number, appendTo, handler);
+    return _format(number, appendTo, handler, status);
+}
+
+UnicodeString&
+DecimalFormat::format(int64_t number,
+                      UnicodeString& appendTo,
+                      FieldPosition& fieldPosition,
+                      UErrorCode& status) const
+{
+    FieldPositionOnlyHandler handler(fieldPosition);
+    return _format(number, appendTo, handler, status);
 }
 
 UnicodeString&
@@ -984,15 +1384,96 @@ DecimalFormat::format(int64_t number,
                       UErrorCode& status) const
 {
     FieldPositionIteratorHandler handler(posIter, status);
-    return _format(number, appendTo, handler);
+    return _format(number, appendTo, handler, status);
 }
 
 UnicodeString&
 DecimalFormat::_format(int64_t number,
                        UnicodeString& appendTo,
-                       FieldPositionHandler& handler) const
+                       FieldPositionHandler& handler,
+                       UErrorCode &status) const
 {
-    UErrorCode status = U_ZERO_ERROR;
+    // Bottleneck function for formatting int64_t
+    if (U_FAILURE(status)) {
+        return appendTo;
+    }
+
+#if UCONFIG_FORMAT_FASTPATHS_49
+  // const UnicodeString *posPrefix = fPosPrefixPattern;
+  // const UnicodeString *posSuffix = fPosSuffixPattern;
+  // const UnicodeString *negSuffix = fNegSuffixPattern;
+
+  const DecimalFormatInternal &data = internalData(fReserved);
+
+#ifdef FMT_DEBUG
+  data.dump();
+  printf("fastpath? [%d]\n", number);
+#endif
+    
+  if( data.fFastFormatStatus==kFastpathYES) {
+
+#define kZero 0x0030
+    const int32_t MAX_IDX = MAX_DIGITS+2;
+    UChar outputStr[MAX_IDX];
+    int32_t destIdx = MAX_IDX;
+    outputStr[--destIdx] = 0;  // term
+
+    int64_t  n = number;
+    if (number < 1) {
+      // Negative numbers are slightly larger than positive
+      // output the first digit (or the leading zero)
+      outputStr[--destIdx] = (-(n % 10) + kZero);
+      n /= -10;
+    }
+    // get any remaining digits
+    while (n > 0) {
+      outputStr[--destIdx] = (n % 10) + kZero;
+      n /= 10;
+    }
+    
+
+        // Slide the number to the start of the output str
+    U_ASSERT(destIdx >= 0);
+    int32_t length = MAX_IDX - destIdx -1;
+    /*int32_t prefixLen = */ appendAffix(appendTo, number, handler, number<0, TRUE);
+    int32_t maxIntDig = getMaximumIntegerDigits();
+    int32_t destlength = length<=maxIntDig?length:maxIntDig; // dest length pinned to max int digits
+
+    if(length>maxIntDig && fBoolFlags.contains(UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS)) {
+      status = U_ILLEGAL_ARGUMENT_ERROR;
+    }
+
+    int32_t prependZero = getMinimumIntegerDigits() - destlength;
+
+#ifdef FMT_DEBUG
+    printf("prependZero=%d, length=%d, minintdig=%d maxintdig=%d destlength=%d skip=%d\n", prependZero, length, getMinimumIntegerDigits(), maxIntDig, destlength, length-destlength);
+#endif    
+    int32_t intBegin = appendTo.length();
+
+    while((prependZero--)>0) {
+      appendTo.append((UChar)0x0030); // '0'
+    }
+
+    appendTo.append(outputStr+destIdx+
+                    (length-destlength), // skip any leading digits
+                    destlength);
+    handler.addAttribute(kIntegerField, intBegin, appendTo.length());
+
+    /*int32_t suffixLen =*/ appendAffix(appendTo, number, handler, number<0, FALSE);
+
+    //outputStr[length]=0;
+    
+#ifdef FMT_DEBUG
+        printf("Writing [%s] length [%d] max %d for [%d]\n", outputStr+destIdx, length, MAX_IDX, number);
+#endif
+
+#undef kZero
+
+    return appendTo;
+  } // end fastpath
+#endif
+
+  // Else the slow way - via DigitList
     DigitList digits;
     digits.set(number);
     return _format(digits, appendTo, handler, status);
@@ -1004,9 +1485,20 @@ UnicodeString&
 DecimalFormat::format(  double number,
                         UnicodeString& appendTo,
                         FieldPosition& fieldPosition) const
+{
+    UErrorCode status = U_ZERO_ERROR; /* ignored */
+    FieldPositionOnlyHandler handler(fieldPosition);
+    return _format(number, appendTo, handler, status);
+}
+
+UnicodeString&
+DecimalFormat::format(  double number,
+                        UnicodeString& appendTo,
+                        FieldPosition& fieldPosition,
+                        UErrorCode& status) const
 {
     FieldPositionOnlyHandler handler(fieldPosition);
-    return _format(number, appendTo, handler);
+    return _format(number, appendTo, handler, status);
 }
 
 UnicodeString&
@@ -1016,14 +1508,18 @@ DecimalFormat::format(  double number,
                         UErrorCode& status) const
 {
   FieldPositionIteratorHandler handler(posIter, status);
-  return _format(number, appendTo, handler);
+  return _format(number, appendTo, handler, status);
 }
 
 UnicodeString&
 DecimalFormat::_format( double number,
                         UnicodeString& appendTo,
-                        FieldPositionHandler& handler) const
+                        FieldPositionHandler& handler,
+                        UErrorCode &status) const
 {
+    if (U_FAILURE(status)) {
+        return appendTo;
+    }
     // Special case for NaN, sets the begin and end index to be the
     // the string length of localized name of NaN.
     // TODO:  let NaNs go through DigitList.
@@ -1038,7 +1534,6 @@ DecimalFormat::_format( double number,
         return appendTo;
     }
 
-    UErrorCode status = U_ZERO_ERROR;
     DigitList digits;
     digits.set(number);
     _format(digits, appendTo, handler, status);
@@ -1055,6 +1550,47 @@ DecimalFormat::format(const StringPiece &number,
                       FieldPositionIterator *posIter,
                       UErrorCode &status) const
 {
+#if UCONFIG_FORMAT_FASTPATHS_49
+  // don't bother if the int64 path is not optimized
+  int32_t len    = number.length();
+
+  if(len>0&&len<10) { /* 10 or more digits may not be an int64 */
+    const char *data = number.data();
+    int64_t num = 0;
+    UBool neg = FALSE;
+    UBool ok = TRUE;
+    
+    int32_t start  = 0;
+
+    if(data[start]=='+') {
+      start++;
+    } else if(data[start]=='-') {
+      neg=TRUE;
+      start++;
+    }
+
+    int32_t place = 1; /* 1, 10, ... */
+    for(int32_t i=len-1;i>=start;i--) {
+      if(data[i]>='0'&&data[i]<='9') {
+        num+=place*(int64_t)(data[i]-'0');
+      } else {
+        ok=FALSE;
+        break;
+      }
+      place *= 10;
+    }
+
+    if(ok) {
+      if(neg) {
+        num = -num;// add minus bit
+      }
+      // format as int64_t
+      return format(num, toAppendTo, posIter, status);
+    }
+    // else fall through
+  }
+#endif
+
     DigitList   dnum;
     dnum.set(number, status);
     if (U_FAILURE(status)) {
@@ -1088,25 +1624,19 @@ DecimalFormat::format(const DigitList &number,
     return appendTo;
 }
 
+DigitList&
+DecimalFormat::_round(const DigitList &number, DigitList &adjustedNum, UBool& isNegative, UErrorCode &status) const {
+    if (U_FAILURE(status)) {
+        return adjustedNum;
+    }
 
+    // note: number and adjustedNum may refer to the same DigitList, in cases where a copy
+    //       is not needed by the caller.
 
-UnicodeString&
-DecimalFormat::_format(const DigitList &number,
-                        UnicodeString& appendTo,
-                        FieldPositionHandler& handler,
-                        UErrorCode &status) const
-{
-    // Special case for NaN, sets the begin and end index to be the
-    // the string length of localized name of NaN.
-    if (number.isNaN())
-    {
-        int begin = appendTo.length();
-        appendTo += getConstSymbol(DecimalFormatSymbols::kNaNSymbol);
-
-        handler.addAttribute(kIntegerField, begin, appendTo.length());
-
-        addPadding(appendTo, handler, 0, 0);
-        return appendTo;
+    adjustedNum = number;
+    isNegative = false;
+    if (number.isNaN()) {
+        return adjustedNum;
     }
 
     // Do this BEFORE checking to see if value is infinite or negative! Sets the
@@ -1114,53 +1644,73 @@ DecimalFormat::_format(const DigitList &number,
     // localized name of Infinite and the positive/negative localized
     // signs.
 
-    DigitList adjustedNum(number);  // Copy, so we do not alter the original. 
     adjustedNum.setRoundingMode(fRoundingMode);
     if (fMultiplier != NULL) {
         adjustedNum.mult(*fMultiplier, status);
+        if (U_FAILURE(status)) {
+            return adjustedNum;
+        }
     }
 
-    /* 
+    if (fScale != 0) {
+        DigitList ten;
+        ten.set((int32_t)10);
+        if (fScale > 0) {
+            for (int32_t i = fScale ; i > 0 ; i--) {
+                adjustedNum.mult(ten, status);
+                if (U_FAILURE(status)) {
+                    return adjustedNum;
+                }
+            }
+        } else {
+            for (int32_t i = fScale ; i < 0 ; i++) {
+                adjustedNum.div(ten, status);
+                if (U_FAILURE(status)) {
+                    return adjustedNum;
+                }
+            }
+        }
+    }
+
+    /*
      * Note: sign is important for zero as well as non-zero numbers.
      * Proper detection of -0.0 is needed to deal with the
      * issues raised by bugs 4106658, 4106667, and 4147706.  Liu 7/6/98.
      */
-    UBool isNegative = !adjustedNum.isPositive();
+    isNegative = !adjustedNum.isPositive();
 
     // Apply rounding after multiplier
-    
+
     adjustedNum.fContext.status &= ~DEC_Inexact;
     if (fRoundingIncrement != NULL) {
         adjustedNum.div(*fRoundingIncrement, status);
         adjustedNum.toIntegralValue();
         adjustedNum.mult(*fRoundingIncrement, status);
         adjustedNum.trim();
+        if (U_FAILURE(status)) {
+            return adjustedNum;
+        }
     }
     if (fRoundingMode == kRoundUnnecessary && (adjustedNum.fContext.status & DEC_Inexact)) {
         status = U_FORMAT_INEXACT_ERROR;
-        return appendTo;
+        return adjustedNum;
     }
-        
 
-    // Special case for INFINITE,
     if (adjustedNum.isInfinite()) {
-        int32_t prefixLen = appendAffix(appendTo, adjustedNum.getDouble(), handler, isNegative, TRUE);
-
-        int begin = appendTo.length();
-        appendTo += getConstSymbol(DecimalFormatSymbols::kInfinitySymbol);
-
-        handler.addAttribute(kIntegerField, begin, appendTo.length());
-
-        int32_t suffixLen = appendAffix(appendTo, adjustedNum.getDouble(), handler, isNegative, FALSE);
-
-        addPadding(appendTo, handler, prefixLen, suffixLen);
-        return appendTo;
+        return adjustedNum;
     }
 
     if (fUseExponentialNotation || areSignificantDigitsUsed()) {
         int32_t sigDigits = precision();
         if (sigDigits > 0) {
             adjustedNum.round(sigDigits);
+            // Travis Keep (21/2/2014): Calling round on a digitList does not necessarily
+            // preserve the sign of that digit list. Preserving the sign is especially
+            // important when formatting -0.0 for instance. Not preserving the sign seems
+            // like a bug because I cannot think of any case where the sign would actually
+            // have to change when rounding. For now, we preserve the sign by setting the
+            // positive attribute directly.
+            adjustedNum.setPositive(!isNegative);
         }
     } else {
         // Fixed point format.  Round to a set number of fraction digits.
@@ -1169,20 +1719,56 @@ DecimalFormat::_format(const DigitList &number,
     }
     if (fRoundingMode == kRoundUnnecessary && (adjustedNum.fContext.status & DEC_Inexact)) {
         status = U_FORMAT_INEXACT_ERROR;
-        return appendTo;
+        return adjustedNum;
     }
-    return subformat(appendTo, handler, adjustedNum, FALSE);
+    return adjustedNum;
 }
 
-
 UnicodeString&
-DecimalFormat::format(  const Formattable& obj,
+DecimalFormat::_format(const DigitList &number,
                         UnicodeString& appendTo,
-                        FieldPosition& fieldPosition,
-                        UErrorCodestatus) const
+                        FieldPositionHandler& handler,
+                        UErrorCode &status) const
 {
-    return NumberFormat::format(obj, appendTo, fieldPosition, status);
+    if (U_FAILURE(status)) {
+        return appendTo;
+    }
+
+    // Special case for NaN, sets the begin and end index to be the
+    // the string length of localized name of NaN.
+    if (number.isNaN())
+    {
+        int begin = appendTo.length();
+        appendTo += getConstSymbol(DecimalFormatSymbols::kNaNSymbol);
+
+        handler.addAttribute(kIntegerField, begin, appendTo.length());
+
+        addPadding(appendTo, handler, 0, 0);
+        return appendTo;
+    }
+
+    DigitList adjustedNum;
+    UBool isNegative;
+    _round(number, adjustedNum, isNegative, status);
+    if (U_FAILURE(status)) {
+        return appendTo;
+    }
+
+    // Special case for INFINITE,
+    if (adjustedNum.isInfinite()) {
+        int32_t prefixLen = appendAffix(appendTo, adjustedNum.getDouble(), handler, isNegative, TRUE);
+
+        int begin = appendTo.length();
+        appendTo += getConstSymbol(DecimalFormatSymbols::kInfinitySymbol);
+
+        handler.addAttribute(kIntegerField, begin, appendTo.length());
+
+        int32_t suffixLen = appendAffix(appendTo, adjustedNum.getDouble(), handler, isNegative, FALSE);
+
+        addPadding(appendTo, handler, prefixLen, suffixLen);
+        return appendTo;
+    }
+    return subformat(appendTo, handler, adjustedNum, FALSE, status);
 }
 
 /**
@@ -1217,7 +1803,8 @@ UnicodeString&
 DecimalFormat::subformat(UnicodeString& appendTo,
                          FieldPositionHandler& handler,
                          DigitList&     digits,
-                         UBool          isInteger) const
+                         UBool          isInteger,
+                         UErrorCode& status) const
 {
     // char zero = '0'; 
     // DigitList returns digits as '0' thru '9', so we will need to 
@@ -1236,16 +1823,16 @@ DecimalFormat::subformat(UnicodeString& appendTo,
     localizedDigits[9] = getConstSymbol(DecimalFormatSymbols::kNineDigitSymbol).char32At(0);
 
     const UnicodeString *grouping ;
-    if(fCurrencySignCount > fgCurrencySignCountZero) {
-        grouping = &getConstSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol);
-    }else{
+    if(fCurrencySignCount == fgCurrencySignCountZero) {
         grouping = &getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol);
+    }else{
+        grouping = &getConstSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol);
     }
     const UnicodeString *decimal;
-    if(fCurrencySignCount > fgCurrencySignCountZero) {
-        decimal = &getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol);
-    } else {
+    if(fCurrencySignCount == fgCurrencySignCountZero) {
         decimal = &getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
+    } else {
+        decimal = &getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol);
     }
     UBool useSigDig = areSignificantDigitsUsed();
     int32_t maxIntDig = getMaximumIntegerDigits();
@@ -1426,6 +2013,9 @@ DecimalFormat::subformat(UnicodeString& appendTo,
         if (count > maxIntDig && maxIntDig >= 0) {
             count = maxIntDig;
             digitIndex = digits.getDecimalAt() - count;
+            if(fBoolFlags.contains(UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS)) {
+                status = U_ILLEGAL_ARGUMENT_ERROR;
+            }
         }
 
         int32_t sizeBeforeIntegerPart = appendTo.length();
@@ -1456,6 +2046,14 @@ DecimalFormat::subformat(UnicodeString& appendTo,
             }
         }
 
+        // This handles the special case of formatting 0. For zero only, we count the
+        // zero to the left of the decimal point as one signficant digit. Ordinarily we
+        // do not count any leading 0's as significant. If the number we are formatting
+        // is not zero, then either sigCount or digits.getCount() will be non-zero.
+        if (sigCount == 0 && digits.getCount() == 0) {
+          sigCount = 1;
+        }
+
         // TODO(dlf): this looks like it was a bug, we marked the int field as ending
         // before the zero was generated.
         // Record field information for caller.
@@ -1580,14 +2178,6 @@ void DecimalFormat::addPadding(UnicodeString& appendTo,
 
 //------------------------------------------------------------------------------
 
-void
-DecimalFormat::parse(const UnicodeString& text,
-                     Formattable& result,
-                     UErrorCode& status) const
-{
-    NumberFormat::parse(text, result, status);
-}
-
 void
 DecimalFormat::parse(const UnicodeString& text,
                      Formattable& result,
@@ -1599,7 +2189,7 @@ CurrencyAmount* DecimalFormat::parseCurrency(const UnicodeString& text,
                                              ParsePosition& pos) const {
     Formattable parseResult;
     int32_t start = pos.getIndex();
-    UChar curbuf[4];
+    UChar curbuf[4] = {};
     parse(text, parseResult, pos, curbuf);
     if (pos.getIndex() != start) {
         UErrorCode ec = U_ZERO_ERROR;
@@ -1637,6 +2227,11 @@ void DecimalFormat::parse(const UnicodeString& text,
     // clear any old contents in the result.  In particular, clears any DigitList
     //   that it may be holding.
     result.setLong(0);
+    if (currency != NULL) {
+        for (int32_t ci=0; ci<4; ci++) {
+            currency[ci] = 0;
+        }
+    }
 
     // Handle NaN as a special case:
 
@@ -1672,16 +2267,16 @@ void DecimalFormat::parse(const UnicodeString& text,
 
     // status is used to record whether a number is infinite.
     UBool status[fgStatusLength];
-    DigitList *digits = new DigitList;
+
+    DigitList *digits = result.getInternalDigitList(); // get one from the stack buffer
     if (digits == NULL) {
         return;    // no way to report error from here.
     }
 
-    if (fCurrencySignCount > fgCurrencySignCountZero) {
+    if (fCurrencySignCount != fgCurrencySignCountZero) {
         if (!parseForCurrency(text, parsePosition, *digits,
                               status, currency)) {
-            delete digits;
-            return;
+          return;
         }
     } else {
         if (!subparse(text,
@@ -1689,8 +2284,8 @@ void DecimalFormat::parse(const UnicodeString& text,
                       fPosPrefixPattern, fPosSuffixPattern,
                       FALSE, UCURR_SYMBOL_NAME,
                       parsePosition, *digits, status, currency)) {
+            debug("!subparse(...) - rewind");
             parsePosition.setIndex(startIdx);
-            delete digits;
             return;
         }
     }
@@ -1699,7 +2294,7 @@ void DecimalFormat::parse(const UnicodeString& text,
     if (status[fgStatusInfinite]) {
         double inf = uprv_getInfinity();
         result.setDouble(digits->isPositive() ? inf : -inf);
-        delete digits;    // TODO:  set the dl to infinity, and let it fall into the code below.
+        // TODO:  set the dl to infinity, and let it fall into the code below.
     }
 
     else {
@@ -1709,6 +2304,22 @@ void DecimalFormat::parse(const UnicodeString& text,
             digits->div(*fMultiplier, ec);
         }
 
+        if (fScale != 0) {
+            DigitList ten;
+            ten.set((int32_t)10);
+            if (fScale > 0) {
+                for (int32_t i = fScale; i > 0; i--) {
+                    UErrorCode ec = U_ZERO_ERROR;
+                    digits->div(ten,ec);
+                }
+            } else {
+                for (int32_t i = fScale; i < 0; i++) {
+                    UErrorCode ec = U_ZERO_ERROR;
+                    digits->mult(ten,ec);
+                }
+            }
+        }
+
         // Negative zero special case:
         //    if parsing integerOnly, change to +0, which goes into an int32 in a Formattable.
         //    if not parsing integerOnly, leave as -0, which a double can represent.
@@ -1772,6 +2383,12 @@ DecimalFormat::parseForCurrency(const UnicodeString& text,
         UBool tmpStatus[fgStatusLength];
         ParsePosition tmpPos(origPos);
         DigitList tmpDigitList;
+
+#ifdef FMT_DEBUG
+        debug("trying affix for currency..");
+        affixPtn->dump();
+#endif
+
         UBool result = subparse(text,
                                 &affixPtn->negPrefixPatternForCurrency,
                                 &affixPtn->negSuffixPatternForCurrency,
@@ -1801,16 +2418,21 @@ DecimalFormat::parseForCurrency(const UnicodeString& text,
     // and the parse stops at "\u00A4".
     // We will just use simple affix comparison (look for exact match)
     // to pass it.
+    //
+    // TODO: We should parse against simple affix first when
+    // output currency is not requested. After the complex currency
+    // parsing implementation was introduced, the default currency
+    // instance parsing slowed down because of the new code flow.
+    // I filed #10312 - Yoshito
     UBool tmpStatus_2[fgStatusLength];
     ParsePosition tmpPos_2(origPos);
     DigitList tmpDigitList_2;
-    // set currencySignCount to 0 so that compareAffix function will
-    // fall to compareSimpleAffix path, not compareComplexAffix path.
-    // ?? TODO: is it right? need "false"?
+
+    // Disable complex currency parsing and try it again.
     UBool result = subparse(text,
                             &fNegativePrefix, &fNegativeSuffix,
                             &fPositivePrefix, &fPositiveSuffix,
-                            FALSE, UCURR_SYMBOL_NAME,
+                            FALSE /* disable complex currency parsing */, UCURR_SYMBOL_NAME,
                             tmpPos_2, tmpDigitList_2, tmpStatus_2,
                             currency);
     if (result) {
@@ -1846,7 +2468,7 @@ DecimalFormat::parseForCurrency(const UnicodeString& text,
  * @param negSuffix negative suffix.
  * @param posPrefix positive prefix.
  * @param posSuffix positive suffix.
- * @param currencyParsing whether it is currency parsing or not.
+ * @param complexCurrencyParsing whether it is complex currency parsing or not.
  * @param type the currency type to parse against, LONG_NAME only or not.
  * @param parsePosition The position at which to being parsing.  Upon
  * return, the first unparsed character.
@@ -1863,7 +2485,7 @@ UBool DecimalFormat::subparse(const UnicodeString& text,
                               const UnicodeString* negSuffix,
                               const UnicodeString* posPrefix,
                               const UnicodeString* posSuffix,
-                              UBool currencyParsing,
+                              UBool complexCurrencyParsing,
                               int8_t type,
                               ParsePosition& parsePosition,
                               DigitList& digits, UBool* status,
@@ -1878,16 +2500,153 @@ UBool DecimalFormat::subparse(const UnicodeString& text,
 
     int32_t position = parsePosition.getIndex();
     int32_t oldStart = position;
+    int32_t textLength = text.length(); // One less pointer to follow
     UBool strictParse = !isLenient();
+    UChar32 zero = getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0);
+    const UnicodeString *groupingString = &getConstSymbol(fCurrencySignCount == fgCurrencySignCountZero ?
+        DecimalFormatSymbols::kGroupingSeparatorSymbol : DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol);
+    UChar32 groupingChar = groupingString->char32At(0);
+    int32_t groupingStringLength = groupingString->length();
+    int32_t groupingCharLength   = U16_LENGTH(groupingChar);
+    UBool   groupingUsed = isGroupingUsed();
+#ifdef FMT_DEBUG
+    UChar dbgbuf[300];
+    UnicodeString s(dbgbuf,0,300);;
+    s.append((UnicodeString)"PARSE \"").append(text.tempSubString(position)).append((UnicodeString)"\" " );
+#define DBGAPPD(x) if(x) { s.append(UnicodeString(#x "="));  if(x->isEmpty()) { s.append(UnicodeString("<empty>")); } else { s.append(*x); } s.append(UnicodeString(" ")); } else { s.append(UnicodeString(#x "=NULL ")); }
+    DBGAPPD(negPrefix);
+    DBGAPPD(negSuffix);
+    DBGAPPD(posPrefix);
+    DBGAPPD(posSuffix);
+    debugout(s);
+    printf("currencyParsing=%d, fFormatWidth=%d, isParseIntegerOnly=%c text.length=%d negPrefLen=%d\n", currencyParsing, fFormatWidth, (isParseIntegerOnly())?'Y':'N', text.length(),  negPrefix!=NULL?negPrefix->length():-1);
+#endif
+
+    UBool fastParseOk = false; /* TRUE iff fast parse is OK */
+    // UBool fastParseHadDecimal = FALSE; /* true if fast parse saw a decimal point. */
+    const DecimalFormatInternal &data = internalData(fReserved);
+    if((data.fFastParseStatus==kFastpathYES) &&
+       fCurrencySignCount == fgCurrencySignCountZero &&
+       //       (negPrefix!=NULL&&negPrefix->isEmpty()) ||
+       text.length()>0 &&
+       text.length()<32 &&
+       (posPrefix==NULL||posPrefix->isEmpty()) &&
+       (posSuffix==NULL||posSuffix->isEmpty()) &&
+       //            (negPrefix==NULL||negPrefix->isEmpty()) &&
+       //            (negSuffix==NULL||(negSuffix->isEmpty()) ) &&
+       TRUE) {  // optimized path
+      int j=position;
+      int l=text.length();
+      int digitCount=0;
+      UChar32 ch = text.char32At(j);
+      const UnicodeString *decimalString = &getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
+      UChar32 decimalChar = 0;
+      UBool intOnly = FALSE;
+      UChar32 lookForGroup = (groupingUsed&&intOnly&&strictParse)?groupingChar:0;
+
+      int32_t decimalCount = decimalString->countChar32(0,3);
+      if(isParseIntegerOnly()) {
+        decimalChar = 0; // not allowed
+        intOnly = TRUE; // Don't look for decimals.
+      } else if(decimalCount==1) {
+        decimalChar = decimalString->char32At(0); // Look for this decimal
+      } else if(decimalCount==0) {
+        decimalChar=0; // NO decimal set
+      } else {
+        j=l+1;//Set counter to end of line, so that we break. Unknown decimal situation.
+      }
+
+#ifdef FMT_DEBUG
+      printf("Preparing to do fastpath parse: decimalChar=U+%04X, groupingChar=U+%04X, first ch=U+%04X intOnly=%c strictParse=%c\n",
+        decimalChar, groupingChar, ch,
+        (intOnly)?'y':'n',
+        (strictParse)?'y':'n');
+#endif
+      if(ch==0x002D) { // '-'
+        j=l+1;//=break - negative number.
+        
+        /*
+          parsedNum.append('-',err); 
+          j+=U16_LENGTH(ch);
+          if(j<l) ch = text.char32At(j);
+        */
+      } else {
+        parsedNum.append('+',err);
+      }
+      while(j<l) {
+        int32_t digit = ch - zero;
+        if(digit >=0 && digit <= 9) {
+          parsedNum.append((char)(digit + '0'), err);
+          if((digitCount>0) || digit!=0 || j==(l-1)) {
+            digitCount++;
+          }
+        } else if(ch == 0) { // break out
+          digitCount=-1;
+          break;
+        } else if(ch == decimalChar) {
+          parsedNum.append((char)('.'), err);
+          decimalChar=0; // no more decimals.
+          // fastParseHadDecimal=TRUE;
+        } else if(ch == lookForGroup) {
+          // ignore grouping char. No decimals, so it has to be an ignorable grouping sep
+        } else if(intOnly && (lookForGroup!=0) && !u_isdigit(ch)) {
+          // parsing integer only and can fall through
+        } else {
+          digitCount=-1; // fail - fall through to slow parse
+          break;
+        }
+        j+=U16_LENGTH(ch);
+        ch = text.char32At(j); // for next  
+      }
+      if(
+         ((j==l)||intOnly) // end OR only parsing integer
+         && (digitCount>0)) { // and have at least one digit
+#ifdef FMT_DEBUG
+        printf("PP -> %d, good = [%s]  digitcount=%d, fGroupingSize=%d fGroupingSize2=%d!\n", j, parsedNum.data(), digitCount, fGroupingSize, fGroupingSize2);
+#endif
+        fastParseOk=true; // Fast parse OK!
 
+#ifdef SKIP_OPT
+        debug("SKIP_OPT");
+        /* for testing, try it the slow way. also */
+        fastParseOk=false;
+        parsedNum.clear();
+#else
+        parsePosition.setIndex(position=j);
+        status[fgStatusInfinite]=false;
+#endif
+      } else {
+        // was not OK. reset, retry
+#ifdef FMT_DEBUG
+        printf("Fall through: j=%d, l=%d, digitCount=%d\n", j, l, digitCount);
+#endif
+        parsedNum.clear();
+      }
+    } else {
+#ifdef FMT_DEBUG
+      printf("Could not fastpath parse. ");
+      printf("fFormatWidth=%d ", fFormatWidth);
+      printf("text.length()=%d ", text.length());
+      printf("posPrefix=%p posSuffix=%p ", posPrefix, posSuffix);
+
+      printf("\n");
+#endif
+    }
+
+  if(!fastParseOk 
+#if UCONFIG_HAVE_PARSEALLINPUT
+     && fParseAllInput!=UNUM_YES
+#endif
+     ) 
+  {
     // Match padding before prefix
     if (fFormatWidth > 0 && fPadPosition == kPadBeforePrefix) {
         position = skipPadding(text, position);
     }
 
     // Match positive and negative prefixes; prefer longest match.
-    int32_t posMatch = compareAffix(text, position, FALSE, TRUE, posPrefix, currencyParsing, type, currency);
-    int32_t negMatch = compareAffix(text, position, TRUE,  TRUE, negPrefix, currencyParsing, type, currency);
+    int32_t posMatch = compareAffix(text, position, FALSE, TRUE, posPrefix, complexCurrencyParsing, type, currency);
+    int32_t negMatch = compareAffix(text, position, TRUE,  TRUE, negPrefix, complexCurrencyParsing, type, currency);
     if (posMatch >= 0 && negMatch >= 0) {
         if (posMatch > negMatch) {
             negMatch = -1;
@@ -1935,7 +2694,6 @@ UBool DecimalFormat::subparse(const UnicodeString& text,
         // put only significant digits into the DigitList, and adjust the
         // exponent as needed.
 
-        UChar32 zero = getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0);
 
         UBool strictFail = FALSE; // did we exit with a strict parse failure?
         int32_t lastGroup = -1; // where did we last see a grouping separator?
@@ -1943,15 +2701,15 @@ UBool DecimalFormat::subparse(const UnicodeString& text,
         int32_t gs2 = fGroupingSize2 == 0 ? fGroupingSize : fGroupingSize2;
 
         const UnicodeString *decimalString;
-        if (fCurrencySignCount > fgCurrencySignCountZero) {
+        if (fCurrencySignCount != fgCurrencySignCountZero) {
             decimalString = &getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol);
         } else {
             decimalString = &getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
         }
         UChar32 decimalChar = decimalString->char32At(0);
+        int32_t decimalStringLength = decimalString->length();
+        int32_t decimalCharLength   = U16_LENGTH(decimalChar);
 
-        const UnicodeString *groupingString = &getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol);
-        UChar32 groupingChar = groupingString->char32At(0);
         UBool sawDecimal = FALSE;
         UChar32 sawDecimalChar = 0xFFFF;
         UBool sawGrouping = FALSE;
@@ -1959,11 +2717,6 @@ UBool DecimalFormat::subparse(const UnicodeString& text,
         UBool sawDigit = FALSE;
         int32_t backup = -1;
         int32_t digit;
-        int32_t textLength = text.length(); // One less pointer to follow
-        int32_t decimalStringLength = decimalString->length();
-        int32_t decimalCharLength   = U16_LENGTH(decimalChar);
-        int32_t groupingStringLength = groupingString->length();
-        int32_t groupingCharLength   = U16_LENGTH(groupingChar);
 
         // equivalent grouping and decimal support
         const UnicodeSet *decimalSet = NULL;
@@ -1975,9 +2728,9 @@ UBool DecimalFormat::subparse(const UnicodeString& text,
 
         if (groupingCharLength == groupingStringLength) {
             if (strictParse) {
-                groupingSet = DecimalFormatStaticSets::gStaticSets->fStrictDefaultGroupingSeparators;
+                groupingSet = fStaticSets->fStrictDefaultGroupingSeparators;
             } else {
-                groupingSet = DecimalFormatStaticSets::gStaticSets->fDefaultGroupingSeparators;
+                groupingSet = fStaticSets->fDefaultGroupingSeparators;
             }
         }
 
@@ -2065,7 +2818,7 @@ UBool DecimalFormat::subparse(const UnicodeString& text,
             else if (groupingStringLength > 0 && 
                 matchGrouping(groupingChar, sawGrouping, sawGroupingChar, groupingSet, 
                             decimalChar, decimalSet,
-                            ch) && isGroupingUsed())
+                            ch) && groupingUsed)
             {
                 if (sawDecimal) {
                     break;
@@ -2120,61 +2873,67 @@ UBool DecimalFormat::subparse(const UnicodeString& text,
                 // decimalSet is considered to consist of (ch,ch)
             }
             else {
-                const UnicodeString *tmp;
-                tmp = &getConstSymbol(DecimalFormatSymbols::kExponentialSymbol);
-                if (!text.caseCompare(position, tmp->length(), *tmp, U_FOLD_CASE_DEFAULT))    // error code is set below if !sawDigit 
-                {
-                    // Parse sign, if present
-                    int32_t pos = position + tmp->length();
-                    char exponentSign = '+';
 
-                    if (pos < textLength)
+                if(!fBoolFlags.contains(UNUM_PARSE_NO_EXPONENT) || // don't parse if this is set unless..
+                   isScientificNotation()) { // .. it's an exponent format - ignore setting and parse anyways
+                    const UnicodeString *tmp;
+                    tmp = &getConstSymbol(DecimalFormatSymbols::kExponentialSymbol);
+                    // TODO: CASE
+                    if (!text.caseCompare(position, tmp->length(), *tmp, U_FOLD_CASE_DEFAULT))    // error code is set below if !sawDigit 
                     {
-                        tmp = &getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol);
-                        if (!text.compare(pos, tmp->length(), *tmp))
+                        // Parse sign, if present
+                        int32_t pos = position + tmp->length();
+                        char exponentSign = '+';
+
+                        if (pos < textLength)
                         {
-                            pos += tmp->length();
-                        }
-                        else {
-                            tmp = &getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
+                            tmp = &getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol);
                             if (!text.compare(pos, tmp->length(), *tmp))
                             {
-                                exponentSign = '-';
                                 pos += tmp->length();
                             }
+                            else {
+                                tmp = &getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
+                                if (!text.compare(pos, tmp->length(), *tmp))
+                                {
+                                    exponentSign = '-';
+                                    pos += tmp->length();
+                                }
+                            }
                         }
-                    }
 
-                    UBool sawExponentDigit = FALSE;
-                    while (pos < textLength) {
-                        ch = text[(int32_t)pos];
-                        digit = ch - zero;
+                        UBool sawExponentDigit = FALSE;
+                        while (pos < textLength) {
+                            ch = text[(int32_t)pos];
+                            digit = ch - zero;
 
-                        if (digit < 0 || digit > 9) {
-                            digit = u_charDigitValue(ch);
-                        }
-                        if (0 <= digit && digit <= 9) {
-                            if (!sawExponentDigit) {
-                                parsedNum.append('E', err);
-                                parsedNum.append(exponentSign, err);
-                                sawExponentDigit = TRUE;
+                            if (digit < 0 || digit > 9) {
+                                digit = u_charDigitValue(ch);
+                            }
+                            if (0 <= digit && digit <= 9) {
+                                if (!sawExponentDigit) {
+                                    parsedNum.append('E', err);
+                                    parsedNum.append(exponentSign, err);
+                                    sawExponentDigit = TRUE;
+                                }
+                                ++pos;
+                                parsedNum.append((char)(digit + '0'), err);
+                            } else {
+                                break;
                             }
-                            ++pos;
-                            parsedNum.append((char)(digit + '0'), err);
-                        } else {
-                            break;
                         }
-                    }
 
-                    if (sawExponentDigit) {
-                        position = pos; // Advance past the exponent
-                    }
+                        if (sawExponentDigit) {
+                            position = pos; // Advance past the exponent
+                        }
 
-                    break; // Whether we fail or succeed, we exit this loop
-                }
-                else {
+                        break; // Whether we fail or succeed, we exit this loop
+                    } else {
+                        break;
+                    }
+                } else { // not parsing exponent
                     break;
-                }
+              }
             }
         }
 
@@ -2194,6 +2953,7 @@ UBool DecimalFormat::subparse(const UnicodeString& text,
 
             parsePosition.setIndex(oldStart);
             parsePosition.setErrorIndex(position);
+            debug("strictFail!");
             return FALSE;
         }
 
@@ -2204,6 +2964,10 @@ UBool DecimalFormat::subparse(const UnicodeString& text,
         // parse "$" with pattern "$#0.00". (return index 0 and error index
         // 1).
         if (!sawDigit && digitCount == 0) {
+#ifdef FMT_DEBUG
+            debug("none of text rec");
+            printf("position=%d\n",position);
+#endif
             parsePosition.setIndex(oldStart);
             parsePosition.setErrorIndex(oldStart);
             return FALSE;
@@ -2219,10 +2983,10 @@ UBool DecimalFormat::subparse(const UnicodeString& text,
 
     // Match positive and negative suffixes; prefer longest match.
     if (posMatch >= 0 || (!strictParse && negMatch < 0)) {
-        posSuffixMatch = compareAffix(text, position, FALSE, FALSE, posSuffix, currencyParsing, type, currency);
+        posSuffixMatch = compareAffix(text, position, FALSE, FALSE, posSuffix, complexCurrencyParsing, type, currency);
     }
     if (negMatch >= 0) {
-        negSuffixMatch = compareAffix(text, position, TRUE, FALSE, negSuffix, currencyParsing, type, currency);
+        negSuffixMatch = compareAffix(text, position, TRUE, FALSE, negSuffix, complexCurrencyParsing, type, currency);
     }
     if (posSuffixMatch >= 0 && negSuffixMatch >= 0) {
         if (posSuffixMatch > negSuffixMatch) {
@@ -2235,6 +2999,7 @@ UBool DecimalFormat::subparse(const UnicodeString& text,
     // Fail if neither or both
     if (strictParse && ((posSuffixMatch >= 0) == (negSuffixMatch >= 0))) {
         parsePosition.setErrorIndex(position);
+        debug("neither or both");
         return FALSE;
     }
 
@@ -2248,15 +3013,40 @@ UBool DecimalFormat::subparse(const UnicodeString& text,
     parsePosition.setIndex(position);
 
     parsedNum.data()[0] = (posSuffixMatch >= 0 || (!strictParse && negMatch < 0 && negSuffixMatch < 0)) ? '+' : '-';
-
-    if(parsePosition.getIndex() == oldStart)
+#ifdef FMT_DEBUG
+printf("PP -> %d, SLOW = [%s]!    pp=%d, os=%d, err=%s\n", position, parsedNum.data(), parsePosition.getIndex(),oldStart,u_errorName(err));
+#endif
+  } /* end SLOW parse */
+  if(parsePosition.getIndex() == oldStart)
     {
+#ifdef FMT_DEBUG
+      printf(" PP didnt move, err\n");
+#endif
+        parsePosition.setErrorIndex(position);
+        return FALSE;
+    }
+#if UCONFIG_HAVE_PARSEALLINPUT
+  else if (fParseAllInput==UNUM_YES&&parsePosition.getIndex()!=textLength)
+    {
+#ifdef FMT_DEBUG
+      printf(" PP didnt consume all (UNUM_YES), err\n");
+#endif
         parsePosition.setErrorIndex(position);
         return FALSE;
     }
-    digits.set(parsedNum.toStringPiece(), err);
+#endif
+    // uint32_t bits = (fastParseOk?kFastpathOk:0) |
+    //   (fastParseHadDecimal?0:kNoDecimal);
+    //printf("FPOK=%d, FPHD=%d, bits=%08X\n", fastParseOk, fastParseHadDecimal, bits);
+    digits.set(parsedNum.toStringPiece(),
+               err,
+               0//bits
+               );
 
     if (U_FAILURE(err)) {
+#ifdef FMT_DEBUG
+      printf(" err setting %s\n", u_errorName(err));
+#endif
         parsePosition.setErrorIndex(position);
         return FALSE;
     }
@@ -2287,7 +3077,7 @@ int32_t DecimalFormat::skipPadding(const UnicodeString& text, int32_t position)
  * @param isNegative
  * @param isPrefix
  * @param affixPat affix pattern used for currency affix comparison.
- * @param currencyParsing whether it is currency parsing or not
+ * @param complexCurrencyParsing whether it is currency parsing or not
  * @param type the currency type to parse against, LONG_NAME only or not.
  * @param currency return value for parsed currency, for generic
  * currency parsing mode, or null for normal parsing. In generic
@@ -2300,13 +3090,13 @@ int32_t DecimalFormat::compareAffix(const UnicodeString& text,
                                     UBool isNegative,
                                     UBool isPrefix,
                                     const UnicodeString* affixPat,
-                                    UBool currencyParsing,
+                                    UBool complexCurrencyParsing,
                                     int8_t type,
                                     UChar* currency) const
 {
     const UnicodeString *patternToCompare;
     if (fCurrencyChoice != NULL || currency != NULL ||
-        (fCurrencySignCount > fgCurrencySignCountZero && currencyParsing)) {
+        (fCurrencySignCount != fgCurrencySignCountZero && complexCurrencyParsing)) {
 
         if (affixPat != NULL) {
             return compareComplexAffix(*affixPat, text, pos, type, currency);
@@ -2332,6 +3122,40 @@ int32_t DecimalFormat::compareAffix(const UnicodeString& text,
     return compareSimpleAffix(*patternToCompare, text, pos, isLenient());
 }
 
+UBool DecimalFormat::equalWithSignCompatibility(UChar32 lhs, UChar32 rhs) const {
+    if (lhs == rhs) {
+        return TRUE;
+    }
+    U_ASSERT(fStaticSets != NULL); // should already be loaded
+    const UnicodeSet *minusSigns = fStaticSets->fMinusSigns;
+    const UnicodeSet *plusSigns = fStaticSets->fPlusSigns;
+    return (minusSigns->contains(lhs) && minusSigns->contains(rhs)) ||
+        (plusSigns->contains(lhs) && plusSigns->contains(rhs));
+}
+
+// check for LRM 0x200E, RLM 0x200F, ALM 0x061C
+#define IS_BIDI_MARK(c) (c==0x200E || c==0x200F || c==0x061C)
+
+#define TRIM_BUFLEN 32
+UnicodeString& DecimalFormat::trimMarksFromAffix(const UnicodeString& affix, UnicodeString& trimmedAffix) {
+    UChar trimBuf[TRIM_BUFLEN];
+    int32_t affixLen = affix.length();
+    int32_t affixPos, trimLen = 0;
+
+    for (affixPos = 0; affixPos < affixLen; affixPos++) {
+        UChar c = affix.charAt(affixPos);
+        if (!IS_BIDI_MARK(c)) {
+            if (trimLen < TRIM_BUFLEN) {
+                trimBuf[trimLen++] = c;
+            } else {
+                trimLen = 0;
+                break;
+            }
+        }
+    }
+    return (trimLen > 0)? trimmedAffix.setTo(trimBuf, trimLen): trimmedAffix.setTo(affix);
+}
+
 /**
  * Return the length matched by the given affix, or -1 if none.
  * Runs of white space in the affix, match runs of white space in
@@ -2345,31 +3169,41 @@ int32_t DecimalFormat::compareAffix(const UnicodeString& text,
 int32_t DecimalFormat::compareSimpleAffix(const UnicodeString& affix,
                                           const UnicodeString& input,
                                           int32_t pos,
-                                          UBool lenient) {
-    UErrorCode status = U_ZERO_ERROR;
+                                          UBool lenient) const {
     int32_t start = pos;
-    UChar32 affixChar = affix.char32At(0);
-    int32_t affixLength = affix.length();
+    UnicodeString trimmedAffix;
+    // For more efficiency we should keep lazily-created trimmed affixes around in
+    // instance variables instead of trimming each time they are used (the next step)
+    trimMarksFromAffix(affix, trimmedAffix);
+    UChar32 affixChar = trimmedAffix.char32At(0);
+    int32_t affixLength = trimmedAffix.length();
     int32_t inputLength = input.length();
     int32_t affixCharLength = U16_LENGTH(affixChar);
     UnicodeSet *affixSet;
+    UErrorCode status = U_ZERO_ERROR;
 
-    DecimalFormatStaticSets::initSets(&status);
+    U_ASSERT(fStaticSets != NULL); // should already be loaded
 
+    if (U_FAILURE(status)) {
+        return -1;
+    }
     if (!lenient) {
-        affixSet = DecimalFormatStaticSets::gStaticSets->fStrictDashEquivalents;
-        
-        // If the affix is exactly one character long and that character
+        affixSet = fStaticSets->fStrictDashEquivalents;
+
+        // If the trimmedAffix is exactly one character long and that character
         // is in the dash set and the very next input character is also
         // in the dash set, return a match.
         if (affixCharLength == affixLength && affixSet->contains(affixChar))  {
-            if (affixSet->contains(input.char32At(pos))) {
-                return 1;
+            UChar32 ic = input.char32At(pos);
+            if (affixSet->contains(ic)) {
+                pos += U16_LENGTH(ic);
+                pos = skipBidiMarks(input, pos); // skip any trailing bidi marks
+                return pos - start;
             }
         }
 
         for (int32_t i = 0; i < affixLength; ) {
-            UChar32 c = affix.char32At(i);
+            UChar32 c = trimmedAffix.char32At(i);
             int32_t len = U16_LENGTH(c);
             if (PatternProps::isWhiteSpace(c)) {
                 // We may have a pattern like: \u200F \u0020
@@ -2379,23 +3213,29 @@ int32_t DecimalFormat::compareSimpleAffix(const UnicodeString& affix,
                 // match of the run of Pattern_White_Space in the pattern,
                 // then match any extra characters.
                 UBool literalMatch = FALSE;
-                while (pos < inputLength &&
-                       input.char32At(pos) == c) {
-                    literalMatch = TRUE;
-                    i += len;
-                    pos += len;
-                    if (i == affixLength) {
-                        break;
-                    }
-                    c = affix.char32At(i);
-                    len = U16_LENGTH(c);
-                    if (!PatternProps::isWhiteSpace(c)) {
+                while (pos < inputLength) {
+                    UChar32 ic = input.char32At(pos);
+                    if (ic == c) {
+                        literalMatch = TRUE;
+                        i += len;
+                        pos += len;
+                        if (i == affixLength) {
+                            break;
+                        }
+                        c = trimmedAffix.char32At(i);
+                        len = U16_LENGTH(c);
+                        if (!PatternProps::isWhiteSpace(c)) {
+                            break;
+                        }
+                    } else if (IS_BIDI_MARK(ic)) {
+                        pos ++; // just skip over this input text
+                    } else {
                         break;
                     }
                 }
 
                 // Advance over run in pattern
-                i = skipPatternWhiteSpace(affix, i);
+                i = skipPatternWhiteSpace(trimmedAffix, i);
 
                 // Advance over run in input text
                 // Must see at least one white space char in input,
@@ -2408,51 +3248,64 @@ int32_t DecimalFormat::compareSimpleAffix(const UnicodeString& affix,
 
                 // If we skip UWhiteSpace in the input text, we need to skip it in the pattern.
                 // Otherwise, the previous lines may have skipped over text (such as U+00A0) that
-                // is also in the affix.
-                i = skipUWhiteSpace(affix, i);
+                // is also in the trimmedAffix.
+                i = skipUWhiteSpace(trimmedAffix, i);
             } else {
-                if (pos < inputLength &&
-                    input.char32At(pos) == c) {
-                    i += len;
-                    pos += len;
-                } else {
+                UBool match = FALSE;
+                while (pos < inputLength) {
+                    UChar32 ic = input.char32At(pos);
+                    if (!match && ic == c) {
+                        i += len;
+                        pos += len;
+                        match = TRUE;
+                    } else if (IS_BIDI_MARK(ic)) {
+                        pos++; // just skip over this input text
+                    } else {
+                        break;
+                    }
+                }
+                if (!match) {
                     return -1;
                 }
             }
         }
     } else {
         UBool match = FALSE;
-        
-        affixSet = DecimalFormatStaticSets::gStaticSets->fDashEquivalents;
+
+        affixSet = fStaticSets->fDashEquivalents;
 
         if (affixCharLength == affixLength && affixSet->contains(affixChar))  {
-            pos = skipUWhiteSpace(input, pos);
-            
-            if (affixSet->contains(input.char32At(pos))) {
-                return pos - start + 1;
+            pos = skipUWhiteSpaceAndMarks(input, pos);
+            UChar32 ic = input.char32At(pos);
+
+            if (affixSet->contains(ic)) {
+                pos += U16_LENGTH(ic);
+                pos = skipBidiMarks(input, pos);
+                return pos - start;
             }
         }
 
         for (int32_t i = 0; i < affixLength; )
         {
-            //i = skipRuleWhiteSpace(affix, i);
-            i = skipUWhiteSpace(affix, i);
-            pos = skipUWhiteSpace(input, pos);
+            //i = skipRuleWhiteSpace(trimmedAffix, i);
+            i = skipUWhiteSpace(trimmedAffix, i);
+            pos = skipUWhiteSpaceAndMarks(input, pos);
 
             if (i >= affixLength || pos >= inputLength) {
                 break;
             }
 
-            UChar32 c = affix.char32At(i);
-            int32_t len = U16_LENGTH(c);
+            UChar32 c = trimmedAffix.char32At(i);
+            UChar32 ic = input.char32At(pos);
 
-            if (input.char32At(pos) != c) {
+            if (!equalWithSignCompatibility(ic, c)) {
                 return -1;
             }
 
             match = TRUE;
-            i += len;
-            pos += len;
+            i += U16_LENGTH(c);
+            pos += U16_LENGTH(ic);
+            pos = skipBidiMarks(input, pos);
         }
 
         if (affixLength > 0 && ! match) {
@@ -2486,6 +3339,35 @@ int32_t DecimalFormat::skipUWhiteSpace(const UnicodeString& text, int32_t pos) {
     return pos;
 }
 
+/**
+ * Skip over a run of zero or more isUWhiteSpace() characters or bidi marks at pos
+ * in text.
+ */
+int32_t DecimalFormat::skipUWhiteSpaceAndMarks(const UnicodeString& text, int32_t pos) {
+    while (pos < text.length()) {
+        UChar32 c = text.char32At(pos);
+        if (!u_isUWhiteSpace(c) && !IS_BIDI_MARK(c)) { // u_isUWhiteSpace doesn't include LRM,RLM,ALM
+            break;
+        }
+        pos += U16_LENGTH(c);
+    }
+    return pos;
+}
+
+/**
+ * Skip over a run of zero or more bidi marks at pos in text.
+ */
+int32_t DecimalFormat::skipBidiMarks(const UnicodeString& text, int32_t pos) {
+    while (pos < text.length()) {
+        UChar c = text.charAt(pos);
+        if (!IS_BIDI_MARK(c)) {
+            break;
+        }
+        pos++;
+    }
+    return pos;
+}
+
 /**
  * Return the length matched by the given affix, or -1 if none.
  * @param affixPat pattern string
@@ -2507,7 +3389,7 @@ int32_t DecimalFormat::compareComplexAffix(const UnicodeString& affixPat,
     int32_t start = pos;
     U_ASSERT(currency != NULL ||
              (fCurrencyChoice != NULL && *getCurrency() != 0) ||
-             fCurrencySignCount > fgCurrencySignCountZero);
+             fCurrencySignCount != fgCurrencySignCountZero);
 
     for (int32_t i=0;
          i<affixPat.length() && pos >= 0; ) {
@@ -2561,8 +3443,8 @@ int32_t DecimalFormat::compareComplexAffix(const UnicodeString& affixPat,
                         UChar effectiveCurr[4];
                         getEffectiveCurrency(effectiveCurr, ec);
                         if ( U_FAILURE(ec) || u_strncmp(curr,effectiveCurr,4) != 0 ) {
-                               pos = -1;
-                               continue;
+                            pos = -1;
+                            continue;
                         }
                     }
                     pos = ppos.getIndex();
@@ -2716,6 +3598,9 @@ DecimalFormat::adoptDecimalFormatSymbols(DecimalFormatSymbols* symbolsToAdopt)
         setCurrencyForSymbols();
     }
     expandAffixes(NULL);
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 //------------------------------------------------------------------------------
 // Setting the symbols is equlivalent to adopting a newly created localized
@@ -2725,6 +3610,9 @@ void
 DecimalFormat::setDecimalFormatSymbols(const DecimalFormatSymbols& symbols)
 {
     adoptDecimalFormatSymbols(new DecimalFormatSymbols(symbols));
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 
 
@@ -2742,7 +3630,7 @@ DecimalFormat::adoptCurrencyPluralInfo(CurrencyPluralInfo* toAdopt)
         delete fCurrencyPluralInfo;
         fCurrencyPluralInfo = toAdopt;
         // re-set currency affix patterns and currency affixes.
-        if (fCurrencySignCount > fgCurrencySignCountZero) {
+        if (fCurrencySignCount != fgCurrencySignCountZero) {
             UErrorCode status = U_ZERO_ERROR;
             if (fAffixPatternsForCurrency) {
                 deleteHashForAffixPattern();
@@ -2754,12 +3642,18 @@ DecimalFormat::adoptCurrencyPluralInfo(CurrencyPluralInfo* toAdopt)
             }
         }
     }
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 
 void
 DecimalFormat::setCurrencyPluralInfo(const CurrencyPluralInfo& info)
 {
     adoptCurrencyPluralInfo(info.clone());
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 
 
@@ -2800,6 +3694,9 @@ DecimalFormat::setCurrencyForSymbols() {
     }
     ec = U_ZERO_ERROR; // reset local error code!
     setCurrencyInternally(c, ec);
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 
 
@@ -2822,6 +3719,9 @@ DecimalFormat::setPositivePrefix(const UnicodeString& newValue)
     fPositivePrefix = newValue;
     delete fPosPrefixPattern;
     fPosPrefixPattern = 0;
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 
 //------------------------------------------------------------------------------
@@ -2843,6 +3743,9 @@ DecimalFormat::setNegativePrefix(const UnicodeString& newValue)
     fNegativePrefix = newValue;
     delete fNegPrefixPattern;
     fNegPrefixPattern = 0;
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 
 //------------------------------------------------------------------------------
@@ -2864,6 +3767,9 @@ DecimalFormat::setPositiveSuffix(const UnicodeString& newValue)
     fPositiveSuffix = newValue;
     delete fPosSuffixPattern;
     fPosSuffixPattern = 0;
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 
 //------------------------------------------------------------------------------
@@ -2885,6 +3791,9 @@ DecimalFormat::setNegativeSuffix(const UnicodeString& newValue)
     fNegativeSuffix = newValue;
     delete fNegSuffixPattern;
     fNegSuffixPattern = 0;
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 
 //------------------------------------------------------------------------------
@@ -2925,6 +3834,9 @@ DecimalFormat::setMultiplier(int32_t newValue)
             fMultiplier->set(newValue);
         }
     }
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 
 /**
@@ -2966,6 +3878,9 @@ void DecimalFormat::setRoundingIncrement(double newValue) {
     // or fRoundingIncrement could not be created.
     delete fRoundingIncrement;
     fRoundingIncrement = NULL;
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 
 /**
@@ -2989,6 +3904,9 @@ DecimalFormat::ERoundingMode DecimalFormat::getRoundingMode() const {
  */
 void DecimalFormat::setRoundingMode(ERoundingMode roundingMode) {
     fRoundingMode = roundingMode;
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 
 /**
@@ -3018,6 +3936,9 @@ int32_t DecimalFormat::getFormatWidth() const {
  */
 void DecimalFormat::setFormatWidth(int32_t width) {
     fFormatWidth = (width > 0) ? width : 0;
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 
 UnicodeString DecimalFormat::getPadCharacterString() const {
@@ -3031,6 +3952,9 @@ void DecimalFormat::setPadCharacter(const UnicodeString &padChar) {
     else {
         fPad = kDefaultPad;
     }
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 
 /**
@@ -3075,6 +3999,9 @@ DecimalFormat::EPadPosition DecimalFormat::getPadPosition() const {
  */
 void DecimalFormat::setPadPosition(EPadPosition padPos) {
     fPadPosition = padPos;
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 
 /**
@@ -3086,7 +4013,7 @@ void DecimalFormat::setPadPosition(EPadPosition padPos) {
  * @see #isExponentSignAlwaysShown
  * @see #setExponentSignAlwaysShown
  */
-UBool DecimalFormat::isScientificNotation() {
+UBool DecimalFormat::isScientificNotation() const {
     return fUseExponentialNotation;
 }
 
@@ -3102,6 +4029,9 @@ UBool DecimalFormat::isScientificNotation() {
  */
 void DecimalFormat::setScientificNotation(UBool useScientific) {
     fUseExponentialNotation = useScientific;
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 
 /**
@@ -3130,6 +4060,9 @@ int8_t DecimalFormat::getMinimumExponentDigits() const {
  */
 void DecimalFormat::setMinimumExponentDigits(int8_t minExpDig) {
     fMinExponentDigits = (int8_t)((minExpDig > 0) ? minExpDig : 1);
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 
 /**
@@ -3143,7 +4076,7 @@ void DecimalFormat::setMinimumExponentDigits(int8_t minExpDig) {
  * @see #getMinimumExponentDigits
  * @see #setExponentSignAlwaysShown
  */
-UBool DecimalFormat::isExponentSignAlwaysShown() {
+UBool DecimalFormat::isExponentSignAlwaysShown() const {
     return fExponentSignAlwaysShown;
 }
 
@@ -3161,6 +4094,9 @@ UBool DecimalFormat::isExponentSignAlwaysShown() {
  */
 void DecimalFormat::setExponentSignAlwaysShown(UBool expSignAlways) {
     fExponentSignAlwaysShown = expSignAlways;
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 
 //------------------------------------------------------------------------------
@@ -3170,7 +4106,7 @@ void DecimalFormat::setExponentSignAlwaysShown(UBool expSignAlways) {
 int32_t
 DecimalFormat::getGroupingSize() const
 {
-    return fGroupingSize;
+    return isGroupingUsed() ? fGroupingSize : 0;
 }
 
 //------------------------------------------------------------------------------
@@ -3180,6 +4116,9 @@ void
 DecimalFormat::setGroupingSize(int32_t newValue)
 {
     fGroupingSize = newValue;
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 
 //------------------------------------------------------------------------------
@@ -3196,6 +4135,9 @@ void
 DecimalFormat::setSecondaryGroupingSize(int32_t newValue)
 {
     fGroupingSize2 = newValue;
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 
 //------------------------------------------------------------------------------
@@ -3214,6 +4156,9 @@ void
 DecimalFormat::setDecimalSeparatorAlwaysShown(UBool newValue)
 {
     fDecimalSeparatorAlwaysShown = newValue;
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 
 //------------------------------------------------------------------------------
@@ -3264,13 +4209,13 @@ void DecimalFormat::expandAffixes(const UnicodeString* pluralCount) {
     }
 #ifdef FMT_DEBUG
     UnicodeString s;
-    s.append("[")
-        .append(*fPosPrefixPattern).append("|").append(*fPosSuffixPattern)
-        .append(";") .append(*fNegPrefixPattern).append("|").append(*fNegSuffixPattern)
-        .append("]->[")
-        .append(fPositivePrefix).append("|").append(fPositiveSuffix)
-        .append(";") .append(fNegativePrefix).append("|").append(fNegativeSuffix)
-        .append("]\n");
+    s.append(UnicodeString("["))
+      .append(DEREFSTR(fPosPrefixPattern)).append((UnicodeString)"|").append(DEREFSTR(fPosSuffixPattern))
+      .append((UnicodeString)";") .append(DEREFSTR(fNegPrefixPattern)).append((UnicodeString)"|").append(DEREFSTR(fNegSuffixPattern))
+        .append((UnicodeString)"]->[")
+        .append(fPositivePrefix).append((UnicodeString)"|").append(fPositiveSuffix)
+        .append((UnicodeString)";") .append(fNegativePrefix).append((UnicodeString)"|").append(fNegativeSuffix)
+        .append((UnicodeString)"]\n");
     debugout(s);
 #endif
 }
@@ -3492,7 +4437,15 @@ int32_t DecimalFormat::appendAffix(UnicodeString& buf, double number,
 
     const UnicodeString* affix;
     if (fCurrencySignCount == fgCurrencySignCountInPluralFormat) {
-        UnicodeString pluralCount = fCurrencyPluralInfo->getPluralRules()->select(number);
+        // TODO: get an accurate count of visible fraction digits.
+        UnicodeString pluralCount;
+        int32_t minFractionDigits = this->getMinimumFractionDigits();
+        if (minFractionDigits > 0) {
+            FixedDecimal ni(number, this->getMinimumFractionDigits());
+            pluralCount = fCurrencyPluralInfo->getPluralRules()->select(ni);
+        } else {
+            pluralCount = fCurrencyPluralInfo->getPluralRules()->select(number);
+        }
         AffixesForCurrency* oneSet;
         if (fStyle == UNUM_CURRENCY_PLURAL) {
             oneSet = (AffixesForCurrency*)fPluralAffixesForCurrency->get(pluralCount);
@@ -3958,596 +4911,77 @@ DecimalFormat::applyPatternWithoutExpandAffix(const UnicodeString& pattern,
     {
         return;
     }
-    // Clear error struct
-    parseError.offset = -1;
-    parseError.preContext[0] = parseError.postContext[0] = (UChar)0;
-
-    // Set the significant pattern symbols
-    UChar32 zeroDigit               = kPatternZeroDigit; // '0'
-    UChar32 sigDigit                = kPatternSignificantDigit; // '@'
-    UnicodeString groupingSeparator ((UChar)kPatternGroupingSeparator);
-    UnicodeString decimalSeparator  ((UChar)kPatternDecimalSeparator);
-    UnicodeString percent           ((UChar)kPatternPercent);
-    UnicodeString perMill           ((UChar)kPatternPerMill);
-    UnicodeString digit             ((UChar)kPatternDigit); // '#'
-    UnicodeString separator         ((UChar)kPatternSeparator);
-    UnicodeString exponent          ((UChar)kPatternExponent);
-    UnicodeString plus              ((UChar)kPatternPlus);
-    UnicodeString minus             ((UChar)kPatternMinus);
-    UnicodeString padEscape         ((UChar)kPatternPadEscape);
-    // Substitute with the localized symbols if necessary
+    DecimalFormatPatternParser patternParser;
     if (localized) {
-        zeroDigit = getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0);
-        sigDigit = getConstSymbol(DecimalFormatSymbols::kSignificantDigitSymbol).char32At(0);
-        groupingSeparator.  remove().append(getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol));
-        decimalSeparator.   remove().append(getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol));
-        percent.            remove().append(getConstSymbol(DecimalFormatSymbols::kPercentSymbol));
-        perMill.            remove().append(getConstSymbol(DecimalFormatSymbols::kPerMillSymbol));
-        digit.              remove().append(getConstSymbol(DecimalFormatSymbols::kDigitSymbol));
-        separator.          remove().append(getConstSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol));
-        exponent.           remove().append(getConstSymbol(DecimalFormatSymbols::kExponentialSymbol));
-        plus.               remove().append(getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol));
-        minus.              remove().append(getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol));
-        padEscape.          remove().append(getConstSymbol(DecimalFormatSymbols::kPadEscapeSymbol));
-    }
-    UChar nineDigit = (UChar)(zeroDigit + 9);
-    int32_t digitLen = digit.length();
-    int32_t groupSepLen = groupingSeparator.length();
-    int32_t decimalSepLen = decimalSeparator.length();
-
-    int32_t pos = 0;
-    int32_t patLen = pattern.length();
-    // Part 0 is the positive pattern.  Part 1, if present, is the negative
-    // pattern.
-    for (int32_t part=0; part<2 && pos<patLen; ++part) {
-        // The subpart ranges from 0 to 4: 0=pattern proper, 1=prefix,
-        // 2=suffix, 3=prefix in quote, 4=suffix in quote.  Subpart 0 is
-        // between the prefix and suffix, and consists of pattern
-        // characters.  In the prefix and suffix, percent, perMill, and
-        // currency symbols are recognized and translated.
-        int32_t subpart = 1, sub0Start = 0, sub0Limit = 0, sub2Limit = 0;
-
-        // It's important that we don't change any fields of this object
-        // prematurely.  We set the following variables for the multiplier,
-        // grouping, etc., and then only change the actual object fields if
-        // everything parses correctly.  This also lets us register
-        // the data from part 0 and ignore the part 1, except for the
-        // prefix and suffix.
-        UnicodeString prefix;
-        UnicodeString suffix;
-        int32_t decimalPos = -1;
-        int32_t multiplier = 1;
-        int32_t digitLeftCount = 0, zeroDigitCount = 0, digitRightCount = 0, sigDigitCount = 0;
-        int8_t groupingCount = -1;
-        int8_t groupingCount2 = -1;
-        int32_t padPos = -1;
-        UChar32 padChar = 0;
-        int32_t roundingPos = -1;
-        DigitList roundingInc;
-        int8_t expDigits = -1;
-        UBool expSignAlways = FALSE;
-
-        // The affix is either the prefix or the suffix.
-        UnicodeString* affix = &prefix;
-
-        int32_t start = pos;
-        UBool isPartDone = FALSE;
-        UChar32 ch;
-
-        for (; !isPartDone && pos < patLen; ) {
-            // Todo: account for surrogate pairs
-            ch = pattern.char32At(pos);
-            switch (subpart) {
-            case 0: // Pattern proper subpart (between prefix & suffix)
-                // Process the digits, decimal, and grouping characters.  We
-                // record five pieces of information.  We expect the digits
-                // to occur in the pattern ####00.00####, and we record the
-                // number of left digits, zero (central) digits, and right
-                // digits.  The position of the last grouping character is
-                // recorded (should be somewhere within the first two blocks
-                // of characters), as is the position of the decimal point,
-                // if any (should be in the zero digits).  If there is no
-                // decimal point, then there should be no right digits.
-                if (pattern.compare(pos, digitLen, digit) == 0) {
-                    if (zeroDigitCount > 0 || sigDigitCount > 0) {
-                        ++digitRightCount;
-                    } else {
-                        ++digitLeftCount;
-                    }
-                    if (groupingCount >= 0 && decimalPos < 0) {
-                        ++groupingCount;
-                    }
-                    pos += digitLen;
-                } else if ((ch >= zeroDigit && ch <= nineDigit) ||
-                           ch == sigDigit) {
-                    if (digitRightCount > 0) {
-                        // Unexpected '0'
-                        debug("Unexpected '0'")
-                        status = U_UNEXPECTED_TOKEN;
-                        syntaxError(pattern,pos,parseError);
-                        return;
-                    }
-                    if (ch == sigDigit) {
-                        ++sigDigitCount;
-                    } else {
-                        if (ch != zeroDigit && roundingPos < 0) {
-                            roundingPos = digitLeftCount + zeroDigitCount;
-                        }
-                        if (roundingPos >= 0) {
-                            roundingInc.append((char)(ch - zeroDigit + '0'));
-                        }
-                        ++zeroDigitCount;
-                    }
-                    if (groupingCount >= 0 && decimalPos < 0) {
-                        ++groupingCount;
-                    }
-                    pos += U16_LENGTH(ch);
-                } else if (pattern.compare(pos, groupSepLen, groupingSeparator) == 0) {
-                    if (decimalPos >= 0) {
-                        // Grouping separator after decimal
-                        debug("Grouping separator after decimal")
-                        status = U_UNEXPECTED_TOKEN;
-                        syntaxError(pattern,pos,parseError);
-                        return;
-                    }
-                    groupingCount2 = groupingCount;
-                    groupingCount = 0;
-                    pos += groupSepLen;
-                } else if (pattern.compare(pos, decimalSepLen, decimalSeparator) == 0) {
-                    if (decimalPos >= 0) {
-                        // Multiple decimal separators
-                        debug("Multiple decimal separators")
-                        status = U_MULTIPLE_DECIMAL_SEPARATORS;
-                        syntaxError(pattern,pos,parseError);
-                        return;
-                    }
-                    // Intentionally incorporate the digitRightCount,
-                    // even though it is illegal for this to be > 0
-                    // at this point.  We check pattern syntax below.
-                    decimalPos = digitLeftCount + zeroDigitCount + digitRightCount;
-                    pos += decimalSepLen;
-                } else {
-                    if (pattern.compare(pos, exponent.length(), exponent) == 0) {
-                        if (expDigits >= 0) {
-                            // Multiple exponential symbols
-                            debug("Multiple exponential symbols")
-                            status = U_MULTIPLE_EXPONENTIAL_SYMBOLS;
-                            syntaxError(pattern,pos,parseError);
-                            return;
-                        }
-                        if (groupingCount >= 0) {
-                            // Grouping separator in exponential pattern
-                            debug("Grouping separator in exponential pattern")
-                            status = U_MALFORMED_EXPONENTIAL_PATTERN;
-                            syntaxError(pattern,pos,parseError);
-                            return;
-                        }
-                        pos += exponent.length();
-                        // Check for positive prefix
-                        if (pos < patLen
-                            && pattern.compare(pos, plus.length(), plus) == 0) {
-                            expSignAlways = TRUE;
-                            pos += plus.length();
-                        }
-                        // Use lookahead to parse out the exponential part of the
-                        // pattern, then jump into suffix subpart.
-                        expDigits = 0;
-                        while (pos < patLen &&
-                               pattern.char32At(pos) == zeroDigit) {
-                            ++expDigits;
-                            pos += U16_LENGTH(zeroDigit);
-                        }
-
-                        // 1. Require at least one mantissa pattern digit
-                        // 2. Disallow "#+ @" in mantissa
-                        // 3. Require at least one exponent pattern digit
-                        if (((digitLeftCount + zeroDigitCount) < 1 &&
-                             (sigDigitCount + digitRightCount) < 1) ||
-                            (sigDigitCount > 0 && digitLeftCount > 0) ||
-                            expDigits < 1) {
-                            // Malformed exponential pattern
-                            debug("Malformed exponential pattern")
-                            status = U_MALFORMED_EXPONENTIAL_PATTERN;
-                            syntaxError(pattern,pos,parseError);
-                            return;
-                        }
-                    }
-                    // Transition to suffix subpart
-                    subpart = 2; // suffix subpart
-                    affix = &suffix;
-                    sub0Limit = pos;
-                    continue;
-                }
-                break;
-            case 1: // Prefix subpart
-            case 2: // Suffix subpart
-                // Process the prefix / suffix characters
-                // Process unquoted characters seen in prefix or suffix
-                // subpart.
-
-                // Several syntax characters implicitly begins the
-                // next subpart if we are in the prefix; otherwise
-                // they are illegal if unquoted.
-                if (!pattern.compare(pos, digitLen, digit) ||
-                    !pattern.compare(pos, groupSepLen, groupingSeparator) ||
-                    !pattern.compare(pos, decimalSepLen, decimalSeparator) ||
-                    (ch >= zeroDigit && ch <= nineDigit) ||
-                    ch == sigDigit) {
-                    if (subpart == 1) { // prefix subpart
-                        subpart = 0; // pattern proper subpart
-                        sub0Start = pos; // Reprocess this character
-                        continue;
-                    } else {
-                        status = U_UNQUOTED_SPECIAL;
-                        syntaxError(pattern,pos,parseError);
-                        return;
-                    }
-                } else if (ch == kCurrencySign) {
-                    affix->append(kQuote); // Encode currency
-                    // Use lookahead to determine if the currency sign is
-                    // doubled or not.
-                    U_ASSERT(U16_LENGTH(kCurrencySign) == 1);
-                    if ((pos+1) < pattern.length() && pattern[pos+1] == kCurrencySign) {
-                        affix->append(kCurrencySign);
-                        ++pos; // Skip over the doubled character
-                        if ((pos+1) < pattern.length() &&
-                            pattern[pos+1] == kCurrencySign) {
-                            affix->append(kCurrencySign);
-                            ++pos; // Skip over the doubled character
-                            fCurrencySignCount = fgCurrencySignCountInPluralFormat;
-                        } else {
-                            fCurrencySignCount = fgCurrencySignCountInISOFormat;
-                        }
-                    } else {
-                        fCurrencySignCount = fgCurrencySignCountInSymbolFormat;
-                    }
-                    // Fall through to append(ch)
-                } else if (ch == kQuote) {
-                    // A quote outside quotes indicates either the opening
-                    // quote or two quotes, which is a quote literal.  That is,
-                    // we have the first quote in 'do' or o''clock.
-                    U_ASSERT(U16_LENGTH(kQuote) == 1);
-                    ++pos;
-                    if (pos < pattern.length() && pattern[pos] == kQuote) {
-                        affix->append(kQuote); // Encode quote
-                        // Fall through to append(ch)
-                    } else {
-                        subpart += 2; // open quote
-                        continue;
-                    }
-                } else if (pattern.compare(pos, separator.length(), separator) == 0) {
-                    // Don't allow separators in the prefix, and don't allow
-                    // separators in the second pattern (part == 1).
-                    if (subpart == 1 || part == 1) {
-                        // Unexpected separator
-                        debug("Unexpected separator")
-                        status = U_UNEXPECTED_TOKEN;
-                        syntaxError(pattern,pos,parseError);
-                        return;
-                    }
-                    sub2Limit = pos;
-                    isPartDone = TRUE; // Go to next part
-                    pos += separator.length();
-                    break;
-                } else if (pattern.compare(pos, percent.length(), percent) == 0) {
-                    // Next handle characters which are appended directly.
-                    if (multiplier != 1) {
-                        // Too many percent/perMill characters
-                        debug("Too many percent characters")
-                        status = U_MULTIPLE_PERCENT_SYMBOLS;
-                        syntaxError(pattern,pos,parseError);
-                        return;
-                    }
-                    affix->append(kQuote); // Encode percent/perMill
-                    affix->append(kPatternPercent); // Use unlocalized pattern char
-                    multiplier = 100;
-                    pos += percent.length();
-                    break;
-                } else if (pattern.compare(pos, perMill.length(), perMill) == 0) {
-                    // Next handle characters which are appended directly.
-                    if (multiplier != 1) {
-                        // Too many percent/perMill characters
-                        debug("Too many perMill characters")
-                        status = U_MULTIPLE_PERMILL_SYMBOLS;
-                        syntaxError(pattern,pos,parseError);
-                        return;
-                    }
-                    affix->append(kQuote); // Encode percent/perMill
-                    affix->append(kPatternPerMill); // Use unlocalized pattern char
-                    multiplier = 1000;
-                    pos += perMill.length();
-                    break;
-                } else if (pattern.compare(pos, padEscape.length(), padEscape) == 0) {
-                    if (padPos >= 0 ||               // Multiple pad specifiers
-                        (pos+1) == pattern.length()) { // Nothing after padEscape
-                        debug("Multiple pad specifiers")
-                        status = U_MULTIPLE_PAD_SPECIFIERS;
-                        syntaxError(pattern,pos,parseError);
-                        return;
-                    }
-                    padPos = pos;
-                    pos += padEscape.length();
-                    padChar = pattern.char32At(pos);
-                    pos += U16_LENGTH(padChar);
-                    break;
-                } else if (pattern.compare(pos, minus.length(), minus) == 0) {
-                    affix->append(kQuote); // Encode minus
-                    affix->append(kPatternMinus);
-                    pos += minus.length();
-                    break;
-                } else if (pattern.compare(pos, plus.length(), plus) == 0) {
-                    affix->append(kQuote); // Encode plus
-                    affix->append(kPatternPlus);
-                    pos += plus.length();
-                    break;
-                }
-                // Unquoted, non-special characters fall through to here, as
-                // well as other code which needs to append something to the
-                // affix.
-                affix->append(ch);
-                pos += U16_LENGTH(ch);
-                break;
-            case 3: // Prefix subpart, in quote
-            case 4: // Suffix subpart, in quote
-                // A quote within quotes indicates either the closing
-                // quote or two quotes, which is a quote literal.  That is,
-                // we have the second quote in 'do' or 'don''t'.
-                if (ch == kQuote) {
-                    ++pos;
-                    if (pos < pattern.length() && pattern[pos] == kQuote) {
-                        affix->append(kQuote); // Encode quote
-                        // Fall through to append(ch)
-                    } else {
-                        subpart -= 2; // close quote
-                        continue;
-                    }
-                }
-                affix->append(ch);
-                pos += U16_LENGTH(ch);
-                break;
-            }
-        }
-
-        if (sub0Limit == 0) {
-            sub0Limit = pattern.length();
-        }
-
-        if (sub2Limit == 0) {
-            sub2Limit = pattern.length();
-        }
-
-        /* Handle patterns with no '0' pattern character.  These patterns
-         * are legal, but must be recodified to make sense.  "##.###" ->
-         * "#0.###".  ".###" -> ".0##".
-         *
-         * We allow patterns of the form "####" to produce a zeroDigitCount
-         * of zero (got that?); although this seems like it might make it
-         * possible for format() to produce empty strings, format() checks
-         * for this condition and outputs a zero digit in this situation.
-         * Having a zeroDigitCount of zero yields a minimum integer digits
-         * of zero, which allows proper round-trip patterns.  We don't want
-         * "#" to become "#0" when toPattern() is called (even though that's
-         * what it really is, semantically).
-         */
-        if (zeroDigitCount == 0 && sigDigitCount == 0 &&
-            digitLeftCount > 0 && decimalPos >= 0) {
-            // Handle "###.###" and "###." and ".###"
-            int n = decimalPos;
-            if (n == 0)
-                ++n; // Handle ".###"
-            digitRightCount = digitLeftCount - n;
-            digitLeftCount = n - 1;
-            zeroDigitCount = 1;
-        }
-
-        // Do syntax checking on the digits, decimal points, and quotes.
-        if ((decimalPos < 0 && digitRightCount > 0 && sigDigitCount == 0) ||
-            (decimalPos >= 0 &&
-             (sigDigitCount > 0 ||
-              decimalPos < digitLeftCount ||
-              decimalPos > (digitLeftCount + zeroDigitCount))) ||
-            groupingCount == 0 || groupingCount2 == 0 ||
-            (sigDigitCount > 0 && zeroDigitCount > 0) ||
-            subpart > 2)
-        { // subpart > 2 == unmatched quote
-            debug("Syntax error")
-            status = U_PATTERN_SYNTAX_ERROR;
-            syntaxError(pattern,pos,parseError);
-            return;
-        }
-
-        // Make sure pad is at legal position before or after affix.
-        if (padPos >= 0) {
-            if (padPos == start) {
-                padPos = kPadBeforePrefix;
-            } else if (padPos+2 == sub0Start) {
-                padPos = kPadAfterPrefix;
-            } else if (padPos == sub0Limit) {
-                padPos = kPadBeforeSuffix;
-            } else if (padPos+2 == sub2Limit) {
-                padPos = kPadAfterSuffix;
-            } else {
-                // Illegal pad position
-                debug("Illegal pad position")
-                status = U_ILLEGAL_PAD_POSITION;
-                syntaxError(pattern,pos,parseError);
-                return;
-            }
-        }
-
-        if (part == 0) {
-            delete fPosPrefixPattern;
-            delete fPosSuffixPattern;
-            delete fNegPrefixPattern;
-            delete fNegSuffixPattern;
-            fPosPrefixPattern = new UnicodeString(prefix);
-            /* test for NULL */
-            if (fPosPrefixPattern == 0) {
-                status = U_MEMORY_ALLOCATION_ERROR;
-                return;
-            }
-            fPosSuffixPattern = new UnicodeString(suffix);
-            /* test for NULL */
-            if (fPosSuffixPattern == 0) {
-                status = U_MEMORY_ALLOCATION_ERROR;
-                delete fPosPrefixPattern;
-                return;
-            }
-            fNegPrefixPattern = 0;
-            fNegSuffixPattern = 0;
-
-            fUseExponentialNotation = (expDigits >= 0);
-            if (fUseExponentialNotation) {
-                fMinExponentDigits = expDigits;
-            }
-            fExponentSignAlwaysShown = expSignAlways;
-            int32_t digitTotalCount = digitLeftCount + zeroDigitCount + digitRightCount;
-            // The effectiveDecimalPos is the position the decimal is at or
-            // would be at if there is no decimal.  Note that if
-            // decimalPos<0, then digitTotalCount == digitLeftCount +
-            // zeroDigitCount.
-            int32_t effectiveDecimalPos = decimalPos >= 0 ? decimalPos : digitTotalCount;
-            UBool isSigDig = (sigDigitCount > 0);
-            setSignificantDigitsUsed(isSigDig);
-            if (isSigDig) {
-                setMinimumSignificantDigits(sigDigitCount);
-                setMaximumSignificantDigits(sigDigitCount + digitRightCount);
-            } else {
-                int32_t minInt = effectiveDecimalPos - digitLeftCount;
-                setMinimumIntegerDigits(minInt);
-                setMaximumIntegerDigits(fUseExponentialNotation
-                    ? digitLeftCount + getMinimumIntegerDigits()
-                    : kDoubleIntegerDigits);
-                setMaximumFractionDigits(decimalPos >= 0
-                    ? (digitTotalCount - decimalPos) : 0);
-                setMinimumFractionDigits(decimalPos >= 0
-                    ? (digitLeftCount + zeroDigitCount - decimalPos) : 0);
-            }
-            setGroupingUsed(groupingCount > 0);
-            fGroupingSize = (groupingCount > 0) ? groupingCount : 0;
-            fGroupingSize2 = (groupingCount2 > 0 && groupingCount2 != groupingCount)
-                ? groupingCount2 : 0;
-            setMultiplier(multiplier);
-            setDecimalSeparatorAlwaysShown(decimalPos == 0
-                    || decimalPos == digitTotalCount);
-            if (padPos >= 0) {
-                fPadPosition = (EPadPosition) padPos;
-                // To compute the format width, first set up sub0Limit -
-                // sub0Start.  Add in prefix/suffix length later.
-
-                // fFormatWidth = prefix.length() + suffix.length() +
-                //    sub0Limit - sub0Start;
-                fFormatWidth = sub0Limit - sub0Start;
-                fPad = padChar;
-            } else {
-                fFormatWidth = 0;
-            }
-            if (roundingPos >= 0) {
-                roundingInc.setDecimalAt(effectiveDecimalPos - roundingPos);
-                if (fRoundingIncrement != NULL) {
-                    *fRoundingIncrement = roundingInc;
-                } else {
-                    fRoundingIncrement = new DigitList(roundingInc);
-                    /* test for NULL */
-                    if (fRoundingIncrement == NULL) {
-                        status = U_MEMORY_ALLOCATION_ERROR;
-                        delete fPosPrefixPattern;
-                        delete fPosSuffixPattern;
-                        return;
-                    }
-                }
-                fRoundingMode = kRoundHalfEven;
-            } else {
-                setRoundingIncrement(0.0);
-            }
-        } else {
-            fNegPrefixPattern = new UnicodeString(prefix);
-            /* test for NULL */
-            if (fNegPrefixPattern == 0) {
-                status = U_MEMORY_ALLOCATION_ERROR;
-                return;
-            }
-            fNegSuffixPattern = new UnicodeString(suffix);
-            /* test for NULL */
-            if (fNegSuffixPattern == 0) {
-                delete fNegPrefixPattern;
-                status = U_MEMORY_ALLOCATION_ERROR;
-                return;
-            }
-        }
+      patternParser.useSymbols(*fSymbols);
     }
-
-    if (pattern.length() == 0) {
-        delete fNegPrefixPattern;
-        delete fNegSuffixPattern;
-        fNegPrefixPattern = NULL;
-        fNegSuffixPattern = NULL;
-        if (fPosPrefixPattern != NULL) {
-            fPosPrefixPattern->remove();
-        } else {
-            fPosPrefixPattern = new UnicodeString();
-            /* test for NULL */
-            if (fPosPrefixPattern == 0) {
-                status = U_MEMORY_ALLOCATION_ERROR;
-                return;
-            }
-        }
-        if (fPosSuffixPattern != NULL) {
-            fPosSuffixPattern->remove();
+    fFormatPattern = pattern;
+    DecimalFormatPattern out;
+    patternParser.applyPatternWithoutExpandAffix(
+        pattern,
+        out,
+        parseError,
+        status);
+    if (U_FAILURE(status)) {
+      return;
+    }
+
+    setMinimumIntegerDigits(out.fMinimumIntegerDigits);
+    setMaximumIntegerDigits(out.fMaximumIntegerDigits);
+    setMinimumFractionDigits(out.fMinimumFractionDigits);
+    setMaximumFractionDigits(out.fMaximumFractionDigits);
+    setSignificantDigitsUsed(out.fUseSignificantDigits);
+    if (out.fUseSignificantDigits) {
+        setMinimumSignificantDigits(out.fMinimumSignificantDigits);
+        setMaximumSignificantDigits(out.fMaximumSignificantDigits);
+    }
+    fUseExponentialNotation = out.fUseExponentialNotation;
+    if (out.fUseExponentialNotation) {
+        fMinExponentDigits = out.fMinExponentDigits;
+    }
+    fExponentSignAlwaysShown = out.fExponentSignAlwaysShown;
+    fCurrencySignCount = out.fCurrencySignCount;
+    setGroupingUsed(out.fGroupingUsed);
+    if (out.fGroupingUsed) {
+        fGroupingSize = out.fGroupingSize;
+        fGroupingSize2 = out.fGroupingSize2;
+    }
+    setMultiplier(out.fMultiplier);
+    fDecimalSeparatorAlwaysShown = out.fDecimalSeparatorAlwaysShown;
+    fFormatWidth = out.fFormatWidth;
+    if (out.fRoundingIncrementUsed) {
+        if (fRoundingIncrement != NULL) {
+            *fRoundingIncrement = out.fRoundingIncrement;
         } else {
-            fPosSuffixPattern = new UnicodeString();
+            fRoundingIncrement = new DigitList(out.fRoundingIncrement);
             /* test for NULL */
-            if (fPosSuffixPattern == 0) {
-                delete fPosPrefixPattern;
-                status = U_MEMORY_ALLOCATION_ERROR;
-                return;
+            if (fRoundingIncrement == NULL) {
+                 status = U_MEMORY_ALLOCATION_ERROR;
+                 return;
             }
         }
-
-        setMinimumIntegerDigits(0);
-        setMaximumIntegerDigits(kDoubleIntegerDigits);
-        setMinimumFractionDigits(0);
-        setMaximumFractionDigits(kDoubleFractionDigits);
-
-        fUseExponentialNotation = FALSE;
-        fCurrencySignCount = 0;
-        setGroupingUsed(FALSE);
-        fGroupingSize = 0;
-        fGroupingSize2 = 0;
-        setMultiplier(1);
-        setDecimalSeparatorAlwaysShown(FALSE);
-        fFormatWidth = 0;
+    } else {
         setRoundingIncrement(0.0);
     }
-
-    // If there was no negative pattern, or if the negative pattern is
-    // identical to the positive pattern, then prepend the minus sign to the
-    // positive pattern to form the negative pattern.
-    if (fNegPrefixPattern == NULL ||
-        (*fNegPrefixPattern == *fPosPrefixPattern
-         && *fNegSuffixPattern == *fPosSuffixPattern)) {
-        _copy_us_ptr(&fNegSuffixPattern, fPosSuffixPattern);
-        if (fNegPrefixPattern == NULL) {
-            fNegPrefixPattern = new UnicodeString();
-            /* test for NULL */
-            if (fNegPrefixPattern == 0) {
-                status = U_MEMORY_ALLOCATION_ERROR;
-                return;
-            }
-        } else {
-            fNegPrefixPattern->remove();
-        }
-        fNegPrefixPattern->append(kQuote).append(kPatternMinus)
-            .append(*fPosPrefixPattern);
+    fPad = out.fPad;
+    switch (out.fPadPosition) {
+        case DecimalFormatPattern::kPadBeforePrefix:
+            fPadPosition = kPadBeforePrefix;
+            break;
+        case DecimalFormatPattern::kPadAfterPrefix:
+            fPadPosition = kPadAfterPrefix;
+            break;
+        case DecimalFormatPattern::kPadBeforeSuffix:
+            fPadPosition = kPadBeforeSuffix;
+            break;
+        case DecimalFormatPattern::kPadAfterSuffix:
+            fPadPosition = kPadAfterSuffix;
+            break;
     }
-#ifdef FMT_DEBUG
-    UnicodeString s;
-    s.append("\"").append(pattern).append("\"->");
-    debugout(s);
-#endif
-
-    // save the pattern
-    fFormatPattern = pattern;
+    copyString(out.fNegPrefixPattern, out.fNegPatternsBogus, fNegPrefixPattern, status);
+    copyString(out.fNegSuffixPattern, out.fNegPatternsBogus, fNegSuffixPattern, status);
+    copyString(out.fPosPrefixPattern, out.fPosPatternsBogus, fPosPrefixPattern, status);
+    copyString(out.fPosSuffixPattern, out.fPosPatternsBogus, fPosSuffixPattern, status);
 }
 
 
@@ -4586,6 +5020,9 @@ DecimalFormat::applyPattern(const UnicodeString& pattern,
     }
     applyPatternWithoutExpandAffix(pattern, localized, parseError, status);
     expandAffixAdjustWidth(NULL);
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 
 
@@ -4597,16 +5034,22 @@ DecimalFormat::applyPatternInternally(const UnicodeString& pluralCount,
                                       UErrorCode& status) {
     applyPatternWithoutExpandAffix(pattern, localized, parseError, status);
     expandAffixAdjustWidth(&pluralCount);
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 
 
 /**
  * Sets the maximum number of digits allowed in the integer portion of a
- * number. This override limits the integer digit count to 309.
+ * number. 
  * @see NumberFormat#setMaximumIntegerDigits
  */
 void DecimalFormat::setMaximumIntegerDigits(int32_t newValue) {
-    NumberFormat::setMaximumIntegerDigits(_min(newValue, kDoubleIntegerDigits));
+    NumberFormat::setMaximumIntegerDigits(_min(newValue, gDefaultMaxIntegerDigits));
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 
 /**
@@ -4616,6 +5059,9 @@ void DecimalFormat::setMaximumIntegerDigits(int32_t newValue) {
  */
 void DecimalFormat::setMinimumIntegerDigits(int32_t newValue) {
     NumberFormat::setMinimumIntegerDigits(_min(newValue, kDoubleIntegerDigits));
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 
 /**
@@ -4625,6 +5071,9 @@ void DecimalFormat::setMinimumIntegerDigits(int32_t newValue) {
  */
 void DecimalFormat::setMaximumFractionDigits(int32_t newValue) {
     NumberFormat::setMaximumFractionDigits(_min(newValue, kDoubleFractionDigits));
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 
 /**
@@ -4634,6 +5083,9 @@ void DecimalFormat::setMaximumFractionDigits(int32_t newValue) {
  */
 void DecimalFormat::setMinimumFractionDigits(int32_t newValue) {
     NumberFormat::setMinimumFractionDigits(_min(newValue, kDoubleFractionDigits));
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 
 int32_t DecimalFormat::getMinimumSignificantDigits() const {
@@ -4652,6 +5104,10 @@ void DecimalFormat::setMinimumSignificantDigits(int32_t min) {
     int32_t max = _max(fMaxSignificantDigits, min);
     fMinSignificantDigits = min;
     fMaxSignificantDigits = max;
+    fUseSignificantDigits = TRUE;
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 
 void DecimalFormat::setMaximumSignificantDigits(int32_t max) {
@@ -4663,6 +5119,10 @@ void DecimalFormat::setMaximumSignificantDigits(int32_t max) {
     int32_t min = _min(fMinSignificantDigits, max);
     fMinSignificantDigits = min;
     fMaxSignificantDigits = max;
+    fUseSignificantDigits = TRUE;
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 
 UBool DecimalFormat::areSignificantDigitsUsed() const {
@@ -4671,6 +5131,9 @@ UBool DecimalFormat::areSignificantDigitsUsed() const {
 
 void DecimalFormat::setSignificantDigitsUsed(UBool useSignificantDigits) {
     fUseSignificantDigits = useSignificantDigits;
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 
 void DecimalFormat::setCurrencyInternally(const UChar* theCurrency,
@@ -4688,7 +5151,7 @@ void DecimalFormat::setCurrencyInternally(const UChar* theCurrency,
 
     double rounding = 0.0;
     int32_t frac = 0;
-    if (fCurrencySignCount > fgCurrencySignCountZero && isCurr) {
+    if (fCurrencySignCount != fgCurrencySignCountZero && isCurr) {
         rounding = ucurr_getRoundingIncrement(theCurrency, &ec);
         frac = ucurr_getDefaultFractionDigits(theCurrency, &ec);
     }
@@ -4696,7 +5159,7 @@ void DecimalFormat::setCurrencyInternally(const UChar* theCurrency,
     NumberFormat::setCurrency(theCurrency, ec);
     if (U_FAILURE(ec)) return;
 
-    if (fCurrencySignCount > fgCurrencySignCountZero) {
+    if (fCurrencySignCount != fgCurrencySignCountZero) {
         // NULL or empty currency is *legal* and indicates no currency.
         if (isCurr) {
             setRoundingIncrement(rounding);
@@ -4705,6 +5168,9 @@ void DecimalFormat::setCurrencyInternally(const UChar* theCurrency,
         }
         expandAffixes(NULL);
     }
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 
 void DecimalFormat::setCurrency(const UChar* theCurrency, UErrorCode& ec) {
@@ -4718,12 +5184,18 @@ void DecimalFormat::setCurrency(const UChar* theCurrency, UErrorCode& ec) {
     }
     // set the currency after apply pattern to get the correct rounding/fraction
     setCurrencyInternally(theCurrency, ec);
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 
 // Deprecated variant with no UErrorCode parameter
 void DecimalFormat::setCurrency(const UChar* theCurrency) {
     UErrorCode ec = U_ZERO_ERROR;
     setCurrency(theCurrency, ec);
+#if UCONFIG_FORMAT_FASTPATHS_49
+    handleChanged();
+#endif
 }
 
 void DecimalFormat::getEffectiveCurrency(UChar* result, UErrorCode& ec) const {
@@ -4862,7 +5334,228 @@ DecimalFormat::copyHashForAffixPattern(const Hashtable* source,
     }
 }
 
+// this is only overridden to call handleChanged() for fastpath purposes.
+void
+DecimalFormat::setGroupingUsed(UBool newValue) {
+  NumberFormat::setGroupingUsed(newValue);
+  handleChanged();
+}
+
+// this is only overridden to call handleChanged() for fastpath purposes.
+void
+DecimalFormat::setParseIntegerOnly(UBool newValue) {
+  NumberFormat::setParseIntegerOnly(newValue);
+  handleChanged();
+}
+
+// this is only overridden to call handleChanged() for fastpath purposes.
+// setContext doesn't affect the fastPath right now, but this is called for completeness
+void
+DecimalFormat::setContext(UDisplayContext value, UErrorCode& status) {
+  NumberFormat::setContext(value, status);
+  handleChanged();
+}
+
+
+DecimalFormat& DecimalFormat::setAttribute( UNumberFormatAttribute attr,
+                                            int32_t newValue,
+                                            UErrorCode &status) {
+  if(U_FAILURE(status)) return *this;
+
+  switch(attr) {
+  case UNUM_LENIENT_PARSE:
+    setLenient(newValue!=0);
+    break;
+
+    case UNUM_PARSE_INT_ONLY:
+      setParseIntegerOnly(newValue!=0);
+      break;
+      
+    case UNUM_GROUPING_USED:
+      setGroupingUsed(newValue!=0);
+      break;
+        
+    case UNUM_DECIMAL_ALWAYS_SHOWN:
+      setDecimalSeparatorAlwaysShown(newValue!=0);
+        break;
+        
+    case UNUM_MAX_INTEGER_DIGITS:
+      setMaximumIntegerDigits(newValue);
+        break;
+        
+    case UNUM_MIN_INTEGER_DIGITS:
+      setMinimumIntegerDigits(newValue);
+        break;
+        
+    case UNUM_INTEGER_DIGITS:
+      setMinimumIntegerDigits(newValue);
+      setMaximumIntegerDigits(newValue);
+        break;
+        
+    case UNUM_MAX_FRACTION_DIGITS:
+      setMaximumFractionDigits(newValue);
+        break;
+        
+    case UNUM_MIN_FRACTION_DIGITS:
+      setMinimumFractionDigits(newValue);
+        break;
+        
+    case UNUM_FRACTION_DIGITS:
+      setMinimumFractionDigits(newValue);
+      setMaximumFractionDigits(newValue);
+      break;
+        
+    case UNUM_SIGNIFICANT_DIGITS_USED:
+      setSignificantDigitsUsed(newValue!=0);
+        break;
+
+    case UNUM_MAX_SIGNIFICANT_DIGITS:
+      setMaximumSignificantDigits(newValue);
+        break;
+        
+    case UNUM_MIN_SIGNIFICANT_DIGITS:
+      setMinimumSignificantDigits(newValue);
+        break;
+        
+    case UNUM_MULTIPLIER:
+      setMultiplier(newValue);    
+       break;
+        
+    case UNUM_GROUPING_SIZE:
+      setGroupingSize(newValue);    
+        break;
+        
+    case UNUM_ROUNDING_MODE:
+      setRoundingMode((DecimalFormat::ERoundingMode)newValue);
+        break;
+        
+    case UNUM_FORMAT_WIDTH:
+      setFormatWidth(newValue);
+        break;
+        
+    case UNUM_PADDING_POSITION:
+        /** The position at which padding will take place. */
+      setPadPosition((DecimalFormat::EPadPosition)newValue);
+        break;
+        
+    case UNUM_SECONDARY_GROUPING_SIZE:
+      setSecondaryGroupingSize(newValue);
+        break;
+
+#if UCONFIG_HAVE_PARSEALLINPUT
+    case UNUM_PARSE_ALL_INPUT:
+      setParseAllInput((UNumberFormatAttributeValue)newValue);
+        break;
+#endif
+
+    /* These are stored in fBoolFlags */
+    case UNUM_PARSE_NO_EXPONENT:
+    case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS:
+      if(!fBoolFlags.isValidValue(newValue)) {
+          status = U_ILLEGAL_ARGUMENT_ERROR;
+      } else {
+          fBoolFlags.set(attr, newValue);
+      }
+      break;
+
+    case UNUM_SCALE:
+        fScale = newValue;
+        break;
+
+    default:
+      status = U_UNSUPPORTED_ERROR;
+      break;
+  }
+  return *this;
+}
+
+int32_t DecimalFormat::getAttribute( UNumberFormatAttribute attr, 
+                                     UErrorCode &status ) const {
+  if(U_FAILURE(status)) return -1;
+  switch(attr) {
+    case UNUM_LENIENT_PARSE: 
+        return isLenient();
+
+    case UNUM_PARSE_INT_ONLY:
+        return isParseIntegerOnly();
+        
+    case UNUM_GROUPING_USED:
+        return isGroupingUsed();
+        
+    case UNUM_DECIMAL_ALWAYS_SHOWN:
+        return isDecimalSeparatorAlwaysShown();    
+        
+    case UNUM_MAX_INTEGER_DIGITS:
+        return getMaximumIntegerDigits();
+        
+    case UNUM_MIN_INTEGER_DIGITS:
+        return getMinimumIntegerDigits();
+        
+    case UNUM_INTEGER_DIGITS:
+        // TBD: what should this return?
+        return getMinimumIntegerDigits();
+        
+    case UNUM_MAX_FRACTION_DIGITS:
+        return getMaximumFractionDigits();
+        
+    case UNUM_MIN_FRACTION_DIGITS:
+        return getMinimumFractionDigits();
+        
+    case UNUM_FRACTION_DIGITS:
+        // TBD: what should this return?
+        return getMinimumFractionDigits();
+        
+    case UNUM_SIGNIFICANT_DIGITS_USED:
+        return areSignificantDigitsUsed();
+        
+    case UNUM_MAX_SIGNIFICANT_DIGITS:
+        return getMaximumSignificantDigits();
+        
+    case UNUM_MIN_SIGNIFICANT_DIGITS:
+        return getMinimumSignificantDigits();
+        
+    case UNUM_MULTIPLIER:
+        return getMultiplier();    
+        
+    case UNUM_GROUPING_SIZE:
+        return getGroupingSize();    
+        
+    case UNUM_ROUNDING_MODE:
+        return getRoundingMode();
+        
+    case UNUM_FORMAT_WIDTH:
+        return getFormatWidth();
+        
+    case UNUM_PADDING_POSITION:
+        return getPadPosition();
+        
+    case UNUM_SECONDARY_GROUPING_SIZE:
+        return getSecondaryGroupingSize();
+        
+    /* These are stored in fBoolFlags */
+    case UNUM_PARSE_NO_EXPONENT:
+    case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS:
+      return fBoolFlags.get(attr);
+
+    case UNUM_SCALE:
+        return fScale;
+
+    default:
+        status = U_UNSUPPORTED_ERROR;
+        break;
+  }
+
+  return -1; /* undefined */
+}
 
+#if UCONFIG_HAVE_PARSEALLINPUT
+void DecimalFormat::setParseAllInput(UNumberFormatAttributeValue value) {
+  fParseAllInput = value;
+#if UCONFIG_FORMAT_FASTPATHS_49
+  handleChanged();
+#endif
+}
+#endif
 
 void
 DecimalFormat::copyHashForAffix(const Hashtable* source,