// © 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 // Allow implicit conversion from char16_t* to UnicodeString for this file: // Helpful in toString methods and elsewhere. #define UNISTR_FROM_STRING_EXPLICIT #include "fphdlimp.h" #include "number_utypes.h" #include "numparse_types.h" #include "formattedval_impl.h" #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; using namespace icu::number::impl; U_NAMESPACE_BEGIN namespace number { namespace impl { /** * Implementation class for UNumberFormatter. Wraps a LocalizedNumberFormatter. */ struct UNumberFormatterData : public UMemory, // Magic number as ASCII == "NFR" (NumberFormatteR) public IcuCApiHelper { LocalizedNumberFormatter fFormatter; }; /** * Implementation class for USimpleNumber. Wraps a SimpleNumberFormatter. */ struct USimpleNumberData : public UMemory, // Magic number as ASCII == "SNM" (SimpleNuMber) public IcuCApiHelper { SimpleNumber fNumber; }; /** * Implementation class for USimpleNumberFormatter. Wraps a SimpleNumberFormatter. */ struct USimpleNumberFormatterData : public UMemory, // Magic number as ASCII == "SNF" (SimpleNumberFormatter) public IcuCApiHelper { SimpleNumberFormatter fFormatter; }; struct UFormattedNumberImpl; // Magic number as ASCII == "FDN" (FormatteDNumber) typedef IcuCApiHelper UFormattedNumberApiHelper; struct UFormattedNumberImpl : public UFormattedValueImpl, public UFormattedNumberApiHelper { UFormattedNumberImpl(); ~UFormattedNumberImpl(); FormattedNumber fImpl; UFormattedNumberData fData; void setTo(FormattedNumber value); }; UFormattedNumberImpl::UFormattedNumberImpl() : fImpl(&fData) { fFormattedValue = &fImpl; } UFormattedNumberImpl::~UFormattedNumberImpl() { // Disown the data from fImpl so it doesn't get deleted twice fImpl.fData = nullptr; } void UFormattedNumberImpl::setTo(FormattedNumber value) { fData = std::move(*value.fData); } } } U_NAMESPACE_END UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL( UFormattedNumber, UFormattedNumberImpl, UFormattedNumberApiHelper, unumf) const DecimalQuantity* icu::number::impl::validateUFormattedNumberToDecimalQuantity( const UFormattedNumber* uresult, UErrorCode& status) { auto* result = UFormattedNumberApiHelper::validate(uresult, status); if (U_FAILURE(status)) { return nullptr; } return &result->fData.quantity; } U_CAPI UNumberFormatter* U_EXPORT2 unumf_openForSkeletonAndLocale(const char16_t* skeleton, int32_t skeletonLen, const char* locale, UErrorCode* ec) { auto* impl = new UNumberFormatterData(); if (impl == nullptr) { *ec = U_MEMORY_ALLOCATION_ERROR; return nullptr; } // Readonly-alias constructor (first argument is whether we are NUL-terminated) UnicodeString skeletonString(skeletonLen == -1, skeleton, skeletonLen); impl->fFormatter = NumberFormatter::forSkeleton(skeletonString, *ec).locale(locale); return impl->exportForC(); } U_CAPI UNumberFormatter* U_EXPORT2 unumf_openForSkeletonAndLocaleWithError(const char16_t* skeleton, int32_t skeletonLen, const char* locale, UParseError* perror, UErrorCode* ec) { auto* impl = new UNumberFormatterData(); if (impl == nullptr) { *ec = U_MEMORY_ALLOCATION_ERROR; return nullptr; } // Readonly-alias constructor (first argument is whether we are NUL-terminated) UnicodeString skeletonString(skeletonLen == -1, skeleton, skeletonLen); UParseError tempParseError; impl->fFormatter = NumberFormatter::forSkeleton(skeletonString, (perror == nullptr) ? tempParseError : *perror, *ec).locale(locale); return impl->exportForC(); } U_CAPI void U_EXPORT2 unumf_formatInt(const UNumberFormatter* uformatter, int64_t value, UFormattedNumber* uresult, UErrorCode* ec) { const UNumberFormatterData* formatter = UNumberFormatterData::validate(uformatter, *ec); auto* result = UFormattedNumberApiHelper::validate(uresult, *ec); if (U_FAILURE(*ec)) { return; } result->fData.resetString(); result->fData.quantity.clear(); result->fData.quantity.setToLong(value); formatter->fFormatter.formatImpl(&result->fData, *ec); } U_CAPI void U_EXPORT2 unumf_formatDouble(const UNumberFormatter* uformatter, double value, UFormattedNumber* uresult, UErrorCode* ec) { const UNumberFormatterData* formatter = UNumberFormatterData::validate(uformatter, *ec); auto* result = UFormattedNumberApiHelper::validate(uresult, *ec); if (U_FAILURE(*ec)) { return; } result->fData.resetString(); result->fData.quantity.clear(); result->fData.quantity.setToDouble(value); formatter->fFormatter.formatImpl(&result->fData, *ec); } U_CAPI void U_EXPORT2 unumf_formatDecimal(const UNumberFormatter* uformatter, const char* value, int32_t valueLen, UFormattedNumber* uresult, UErrorCode* ec) { const UNumberFormatterData* formatter = UNumberFormatterData::validate(uformatter, *ec); auto* result = UFormattedNumberApiHelper::validate(uresult, *ec); if (U_FAILURE(*ec)) { return; } result->fData.resetString(); result->fData.quantity.clear(); result->fData.quantity.setToDecNumber({value, valueLen}, *ec); if (U_FAILURE(*ec)) { return; } formatter->fFormatter.formatImpl(&result->fData, *ec); } U_CAPI int32_t U_EXPORT2 unumf_resultToString(const UFormattedNumber* uresult, char16_t* buffer, int32_t bufferCapacity, UErrorCode* ec) { const auto* result = UFormattedNumberApiHelper::validate(uresult, *ec); if (U_FAILURE(*ec)) { return 0; } if (buffer == nullptr ? bufferCapacity != 0 : bufferCapacity < 0) { *ec = U_ILLEGAL_ARGUMENT_ERROR; return 0; } return result->fData.toTempString(*ec).extract(buffer, bufferCapacity, *ec); } U_CAPI UBool U_EXPORT2 unumf_resultNextFieldPosition(const UFormattedNumber* uresult, UFieldPosition* ufpos, UErrorCode* ec) { const auto* result = UFormattedNumberApiHelper::validate(uresult, *ec); if (U_FAILURE(*ec)) { return false; } if (ufpos == nullptr) { *ec = U_ILLEGAL_ARGUMENT_ERROR; return false; } FieldPosition fp; fp.setField(ufpos->field); fp.setBeginIndex(ufpos->beginIndex); fp.setEndIndex(ufpos->endIndex); bool retval = result->fData.nextFieldPosition(fp, *ec); ufpos->beginIndex = fp.getBeginIndex(); ufpos->endIndex = fp.getEndIndex(); // NOTE: MSVC sometimes complains when implicitly converting between bool and UBool return retval ? true : false; } U_CAPI void U_EXPORT2 unumf_resultGetAllFieldPositions(const UFormattedNumber* uresult, UFieldPositionIterator* ufpositer, UErrorCode* ec) { const auto* result = UFormattedNumberApiHelper::validate(uresult, *ec); if (U_FAILURE(*ec)) { return; } if (ufpositer == nullptr) { *ec = U_ILLEGAL_ARGUMENT_ERROR; return; } auto* fpi = reinterpret_cast(ufpositer); FieldPositionIteratorHandler fpih(fpi, *ec); result->fData.getAllFieldPositions(fpih, *ec); } U_CAPI int32_t U_EXPORT2 unumf_resultToDecimalNumber( const UFormattedNumber* uresult, char* dest, int32_t destCapacity, UErrorCode* ec) { const auto* result = UFormattedNumberApiHelper::validate(uresult, *ec); if (U_FAILURE(*ec)) { return 0; } DecNum decnum; return result->fData.quantity .toDecNum(decnum, *ec) .toCharString(*ec) .extract(dest, destCapacity, *ec); } U_CAPI void U_EXPORT2 unumf_close(UNumberFormatter* f) { UErrorCode localStatus = U_ZERO_ERROR; const UNumberFormatterData* impl = UNumberFormatterData::validate(f, localStatus); delete impl; } ///// SIMPLE NUMBER FORMATTER ///// U_CAPI USimpleNumber* U_EXPORT2 usnum_openForInt64(int64_t value, UErrorCode* ec) { auto* number = new USimpleNumberData(); if (number == nullptr) { *ec = U_MEMORY_ALLOCATION_ERROR; return nullptr; } number->fNumber = SimpleNumber::forInt64(value, *ec); return number->exportForC(); } U_CAPI void U_EXPORT2 usnum_setToInt64(USimpleNumber* unumber, int64_t value, UErrorCode* ec) { auto* number = USimpleNumberData::validate(unumber, *ec); if (U_FAILURE(*ec)) { return; } number->fNumber = SimpleNumber::forInt64(value, *ec); } 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_format( 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)) { return; } auto localResult = formatter->fFormatter.format(std::move(number->fNumber), *ec); if (U_FAILURE(*ec)) { return; } result->setTo(std::move(localResult)); } 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 */