diff options
Diffstat (limited to '')
-rw-r--r-- | intl/icu/source/i18n/numrange_fluent.cpp | 410 |
1 files changed, 410 insertions, 0 deletions
diff --git a/intl/icu/source/i18n/numrange_fluent.cpp b/intl/icu/source/i18n/numrange_fluent.cpp new file mode 100644 index 0000000000..1b2ebc6e61 --- /dev/null +++ b/intl/icu/source/i18n/numrange_fluent.cpp @@ -0,0 +1,410 @@ +// © 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 "numrange_impl.h" +#include "util.h" +#include "number_utypes.h" +#include "number_decnum.h" + +using namespace icu; +using namespace icu::number; +using namespace icu::number::impl; + + +// This function needs to be declared in this namespace so it can be friended. +// NOTE: In Java, this logic is handled in the resolve() function. +void icu::number::impl::touchRangeLocales(RangeMacroProps& macros) { + macros.formatter1.fMacros.locale = macros.locale; + macros.formatter2.fMacros.locale = macros.locale; +} + + +template<typename Derived> +Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(const UnlocalizedNumberFormatter& formatter) const& { + Derived copy(*this); + copy.fMacros.formatter1 = formatter; + copy.fMacros.singleFormatter = true; + touchRangeLocales(copy.fMacros); + return copy; +} + +template<typename Derived> +Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(const UnlocalizedNumberFormatter& formatter) && { + Derived move(std::move(*this)); + move.fMacros.formatter1 = formatter; + move.fMacros.singleFormatter = true; + touchRangeLocales(move.fMacros); + return move; +} + +template<typename Derived> +Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(UnlocalizedNumberFormatter&& formatter) const& { + Derived copy(*this); + copy.fMacros.formatter1 = std::move(formatter); + copy.fMacros.singleFormatter = true; + touchRangeLocales(copy.fMacros); + return copy; +} + +template<typename Derived> +Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(UnlocalizedNumberFormatter&& formatter) && { + Derived move(std::move(*this)); + move.fMacros.formatter1 = std::move(formatter); + move.fMacros.singleFormatter = true; + touchRangeLocales(move.fMacros); + return move; +} + +template<typename Derived> +Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(const UnlocalizedNumberFormatter& formatter) const& { + Derived copy(*this); + copy.fMacros.formatter1 = formatter; + copy.fMacros.singleFormatter = false; + touchRangeLocales(copy.fMacros); + return copy; +} + +template<typename Derived> +Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(const UnlocalizedNumberFormatter& formatter) && { + Derived move(std::move(*this)); + move.fMacros.formatter1 = formatter; + move.fMacros.singleFormatter = false; + touchRangeLocales(move.fMacros); + return move; +} + +template<typename Derived> +Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(UnlocalizedNumberFormatter&& formatter) const& { + Derived copy(*this); + copy.fMacros.formatter1 = std::move(formatter); + copy.fMacros.singleFormatter = false; + touchRangeLocales(copy.fMacros); + return copy; +} + +template<typename Derived> +Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(UnlocalizedNumberFormatter&& formatter) && { + Derived move(std::move(*this)); + move.fMacros.formatter1 = std::move(formatter); + move.fMacros.singleFormatter = false; + touchRangeLocales(move.fMacros); + return move; +} + +template<typename Derived> +Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(const UnlocalizedNumberFormatter& formatter) const& { + Derived copy(*this); + copy.fMacros.formatter2 = formatter; + copy.fMacros.singleFormatter = false; + touchRangeLocales(copy.fMacros); + return copy; +} + +template<typename Derived> +Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(const UnlocalizedNumberFormatter& formatter) && { + Derived move(std::move(*this)); + move.fMacros.formatter2 = formatter; + move.fMacros.singleFormatter = false; + touchRangeLocales(move.fMacros); + return move; +} + +template<typename Derived> +Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(UnlocalizedNumberFormatter&& formatter) const& { + Derived copy(*this); + copy.fMacros.formatter2 = std::move(formatter); + copy.fMacros.singleFormatter = false; + touchRangeLocales(copy.fMacros); + return copy; +} + +template<typename Derived> +Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(UnlocalizedNumberFormatter&& formatter) && { + Derived move(std::move(*this)); + move.fMacros.formatter2 = std::move(formatter); + move.fMacros.singleFormatter = false; + touchRangeLocales(move.fMacros); + return move; +} + +template<typename Derived> +Derived NumberRangeFormatterSettings<Derived>::collapse(UNumberRangeCollapse collapse) const& { + Derived copy(*this); + copy.fMacros.collapse = collapse; + return copy; +} + +template<typename Derived> +Derived NumberRangeFormatterSettings<Derived>::collapse(UNumberRangeCollapse collapse) && { + Derived move(std::move(*this)); + move.fMacros.collapse = collapse; + return move; +} + +template<typename Derived> +Derived NumberRangeFormatterSettings<Derived>::identityFallback(UNumberRangeIdentityFallback identityFallback) const& { + Derived copy(*this); + copy.fMacros.identityFallback = identityFallback; + return copy; +} + +template<typename Derived> +Derived NumberRangeFormatterSettings<Derived>::identityFallback(UNumberRangeIdentityFallback identityFallback) && { + Derived move(std::move(*this)); + move.fMacros.identityFallback = identityFallback; + return move; +} + +template<typename Derived> +LocalPointer<Derived> NumberRangeFormatterSettings<Derived>::clone() const & { + return LocalPointer<Derived>(new Derived(*this)); +} + +template<typename Derived> +LocalPointer<Derived> NumberRangeFormatterSettings<Derived>::clone() && { + return LocalPointer<Derived>(new Derived(std::move(*this))); +} + +// Declare all classes that implement NumberRangeFormatterSettings +// See https://stackoverflow.com/a/495056/1407170 +template +class icu::number::NumberRangeFormatterSettings<icu::number::UnlocalizedNumberRangeFormatter>; +template +class icu::number::NumberRangeFormatterSettings<icu::number::LocalizedNumberRangeFormatter>; + + +UnlocalizedNumberRangeFormatter NumberRangeFormatter::with() { + UnlocalizedNumberRangeFormatter result; + return result; +} + +LocalizedNumberRangeFormatter NumberRangeFormatter::withLocale(const Locale& locale) { + return with().locale(locale); +} + + +template<typename T> using NFS = NumberRangeFormatterSettings<T>; +using LNF = LocalizedNumberRangeFormatter; +using UNF = UnlocalizedNumberRangeFormatter; + +UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(const UNF& other) + : UNF(static_cast<const NFS<UNF>&>(other)) {} + +UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(const NFS<UNF>& other) + : NFS<UNF>(other) { + // No additional fields to assign +} + +// Make default copy constructor call the NumberRangeFormatterSettings copy constructor. +UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(UNF&& src) noexcept + : UNF(static_cast<NFS<UNF>&&>(src)) {} + +UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(NFS<UNF>&& src) noexcept + : NFS<UNF>(std::move(src)) { + // No additional fields to assign +} + +UnlocalizedNumberRangeFormatter& UnlocalizedNumberRangeFormatter::operator=(const UNF& other) { + NFS<UNF>::operator=(static_cast<const NFS<UNF>&>(other)); + // No additional fields to assign + return *this; +} + +UnlocalizedNumberRangeFormatter& UnlocalizedNumberRangeFormatter::operator=(UNF&& src) noexcept { + NFS<UNF>::operator=(static_cast<NFS<UNF>&&>(src)); + // No additional fields to assign + return *this; +} + +// Make default copy constructor call the NumberRangeFormatterSettings copy constructor. +LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const LNF& other) + : LNF(static_cast<const NFS<LNF>&>(other)) {} + +LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const NFS<LNF>& other) + : NFS<LNF>(other) { + // No additional fields to assign +} + +LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(LocalizedNumberRangeFormatter&& src) noexcept + : LNF(static_cast<NFS<LNF>&&>(src)) {} + +LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(NFS<LNF>&& src) noexcept + : NFS<LNF>(std::move(src)) { + // Steal the compiled formatter + LNF&& _src = static_cast<LNF&&>(src); +#ifndef __wasi__ + auto* stolen = _src.fAtomicFormatter.exchange(nullptr); + delete fAtomicFormatter.exchange(stolen); +#else + delete fAtomicFormatter; + fAtomicFormatter = _src.fAtomicFormatter; + _src.fAtomicFormatter = nullptr; +#endif +} + +LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(const LNF& other) { + if (this == &other) { return *this; } // self-assignment: no-op + NFS<LNF>::operator=(static_cast<const NFS<LNF>&>(other)); + // Do not steal; just clear +#ifndef __wasi__ + delete fAtomicFormatter.exchange(nullptr); +#else + delete fAtomicFormatter; +#endif + return *this; +} + +LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(LNF&& src) noexcept { + NFS<LNF>::operator=(static_cast<NFS<LNF>&&>(src)); + // Steal the compiled formatter +#ifndef __wasi__ + auto* stolen = src.fAtomicFormatter.exchange(nullptr); + delete fAtomicFormatter.exchange(stolen); +#else + delete fAtomicFormatter; + fAtomicFormatter = src.fAtomicFormatter; + src.fAtomicFormatter = nullptr; +#endif + return *this; +} + + +LocalizedNumberRangeFormatter::~LocalizedNumberRangeFormatter() { +#ifndef __wasi__ + delete fAtomicFormatter.exchange(nullptr); +#else + delete fAtomicFormatter; +#endif +} + +LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const RangeMacroProps& macros, const Locale& locale) { + fMacros = macros; + fMacros.locale = locale; + touchRangeLocales(fMacros); +} + +LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(RangeMacroProps&& macros, const Locale& locale) { + fMacros = std::move(macros); + fMacros.locale = locale; + touchRangeLocales(fMacros); +} + +LocalizedNumberRangeFormatter UnlocalizedNumberRangeFormatter::locale(const Locale& locale) const& { + return LocalizedNumberRangeFormatter(fMacros, locale); +} + +LocalizedNumberRangeFormatter UnlocalizedNumberRangeFormatter::locale(const Locale& locale)&& { + return LocalizedNumberRangeFormatter(std::move(fMacros), locale); +} + + +FormattedNumberRange LocalizedNumberRangeFormatter::formatFormattableRange( + const Formattable& first, const Formattable& second, UErrorCode& status) const { + if (U_FAILURE(status)) { + return FormattedNumberRange(U_ILLEGAL_ARGUMENT_ERROR); + } + + auto results = new UFormattedNumberRangeData(); + if (results == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + return FormattedNumberRange(status); + } + + first.populateDecimalQuantity(results->quantity1, status); + if (U_FAILURE(status)) { + return FormattedNumberRange(status); + } + + second.populateDecimalQuantity(results->quantity2, status); + if (U_FAILURE(status)) { + return FormattedNumberRange(status); + } + + formatImpl(*results, first == second, status); + + // Do not save the results object if we encountered a failure. + if (U_SUCCESS(status)) { + return FormattedNumberRange(results); + } else { + delete results; + return FormattedNumberRange(status); + } +} + +void LocalizedNumberRangeFormatter::formatImpl( + UFormattedNumberRangeData& results, bool equalBeforeRounding, UErrorCode& status) const { + auto* impl = getFormatter(status); + if (U_FAILURE(status)) { + return; + } + if (impl == nullptr) { + status = U_INTERNAL_PROGRAM_ERROR; + return; + } + impl->format(results, equalBeforeRounding, status); + if (U_FAILURE(status)) { + return; + } + results.getStringRef().writeTerminator(status); +} + +const impl::NumberRangeFormatterImpl* +LocalizedNumberRangeFormatter::getFormatter(UErrorCode& status) const { + // TODO: Move this into umutex.h? (similar logic also in decimfmt.cpp) + // See ICU-20146 + + if (U_FAILURE(status)) { + return nullptr; + } + + // First try to get the pre-computed formatter +#ifndef __wasi__ + auto* ptr = fAtomicFormatter.load(); +#else + auto* ptr = fAtomicFormatter; +#endif + if (ptr != nullptr) { + return ptr; + } + + // Try computing the formatter on our own + auto* temp = new NumberRangeFormatterImpl(fMacros, status); + if (U_FAILURE(status)) { + delete temp; + return nullptr; + } + if (temp == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + return nullptr; + } + + // Note: ptr starts as nullptr; during compare_exchange, + // it is set to what is actually stored in the atomic + // if another thread beat us to computing the formatter object. + auto* nonConstThis = const_cast<LocalizedNumberRangeFormatter*>(this); +#ifndef __wasi__ + if (!nonConstThis->fAtomicFormatter.compare_exchange_strong(ptr, temp)) { + // Another thread beat us to computing the formatter + delete temp; + return ptr; + } else { + // Our copy of the formatter got stored in the atomic + return temp; + } +#else + nonConstThis->fAtomicFormatter = temp; + return temp; +#endif + +} + + +#endif /* #if !UCONFIG_NO_FORMATTING */ |