]> granicus.if.org Git - icu/commitdiff
ICU-8610 C++ number skeleton code is building. Testing is next.
authorShane Carr <shane@unicode.org>
Fri, 23 Mar 2018 10:07:38 +0000 (10:07 +0000)
committerShane Carr <shane@unicode.org>
Fri, 23 Mar 2018 10:07:38 +0000 (10:07 +0000)
X-SVN-Rev: 41144

icu4c/source/i18n/Makefile.in
icu4c/source/i18n/number_skeletons.cpp
icu4c/source/i18n/number_skeletons.h
icu4c/source/i18n/numparse_stringsegment.cpp
icu4j/main/classes/core/src/com/ibm/icu/number/NumberSkeletonImpl.java

index e249995b47ace82949ea3e7f5bb78e5678123423..0e11817b1a3ddb0b628b44f6e430509e1033516a 100644 (file)
@@ -108,7 +108,7 @@ double-conversion-cached-powers.o double-conversion-diy-fp.o double-conversion-f
 numparse_stringsegment.o numparse_unisets.o numparse_parsednumber.o \
 numparse_impl.o numparse_symbols.o numparse_decimal.o numparse_scientific.o \
 numparse_currency.o numparse_affixes.o numparse_compositions.o numparse_validators.o \
-number_mapper.o number_multiplier.o number_currencysymbols.o
+number_mapper.o number_multiplier.o number_currencysymbols.o number_skeletons.o
 
 
 ## Header files to install
index dbb94852285cb31174bec71c886ce648f376761c..3efae97f20ab491cb90d2b138e3f2af0bda71e97 100644 (file)
@@ -1,7 +1,6 @@
 // © 2018 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html
 
-#include <unicode/numberformatter.h>
 #include "unicode/utypes.h"
 
 #if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT
 #include "number_skeletons.h"
 #include "umutex.h"
 #include "ucln_in.h"
-#include "hash.h"
 #include "patternprops.h"
 #include "unicode/ucharstriebuilder.h"
 #include "number_utils.h"
+#include "number_decimalquantity.h"
+#include "unicode/numberformatter.h"
 
 using namespace icu;
 using namespace icu::number;
@@ -34,6 +34,7 @@ char16_t* kSerializedStemTrie = nullptr;
 UBool U_CALLCONV cleanupNumberSkeletons() {
     uprv_free(kSerializedStemTrie);
     kSerializedStemTrie = nullptr;
+    return TRUE;
 }
 
 void U_CALLCONV initNumberSkeletons(UErrorCode& status) {
@@ -99,7 +100,14 @@ void U_CALLCONV initNumberSkeletons(UErrorCode& status) {
 }
 
 
-#define CHECK_NULL(seen, field, status) void; /* for auto-format line wraping */ \
+inline void appendMultiple(UnicodeString& sb, UChar32 cp, int32_t count) {
+    for (int i = 0; i < count; i++) {
+        sb.append(cp);
+    }
+}
+
+
+#define CHECK_NULL(seen, field, status) (void)(seen); /* for auto-format line wraping */ \
 { \
     if ((seen).field) { \
         (status) = U_NUMBER_SKELETON_SYNTAX_ERROR; \
@@ -109,6 +117,15 @@ void U_CALLCONV initNumberSkeletons(UErrorCode& status) {
 }
 
 
+const char16_t* const kRoundingModeStrings[] = {
+        u"up", u"down", u"ceiling", u"floor", u"half-up", u"half-down", u"half-even", u"unnecessary"};
+
+constexpr int32_t kRoundingModeCount = 8;
+static_assert(
+        sizeof(kRoundingModeStrings) / sizeof(*kRoundingModeStrings) == kRoundingModeCount,
+        "kRoundingModeCount should be the number of rounding modes");
+
+
 } // anonymous namespace
 
 
@@ -376,6 +393,7 @@ MacroProps skeleton::parseSkeleton(const UnicodeString& skeletonString, UErrorCo
                 stem = parseOption(stem, segment, macros, status);
             }
             segment.resetLength();
+            if (U_FAILURE(status)) { return macros; }
 
             // Consume the segment:
             segment.adjustOffset(offset);
@@ -439,6 +457,8 @@ skeleton::parseStem(const StringSegment& segment, const UCharsTrie& stemTrie, Se
         CHECK_NULL(seen, rounder, status);
             blueprint_helpers::parseDigitsStem(segment, macros, status);
             return STATE_NULL;
+        default:
+            break;
     }
 
     // Now look at the stemsTrie, which is already be pointing at our stem.
@@ -706,6 +726,461 @@ void GeneratorHelpers::generateSkeleton(const MacroProps& macros, UnicodeString&
 }
 
 
+bool blueprint_helpers::parseExponentWidthOption(const StringSegment& segment, MacroProps& macros,
+                                                 UErrorCode&) {
+    if (segment.charAt(0) != u'+') {
+        return false;
+    }
+    int32_t offset = 1;
+    int32_t minExp = 0;
+    for (; offset < segment.length(); offset++) {
+        if (segment.charAt(offset) == u'e') {
+            minExp++;
+        } else {
+            break;
+        }
+    }
+    if (offset < segment.length()) {
+        return false;
+    }
+    // Use the public APIs to enforce bounds checking
+    macros.notation = static_cast<ScientificNotation&>(macros.notation).withMinExponentDigits(minExp);
+    return true;
+}
+
+void
+blueprint_helpers::generateExponentWidthOption(int32_t minExponentDigits, UnicodeString& sb, UErrorCode&) {
+    sb.append(u'+');
+    appendMultiple(sb, u'e', minExponentDigits);
+}
+
+bool
+blueprint_helpers::parseExponentSignOption(const StringSegment& segment, MacroProps& macros, UErrorCode&) {
+    // Get the sign display type out of the CharsTrie data structure.
+    UCharsTrie tempStemTrie(kSerializedStemTrie);
+    UStringTrieResult result = tempStemTrie.next(segment.toUnicodeString().getBuffer(), segment.length());
+    if (result != USTRINGTRIE_INTERMEDIATE_VALUE && result != USTRINGTRIE_FINAL_VALUE) {
+        return false;
+    }
+    auto sign = stem_to_object::signDisplay(static_cast<StemEnum>(tempStemTrie.getValue()));
+    if (sign == UNUM_SIGN_COUNT) {
+        return false;
+    }
+    macros.notation = static_cast<ScientificNotation&>(macros.notation).withExponentSignDisplay(sign);
+    return true;
+}
+
+void blueprint_helpers::parseCurrencyOption(const StringSegment& segment, MacroProps& macros,
+                                            UErrorCode& status) {
+    if (segment.length() != 3) {
+        // throw new SkeletonSyntaxException("Invalid currency", segment);
+        status = U_NUMBER_SKELETON_SYNTAX_ERROR;
+        return;
+    }
+    const UChar* currencyCode = segment.toUnicodeString().getTerminatedBuffer();
+    // Check that the currency code is valid:
+    int32_t numericCode = ucurr_getNumericCode(currencyCode);
+    if (numericCode == 0) {
+        // throw new SkeletonSyntaxException("Invalid currency", segment);
+        status = U_NUMBER_SKELETON_SYNTAX_ERROR;
+        return;
+    }
+    // Slicing is OK
+    macros.unit = CurrencyUnit(currencyCode, status); // NOLINT
+}
+
+void
+blueprint_helpers::generateCurrencyOption(const CurrencyUnit& currency, UnicodeString& sb, UErrorCode&) {
+    sb.append(currency.getISOCurrency(), -1);
+}
+
+void blueprint_helpers::parseMeasureUnitOption(const StringSegment& segment, MacroProps& macros,
+                                               UErrorCode& status) {
+    // NOTE: The category (type) of the unit is guaranteed to be a valid subtag (alphanumeric)
+    // http://unicode.org/reports/tr35/#Validity_Data
+    int firstHyphen = 0;
+    while (firstHyphen < segment.length() && segment.charAt(firstHyphen) != '-') {
+        firstHyphen++;
+    }
+    if (firstHyphen == segment.length()) {
+        // throw new SkeletonSyntaxException("Invalid measure unit option", segment);
+        status = U_NUMBER_SKELETON_SYNTAX_ERROR;
+        return;
+    }
+
+    // MeasureUnit is in char space; we need to convert.
+    // Note: the longest type/subtype as of this writing (March 2018) is 24 chars.
+    static constexpr int32_t CAPACITY = 30;
+    char type[CAPACITY];
+    char subType[CAPACITY];
+    const int32_t typeLen = firstHyphen;
+    const int32_t subTypeLen = segment.length() - firstHyphen - 1;
+    if (typeLen + 1 > CAPACITY || subTypeLen + 1 > CAPACITY) {
+        // Type or subtype longer than 30?
+        // The capacity should be increased if this is a problem with a real CLDR unit.
+        status = U_NUMBER_SKELETON_SYNTAX_ERROR;
+        return;
+    }
+    u_UCharsToChars(segment.toUnicodeString().getBuffer(), type, typeLen);
+    u_UCharsToChars(segment.toUnicodeString().getBuffer() + firstHyphen + 1, subType, subTypeLen);
+    type[typeLen] = 0;
+    subType[subTypeLen] = 0;
+
+    // Note: the largest type as of this writing (March 2018) is "volume", which has 24 units.
+    MeasureUnit units[30];
+    UErrorCode localStatus = U_ZERO_ERROR;
+    int32_t numUnits = MeasureUnit::getAvailable(type, units, 30, localStatus);
+    if (U_FAILURE(localStatus)) {
+        // More than 30 units in this type?
+        status = U_NUMBER_SKELETON_SYNTAX_ERROR;
+        return;
+    }
+    for (int32_t i = 0; i < numUnits; i++) {
+        auto& unit = units[i];
+        if (uprv_strcmp(subType, unit.getSubtype()) == 0) {
+            macros.unit = unit;
+            return;
+        }
+    }
+
+    // throw new SkeletonSyntaxException("Unknown measure unit", segment);
+    status = U_NUMBER_SKELETON_SYNTAX_ERROR;
+}
+
+void blueprint_helpers::generateMeasureUnitOption(const MeasureUnit& measureUnit, UnicodeString& sb,
+                                                  UErrorCode& status) {
+    // We need to convert from char* to UChar*...
+    // See comments in the previous function about the capacity setting.
+    static constexpr int32_t CAPACITY = 30;
+    char16_t type16[CAPACITY];
+    char16_t subType16[CAPACITY];
+    const auto typeLen = static_cast<int32_t>(uprv_strlen(measureUnit.getType()));
+    const auto subTypeLen = static_cast<int32_t>(uprv_strlen(measureUnit.getSubtype()));
+    if (typeLen + 1 > CAPACITY || subTypeLen + 1 > CAPACITY) {
+        // Type or subtype longer than 30?
+        // The capacity should be increased if this is a problem with a real CLDR unit.
+        status = U_UNSUPPORTED_ERROR;
+        return;
+    }
+    u_charsToUChars(measureUnit.getType(), type16, typeLen);
+    u_charsToUChars(measureUnit.getSubtype(), subType16, subTypeLen);
+
+    sb.append(type16, typeLen);
+    sb.append(u'-');
+    sb.append(subType16, subTypeLen);
+}
+
+void blueprint_helpers::parseMeasurePerUnitOption(const StringSegment& segment, MacroProps& macros,
+                                                  UErrorCode& status) {
+    // A little bit of a hack: safe the current unit (numerator), call the main measure unit
+    // parsing code, put back the numerator unit, and put the new unit into per-unit.
+    MeasureUnit numerator = macros.unit;
+    parseMeasureUnitOption(segment, macros, status);
+    macros.perUnit = macros.unit;
+    macros.unit = numerator;
+}
+
+void blueprint_helpers::parseFractionStem(const StringSegment& segment, MacroProps& macros,
+                                          UErrorCode& status) {
+    U_ASSERT(segment.charAt(0) == u'.');
+    int32_t offset = 1;
+    int32_t minFrac = 0;
+    int32_t maxFrac;
+    for (; offset < segment.length(); offset++) {
+        if (segment.charAt(offset) == u'0') {
+            minFrac++;
+        } else {
+            break;
+        }
+    }
+    if (offset < segment.length()) {
+        if (segment.charAt(offset) == u'+') {
+            maxFrac = -1;
+            offset++;
+        } else {
+            maxFrac = minFrac;
+            for (; offset < segment.length(); offset++) {
+                if (segment.charAt(offset) == u'#') {
+                    maxFrac++;
+                } else {
+                    break;
+                }
+            }
+        }
+    } else {
+        maxFrac = minFrac;
+    }
+    if (offset < segment.length()) {
+        // throw new SkeletonSyntaxException("Invalid fraction stem", segment);
+        status = U_NUMBER_SKELETON_SYNTAX_ERROR;
+        return;
+    }
+    // Use the public APIs to enforce bounds checking
+    if (maxFrac == -1) {
+        macros.rounder = Rounder::minFraction(minFrac);
+    } else {
+        macros.rounder = Rounder::minMaxFraction(minFrac, maxFrac);
+    }
+}
+
+void
+blueprint_helpers::generateFractionStem(int32_t minFrac, int32_t maxFrac, UnicodeString& sb, UErrorCode&) {
+    if (minFrac == 0 && maxFrac == 0) {
+        sb.append(u"round-integer", -1);
+        return;
+    }
+    sb.append(u'.');
+    appendMultiple(sb, u'0', minFrac);
+    if (maxFrac == -1) {
+        sb.append(u'+');
+    } else {
+        appendMultiple(sb, u'#', maxFrac - minFrac);
+    }
+}
+
+void
+blueprint_helpers::parseDigitsStem(const StringSegment& segment, MacroProps& macros, UErrorCode& status) {
+    U_ASSERT(segment.charAt(0) == u'@');
+    int offset = 0;
+    int minSig = 0;
+    int maxSig;
+    for (; offset < segment.length(); offset++) {
+        if (segment.charAt(offset) == u'@') {
+            minSig++;
+        } else {
+            break;
+        }
+    }
+    if (offset < segment.length()) {
+        if (segment.charAt(offset) == u'+') {
+            maxSig = -1;
+            offset++;
+        } else {
+            maxSig = minSig;
+            for (; offset < segment.length(); offset++) {
+                if (segment.charAt(offset) == u'#') {
+                    maxSig++;
+                } else {
+                    break;
+                }
+            }
+        }
+    } else {
+        maxSig = minSig;
+    }
+    if (offset < segment.length()) {
+        // throw new SkeletonSyntaxException("Invalid significant digits stem", segment);
+        status = U_NUMBER_SKELETON_SYNTAX_ERROR;
+    }
+    // Use the public APIs to enforce bounds checking
+    if (maxSig == -1) {
+        macros.rounder = Rounder::minDigits(minSig);
+    } else {
+        macros.rounder = Rounder::minMaxDigits(minSig, maxSig);
+    }
+}
+
+void
+blueprint_helpers::generateDigitsStem(int32_t minSig, int32_t maxSig, UnicodeString& sb, UErrorCode&) {
+    appendMultiple(sb, u'@', minSig);
+    if (maxSig == -1) {
+        sb.append(u'+');
+    } else {
+        appendMultiple(sb, u'#', maxSig - minSig);
+    }
+}
+
+bool blueprint_helpers::parseFracSigOption(const StringSegment& segment, MacroProps& macros,
+                                           UErrorCode& status) {
+    if (segment.charAt(0) != u'@') {
+        return false;
+    }
+    int offset = 0;
+    int minSig = 0;
+    int maxSig;
+    for (; offset < segment.length(); offset++) {
+        if (segment.charAt(offset) == u'@') {
+            minSig++;
+        } else {
+            break;
+        }
+    }
+    // For the frac-sig option, there must be minSig or maxSig but not both.
+    // Valid: @+, @@+, @@@+
+    // Valid: @#, @##, @###
+    // Invalid: @, @@, @@@
+    // Invalid: @@#, @@##, @@@#
+    if (offset < segment.length()) {
+        if (segment.charAt(offset) == u'+') {
+            maxSig = -1;
+            offset++;
+        } else if (minSig > 1) {
+            // @@#, @@##, @@@#
+            // throw new SkeletonSyntaxException("Invalid digits option for fraction rounder", segment);
+            status = U_NUMBER_SKELETON_SYNTAX_ERROR;
+            return false;
+        } else {
+            maxSig = minSig;
+            for (; offset < segment.length(); offset++) {
+                if (segment.charAt(offset) == u'#') {
+                    maxSig++;
+                } else {
+                    break;
+                }
+            }
+        }
+    } else {
+        // @, @@, @@@
+        // throw new SkeletonSyntaxException("Invalid digits option for fraction rounder", segment);
+        status = U_NUMBER_SKELETON_SYNTAX_ERROR;
+        return false;
+    }
+    if (offset < segment.length()) {
+        // throw new SkeletonSyntaxException("Invalid digits option for fraction rounder", segment);
+        status = U_NUMBER_SKELETON_SYNTAX_ERROR;
+        return false;
+    }
+
+    auto& oldRounder = static_cast<const FractionRounder&>(macros.rounder);
+    if (maxSig == -1) {
+        macros.rounder = oldRounder.withMinDigits(minSig);
+    } else {
+        macros.rounder = oldRounder.withMaxDigits(maxSig);
+    }
+    return true;
+}
+
+void blueprint_helpers::parseIncrementOption(const StringSegment& segment, MacroProps& macros,
+                                             UErrorCode& status) {
+    // Utilize DecimalQuantity/decNumber to parse this for us.
+    static constexpr int32_t CAPACITY = 30;
+    char buffer[CAPACITY];
+    if (segment.length() > CAPACITY) {
+        // No support for numbers this long; they won't fit in a double anyway.
+        status = U_NUMBER_SKELETON_SYNTAX_ERROR;
+        return;
+    }
+    u_UCharsToChars(segment.toUnicodeString().getBuffer(), buffer, segment.length());
+    DecimalQuantity dq;
+    dq.setToDecNumber({buffer, segment.length()});
+    double increment = dq.toDouble();
+    macros.rounder = Rounder::increment(increment);
+}
+
+void blueprint_helpers::generateIncrementOption(double increment, UnicodeString& sb, UErrorCode&) {
+    // Utilize DecimalQuantity/double_conversion to format this for us.
+    DecimalQuantity dq;
+    dq.setToDouble(increment);
+    dq.roundToInfinity();
+    sb.append(dq.toPlainString());
+}
+
+bool
+blueprint_helpers::parseRoundingModeOption(const StringSegment& segment, MacroProps& macros, UErrorCode&) {
+    for (int rm = 0; rm < kRoundingModeCount; rm++) {
+        if (segment == UnicodeString(kRoundingModeStrings[rm], -1)) {
+            macros.rounder = macros.rounder.withMode(static_cast<RoundingMode>(rm));
+            return true;
+        }
+    }
+    return false;
+}
+
+void blueprint_helpers::generateRoundingModeOption(RoundingMode mode, UnicodeString& sb, UErrorCode&) {
+    sb.append(kRoundingModeStrings[mode], -1);
+}
+
+void blueprint_helpers::parseIntegerWidthOption(const StringSegment& segment, MacroProps& macros,
+                                                UErrorCode& status) {
+    int32_t offset = 0;
+    int32_t minInt = 0;
+    int32_t maxInt;
+    if (segment.charAt(0) == u'+') {
+        maxInt = -1;
+        offset++;
+    } else {
+        maxInt = 0;
+    }
+    for (; offset < segment.length(); offset++) {
+        if (segment.charAt(offset) == u'#') {
+            maxInt++;
+        } else {
+            break;
+        }
+    }
+    if (offset < segment.length()) {
+        for (; offset < segment.length(); offset++) {
+            if (segment.charAt(offset) == u'0') {
+                minInt++;
+            } else {
+                break;
+            }
+        }
+    }
+    if (maxInt != -1) {
+        maxInt += minInt;
+    }
+    if (offset < segment.length()) {
+        // throw new SkeletonSyntaxException("Invalid integer width stem", segment);
+        status = U_NUMBER_SKELETON_SYNTAX_ERROR;
+        return;
+    }
+    // Use the public APIs to enforce bounds checking
+    if (maxInt == -1) {
+        macros.integerWidth = IntegerWidth::zeroFillTo(minInt);
+    } else {
+        macros.integerWidth = IntegerWidth::zeroFillTo(minInt).truncateAt(maxInt);
+    }
+}
+
+void blueprint_helpers::generateIntegerWidthOption(int32_t minInt, int32_t maxInt, UnicodeString& sb,
+                                                   UErrorCode&) {
+    if (maxInt == -1) {
+        sb.append(u'+');
+    } else {
+        appendMultiple(sb, u'#', maxInt - minInt);
+    }
+    appendMultiple(sb, u'0', minInt);
+}
+
+void blueprint_helpers::parseNumberingSystemOption(const StringSegment& segment, MacroProps& macros,
+                                                   UErrorCode& status) {
+    // Need to do char <-> UChar conversion...
+    static constexpr int32_t CAPACITY = 30;
+    char buffer[CAPACITY];
+    if (segment.length() + 1 > CAPACITY) {
+        // No support for numbers this long; they won't fit in a double anyway.
+        status = U_NUMBER_SKELETON_SYNTAX_ERROR;
+        return;
+    }
+    u_UCharsToChars(segment.toUnicodeString().getBuffer(), buffer, segment.length());
+    buffer[segment.length()] = 0;
+
+    NumberingSystem* ns = NumberingSystem::createInstanceByName(buffer, status);
+    if (ns == nullptr) {
+        // throw new SkeletonSyntaxException("Unknown numbering system", segment);
+        status = U_NUMBER_SKELETON_SYNTAX_ERROR;
+        return;
+    }
+    macros.symbols.setTo(ns);
+}
+
+void blueprint_helpers::generateNumberingSystemOption(const NumberingSystem& ns, UnicodeString& sb,
+                                                      UErrorCode& status) {
+    // Need to do char <-> UChar conversion...
+    static constexpr int32_t CAPACITY = 30;
+    char16_t buffer16[CAPACITY];
+    const auto len = static_cast<int32_t>(uprv_strlen(ns.getName()));
+    if (len > CAPACITY) {
+        // No support for numbers this long; they won't fit in a double anyway.
+        status = U_UNSUPPORTED_ERROR;
+        return;
+    }
+    u_charsToUChars(ns.getName(), buffer16, len);
+    sb.append(buffer16, len);
+}
+
+
 bool GeneratorHelpers::notation(const MacroProps& macros, UnicodeString& sb, UErrorCode& status) {
     if (macros.notation.fType == Notation::NTN_COMPACT) {
         UNumberCompactStyle style = macros.notation.fUnion.compactStyle;
@@ -770,6 +1245,7 @@ bool GeneratorHelpers::perUnit(const MacroProps& macros, UnicodeString& sb, UErr
     // Per-units are currently expected to be only MeasureUnits.
     if (unitIsCurrency(macros.perUnit) || unitIsNoUnit(macros.perUnit)) {
         status = U_UNSUPPORTED_ERROR;
+        return false;
     } else {
         sb.append(u"per-measure-unit/", -1);
         blueprint_helpers::generateMeasureUnitOption(macros.perUnit, sb, status);
@@ -824,10 +1300,12 @@ bool GeneratorHelpers::rounding(const MacroProps& macros, UnicodeString& sb, UEr
 bool GeneratorHelpers::grouping(const MacroProps& macros, UnicodeString& sb, UErrorCode& status) {
     if (macros.grouper.isBogus() || macros.grouper.fStrategy == UNUM_GROUPING_COUNT) {
         status = U_UNSUPPORTED_ERROR;
+        return false;
     } else if (macros.grouper.fStrategy == UNUM_GROUPING_AUTO) {
         return false; // Default value
     } else {
         enum_to_stem_string::groupingStrategy(macros.grouper.fStrategy, sb);
+        return true;
     }
 }
 
@@ -864,7 +1342,7 @@ bool GeneratorHelpers::symbols(const MacroProps& macros, UnicodeString& sb, UErr
     }
 }
 
-bool GeneratorHelpers::unitWidth(const MacroProps& macros, UnicodeString& sb, UErrorCode& status) {
+bool GeneratorHelpers::unitWidth(const MacroProps& macros, UnicodeString& sb, UErrorCode&) {
     if (macros.unitWidth == UNUM_UNIT_WIDTH_SHORT || macros.unitWidth == UNUM_UNIT_WIDTH_COUNT) {
         return false; // Default or Bogus
     }
@@ -872,7 +1350,7 @@ bool GeneratorHelpers::unitWidth(const MacroProps& macros, UnicodeString& sb, UE
     return true;
 }
 
-bool GeneratorHelpers::sign(const MacroProps& macros, UnicodeString& sb, UErrorCode& status) {
+bool GeneratorHelpers::sign(const MacroProps& macros, UnicodeString& sb, UErrorCode&) {
     if (macros.sign == UNUM_SIGN_AUTO || macros.sign == UNUM_SIGN_COUNT) {
         return false; // Default or Bogus
     }
@@ -880,7 +1358,7 @@ bool GeneratorHelpers::sign(const MacroProps& macros, UnicodeString& sb, UErrorC
     return true;
 }
 
-bool GeneratorHelpers::decimal(const MacroProps& macros, UnicodeString& sb, UErrorCode& status) {
+bool GeneratorHelpers::decimal(const MacroProps& macros, UnicodeString& sb, UErrorCode&) {
     if (macros.decimal == UNUM_DECIMAL_SEPARATOR_AUTO || macros.decimal == UNUM_DECIMAL_SEPARATOR_COUNT) {
         return false; // Default or Bogus
     }
index 843f1390af4e4c5204809e566f9e84e29bf29536..e874d6acc33e26d05baa0044d4683938621f2d08 100644 (file)
@@ -192,7 +192,7 @@ namespace blueprint_helpers {
 /** @return Whether we successfully found and parsed an exponent width option. */
 bool parseExponentWidthOption(const StringSegment& segment, MacroProps& macros, UErrorCode& status);
 
-void generateExponentWidthOption(int32_t xyz, UnicodeString& sb, UErrorCode& status);
+void generateExponentWidthOption(int32_t minExponentDigits, UnicodeString& sb, UErrorCode& status);
 
 /** @return Whether we successfully found and parsed an exponent sign option. */
 bool parseExponentSignOption(const StringSegment& segment, MacroProps& macros, UErrorCode& status);
@@ -225,7 +225,7 @@ void generateIncrementOption(double increment, UnicodeString& sb, UErrorCode& st
 /** @return Whether we successfully found and parsed a rounding mode. */
 bool parseRoundingModeOption(const StringSegment& segment, MacroProps& macros, UErrorCode& status);
 
-void generateRoundingModeOption(RoundingMode, UnicodeString& sb, UErrorCode& status);
+void generateRoundingModeOption(RoundingMode mode, UnicodeString& sb, UErrorCode& status);
 
 void parseIntegerWidthOption(const StringSegment& segment, MacroProps& macros, UErrorCode& status);
 
index e3bdc68c25bf36e5bf01e28e6cd8fd00cadd92f0..aa8e62beefb4b2e4b895187e41ca56e99b64a930 100644 (file)
@@ -61,7 +61,8 @@ UChar32 StringSegment::codePointAt(int32_t index) const {
 }
 
 UnicodeString StringSegment::toUnicodeString() const {
-    return UnicodeString(fStr, fStart, fEnd - fStart);
+    // Use the readonly-aliasing constructor for efficiency.
+    return UnicodeString(FALSE, fStr.getBuffer() + fStart, fEnd - fStart);
 }
 
 UChar32 StringSegment::getCodePoint() const {
index dc831d2dd5c6e238a75ed2a824ac205e44d6b10e..6b8d77c9ac829ef25725f7111ec414da26c9b3d7 100644 (file)
@@ -884,13 +884,14 @@ class NumberSkeletonImpl {
         }
 
         private static void generateMeasureUnitOption(MeasureUnit unit, StringBuilder sb) {
-            sb.append(unit.getType() + "-" + unit.getSubtype());
+            sb.append(unit.getType());
+            sb.append("-");
+            sb.append(unit.getSubtype());
         }
 
         private static void parseMeasurePerUnitOption(StringSegment segment, MacroProps macros) {
             // A little bit of a hack: safe the current unit (numerator), call the main measure unit
-            // parsing
-            // code, put back the numerator unit, and put the new unit into per-unit.
+            // parsing code, put back the numerator unit, and put the new unit into per-unit.
             MeasureUnit numerator = macros.unit;
             parseMeasureUnitOption(segment, macros);
             macros.perUnit = macros.unit;
@@ -1083,8 +1084,7 @@ class NumberSkeletonImpl {
         }
 
         private static void generateRoundingModeOption(RoundingMode mode, StringBuilder sb) {
-            String option = ROUNDING_MODE_STRINGS[mode.ordinal()];
-            sb.append(option);
+            sb.append(ROUNDING_MODE_STRINGS[mode.ordinal()]);
         }
 
         private static void parseIntegerWidthOption(StringSegment segment, MacroProps macros) {