1
0
mirror of https://git.savannah.gnu.org/git/guix.git synced 2026-04-06 21:20:33 +02:00

gnu: icu4c-77: Apply Mozilla patches.

Suggested by Deltafire.

* gnu/packages/patches/icu4c-icu-22132-fix-vtimezone.patch: Rename to...
* gnu/packages/patches/icu4c-22132-standardize-vtzone-output.patch: ... this.
* gnu/packages/patches/icu4c-20548-dateinterval-timezone.patch: New file.
* gnu/packages/patches/icu4c-dayperiod-fractional-seconds.patch: New file.
* gnu/packages/patches/icu4c-23069-rosh-hashanah-postponement.patch
* gnu/packages/patches/icu4c-dtitvfmt-adopt-calendar.patch
* gnu/packages/patches/icu4c-wasi-workaround.patch: New files.
* gnu/packages/patches/icu4c-double-conversion.patch: New file.
* gnu/local.mk (dist_patch_DATA): Update accordingly.
* gnu/packages/icu4c.scm (icu4c-77) [source]: Apply patches.

Fixes: #3166
Change-Id: I9ce64a81f763e5c9ff2940a2d844a0b44d2800a8
This commit is contained in:
Maxim Cournoyer
2025-11-11 16:29:59 +09:00
parent c2ca6b7947
commit d4097d3563
9 changed files with 1347 additions and 6 deletions

View File

@@ -1609,7 +1609,14 @@ dist_patch_DATA = \
%D%/packages/patches/icedtea-7-hotspot-aarch64-use-c++98.patch \ %D%/packages/patches/icedtea-7-hotspot-aarch64-use-c++98.patch \
%D%/packages/patches/icedtea-7-hotspot-pointer-comparison.patch \ %D%/packages/patches/icedtea-7-hotspot-pointer-comparison.patch \
%D%/packages/patches/icu4c-icu-22132-fix-vtimezone.patch \ %D%/packages/patches/icu4c-icu-22132-fix-vtimezone.patch \
%D%/packages/patches/icu4c-20548-dateinterval-timezone.patch \
%D%/packages/patches/icu4c-22132-standardize-vtzone-output.patch \
%D%/packages/patches/icu4c-23069-rosh-hashanah-postponement.patch \
%D%/packages/patches/icu4c-dayperiod-fractional-seconds.patch \
%D%/packages/patches/icu4c-double-conversion.patch \
%D%/packages/patches/icu4c-dtitvfmt-adopt-calendar.patch \
%D%/packages/patches/icu4c-fix-TestHebrewCalendarInTemporalLeapYear.patch \ %D%/packages/patches/icu4c-fix-TestHebrewCalendarInTemporalLeapYear.patch \
%D%/packages/patches/icu4c-wasi-workaround.patch \
%D%/packages/patches/id3lib-CVE-2007-4460.patch \ %D%/packages/patches/id3lib-CVE-2007-4460.patch \
%D%/packages/patches/id3lib-UTF16-writing-bug.patch \ %D%/packages/patches/id3lib-UTF16-writing-bug.patch \
%D%/packages/patches/ilmbase-fix-tests.patch \ %D%/packages/patches/ilmbase-fix-tests.patch \

View File

@@ -11,6 +11,7 @@
;;; Copyright © 2021 Guillaume Le Vaillant <glv@posteo.net> ;;; Copyright © 2021 Guillaume Le Vaillant <glv@posteo.net>
;;; Copyright © 2023 Nicolas Graves <ngraves@ngraves.fr> ;;; Copyright © 2023 Nicolas Graves <ngraves@ngraves.fr>
;;; Copyright © 2024 Zheng Junjie <873216071@qq.com> ;;; Copyright © 2024 Zheng Junjie <873216071@qq.com>
;;; Copyright © 2025 Maxim Cournoyer <maxim@guixotic.coop>
;;; ;;;
;;; This file is part of GNU Guix. ;;; This file is part of GNU Guix.
;;; ;;;
@@ -179,12 +180,26 @@ C/C++ part.")
(inherit icu4c) (inherit icu4c)
(name "icu4c") (name "icu4c")
(version "77.1") (version "77.1")
(source (origin (source
(method url-fetch) (origin
(uri (icu4c-uri version)) (method url-fetch)
(sha256 (uri (icu4c-uri version))
(base32 (sha256
"0qa0yapkypywhzx8ai1p27125h9v1qy89f7v3w1kjz1jfwgl73jq")))))) (base32
"0qa0yapkypywhzx8ai1p27125h9v1qy89f7v3w1kjz1jfwgl73jq"))
(patches
(search-patches
;; These are the relevant patches Firefox applies (see
;; <https://github.com/mozilla-firefox/firefox/tree/main/intl/icu-patches>).
;; The 'intl/icu' prefix in the file names must be stripped. These
;; are necessary to ensure applications like Icedove run correctly.
"icu4c-22132-standardize-vtzone-output.patch"
"icu4c-20548-dateinterval-timezone.patch"
"icu4c-23069-rosh-hashanah-postponement.patch"
"icu4c-dayperiod-fractional-seconds.patch"
"icu4c-double-conversion.patch"
"icu4c-dtitvfmt-adopt-calendar.patch"
"icu4c-wasi-workaround.patch"))))))
(define-public icu4c-build-root (define-public icu4c-build-root
(package (package

View File

@@ -0,0 +1,165 @@
Retrieved from <https://raw.githubusercontent.com/mozilla-firefox/firefox/refs/heads/main/intl/icu-patches/bug-1856290-ICU-20548-dateinterval-timezone.diff>
# Handle 'O' time zone skeleton in DateIntervalFormat.
# Keep time zone skeleton field widths in DateIntervalFormat.
#
# ICU bug: https://unicode-org.atlassian.net/browse/ICU-20548
diff --git a/source/i18n/dtitv_impl.h b/source/i18n/dtitv_impl.h
--- a/source/i18n/dtitv_impl.h
+++ b/source/i18n/dtitv_impl.h
@@ -84,16 +84,19 @@
#define CAP_W ((char16_t)0x0057)
#define CAP_Y ((char16_t)0x0059)
#define CAP_Z ((char16_t)0x005A)
//#define MINIMUM_SUPPORTED_CALENDAR_FIELD UCAL_MINUTE
#define MAX_E_COUNT 5
#define MAX_M_COUNT 5
+#define MAX_z_COUNT 4
+#define MAX_v_COUNT 4
+#define MAX_O_COUNT 4
//#define MAX_INTERVAL_INDEX 4
#define MAX_POSITIVE_INT 56632
#endif /* #if !UCONFIG_NO_FORMATTING */
#endif
//eof
diff --git a/source/i18n/dtitvfmt.cpp b/source/i18n/dtitvfmt.cpp
--- a/source/i18n/dtitvfmt.cpp
+++ b/source/i18n/dtitvfmt.cpp
@@ -1061,16 +1061,17 @@ DateIntervalFormat::getDateTimeSkeleton(
// timeSkeleton follows the sequence of hm*[v|z]?
int32_t ECount = 0;
int32_t dCount = 0;
int32_t MCount = 0;
int32_t yCount = 0;
int32_t mCount = 0;
int32_t vCount = 0;
int32_t zCount = 0;
+ int32_t OCount = 0;
char16_t hourChar = u'\0';
int32_t i;
for (i = 0; i < skeleton.length(); ++i) {
char16_t ch = skeleton[i];
switch ( ch ) {
case CAP_E:
dateSkeleton.append(ch);
@@ -1123,16 +1124,20 @@ DateIntervalFormat::getDateTimeSkeleton(
case LOW_Z:
++zCount;
timeSkeleton.append(ch);
break;
case LOW_V:
++vCount;
timeSkeleton.append(ch);
break;
+ case CAP_O:
+ ++OCount;
+ timeSkeleton.append(ch);
+ break;
case LOW_A:
case CAP_V:
case CAP_Z:
case LOW_J:
case LOW_S:
case CAP_S:
case CAP_A:
case LOW_B:
@@ -1174,20 +1179,41 @@ DateIntervalFormat::getDateTimeSkeleton(
/* generate normalized form for time */
if ( hourChar != u'\0' ) {
normalizedTimeSkeleton.append(hourChar);
}
if ( mCount != 0 ) {
normalizedTimeSkeleton.append(LOW_M);
}
if ( zCount != 0 ) {
- normalizedTimeSkeleton.append(LOW_Z);
+ if ( zCount <= 3 ) {
+ normalizedTimeSkeleton.append(LOW_Z);
+ } else {
+ for ( int32_t j = 0; j < zCount && j < MAX_z_COUNT; ++j ) {
+ normalizedTimeSkeleton.append(LOW_Z);
+ }
+ }
}
if ( vCount != 0 ) {
- normalizedTimeSkeleton.append(LOW_V);
+ if ( vCount <= 3 ) {
+ normalizedTimeSkeleton.append(LOW_V);
+ } else {
+ for ( int32_t j = 0; j < vCount && j < MAX_v_COUNT; ++j ) {
+ normalizedTimeSkeleton.append(LOW_V);
+ }
+ }
+ }
+ if ( OCount != 0 ) {
+ if ( OCount <= 3 ) {
+ normalizedTimeSkeleton.append(CAP_O);
+ } else {
+ for ( int32_t j = 0; j < OCount && j < MAX_O_COUNT; ++j ) {
+ normalizedTimeSkeleton.append(CAP_O);
+ }
+ }
}
}
/**
* Generate date or time interval pattern from resource,
* and set them into the interval pattern locale to this formatter.
*
@@ -1732,18 +1758,23 @@ DateIntervalFormat::adjustFieldWidth(con
findReplaceInPattern(adjustedPtn, UnicodeString(u"a\u202F",-1), UnicodeString());
findReplaceInPattern(adjustedPtn, UnicodeString(LOW_A), UnicodeString());
// adjust interior double spaces, remove exterior whitespace
findReplaceInPattern(adjustedPtn, UnicodeString(" "), UnicodeString(" "));
adjustedPtn.trim();
}
if ( differenceInfo == 2 ) {
if (inputSkeleton.indexOf(LOW_Z) != -1) {
+ bestMatchSkeletonFieldWidth[(int)(LOW_Z - PATTERN_CHAR_BASE)] = bestMatchSkeletonFieldWidth[(int)(LOW_V - PATTERN_CHAR_BASE)];
findReplaceInPattern(adjustedPtn, UnicodeString(LOW_V), UnicodeString(LOW_Z));
}
+ if (inputSkeleton.indexOf(CAP_O) != -1) {
+ bestMatchSkeletonFieldWidth[(int)(CAP_O - PATTERN_CHAR_BASE)] = bestMatchSkeletonFieldWidth[(int)(LOW_V - PATTERN_CHAR_BASE)];
+ findReplaceInPattern(adjustedPtn, UnicodeString(LOW_V), UnicodeString(CAP_O));
+ }
if (inputSkeleton.indexOf(CAP_K) != -1) {
findReplaceInPattern(adjustedPtn, UnicodeString(LOW_H), UnicodeString(CAP_K));
}
if (inputSkeleton.indexOf(LOW_K) != -1) {
findReplaceInPattern(adjustedPtn, UnicodeString(CAP_H), UnicodeString(LOW_K));
}
if (inputSkeleton.indexOf(LOW_B) != -1) {
findReplaceInPattern(adjustedPtn, UnicodeString(LOW_A), UnicodeString(LOW_B));
diff --git a/source/i18n/dtitvinf.cpp b/source/i18n/dtitvinf.cpp
--- a/source/i18n/dtitvinf.cpp
+++ b/source/i18n/dtitvinf.cpp
@@ -582,19 +582,20 @@ DateIntervalInfo::getBestSkeleton(const
// hack for certain alternate characters
// resource bundles only have time skeletons containing 'v', 'h', and 'H'
// but not time skeletons containing 'z', 'K', or 'k'
// the skeleton may also include 'a' or 'b', which never occur in the resource bundles, so strip them out too
UBool replacedAlternateChars = false;
const UnicodeString* inputSkeleton = &skeleton;
UnicodeString copySkeleton;
- if ( skeleton.indexOf(LOW_Z) != -1 || skeleton.indexOf(LOW_K) != -1 || skeleton.indexOf(CAP_K) != -1 || skeleton.indexOf(LOW_A) != -1 || skeleton.indexOf(LOW_B) != -1 ) {
+ if ( skeleton.indexOf(LOW_Z) != -1 || skeleton.indexOf(CAP_O) != -1 || skeleton.indexOf(LOW_K) != -1 || skeleton.indexOf(CAP_K) != -1 || skeleton.indexOf(LOW_A) != -1 || skeleton.indexOf(LOW_B) != -1 ) {
copySkeleton = skeleton;
copySkeleton.findAndReplace(UnicodeString(LOW_Z), UnicodeString(LOW_V));
+ copySkeleton.findAndReplace(UnicodeString(CAP_O), UnicodeString(LOW_V));
copySkeleton.findAndReplace(UnicodeString(LOW_K), UnicodeString(CAP_H));
copySkeleton.findAndReplace(UnicodeString(CAP_K), UnicodeString(LOW_H));
copySkeleton.findAndReplace(UnicodeString(LOW_A), UnicodeString());
copySkeleton.findAndReplace(UnicodeString(LOW_B), UnicodeString());
inputSkeleton = &copySkeleton;
replacedAlternateChars = true;
}

View File

@@ -0,0 +1,30 @@
Retrieved from: <https://raw.githubusercontent.com/mozilla-firefox/firefox/refs/heads/main/intl/icu-patches/bug-1790071-ICU-22132-standardize-vtzone-output.diff>
diff --git a/source/i18n/vtzone.cpp b/source/i18n/vtzone.cpp
--- a/source/i18n/vtzone.cpp
+++ b/source/i18n/vtzone.cpp
@@ -1735,14 +1735,17 @@ VTimeZone::write(VTZWriter& writer, UErr
}
}
} else {
- UnicodeString icutzprop;
- UVector customProps(nullptr, uhash_compareUnicodeString, status);
+ UVector customProps(uprv_deleteUObject, uhash_compareUnicodeString, status);
if (olsonzid.length() > 0 && icutzver.length() > 0) {
- icutzprop.append(olsonzid);
- icutzprop.append(u'[');
- icutzprop.append(icutzver);
- icutzprop.append(u']');
- customProps.addElement(&icutzprop, status);
+ LocalPointer<UnicodeString> icutzprop(new UnicodeString(ICU_TZINFO_PROP), status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ icutzprop->append(olsonzid);
+ icutzprop->append(u'[');
+ icutzprop->append(icutzver);
+ icutzprop->append(u']');
+ customProps.adoptElement(icutzprop.orphan(), status);
}
writeZone(writer, *tz, &customProps, status);
}

View File

@@ -0,0 +1,26 @@
Retrieved from: <https://raw.githubusercontent.com/mozilla-firefox/firefox/refs/heads/main/intl/icu-patches/bug-1954138-ICU-23069-rosh-hashanah-postponement.diff>
diff --git a/source/i18n/hebrwcal.cpp b/source/i18n/hebrwcal.cpp
--- a/source/i18n/hebrwcal.cpp
+++ b/source/i18n/hebrwcal.cpp
@@ -441,19 +441,18 @@ int32_t startOfYear(int32_t year, UError
day = months * 29LL + frac / DAY_PARTS; // Whole # part of calculation
frac = frac % DAY_PARTS; // Time of day
int32_t wd = (day % 7); // Day of week (0 == Monday)
if (wd == 2 || wd == 4 || wd == 6) {
// If the 1st is on Sun, Wed, or Fri, postpone to the next day
day += 1;
- wd = (day % 7);
}
- if (wd == 1 && frac > 15*HOUR_PARTS+204 && !HebrewCalendar::isLeapYear(year) ) {
+ else if (wd == 1 && frac > 15*HOUR_PARTS+204 && !HebrewCalendar::isLeapYear(year) ) {
// If the new moon falls after 3:11:20am (15h204p from the previous noon)
// on a Tuesday and it is not a leap year, postpone by 2 days.
// This prevents 356-day years.
day += 2;
}
else if (wd == 0 && frac > 21*HOUR_PARTS+589 && HebrewCalendar::isLeapYear(year-1) ) {
// If the new moon falls after 9:32:43 1/3am (21h589p from yesterday noon)
// on a Monday and *last* year was a leap year, postpone by 1 day.

View File

@@ -0,0 +1,25 @@
Retrieved from: <https://raw.githubusercontent.com/mozilla-firefox/firefox/refs/heads/main/intl/icu-patches/bug-1636984-append-item-dayperiod-fractional-seconds.diff>
# Add <appendItem> entries for "DayPeriod" and "FractionalSeconds" to avoid the
# "├ ┤" parentheses from ICU and instead use the normal "( )" parentheses.
#
# CLDR bug: https://unicode-org.atlassian.net/browse/CLDR-13184
diff --git a/source/i18n/dtptngen.cpp b/source/i18n/dtptngen.cpp
--- a/source/i18n/dtptngen.cpp
+++ b/source/i18n/dtptngen.cpp
@@ -259,12 +259,12 @@ static const dtTypeElem dtTypes[] = {
{0, UDATPG_FIELD_COUNT, 0, 0, 0} , // last row of dtTypes[]
};
static const char* const CLDR_FIELD_APPEND[] = {
"Era", "Year", "Quarter", "Month", "Week", "*", "Day-Of-Week",
- "*", "*", "Day", "*", // The UDATPG_x_FIELD constants and these fields have a different order than in ICU4J
- "Hour", "Minute", "Second", "*", "Timezone"
+ "*", "*", "Day", "DayPeriod", // The UDATPG_x_FIELD constants and these fields have a different order than in ICU4J
+ "Hour", "Minute", "Second", "FractionalSecond", "Timezone"
};
static const char* const CLDR_FIELD_NAME[UDATPG_FIELD_COUNT] = {
"era", "year", "quarter", "month", "week", "weekOfMonth", "weekday",
"dayOfYear", "weekdayOfMonth", "day", "dayperiod", // The UDATPG_x_FIELD constants and these fields have a different order than in ICU4J

View File

@@ -0,0 +1,200 @@
Retrieved from: <https://raw.githubusercontent.com/mozilla-firefox/firefox/refs/heads/main/intl/icu-patches/double-conversion.diff>
diff --git a/source/i18n/measunit_extra.cpp b/source/i18n/measunit_extra.cpp
--- a/source/i18n/measunit_extra.cpp
+++ b/source/i18n/measunit_extra.cpp
@@ -10,17 +10,21 @@
// Allow implicit conversion from char16_t* to UnicodeString for this file:
// Helpful in toString methods and elsewhere.
#define UNISTR_FROM_STRING_EXPLICIT
#include "charstr.h"
#include "cmemory.h"
#include "cstring.h"
+#ifdef JS_HAS_INTL_API
+#include "double-conversion/string-to-double.h"
+#else
#include "double-conversion-string-to-double.h"
+#endif
#include "measunit_impl.h"
#include "resource.h"
#include "uarrsort.h"
#include "uassert.h"
#include "ucln_in.h"
#include "umutex.h"
#include "unicode/bytestrie.h"
#include "unicode/bytestriebuilder.h"
@@ -33,17 +37,21 @@
#include "util.h"
#include <limits.h>
#include <cstdlib>
U_NAMESPACE_BEGIN
namespace {
+#ifdef JS_HAS_INTL_API
+using double_conversion::StringToDoubleConverter;
+#else
using icu::double_conversion::StringToDoubleConverter;
+#endif
// TODO: Propose a new error code for this?
constexpr UErrorCode kUnitIdentifierSyntaxError = U_ILLEGAL_ARGUMENT_ERROR;
// Trie value offset for SI or binary prefixes. This is big enough to ensure we only
// insert positive integers into the trie.
constexpr int32_t kPrefixOffset = 64;
static_assert(kPrefixOffset + UMEASURE_PREFIX_INTERNAL_MIN_BIN > 0,
diff --git a/source/i18n/number_decimalquantity.cpp b/source/i18n/number_decimalquantity.cpp
--- a/source/i18n/number_decimalquantity.cpp
+++ b/source/i18n/number_decimalquantity.cpp
@@ -11,28 +11,37 @@
#include <stdlib.h>
#include "unicode/plurrule.h"
#include "cmemory.h"
#include "number_decnum.h"
#include "putilimp.h"
#include "number_decimalquantity.h"
#include "number_roundingutils.h"
+#ifdef JS_HAS_INTL_API
+#include "double-conversion/double-conversion.h"
+#else
#include "double-conversion.h"
+#endif
#include "charstr.h"
#include "number_utils.h"
#include "uassert.h"
#include "util.h"
using namespace icu;
using namespace icu::number;
using namespace icu::number::impl;
+#ifdef JS_HAS_INTL_API
+using double_conversion::DoubleToStringConverter;
+using double_conversion::StringToDoubleConverter;
+#else
using icu::double_conversion::DoubleToStringConverter;
using icu::double_conversion::StringToDoubleConverter;
+#endif
namespace {
int8_t NEGATIVE_FLAG = 1;
int8_t INFINITY_FLAG = 2;
int8_t NAN_FLAG = 4;
/** Helper function for safe subtraction (no overflow). */
diff --git a/source/i18n/number_rounding.cpp b/source/i18n/number_rounding.cpp
--- a/source/i18n/number_rounding.cpp
+++ b/source/i18n/number_rounding.cpp
@@ -5,17 +5,21 @@
#if !UCONFIG_NO_FORMATTING
#include "charstr.h"
#include "uassert.h"
#include "unicode/numberformatter.h"
#include "number_types.h"
#include "number_decimalquantity.h"
+#ifdef JS_HAS_INTL_API
+#include "double-conversion/double-conversion.h"
+#else
#include "double-conversion.h"
+#endif
#include "number_roundingutils.h"
#include "number_skeletons.h"
#include "number_decnum.h"
#include "putilimp.h"
#include "string_segment.h"
using namespace icu;
using namespace icu::number;
diff --git a/source/i18n/number_utils.cpp b/source/i18n/number_utils.cpp
--- a/source/i18n/number_utils.cpp
+++ b/source/i18n/number_utils.cpp
@@ -12,26 +12,34 @@
#include <stdlib.h>
#include <cmath>
#include "number_decnum.h"
#include "number_types.h"
#include "number_utils.h"
#include "charstr.h"
#include "decContext.h"
#include "decNumber.h"
+#ifdef JS_HAS_INTL_API
+#include "double-conversion/double-conversion.h"
+#else
#include "double-conversion.h"
+#endif
#include "fphdlimp.h"
#include "uresimp.h"
#include "ureslocs.h"
using namespace icu;
using namespace icu::number;
using namespace icu::number::impl;
+#ifdef JS_HAS_INTL_API
+using double_conversion::DoubleToStringConverter;
+#else
using icu::double_conversion::DoubleToStringConverter;
+#endif
namespace {
const char16_t*
doGetPattern(UResourceBundle* res, const char* nsName, const char* patternKey, UErrorCode& publicStatus,
UErrorCode& localStatus) {
// Construct the path into the resource bundle
diff --git a/source/i18n/units_converter.cpp b/source/i18n/units_converter.cpp
--- a/source/i18n/units_converter.cpp
+++ b/source/i18n/units_converter.cpp
@@ -2,17 +2,21 @@
// License & terms of use: http://www.unicode.org/copyright.html
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "charstr.h"
#include "cmemory.h"
+#ifdef JS_HAS_INTL_API
+#include "double-conversion/string-to-double.h"
+#else
#include "double-conversion-string-to-double.h"
+#endif
#include "measunit_impl.h"
#include "putilimp.h"
#include "uassert.h"
#include "unicode/errorcode.h"
#include "unicode/localpointer.h"
#include "unicode/stringpiece.h"
#include "units_converter.h"
#include <algorithm>
@@ -101,17 +105,21 @@ void U_I18N_API Factor::substituteConsta
this->constantExponents[i] = 0;
}
}
namespace {
/* Helpers */
+#ifdef JS_HAS_INTL_API
+using double_conversion::StringToDoubleConverter;
+#else
using icu::double_conversion::StringToDoubleConverter;
+#endif
// TODO: Make this a shared-utility function.
// Returns `double` from a scientific number(i.e. "1", "2.01" or "3.09E+4")
double strToDouble(StringPiece strNum, UErrorCode &status) {
// We are processing well-formed input, so we don't need any special options to
// StringToDoubleConverter.
StringToDoubleConverter converter(0, 0, 0, "", "");
int32_t count;

View File

@@ -0,0 +1,71 @@
Retrieved from: <https://raw.githubusercontent.com/mozilla-firefox/firefox/refs/heads/main/intl/icu-patches/bug-1954138-dtitvfmt-adopt-calendar.diff>
diff --git a/source/i18n/dtitvfmt.cpp b/source/i18n/dtitvfmt.cpp
--- a/source/i18n/dtitvfmt.cpp
+++ b/source/i18n/dtitvfmt.cpp
@@ -631,16 +631,38 @@ DateIntervalFormat::getTimeZone() const
if (fDateFormat != nullptr) {
Mutex lock(&gFormatterMutex);
return fDateFormat->getTimeZone();
}
// If fDateFormat is nullptr (unexpected), create default timezone.
return *(TimeZone::createDefault());
}
+void DateIntervalFormat::adoptCalendar(Calendar *calendarToAdopt) {
+ if (fDateFormat != nullptr) {
+ fDateFormat->adoptCalendar(calendarToAdopt);
+ }
+
+ // The fDateFormat has the primary calendar for the DateIntervalFormat and has
+ // ownership of any adopted Calendar; fFromCalendar and fToCalendar are internal
+ // work clones of that calendar.
+
+ delete fFromCalendar;
+ fFromCalendar = nullptr;
+
+ delete fToCalendar;
+ fToCalendar = nullptr;
+
+ const Calendar *calendar = fDateFormat->getCalendar();
+ if (calendar != nullptr) {
+ fFromCalendar = calendar->clone();
+ fToCalendar = calendar->clone();
+ }
+}
+
void
DateIntervalFormat::setContext(UDisplayContext value, UErrorCode& status)
{
if (U_FAILURE(status))
return;
if (static_cast<UDisplayContextType>(static_cast<uint32_t>(value) >> 8) == UDISPCTX_TYPE_CAPITALIZATION) {
fCapitalizationContext = value;
} else {
diff --git a/source/i18n/unicode/dtitvfmt.h b/source/i18n/unicode/dtitvfmt.h
--- a/source/i18n/unicode/dtitvfmt.h
+++ b/source/i18n/unicode/dtitvfmt.h
@@ -637,16 +637,23 @@ public:
/**
* Sets the time zone for the calendar used by this DateIntervalFormat object.
* @param zone the new time zone.
* @stable ICU 4.8
*/
virtual void setTimeZone(const TimeZone& zone);
/**
+ * Sets the calendar used by this DateIntervalFormat object. The caller no longer owns
+ * the Calendar object and should not delete it after this call.
+ * @param calendarToAdopt the Calendar to be adopted.
+ */
+ virtual void adoptCalendar(Calendar *calendarToAdopt);
+
+ /**
* Set a particular UDisplayContext value in the formatter, such as
* UDISPCTX_CAPITALIZATION_FOR_STANDALONE. This causes the formatted
* result to be capitalized appropriately for the context in which
* it is intended to be used, considering both the locale and the
* type of field at the beginning of the formatted result.
* @param value The UDisplayContext value to set.
* @param status Input/output status. If at entry this indicates a failure
* status, the function will do nothing; otherwise this will be

View File

@@ -0,0 +1,802 @@
Retrieved from: <https://github.com/mozilla-firefox/firefox/blob/main/intl/icu-patches/bug-1706949-wasi-workaround.diff>
# Handle WASI lack of support for <thread> and <atomic>.
#
# WASI issue: https://github.com/WebAssembly/wasi-sdk/issues/180
diff --git a/source/common/putilimp.h b/source/common/putilimp.h
index 5b95a68..7097232 100644
--- a/source/common/putilimp.h
+++ b/source/common/putilimp.h
@@ -105,10 +105,12 @@ typedef size_t uintptr_t;
#endif
#elif U_PLATFORM == U_PF_OS400
/* not defined */
#elif U_PLATFORM == U_PF_HAIKU
/* not defined */
+#elif defined(__wasi__)
+ /* not defined */
#else
# define U_TZSET tzset
#endif
#if defined(U_TIMEZONE) || defined(U_HAVE_TIMEZONE)
@@ -130,10 +132,12 @@ typedef size_t uintptr_t;
/* not defined */
#elif U_PLATFORM == U_PF_OS400
/* not defined */
#elif U_PLATFORM == U_PF_IPHONE
/* not defined */
+#elif defined(__wasi__)
+ /* not defined */
#else
# define U_TIMEZONE timezone
#endif
#if defined(U_TZNAME) || defined(U_HAVE_TZNAME)
@@ -145,10 +149,12 @@ typedef size_t uintptr_t;
#endif
#elif U_PLATFORM == U_PF_OS400
/* not defined */
#elif U_PLATFORM == U_PF_HAIKU
/* not defined, (well it is but a loop back to icu) */
+#elif defined(__wasi__)
+ /* not defined */
#else
# define U_TZNAME tzname
#endif
#ifdef U_HAVE_MMAP
diff --git a/source/common/umapfile.h b/source/common/umapfile.h
index 92bd567..4ed1112 100644
--- a/source/common/umapfile.h
+++ b/source/common/umapfile.h
@@ -38,10 +38,12 @@ U_CFUNC void uprv_unmapFile(UDataMemory *pData);
#define MAP_POSIX 2
#define MAP_STDIO 3
#if UCONFIG_NO_FILE_IO
# define MAP_IMPLEMENTATION MAP_NONE
+#elif defined(__wasi__)
+# define MAP_IMPLEMENTATION MAP_STDIO
#elif U_PLATFORM_USES_ONLY_WIN32_API
# define MAP_IMPLEMENTATION MAP_WIN32
#elif U_HAVE_MMAP || U_PLATFORM == U_PF_OS390
# define MAP_IMPLEMENTATION MAP_POSIX
#else /* unknown platform, no memory map implementation: use stdio.h and uprv_malloc() instead */
diff --git a/source/common/umutex.cpp b/source/common/umutex.cpp
index ccbee99..6c3452c 100644
--- a/source/common/umutex.cpp
+++ b/source/common/umutex.cpp
@@ -43,6 +43,7 @@ U_NAMESPACE_BEGIN
*
*************************************************************************************************/
+#ifndef __wasi__
namespace {
std::mutex *initMutex;
std::condition_variable *initCondition;
@@ -55,9 +56,11 @@ std::once_flag initFlag;
std::once_flag *pInitFlag = &initFlag;
} // Anonymous namespace
+#endif
U_CDECL_BEGIN
static UBool U_CALLCONV umtx_cleanup() {
+#ifndef __wasi__
initMutex->~mutex();
initCondition->~condition_variable();
UMutex::cleanup();
@@ -66,17 +69,21 @@ static UBool U_CALLCONV umtx_cleanup() {
// Do not use this trick anywhere else in ICU; use umtx_initOnce, not std::call_once().
pInitFlag->~once_flag();
pInitFlag = new(&initFlag) std::once_flag();
+#endif
return true;
}
static void U_CALLCONV umtx_init() {
+#ifndef __wasi__
initMutex = STATIC_NEW(std::mutex);
initCondition = STATIC_NEW(std::condition_variable);
ucln_common_registerCleanup(UCLN_COMMON_MUTEX, umtx_cleanup);
+#endif
}
U_CDECL_END
+#ifndef __wasi__
std::mutex *UMutex::getMutex() {
std::mutex *retPtr = fMutex.load(std::memory_order_acquire);
if (retPtr == nullptr) {
@@ -93,14 +100,17 @@ std::mutex *UMutex::getMutex() {
U_ASSERT(retPtr != nullptr);
return retPtr;
}
+#endif
UMutex *UMutex::gListHead = nullptr;
void UMutex::cleanup() {
UMutex *next = nullptr;
for (UMutex *m = gListHead; m != nullptr; m = next) {
+#ifndef __wasi__
(*m->fMutex).~mutex();
m->fMutex = nullptr;
+#endif
next = m->fListLink;
m->fListLink = nullptr;
}
@@ -110,20 +120,24 @@ void UMutex::cleanup() {
U_CAPI void U_EXPORT2
umtx_lock(UMutex *mutex) {
+#ifndef __wasi__
if (mutex == nullptr) {
mutex = &globalMutex;
}
mutex->lock();
+#endif
}
U_CAPI void U_EXPORT2
umtx_unlock(UMutex* mutex)
{
+#ifndef __wasi__
if (mutex == nullptr) {
mutex = &globalMutex;
}
mutex->unlock();
+#endif
}
@@ -143,18 +157,22 @@ umtx_unlock(UMutex* mutex)
//
U_COMMON_API UBool U_EXPORT2
umtx_initImplPreInit(UInitOnce &uio) {
+#ifndef __wasi__
std::call_once(*pInitFlag, umtx_init);
std::unique_lock<std::mutex> lock(*initMutex);
+#endif
if (umtx_loadAcquire(uio.fState) == 0) {
umtx_storeRelease(uio.fState, 1);
return true; // Caller will next call the init function.
} else {
+#ifndef __wasi__
while (umtx_loadAcquire(uio.fState) == 1) {
// Another thread is currently running the initialization.
// Wait until it completes.
initCondition->wait(lock);
}
U_ASSERT(uio.fState == 2);
+#endif
return false;
}
}
@@ -168,11 +186,13 @@ umtx_initImplPreInit(UInitOnce &uio) {
U_COMMON_API void U_EXPORT2
umtx_initImplPostInit(UInitOnce &uio) {
+#ifndef __wasi__
{
std::unique_lock<std::mutex> lock(*initMutex);
umtx_storeRelease(uio.fState, 2);
}
initCondition->notify_all();
+#endif
}
U_NAMESPACE_END
diff --git a/source/common/umutex.h b/source/common/umutex.h
index 8d76b3f..c1a58db 100644
--- a/source/common/umutex.h
+++ b/source/common/umutex.h
@@ -20,9 +20,12 @@
#ifndef UMUTEX_H
#define UMUTEX_H
+#ifndef __wasi__
#include <atomic>
#include <condition_variable>
#include <mutex>
+#endif
+
#include <type_traits>
#include "unicode/utypes.h"
@@ -37,6 +40,8 @@
#error U_USER_ATOMICS and U_USER_MUTEX_H are not supported
#endif
+#ifndef __wasi__
+
// Export an explicit template instantiation of std::atomic<int32_t>.
// When building DLLs for Windows this is required as it is used as a data member of the exported SharedObject class.
// See digitlst.h, pluralaffix.h, datefmt.h, and others for similar examples.
@@ -61,6 +66,7 @@ template struct std::atomic<std::mutex *>;
#endif
#endif
+#endif
U_NAMESPACE_BEGIN
@@ -68,10 +68,12 @@ U_NAMESPACE_BEGIN
*
* Low Level Atomic Operations, ICU wrappers for.
*
****************************************************************************/
+#ifndef __wasi__
+
typedef std::atomic<int32_t> u_atomic_int32_t;
inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
return var.load(std::memory_order_acquire);
}
@@ -86,10 +88,31 @@ inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
return var->fetch_sub(1) - 1;
}
+#else
+
+typedef int32_t u_atomic_int32_t;
+
+inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
+ return var;
+}
+
+inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
+ var = val;
+}
+
+inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
+ return ++(*var);
+}
+
+inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
+ return --(*var);
+}
+
+#endif
/*************************************************************************************************
*
* UInitOnce Definitions.
*
@@ -225,21 +248,29 @@ class U_COMMON_API UMutex {
UMutex &operator =(const UMutex &other) = delete;
void *operator new(size_t) = delete;
// requirements for C++ BasicLockable, allows UMutex to work with std::lock_guard
void lock() {
+#ifndef __wasi__
std::mutex *m = fMutex.load(std::memory_order_acquire);
if (m == nullptr) { m = getMutex(); }
m->lock();
+#endif
+ }
+ void unlock() {
+#ifndef __wasi__
+ fMutex.load(std::memory_order_relaxed)->unlock();
+#endif
}
- void unlock() { fMutex.load(std::memory_order_relaxed)->unlock(); }
static void cleanup();
private:
+#ifndef __wasi__
alignas(std::mutex) char fStorage[sizeof(std::mutex)] {};
std::atomic<std::mutex *> fMutex { nullptr };
+#endif
/** All initialized UMutexes are kept in a linked list, so that they can be found,
* and the underlying std::mutex destructed, by u_cleanup().
*/
UMutex *fListLink { nullptr };
@@ -247,11 +278,13 @@ class U_COMMON_API UMutex {
/** Out-of-line function to lazily initialize a UMutex on first use.
* Initial fast check is inline, in lock(). The returned value may never
* be nullptr.
*/
+#ifndef __wasi__
std::mutex *getMutex();
+#endif
};
/* Lock a mutex.
* @param mutex The given mutex to be locked. Pass NULL to specify
diff --git a/source/common/unifiedcache.cpp b/source/common/unifiedcache.cpp
--- a/source/common/unifiedcache.cpp
+++ b/source/common/unifiedcache.cpp
@@ -11,19 +11,23 @@
*/
#include "unifiedcache.h"
#include <algorithm> // For std::max()
-#include <mutex>
+#ifndef __wasi__
+ #include <mutex>
+#endif
#include "uassert.h"
#include "uhash.h"
#include "ucln_cmn.h"
static icu::UnifiedCache *gCache = nullptr;
+#ifndef __wasi__
static std::mutex *gCacheMutex = nullptr;
static std::condition_variable *gInProgressValueAddedCond;
+#endif
static icu::UInitOnce gCacheInitOnce {};
static const int32_t MAX_EVICT_ITERATIONS = 10;
static const int32_t DEFAULT_MAX_UNUSED = 1000;
static const int32_t DEFAULT_PERCENTAGE_OF_IN_USE = 100;
@@ -32,14 +36,16 @@ static const int32_t DEFAULT_PERCENTAGE_OF_IN_USE = 100;
U_CDECL_BEGIN
static UBool U_CALLCONV unifiedcache_cleanup() {
gCacheInitOnce.reset();
delete gCache;
gCache = nullptr;
+#ifndef __wasi__
gCacheMutex->~mutex();
gCacheMutex = nullptr;
gInProgressValueAddedCond->~condition_variable();
gInProgressValueAddedCond = nullptr;
+#endif
return true;
}
U_CDECL_END
@@ -70,12 +76,14 @@ CacheKeyBase::~CacheKeyBase() {
static void U_CALLCONV cacheInit(UErrorCode &status) {
U_ASSERT(gCache == nullptr);
ucln_common_registerCleanup(
UCLN_COMMON_UNIFIED_CACHE, unifiedcache_cleanup);
+#ifndef __wasi__
gCacheMutex = STATIC_NEW(std::mutex);
gInProgressValueAddedCond = STATIC_NEW(std::condition_variable);
+#endif
gCache = new UnifiedCache(status);
if (gCache == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
}
if (U_FAILURE(status)) {
@@ -133,41 +141,53 @@ void UnifiedCache::setEvictionPolicy(
}
if (count < 0 || percentageOfInUseItems < 0) {
status = U_ILLEGAL_ARGUMENT_ERROR;
return;
}
+#ifndef __wasi__
std::lock_guard<std::mutex> lock(*gCacheMutex);
+#endif
fMaxUnused = count;
fMaxPercentageOfInUse = percentageOfInUseItems;
}
int32_t UnifiedCache::unusedCount() const {
+#ifndef __wasi__
std::lock_guard<std::mutex> lock(*gCacheMutex);
+#endif
return uhash_count(fHashtable) - fNumValuesInUse;
}
int64_t UnifiedCache::autoEvictedCount() const {
+#ifndef __wasi__
std::lock_guard<std::mutex> lock(*gCacheMutex);
+#endif
return fAutoEvictedCount;
}
int32_t UnifiedCache::keyCount() const {
+#ifndef __wasi__
std::lock_guard<std::mutex> lock(*gCacheMutex);
+#endif
return uhash_count(fHashtable);
}
void UnifiedCache::flush() const {
+#ifndef __wasi__
std::lock_guard<std::mutex> lock(*gCacheMutex);
+#endif
// Use a loop in case cache items that are flushed held hard references to
// other cache items making those additional cache items eligible for
// flushing.
while (_flush(false));
}
void UnifiedCache::handleUnreferencedObject() const {
+#ifndef __wasi__
std::lock_guard<std::mutex> lock(*gCacheMutex);
+#endif
--fNumValuesInUse;
_runEvictionSlice();
}
#ifdef UNIFIED_CACHE_DEBUG
@@ -182,11 +202,13 @@ void UnifiedCache::dump() {
}
cache->dumpContents();
}
void UnifiedCache::dumpContents() const {
+#ifndef __wasi__
std::lock_guard<std::mutex> lock(*gCacheMutex);
+#endif
_dumpContents();
}
// Dumps content of cache.
// On entry, gCacheMutex must be held.
@@ -222,11 +244,13 @@ UnifiedCache::~UnifiedCache() {
flush();
{
// Now all that should be left in the cache are entries that refer to
// each other and entries with hard references from outside the cache.
// Nothing we can do about these so proceed to wipe out the cache.
+#ifndef __wasi__
std::lock_guard<std::mutex> lock(*gCacheMutex);
+#endif
_flush(true);
}
uhash_close(fHashtable);
fHashtable = nullptr;
delete fNoValue;
@@ -323,11 +347,13 @@ void UnifiedCache::_putNew(
void UnifiedCache::_putIfAbsentAndGet(
const CacheKeyBase &key,
const SharedObject *&value,
UErrorCode &status) const {
+#ifndef __wasi__
std::lock_guard<std::mutex> lock(*gCacheMutex);
+#endif
const UHashElement *element = uhash_find(fHashtable, &key);
if (element != nullptr && !_inProgress(element)) {
_fetch(element, value, status);
return;
}
@@ -348,18 +374,22 @@ UBool UnifiedCache::_poll(
const CacheKeyBase &key,
const SharedObject *&value,
UErrorCode &status) const {
U_ASSERT(value == nullptr);
U_ASSERT(status == U_ZERO_ERROR);
+#ifndef __wasi__
std::unique_lock<std::mutex> lock(*gCacheMutex);
+#endif
const UHashElement *element = uhash_find(fHashtable, &key);
// If the hash table contains an inProgress placeholder entry for this key,
// this means that another thread is currently constructing the value object.
// Loop, waiting for that construction to complete.
while (element != nullptr && _inProgress(element)) {
+#ifndef __wasi__
gInProgressValueAddedCond->wait(lock);
+#endif
element = uhash_find(fHashtable, &key);
}
// If the hash table contains an entry for the key,
// fetch out the contents and return them.
@@ -426,13 +456,15 @@ void UnifiedCache::_put(
UHashElement *ptr = const_cast<UHashElement *>(element);
ptr->value.pointer = (void *) value;
U_ASSERT(oldValue == fNoValue);
removeSoftRef(oldValue);
+#ifndef __wasi__
// Tell waiting threads that we replace in-progress status with
// an error.
gInProgressValueAddedCond->notify_all();
+#endif
}
void UnifiedCache::_fetch(
const UHashElement *element,
const SharedObject *&value,
diff --git a/source/i18n/decContext.h b/source/i18n/decContext.h
index 59ab65e..20f3526 100644
--- a/source/i18n/decContext.h
+++ b/source/i18n/decContext.h
@@ -61,7 +61,9 @@
/* #include <stdint.h> */ /* C99 standard integers */
#endif
#include <stdio.h> /* for printf, etc. */
+#ifndef __wasi__
#include <signal.h> /* for traps */
+#endif
/* Extended flags setting -- set this to 0 to use only IEEE flags */
#if !defined(DECEXTFLAG)
diff --git a/source/i18n/decimfmt.cpp b/source/i18n/decimfmt.cpp
index daa1129..c8f1eda 100644
--- a/source/i18n/decimfmt.cpp
+++ b/source/i18n/decimfmt.cpp
@@ -480,8 +480,13 @@ DecimalFormat& DecimalFormat::operator=(const DecimalFormat& rhs) {
DecimalFormat::~DecimalFormat() {
if (fields == nullptr) { return; }
+#ifndef __wasi__
delete fields->atomicParser.exchange(nullptr);
delete fields->atomicCurrencyParser.exchange(nullptr);
+#else
+ delete fields->atomicParser;
+ delete fields->atomicCurrencyParser;
+#endif
delete fields;
}
@@ -1626,8 +1631,13 @@ void DecimalFormat::touch(UErrorCode& status) {
setupFastFormat();
// Delete the parsers if they were made previously
+#ifndef __wasi__
delete fields->atomicParser.exchange(nullptr);
delete fields->atomicCurrencyParser.exchange(nullptr);
+#else
+ delete fields->atomicParser;
+ delete fields->atomicCurrencyParser;
+#endif
// In order for the getters to work, we need to populate some fields in NumberFormat.
NumberFormat::setCurrency(fields->exportedProperties.currency.get(status).getISOCurrency(), status);
@@ -1662,7 +1672,11 @@ const numparse::impl::NumberParserImpl* DecimalFormat::getParser(UErrorCode& sta
}
// First try to get the pre-computed parser
+#ifndef __wasi__
auto* ptr = fields->atomicParser.load();
+#else
+ auto* ptr = fields->atomicParser;
+#endif
if (ptr != nullptr) {
return ptr;
}
@@ -1681,6 +1695,7 @@ const numparse::impl::NumberParserImpl* DecimalFormat::getParser(UErrorCode& sta
// it is set to what is actually stored in the atomic
// if another thread beat us to computing the parser object.
auto* nonConstThis = const_cast<DecimalFormat*>(this);
+#ifndef __wasi__
if (!nonConstThis->fields->atomicParser.compare_exchange_strong(ptr, temp)) {
// Another thread beat us to computing the parser
delete temp;
@@ -1689,13 +1704,21 @@ const numparse::impl::NumberParserImpl* DecimalFormat::getParser(UErrorCode& sta
// Our copy of the parser got stored in the atomic
return temp;
}
+#else
+ nonConstThis->fields->atomicParser = temp;
+ return temp;
+#endif
}
const numparse::impl::NumberParserImpl* DecimalFormat::getCurrencyParser(UErrorCode& status) const {
if (U_FAILURE(status)) { return nullptr; }
// First try to get the pre-computed parser
+#ifndef __wasi__
auto* ptr = fields->atomicCurrencyParser.load();
+#else
+ auto* ptr = fields->atomicCurrencyParser;
+#endif
if (ptr != nullptr) {
return ptr;
}
@@ -1710,6 +1733,7 @@ const numparse::impl::NumberParserImpl* DecimalFormat::getCurrencyParser(UErrorC
// 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 parser object.
auto* nonConstThis = const_cast<DecimalFormat*>(this);
+#ifndef __wasi__
if (!nonConstThis->fields->atomicCurrencyParser.compare_exchange_strong(ptr, temp)) {
// Another thread beat us to computing the parser
delete temp;
@@ -1718,6 +1742,10 @@ const numparse::impl::NumberParserImpl* DecimalFormat::getCurrencyParser(UErrorC
// Our copy of the parser got stored in the atomic
return temp;
}
+#else
+ nonConstThis->fields->atomicCurrencyParser = temp;
+ return temp;
+#endif
}
void
diff --git a/source/i18n/number_mapper.h b/source/i18n/number_mapper.h
index 9ecd776..d094289 100644
--- a/source/i18n/number_mapper.h
+++ b/source/i18n/number_mapper.h
@@ -7,7 +7,6 @@
#ifndef __NUMBER_MAPPER_H__
#define __NUMBER_MAPPER_H__
-#include <atomic>
#include "number_types.h"
#include "unicode/currpinf.h"
#include "standardplural.h"
@@ -15,6 +14,10 @@
#include "number_currencysymbols.h"
#include "numparse_impl.h"
+#ifndef __wasi__
+#include <atomic>
+#endif
+
U_NAMESPACE_BEGIN
namespace number {
namespace impl {
@@ -193,10 +196,18 @@ struct DecimalFormatFields : public UMemory {
LocalizedNumberFormatter formatter;
/** The lazy-computed parser for .parse() */
+#ifndef __wasi__
std::atomic<::icu::numparse::impl::NumberParserImpl*> atomicParser = {};
+#else
+ ::icu::numparse::impl::NumberParserImpl* atomicParser = nullptr;
+#endif
/** The lazy-computed parser for .parseCurrency() */
+#ifndef __wasi__
std::atomic<::icu::numparse::impl::NumberParserImpl*> atomicCurrencyParser = {};
+#else
+ ::icu::numparse::impl::NumberParserImpl* atomicCurrencyParser = {};
+#endif
/** Small object ownership warehouse for the formatter and parser */
DecimalFormatWarehouse warehouse;
diff --git a/source/i18n/numrange_fluent.cpp b/source/i18n/numrange_fluent.cpp
--- a/source/i18n/numrange_fluent.cpp
+++ b/source/i18n/numrange_fluent.cpp
@@ -246,33 +246,53 @@ LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(LocalizedNumberRang
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;
@@ -363,11 +383,15 @@ LocalizedNumberRangeFormatter::getFormatter(UErrorCode& status) const {
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
@@ -378,17 +378,22 @@ LocalizedNumberRangeFormatter::getFormatter(UErrorCode& status) const {
// 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.getAlias())) {
// Another thread beat us to computing the formatter
return ptr;
} else {
// Our copy of the formatter got stored in the atomic
return temp.orphan();
}
+#else
+ nonConstThis->fAtomicFormatter = temp.getAlias();
+ return temp.orphan();
+#endif
}
#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/source/i18n/unicode/numberrangeformatter.h b/source/i18n/unicode/numberrangeformatter.h
index b9a4600..0ba2fa0 100644
--- a/source/i18n/unicode/numberrangeformatter.h
+++ b/source/i18n/unicode/numberrangeformatter.h
@@ -10,7 +10,6 @@
#if !UCONFIG_NO_FORMATTING
-#include <atomic>
#include "unicode/appendable.h"
#include "unicode/fieldpos.h"
#include "unicode/formattedvalue.h"
@@ -18,6 +17,10 @@
#include "unicode/numberformatter.h"
#include "unicode/unumberrangeformatter.h"
+#ifndef __wasi__
+#include <atomic>
+#endif
+
/**
* \file
* \brief C++ API: Library for localized formatting of number, currency, and unit ranges.
@@ -77,7 +80,9 @@ struct UFormattedNumberRangeImpl;
} // namespace icu::number
U_NAMESPACE_END
+#ifndef __wasi__
template struct U_I18N_API std::atomic< U_NAMESPACE_QUALIFIER number::impl::NumberRangeFormatterImpl*>;
+#endif
U_NAMESPACE_BEGIN
namespace number { // icu::number
@@ -546,7 +551,11 @@ class U_I18N_API LocalizedNumberRangeFormatter
~LocalizedNumberRangeFormatter();
private:
+#ifndef __wasi__
std::atomic<impl::NumberRangeFormatterImpl*> fAtomicFormatter = {};
+#else
+ impl::NumberRangeFormatterImpl* fAtomicFormatter = nullptr;
+#endif
const impl::NumberRangeFormatterImpl* getFormatter(UErrorCode& stauts) const;