Bug 1821930 [wpt PR 38950] - LoAF: expose firstUIEventTimestamp, a=testonly
[gecko.git] / intl / icu-patches / bug-1706949-wasi-workaround.diff
blobf56432f174b567119a458c54e8c41e77246b70e0
1 # Handle WASI lack of support for <thread> and <atomic>.
3 # WASI issue: https://github.com/WebAssembly/wasi-sdk/issues/180
5 diff --git a/intl/icu/source/common/putilimp.h b/intl/icu/source/common/putilimp.h
6 index 5b95a68..7097232 100644
7 --- a/intl/icu/source/common/putilimp.h
8 +++ b/intl/icu/source/common/putilimp.h
9 @@ -103,6 +103,8 @@ typedef size_t uintptr_t;
10 #endif
11 #elif U_PLATFORM == U_PF_OS400
12 /* not defined */
13 +#elif defined(__wasi__)
14 + /* not defined */
15 #else
16 # define U_TZSET tzset
17 #endif
18 @@ -128,6 +130,8 @@ typedef size_t uintptr_t;
19 /* not defined */
20 #elif U_PLATFORM == U_PF_IPHONE
21 /* not defined */
22 +#elif defined(__wasi__)
23 + /* not defined */
24 #else
25 # define U_TIMEZONE timezone
26 #endif
27 @@ -141,6 +145,8 @@ typedef size_t uintptr_t;
28 #endif
29 #elif U_PLATFORM == U_PF_OS400
30 /* not defined */
31 +#elif defined(__wasi__)
32 + /* not defined */
33 #else
34 # define U_TZNAME tzname
35 #endif
36 diff --git a/intl/icu/source/common/umapfile.h b/intl/icu/source/common/umapfile.h
37 index 92bd567..4ed1112 100644
38 --- a/intl/icu/source/common/umapfile.h
39 +++ b/intl/icu/source/common/umapfile.h
40 @@ -41,6 +41,8 @@ U_CFUNC void uprv_unmapFile(UDataMemory *pData);
42 #if UCONFIG_NO_FILE_IO
43 # define MAP_IMPLEMENTATION MAP_NONE
44 +#elif defined(__wasi__)
45 +# define MAP_IMPLEMENTATION MAP_STDIO
46 #elif U_PLATFORM_USES_ONLY_WIN32_API
47 # define MAP_IMPLEMENTATION MAP_WIN32
48 #elif U_HAVE_MMAP || U_PLATFORM == U_PF_OS390
49 diff --git a/intl/icu/source/common/umutex.cpp b/intl/icu/source/common/umutex.cpp
50 index ccbee99..6c3452c 100644
51 --- a/intl/icu/source/common/umutex.cpp
52 +++ b/intl/icu/source/common/umutex.cpp
53 @@ -43,6 +43,7 @@ U_NAMESPACE_BEGIN
55 *************************************************************************************************/
57 +#ifndef __wasi__
58 namespace {
59 std::mutex *initMutex;
60 std::condition_variable *initCondition;
61 @@ -55,9 +56,11 @@ std::once_flag initFlag;
62 std::once_flag *pInitFlag = &initFlag;
64 } // Anonymous namespace
65 +#endif
67 U_CDECL_BEGIN
68 static UBool U_CALLCONV umtx_cleanup() {
69 +#ifndef __wasi__
70 initMutex->~mutex();
71 initCondition->~condition_variable();
72 UMutex::cleanup();
73 @@ -66,17 +69,21 @@ static UBool U_CALLCONV umtx_cleanup() {
74 // Do not use this trick anywhere else in ICU; use umtx_initOnce, not std::call_once().
75 pInitFlag->~once_flag();
76 pInitFlag = new(&initFlag) std::once_flag();
77 +#endif
78 return true;
81 static void U_CALLCONV umtx_init() {
82 +#ifndef __wasi__
83 initMutex = STATIC_NEW(std::mutex);
84 initCondition = STATIC_NEW(std::condition_variable);
85 ucln_common_registerCleanup(UCLN_COMMON_MUTEX, umtx_cleanup);
86 +#endif
88 U_CDECL_END
91 +#ifndef __wasi__
92 std::mutex *UMutex::getMutex() {
93 std::mutex *retPtr = fMutex.load(std::memory_order_acquire);
94 if (retPtr == nullptr) {
95 @@ -93,14 +100,17 @@ std::mutex *UMutex::getMutex() {
96 U_ASSERT(retPtr != nullptr);
97 return retPtr;
99 +#endif
101 UMutex *UMutex::gListHead = nullptr;
103 void UMutex::cleanup() {
104 UMutex *next = nullptr;
105 for (UMutex *m = gListHead; m != nullptr; m = next) {
106 +#ifndef __wasi__
107 (*m->fMutex).~mutex();
108 m->fMutex = nullptr;
109 +#endif
110 next = m->fListLink;
111 m->fListLink = nullptr;
113 @@ -110,20 +120,24 @@ void UMutex::cleanup() {
115 U_CAPI void U_EXPORT2
116 umtx_lock(UMutex *mutex) {
117 +#ifndef __wasi__
118 if (mutex == nullptr) {
119 mutex = &globalMutex;
121 mutex->lock();
122 +#endif
126 U_CAPI void U_EXPORT2
127 umtx_unlock(UMutex* mutex)
129 +#ifndef __wasi__
130 if (mutex == nullptr) {
131 mutex = &globalMutex;
133 mutex->unlock();
134 +#endif
138 @@ -143,18 +157,22 @@ umtx_unlock(UMutex* mutex)
140 U_COMMON_API UBool U_EXPORT2
141 umtx_initImplPreInit(UInitOnce &uio) {
142 +#ifndef __wasi__
143 std::call_once(*pInitFlag, umtx_init);
144 std::unique_lock<std::mutex> lock(*initMutex);
145 +#endif
146 if (umtx_loadAcquire(uio.fState) == 0) {
147 umtx_storeRelease(uio.fState, 1);
148 return true; // Caller will next call the init function.
149 } else {
150 +#ifndef __wasi__
151 while (umtx_loadAcquire(uio.fState) == 1) {
152 // Another thread is currently running the initialization.
153 // Wait until it completes.
154 initCondition->wait(lock);
156 U_ASSERT(uio.fState == 2);
157 +#endif
158 return false;
161 @@ -168,11 +186,13 @@ umtx_initImplPreInit(UInitOnce &uio) {
163 U_COMMON_API void U_EXPORT2
164 umtx_initImplPostInit(UInitOnce &uio) {
165 +#ifndef __wasi__
167 std::unique_lock<std::mutex> lock(*initMutex);
168 umtx_storeRelease(uio.fState, 2);
170 initCondition->notify_all();
171 +#endif
174 U_NAMESPACE_END
175 diff --git a/intl/icu/source/common/umutex.h b/intl/icu/source/common/umutex.h
176 index 8d76b3f..c1a58db 100644
177 --- a/intl/icu/source/common/umutex.h
178 +++ b/intl/icu/source/common/umutex.h
179 @@ -20,9 +20,12 @@
180 #ifndef UMUTEX_H
181 #define UMUTEX_H
183 +#ifndef __wasi__
184 #include <atomic>
185 #include <condition_variable>
186 #include <mutex>
187 +#endif
189 #include <type_traits>
191 #include "unicode/utypes.h"
192 @@ -37,6 +40,8 @@
193 #error U_USER_ATOMICS and U_USER_MUTEX_H are not supported
194 #endif
196 +#ifndef __wasi__
198 // Export an explicit template instantiation of std::atomic<int32_t>.
199 // When building DLLs for Windows this is required as it is used as a data member of the exported SharedObject class.
200 // See digitlst.h, pluralaffix.h, datefmt.h, and others for similar examples.
201 @@ -61,6 +66,7 @@ template struct std::atomic<std::mutex *>;
202 #endif
203 #endif
205 +#endif
207 U_NAMESPACE_BEGIN
209 @@ -70,6 +76,8 @@ U_NAMESPACE_BEGIN
211 ****************************************************************************/
213 +#ifndef __wasi__
215 typedef std::atomic<int32_t> u_atomic_int32_t;
216 #define ATOMIC_INT32_T_INITIALIZER(val) ATOMIC_VAR_INIT(val)
218 @@ -89,6 +97,28 @@ inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
219 return var->fetch_sub(1) - 1;
222 +#else
224 +typedef int32_t u_atomic_int32_t;
225 +#define ATOMIC_INT32_T_INITIALIZER(val) val
227 +inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
228 + return var;
231 +inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
232 + var = val;
235 +inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
236 + return ++(*var);
239 +inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
240 + return --(*var);
243 +#endif
245 /*************************************************************************************************
247 @@ -231,17 +261,25 @@ class U_COMMON_API UMutex {
249 // requirements for C++ BasicLockable, allows UMutex to work with std::lock_guard
250 void lock() {
251 +#ifndef __wasi__
252 std::mutex *m = fMutex.load(std::memory_order_acquire);
253 if (m == nullptr) { m = getMutex(); }
254 m->lock();
255 +#endif
257 + void unlock() {
258 +#ifndef __wasi__
259 + fMutex.load(std::memory_order_relaxed)->unlock();
260 +#endif
262 - void unlock() { fMutex.load(std::memory_order_relaxed)->unlock(); }
264 static void cleanup();
266 private:
267 +#ifndef __wasi__
268 alignas(std::mutex) char fStorage[sizeof(std::mutex)] {};
269 std::atomic<std::mutex *> fMutex { nullptr };
270 +#endif
272 /** All initialized UMutexes are kept in a linked list, so that they can be found,
273 * and the underlying std::mutex destructed, by u_cleanup().
274 @@ -253,7 +291,9 @@ class U_COMMON_API UMutex {
275 * Initial fast check is inline, in lock(). The returned value may never
276 * be nullptr.
278 +#ifndef __wasi__
279 std::mutex *getMutex();
280 +#endif
284 diff --git a/intl/icu/source/common/unifiedcache.cpp b/intl/icu/source/common/unifiedcache.cpp
285 --- a/intl/icu/source/common/unifiedcache.cpp
286 +++ b/intl/icu/source/common/unifiedcache.cpp
287 @@ -11,19 +11,23 @@
290 #include "unifiedcache.h"
292 #include <algorithm> // For std::max()
293 -#include <mutex>
294 +#ifndef __wasi__
295 + #include <mutex>
296 +#endif
298 #include "uassert.h"
299 #include "uhash.h"
300 #include "ucln_cmn.h"
302 static icu::UnifiedCache *gCache = NULL;
303 +#ifndef __wasi__
304 static std::mutex *gCacheMutex = nullptr;
305 static std::condition_variable *gInProgressValueAddedCond;
306 +#endif
307 static icu::UInitOnce gCacheInitOnce {};
309 static const int32_t MAX_EVICT_ITERATIONS = 10;
310 static const int32_t DEFAULT_MAX_UNUSED = 1000;
311 static const int32_t DEFAULT_PERCENTAGE_OF_IN_USE = 100;
312 @@ -32,14 +36,16 @@ static const int32_t DEFAULT_PERCENTAGE_OF_IN_USE = 100;
313 U_CDECL_BEGIN
314 static UBool U_CALLCONV unifiedcache_cleanup() {
315 gCacheInitOnce.reset();
316 delete gCache;
317 gCache = nullptr;
318 +#ifndef __wasi__
319 gCacheMutex->~mutex();
320 gCacheMutex = nullptr;
321 gInProgressValueAddedCond->~condition_variable();
322 gInProgressValueAddedCond = nullptr;
323 +#endif
324 return true;
326 U_CDECL_END
329 @@ -70,12 +76,14 @@ CacheKeyBase::~CacheKeyBase() {
330 static void U_CALLCONV cacheInit(UErrorCode &status) {
331 U_ASSERT(gCache == NULL);
332 ucln_common_registerCleanup(
333 UCLN_COMMON_UNIFIED_CACHE, unifiedcache_cleanup);
335 +#ifndef __wasi__
336 gCacheMutex = STATIC_NEW(std::mutex);
337 gInProgressValueAddedCond = STATIC_NEW(std::condition_variable);
338 +#endif
339 gCache = new UnifiedCache(status);
340 if (gCache == NULL) {
341 status = U_MEMORY_ALLOCATION_ERROR;
343 if (U_FAILURE(status)) {
344 @@ -133,41 +141,53 @@ void UnifiedCache::setEvictionPolicy(
346 if (count < 0 || percentageOfInUseItems < 0) {
347 status = U_ILLEGAL_ARGUMENT_ERROR;
348 return;
350 +#ifndef __wasi__
351 std::lock_guard<std::mutex> lock(*gCacheMutex);
352 +#endif
353 fMaxUnused = count;
354 fMaxPercentageOfInUse = percentageOfInUseItems;
357 int32_t UnifiedCache::unusedCount() const {
358 +#ifndef __wasi__
359 std::lock_guard<std::mutex> lock(*gCacheMutex);
360 +#endif
361 return uhash_count(fHashtable) - fNumValuesInUse;
364 int64_t UnifiedCache::autoEvictedCount() const {
365 +#ifndef __wasi__
366 std::lock_guard<std::mutex> lock(*gCacheMutex);
367 +#endif
368 return fAutoEvictedCount;
371 int32_t UnifiedCache::keyCount() const {
372 +#ifndef __wasi__
373 std::lock_guard<std::mutex> lock(*gCacheMutex);
374 +#endif
375 return uhash_count(fHashtable);
378 void UnifiedCache::flush() const {
379 +#ifndef __wasi__
380 std::lock_guard<std::mutex> lock(*gCacheMutex);
381 +#endif
383 // Use a loop in case cache items that are flushed held hard references to
384 // other cache items making those additional cache items eligible for
385 // flushing.
386 while (_flush(false));
389 void UnifiedCache::handleUnreferencedObject() const {
390 +#ifndef __wasi__
391 std::lock_guard<std::mutex> lock(*gCacheMutex);
392 +#endif
393 --fNumValuesInUse;
394 _runEvictionSlice();
397 #ifdef UNIFIED_CACHE_DEBUG
398 @@ -182,11 +202,13 @@ void UnifiedCache::dump() {
400 cache->dumpContents();
403 void UnifiedCache::dumpContents() const {
404 +#ifndef __wasi__
405 std::lock_guard<std::mutex> lock(*gCacheMutex);
406 +#endif
407 _dumpContents();
410 // Dumps content of cache.
411 // On entry, gCacheMutex must be held.
412 @@ -222,11 +244,13 @@ UnifiedCache::~UnifiedCache() {
413 flush();
415 // Now all that should be left in the cache are entries that refer to
416 // each other and entries with hard references from outside the cache.
417 // Nothing we can do about these so proceed to wipe out the cache.
418 +#ifndef __wasi__
419 std::lock_guard<std::mutex> lock(*gCacheMutex);
420 +#endif
421 _flush(true);
423 uhash_close(fHashtable);
424 fHashtable = nullptr;
425 delete fNoValue;
426 @@ -323,11 +347,13 @@ void UnifiedCache::_putNew(
428 void UnifiedCache::_putIfAbsentAndGet(
429 const CacheKeyBase &key,
430 const SharedObject *&value,
431 UErrorCode &status) const {
432 +#ifndef __wasi__
433 std::lock_guard<std::mutex> lock(*gCacheMutex);
434 +#endif
435 const UHashElement *element = uhash_find(fHashtable, &key);
436 if (element != NULL && !_inProgress(element)) {
437 _fetch(element, value, status);
438 return;
440 @@ -348,18 +374,22 @@ UBool UnifiedCache::_poll(
441 const CacheKeyBase &key,
442 const SharedObject *&value,
443 UErrorCode &status) const {
444 U_ASSERT(value == NULL);
445 U_ASSERT(status == U_ZERO_ERROR);
446 +#ifndef __wasi__
447 std::unique_lock<std::mutex> lock(*gCacheMutex);
448 +#endif
449 const UHashElement *element = uhash_find(fHashtable, &key);
451 // If the hash table contains an inProgress placeholder entry for this key,
452 // this means that another thread is currently constructing the value object.
453 // Loop, waiting for that construction to complete.
454 while (element != NULL && _inProgress(element)) {
455 +#ifndef __wasi__
456 gInProgressValueAddedCond->wait(lock);
457 +#endif
458 element = uhash_find(fHashtable, &key);
461 // If the hash table contains an entry for the key,
462 // fetch out the contents and return them.
463 @@ -426,13 +456,15 @@ void UnifiedCache::_put(
464 UHashElement *ptr = const_cast<UHashElement *>(element);
465 ptr->value.pointer = (void *) value;
466 U_ASSERT(oldValue == fNoValue);
467 removeSoftRef(oldValue);
469 +#ifndef __wasi__
470 // Tell waiting threads that we replace in-progress status with
471 // an error.
472 gInProgressValueAddedCond->notify_all();
473 +#endif
476 void UnifiedCache::_fetch(
477 const UHashElement *element,
478 const SharedObject *&value,
479 diff --git a/intl/icu/source/i18n/decContext.h b/intl/icu/source/i18n/decContext.h
480 index 59ab65e..20f3526 100644
481 --- a/intl/icu/source/i18n/decContext.h
482 +++ b/intl/icu/source/i18n/decContext.h
483 @@ -61,7 +61,9 @@
484 /* #include <stdint.h> */ /* C99 standard integers */
485 #endif
486 #include <stdio.h> /* for printf, etc. */
487 +#ifndef __wasi__
488 #include <signal.h> /* for traps */
489 +#endif
491 /* Extended flags setting -- set this to 0 to use only IEEE flags */
492 #if !defined(DECEXTFLAG)
493 diff --git a/intl/icu/source/i18n/decimfmt.cpp b/intl/icu/source/i18n/decimfmt.cpp
494 index daa1129..c8f1eda 100644
495 --- a/intl/icu/source/i18n/decimfmt.cpp
496 +++ b/intl/icu/source/i18n/decimfmt.cpp
497 @@ -480,8 +480,13 @@ DecimalFormat& DecimalFormat::operator=(const DecimalFormat& rhs) {
498 DecimalFormat::~DecimalFormat() {
499 if (fields == nullptr) { return; }
501 +#ifndef __wasi__
502 delete fields->atomicParser.exchange(nullptr);
503 delete fields->atomicCurrencyParser.exchange(nullptr);
504 +#else
505 + delete fields->atomicParser;
506 + delete fields->atomicCurrencyParser;
507 +#endif
508 delete fields;
511 @@ -1626,8 +1631,13 @@ void DecimalFormat::touch(UErrorCode& status) {
512 setupFastFormat();
514 // Delete the parsers if they were made previously
515 +#ifndef __wasi__
516 delete fields->atomicParser.exchange(nullptr);
517 delete fields->atomicCurrencyParser.exchange(nullptr);
518 +#else
519 + delete fields->atomicParser;
520 + delete fields->atomicCurrencyParser;
521 +#endif
523 // In order for the getters to work, we need to populate some fields in NumberFormat.
524 NumberFormat::setCurrency(fields->exportedProperties.currency.get(status).getISOCurrency(), status);
525 @@ -1662,7 +1672,11 @@ const numparse::impl::NumberParserImpl* DecimalFormat::getParser(UErrorCode& sta
528 // First try to get the pre-computed parser
529 +#ifndef __wasi__
530 auto* ptr = fields->atomicParser.load();
531 +#else
532 + auto* ptr = fields->atomicParser;
533 +#endif
534 if (ptr != nullptr) {
535 return ptr;
537 @@ -1681,6 +1695,7 @@ const numparse::impl::NumberParserImpl* DecimalFormat::getParser(UErrorCode& sta
538 // it is set to what is actually stored in the atomic
539 // if another thread beat us to computing the parser object.
540 auto* nonConstThis = const_cast<DecimalFormat*>(this);
541 +#ifndef __wasi__
542 if (!nonConstThis->fields->atomicParser.compare_exchange_strong(ptr, temp)) {
543 // Another thread beat us to computing the parser
544 delete temp;
545 @@ -1689,13 +1704,21 @@ const numparse::impl::NumberParserImpl* DecimalFormat::getParser(UErrorCode& sta
546 // Our copy of the parser got stored in the atomic
547 return temp;
549 +#else
550 + nonConstThis->fields->atomicParser = temp;
551 + return temp;
552 +#endif
555 const numparse::impl::NumberParserImpl* DecimalFormat::getCurrencyParser(UErrorCode& status) const {
556 if (U_FAILURE(status)) { return nullptr; }
558 // First try to get the pre-computed parser
559 +#ifndef __wasi__
560 auto* ptr = fields->atomicCurrencyParser.load();
561 +#else
562 + auto* ptr = fields->atomicCurrencyParser;
563 +#endif
564 if (ptr != nullptr) {
565 return ptr;
567 @@ -1710,6 +1733,7 @@ const numparse::impl::NumberParserImpl* DecimalFormat::getCurrencyParser(UErrorC
568 // Note: ptr starts as nullptr; during compare_exchange, it is set to what is actually stored in the
569 // atomic if another thread beat us to computing the parser object.
570 auto* nonConstThis = const_cast<DecimalFormat*>(this);
571 +#ifndef __wasi__
572 if (!nonConstThis->fields->atomicCurrencyParser.compare_exchange_strong(ptr, temp)) {
573 // Another thread beat us to computing the parser
574 delete temp;
575 @@ -1718,6 +1742,10 @@ const numparse::impl::NumberParserImpl* DecimalFormat::getCurrencyParser(UErrorC
576 // Our copy of the parser got stored in the atomic
577 return temp;
579 +#else
580 + nonConstThis->fields->atomicCurrencyParser = temp;
581 + return temp;
582 +#endif
585 void
586 diff --git a/intl/icu/source/i18n/number_mapper.h b/intl/icu/source/i18n/number_mapper.h
587 index 9ecd776..d094289 100644
588 --- a/intl/icu/source/i18n/number_mapper.h
589 +++ b/intl/icu/source/i18n/number_mapper.h
590 @@ -7,7 +7,6 @@
591 #ifndef __NUMBER_MAPPER_H__
592 #define __NUMBER_MAPPER_H__
594 -#include <atomic>
595 #include "number_types.h"
596 #include "unicode/currpinf.h"
597 #include "standardplural.h"
598 @@ -15,6 +14,10 @@
599 #include "number_currencysymbols.h"
600 #include "numparse_impl.h"
602 +#ifndef __wasi__
603 +#include <atomic>
604 +#endif
606 U_NAMESPACE_BEGIN
607 namespace number {
608 namespace impl {
609 @@ -193,10 +196,18 @@ struct DecimalFormatFields : public UMemory {
610 LocalizedNumberFormatter formatter;
612 /** The lazy-computed parser for .parse() */
613 +#ifndef __wasi__
614 std::atomic<::icu::numparse::impl::NumberParserImpl*> atomicParser = {};
615 +#else
616 + ::icu::numparse::impl::NumberParserImpl* atomicParser = nullptr;
617 +#endif
619 /** The lazy-computed parser for .parseCurrency() */
620 +#ifndef __wasi__
621 std::atomic<::icu::numparse::impl::NumberParserImpl*> atomicCurrencyParser = {};
622 +#else
623 + ::icu::numparse::impl::NumberParserImpl* atomicCurrencyParser = {};
624 +#endif
626 /** Small object ownership warehouse for the formatter and parser */
627 DecimalFormatWarehouse warehouse;
628 diff --git a/intl/icu/source/i18n/numrange_fluent.cpp b/intl/icu/source/i18n/numrange_fluent.cpp
629 index f1060b3..66e12ee 100644
630 --- a/intl/icu/source/i18n/numrange_fluent.cpp
631 +++ b/intl/icu/source/i18n/numrange_fluent.cpp
632 @@ -240,29 +240,49 @@ LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(NFS<LNF>&& src) U_N
633 : NFS<LNF>(std::move(src)) {
634 // Steal the compiled formatter
635 LNF&& _src = static_cast<LNF&&>(src);
636 +#ifndef __wasi__
637 auto* stolen = _src.fAtomicFormatter.exchange(nullptr);
638 delete fAtomicFormatter.exchange(stolen);
639 +#else
640 + delete fAtomicFormatter;
641 + fAtomicFormatter = _src.fAtomicFormatter;
642 + _src.fAtomicFormatter = nullptr;
643 +#endif
646 LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(const LNF& other) {
647 if (this == &other) { return *this; } // self-assignment: no-op
648 NFS<LNF>::operator=(static_cast<const NFS<LNF>&>(other));
649 // Do not steal; just clear
650 +#ifndef __wasi__
651 delete fAtomicFormatter.exchange(nullptr);
652 +#else
653 + delete fAtomicFormatter;
654 +#endif
655 return *this;
658 LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(LNF&& src) U_NOEXCEPT {
659 NFS<LNF>::operator=(static_cast<NFS<LNF>&&>(src));
660 // Steal the compiled formatter
661 +#ifndef __wasi__
662 auto* stolen = src.fAtomicFormatter.exchange(nullptr);
663 delete fAtomicFormatter.exchange(stolen);
664 +#else
665 + delete fAtomicFormatter;
666 + fAtomicFormatter = src.fAtomicFormatter;
667 + src.fAtomicFormatter = nullptr;
668 +#endif
669 return *this;
673 LocalizedNumberRangeFormatter::~LocalizedNumberRangeFormatter() {
674 +#ifndef __wasi__
675 delete fAtomicFormatter.exchange(nullptr);
676 +#else
677 + delete fAtomicFormatter;
678 +#endif
681 LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const RangeMacroProps& macros, const Locale& locale) {
682 @@ -346,7 +366,11 @@ LocalizedNumberRangeFormatter::getFormatter(UErrorCode& status) const {
685 // First try to get the pre-computed formatter
686 +#ifndef __wasi__
687 auto* ptr = fAtomicFormatter.load();
688 +#else
689 + auto* ptr = fAtomicFormatter;
690 +#endif
691 if (ptr != nullptr) {
692 return ptr;
694 @@ -365,6 +389,7 @@ LocalizedNumberRangeFormatter::getFormatter(UErrorCode& status) const {
695 // it is set to what is actually stored in the atomic
696 // if another thread beat us to computing the formatter object.
697 auto* nonConstThis = const_cast<LocalizedNumberRangeFormatter*>(this);
698 +#ifndef __wasi__
699 if (!nonConstThis->fAtomicFormatter.compare_exchange_strong(ptr, temp)) {
700 // Another thread beat us to computing the formatter
701 delete temp;
702 @@ -373,6 +398,10 @@ LocalizedNumberRangeFormatter::getFormatter(UErrorCode& status) const {
703 // Our copy of the formatter got stored in the atomic
704 return temp;
706 +#else
707 + nonConstThis->fAtomicFormatter = temp;
708 + return temp;
709 +#endif
713 diff --git a/intl/icu/source/i18n/unicode/numberrangeformatter.h b/intl/icu/source/i18n/unicode/numberrangeformatter.h
714 index b9a4600..0ba2fa0 100644
715 --- a/intl/icu/source/i18n/unicode/numberrangeformatter.h
716 +++ b/intl/icu/source/i18n/unicode/numberrangeformatter.h
717 @@ -10,7 +10,6 @@
719 #if !UCONFIG_NO_FORMATTING
721 -#include <atomic>
722 #include "unicode/appendable.h"
723 #include "unicode/fieldpos.h"
724 #include "unicode/formattedvalue.h"
725 @@ -18,6 +17,10 @@
726 #include "unicode/numberformatter.h"
727 #include "unicode/unumberrangeformatter.h"
729 +#ifndef __wasi__
730 +#include <atomic>
731 +#endif
734 * \file
735 * \brief C++ API: Library for localized formatting of number, currency, and unit ranges.
736 @@ -77,7 +80,9 @@ struct UFormattedNumberRangeImpl;
737 } // namespace icu::number
738 U_NAMESPACE_END
740 +#ifndef __wasi__
741 template struct U_I18N_API std::atomic< U_NAMESPACE_QUALIFIER number::impl::NumberRangeFormatterImpl*>;
742 +#endif
744 U_NAMESPACE_BEGIN
745 namespace number { // icu::number
746 @@ -546,7 +551,11 @@ class U_I18N_API LocalizedNumberRangeFormatter
747 ~LocalizedNumberRangeFormatter();
749 private:
750 +#ifndef __wasi__
751 std::atomic<impl::NumberRangeFormatterImpl*> fAtomicFormatter = {};
752 +#else
753 + impl::NumberRangeFormatterImpl* fAtomicFormatter = nullptr;
754 +#endif
756 const impl::NumberRangeFormatterImpl* getFormatter(UErrorCode& stauts) const;