// Initializes this with the decimal format symbols in the default locale.
DecimalFormatSymbols::DecimalFormatSymbols(UErrorCode& status)
- : UObject(), locale(), currPattern(NULL) {
+ : UObject(), locale() {
initialize(locale, status, true);
}
// Initializes this with the decimal format symbols in the desired locale.
DecimalFormatSymbols::DecimalFormatSymbols(const Locale& loc, UErrorCode& status)
- : UObject(), locale(loc), currPattern(NULL) {
+ : UObject(), locale(loc) {
initialize(locale, status);
}
DecimalFormatSymbols::DecimalFormatSymbols(const Locale& loc, const NumberingSystem& ns, UErrorCode& status)
- : UObject(), locale(loc), currPattern(NULL) {
+ : UObject(), locale(loc) {
initialize(locale, status, false, &ns);
}
DecimalFormatSymbols::DecimalFormatSymbols()
- : UObject(), locale(Locale::getRoot()), currPattern(NULL) {
+ : UObject(), locale(Locale::getRoot()) {
*validLocale = *actualLocale = 0;
initialize();
}
fIsCustomIntlCurrencySymbol = rhs.fIsCustomIntlCurrencySymbol;
fCodePointZero = rhs.fCodePointZero;
currPattern = rhs.currPattern;
+ uprv_strcpy(nsName, rhs.nsName);
}
return *this;
}
} else {
nsName = gLatn;
}
+ uprv_strcpy(this->nsName, nsName);
// Open resource bundles
const char* locStr = loc.getName();
fCodePointZero = 0x30;
U_ASSERT(fCodePointZero == fSymbols[kZeroDigitSymbol].char32At(0));
currPattern = nullptr;
-
+ nsName[0] = 0;
}
void DecimalFormatSymbols::setCurrency(const UChar* currency, UErrorCode& status) {
virtual ~FormattedValueStringBuilderImpl();
+ FormattedValueStringBuilderImpl(FormattedValueStringBuilderImpl&&) = default;
+ FormattedValueStringBuilderImpl& operator=(FormattedValueStringBuilderImpl&&) = default;
+
// Implementation of FormattedValue (const):
UnicodeString toString(UErrorCode& status) const U_OVERRIDE;
<ClCompile Include="number_mapper.cpp" />
<ClCompile Include="number_multiplier.cpp" />
<ClCompile Include="number_currencysymbols.cpp" />
+ <ClCompile Include="number_simple.cpp" />
<ClCompile Include="number_skeletons.cpp" />
<ClCompile Include="number_symbolswrapper.cpp" />
<ClCompile Include="number_capi.cpp" />
<ClCompile Include="number_currencysymbols.cpp">
<Filter>formatting</Filter>
</ClCompile>
+ <ClCompile Include="number_simple.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
<ClCompile Include="number_skeletons.cpp">
<Filter>formatting</Filter>
</ClCompile>
<ClCompile Include="number_mapper.cpp" />
<ClCompile Include="number_multiplier.cpp" />
<ClCompile Include="number_currencysymbols.cpp" />
+ <ClCompile Include="number_simple.cpp" />
<ClCompile Include="number_skeletons.cpp" />
<ClCompile Include="number_symbolswrapper.cpp" />
<ClCompile Include="number_capi.cpp" />
#include "number_decnum.h"
#include "unicode/numberformatter.h"
#include "unicode/unumberformatter.h"
+#include "unicode/simplenumberformatter.h"
+#include "unicode/usimplenumberformatter.h"
using namespace icu;
using namespace icu::number;
LocalizedNumberFormatter fFormatter;
};
+/**
+ * Implementation class for USimpleNumber. Wraps a SimpleNumberFormatter.
+ */
+struct USimpleNumberData : public UMemory,
+ // Magic number as ASCII == "SNM" (SimpleNuMber)
+ public IcuCApiHelper<USimpleNumber, USimpleNumberData, 0x534E4D00> {
+ SimpleNumber fNumber;
+};
+
+/**
+ * Implementation class for USimpleNumberFormatter. Wraps a SimpleNumberFormatter.
+ */
+struct USimpleNumberFormatterData : public UMemory,
+ // Magic number as ASCII == "SNF" (SimpleNumberFormatter)
+ public IcuCApiHelper<USimpleNumberFormatter, USimpleNumberFormatterData, 0x534E4600> {
+ SimpleNumberFormatter fFormatter;
+};
+
struct UFormattedNumberImpl;
// Magic number as ASCII == "FDN" (FormatteDNumber)
FormattedNumber fImpl;
UFormattedNumberData fData;
+
+ void setTo(FormattedNumber value);
};
UFormattedNumberImpl::UFormattedNumberImpl()
fImpl.fData = nullptr;
}
+void UFormattedNumberImpl::setTo(FormattedNumber value) {
+ fData = std::move(*value.fData);
+}
+
}
}
U_NAMESPACE_END
}
+///// SIMPLE NUMBER FORMATTER /////
+
+U_CAPI USimpleNumber* U_EXPORT2
+usnum_openForInt64(int64_t value, UErrorCode* ec) {
+ auto* impl = new USimpleNumberData();
+ if (impl == nullptr) {
+ *ec = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
+ impl->fNumber = SimpleNumber::forInt64(value, *ec);
+ return impl->exportForC();
+}
+
+U_CAPI void U_EXPORT2
+usnum_multiplyByPowerOfTen(USimpleNumber* unumber, int32_t power, UErrorCode* ec) {
+ auto* number = USimpleNumberData::validate(unumber, *ec);
+ if (U_FAILURE(*ec)) {
+ return;
+ }
+ number->fNumber.multiplyByPowerOfTen(power, *ec);
+}
+
+U_CAPI void U_EXPORT2
+usnum_roundTo(USimpleNumber* unumber, int32_t position, UNumberFormatRoundingMode roundingMode, UErrorCode* ec) {
+ auto* number = USimpleNumberData::validate(unumber, *ec);
+ if (U_FAILURE(*ec)) {
+ return;
+ }
+ number->fNumber.roundTo(position, roundingMode, *ec);
+}
+
+U_CAPI void U_EXPORT2
+usnum_setMinimumIntegerDigits(USimpleNumber* unumber, int32_t minimumIntegerDigits, UErrorCode* ec) {
+ auto* number = USimpleNumberData::validate(unumber, *ec);
+ if (U_FAILURE(*ec)) {
+ return;
+ }
+ number->fNumber.setMinimumIntegerDigits(minimumIntegerDigits, *ec);
+}
+
+U_CAPI void U_EXPORT2
+usnum_setMinimumFractionDigits(USimpleNumber* unumber, int32_t minimumFractionDigits, UErrorCode* ec) {
+ auto* number = USimpleNumberData::validate(unumber, *ec);
+ if (U_FAILURE(*ec)) {
+ return;
+ }
+ number->fNumber.setMinimumFractionDigits(minimumFractionDigits, *ec);
+}
+
+U_CAPI void U_EXPORT2
+usnum_truncateStart(USimpleNumber* unumber, int32_t maximumIntegerDigits, UErrorCode* ec) {
+ auto* number = USimpleNumberData::validate(unumber, *ec);
+ if (U_FAILURE(*ec)) {
+ return;
+ }
+ number->fNumber.truncateStart(maximumIntegerDigits, *ec);
+}
+
+U_CAPI void U_EXPORT2
+usnum_setSign(USimpleNumber* unumber, USimpleNumberSign sign, UErrorCode* ec) {
+ auto* number = USimpleNumberData::validate(unumber, *ec);
+ if (U_FAILURE(*ec)) {
+ return;
+ }
+ number->fNumber.setSign(sign, *ec);
+}
+
+U_CAPI USimpleNumberFormatter* U_EXPORT2
+usnumf_openForLocale(const char* locale, UErrorCode* ec) {
+ auto* impl = new USimpleNumberFormatterData();
+ if (impl == nullptr) {
+ *ec = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
+ impl->fFormatter = SimpleNumberFormatter::forLocale(locale, *ec);
+ return impl->exportForC();
+}
+
+U_CAPI USimpleNumberFormatter* U_EXPORT2
+usnumf_openForLocaleAndGroupingStrategy(
+ const char* locale, UNumberGroupingStrategy groupingStrategy, UErrorCode* ec) {
+ auto* impl = new USimpleNumberFormatterData();
+ if (impl == nullptr) {
+ *ec = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
+ impl->fFormatter = SimpleNumberFormatter::forLocaleAndGroupingStrategy(locale, groupingStrategy, *ec);
+ return impl->exportForC();
+}
+
+U_CAPI void U_EXPORT2
+usnumf_formatAndAdoptNumber(
+ const USimpleNumberFormatter* uformatter,
+ USimpleNumber* unumber,
+ UFormattedNumber* uresult,
+ UErrorCode* ec) {
+ auto* formatter = USimpleNumberFormatterData::validate(uformatter, *ec);
+ auto* number = USimpleNumberData::validate(unumber, *ec);
+ auto* result = UFormattedNumberApiHelper::validate(uresult, *ec);
+ if (U_FAILURE(*ec)) {
+ delete number;
+ return;
+ }
+ auto localResult = formatter->fFormatter.format(std::move(number->fNumber), *ec);
+ result->setTo(std::move(localResult));
+ delete number;
+}
+
+U_CAPI void U_EXPORT2
+usnumf_formatInt64(
+ const USimpleNumberFormatter* uformatter,
+ int64_t value,
+ UFormattedNumber* uresult,
+ UErrorCode* ec) {
+ auto* formatter = USimpleNumberFormatterData::validate(uformatter, *ec);
+ auto* result = UFormattedNumberApiHelper::validate(uresult, *ec);
+ if (U_FAILURE(*ec)) {
+ return;
+ }
+ auto localResult = formatter->fFormatter.formatInt64(value, *ec);
+ result->setTo(std::move(localResult));
+}
+
+U_CAPI void U_EXPORT2
+usnum_close(USimpleNumber* unumber) {
+ UErrorCode localStatus = U_ZERO_ERROR;
+ const USimpleNumberData* impl = USimpleNumberData::validate(unumber, localStatus);
+ delete impl;
+}
+
+U_CAPI void U_EXPORT2
+usnumf_close(USimpleNumberFormatter* uformatter) {
+ UErrorCode localStatus = U_ZERO_ERROR;
+ const USimpleNumberFormatterData* impl = USimpleNumberFormatterData::validate(uformatter, localStatus);
+ delete impl;
+}
+
+
#endif /* #if !UCONFIG_NO_FORMATTING */
NumberFormatterImpl impl(macros, false, status);
MicroProps& micros = impl.preProcessUnsafe(inValue, status);
if (U_FAILURE(status)) { return 0; }
- int32_t length = writeNumber(micros, inValue, outString, 0, status);
+ int32_t length = writeNumber(micros.simple, inValue, outString, 0, status);
length += writeAffixes(micros, outString, 0, length, status);
results->outputUnit = std::move(micros.outputUnit);
results->gender = micros.gender;
MicroProps micros;
preProcess(inValue, micros, status);
if (U_FAILURE(status)) { return 0; }
- int32_t length = writeNumber(micros, inValue, outString, 0, status);
+ int32_t length = writeNumber(micros.simple, inValue, outString, 0, status);
length += writeAffixes(micros, outString, 0, length, status);
results->outputUnit = std::move(micros.outputUnit);
results->gender = micros.gender;
// Resolve the symbols. Do this here because currency may need to customize them.
if (macros.symbols.isDecimalFormatSymbols()) {
- fMicros.symbols = macros.symbols.getDecimalFormatSymbols();
+ fMicros.simple.symbols = macros.symbols.getDecimalFormatSymbols();
} else {
LocalPointer<DecimalFormatSymbols> newSymbols(
new DecimalFormatSymbols(macros.locale, *ns, status), status);
return nullptr;
}
}
- fMicros.symbols = newSymbols.getAlias();
+ fMicros.simple.symbols = newSymbols.getAlias();
fSymbols.adoptInstead(newSymbols.orphan());
}
// Load and parse the pattern string. It is used for grouping sizes and affixes only.
// If we are formatting currency, check for a currency-specific pattern.
const char16_t* pattern = nullptr;
- if (isCurrency && fMicros.symbols->getCurrencyPattern() != nullptr) {
- pattern = fMicros.symbols->getCurrencyPattern();
+ if (isCurrency && fMicros.simple.symbols->getCurrencyPattern() != nullptr) {
+ pattern = fMicros.simple.symbols->getCurrencyPattern();
}
if (pattern == nullptr) {
CldrPatternStyle patternStyle;
// Grouping strategy
if (!macros.grouper.isBogus()) {
- fMicros.grouping = macros.grouper;
+ fMicros.simple.grouping = macros.grouper;
} else if (isCompactNotation) {
// Compact notation uses minGrouping by default since ICU 59
- fMicros.grouping = Grouper::forStrategy(UNUM_GROUPING_MIN2);
+ fMicros.simple.grouping = Grouper::forStrategy(UNUM_GROUPING_MIN2);
} else {
- fMicros.grouping = Grouper::forStrategy(UNUM_GROUPING_AUTO);
+ fMicros.simple.grouping = Grouper::forStrategy(UNUM_GROUPING_AUTO);
}
- fMicros.grouping.setLocaleData(*fPatternInfo, macros.locale);
+ fMicros.simple.grouping.setLocaleData(*fPatternInfo, macros.locale);
// Padding strategy
if (!macros.padder.isBogus()) {
// Decimal mark display
if (macros.decimal != UNUM_DECIMAL_SEPARATOR_COUNT) {
- fMicros.decimal = macros.decimal;
+ fMicros.simple.decimal = macros.decimal;
} else {
- fMicros.decimal = UNUM_DECIMAL_SEPARATOR_AUTO;
+ fMicros.simple.decimal = UNUM_DECIMAL_SEPARATOR_AUTO;
}
// Use monetary separator symbols
- fMicros.useCurrency = isCurrency;
+ fMicros.simple.useCurrency = isCurrency;
// Inner modifier (scientific notation)
if (macros.notation.fType == Notation::NTN_SCIENTIFIC) {
- auto newScientificHandler = new ScientificHandler(¯os.notation, fMicros.symbols, chain);
+ auto newScientificHandler = new ScientificHandler(¯os.notation, fMicros.simple.symbols, chain);
if (newScientificHandler == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
return nullptr;
patternModifier->setPatternAttributes(fMicros.sign, isPermille, macros.approximately);
if (patternModifier->needsPlurals()) {
patternModifier->setSymbols(
- fMicros.symbols,
+ fMicros.simple.symbols,
currency,
unitWidth,
resolvePluralRules(macros.rules, macros.locale, status),
status);
} else {
- patternModifier->setSymbols(fMicros.symbols, currency, unitWidth, nullptr, status);
+ patternModifier->setSymbols(fMicros.simple.symbols, currency, unitWidth, nullptr, status);
}
if (safe) {
fImmutablePatternModifier.adoptInsteadAndCheckErrorCode(patternModifier->createImmutable(status),
// currencyAsDecimal
if (affixProvider->currencyAsDecimal()) {
- fMicros.currencyAsDecimal = patternModifier->getCurrencySymbolForUnitWidth(status);
+ fMicros.simple.currencyAsDecimal = patternModifier->getCurrencySymbolForUnitWidth(status);
}
// Outer modifier (CLDR units and currency long names)
}
const PluralRules*
-NumberFormatterImpl::resolvePluralRules(const PluralRules* rulesPtr, const Locale& locale,
- UErrorCode& status) {
+NumberFormatterImpl::resolvePluralRules(
+ const PluralRules* rulesPtr,
+ const Locale& locale,
+ UErrorCode& status) {
if (rulesPtr != nullptr) {
return rulesPtr;
}
return fRules.getAlias();
}
-int32_t NumberFormatterImpl::writeAffixes(const MicroProps& micros, FormattedStringBuilder& string,
- int32_t start, int32_t end, UErrorCode& status) {
+int32_t NumberFormatterImpl::writeAffixes(
+ const MicroProps& micros,
+ FormattedStringBuilder& string,
+ int32_t start,
+ int32_t end,
+ UErrorCode& status) {
U_ASSERT(micros.modOuter != nullptr);
// Always apply the inner modifier (which is "strong").
int32_t length = micros.modInner->apply(string, start, end, status);
return length;
}
-int32_t NumberFormatterImpl::writeNumber(const MicroProps& micros, DecimalQuantity& quantity,
- FormattedStringBuilder& string, int32_t index,
- UErrorCode& status) {
+int32_t NumberFormatterImpl::writeNumber(
+ const SimpleMicroProps& micros,
+ DecimalQuantity& quantity,
+ FormattedStringBuilder& string,
+ int32_t index,
+ UErrorCode& status) {
int32_t length = 0;
if (quantity.isInfinite()) {
length += string.insert(
} else {
// Add the integer digits
- length += writeIntegerDigits(micros, quantity, string, length + index, status);
+ length += writeIntegerDigits(
+ micros,
+ quantity,
+ string,
+ length + index,
+ status);
// Add the decimal point
if (quantity.getLowerDisplayMagnitude() < 0 || micros.decimal == UNUM_DECIMAL_SEPARATOR_ALWAYS) {
return length;
}
-int32_t NumberFormatterImpl::writeIntegerDigits(const MicroProps& micros, DecimalQuantity& quantity,
- FormattedStringBuilder& string, int32_t index,
- UErrorCode& status) {
+int32_t NumberFormatterImpl::writeIntegerDigits(
+ const SimpleMicroProps& micros,
+ DecimalQuantity& quantity,
+ FormattedStringBuilder& string,
+ int32_t index,
+ UErrorCode& status) {
int length = 0;
int integerCount = quantity.getUpperDisplayMagnitude() + 1;
for (int i = 0; i < integerCount; i++) {
return length;
}
-int32_t NumberFormatterImpl::writeFractionDigits(const MicroProps& micros, DecimalQuantity& quantity,
- FormattedStringBuilder& string, int32_t index,
- UErrorCode& status) {
+int32_t NumberFormatterImpl::writeFractionDigits(
+ const SimpleMicroProps& micros,
+ DecimalQuantity& quantity,
+ FormattedStringBuilder& string,
+ int32_t index,
+ UErrorCode& status) {
int length = 0;
int fractionCount = -quantity.getLowerDisplayMagnitude();
for (int i = 0; i < fractionCount; i++) {
* Synthesizes the output string from a MicroProps and DecimalQuantity.
* This method formats only the main number, not affixes.
*/
- static int32_t writeNumber(const MicroProps& micros, DecimalQuantity& quantity,
- FormattedStringBuilder& string, int32_t index, UErrorCode& status);
+ static int32_t writeNumber(
+ const SimpleMicroProps& micros,
+ DecimalQuantity& quantity,
+ FormattedStringBuilder& string,
+ int32_t index,
+ UErrorCode& status);
/**
* Adds the affixes. Intended to be called immediately after formatNumber.
*/
- static int32_t writeAffixes(const MicroProps& micros, FormattedStringBuilder& string, int32_t start,
- int32_t end, UErrorCode& status);
+ static int32_t writeAffixes(
+ const MicroProps& micros,
+ FormattedStringBuilder& string,
+ int32_t start,
+ int32_t end,
+ UErrorCode& status);
private:
// Head of the MicroPropsGenerator linked list. Subclasses' processQuantity
macrosToMicroGenerator(const MacroProps ¯os, bool safe, UErrorCode &status);
static int32_t
- writeIntegerDigits(const MicroProps µs, DecimalQuantity &quantity, FormattedStringBuilder &string,
- int32_t index, UErrorCode &status);
+ writeIntegerDigits(
+ const SimpleMicroProps& micros,
+ DecimalQuantity &quantity,
+ FormattedStringBuilder &string,
+ int32_t index,
+ UErrorCode &status);
static int32_t
- writeFractionDigits(const MicroProps µs, DecimalQuantity &quantity, FormattedStringBuilder &string,
- int32_t index, UErrorCode &status);
+ writeFractionDigits(
+ const SimpleMicroProps& micros,
+ DecimalQuantity &quantity,
+ FormattedStringBuilder &string,
+ int32_t index,
+ UErrorCode &status);
};
} // namespace impl
UErrorCode status = U_ZERO_ERROR;
};
+struct SimpleMicroProps : public UMemory {
+ Grouper grouping;
+ bool useCurrency = false;
+ UNumberDecimalSeparatorDisplay decimal = UNUM_DECIMAL_SEPARATOR_AUTO;
+
+ // Currency symbol to be used as the decimal separator
+ UnicodeString currencyAsDecimal = ICU_Utility::makeBogusString();
+
+ // Note: This struct has no direct ownership of the following pointer.
+ const DecimalFormatSymbols* symbols = nullptr;
+};
+
/**
* MicroProps is the first MicroPropsGenerator that should be should be called,
* producing an initialized MicroProps instance that will be passed on and
* modified throughout the rest of the chain of MicroPropsGenerator instances.
*/
struct MicroProps : public MicroPropsGenerator {
+ SimpleMicroProps simple;
// NOTE: All of these fields are properly initialized in NumberFormatterImpl.
RoundingImpl rounder;
- Grouper grouping;
Padder padding;
IntegerWidth integerWidth;
UNumberSignDisplay sign;
- UNumberDecimalSeparatorDisplay decimal;
- bool useCurrency;
char nsName[9];
- // Currency symbol to be used as the decimal separator
- UnicodeString currencyAsDecimal = ICU_Utility::makeBogusString();
-
// No ownership: must point at a string which will outlive MicroProps
// instances, e.g. a string with static storage duration, or just a string
// that will never be deallocated or modified.
const char *gender;
// Note: This struct has no direct ownership of the following pointers.
- const DecimalFormatSymbols* symbols;
// Pointers to Modifiers provided by the number formatting pipeline (when
// the value is known):
ModifierStore::~ModifierStore() = default;
-AdoptingModifierStore::~AdoptingModifierStore() {
+AdoptingSignumModifierStore::~AdoptingSignumModifierStore() {
for (const Modifier *mod : mods) {
delete mod;
}
}
+AdoptingSignumModifierStore&
+AdoptingSignumModifierStore::operator=(AdoptingSignumModifierStore&& other) U_NOEXCEPT {
+ for (size_t i=0; i<SIGNUM_COUNT; i++) {
+ this->mods[i] = other.mods[i];
+ other.mods[i] = nullptr;
+ }
+ return *this;
+}
+
int32_t ConstantAffixModifier::apply(FormattedStringBuilder &output, int leftIndex, int rightIndex,
UErrorCode &status) const {
bool fStrong;
};
+/** An adopting Modifier store that varies by signum but not plural form. */
+class U_I18N_API AdoptingSignumModifierStore : public UMemory {
+ public:
+ virtual ~AdoptingSignumModifierStore();
+
+ AdoptingSignumModifierStore() = default;
+
+ // No copying!
+ AdoptingSignumModifierStore(const AdoptingSignumModifierStore &other) = delete;
+ AdoptingSignumModifierStore& operator=(const AdoptingSignumModifierStore& other) = delete;
+
+ // Moving is OK
+ AdoptingSignumModifierStore(AdoptingSignumModifierStore &&other) U_NOEXCEPT {
+ *this = std::move(other);
+ }
+ AdoptingSignumModifierStore& operator=(AdoptingSignumModifierStore&& other) U_NOEXCEPT;
+
+ /** Take ownership of the Modifier and slot it in at the given Signum. */
+ void adoptModifier(Signum signum, const Modifier* mod) {
+ U_ASSERT(mods[signum] == nullptr);
+ mods[signum] = mod;
+ }
+
+ inline const Modifier*& operator[](Signum signum) {
+ return mods[signum];
+ }
+ inline Modifier const* operator[](Signum signum) const {
+ return mods[signum];
+ }
+
+ private:
+ const Modifier* mods[SIGNUM_COUNT] = {};
+};
+
/**
* This implementation of ModifierStore adopts Modifier pointers.
*/
class U_I18N_API AdoptingModifierStore : public ModifierStore, public UMemory {
public:
- virtual ~AdoptingModifierStore();
-
static constexpr StandardPlural::Form DEFAULT_STANDARD_PLURAL = StandardPlural::OTHER;
AdoptingModifierStore() = default;
// No copying!
AdoptingModifierStore(const AdoptingModifierStore &other) = delete;
- /**
- * Sets the Modifier with the specified signum and plural form.
- */
- void adoptModifier(Signum signum, StandardPlural::Form plural, const Modifier *mod) {
- U_ASSERT(mods[getModIndex(signum, plural)] == nullptr);
- mods[getModIndex(signum, plural)] = mod;
+ // Moving is OK
+ AdoptingModifierStore(AdoptingModifierStore &&other) = default;
+
+ /** Sets the modifiers for a specific plural form. */
+ void adoptSignumModifierStore(StandardPlural::Form plural, AdoptingSignumModifierStore other) {
+ mods[plural] = std::move(other);
}
- /**
- * Sets the Modifier with the specified signum.
- * The modifier will apply to all plural forms.
- */
- void adoptModifierWithoutPlural(Signum signum, const Modifier *mod) {
- U_ASSERT(mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)] == nullptr);
- mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)] = mod;
+ /** Sets the modifiers for the default plural form. */
+ void adoptSignumModifierStoreNoPlural(AdoptingSignumModifierStore other) {
+ mods[DEFAULT_STANDARD_PLURAL] = std::move(other);
}
/** Returns a reference to the modifier; no ownership change. */
const Modifier *getModifier(Signum signum, StandardPlural::Form plural) const U_OVERRIDE {
- const Modifier* modifier = mods[getModIndex(signum, plural)];
+ const Modifier* modifier = mods[plural][signum];
if (modifier == nullptr && plural != DEFAULT_STANDARD_PLURAL) {
- modifier = mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)];
+ modifier = mods[DEFAULT_STANDARD_PLURAL][signum];
}
return modifier;
}
/** Returns a reference to the modifier; no ownership change. */
const Modifier *getModifierWithoutPlural(Signum signum) const {
- return mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)];
+ return mods[DEFAULT_STANDARD_PLURAL][signum];
}
private:
// NOTE: mods is zero-initialized (to nullptr)
- const Modifier *mods[4 * StandardPlural::COUNT] = {};
-
- inline static int32_t getModIndex(Signum signum, StandardPlural::Form plural) {
- U_ASSERT(signum >= 0 && signum < SIGNUM_COUNT);
- U_ASSERT(plural >= 0 && plural < StandardPlural::COUNT);
- return static_cast<int32_t>(plural) * SIGNUM_COUNT + signum;
- }
+ AdoptingSignumModifierStore mods[StandardPlural::COUNT] = {};
};
} // namespace impl
// Silently ignore any error codes.
}
+AdoptingSignumModifierStore MutablePatternModifier::createImmutableForPlural(StandardPlural::Form plural, UErrorCode& status) {
+ AdoptingSignumModifierStore pm;
+
+ setNumberProperties(SIGNUM_POS, plural);
+ pm.adoptModifier(SIGNUM_POS, createConstantModifier(status));
+ setNumberProperties(SIGNUM_NEG_ZERO, plural);
+ pm.adoptModifier(SIGNUM_NEG_ZERO, createConstantModifier(status));
+ setNumberProperties(SIGNUM_POS_ZERO, plural);
+ pm.adoptModifier(SIGNUM_POS_ZERO, createConstantModifier(status));
+ setNumberProperties(SIGNUM_NEG, plural);
+ pm.adoptModifier(SIGNUM_NEG, createConstantModifier(status));
+
+ return pm;
+}
+
ImmutablePatternModifier* MutablePatternModifier::createImmutable(UErrorCode& status) {
// TODO: Move StandardPlural VALUES to standardplural.h
static const StandardPlural::Form STANDARD_PLURAL_VALUES[] = {
if (needsPlurals()) {
// Slower path when we require the plural keyword.
for (StandardPlural::Form plural : STANDARD_PLURAL_VALUES) {
- setNumberProperties(SIGNUM_POS, plural);
- pm->adoptModifier(SIGNUM_POS, plural, createConstantModifier(status));
- setNumberProperties(SIGNUM_NEG_ZERO, plural);
- pm->adoptModifier(SIGNUM_NEG_ZERO, plural, createConstantModifier(status));
- setNumberProperties(SIGNUM_POS_ZERO, plural);
- pm->adoptModifier(SIGNUM_POS_ZERO, plural, createConstantModifier(status));
- setNumberProperties(SIGNUM_NEG, plural);
- pm->adoptModifier(SIGNUM_NEG, plural, createConstantModifier(status));
+ pm->adoptSignumModifierStore(plural, createImmutableForPlural(plural, status));
}
if (U_FAILURE(status)) {
delete pm;
return new ImmutablePatternModifier(pm, fRules); // adopts pm
} else {
// Faster path when plural keyword is not needed.
- setNumberProperties(SIGNUM_POS, StandardPlural::Form::COUNT);
- pm->adoptModifierWithoutPlural(SIGNUM_POS, createConstantModifier(status));
- setNumberProperties(SIGNUM_NEG_ZERO, StandardPlural::Form::COUNT);
- pm->adoptModifierWithoutPlural(SIGNUM_NEG_ZERO, createConstantModifier(status));
- setNumberProperties(SIGNUM_POS_ZERO, StandardPlural::Form::COUNT);
- pm->adoptModifierWithoutPlural(SIGNUM_POS_ZERO, createConstantModifier(status));
- setNumberProperties(SIGNUM_NEG, StandardPlural::Form::COUNT);
- pm->adoptModifierWithoutPlural(SIGNUM_NEG, createConstantModifier(status));
+ pm->adoptSignumModifierStoreNoPlural(createImmutableForPlural(StandardPlural::Form::COUNT, status));
if (U_FAILURE(status)) {
delete pm;
return nullptr;
*/
bool needsPlurals() const;
+ /** Creates a quantity-dependent Modifier for the specified plural form. */
+ AdoptingSignumModifierStore createImmutableForPlural(StandardPlural::Form plural, UErrorCode& status);
+
/**
* Creates a new quantity-dependent Modifier that behaves the same as the current instance, but which is immutable
* and can be saved for future use. The number properties in the current instance are mutated; all other properties
--- /dev/null
+// © 2017 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/numberformatter.h"
+#include "unicode/simplenumberformatter.h"
+#include "number_formatimpl.h"
+#include "number_utils.h"
+#include "number_patternmodifier.h"
+#include "number_utypes.h"
+
+using namespace icu;
+using namespace icu::number;
+using namespace icu::number::impl;
+
+
+SimpleNumber
+SimpleNumber::forInt64(int64_t value, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return SimpleNumber();
+ }
+ auto results = new UFormattedNumberData();
+ if (results == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return SimpleNumber();
+ }
+ results->quantity.setToLong(value);
+ return SimpleNumber(results, status);
+}
+
+SimpleNumber::SimpleNumber(UFormattedNumberData* data, UErrorCode& status) : fData(data) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (fData == nullptr) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ if (fData->quantity.isNegative()) {
+ fSign = UNUM_SIMPLE_NUMBER_MINUS_SIGN;
+ } else {
+ fSign = UNUM_SIMPLE_NUMBER_NO_SIGN;
+ }
+}
+
+void SimpleNumber::cleanup() {
+ delete fData;
+ fData = nullptr;
+}
+
+void SimpleNumber::multiplyByPowerOfTen(int32_t power, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (fData == nullptr) {
+ status = U_INVALID_STATE_ERROR;
+ return;
+ }
+ fData->quantity.adjustMagnitude(power);
+}
+
+void SimpleNumber::roundTo(int32_t position, UNumberFormatRoundingMode roundingMode, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (fData == nullptr) {
+ status = U_INVALID_STATE_ERROR;
+ return;
+ }
+ fData->quantity.roundToMagnitude(position, roundingMode, status);
+}
+
+void SimpleNumber::setMinimumIntegerDigits(uint32_t position, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (fData == nullptr) {
+ status = U_INVALID_STATE_ERROR;
+ return;
+ }
+ fData->quantity.setMinInteger(position);
+}
+
+void SimpleNumber::setMinimumFractionDigits(uint32_t position, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (fData == nullptr) {
+ status = U_INVALID_STATE_ERROR;
+ return;
+ }
+ fData->quantity.setMinFraction(position);
+}
+
+void SimpleNumber::truncateStart(uint32_t position, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (fData == nullptr) {
+ status = U_INVALID_STATE_ERROR;
+ return;
+ }
+ fData->quantity.applyMaxInteger(position);
+}
+
+void SimpleNumber::setSign(USimpleNumberSign sign, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (fData == nullptr) {
+ status = U_INVALID_STATE_ERROR;
+ return;
+ }
+ fSign = sign;
+}
+
+
+void SimpleNumberFormatter::cleanup() {
+ delete fOwnedSymbols;
+ delete fMicros;
+ delete fPatternModifier;
+ fOwnedSymbols = nullptr;
+ fMicros = nullptr;
+ fPatternModifier = nullptr;
+}
+
+SimpleNumberFormatter SimpleNumberFormatter::forLocale(const icu::Locale &locale, UErrorCode &status) {
+ return SimpleNumberFormatter::forLocaleAndGroupingStrategy(locale, UNUM_GROUPING_AUTO, status);
+}
+
+SimpleNumberFormatter SimpleNumberFormatter::forLocaleAndGroupingStrategy(
+ const icu::Locale &locale,
+ UNumberGroupingStrategy groupingStrategy,
+ UErrorCode &status) {
+ SimpleNumberFormatter retval;
+ retval.fOwnedSymbols = new DecimalFormatSymbols(locale, status);
+ if (U_FAILURE(status)) {
+ return retval;
+ }
+ if (retval.fOwnedSymbols == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return retval;
+ }
+ retval.initialize(locale, *retval.fOwnedSymbols, groupingStrategy, status);
+ return retval;
+}
+
+
+SimpleNumberFormatter SimpleNumberFormatter::forLocaleAndSymbolsAndGroupingStrategy(
+ const icu::Locale &locale,
+ const DecimalFormatSymbols &symbols,
+ UNumberGroupingStrategy groupingStrategy,
+ UErrorCode &status) {
+ SimpleNumberFormatter retval;
+ retval.initialize(locale, symbols, groupingStrategy, status);
+ return retval;
+}
+
+
+void SimpleNumberFormatter::initialize(
+ const icu::Locale &locale,
+ const DecimalFormatSymbols &symbols,
+ UNumberGroupingStrategy groupingStrategy,
+ UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ fMicros = new SimpleMicroProps();
+ if (fMicros == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ fMicros->symbols = &symbols;
+
+ auto pattern = utils::getPatternForStyle(
+ locale,
+ symbols.getNumberingSystemName(),
+ CLDR_PATTERN_STYLE_DECIMAL,
+ status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ ParsedPatternInfo patternInfo;
+ PatternParser::parseToPatternInfo(UnicodeString(pattern), patternInfo, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ auto grouper = Grouper::forStrategy(groupingStrategy);
+ grouper.setLocaleData(patternInfo, locale);
+ fMicros->grouping = grouper;
+
+ MutablePatternModifier patternModifier(false);
+ patternModifier.setPatternInfo(&patternInfo, kUndefinedField);
+ patternModifier.setPatternAttributes(UNUM_SIGN_EXCEPT_ZERO, false, false);
+ patternModifier.setSymbols(fMicros->symbols, {}, UNUM_UNIT_WIDTH_SHORT, nullptr, status);
+
+ fPatternModifier = new AdoptingSignumModifierStore(patternModifier.createImmutableForPlural(StandardPlural::COUNT, status));
+
+ fGroupingStrategy = groupingStrategy;
+ return;
+}
+
+FormattedNumber SimpleNumberFormatter::format(SimpleNumber value, UErrorCode &status) const {
+ formatImpl(value.fData, value.fSign, status);
+
+ // Do not save the results object if we encountered a failure.
+ if (U_SUCCESS(status)) {
+ auto temp = value.fData;
+ value.fData = nullptr;
+ return FormattedNumber(temp);
+ } else {
+ return FormattedNumber(status);
+ }
+}
+
+void SimpleNumberFormatter::formatImpl(UFormattedNumberData* data, USimpleNumberSign sign, UErrorCode &status) const {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (data == nullptr) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ if (fPatternModifier == nullptr || fMicros == nullptr) {
+ status = U_INVALID_STATE_ERROR;
+ return;
+ }
+
+ Signum signum;
+ if (sign == UNUM_SIMPLE_NUMBER_MINUS_SIGN) {
+ signum = SIGNUM_NEG;
+ } else if (sign == UNUM_SIMPLE_NUMBER_PLUS_SIGN) {
+ signum = SIGNUM_POS;
+ } else {
+ signum = SIGNUM_POS_ZERO;
+ }
+
+ const Modifier* modifier = (*fPatternModifier)[signum];
+ auto length = NumberFormatterImpl::writeNumber(
+ *fMicros,
+ data->quantity,
+ data->getStringRef(),
+ 0,
+ status);
+ length += modifier->apply(data->getStringRef(), 0, length, status);
+ data->getStringRef().writeTerminator(status);
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
UFormattedNumberData() : FormattedValueStringBuilderImpl(kUndefinedField) {}
virtual ~UFormattedNumberData();
+ UFormattedNumberData(UFormattedNumberData&&) = default;
+ UFormattedNumberData& operator=(UFormattedNumberData&&) = default;
+
// The formatted quantity.
DecimalQuantity quantity;
UErrorCode& status) const {
if (U_FAILURE(status)) { return; }
if (fSameFormatters) {
- int32_t length = NumberFormatterImpl::writeNumber(micros1, data.quantity1, data.getStringRef(), 0, status);
+ int32_t length = NumberFormatterImpl::writeNumber(micros1.simple, data.quantity1, data.getStringRef(), 0, status);
NumberFormatterImpl::writeAffixes(micros1, data.getStringRef(), 0, length, status);
} else {
formatRange(data, micros1, micros2, status);
MicroProps microsAppx;
data.quantity1.resetExponent();
fApproximatelyFormatter.preProcess(data.quantity1, microsAppx, status);
- int32_t length = NumberFormatterImpl::writeNumber(microsAppx, data.quantity1, data.getStringRef(), 0, status);
+ int32_t length = NumberFormatterImpl::writeNumber(microsAppx.simple, data.quantity1, data.getStringRef(), 0, status);
length += microsAppx.modInner->apply(data.getStringRef(), 0, length, status);
length += microsAppx.modMiddle->apply(data.getStringRef(), 0, length, status);
microsAppx.modOuter->apply(data.getStringRef(), 0, length, status);
}
}
- length1 += NumberFormatterImpl::writeNumber(micros1, data.quantity1, string, UPRV_INDEX_0, status);
+ length1 += NumberFormatterImpl::writeNumber(micros1.simple, data.quantity1, string, UPRV_INDEX_0, status);
// ICU-21684: Write the second number to a temp string to avoid repeated insert operations
FormattedStringBuilder tempString;
- NumberFormatterImpl::writeNumber(micros2, data.quantity2, tempString, 0, status);
+ NumberFormatterImpl::writeNumber(micros2.simple, data.quantity2, tempString, 0, status);
length2 += string.insert(UPRV_INDEX_2, tempString, status);
// TODO: Support padding?
number_patternstring.cpp
number_rounding.cpp
number_scientific.cpp
+number_simple.cpp
number_skeletons.cpp
number_symbolswrapper.cpp
number_usageprefs.cpp
* @internal
*/
inline const char16_t* getCurrencyPattern(void) const;
+
+ /**
+ * Returns the numbering system with which this DecimalFormatSymbols was initialized.
+ * @internal
+ */
+ inline const char* getNumberingSystemName(void) const;
#endif /* U_HIDE_INTERNAL_API */
private:
char actualLocale[ULOC_FULLNAME_CAPACITY];
char validLocale[ULOC_FULLNAME_CAPACITY];
- const char16_t* currPattern;
+ const char16_t* currPattern = nullptr;
UnicodeString currencySpcBeforeSym[UNUM_CURRENCY_SPACING_COUNT];
UnicodeString currencySpcAfterSym[UNUM_CURRENCY_SPACING_COUNT];
UBool fIsCustomCurrencySymbol;
UBool fIsCustomIntlCurrencySymbol;
+ char nsName[kInternalNumSysNameCapacity+1] = {};
};
// -------------------------------------
DecimalFormatSymbols::getCurrencyPattern() const {
return currPattern;
}
+inline const char*
+DecimalFormatSymbols::getNumberingSystemName() const {
+ return nsName;
+}
#endif /* U_HIDE_INTERNAL_API */
U_NAMESPACE_END
--- /dev/null
+// © 2022 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#ifndef __FORMATTEDNUMBER_H__
+#define __FORMATTEDNUMBER_H__
+
+#include "unicode/utypes.h"
+
+#if U_SHOW_CPLUSPLUS_API
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/uobject.h"
+#include "unicode/formattedvalue.h"
+#include "unicode/measunit.h"
+#include "unicode/udisplayoptions.h"
+
+/**
+ * \file
+ * \brief C API: Formatted number result from various number formatting functions.
+ *
+ * See also {@link icu::FormattedValue} for additional things you can do with a FormattedNumber.
+ */
+
+U_NAMESPACE_BEGIN
+
+class FieldPositionIteratorHandler;
+
+namespace number { // icu::number
+
+namespace impl {
+class DecimalQuantity;
+class UFormattedNumberData;
+struct UFormattedNumberImpl;
+} // icu::number::impl
+
+
+
+/**
+ * The result of a number formatting operation. This class allows the result to be exported in several data types,
+ * including a UnicodeString and a FieldPositionIterator.
+ *
+ * Instances of this class are immutable and thread-safe.
+ *
+ * @stable ICU 60
+ */
+class U_I18N_API FormattedNumber : public UMemory, public FormattedValue {
+ public:
+
+ /**
+ * Default constructor; makes an empty FormattedNumber.
+ * @stable ICU 64
+ */
+ FormattedNumber()
+ : fData(nullptr), fErrorCode(U_INVALID_STATE_ERROR) {}
+
+ /**
+ * Move constructor: Leaves the source FormattedNumber in an undefined state.
+ * @stable ICU 62
+ */
+ FormattedNumber(FormattedNumber&& src) U_NOEXCEPT;
+
+ /**
+ * Destruct an instance of FormattedNumber.
+ * @stable ICU 60
+ */
+ virtual ~FormattedNumber() U_OVERRIDE;
+
+ /** Copying not supported; use move constructor instead. */
+ FormattedNumber(const FormattedNumber&) = delete;
+
+ /** Copying not supported; use move assignment instead. */
+ FormattedNumber& operator=(const FormattedNumber&) = delete;
+
+ /**
+ * Move assignment: Leaves the source FormattedNumber in an undefined state.
+ * @stable ICU 62
+ */
+ FormattedNumber& operator=(FormattedNumber&& src) U_NOEXCEPT;
+
+ // Copybrief: this method is older than the parent method
+ /**
+ * @copybrief FormattedValue::toString()
+ *
+ * For more information, see FormattedValue::toString()
+ *
+ * @stable ICU 62
+ */
+ UnicodeString toString(UErrorCode& status) const U_OVERRIDE;
+
+ // Copydoc: this method is new in ICU 64
+ /** @copydoc FormattedValue::toTempString() */
+ UnicodeString toTempString(UErrorCode& status) const U_OVERRIDE;
+
+ // Copybrief: this method is older than the parent method
+ /**
+ * @copybrief FormattedValue::appendTo()
+ *
+ * For more information, see FormattedValue::appendTo()
+ *
+ * @stable ICU 62
+ */
+ Appendable &appendTo(Appendable& appendable, UErrorCode& status) const U_OVERRIDE;
+
+ // Copydoc: this method is new in ICU 64
+ /** @copydoc FormattedValue::nextPosition() */
+ UBool nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const U_OVERRIDE;
+
+ /**
+ * Export the formatted number as a "numeric string" conforming to the
+ * syntax defined in the Decimal Arithmetic Specification, available at
+ * http://speleotrove.com/decimal
+ *
+ * This endpoint is useful for obtaining the exact number being printed
+ * after scaling and rounding have been applied by the number formatter.
+ *
+ * Example call site:
+ *
+ * auto decimalNumber = fn.toDecimalNumber<std::string>(status);
+ *
+ * @tparam StringClass A string class compatible with StringByteSink;
+ * for example, std::string.
+ * @param status Set if an error occurs.
+ * @return A StringClass containing the numeric string.
+ * @stable ICU 65
+ */
+ template<typename StringClass>
+ inline StringClass toDecimalNumber(UErrorCode& status) const;
+
+ /**
+ * Gets the resolved output unit.
+ *
+ * The output unit is dependent upon the localized preferences for the usage
+ * specified via NumberFormatterSettings::usage(), and may be a unit with
+ * UMEASURE_UNIT_MIXED unit complexity (MeasureUnit::getComplexity()), such
+ * as "foot-and-inch" or "hour-and-minute-and-second".
+ *
+ * @return `MeasureUnit`.
+ * @stable ICU 68
+ */
+ MeasureUnit getOutputUnit(UErrorCode& status) const;
+
+#ifndef U_HIDE_DRAFT_API
+
+ /**
+ * Gets the noun class of the formatted output. Returns `UNDEFINED` when the noun class
+ * is not supported yet.
+ *
+ * @return UDisplayOptionsNounClass
+ * @draft ICU 72
+ */
+ UDisplayOptionsNounClass getNounClass(UErrorCode &status) const;
+
+#endif // U_HIDE_DRAFT_API
+
+#ifndef U_HIDE_INTERNAL_API
+
+ /**
+ * Gets the raw DecimalQuantity for plural rule selection.
+ * @internal
+ */
+ void getDecimalQuantity(impl::DecimalQuantity& output, UErrorCode& status) const;
+
+ /**
+ * Populates the mutable builder type FieldPositionIteratorHandler.
+ * @internal
+ */
+ void getAllFieldPositionsImpl(FieldPositionIteratorHandler& fpih, UErrorCode& status) const;
+
+#endif /* U_HIDE_INTERNAL_API */
+
+ private:
+ // Can't use LocalPointer because UFormattedNumberData is forward-declared
+ impl::UFormattedNumberData *fData;
+
+ // Error code for the terminal methods
+ UErrorCode fErrorCode;
+
+ /**
+ * Internal constructor from data type. Adopts the data pointer.
+ * @internal (private)
+ */
+ explicit FormattedNumber(impl::UFormattedNumberData *results)
+ : fData(results), fErrorCode(U_ZERO_ERROR) {}
+
+ explicit FormattedNumber(UErrorCode errorCode)
+ : fData(nullptr), fErrorCode(errorCode) {}
+
+ void toDecimalNumber(ByteSink& sink, UErrorCode& status) const;
+
+ // To give LocalizedNumberFormatter format methods access to this class's constructor:
+ friend class LocalizedNumberFormatter;
+ friend class SimpleNumberFormatter;
+
+ // To give C API access to internals
+ friend struct impl::UFormattedNumberImpl;
+};
+
+template<typename StringClass>
+StringClass FormattedNumber::toDecimalNumber(UErrorCode& status) const {
+ StringClass result;
+ StringByteSink<StringClass> sink(&result);
+ toDecimalNumber(sink, status);
+ return result;
+}
+
+} // namespace number
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif /* U_SHOW_CPLUSPLUS_API */
+
+#endif // __FORMATTEDNUMBER_H__
+
#include "unicode/dcfmtsym.h"
#include "unicode/displayoptions.h"
#include "unicode/fieldpos.h"
-#include "unicode/formattedvalue.h"
#include "unicode/fpositer.h"
#include "unicode/measunit.h"
#include "unicode/nounit.h"
#include "unicode/parseerr.h"
#include "unicode/plurrule.h"
#include "unicode/ucurr.h"
-#include "unicode/udisplayoptions.h"
#include "unicode/unum.h"
#include "unicode/unumberformatter.h"
#include "unicode/uobject.h"
+#include "unicode/unumberoptions.h"
+#include "unicode/formattednumber.h"
/**
* \file
// Forward declarations:
class UnlocalizedNumberFormatter;
class LocalizedNumberFormatter;
+class SimpleNumberFormatter;
class FormattedNumber;
class Notation;
class ScientificNotation;
class MutablePatternModifier;
class ImmutablePatternModifier;
struct DecimalFormatWarehouse;
+struct SimpleMicroProps;
+class AdoptingSignumModifierStore;
/**
* Used for NumberRangeFormatter and implemented in numrange_fluent.cpp.
// To allow MacroProps/MicroProps to initialize empty instances:
friend struct MacroProps;
friend struct MicroProps;
+ friend struct SimpleMicroProps;
// To allow NumberFormatterImpl to access isBogus() and perform other operations:
friend class NumberFormatterImpl;
+ friend class ::icu::number::SimpleNumberFormatter;
// To allow NumberParserImpl to perform setLocaleData():
friend class ::icu::numparse::impl::NumberParserImpl;
#pragma warning(pop)
#endif
-/**
- * The result of a number formatting operation. This class allows the result to be exported in several data types,
- * including a UnicodeString and a FieldPositionIterator.
- *
- * Instances of this class are immutable and thread-safe.
- *
- * @stable ICU 60
- */
-class U_I18N_API FormattedNumber : public UMemory, public FormattedValue {
- public:
-
- /**
- * Default constructor; makes an empty FormattedNumber.
- * @stable ICU 64
- */
- FormattedNumber()
- : fData(nullptr), fErrorCode(U_INVALID_STATE_ERROR) {}
-
- /**
- * Move constructor: Leaves the source FormattedNumber in an undefined state.
- * @stable ICU 62
- */
- FormattedNumber(FormattedNumber&& src) U_NOEXCEPT;
-
- /**
- * Destruct an instance of FormattedNumber.
- * @stable ICU 60
- */
- virtual ~FormattedNumber() U_OVERRIDE;
-
- /** Copying not supported; use move constructor instead. */
- FormattedNumber(const FormattedNumber&) = delete;
-
- /** Copying not supported; use move assignment instead. */
- FormattedNumber& operator=(const FormattedNumber&) = delete;
-
- /**
- * Move assignment: Leaves the source FormattedNumber in an undefined state.
- * @stable ICU 62
- */
- FormattedNumber& operator=(FormattedNumber&& src) U_NOEXCEPT;
-
- // Copybrief: this method is older than the parent method
- /**
- * @copybrief FormattedValue::toString()
- *
- * For more information, see FormattedValue::toString()
- *
- * @stable ICU 62
- */
- UnicodeString toString(UErrorCode& status) const U_OVERRIDE;
-
- // Copydoc: this method is new in ICU 64
- /** @copydoc FormattedValue::toTempString() */
- UnicodeString toTempString(UErrorCode& status) const U_OVERRIDE;
-
- // Copybrief: this method is older than the parent method
- /**
- * @copybrief FormattedValue::appendTo()
- *
- * For more information, see FormattedValue::appendTo()
- *
- * @stable ICU 62
- */
- Appendable &appendTo(Appendable& appendable, UErrorCode& status) const U_OVERRIDE;
-
- // Copydoc: this method is new in ICU 64
- /** @copydoc FormattedValue::nextPosition() */
- UBool nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const U_OVERRIDE;
-
- /**
- * Export the formatted number as a "numeric string" conforming to the
- * syntax defined in the Decimal Arithmetic Specification, available at
- * http://speleotrove.com/decimal
- *
- * This endpoint is useful for obtaining the exact number being printed
- * after scaling and rounding have been applied by the number formatter.
- *
- * Example call site:
- *
- * auto decimalNumber = fn.toDecimalNumber<std::string>(status);
- *
- * @tparam StringClass A string class compatible with StringByteSink;
- * for example, std::string.
- * @param status Set if an error occurs.
- * @return A StringClass containing the numeric string.
- * @stable ICU 65
- */
- template<typename StringClass>
- inline StringClass toDecimalNumber(UErrorCode& status) const;
-
- /**
- * Gets the resolved output unit.
- *
- * The output unit is dependent upon the localized preferences for the usage
- * specified via NumberFormatterSettings::usage(), and may be a unit with
- * UMEASURE_UNIT_MIXED unit complexity (MeasureUnit::getComplexity()), such
- * as "foot-and-inch" or "hour-and-minute-and-second".
- *
- * @return `MeasureUnit`.
- * @stable ICU 68
- */
- MeasureUnit getOutputUnit(UErrorCode& status) const;
-
-#ifndef U_HIDE_DRAFT_API
-
- /**
- * Gets the noun class of the formatted output. Returns `UNDEFINED` when the noun class
- * is not supported yet.
- *
- * @return UDisplayOptionsNounClass
- * @draft ICU 72
- */
- UDisplayOptionsNounClass getNounClass(UErrorCode &status) const;
-
-#endif // U_HIDE_DRAFT_API
-
-#ifndef U_HIDE_INTERNAL_API
-
- /**
- * Gets the raw DecimalQuantity for plural rule selection.
- * @internal
- */
- void getDecimalQuantity(impl::DecimalQuantity& output, UErrorCode& status) const;
-
- /**
- * Populates the mutable builder type FieldPositionIteratorHandler.
- * @internal
- */
- void getAllFieldPositionsImpl(FieldPositionIteratorHandler& fpih, UErrorCode& status) const;
-
-#endif /* U_HIDE_INTERNAL_API */
-
- private:
- // Can't use LocalPointer because UFormattedNumberData is forward-declared
- const impl::UFormattedNumberData *fData;
-
- // Error code for the terminal methods
- UErrorCode fErrorCode;
-
- /**
- * Internal constructor from data type. Adopts the data pointer.
- * @internal (private)
- */
- explicit FormattedNumber(impl::UFormattedNumberData *results)
- : fData(results), fErrorCode(U_ZERO_ERROR) {}
-
- explicit FormattedNumber(UErrorCode errorCode)
- : fData(nullptr), fErrorCode(errorCode) {}
-
- void toDecimalNumber(ByteSink& sink, UErrorCode& status) const;
-
- // To give LocalizedNumberFormatter format methods access to this class's constructor:
- friend class LocalizedNumberFormatter;
-
- // To give C API access to internals
- friend struct impl::UFormattedNumberImpl;
-};
-
-template<typename StringClass>
-StringClass FormattedNumber::toDecimalNumber(UErrorCode& status) const {
- StringClass result;
- StringByteSink<StringClass> sink(&result);
- toDecimalNumber(sink, status);
- return result;
-}
-
/**
* See the main description in numberformatter.h for documentation and examples.
*
--- /dev/null
+// © 2022 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#ifndef __SIMPLENUMBERFORMATTERH__
+#define __SIMPLENUMBERFORMATTERH__
+
+#include "unicode/utypes.h"
+
+#if U_SHOW_CPLUSPLUS_API
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/dcfmtsym.h"
+#include "unicode/usimplenumberformatter.h"
+#include "unicode/formattednumber.h"
+
+/**
+ * \file
+ * \brief C++ API: Simple number formatting focused on low memory and code size.
+ *
+ * These functions render locale-aware number strings but without the bells and whistles found in
+ * other number formatting APIs such as those in numberformatter.h, like units and currencies.
+ *
+ * <pre>
+ * SimpleNumberFormatter snf = SimpleNumberFormatter::forLocale("de-CH", status);
+ * FormattedNumber result = snf.formatInt64(-1000007, status);
+ * assertEquals("", u"-1’000’007", result.toString(status));
+ * </pre>
+ */
+
+U_NAMESPACE_BEGIN
+
+
+namespace number { // icu::number
+
+
+namespace impl {
+class UFormattedNumberData;
+struct SimpleMicroProps;
+class AdoptingSignumModifierStore;
+} // icu::number::impl
+
+
+#ifndef U_HIDE_DRAFT_API
+
+
+/**
+ * An input type for SimpleNumberFormatter.
+ *
+ * This class is mutable and not intended for public subclassing. This class is movable but not copyable.
+ *
+ * @draft ICU 73
+ */
+class U_I18N_API SimpleNumber : public UMemory {
+ public:
+ /**
+ * Creates a SimpleNumber for an integer.
+ *
+ * @draft ICU 73
+ */
+ static SimpleNumber forInt64(int64_t value, UErrorCode& status);
+
+ /**
+ * Changes the value of the SimpleNumber by a power of 10.
+ *
+ * This function immediately mutates the inner value.
+ *
+ * @draft ICU 73
+ */
+ void multiplyByPowerOfTen(int32_t power, UErrorCode& status);
+
+ /**
+ * Rounds the value currently stored in the SimpleNumber to the given power of 10.
+ *
+ * This function immediately mutates the inner value.
+ *
+ * @draft ICU 73
+ */
+ void roundTo(int32_t power, UNumberFormatRoundingMode roundingMode, UErrorCode& status);
+
+ /**
+ * Truncates the most significant digits to the given maximum number of integer digits.
+ *
+ * This function immediately mutates the inner value.
+ *
+ * @draft ICU 73
+ */
+ void truncateStart(uint32_t maximumIntegerDigits, UErrorCode& status);
+
+ /**
+ * Pads the beginning of the number with zeros up to the given minimum number of integer digits.
+ *
+ * This setting is applied upon formatting the number.
+ *
+ * @draft ICU 73
+ */
+ void setMinimumIntegerDigits(uint32_t minimumIntegerDigits, UErrorCode& status);
+
+ /**
+ * Pads the end of the number with zeros up to the given minimum number of fraction digits.
+ *
+ * This setting is applied upon formatting the number.
+ *
+ * @draft ICU 73
+ */
+ void setMinimumFractionDigits(uint32_t minimumFractionDigits, UErrorCode& status);
+
+ /**
+ * Sets the sign of the number: an explicit plus sign, explicit minus sign, or no sign.
+ *
+ * This setting is applied upon formatting the number.
+ *
+ * NOTE: This does not support accounting sign notation.
+ *
+ * @draft ICU 73
+ */
+ void setSign(USimpleNumberSign sign, UErrorCode& status);
+
+ /**
+ * Creates a new, empty SimpleNumber that does not contain a value.
+ *
+ * NOTE: This number will fail to format; use forInt64() to create a SimpleNumber with a value.
+ *
+ * @draft ICU 73
+ */
+ SimpleNumber() = default;
+
+ /**
+ * Destruct this SimpleNumber, cleaning up any memory it might own.
+ *
+ * @draft ICU 73
+ */
+ ~SimpleNumber() {
+ cleanup();
+ }
+
+ /**
+ * SimpleNumber move constructor.
+ *
+ * @draft ICU 73
+ */
+ SimpleNumber(SimpleNumber&& other) U_NOEXCEPT {
+ fData = other.fData;
+ fSign = other.fSign;
+ other.fData = nullptr;
+ }
+
+ /**
+ * SimpleNumber move assignment.
+ *
+ * @draft ICU 73
+ */
+ SimpleNumber& operator=(SimpleNumber&& other) U_NOEXCEPT {
+ cleanup();
+ fData = other.fData;
+ fSign = other.fSign;
+ other.fData = nullptr;
+ return *this;
+ }
+
+ private:
+ SimpleNumber(impl::UFormattedNumberData* data, UErrorCode& status);
+ SimpleNumber(const SimpleNumber&) = delete;
+ SimpleNumber& operator=(const SimpleNumber&) = delete;
+
+ void cleanup();
+
+ impl::UFormattedNumberData* fData = nullptr;
+ USimpleNumberSign fSign = UNUM_SIMPLE_NUMBER_NO_SIGN;
+
+ friend class SimpleNumberFormatter;
+};
+
+
+/**
+ * A special NumberFormatter focused on smaller binary size and memory use.
+ *
+ * SimpleNumberFormatter is capable of basic number formatting, including grouping separators,
+ * sign display, and rounding. It is not capable of currencies, compact notation, or units.
+ *
+ * This class is immutable and not intended for public subclassing. This class is movable but not copyable.
+ *
+ * @draft ICU 73
+ */
+class U_I18N_API SimpleNumberFormatter : public UMemory {
+ public:
+ /**
+ * Creates a new SimpleNumberFormatter with all locale defaults.
+ *
+ * @draft ICU 73
+ */
+ static SimpleNumberFormatter forLocale(
+ const icu::Locale &locale,
+ UErrorCode &status);
+
+ /**
+ * Creates a new SimpleNumberFormatter, overriding the grouping strategy.
+ *
+ * @draft ICU 73
+ */
+ static SimpleNumberFormatter forLocaleAndGroupingStrategy(
+ const icu::Locale &locale,
+ UNumberGroupingStrategy groupingStrategy,
+ UErrorCode &status);
+
+ /**
+ * Creates a new SimpleNumberFormatter, overriding the grouping strategy and symbols.
+ *
+ * IMPORTANT: For efficiency, this function borrows the symbols. The symbols MUST remain valid
+ * for the lifetime of the SimpleNumberFormatter.
+ *
+ * @draft ICU 73
+ */
+ static SimpleNumberFormatter forLocaleAndSymbolsAndGroupingStrategy(
+ const icu::Locale &locale,
+ const DecimalFormatSymbols &symbols,
+ UNumberGroupingStrategy groupingStrategy,
+ UErrorCode &status);
+
+ /**
+ * Formats a value using this SimpleNumberFormatter.
+ *
+ * The SimpleNumber argument is "consumed". A new SimpleNumber object should be created for
+ * every formatting operation.
+ *
+ * @draft ICU 73
+ */
+ FormattedNumber format(SimpleNumber value, UErrorCode &status) const;
+
+ /**
+ * Formats an integer using this SimpleNumberFormatter.
+ *
+ * For more control over the formatting, use SimpleNumber.
+ *
+ * @draft ICU 73
+ */
+ FormattedNumber formatInt64(int64_t value, UErrorCode &status) const {
+ return format(SimpleNumber::forInt64(value, status), status);
+ }
+
+#ifndef U_HIDE_INTERNAL_API
+ /**
+ * Run the formatter with the internal types.
+ * @internal
+ */
+ void formatImpl(impl::UFormattedNumberData* data, USimpleNumberSign sign, UErrorCode& status) const;
+#endif // U_HIDE_INTERNAL_API
+
+ /**
+ * Destruct this SimpleNumberFormatter, cleaning up any memory it might own.
+ *
+ * @draft ICU 73
+ */
+ ~SimpleNumberFormatter() {
+ cleanup();
+ }
+
+ /**
+ * Creates a shell, initialized but non-functional SimpleNumberFormatter.
+ *
+ * @draft ICU 73
+ */
+ SimpleNumberFormatter() = default;
+
+ /**
+ * SimpleNumberFormatter: Move constructor.
+ *
+ * @draft ICU 73
+ */
+ SimpleNumberFormatter(SimpleNumberFormatter&& other) U_NOEXCEPT {
+ fGroupingStrategy = other.fGroupingStrategy;
+ fOwnedSymbols = other.fOwnedSymbols;
+ fMicros = other.fMicros;
+ fPatternModifier = other.fPatternModifier;
+ other.fOwnedSymbols = nullptr;
+ other.fMicros = nullptr;
+ other.fPatternModifier = nullptr;
+ }
+
+ /**
+ * SimpleNumberFormatter: Move assignment.
+ *
+ * @draft ICU 73
+ */
+ SimpleNumberFormatter& operator=(SimpleNumberFormatter&& other) U_NOEXCEPT {
+ cleanup();
+ fGroupingStrategy = other.fGroupingStrategy;
+ fOwnedSymbols = other.fOwnedSymbols;
+ fMicros = other.fMicros;
+ fPatternModifier = other.fPatternModifier;
+ other.fOwnedSymbols = nullptr;
+ other.fMicros = nullptr;
+ other.fPatternModifier = nullptr;
+ return *this;
+ }
+
+ private:
+ void initialize(
+ const icu::Locale &locale,
+ const DecimalFormatSymbols &symbols,
+ UNumberGroupingStrategy groupingStrategy,
+ UErrorCode &status);
+
+ void cleanup();
+
+ SimpleNumberFormatter(const SimpleNumberFormatter&) = delete;
+
+ SimpleNumberFormatter& operator=(const SimpleNumberFormatter&) = delete;
+
+ UNumberGroupingStrategy fGroupingStrategy = UNUM_GROUPING_AUTO;
+
+ // Owned Pointers:
+ DecimalFormatSymbols* fOwnedSymbols = nullptr; // can be empty
+ impl::SimpleMicroProps* fMicros = nullptr;
+ impl::AdoptingSignumModifierStore* fPatternModifier = nullptr;
+};
+
+
+#endif // U_HIDE_DRAFT_API
+
+} // namespace number
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif /* U_SHOW_CPLUSPLUS_API */
+
+#endif // __SIMPLENUMBERFORMATTERH__
+
--- /dev/null
+// © 2022 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#ifndef __UFORMATTEDNUMBER_H__
+#define __UFORMATTEDNUMBER_H__
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/ufieldpositer.h"
+#include "unicode/uformattedvalue.h"
+#include "unicode/umisc.h"
+
+/**
+ * \file
+ * \brief C API: Formatted number result from various number formatting functions.
+ *
+ * Create a `UFormattedNumber` to hold the result of a number formatting operation. The same
+ * `UFormattedNumber` can be reused multiple times.
+ *
+ * <pre>
+ * LocalUFormattedNumberPointer uresult(unumf_openResult(status));
+ *
+ * // pass uresult.getAlias() to your number formatter
+ *
+ * int32_t length;
+ * const UChar* s = ufmtval_getString(unumf_resultAsValue(uresult.getAlias(), status), &length, status));
+ *
+ * // The string result is in `s` with the given `length` (it is also NUL-terminated).
+ * </pre>
+ */
+
+
+struct UFormattedNumber;
+/**
+ * C-compatible version of icu::number::FormattedNumber.
+ *
+ * NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead.
+ *
+ * @stable ICU 62
+ */
+typedef struct UFormattedNumber UFormattedNumber;
+
+
+/**
+ * Creates an object to hold the result of a UNumberFormatter
+ * operation. The object can be used repeatedly; it is cleared whenever
+ * passed to a format function.
+ *
+ * @param ec Set if an error occurs.
+ * @stable ICU 62
+ */
+U_CAPI UFormattedNumber* U_EXPORT2
+unumf_openResult(UErrorCode* ec);
+
+
+/**
+ * Returns a representation of a UFormattedNumber as a UFormattedValue,
+ * which can be subsequently passed to any API requiring that type.
+ *
+ * The returned object is owned by the UFormattedNumber and is valid
+ * only as long as the UFormattedNumber is present and unchanged in memory.
+ *
+ * You can think of this method as a cast between types.
+ *
+ * @param uresult The object containing the formatted string.
+ * @param ec Set if an error occurs.
+ * @return A UFormattedValue owned by the input object.
+ * @stable ICU 64
+ */
+U_CAPI const UFormattedValue* U_EXPORT2
+unumf_resultAsValue(const UFormattedNumber* uresult, UErrorCode* ec);
+
+
+/**
+ * Extracts the result number string out of a UFormattedNumber to a UChar buffer if possible.
+ * If bufferCapacity is greater than the required length, a terminating NUL is written.
+ * If bufferCapacity is less than the required length, an error code is set.
+ *
+ * Also see ufmtval_getString, which returns a NUL-terminated string:
+ *
+ * int32_t len;
+ * const UChar* str = ufmtval_getString(unumf_resultAsValue(uresult, &ec), &len, &ec);
+ *
+ * NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead.
+ *
+ * @param uresult The object containing the formatted number.
+ * @param buffer Where to save the string output.
+ * @param bufferCapacity The number of UChars available in the buffer.
+ * @param ec Set if an error occurs.
+ * @return The required length.
+ * @stable ICU 62
+ */
+U_CAPI int32_t U_EXPORT2
+unumf_resultToString(const UFormattedNumber* uresult, UChar* buffer, int32_t bufferCapacity,
+ UErrorCode* ec);
+
+
+/**
+ * Determines the start and end indices of the next occurrence of the given <em>field</em> in the
+ * output string. This allows you to determine the locations of, for example, the integer part,
+ * fraction part, or symbols.
+ *
+ * This is a simpler but less powerful alternative to {@link ufmtval_nextPosition}.
+ *
+ * If a field occurs just once, calling this method will find that occurrence and return it. If a
+ * field occurs multiple times, this method may be called repeatedly with the following pattern:
+ *
+ * <pre>
+ * UFieldPosition ufpos = {UNUM_GROUPING_SEPARATOR_FIELD, 0, 0};
+ * while (unumf_resultNextFieldPosition(uresult, ufpos, &ec)) {
+ * // do something with ufpos.
+ * }
+ * </pre>
+ *
+ * This method is useful if you know which field to query. If you want all available field position
+ * information, use unumf_resultGetAllFieldPositions().
+ *
+ * NOTE: All fields of the UFieldPosition must be initialized before calling this method.
+ *
+ * @param uresult The object containing the formatted number.
+ * @param ufpos
+ * Input+output variable. On input, the "field" property determines which field to look up,
+ * and the "endIndex" property determines where to begin the search. On output, the
+ * "beginIndex" field is set to the beginning of the first occurrence of the field after the
+ * input "endIndex", and "endIndex" is set to the end of that occurrence of the field
+ * (exclusive index). If a field position is not found, the FieldPosition is not changed and
+ * the method returns false.
+ * @param ec Set if an error occurs.
+ * @stable ICU 62
+ */
+U_CAPI UBool U_EXPORT2
+unumf_resultNextFieldPosition(const UFormattedNumber* uresult, UFieldPosition* ufpos, UErrorCode* ec);
+
+
+/**
+ * Populates the given iterator with all fields in the formatted output string. This allows you to
+ * determine the locations of the integer part, fraction part, and sign.
+ *
+ * This is an alternative to the more powerful {@link ufmtval_nextPosition} API.
+ *
+ * If you need information on only one field, use {@link ufmtval_nextPosition} or
+ * {@link unumf_resultNextFieldPosition}.
+ *
+ * @param uresult The object containing the formatted number.
+ * @param ufpositer
+ * A pointer to a UFieldPositionIterator created by {@link #ufieldpositer_open}. Iteration
+ * information already present in the UFieldPositionIterator is deleted, and the iterator is reset
+ * to apply to the fields in the formatted string created by this function call. The field values
+ * and indexes returned by {@link #ufieldpositer_next} represent fields denoted by
+ * the UNumberFormatFields enum. Fields are not returned in a guaranteed order. Fields cannot
+ * overlap, but they may nest. For example, 1234 could format as "1,234" which might consist of a
+ * grouping separator field for ',' and an integer field encompassing the entire string.
+ * @param ec Set if an error occurs.
+ * @stable ICU 62
+ */
+U_CAPI void U_EXPORT2
+unumf_resultGetAllFieldPositions(const UFormattedNumber* uresult, UFieldPositionIterator* ufpositer,
+ UErrorCode* ec);
+
+
+/**
+ * Extracts the formatted number as a "numeric string" conforming to the
+ * syntax defined in the Decimal Arithmetic Specification, available at
+ * http://speleotrove.com/decimal
+ *
+ * This endpoint is useful for obtaining the exact number being printed
+ * after scaling and rounding have been applied by the number formatter.
+ *
+ * @param uresult The input object containing the formatted number.
+ * @param dest the 8-bit char buffer into which the decimal number is placed
+ * @param destCapacity The size, in chars, of the destination buffer. May be zero
+ * for precomputing the required size.
+ * @param ec receives any error status.
+ * If U_BUFFER_OVERFLOW_ERROR: Returns number of chars for
+ * preflighting.
+ * @return Number of chars in the data. Does not include a trailing NUL.
+ * @stable ICU 68
+ */
+U_CAPI int32_t U_EXPORT2
+unumf_resultToDecimalNumber(
+ const UFormattedNumber* uresult,
+ char* dest,
+ int32_t destCapacity,
+ UErrorCode* ec);
+
+
+/**
+ * Releases the UFormattedNumber created by unumf_openResult().
+ *
+ * @param uresult An object created by unumf_openResult().
+ * @stable ICU 62
+ */
+U_CAPI void U_EXPORT2
+unumf_closeResult(UFormattedNumber* uresult);
+
+
+#if U_SHOW_CPLUSPLUS_API
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalUFormattedNumberPointer
+ * "Smart pointer" class; closes a UFormattedNumber via unumf_closeResult().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * Usage:
+ * <pre>
+ * LocalUFormattedNumberPointer uformatter(unumf_openResult(...));
+ * // no need to explicitly call unumf_closeResult()
+ * </pre>
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 62
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUFormattedNumberPointer, UFormattedNumber, unumf_closeResult);
+
+U_NAMESPACE_END
+#endif // U_SHOW_CPLUSPLUS_API
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+#endif //__UFORMATTEDNUMBER_H__
#include "unicode/uformattable.h"
#include "unicode/udisplaycontext.h"
#include "unicode/ufieldpositer.h"
+#include "unicode/unumberoptions.h"
#if U_SHOW_CPLUSPLUS_API
#include "unicode/localpointer.h"
UNUM_IGNORE = UNUM_PATTERN_DECIMAL
} UNumberFormatStyle;
-/** The possible number format rounding modes.
- *
- * <p>
- * For more detail on rounding modes, see:
- * https://unicode-org.github.io/icu/userguide/format_parse/numbers/rounding-modes
- *
- * @stable ICU 2.0
- */
-typedef enum UNumberFormatRoundingMode {
- UNUM_ROUND_CEILING,
- UNUM_ROUND_FLOOR,
- UNUM_ROUND_DOWN,
- UNUM_ROUND_UP,
- /**
- * Half-even rounding
- * @stable, ICU 3.8
- */
- UNUM_ROUND_HALFEVEN,
-#ifndef U_HIDE_DEPRECATED_API
- /**
- * Half-even rounding, misspelled name
- * @deprecated, ICU 3.8
- */
- UNUM_FOUND_HALFEVEN = UNUM_ROUND_HALFEVEN,
-#endif /* U_HIDE_DEPRECATED_API */
- UNUM_ROUND_HALFDOWN = UNUM_ROUND_HALFEVEN + 1,
- UNUM_ROUND_HALFUP,
- /**
- * ROUND_UNNECESSARY reports an error if formatted result is not exact.
- * @stable ICU 4.8
- */
- UNUM_ROUND_UNNECESSARY,
- /**
- * Rounds ties toward the odd number.
- * @stable ICU 69
- */
- UNUM_ROUND_HALF_ODD,
- /**
- * Rounds ties toward +∞.
- * @stable ICU 69
- */
- UNUM_ROUND_HALF_CEILING,
- /**
- * Rounds ties toward -∞.
- * @stable ICU 69
- */
- UNUM_ROUND_HALF_FLOOR,
-} UNumberFormatRoundingMode;
-
/** The possible number format pad positions.
* @stable ICU 2.0
*/
#if !UCONFIG_NO_FORMATTING
#include "unicode/parseerr.h"
-#include "unicode/ufieldpositer.h"
-#include "unicode/umisc.h"
-#include "unicode/uformattedvalue.h"
+#include "unicode/unumberoptions.h"
+#include "unicode/uformattednumber.h"
/**
UNUM_UNIT_WIDTH_COUNT = 7
} UNumberUnitWidth;
-/**
- * An enum declaring the strategy for when and how to display grouping separators (i.e., the
- * separator, often a comma or period, after every 2-3 powers of ten). The choices are several
- * pre-built strategies for different use cases that employ locale data whenever possible. Example
- * outputs for 1234 and 1234567 in <em>en-IN</em>:
- *
- * <ul>
- * <li>OFF: 1234 and 12345
- * <li>MIN2: 1234 and 12,34,567
- * <li>AUTO: 1,234 and 12,34,567
- * <li>ON_ALIGNED: 1,234 and 12,34,567
- * <li>THOUSANDS: 1,234 and 1,234,567
- * </ul>
- *
- * <p>
- * The default is AUTO, which displays grouping separators unless the locale data says that grouping
- * is not customary. To force grouping for all numbers greater than 1000 consistently across locales,
- * use ON_ALIGNED. On the other hand, to display grouping less frequently than the default, use MIN2
- * or OFF. See the docs of each option for details.
- *
- * <p>
- * Note: This enum specifies the strategy for grouping sizes. To set which character to use as the
- * grouping separator, use the "symbols" setter.
- *
- * @stable ICU 63
- */
-typedef enum UNumberGroupingStrategy {
- /**
- * Do not display grouping separators in any locale.
- *
- * @stable ICU 61
- */
- UNUM_GROUPING_OFF,
-
- /**
- * Display grouping using locale defaults, except do not show grouping on values smaller than
- * 10000 (such that there is a <em>minimum of two digits</em> before the first separator).
- *
- * <p>
- * Note that locales may restrict grouping separators to be displayed only on 1 million or
- * greater (for example, ee and hu) or disable grouping altogether (for example, bg currency).
- *
- * <p>
- * Locale data is used to determine whether to separate larger numbers into groups of 2
- * (customary in South Asia) or groups of 3 (customary in Europe and the Americas).
- *
- * @stable ICU 61
- */
- UNUM_GROUPING_MIN2,
-
- /**
- * Display grouping using the default strategy for all locales. This is the default behavior.
- *
- * <p>
- * Note that locales may restrict grouping separators to be displayed only on 1 million or
- * greater (for example, ee and hu) or disable grouping altogether (for example, bg currency).
- *
- * <p>
- * Locale data is used to determine whether to separate larger numbers into groups of 2
- * (customary in South Asia) or groups of 3 (customary in Europe and the Americas).
- *
- * @stable ICU 61
- */
- UNUM_GROUPING_AUTO,
-
- /**
- * Always display the grouping separator on values of at least 1000.
- *
- * <p>
- * This option ignores the locale data that restricts or disables grouping, described in MIN2 and
- * AUTO. This option may be useful to normalize the alignment of numbers, such as in a
- * spreadsheet.
- *
- * <p>
- * Locale data is used to determine whether to separate larger numbers into groups of 2
- * (customary in South Asia) or groups of 3 (customary in Europe and the Americas).
- *
- * @stable ICU 61
- */
- UNUM_GROUPING_ON_ALIGNED,
-
- /**
- * Use the Western defaults: groups of 3 and enabled for all numbers 1000 or greater. Do not use
- * locale data for determining the grouping strategy.
- *
- * @stable ICU 61
- */
- UNUM_GROUPING_THOUSANDS
-
-#ifndef U_HIDE_INTERNAL_API
- ,
- /**
- * One more than the highest UNumberGroupingStrategy value.
- *
- * @internal ICU 62: The numeric value may change over time; see ICU ticket #12420.
- */
- UNUM_GROUPING_COUNT
-#endif /* U_HIDE_INTERNAL_API */
-
-} UNumberGroupingStrategy;
-
/**
* An enum declaring how to denote positive and negative numbers. Example outputs when formatting
* 123, 0, and -123 in <em>en-US</em>:
*/
typedef struct UNumberFormatter UNumberFormatter;
-struct UFormattedNumber;
-/**
- * C-compatible version of icu::number::FormattedNumber.
- *
- * NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead.
- *
- * @stable ICU 62
- */
-typedef struct UFormattedNumber UFormattedNumber;
-
/**
* Creates a new UNumberFormatter for the given skeleton string and locale. This is currently the only
const UChar* skeleton, int32_t skeletonLen, const char* locale, UParseError* perror, UErrorCode* ec);
-/**
- * Creates an object to hold the result of a UNumberFormatter
- * operation. The object can be used repeatedly; it is cleared whenever
- * passed to a format function.
- *
- * @param ec Set if an error occurs.
- * @stable ICU 62
- */
-U_CAPI UFormattedNumber* U_EXPORT2
-unumf_openResult(UErrorCode* ec);
-
/**
* Uses a UNumberFormatter to format an integer to a UFormattedNumber. A string, field position, and other
unumf_formatDecimal(const UNumberFormatter* uformatter, const char* value, int32_t valueLen,
UFormattedNumber* uresult, UErrorCode* ec);
-/**
- * Returns a representation of a UFormattedNumber as a UFormattedValue,
- * which can be subsequently passed to any API requiring that type.
- *
- * The returned object is owned by the UFormattedNumber and is valid
- * only as long as the UFormattedNumber is present and unchanged in memory.
- *
- * You can think of this method as a cast between types.
- *
- * @param uresult The object containing the formatted string.
- * @param ec Set if an error occurs.
- * @return A UFormattedValue owned by the input object.
- * @stable ICU 64
- */
-U_CAPI const UFormattedValue* U_EXPORT2
-unumf_resultAsValue(const UFormattedNumber* uresult, UErrorCode* ec);
-
-
-/**
- * Extracts the result number string out of a UFormattedNumber to a UChar buffer if possible.
- * If bufferCapacity is greater than the required length, a terminating NUL is written.
- * If bufferCapacity is less than the required length, an error code is set.
- *
- * Also see ufmtval_getString, which returns a NUL-terminated string:
- *
- * int32_t len;
- * const UChar* str = ufmtval_getString(unumf_resultAsValue(uresult, &ec), &len, &ec);
- *
- * NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead.
- *
- * @param uresult The object containing the formatted number.
- * @param buffer Where to save the string output.
- * @param bufferCapacity The number of UChars available in the buffer.
- * @param ec Set if an error occurs.
- * @return The required length.
- * @stable ICU 62
- */
-U_CAPI int32_t U_EXPORT2
-unumf_resultToString(const UFormattedNumber* uresult, UChar* buffer, int32_t bufferCapacity,
- UErrorCode* ec);
-
-
-/**
- * Determines the start and end indices of the next occurrence of the given <em>field</em> in the
- * output string. This allows you to determine the locations of, for example, the integer part,
- * fraction part, or symbols.
- *
- * This is a simpler but less powerful alternative to {@link ufmtval_nextPosition}.
- *
- * If a field occurs just once, calling this method will find that occurrence and return it. If a
- * field occurs multiple times, this method may be called repeatedly with the following pattern:
- *
- * <pre>
- * UFieldPosition ufpos = {UNUM_GROUPING_SEPARATOR_FIELD, 0, 0};
- * while (unumf_resultNextFieldPosition(uresult, ufpos, &ec)) {
- * // do something with ufpos.
- * }
- * </pre>
- *
- * This method is useful if you know which field to query. If you want all available field position
- * information, use unumf_resultGetAllFieldPositions().
- *
- * NOTE: All fields of the UFieldPosition must be initialized before calling this method.
- *
- * @param uresult The object containing the formatted number.
- * @param ufpos
- * Input+output variable. On input, the "field" property determines which field to look up,
- * and the "endIndex" property determines where to begin the search. On output, the
- * "beginIndex" field is set to the beginning of the first occurrence of the field after the
- * input "endIndex", and "endIndex" is set to the end of that occurrence of the field
- * (exclusive index). If a field position is not found, the FieldPosition is not changed and
- * the method returns false.
- * @param ec Set if an error occurs.
- * @stable ICU 62
- */
-U_CAPI UBool U_EXPORT2
-unumf_resultNextFieldPosition(const UFormattedNumber* uresult, UFieldPosition* ufpos, UErrorCode* ec);
-
-
-/**
- * Populates the given iterator with all fields in the formatted output string. This allows you to
- * determine the locations of the integer part, fraction part, and sign.
- *
- * This is an alternative to the more powerful {@link ufmtval_nextPosition} API.
- *
- * If you need information on only one field, use {@link ufmtval_nextPosition} or
- * {@link unumf_resultNextFieldPosition}.
- *
- * @param uresult The object containing the formatted number.
- * @param ufpositer
- * A pointer to a UFieldPositionIterator created by {@link #ufieldpositer_open}. Iteration
- * information already present in the UFieldPositionIterator is deleted, and the iterator is reset
- * to apply to the fields in the formatted string created by this function call. The field values
- * and indexes returned by {@link #ufieldpositer_next} represent fields denoted by
- * the UNumberFormatFields enum. Fields are not returned in a guaranteed order. Fields cannot
- * overlap, but they may nest. For example, 1234 could format as "1,234" which might consist of a
- * grouping separator field for ',' and an integer field encompassing the entire string.
- * @param ec Set if an error occurs.
- * @stable ICU 62
- */
-U_CAPI void U_EXPORT2
-unumf_resultGetAllFieldPositions(const UFormattedNumber* uresult, UFieldPositionIterator* ufpositer,
- UErrorCode* ec);
-
-
-/**
- * Extracts the formatted number as a "numeric string" conforming to the
- * syntax defined in the Decimal Arithmetic Specification, available at
- * http://speleotrove.com/decimal
- *
- * This endpoint is useful for obtaining the exact number being printed
- * after scaling and rounding have been applied by the number formatter.
- *
- * @param uresult The input object containing the formatted number.
- * @param dest the 8-bit char buffer into which the decimal number is placed
- * @param destCapacity The size, in chars, of the destination buffer. May be zero
- * for precomputing the required size.
- * @param ec receives any error status.
- * If U_BUFFER_OVERFLOW_ERROR: Returns number of chars for
- * preflighting.
- * @return Number of chars in the data. Does not include a trailing NUL.
- * @stable ICU 68
- */
-U_CAPI int32_t U_EXPORT2
-unumf_resultToDecimalNumber(
- const UFormattedNumber* uresult,
- char* dest,
- int32_t destCapacity,
- UErrorCode* ec);
/**
unumf_close(UNumberFormatter* uformatter);
-/**
- * Releases the UFormattedNumber created by unumf_openResult().
- *
- * @param uresult An object created by unumf_openResult().
- * @stable ICU 62
- */
-U_CAPI void U_EXPORT2
-unumf_closeResult(UFormattedNumber* uresult);
-
#if U_SHOW_CPLUSPLUS_API
U_NAMESPACE_BEGIN
*/
U_DEFINE_LOCAL_OPEN_POINTER(LocalUNumberFormatterPointer, UNumberFormatter, unumf_close);
-/**
- * \class LocalUFormattedNumberPointer
- * "Smart pointer" class; closes a UFormattedNumber via unumf_closeResult().
- * For most methods see the LocalPointerBase base class.
- *
- * Usage:
- * <pre>
- * LocalUFormattedNumberPointer uformatter(unumf_openResult(...));
- * // no need to explicitly call unumf_closeResult()
- * </pre>
- *
- * @see LocalPointerBase
- * @see LocalPointer
- * @stable ICU 62
- */
-U_DEFINE_LOCAL_OPEN_POINTER(LocalUFormattedNumberPointer, UFormattedNumber, unumf_closeResult);
-
U_NAMESPACE_END
#endif // U_SHOW_CPLUSPLUS_API
--- /dev/null
+// © 2017 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#ifndef __UNUMBEROPTIONS_H__
+#define __UNUMBEROPTIONS_H__
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+/**
+ * \file
+ * \brief C API: Header-only input options for various number formatting APIs.
+ *
+ * You do not normally need to include this header file directly, because it is included in all
+ * files that use these enums.
+ */
+
+
+/** The possible number format rounding modes.
+ *
+ * <p>
+ * For more detail on rounding modes, see:
+ * https://unicode-org.github.io/icu/userguide/format_parse/numbers/rounding-modes
+ *
+ * @stable ICU 2.0
+ */
+typedef enum UNumberFormatRoundingMode {
+ UNUM_ROUND_CEILING,
+ UNUM_ROUND_FLOOR,
+ UNUM_ROUND_DOWN,
+ UNUM_ROUND_UP,
+ /**
+ * Half-even rounding
+ * @stable, ICU 3.8
+ */
+ UNUM_ROUND_HALFEVEN,
+#ifndef U_HIDE_DEPRECATED_API
+ /**
+ * Half-even rounding, misspelled name
+ * @deprecated, ICU 3.8
+ */
+ UNUM_FOUND_HALFEVEN = UNUM_ROUND_HALFEVEN,
+#endif /* U_HIDE_DEPRECATED_API */
+ UNUM_ROUND_HALFDOWN = UNUM_ROUND_HALFEVEN + 1,
+ UNUM_ROUND_HALFUP,
+ /**
+ * ROUND_UNNECESSARY reports an error if formatted result is not exact.
+ * @stable ICU 4.8
+ */
+ UNUM_ROUND_UNNECESSARY,
+ /**
+ * Rounds ties toward the odd number.
+ * @stable ICU 69
+ */
+ UNUM_ROUND_HALF_ODD,
+ /**
+ * Rounds ties toward +∞.
+ * @stable ICU 69
+ */
+ UNUM_ROUND_HALF_CEILING,
+ /**
+ * Rounds ties toward -∞.
+ * @stable ICU 69
+ */
+ UNUM_ROUND_HALF_FLOOR,
+} UNumberFormatRoundingMode;
+
+
+/**
+ * An enum declaring the strategy for when and how to display grouping separators (i.e., the
+ * separator, often a comma or period, after every 2-3 powers of ten). The choices are several
+ * pre-built strategies for different use cases that employ locale data whenever possible. Example
+ * outputs for 1234 and 1234567 in <em>en-IN</em>:
+ *
+ * <ul>
+ * <li>OFF: 1234 and 12345
+ * <li>MIN2: 1234 and 12,34,567
+ * <li>AUTO: 1,234 and 12,34,567
+ * <li>ON_ALIGNED: 1,234 and 12,34,567
+ * <li>THOUSANDS: 1,234 and 1,234,567
+ * </ul>
+ *
+ * <p>
+ * The default is AUTO, which displays grouping separators unless the locale data says that grouping
+ * is not customary. To force grouping for all numbers greater than 1000 consistently across locales,
+ * use ON_ALIGNED. On the other hand, to display grouping less frequently than the default, use MIN2
+ * or OFF. See the docs of each option for details.
+ *
+ * <p>
+ * Note: This enum specifies the strategy for grouping sizes. To set which character to use as the
+ * grouping separator, use the "symbols" setter.
+ *
+ * @stable ICU 63
+ */
+typedef enum UNumberGroupingStrategy {
+ /**
+ * Do not display grouping separators in any locale.
+ *
+ * @stable ICU 61
+ */
+ UNUM_GROUPING_OFF,
+
+ /**
+ * Display grouping using locale defaults, except do not show grouping on values smaller than
+ * 10000 (such that there is a <em>minimum of two digits</em> before the first separator).
+ *
+ * <p>
+ * Note that locales may restrict grouping separators to be displayed only on 1 million or
+ * greater (for example, ee and hu) or disable grouping altogether (for example, bg currency).
+ *
+ * <p>
+ * Locale data is used to determine whether to separate larger numbers into groups of 2
+ * (customary in South Asia) or groups of 3 (customary in Europe and the Americas).
+ *
+ * @stable ICU 61
+ */
+ UNUM_GROUPING_MIN2,
+
+ /**
+ * Display grouping using the default strategy for all locales. This is the default behavior.
+ *
+ * <p>
+ * Note that locales may restrict grouping separators to be displayed only on 1 million or
+ * greater (for example, ee and hu) or disable grouping altogether (for example, bg currency).
+ *
+ * <p>
+ * Locale data is used to determine whether to separate larger numbers into groups of 2
+ * (customary in South Asia) or groups of 3 (customary in Europe and the Americas).
+ *
+ * @stable ICU 61
+ */
+ UNUM_GROUPING_AUTO,
+
+ /**
+ * Always display the grouping separator on values of at least 1000.
+ *
+ * <p>
+ * This option ignores the locale data that restricts or disables grouping, described in MIN2 and
+ * AUTO. This option may be useful to normalize the alignment of numbers, such as in a
+ * spreadsheet.
+ *
+ * <p>
+ * Locale data is used to determine whether to separate larger numbers into groups of 2
+ * (customary in South Asia) or groups of 3 (customary in Europe and the Americas).
+ *
+ * @stable ICU 61
+ */
+ UNUM_GROUPING_ON_ALIGNED,
+
+ /**
+ * Use the Western defaults: groups of 3 and enabled for all numbers 1000 or greater. Do not use
+ * locale data for determining the grouping strategy.
+ *
+ * @stable ICU 61
+ */
+ UNUM_GROUPING_THOUSANDS
+
+#ifndef U_HIDE_INTERNAL_API
+ ,
+ /**
+ * One more than the highest UNumberGroupingStrategy value.
+ *
+ * @internal ICU 62: The numeric value may change over time; see ICU ticket #12420.
+ */
+ UNUM_GROUPING_COUNT
+#endif /* U_HIDE_INTERNAL_API */
+
+} UNumberGroupingStrategy;
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+#endif //__UNUMBEROPTIONS_H__
--- /dev/null
+// © 2022 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#ifndef __USIMPLENUMBERFORMATTER_H__
+#define __USIMPLENUMBERFORMATTER_H__
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/uformattednumber.h"
+#include "unicode/unumberoptions.h"
+
+/**
+ * \file
+ * \brief C API: Simple number formatting focused on low memory and code size.
+ *
+ * These functions render locale-aware number strings but without the bells and whistles found in
+ * other number formatting APIs such as those in unumberformatter.h, like units and currencies.
+ *
+ * <pre>
+ * LocalUSimpleNumberFormatterPointer uformatter(usnumf_openForLocale("de-CH", status));
+ * LocalUFormattedNumberPointer uresult(unumf_openResult(status));
+ * usnumf_formatInt64(uformatter.getAlias(), 55, uresult.getAlias(), status);
+ * assertEquals("",
+ * u"55",
+ * ufmtval_getString(unumf_resultAsValue(uresult.getAlias(), status), nullptr, status));
+ * </pre>
+ */
+
+#ifndef U_HIDE_DRAFT_API
+
+
+/**
+ * An explicit sign option for a SimpleNumber.
+ *
+ * @draft ICU 73
+ */
+typedef enum USimpleNumberSign {
+ /**
+ * Render a plus sign.
+ *
+ * @draft ICU 73
+ */
+ UNUM_SIMPLE_NUMBER_PLUS_SIGN,
+ /**
+ * Render no sign.
+ *
+ * @draft ICU 73
+ */
+ UNUM_SIMPLE_NUMBER_NO_SIGN,
+ /**
+ * Render a minus sign.
+ *
+ * @draft ICU 73
+ */
+ UNUM_SIMPLE_NUMBER_MINUS_SIGN,
+} USimpleNumberSign;
+
+
+struct USimpleNumber;
+/**
+ * C-compatible version of icu::number::SimpleNumber.
+ *
+ * @draft ICU 73
+ */
+typedef struct USimpleNumber USimpleNumber;
+
+
+struct USimpleNumberFormatter;
+/**
+ * C-compatible version of icu::number::SimpleNumberFormatter.
+ *
+ * @draft ICU 73
+ */
+typedef struct USimpleNumberFormatter USimpleNumberFormatter;
+
+
+/**
+ * Creates a new USimpleNumber to be formatted with a USimpleNumberFormatter.
+ *
+ * @draft ICU 73
+ */
+U_CAPI USimpleNumber* U_EXPORT2
+usnum_openForInt64(int64_t value, UErrorCode* ec);
+
+
+/**
+ * Changes the value of the USimpleNumber by a power of 10.
+ *
+ * This function immediately mutates the inner value.
+ *
+ * @draft ICU 73
+ */
+U_CAPI void U_EXPORT2
+usnum_multiplyByPowerOfTen(USimpleNumber* unumber, int32_t power, UErrorCode* ec);
+
+
+/**
+ * Rounds the value currently stored in the USimpleNumber to the given power of 10.
+ *
+ * This function immediately mutates the inner value.
+ *
+ * @draft ICU 73
+ */
+U_CAPI void U_EXPORT2
+usnum_roundTo(USimpleNumber* unumber, int32_t power, UNumberFormatRoundingMode roundingMode, UErrorCode* ec);
+
+
+/**
+ * Pads the beginning of the number with zeros up to the given minimum number of integer digits.
+ *
+ * This setting is applied upon formatting the number.
+ *
+ * @draft ICU 73
+ */
+U_CAPI void U_EXPORT2
+usnum_setMinimumIntegerDigits(USimpleNumber* unumber, int32_t minimumIntegerDigits, UErrorCode* ec);
+
+
+/**
+ * Pads the end of the number with zeros up to the given minimum number of fraction digits.
+ *
+ * This setting is applied upon formatting the number.
+ *
+ * @draft ICU 73
+ */
+U_CAPI void U_EXPORT2
+usnum_setMinimumFractionDigits(USimpleNumber* unumber, int32_t minimumFractionDigits, UErrorCode* ec);
+
+
+/**
+ * Truncates digits from the beginning of the number to the given maximum number of integer digits.
+ *
+ * This function immediately mutates the inner value.
+ *
+ * @draft ICU 73
+ */
+U_CAPI void U_EXPORT2
+usnum_truncateStart(USimpleNumber* unumber, int32_t maximumIntegerDigits, UErrorCode* ec);
+
+
+/**
+ * Sets the sign of the number: an explicit plus sign, explicit minus sign, or no sign.
+ *
+ * This setting is applied upon formatting the number.
+ *
+ * NOTE: This does not support accounting sign notation.
+ *
+ * @draft ICU 73
+ */
+U_CAPI void U_EXPORT2
+usnum_setSign(USimpleNumber* unumber, USimpleNumberSign sign, UErrorCode* ec);
+
+
+/**
+ * Creates a new USimpleNumberFormatter with all locale defaults.
+ *
+ * @draft ICU 73
+ */
+U_CAPI USimpleNumberFormatter* U_EXPORT2
+usnumf_openForLocale(const char* locale, UErrorCode* ec);
+
+
+/**
+ * Creates a new USimpleNumberFormatter, overriding the grouping strategy.
+ *
+ * @draft ICU 73
+ */
+U_CAPI USimpleNumberFormatter* U_EXPORT2
+usnumf_openForLocaleAndGroupingStrategy(
+ const char* locale, UNumberGroupingStrategy groupingStrategy, UErrorCode* ec);
+
+
+/**
+ * Formats a number using this SimpleNumberFormatter.
+ *
+ * The USimpleNumber is adopted and must not be freed after calling this function,
+ * even if the function sets an error code. If you use LocalUSimpleNumberPointer,
+ * call `.orphan()` when passing it to this function.
+ *
+ * @draft ICU 73
+ */
+U_CAPI void U_EXPORT2
+usnumf_formatAndAdoptNumber(
+ const USimpleNumberFormatter* uformatter,
+ USimpleNumber* unumber,
+ UFormattedNumber* uresult,
+ UErrorCode* ec);
+
+
+/**
+ * Formats an integer using this SimpleNumberFormatter.
+ *
+ * For more control over the formatting, use USimpleNumber.
+ *
+ * @draft ICU 73
+ */
+U_CAPI void U_EXPORT2
+usnumf_formatInt64(
+ const USimpleNumberFormatter* uformatter,
+ int64_t value,
+ UFormattedNumber* uresult,
+ UErrorCode* ec);
+
+
+/**
+ * Frees the memory held by a USimpleNumber.
+ *
+ * NOTE: Normally, a USimpleNumber should be adopted by usnumf_formatAndAdoptNumber.
+ *
+ * @draft ICU 73
+ */
+U_CAPI void U_EXPORT2
+usnum_close(USimpleNumber* unumber);
+
+
+/**
+ * Frees the memory held by a USimpleNumberFormatter.
+ *
+ * @draft ICU 73
+ */
+U_CAPI void U_EXPORT2
+usnumf_close(USimpleNumberFormatter* uformatter);
+
+
+#if U_SHOW_CPLUSPLUS_API
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalUSimpleNumberPointer
+ * "Smart pointer" class; closes a USimpleNumber via usnum_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * NOTE: Normally, a USimpleNumber should be adopted by usnumf_formatAndAdoptNumber.
+ * If you use LocalUSimpleNumberPointer, call `.orphan()` when passing to that function.
+ *
+ * Usage:
+ * <pre>
+ * LocalUSimpleNumberPointer uformatter(usnumf_openForInteger(...));
+ * // no need to explicitly call usnum_close()
+ * </pre>
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @draft ICU 73
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUSimpleNumberPointer, USimpleNumber, usnum_close);
+
+/**
+ * \class LocalUSimpleNumberFormatterPointer
+ * "Smart pointer" class; closes a USimpleNumberFormatter via usnumf_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * Usage:
+ * <pre>
+ * LocalUSimpleNumberFormatterPointer uformatter(usnumf_openForLocale(...));
+ * // no need to explicitly call usnumf_close()
+ * </pre>
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @draft ICU 73
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUSimpleNumberFormatterPointer, USimpleNumberFormatter, usnumf_close);
+
+U_NAMESPACE_END
+#endif // U_SHOW_CPLUSPLUS_API
+
+#endif // U_HIDE_DRAFT_API
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+#endif //__USIMPLENUMBERFORMATTER_H__
number_scientific.o
currpinf.o
numrange_fluent.o numrange_impl.o
+ # NOTE: This could go into its own dependency block, but it would require
+ # refactoring more of the dependencies (e.g. removing class methods).
+ number_simple.o
deps
decnumber double_conversion formattable units unitsformatter
listformatter number_representation number_output
numbertest_parse.o numbertest_doubleconversion.o numbertest_skeletons.o \
static_unisets_test.o numfmtdatadriventest.o numbertest_range.o erarulestest.o \
formattedvaluetest.o formatted_string_builder_test.o numbertest_permutation.o \
-units_data_test.o units_router_test.o units_test.o displayoptions_test.o
+units_data_test.o units_router_test.o units_test.o displayoptions_test.o \
+numbertest_simple.o
DEPS = $(OBJECTS:.o=.d)
<ClCompile Include="numbertest_doubleconversion.cpp" />
<ClCompile Include="numbertest_skeletons.cpp" />
<ClCompile Include="numbertest_range.cpp" />
+ <ClCompile Include="numbertest_simple.cpp" />
<ClCompile Include="numbertest_permutation.cpp" />
<ClCompile Include="numfmtst.cpp" />
<ClCompile Include="numfmtdatadriventest.cpp" />
<ClCompile Include="numbertest_range.cpp">
<Filter>formatting</Filter>
</ClCompile>
+ <ClCompile Include="numbertest_simple.cpp">
+ <Filter>formatting</Filter>
+ </ClCompile>
<ClCompile Include="numbertest_permutation.cpp">
<Filter>formatting</Filter>
</ClCompile>
const char16_t* expected);
};
+class SimpleNumberFormatterTest : public IntlTestWithFieldPosition {
+ public:
+ void testBasic();
+ void testWithOptions();
+ void testSymbols();
+ void testSign();
+ void testCopyMove();
+ void testCAPI();
+
+ void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par = 0) override;
+};
+
class NumberPermutationTest : public IntlTest {
public:
void testPermutations();
TESTCLASS(7, NumberParserTest);
TESTCLASS(8, NumberSkeletonTest);
TESTCLASS(9, NumberRangeFormatterTest);
- TESTCLASS(10, NumberPermutationTest);
+ TESTCLASS(10, SimpleNumberFormatterTest);
+ TESTCLASS(11, NumberPermutationTest);
default: name = ""; break; // needed to end loop
}
}
--- /dev/null
+// © 2018 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include <cmath>
+
+#include "numbertest.h"
+#include "unicode/simplenumberformatter.h"
+
+
+void SimpleNumberFormatterTest::runIndexedTest(int32_t index, UBool exec, const char*& name, char*) {
+ if (exec) {
+ logln("TestSuite SimpleNumberFormatterTest: ");
+ }
+ TESTCASE_AUTO_BEGIN;
+ TESTCASE_AUTO(testBasic);
+ TESTCASE_AUTO(testWithOptions);
+ TESTCASE_AUTO(testSymbols);
+ TESTCASE_AUTO(testSign);
+ TESTCASE_AUTO(testCopyMove);
+ TESTCASE_AUTO(testCAPI);
+ TESTCASE_AUTO_END;
+}
+
+void SimpleNumberFormatterTest::testBasic() {
+ IcuTestErrorCode status(*this, "testBasic");
+
+ SimpleNumberFormatter snf = SimpleNumberFormatter::forLocale("de-CH", status);
+ FormattedNumber result = snf.formatInt64(-1000007, status);
+
+ static const UFieldPosition expectedFieldPositions[] = {
+ // field, begin index, end index
+ {UNUM_SIGN_FIELD, 0, 1},
+ {UNUM_GROUPING_SEPARATOR_FIELD, 2, 3},
+ {UNUM_GROUPING_SEPARATOR_FIELD, 6, 7},
+ {UNUM_INTEGER_FIELD, 1, 10},
+ };
+ checkFormattedValue(
+ u"testBasic",
+ result,
+ u"-1’000’007",
+ UFIELD_CATEGORY_NUMBER,
+ expectedFieldPositions,
+ UPRV_LENGTHOF(expectedFieldPositions));
+}
+
+void SimpleNumberFormatterTest::testWithOptions() {
+ IcuTestErrorCode status(*this, "testWithOptions");
+
+ SimpleNumber num = SimpleNumber::forInt64(1250000, status);
+ num.setMinimumIntegerDigits(6, status);
+ num.setMinimumFractionDigits(2, status);
+ num.multiplyByPowerOfTen(-2, status);
+ num.roundTo(3, UNUM_ROUND_HALFUP, status);
+ num.truncateStart(4, status);
+ SimpleNumberFormatter snf = SimpleNumberFormatter::forLocale("bn", status);
+ FormattedNumber result = snf.format(std::move(num), status);
+
+ static const UFieldPosition expectedFieldPositions[] = {
+ // field, begin index, end index
+ {UNUM_GROUPING_SEPARATOR_FIELD, 1, 2},
+ {UNUM_GROUPING_SEPARATOR_FIELD, 4, 5},
+ {UNUM_INTEGER_FIELD, 0, 8},
+ {UNUM_DECIMAL_SEPARATOR_FIELD, 8, 9},
+ {UNUM_FRACTION_FIELD, 9, 11},
+ };
+ checkFormattedValue(
+ u"testWithOptions",
+ result,
+ u"০,০৩,০০০.০০",
+ UFIELD_CATEGORY_NUMBER,
+ expectedFieldPositions,
+ UPRV_LENGTHOF(expectedFieldPositions));
+}
+
+void SimpleNumberFormatterTest::testSymbols() {
+ IcuTestErrorCode status(*this, "testSymbols");
+
+ LocalPointer<DecimalFormatSymbols> symbols(new DecimalFormatSymbols("bn", status), status);
+ SimpleNumberFormatter snf = SimpleNumberFormatter::forLocaleAndSymbolsAndGroupingStrategy(
+ "en-US",
+ *symbols,
+ UNUM_GROUPING_ON_ALIGNED,
+ status
+ );
+ auto result = snf.formatInt64(987654321, status);
+
+ assertEquals("bn symbols with en-US pattern",
+ u"৯৮৭,৬৫৪,৩২১",
+ result.toTempString(status));
+}
+
+void SimpleNumberFormatterTest::testSign() {
+ IcuTestErrorCode status(*this, "testSign");
+
+ SimpleNumberFormatter snf = SimpleNumberFormatter::forLocale("und", status);
+
+ struct TestCase {
+ int64_t input;
+ USimpleNumberSign sign;
+ const char16_t* expected;
+ } cases[] = {
+ { 1, UNUM_SIMPLE_NUMBER_NO_SIGN, u"1" },
+ { 1, UNUM_SIMPLE_NUMBER_PLUS_SIGN, u"+1" },
+ { 1, UNUM_SIMPLE_NUMBER_MINUS_SIGN, u"-1" },
+ { 0, UNUM_SIMPLE_NUMBER_NO_SIGN, u"0" },
+ { 0, UNUM_SIMPLE_NUMBER_PLUS_SIGN, u"+0" },
+ { 0, UNUM_SIMPLE_NUMBER_MINUS_SIGN, u"-0" },
+ { -1, UNUM_SIMPLE_NUMBER_NO_SIGN, u"1" },
+ { -1, UNUM_SIMPLE_NUMBER_PLUS_SIGN, u"+1" },
+ { -1, UNUM_SIMPLE_NUMBER_MINUS_SIGN, u"-1" },
+ };
+ for (auto& cas : cases) {
+ SimpleNumber num = SimpleNumber::forInt64(cas.input, status);
+ num.setSign(cas.sign, status);
+ auto result = snf.format(std::move(num), status);
+ assertEquals("", cas.expected, result.toTempString(status));
+ }
+}
+
+void SimpleNumberFormatterTest::testCopyMove() {
+ IcuTestErrorCode status(*this, "testCopyMove");
+
+ SimpleNumberFormatter snf0 = SimpleNumberFormatter::forLocale("und", status);
+
+ SimpleNumber sn0 = SimpleNumber::forInt64(55, status);
+ SimpleNumber sn1 = std::move(sn0);
+
+ snf0.format(std::move(sn0), status);
+ status.expectErrorAndReset(U_ILLEGAL_ARGUMENT_ERROR, "Use of moved number");
+
+ assertEquals("Move number constructor",
+ u"55",
+ snf0.format(std::move(sn1), status).toTempString(status));
+
+ SimpleNumber sn2;
+ snf0.format(std::move(sn2), status);
+ status.expectErrorAndReset(U_ILLEGAL_ARGUMENT_ERROR, "Default constructed number");
+
+ sn0 = SimpleNumber::forInt64(44, status);
+
+ assertEquals("Move number assignment",
+ u"44",
+ snf0.format(std::move(sn0), status).toTempString(status));
+
+ SimpleNumberFormatter snf1 = std::move(snf0);
+
+ snf0.format(SimpleNumber::forInt64(22, status), status);
+ status.expectErrorAndReset(U_INVALID_STATE_ERROR, "Use of moved formatter");
+
+ assertEquals("Move formatter constructor",
+ u"33",
+ snf1.format(SimpleNumber::forInt64(33, status), status).toTempString(status));
+
+ SimpleNumberFormatter snf2;
+ snf2.format(SimpleNumber::forInt64(22, status), status);
+ status.expectErrorAndReset(U_INVALID_STATE_ERROR, "Default constructed formatter");
+
+ snf0 = std::move(snf1);
+
+ assertEquals("Move formatter assignment",
+ u"22",
+ snf0.format(SimpleNumber::forInt64(22, status), status).toTempString(status));
+
+ snf0 = SimpleNumberFormatter::forLocale("de", status);
+ sn0 = SimpleNumber::forInt64(22, status);
+ sn0 = SimpleNumber::forInt64(11, status);
+
+ assertEquals("Move assignment with nonempty fields",
+ u"11",
+ snf0.format(std::move(sn0), status).toTempString(status));
+}
+
+void SimpleNumberFormatterTest::testCAPI() {
+ IcuTestErrorCode status(*this, "testCAPI");
+
+ LocalUSimpleNumberFormatterPointer uformatter(usnumf_openForLocale("de-CH", status));
+ LocalUFormattedNumberPointer uresult(unumf_openResult(status));
+ usnumf_formatInt64(uformatter.getAlias(), 55, uresult.getAlias(), status);
+ assertEquals("",
+ u"55",
+ ufmtval_getString(unumf_resultAsValue(uresult.getAlias(), status), nullptr, status));
+
+ LocalUSimpleNumberPointer unumber(usnum_openForInt64(44, status));
+ usnumf_formatAndAdoptNumber(uformatter.getAlias(), unumber.orphan(), uresult.getAlias(), status);
+ assertEquals("",
+ u"44",
+ ufmtval_getString(unumf_resultAsValue(uresult.getAlias(), status), nullptr, status));
+
+ unumber.adoptInstead(usnum_openForInt64(2335, status));
+ usnum_multiplyByPowerOfTen(unumber.getAlias(), -2, status);
+ usnum_roundTo(unumber.getAlias(), -1, UNUM_ROUND_HALFEVEN, status);
+ usnum_truncateStart(unumber.getAlias(), 1, status);
+ usnum_setMinimumFractionDigits(unumber.getAlias(), 3, status);
+ usnum_setMinimumIntegerDigits(unumber.getAlias(), 3, status);
+ usnumf_formatAndAdoptNumber(uformatter.getAlias(), unumber.orphan(), uresult.getAlias(), status);
+ assertEquals("",
+ u"003.400",
+ ufmtval_getString(unumf_resultAsValue(uresult.getAlias(), status), nullptr, status));
+}
+
+
+#endif