mirror of
https://codeberg.org/guix/guix.git
synced 2026-01-25 03:55:08 -06:00
* gnu/packages/icu4c.scm (icu4c-78): New variable. * gnu/local.mk (dist_patch_DATA): Add icu4c patches. * gnu/packages/patches/icu4c-78-double-conversion.patch: New file. * gnu/packages/patches/icu4c-bug-1706949-wasi-workaround.patch: New file. * gnu/packages/patches/icu4c-bug-1790071-ICU-22132-standardize-vtzone-output.patch: New file. * gnu/packages/patches/icu4c-bug-1856290-ICU-20548-dateinterval-timezone.patch: New file. * gnu/packages/patches/icu4c-bug-1954138-dtitvfmt-adopt-calendar.patch: New file. * gnu/packages/patches/icu4c-bug-1972781-chinese-based-calendar.patch: New file. * gnu/packages/patches/icu4c-bug-2000225-ICU-23264-increase-measure-unit-capacity.patch: New file. * gnu/packages/patches/icu4c-bug-2002735-ICU-23277-coptic-single-era.patch: New file. * gnu/packages/patches/icu4c-suppress-warnings.patch: New file.
832 lines
24 KiB
Diff
832 lines
24 KiB
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
|
|
--- 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
|
|
--- a/source/common/umapfile.h
|
|
+++ b/source/common/umapfile.h
|
|
@@ -38,10 +38,12 @@ U_CFUNC void uprv_unmapFile(UDataMemory
|
|
#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
|
|
--- a/source/common/umutex.cpp
|
|
+++ b/source/common/umutex.cpp
|
|
@@ -41,10 +41,11 @@ U_NAMESPACE_BEGIN
|
|
*
|
|
* ICU Mutex wrappers.
|
|
*
|
|
*************************************************************************************************/
|
|
|
|
+#ifndef __wasi__
|
|
namespace {
|
|
std::mutex *initMutex;
|
|
std::condition_variable *initCondition;
|
|
|
|
// The ICU global mutex.
|
|
@@ -53,32 +54,38 @@ UMutex globalMutex;
|
|
|
|
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();
|
|
|
|
// Reset the once_flag, by destructing it and creating a fresh one in its place.
|
|
// 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) {
|
|
std::call_once(*pInitFlag, umtx_init);
|
|
std::lock_guard<std::mutex> guard(*initMutex);
|
|
@@ -91,41 +98,48 @@ 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;
|
|
}
|
|
gListHead = nullptr;
|
|
}
|
|
|
|
|
|
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
|
|
}
|
|
|
|
|
|
/*************************************************************************************************
|
|
*
|
|
@@ -141,22 +155,26 @@ umtx_unlock(UMutex* mutex)
|
|
// that knows the C++ types involved. This function returns true if
|
|
// the caller needs to call the Init function.
|
|
//
|
|
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;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -166,15 +184,17 @@ umtx_initImplPreInit(UInitOnce &uio) {
|
|
// Some threads may be racing to test the fState variable outside of the mutex,
|
|
// requiring the use of store/release when changing its value.
|
|
|
|
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
|
|
--- a/source/common/umutex.h
|
|
+++ b/source/common/umutex.h
|
|
@@ -18,13 +18,16 @@
|
|
*/
|
|
|
|
#ifndef UMUTEX_H
|
|
#define UMUTEX_H
|
|
|
|
+#ifndef __wasi__
|
|
#include <atomic>
|
|
#include <condition_variable>
|
|
#include <mutex>
|
|
+#endif
|
|
+
|
|
#include <type_traits>
|
|
|
|
#include "unicode/utypes.h"
|
|
#include "unicode/uclean.h"
|
|
#include "unicode/uobject.h"
|
|
@@ -43,10 +46,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);
|
|
}
|
|
@@ -61,10 +66,31 @@ inline int32_t umtx_atomic_inc(u_atomic_
|
|
|
|
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.
|
|
*
|
|
@@ -211,21 +237,29 @@ public:
|
|
U_COMMON_API UMutex& operator=(const UMutex& other) = delete;
|
|
U_COMMON_API void* operator new(size_t) = delete;
|
|
|
|
// requirements for C++ BasicLockable, allows UMutex to work with std::lock_guard
|
|
U_COMMON_API void lock() {
|
|
+#ifndef __wasi__
|
|
std::mutex *m = fMutex.load(std::memory_order_acquire);
|
|
if (m == nullptr) { m = getMutex(); }
|
|
m->lock();
|
|
+#endif
|
|
}
|
|
- U_COMMON_API void unlock() { fMutex.load(std::memory_order_relaxed)->unlock(); }
|
|
+ U_COMMON_API void unlock() {
|
|
+#ifndef __wasi__
|
|
+ fMutex.load(std::memory_order_relaxed)->unlock();
|
|
+#endif
|
|
+ }
|
|
|
|
U_COMMON_API 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 };
|
|
@@ -233,11 +267,13 @@ private:
|
|
|
|
/** 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()
|
|
+#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_
|
|
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
|
|
--- a/source/i18n/decContext.h
|
|
+++ b/source/i18n/decContext.h
|
|
@@ -59,11 +59,13 @@
|
|
|
|
#if !defined(int32_t)
|
|
/* #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)
|
|
#define DECEXTFLAG 1 /* 1=enable extended flags */
|
|
#endif
|
|
diff --git a/source/i18n/decimfmt.cpp b/source/i18n/decimfmt.cpp
|
|
--- a/source/i18n/decimfmt.cpp
|
|
+++ b/source/i18n/decimfmt.cpp
|
|
@@ -478,12 +478,17 @@ DecimalFormat& DecimalFormat::operator=(
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
DecimalFormat* DecimalFormat::clone() const {
|
|
// can only clone valid objects.
|
|
@@ -1635,12 +1640,17 @@ void DecimalFormat::touch(UErrorCode& st
|
|
|
|
// Do this after fields->exportedProperties are set up
|
|
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);
|
|
NumberFormat::setMaximumIntegerDigits(fields->exportedProperties.maximumIntegerDigits);
|
|
NumberFormat::setMinimumIntegerDigits(fields->exportedProperties.minimumIntegerDigits);
|
|
@@ -1671,11 +1681,15 @@ const numparse::impl::NumberParserImpl*
|
|
if (U_FAILURE(status)) {
|
|
return nullptr;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
// Try computing the parser on our own
|
|
@@ -1690,25 +1704,34 @@ const numparse::impl::NumberParserImpl*
|
|
|
|
// 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->atomicParser.compare_exchange_strong(ptr, temp)) {
|
|
// Another thread beat us to computing the parser
|
|
delete temp;
|
|
return ptr;
|
|
} else {
|
|
// 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;
|
|
}
|
|
|
|
// Try computing the parser on our own
|
|
@@ -1719,18 +1742,23 @@ const numparse::impl::NumberParserImpl*
|
|
}
|
|
|
|
// 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;
|
|
return ptr;
|
|
} else {
|
|
// Our copy of the parser got stored in the atomic
|
|
return temp;
|
|
}
|
|
+#else
|
|
+ nonConstThis->fields->atomicCurrencyParser = temp;
|
|
+ return temp;
|
|
+#endif
|
|
}
|
|
|
|
void
|
|
DecimalFormat::fieldPositionHelper(
|
|
const UFormattedNumberData& formatted,
|
|
diff --git a/source/i18n/number_mapper.h b/source/i18n/number_mapper.h
|
|
--- a/source/i18n/number_mapper.h
|
|
+++ b/source/i18n/number_mapper.h
|
|
@@ -5,18 +5,21 @@
|
|
|
|
#if !UCONFIG_NO_FORMATTING
|
|
#ifndef __NUMBER_MAPPER_H__
|
|
#define __NUMBER_MAPPER_H__
|
|
|
|
-#include <atomic>
|
|
#include "number_types.h"
|
|
#include "unicode/currpinf.h"
|
|
#include "standardplural.h"
|
|
#include "number_patternstring.h"
|
|
#include "number_currencysymbols.h"
|
|
#include "numparse_impl.h"
|
|
|
|
+#ifndef __wasi__
|
|
+#include <atomic>
|
|
+#endif
|
|
+
|
|
U_NAMESPACE_BEGIN
|
|
namespace number::impl {
|
|
|
|
class AutoAffixPatternProvider;
|
|
class CurrencyPluralInfoAffixProvider;
|
|
@@ -194,14 +197,22 @@ struct DecimalFormatFields : public UMem
|
|
* #format} method uses the formatter directly without needing to synchronize.
|
|
*/
|
|
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;
|
|
|
|
/** The effective properties as exported from the formatter object. Used by some getters. */
|
|
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::Localized
|
|
|
|
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::getFormat
|
|
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 +402,22 @@ LocalizedNumberRangeFormatter::getFormat
|
|
|
|
// 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
|
|
--- a/source/i18n/unicode/numberrangeformatter.h
|
|
+++ b/source/i18n/unicode/numberrangeformatter.h
|
|
@@ -8,18 +8,21 @@
|
|
|
|
#if U_SHOW_CPLUSPLUS_API
|
|
|
|
#if !UCONFIG_NO_FORMATTING
|
|
|
|
-#include <atomic>
|
|
#include "unicode/appendable.h"
|
|
#include "unicode/fieldpos.h"
|
|
#include "unicode/formattedvalue.h"
|
|
#include "unicode/fpositer.h"
|
|
#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.
|
|
*
|
|
* The main entrypoint to the formatting of ranges of numbers, including currencies and other units of measurement.
|
|
@@ -559,11 +562,15 @@ class U_I18N_API_CLASS LocalizedNumberRa
|
|
* @stable ICU 63
|
|
*/
|
|
U_I18N_API ~LocalizedNumberRangeFormatter();
|
|
|
|
private:
|
|
+#ifndef __wasi__
|
|
std::atomic<impl::NumberRangeFormatterImpl*> fAtomicFormatter = {};
|
|
+#else
|
|
+ impl::NumberRangeFormatterImpl* fAtomicFormatter = nullptr;
|
|
+#endif
|
|
|
|
const impl::NumberRangeFormatterImpl* getFormatter(UErrorCode& stauts) const;
|
|
|
|
explicit LocalizedNumberRangeFormatter(
|
|
const NumberRangeFormatterSettings<LocalizedNumberRangeFormatter>& other);
|