#include "unicode/numsys.h"
#include "cstring.h"
#include "uassert.h"
+#include "ucln_in.h"
+#include "umutex.h"
#include "uresimp.h"
#include "numsys_impl.h"
return ( algorithmic );
}
-StringEnumeration* NumberingSystem::getAvailableNames(UErrorCode &status) {
- // TODO(ticket #11908): Init-once static cache, with u_cleanup() callback.
- static StringEnumeration* availableNames = nullptr;
+namespace {
+
+UVector* gNumsysNames = nullptr;
+UInitOnce gNumSysInitOnce = U_INITONCE_INITIALIZER;
+
+U_CFUNC UBool U_CALLCONV numSysCleanup() {
+ delete gNumsysNames;
+ gNumsysNames = nullptr;
+ gNumSysInitOnce.reset();
+ return true;
+}
+U_CFUNC void initNumsysNames(UErrorCode &status) {
+ U_ASSERT(gNumsysNames == nullptr);
+ ucln_i18n_registerCleanup(UCLN_I18N_NUMSYS, numSysCleanup);
+
+ // TODO: Simple array of UnicodeString objects, based on length of table resource?
+ LocalPointer<UVector> numsysNames(new UVector(uprv_deleteUObject, nullptr, status), status);
if (U_FAILURE(status)) {
- return nullptr;
+ return;
}
- if ( availableNames == nullptr ) {
- // TODO: Simple array of UnicodeString objects, based on length of table resource?
- LocalPointer<UVector> numsysNames(new UVector(uprv_deleteUObject, nullptr, status), status);
- if (U_FAILURE(status)) {
- return nullptr;
- }
-
- UErrorCode rbstatus = U_ZERO_ERROR;
- UResourceBundle *numberingSystemsInfo = ures_openDirect(nullptr, "numberingSystems", &rbstatus);
- numberingSystemsInfo = ures_getByKey(numberingSystemsInfo, "numberingSystems", numberingSystemsInfo, &rbstatus);
- if (U_FAILURE(rbstatus)) {
- // Don't stomp on the catastrophic failure of OOM.
- if (rbstatus == U_MEMORY_ALLOCATION_ERROR) {
- status = rbstatus;
- } else {
- status = U_MISSING_RESOURCE_ERROR;
- }
- ures_close(numberingSystemsInfo);
- return nullptr;
+ UErrorCode rbstatus = U_ZERO_ERROR;
+ UResourceBundle *numberingSystemsInfo = ures_openDirect(nullptr, "numberingSystems", &rbstatus);
+ numberingSystemsInfo =
+ ures_getByKey(numberingSystemsInfo, "numberingSystems", numberingSystemsInfo, &rbstatus);
+ if (U_FAILURE(rbstatus)) {
+ // Don't stomp on the catastrophic failure of OOM.
+ if (rbstatus == U_MEMORY_ALLOCATION_ERROR) {
+ status = rbstatus;
+ } else {
+ status = U_MISSING_RESOURCE_ERROR;
}
+ ures_close(numberingSystemsInfo);
+ return;
+ }
- while ( ures_hasNext(numberingSystemsInfo) && U_SUCCESS(status) ) {
- LocalUResourceBundlePointer nsCurrent(ures_getNextResource(numberingSystemsInfo, nullptr, &rbstatus));
- if (rbstatus == U_MEMORY_ALLOCATION_ERROR) {
- status = rbstatus; // we want to report OOM failure back to the caller.
- break;
- }
- const char *nsName = ures_getKey(nsCurrent.getAlias());
- LocalPointer<UnicodeString> newElem(new UnicodeString(nsName, -1, US_INV), status);
+ while ( ures_hasNext(numberingSystemsInfo) && U_SUCCESS(status) ) {
+ LocalUResourceBundlePointer nsCurrent(ures_getNextResource(numberingSystemsInfo, nullptr, &rbstatus));
+ if (rbstatus == U_MEMORY_ALLOCATION_ERROR) {
+ status = rbstatus; // we want to report OOM failure back to the caller.
+ break;
+ }
+ const char *nsName = ures_getKey(nsCurrent.getAlias());
+ LocalPointer<UnicodeString> newElem(new UnicodeString(nsName, -1, US_INV), status);
+ if (U_SUCCESS(status)) {
+ numsysNames->addElement(newElem.getAlias(), status);
if (U_SUCCESS(status)) {
- numsysNames->addElement(newElem.getAlias(), status);
- if (U_SUCCESS(status)) {
- newElem.orphan(); // on success, the numsysNames vector owns newElem.
- }
+ newElem.orphan(); // on success, the numsysNames vector owns newElem.
}
}
+ }
- ures_close(numberingSystemsInfo);
- if (U_FAILURE(status)) {
- return nullptr;
- }
- availableNames = new NumsysNameEnumeration(numsysNames.getAlias(), status);
- if (availableNames == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return nullptr;
- }
- numsysNames.orphan(); // The names got adopted.
+ ures_close(numberingSystemsInfo);
+ if (U_SUCCESS(status)) {
+ gNumsysNames = numsysNames.orphan();
}
+ return;
+}
- return availableNames;
+} // end anonymous namespace
+
+StringEnumeration* NumberingSystem::getAvailableNames(UErrorCode &status) {
+ umtx_initOnce(gNumSysInitOnce, &initNumsysNames, status);
+ LocalPointer<StringEnumeration> result(new NumsysNameEnumeration(status), status);
+ return result.orphan();
}
-NumsysNameEnumeration::NumsysNameEnumeration(UVector *numsysNames, UErrorCode& /*status*/) {
- pos=0;
- fNumsysNames = numsysNames;
+NumsysNameEnumeration::NumsysNameEnumeration(UErrorCode& status) : pos(0) {
+ (void)status;
}
const UnicodeString*
NumsysNameEnumeration::snext(UErrorCode& status) {
- if (U_SUCCESS(status) && (fNumsysNames != nullptr) && (pos < fNumsysNames->size())) {
- return (const UnicodeString*)fNumsysNames->elementAt(pos++);
+ if (U_SUCCESS(status) && (gNumsysNames != nullptr) && (pos < gNumsysNames->size())) {
+ return (const UnicodeString*)gNumsysNames->elementAt(pos++);
}
return nullptr;
}
int32_t
NumsysNameEnumeration::count(UErrorCode& /*status*/) const {
- return (fNumsysNames==nullptr) ? 0 : fNumsysNames->size();
+ return (gNumsysNames==nullptr) ? 0 : gNumsysNames->size();
}
NumsysNameEnumeration::~NumsysNameEnumeration() {
- delete fNumsysNames;
}
U_NAMESPACE_END
}
}
- status = U_ZERO_ERROR;
- uenum = unumsys_openAvailableNames(&status);
- if ( U_SUCCESS(status) ) {
- int32_t numsysCount = 0;
- // sanity check for a couple of number systems that must be in the enumeration
- UBool foundLatn = FALSE;
- UBool foundArab = FALSE;
- while ( (numsys = uenum_next(uenum, NULL, &status)) != NULL && U_SUCCESS(status) ) {
- status = U_ZERO_ERROR;
- unumsys = unumsys_openByName(numsys, &status);
- if ( U_SUCCESS(status) ) {
- numsysCount++;
- if ( uprv_strcmp(numsys, "latn") ) foundLatn = TRUE;
- if ( uprv_strcmp(numsys, "arab") ) foundArab = TRUE;
- unumsys_close(unumsys);
- } else {
- log_err("unumsys_openAvailableNames includes %s but unumsys_openByName on it fails with status %s\n",
- numsys, myErrorName(status));
+ for (int i=0; i<3; ++i) {
+ // Run the test of unumsys_openAvailableNames() multiple times.
+ // Helps verify the management of the internal cache of the names.
+ status = U_ZERO_ERROR;
+ uenum = unumsys_openAvailableNames(&status);
+ if ( U_SUCCESS(status) ) {
+ int32_t numsysCount = 0;
+ // sanity check for a couple of number systems that must be in the enumeration
+ UBool foundLatn = FALSE;
+ UBool foundArab = FALSE;
+ while ( (numsys = uenum_next(uenum, NULL, &status)) != NULL && U_SUCCESS(status) ) {
+ status = U_ZERO_ERROR;
+ unumsys = unumsys_openByName(numsys, &status);
+ if ( U_SUCCESS(status) ) {
+ numsysCount++;
+ if ( uprv_strcmp(numsys, "latn") ) foundLatn = TRUE;
+ if ( uprv_strcmp(numsys, "arab") ) foundArab = TRUE;
+ unumsys_close(unumsys);
+ } else {
+ log_err("unumsys_openAvailableNames includes %s but unumsys_openByName on it fails with status %s\n",
+ numsys, myErrorName(status));
+ }
}
+ uenum_close(uenum);
+ if ( numsysCount < 40 || !foundLatn || !foundArab ) {
+ log_err("unumsys_openAvailableNames results incomplete: numsysCount %d, foundLatn %d, foundArab %d\n",
+ numsysCount, foundLatn, foundArab);
+ }
+ } else {
+ log_data_err("unumsys_openAvailableNames fails with status %s\n", myErrorName(status));
}
- uenum_close(uenum);
- if ( numsysCount < 40 || !foundLatn || !foundArab ) {
- log_err("unumsys_openAvailableNames results incomplete: numsysCount %d, foundLatn %d, foundArab %d\n",
- numsysCount, foundLatn, foundArab);
- }
- } else {
- log_data_err("unumsys_openAvailableNames fails with status %s\n", myErrorName(status));
}
}