mirror of
https://github.com/nodejs/node.git
synced 2025-05-02 03:31:35 +00:00
deps: update icu to 77.1
Some checks failed
Coverage Linux (without intl) / coverage-linux-without-intl (push) Waiting to run
Coverage Linux / coverage-linux (push) Waiting to run
Coverage Windows / coverage-windows (push) Waiting to run
Test and upload documentation to artifacts / build-docs (push) Waiting to run
Linters / lint-addon-docs (push) Waiting to run
Linters / lint-cpp (push) Waiting to run
Linters / format-cpp (push) Waiting to run
Linters / lint-js-and-md (push) Waiting to run
Linters / lint-py (push) Waiting to run
Linters / lint-yaml (push) Waiting to run
Linters / lint-sh (push) Waiting to run
Linters / lint-codeowners (push) Waiting to run
Linters / lint-pr-url (push) Waiting to run
Linters / lint-readme (push) Waiting to run
Notify on Push / Notify on Force Push on `main` (push) Waiting to run
Notify on Push / Notify on Push on `main` that lacks metadata (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Waiting to run
License update / update_license (push) Has been cancelled
Find inactive collaborators / find (push) Has been cancelled
Some checks failed
Coverage Linux (without intl) / coverage-linux-without-intl (push) Waiting to run
Coverage Linux / coverage-linux (push) Waiting to run
Coverage Windows / coverage-windows (push) Waiting to run
Test and upload documentation to artifacts / build-docs (push) Waiting to run
Linters / lint-addon-docs (push) Waiting to run
Linters / lint-cpp (push) Waiting to run
Linters / format-cpp (push) Waiting to run
Linters / lint-js-and-md (push) Waiting to run
Linters / lint-py (push) Waiting to run
Linters / lint-yaml (push) Waiting to run
Linters / lint-sh (push) Waiting to run
Linters / lint-codeowners (push) Waiting to run
Linters / lint-pr-url (push) Waiting to run
Linters / lint-readme (push) Waiting to run
Notify on Push / Notify on Force Push on `main` (push) Waiting to run
Notify on Push / Notify on Push on `main` that lacks metadata (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Waiting to run
License update / update_license (push) Has been cancelled
Find inactive collaborators / find (push) Has been cancelled
PR-URL: https://github.com/nodejs/node/pull/57455 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com> Reviewed-By: LiviaMedeiros <livia@cirno.name> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Steven R Loomis <srl295@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Richard Lau <rlau@redhat.com>
This commit is contained in:
parent
8ccbfb656a
commit
ab9660b55a
2
deps/icu-small/LICENSE
vendored
2
deps/icu-small/LICENSE
vendored
@ -2,7 +2,7 @@ UNICODE LICENSE V3
|
|||||||
|
|
||||||
COPYRIGHT AND PERMISSION NOTICE
|
COPYRIGHT AND PERMISSION NOTICE
|
||||||
|
|
||||||
Copyright © 2016-2024 Unicode, Inc.
|
Copyright © 2016-2025 Unicode, Inc.
|
||||||
|
|
||||||
NOTICE TO USER: Carefully read the following legal agreement. BY
|
NOTICE TO USER: Carefully read the following legal agreement. BY
|
||||||
DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR
|
DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR
|
||||||
|
4
deps/icu-small/README-FULL-ICU.txt
vendored
4
deps/icu-small/README-FULL-ICU.txt
vendored
@ -1,8 +1,8 @@
|
|||||||
ICU sources - auto generated by shrink-icu-src.py
|
ICU sources - auto generated by shrink-icu-src.py
|
||||||
|
|
||||||
This directory contains the ICU subset used by --with-intl=full-icu
|
This directory contains the ICU subset used by --with-intl=full-icu
|
||||||
It is a strict subset of ICU 76 source files with the following exception(s):
|
It is a strict subset of ICU 77 source files with the following exception(s):
|
||||||
* deps/icu-small/source/data/in/icudt76l.dat.bz2 : compressed data file
|
* deps/icu-small/source/data/in/icudt77l.dat.bz2 : compressed data file
|
||||||
|
|
||||||
|
|
||||||
To rebuild this directory, see ../../tools/icu/README.md
|
To rebuild this directory, see ../../tools/icu/README.md
|
||||||
|
59
deps/icu-small/source/common/brkiter.cpp
vendored
59
deps/icu-small/source/common/brkiter.cpp
vendored
@ -59,7 +59,7 @@ BreakIterator::buildInstance(const Locale& loc, const char *type, UErrorCode &st
|
|||||||
{
|
{
|
||||||
char fnbuff[256];
|
char fnbuff[256];
|
||||||
char ext[4]={'\0'};
|
char ext[4]={'\0'};
|
||||||
CharString actualLocale;
|
CharString actual;
|
||||||
int32_t size;
|
int32_t size;
|
||||||
const char16_t* brkfname = nullptr;
|
const char16_t* brkfname = nullptr;
|
||||||
UResourceBundle brkRulesStack;
|
UResourceBundle brkRulesStack;
|
||||||
@ -94,7 +94,7 @@ BreakIterator::buildInstance(const Locale& loc, const char *type, UErrorCode &st
|
|||||||
|
|
||||||
// Use the string if we found it
|
// Use the string if we found it
|
||||||
if (U_SUCCESS(status) && brkfname) {
|
if (U_SUCCESS(status) && brkfname) {
|
||||||
actualLocale.append(ures_getLocaleInternal(brkName, &status), -1, status);
|
actual.append(ures_getLocaleInternal(brkName, &status), -1, status);
|
||||||
|
|
||||||
char16_t* extStart=u_strchr(brkfname, 0x002e);
|
char16_t* extStart=u_strchr(brkfname, 0x002e);
|
||||||
int len = 0;
|
int len = 0;
|
||||||
@ -123,10 +123,9 @@ BreakIterator::buildInstance(const Locale& loc, const char *type, UErrorCode &st
|
|||||||
if (U_SUCCESS(status) && result != nullptr) {
|
if (U_SUCCESS(status) && result != nullptr) {
|
||||||
U_LOCALE_BASED(locBased, *(BreakIterator*)result);
|
U_LOCALE_BASED(locBased, *(BreakIterator*)result);
|
||||||
|
|
||||||
locBased.setLocaleIDs(ures_getLocaleByType(b, ULOC_VALID_LOCALE, &status),
|
locBased.setLocaleIDs(ures_getLocaleByType(b, ULOC_VALID_LOCALE, &status),
|
||||||
actualLocale.data());
|
actual.data(), status);
|
||||||
uprv_strncpy(result->requestLocale, loc.getName(), ULOC_FULLNAME_CAPACITY);
|
LocaleBased::setLocaleID(loc.getName(), result->requestLocale, status);
|
||||||
result->requestLocale[ULOC_FULLNAME_CAPACITY-1] = 0; // always terminate
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ures_close(b);
|
ures_close(b);
|
||||||
@ -206,26 +205,32 @@ BreakIterator::getAvailableLocales(int32_t& count)
|
|||||||
|
|
||||||
BreakIterator::BreakIterator()
|
BreakIterator::BreakIterator()
|
||||||
{
|
{
|
||||||
*validLocale = *actualLocale = *requestLocale = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BreakIterator::BreakIterator(const BreakIterator &other) : UObject(other) {
|
BreakIterator::BreakIterator(const BreakIterator &other) : UObject(other) {
|
||||||
uprv_strncpy(actualLocale, other.actualLocale, sizeof(actualLocale));
|
UErrorCode status = U_ZERO_ERROR;
|
||||||
uprv_strncpy(validLocale, other.validLocale, sizeof(validLocale));
|
U_LOCALE_BASED(locBased, *this);
|
||||||
uprv_strncpy(requestLocale, other.requestLocale, sizeof(requestLocale));
|
locBased.setLocaleIDs(other.validLocale, other.actualLocale, status);
|
||||||
|
LocaleBased::setLocaleID(other.requestLocale, requestLocale, status);
|
||||||
|
U_ASSERT(U_SUCCESS(status));
|
||||||
}
|
}
|
||||||
|
|
||||||
BreakIterator &BreakIterator::operator =(const BreakIterator &other) {
|
BreakIterator &BreakIterator::operator =(const BreakIterator &other) {
|
||||||
if (this != &other) {
|
if (this != &other) {
|
||||||
uprv_strncpy(actualLocale, other.actualLocale, sizeof(actualLocale));
|
UErrorCode status = U_ZERO_ERROR;
|
||||||
uprv_strncpy(validLocale, other.validLocale, sizeof(validLocale));
|
U_LOCALE_BASED(locBased, *this);
|
||||||
uprv_strncpy(requestLocale, other.requestLocale, sizeof(requestLocale));
|
locBased.setLocaleIDs(other.validLocale, other.actualLocale, status);
|
||||||
|
LocaleBased::setLocaleID(other.requestLocale, requestLocale, status);
|
||||||
|
U_ASSERT(U_SUCCESS(status));
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
BreakIterator::~BreakIterator()
|
BreakIterator::~BreakIterator()
|
||||||
{
|
{
|
||||||
|
delete validLocale;
|
||||||
|
delete actualLocale;
|
||||||
|
delete requestLocale;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------
|
// ------------------------------------------
|
||||||
@ -394,7 +399,7 @@ BreakIterator::createInstance(const Locale& loc, int32_t kind, UErrorCode& statu
|
|||||||
// revisit this in ICU 3.0 and clean it up/fix it/remove it.
|
// revisit this in ICU 3.0 and clean it up/fix it/remove it.
|
||||||
if (U_SUCCESS(status) && (result != nullptr) && *actualLoc.getName() != 0) {
|
if (U_SUCCESS(status) && (result != nullptr) && *actualLoc.getName() != 0) {
|
||||||
U_LOCALE_BASED(locBased, *result);
|
U_LOCALE_BASED(locBased, *result);
|
||||||
locBased.setLocaleIDs(actualLoc.getName(), actualLoc.getName());
|
locBased.setLocaleIDs(actualLoc.getName(), actualLoc.getName(), status);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -488,6 +493,7 @@ BreakIterator::makeInstance(const Locale& loc, int32_t kind, UErrorCode& status)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
|
delete result;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -496,20 +502,25 @@ BreakIterator::makeInstance(const Locale& loc, int32_t kind, UErrorCode& status)
|
|||||||
|
|
||||||
Locale
|
Locale
|
||||||
BreakIterator::getLocale(ULocDataLocaleType type, UErrorCode& status) const {
|
BreakIterator::getLocale(ULocDataLocaleType type, UErrorCode& status) const {
|
||||||
if (type == ULOC_REQUESTED_LOCALE) {
|
if (U_FAILURE(status)) {
|
||||||
return {requestLocale};
|
return Locale::getRoot();
|
||||||
}
|
}
|
||||||
U_LOCALE_BASED(locBased, *this);
|
if (type == ULOC_REQUESTED_LOCALE) {
|
||||||
return locBased.getLocale(type, status);
|
return requestLocale == nullptr ?
|
||||||
|
Locale::getRoot() : Locale(requestLocale->data());
|
||||||
|
}
|
||||||
|
return LocaleBased::getLocale(validLocale, actualLocale, type, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
BreakIterator::getLocaleID(ULocDataLocaleType type, UErrorCode& status) const {
|
BreakIterator::getLocaleID(ULocDataLocaleType type, UErrorCode& status) const {
|
||||||
if (type == ULOC_REQUESTED_LOCALE) {
|
if (U_FAILURE(status)) {
|
||||||
return requestLocale;
|
return nullptr;
|
||||||
}
|
}
|
||||||
U_LOCALE_BASED(locBased, *this);
|
if (type == ULOC_REQUESTED_LOCALE) {
|
||||||
return locBased.getLocaleID(type, status);
|
return requestLocale == nullptr ? "" : requestLocale->data();
|
||||||
|
}
|
||||||
|
return LocaleBased::getLocaleID(validLocale, actualLocale, type, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -536,8 +547,10 @@ int32_t BreakIterator::getRuleStatusVec(int32_t *fillInVec, int32_t capacity, UE
|
|||||||
}
|
}
|
||||||
|
|
||||||
BreakIterator::BreakIterator (const Locale& valid, const Locale& actual) {
|
BreakIterator::BreakIterator (const Locale& valid, const Locale& actual) {
|
||||||
|
UErrorCode status = U_ZERO_ERROR;
|
||||||
U_LOCALE_BASED(locBased, (*this));
|
U_LOCALE_BASED(locBased, (*this));
|
||||||
locBased.setLocaleIDs(valid, actual);
|
locBased.setLocaleIDs(valid.getName(), actual.getName(), status);
|
||||||
|
U_ASSERT(U_SUCCESS(status));
|
||||||
}
|
}
|
||||||
|
|
||||||
U_NAMESPACE_END
|
U_NAMESPACE_END
|
||||||
|
11
deps/icu-small/source/common/charstr.cpp
vendored
11
deps/icu-small/source/common/charstr.cpp
vendored
@ -70,6 +70,15 @@ CharString &CharString::copyFrom(const CharString &s, UErrorCode &errorCode) {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CharString &CharString::copyFrom(StringPiece s, UErrorCode &errorCode) {
|
||||||
|
if (U_FAILURE(errorCode)) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
len = 0;
|
||||||
|
append(s, errorCode);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
int32_t CharString::lastIndexOf(char c) const {
|
int32_t CharString::lastIndexOf(char c) const {
|
||||||
for(int32_t i=len; i>0;) {
|
for(int32_t i=len; i>0;) {
|
||||||
if(buffer[--i]==c) {
|
if(buffer[--i]==c) {
|
||||||
@ -143,7 +152,7 @@ CharString &CharString::append(const char *s, int32_t sLength, UErrorCode &error
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
CharString &CharString::appendNumber(int32_t number, UErrorCode &status) {
|
CharString &CharString::appendNumber(int64_t number, UErrorCode &status) {
|
||||||
if (number < 0) {
|
if (number < 0) {
|
||||||
this->append('-', status);
|
this->append('-', status);
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
|
3
deps/icu-small/source/common/charstr.h
vendored
3
deps/icu-small/source/common/charstr.h
vendored
@ -74,6 +74,7 @@ public:
|
|||||||
* use a UErrorCode where memory allocations might be needed.
|
* use a UErrorCode where memory allocations might be needed.
|
||||||
*/
|
*/
|
||||||
CharString ©From(const CharString &other, UErrorCode &errorCode);
|
CharString ©From(const CharString &other, UErrorCode &errorCode);
|
||||||
|
CharString ©From(StringPiece s, UErrorCode &errorCode);
|
||||||
|
|
||||||
UBool isEmpty() const { return len==0; }
|
UBool isEmpty() const { return len==0; }
|
||||||
int32_t length() const { return len; }
|
int32_t length() const { return len; }
|
||||||
@ -135,7 +136,7 @@ public:
|
|||||||
}
|
}
|
||||||
CharString &append(const char *s, int32_t sLength, UErrorCode &status);
|
CharString &append(const char *s, int32_t sLength, UErrorCode &status);
|
||||||
|
|
||||||
CharString &appendNumber(int32_t number, UErrorCode &status);
|
CharString &appendNumber(int64_t number, UErrorCode &status);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a writable buffer for appending and writes the buffer's capacity to
|
* Returns a writable buffer for appending and writes the buffer's capacity to
|
||||||
|
2311
deps/icu-small/source/common/localefallback_data.h
vendored
2311
deps/icu-small/source/common/localefallback_data.h
vendored
File diff suppressed because it is too large
Load Diff
72
deps/icu-small/source/common/locbased.cpp
vendored
72
deps/icu-small/source/common/locbased.cpp
vendored
@ -12,44 +12,84 @@
|
|||||||
*/
|
*/
|
||||||
#include "locbased.h"
|
#include "locbased.h"
|
||||||
#include "cstring.h"
|
#include "cstring.h"
|
||||||
|
#include "charstr.h"
|
||||||
|
|
||||||
U_NAMESPACE_BEGIN
|
U_NAMESPACE_BEGIN
|
||||||
|
|
||||||
Locale LocaleBased::getLocale(ULocDataLocaleType type, UErrorCode& status) const {
|
Locale LocaleBased::getLocale(const CharString* valid, const CharString* actual,
|
||||||
const char* id = getLocaleID(type, status);
|
ULocDataLocaleType type, UErrorCode& status) {
|
||||||
|
const char* id = getLocaleID(valid, actual, type, status);
|
||||||
return Locale(id != nullptr ? id : "");
|
return Locale(id != nullptr ? id : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* LocaleBased::getLocaleID(ULocDataLocaleType type, UErrorCode& status) const {
|
const char* LocaleBased::getLocaleID(const CharString* valid, const CharString* actual,
|
||||||
|
ULocDataLocaleType type, UErrorCode& status) {
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case ULOC_VALID_LOCALE:
|
case ULOC_VALID_LOCALE:
|
||||||
return valid;
|
return valid == nullptr ? "" : valid->data();
|
||||||
case ULOC_ACTUAL_LOCALE:
|
case ULOC_ACTUAL_LOCALE:
|
||||||
return actual;
|
return actual == nullptr ? "" : actual->data();
|
||||||
default:
|
default:
|
||||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocaleBased::setLocaleIDs(const char* validID, const char* actualID) {
|
void LocaleBased::setLocaleIDs(const CharString* validID, const CharString* actualID, UErrorCode& status) {
|
||||||
if (validID != nullptr) {
|
setValidLocaleID(validID, status);
|
||||||
uprv_strncpy(valid, validID, ULOC_FULLNAME_CAPACITY);
|
setActualLocaleID(actualID,status);
|
||||||
valid[ULOC_FULLNAME_CAPACITY-1] = 0; // always terminate
|
}
|
||||||
}
|
void LocaleBased::setLocaleIDs(const char* validID, const char* actualID, UErrorCode& status) {
|
||||||
if (actualID != nullptr) {
|
setValidLocaleID(validID, status);
|
||||||
uprv_strncpy(actual, actualID, ULOC_FULLNAME_CAPACITY);
|
setActualLocaleID(actualID,status);
|
||||||
actual[ULOC_FULLNAME_CAPACITY-1] = 0; // always terminate
|
}
|
||||||
|
|
||||||
|
void LocaleBased::setLocaleID(const char* id, CharString*& dest, UErrorCode& status) {
|
||||||
|
if (U_FAILURE(status)) { return; }
|
||||||
|
if (id == nullptr || *id == 0) {
|
||||||
|
delete dest;
|
||||||
|
dest = nullptr;
|
||||||
|
} else {
|
||||||
|
if (dest == nullptr) {
|
||||||
|
dest = new CharString(id, status);
|
||||||
|
if (dest == nullptr) {
|
||||||
|
status = U_MEMORY_ALLOCATION_ERROR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dest->copyFrom(id, status);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocaleBased::setLocaleIDs(const Locale& validID, const Locale& actualID) {
|
void LocaleBased::setLocaleID(const CharString* id, CharString*& dest, UErrorCode& status) {
|
||||||
uprv_strcpy(valid, validID.getName());
|
if (U_FAILURE(status)) { return; }
|
||||||
uprv_strcpy(actual, actualID.getName());
|
if (id == nullptr || id->isEmpty()) {
|
||||||
|
delete dest;
|
||||||
|
dest = nullptr;
|
||||||
|
} else {
|
||||||
|
if (dest == nullptr) {
|
||||||
|
dest = new CharString(*id, status);
|
||||||
|
if (dest == nullptr) {
|
||||||
|
status = U_MEMORY_ALLOCATION_ERROR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dest->copyFrom(*id, status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LocaleBased::equalIDs(const CharString* left, const CharString* right) {
|
||||||
|
// true if both are nullptr
|
||||||
|
if (left == nullptr && right == nullptr) return true;
|
||||||
|
// false if only one is nullptr
|
||||||
|
if (left == nullptr || right == nullptr) return false;
|
||||||
|
return *left == *right;
|
||||||
}
|
}
|
||||||
|
|
||||||
U_NAMESPACE_END
|
U_NAMESPACE_END
|
||||||
|
64
deps/icu-small/source/common/locbased.h
vendored
64
deps/icu-small/source/common/locbased.h
vendored
@ -19,13 +19,14 @@
|
|||||||
/**
|
/**
|
||||||
* Macro to declare a locale LocaleBased wrapper object for the given
|
* Macro to declare a locale LocaleBased wrapper object for the given
|
||||||
* object, which must have two members named `validLocale' and
|
* object, which must have two members named `validLocale' and
|
||||||
* `actualLocale' of size ULOC_FULLNAME_CAPACITY
|
* `actualLocale' of which are pointers to the internal icu::CharString.
|
||||||
*/
|
*/
|
||||||
#define U_LOCALE_BASED(varname, objname) \
|
#define U_LOCALE_BASED(varname, objname) \
|
||||||
LocaleBased varname((objname).validLocale, (objname).actualLocale)
|
LocaleBased varname((objname).validLocale, (objname).actualLocale)
|
||||||
|
|
||||||
U_NAMESPACE_BEGIN
|
U_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
class CharString;
|
||||||
/**
|
/**
|
||||||
* A utility class that unifies the implementation of getLocale() by
|
* A utility class that unifies the implementation of getLocale() by
|
||||||
* various ICU services. This class is likely to be removed in the
|
* various ICU services. This class is likely to be removed in the
|
||||||
@ -41,33 +42,35 @@ class U_COMMON_API LocaleBased : public UMemory {
|
|||||||
* Construct a LocaleBased wrapper around the two pointers. These
|
* Construct a LocaleBased wrapper around the two pointers. These
|
||||||
* will be aliased for the lifetime of this object.
|
* will be aliased for the lifetime of this object.
|
||||||
*/
|
*/
|
||||||
inline LocaleBased(char* validAlias, char* actualAlias);
|
inline LocaleBased(CharString*& validAlias, CharString*& actualAlias);
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct a LocaleBased wrapper around the two const pointers.
|
|
||||||
* These will be aliased for the lifetime of this object.
|
|
||||||
*/
|
|
||||||
inline LocaleBased(const char* validAlias, const char* actualAlias);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return locale meta-data for the service object wrapped by this
|
* Return locale meta-data for the service object wrapped by this
|
||||||
* object. Either the valid or the actual locale may be
|
* object. Either the valid or the actual locale may be
|
||||||
* retrieved.
|
* retrieved.
|
||||||
|
* @param valid The valid locale.
|
||||||
|
* @param actual The actual locale.
|
||||||
* @param type either ULOC_VALID_LOCALE or ULOC_ACTUAL_LOCALE
|
* @param type either ULOC_VALID_LOCALE or ULOC_ACTUAL_LOCALE
|
||||||
* @param status input-output error code
|
* @param status input-output error code
|
||||||
* @return the indicated locale
|
* @return the indicated locale
|
||||||
*/
|
*/
|
||||||
Locale getLocale(ULocDataLocaleType type, UErrorCode& status) const;
|
static Locale getLocale(
|
||||||
|
const CharString* valid, const CharString* actual,
|
||||||
|
ULocDataLocaleType type, UErrorCode& status);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the locale ID for the service object wrapped by this
|
* Return the locale ID for the service object wrapped by this
|
||||||
* object. Either the valid or the actual locale may be
|
* object. Either the valid or the actual locale may be
|
||||||
* retrieved.
|
* retrieved.
|
||||||
|
* @param valid The valid locale.
|
||||||
|
* @param actual The actual locale.
|
||||||
* @param type either ULOC_VALID_LOCALE or ULOC_ACTUAL_LOCALE
|
* @param type either ULOC_VALID_LOCALE or ULOC_ACTUAL_LOCALE
|
||||||
* @param status input-output error code
|
* @param status input-output error code
|
||||||
* @return the indicated locale ID
|
* @return the indicated locale ID
|
||||||
*/
|
*/
|
||||||
const char* getLocaleID(ULocDataLocaleType type, UErrorCode& status) const;
|
static const char* getLocaleID(
|
||||||
|
const CharString* valid, const CharString* actual,
|
||||||
|
ULocDataLocaleType type, UErrorCode& status);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the locale meta-data for the service object wrapped by this
|
* Set the locale meta-data for the service object wrapped by this
|
||||||
@ -75,31 +78,40 @@ class U_COMMON_API LocaleBased : public UMemory {
|
|||||||
* @param valid the ID of the valid locale
|
* @param valid the ID of the valid locale
|
||||||
* @param actual the ID of the actual locale
|
* @param actual the ID of the actual locale
|
||||||
*/
|
*/
|
||||||
void setLocaleIDs(const char* valid, const char* actual);
|
void setLocaleIDs(const char* valid, const char* actual, UErrorCode& status);
|
||||||
|
void setLocaleIDs(const CharString* valid, const CharString* actual, UErrorCode& status);
|
||||||
|
|
||||||
/**
|
static void setLocaleID(const char* id, CharString*& dest, UErrorCode& status);
|
||||||
* Set the locale meta-data for the service object wrapped by this
|
static void setLocaleID(const CharString* id, CharString*& dest, UErrorCode& status);
|
||||||
* object.
|
|
||||||
* @param valid the ID of the valid locale
|
static bool equalIDs(const CharString* left, const CharString* right);
|
||||||
* @param actual the ID of the actual locale
|
|
||||||
*/
|
|
||||||
void setLocaleIDs(const Locale& valid, const Locale& actual);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
char* valid;
|
void setValidLocaleID(const CharString* id, UErrorCode& status);
|
||||||
|
void setActualLocaleID(const CharString* id, UErrorCode& status);
|
||||||
char* actual;
|
void setValidLocaleID(const char* id, UErrorCode& status);
|
||||||
|
void setActualLocaleID(const char* id, UErrorCode& status);
|
||||||
|
|
||||||
|
CharString*& valid;
|
||||||
|
CharString*& actual;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline LocaleBased::LocaleBased(char* validAlias, char* actualAlias) :
|
inline LocaleBased::LocaleBased(CharString*& validAlias, CharString*& actualAlias) :
|
||||||
valid(validAlias), actual(actualAlias) {
|
valid(validAlias), actual(actualAlias) {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline LocaleBased::LocaleBased(const char* validAlias,
|
inline void LocaleBased::setValidLocaleID(const CharString* id, UErrorCode& status) {
|
||||||
const char* actualAlias) :
|
setLocaleID(id, valid, status);
|
||||||
// ugh: cast away const
|
}
|
||||||
valid(const_cast<char*>(validAlias)), actual(const_cast<char*>(actualAlias)) {
|
inline void LocaleBased::setActualLocaleID(const CharString* id, UErrorCode& status) {
|
||||||
|
setLocaleID(id, actual, status);
|
||||||
|
}
|
||||||
|
inline void LocaleBased::setValidLocaleID(const char* id, UErrorCode& status) {
|
||||||
|
setLocaleID(id, valid, status);
|
||||||
|
}
|
||||||
|
inline void LocaleBased::setActualLocaleID(const char* id, UErrorCode& status) {
|
||||||
|
setLocaleID(id, actual, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
U_NAMESPACE_END
|
U_NAMESPACE_END
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
* that then do not depend on resource bundle code and display name data.
|
* that then do not depend on resource bundle code and display name data.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
#include "unicode/utypes.h"
|
#include "unicode/utypes.h"
|
||||||
#include "unicode/brkiter.h"
|
#include "unicode/brkiter.h"
|
||||||
#include "unicode/locid.h"
|
#include "unicode/locid.h"
|
||||||
@ -359,7 +361,7 @@ _getStringOrCopyKey(const char *path, const char *locale,
|
|||||||
return u_terminateUChars(dest, destCapacity, length, &errorCode);
|
return u_terminateUChars(dest, destCapacity, length, &errorCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
using UDisplayNameGetter = icu::CharString(const char*, UErrorCode&);
|
using UDisplayNameGetter = icu::CharString(std::string_view, UErrorCode&);
|
||||||
|
|
||||||
int32_t
|
int32_t
|
||||||
_getDisplayNameForComponent(const char *locale,
|
_getDisplayNameForComponent(const char *locale,
|
||||||
@ -377,6 +379,10 @@ _getDisplayNameForComponent(const char *locale,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (locale == nullptr) {
|
||||||
|
locale = uloc_getDefault();
|
||||||
|
}
|
||||||
|
|
||||||
localStatus = U_ZERO_ERROR;
|
localStatus = U_ZERO_ERROR;
|
||||||
icu::CharString localeBuffer = (*getter)(locale, localStatus);
|
icu::CharString localeBuffer = (*getter)(locale, localStatus);
|
||||||
if (U_FAILURE(localStatus)) {
|
if (U_FAILURE(localStatus)) {
|
||||||
|
43
deps/icu-small/source/common/locid.cpp
vendored
43
deps/icu-small/source/common/locid.cpp
vendored
@ -1828,8 +1828,13 @@ ulocimp_isCanonicalizedLocaleForTest(const char* localeName)
|
|||||||
|
|
||||||
U_NAMESPACE_BEGIN
|
U_NAMESPACE_BEGIN
|
||||||
|
|
||||||
/*This function initializes a Locale from a C locale ID*/
|
|
||||||
Locale& Locale::init(const char* localeID, UBool canonicalize)
|
Locale& Locale::init(const char* localeID, UBool canonicalize)
|
||||||
|
{
|
||||||
|
return localeID == nullptr ? *this = getDefault() : init(StringPiece{localeID}, canonicalize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*This function initializes a Locale from a C locale ID*/
|
||||||
|
Locale& Locale::init(StringPiece localeID, UBool canonicalize)
|
||||||
{
|
{
|
||||||
fIsBogus = false;
|
fIsBogus = false;
|
||||||
/* Free our current storage */
|
/* Free our current storage */
|
||||||
@ -1854,19 +1859,28 @@ Locale& Locale::init(const char* localeID, UBool canonicalize)
|
|||||||
int32_t length;
|
int32_t length;
|
||||||
UErrorCode err;
|
UErrorCode err;
|
||||||
|
|
||||||
if(localeID == nullptr) {
|
|
||||||
// not an error, just set the default locale
|
|
||||||
return *this = getDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* preset all fields to empty */
|
/* preset all fields to empty */
|
||||||
language[0] = script[0] = country[0] = 0;
|
language[0] = script[0] = country[0] = 0;
|
||||||
|
|
||||||
|
const auto parse = [canonicalize](std::string_view localeID,
|
||||||
|
char* name,
|
||||||
|
int32_t nameCapacity,
|
||||||
|
UErrorCode& status) {
|
||||||
|
return ByteSinkUtil::viaByteSinkToTerminatedChars(
|
||||||
|
name, nameCapacity,
|
||||||
|
[&](ByteSink& sink, UErrorCode& status) {
|
||||||
|
if (canonicalize) {
|
||||||
|
ulocimp_canonicalize(localeID, sink, status);
|
||||||
|
} else {
|
||||||
|
ulocimp_getName(localeID, sink, status);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
status);
|
||||||
|
};
|
||||||
|
|
||||||
// "canonicalize" the locale ID to ICU/Java format
|
// "canonicalize" the locale ID to ICU/Java format
|
||||||
err = U_ZERO_ERROR;
|
err = U_ZERO_ERROR;
|
||||||
length = canonicalize ?
|
length = parse(localeID, fullName, sizeof fullNameBuffer, err);
|
||||||
uloc_canonicalize(localeID, fullName, sizeof(fullNameBuffer), &err) :
|
|
||||||
uloc_getName(localeID, fullName, sizeof(fullNameBuffer), &err);
|
|
||||||
|
|
||||||
if (err == U_BUFFER_OVERFLOW_ERROR || length >= static_cast<int32_t>(sizeof(fullNameBuffer))) {
|
if (err == U_BUFFER_OVERFLOW_ERROR || length >= static_cast<int32_t>(sizeof(fullNameBuffer))) {
|
||||||
U_ASSERT(baseName == nullptr);
|
U_ASSERT(baseName == nullptr);
|
||||||
@ -1877,9 +1891,7 @@ Locale& Locale::init(const char* localeID, UBool canonicalize)
|
|||||||
}
|
}
|
||||||
fullName = newFullName;
|
fullName = newFullName;
|
||||||
err = U_ZERO_ERROR;
|
err = U_ZERO_ERROR;
|
||||||
length = canonicalize ?
|
length = parse(localeID, fullName, length + 1, err);
|
||||||
uloc_canonicalize(localeID, fullName, length+1, &err) :
|
|
||||||
uloc_getName(localeID, fullName, length+1, &err);
|
|
||||||
}
|
}
|
||||||
if(U_FAILURE(err) || err == U_STRING_NOT_TERMINATED_WARNING) {
|
if(U_FAILURE(err) || err == U_STRING_NOT_TERMINATED_WARNING) {
|
||||||
/* should never occur */
|
/* should never occur */
|
||||||
@ -2200,6 +2212,13 @@ Locale::createFromName (const char *name)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Locale U_EXPORT2
|
||||||
|
Locale::createFromName(StringPiece name) {
|
||||||
|
Locale loc("");
|
||||||
|
loc.init(name, false);
|
||||||
|
return loc;
|
||||||
|
}
|
||||||
|
|
||||||
Locale U_EXPORT2
|
Locale U_EXPORT2
|
||||||
Locale::createCanonical(const char* name) {
|
Locale::createCanonical(const char* name) {
|
||||||
Locale loc("");
|
Locale loc("");
|
||||||
|
16
deps/icu-small/source/common/loclikely.cpp
vendored
16
deps/icu-small/source/common/loclikely.cpp
vendored
@ -300,6 +300,9 @@ ulocimp_addLikelySubtags(const char* localeID,
|
|||||||
icu::ByteSink& sink,
|
icu::ByteSink& sink,
|
||||||
UErrorCode& status) {
|
UErrorCode& status) {
|
||||||
if (U_FAILURE(status)) { return; }
|
if (U_FAILURE(status)) { return; }
|
||||||
|
if (localeID == nullptr) {
|
||||||
|
localeID = uloc_getDefault();
|
||||||
|
}
|
||||||
icu::CharString localeBuffer = ulocimp_canonicalize(localeID, status);
|
icu::CharString localeBuffer = ulocimp_canonicalize(localeID, status);
|
||||||
_uloc_addLikelySubtags(localeBuffer.data(), sink, status);
|
_uloc_addLikelySubtags(localeBuffer.data(), sink, status);
|
||||||
}
|
}
|
||||||
@ -334,6 +337,9 @@ ulocimp_minimizeSubtags(const char* localeID,
|
|||||||
bool favorScript,
|
bool favorScript,
|
||||||
UErrorCode& status) {
|
UErrorCode& status) {
|
||||||
if (U_FAILURE(status)) { return; }
|
if (U_FAILURE(status)) { return; }
|
||||||
|
if (localeID == nullptr) {
|
||||||
|
localeID = uloc_getDefault();
|
||||||
|
}
|
||||||
icu::CharString localeBuffer = ulocimp_canonicalize(localeID, status);
|
icu::CharString localeBuffer = ulocimp_canonicalize(localeID, status);
|
||||||
_uloc_minimizeSubtags(localeBuffer.data(), sink, favorScript, status);
|
_uloc_minimizeSubtags(localeBuffer.data(), sink, favorScript, status);
|
||||||
}
|
}
|
||||||
@ -349,7 +355,9 @@ uloc_isRightToLeft(const char *locale) {
|
|||||||
UErrorCode errorCode = U_ZERO_ERROR;
|
UErrorCode errorCode = U_ZERO_ERROR;
|
||||||
icu::CharString lang;
|
icu::CharString lang;
|
||||||
icu::CharString script;
|
icu::CharString script;
|
||||||
ulocimp_getSubtags(locale, &lang, &script, nullptr, nullptr, nullptr, errorCode);
|
ulocimp_getSubtags(
|
||||||
|
locale == nullptr ? uloc_getDefault() : locale,
|
||||||
|
&lang, &script, nullptr, nullptr, nullptr, errorCode);
|
||||||
if (U_FAILURE(errorCode) || script.isEmpty()) {
|
if (U_FAILURE(errorCode) || script.isEmpty()) {
|
||||||
// Fastpath: We know the likely scripts and their writing direction
|
// Fastpath: We know the likely scripts and their writing direction
|
||||||
// for some common languages.
|
// for some common languages.
|
||||||
@ -369,7 +377,7 @@ uloc_isRightToLeft(const char *locale) {
|
|||||||
if (U_FAILURE(errorCode)) {
|
if (U_FAILURE(errorCode)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ulocimp_getSubtags(likely.data(), nullptr, &script, nullptr, nullptr, nullptr, errorCode);
|
ulocimp_getSubtags(likely.toStringPiece(), nullptr, &script, nullptr, nullptr, nullptr, errorCode);
|
||||||
if (U_FAILURE(errorCode) || script.isEmpty()) {
|
if (U_FAILURE(errorCode) || script.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -430,7 +438,7 @@ ulocimp_getRegionForSupplementalData(const char *localeID, bool inferRegion,
|
|||||||
icu::CharString rgBuf = GetRegionFromKey(localeID, "rg", status);
|
icu::CharString rgBuf = GetRegionFromKey(localeID, "rg", status);
|
||||||
if (U_SUCCESS(status) && rgBuf.isEmpty()) {
|
if (U_SUCCESS(status) && rgBuf.isEmpty()) {
|
||||||
// No valid rg keyword value, try for unicode_region_subtag
|
// No valid rg keyword value, try for unicode_region_subtag
|
||||||
rgBuf = ulocimp_getRegion(localeID, status);
|
rgBuf = ulocimp_getRegion(localeID == nullptr ? uloc_getDefault() : localeID, status);
|
||||||
if (U_SUCCESS(status) && rgBuf.isEmpty() && inferRegion) {
|
if (U_SUCCESS(status) && rgBuf.isEmpty() && inferRegion) {
|
||||||
// Second check for sd keyword value
|
// Second check for sd keyword value
|
||||||
rgBuf = GetRegionFromKey(localeID, "sd", status);
|
rgBuf = GetRegionFromKey(localeID, "sd", status);
|
||||||
@ -439,7 +447,7 @@ ulocimp_getRegionForSupplementalData(const char *localeID, bool inferRegion,
|
|||||||
UErrorCode rgStatus = U_ZERO_ERROR;
|
UErrorCode rgStatus = U_ZERO_ERROR;
|
||||||
icu::CharString locBuf = ulocimp_addLikelySubtags(localeID, rgStatus);
|
icu::CharString locBuf = ulocimp_addLikelySubtags(localeID, rgStatus);
|
||||||
if (U_SUCCESS(rgStatus)) {
|
if (U_SUCCESS(rgStatus)) {
|
||||||
rgBuf = ulocimp_getRegion(locBuf.data(), status);
|
rgBuf = ulocimp_getRegion(locBuf.toStringPiece(), status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -527,7 +527,7 @@ LSR LikelySubtags::makeMaximizedLsrFrom(const Locale &locale,
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
const char *name = locale.getName();
|
const char *name = locale.getName();
|
||||||
if (uprv_isAtSign(name[0]) && name[1] == 'x' && name[2] == '=') { // name.startsWith("@x=")
|
if (!returnInputIfUnmatch && uprv_isAtSign(name[0]) && name[1] == 'x' && name[2] == '=') { // name.startsWith("@x=")
|
||||||
// Private use language tag x-subtag-subtag... which CLDR changes to
|
// Private use language tag x-subtag-subtag... which CLDR changes to
|
||||||
// und-x-subtag-subtag...
|
// und-x-subtag-subtag...
|
||||||
return LSR(name, "", "", LSR::EXPLICIT_LSR);
|
return LSR(name, "", "", LSR::EXPLICIT_LSR);
|
||||||
|
3
deps/icu-small/source/common/locresdata.cpp
vendored
3
deps/icu-small/source/common/locresdata.cpp
vendored
@ -161,6 +161,9 @@ _uloc_getOrientationHelper(const char* localeId,
|
|||||||
|
|
||||||
if (U_FAILURE(status)) { return result; }
|
if (U_FAILURE(status)) { return result; }
|
||||||
|
|
||||||
|
if (localeId == nullptr) {
|
||||||
|
localeId = uloc_getDefault();
|
||||||
|
}
|
||||||
icu::CharString localeBuffer = ulocimp_canonicalize(localeId, status);
|
icu::CharString localeBuffer = ulocimp_canonicalize(localeId, status);
|
||||||
|
|
||||||
if (U_FAILURE(status)) { return result; }
|
if (U_FAILURE(status)) { return result; }
|
||||||
|
2
deps/icu-small/source/common/punycode.cpp
vendored
2
deps/icu-small/source/common/punycode.cpp
vendored
@ -193,7 +193,7 @@ u_strToPunycode(const char16_t *src, int32_t srcLength,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(src==nullptr || srcLength<-1 || (dest==nullptr && destCapacity!=0)) {
|
if(src==nullptr || srcLength<-1 || destCapacity<0 || (dest==nullptr && destCapacity!=0)) {
|
||||||
*pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
|
*pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
2
deps/icu-small/source/common/putil.cpp
vendored
2
deps/icu-small/source/common/putil.cpp
vendored
@ -76,7 +76,7 @@
|
|||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
|
||||||
#ifndef U_COMMON_IMPLEMENTATION
|
#ifndef U_COMMON_IMPLEMENTATION
|
||||||
#error U_COMMON_IMPLEMENTATION not set - must be set for all ICU source files in common/ - see https://unicode-org.github.io/icu/userguide/howtouseicu
|
#error U_COMMON_IMPLEMENTATION not set - must be set for all ICU source files in common/ - see https://unicode-org.github.io/icu/userguide/icu/howtouseicu.html
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
118
deps/icu-small/source/common/rbbinode.cpp
vendored
118
deps/icu-small/source/common/rbbinode.cpp
vendored
@ -47,7 +47,10 @@ static int gLastSerial = 0;
|
|||||||
// Constructor. Just set the fields to reasonable default values.
|
// Constructor. Just set the fields to reasonable default values.
|
||||||
//
|
//
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
RBBINode::RBBINode(NodeType t) : UMemory() {
|
RBBINode::RBBINode(NodeType t, UErrorCode& status) : UMemory() {
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
#ifdef RBBI_DEBUG
|
#ifdef RBBI_DEBUG
|
||||||
fSerialNum = ++gLastSerial;
|
fSerialNum = ++gLastSerial;
|
||||||
#endif
|
#endif
|
||||||
@ -65,10 +68,13 @@ RBBINode::RBBINode(NodeType t) : UMemory() {
|
|||||||
fVal = 0;
|
fVal = 0;
|
||||||
fPrecedence = precZero;
|
fPrecedence = precZero;
|
||||||
|
|
||||||
UErrorCode status = U_ZERO_ERROR;
|
fFirstPosSet = new UVector(status);
|
||||||
fFirstPosSet = new UVector(status); // TODO - get a real status from somewhere
|
|
||||||
fLastPosSet = new UVector(status);
|
fLastPosSet = new UVector(status);
|
||||||
fFollowPos = new UVector(status);
|
fFollowPos = new UVector(status);
|
||||||
|
if (U_SUCCESS(status) &&
|
||||||
|
(fFirstPosSet == nullptr || fLastPosSet == nullptr || fFollowPos == nullptr)) {
|
||||||
|
status = U_MEMORY_ALLOCATION_ERROR;
|
||||||
|
}
|
||||||
if (t==opCat) {fPrecedence = precOpCat;}
|
if (t==opCat) {fPrecedence = precOpCat;}
|
||||||
else if (t==opOr) {fPrecedence = precOpOr;}
|
else if (t==opOr) {fPrecedence = precOpOr;}
|
||||||
else if (t==opStart) {fPrecedence = precStart;}
|
else if (t==opStart) {fPrecedence = precStart;}
|
||||||
@ -77,7 +83,10 @@ RBBINode::RBBINode(NodeType t) : UMemory() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
RBBINode::RBBINode(const RBBINode &other) : UMemory(other) {
|
RBBINode::RBBINode(const RBBINode &other, UErrorCode& status) : UMemory(other) {
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
#ifdef RBBI_DEBUG
|
#ifdef RBBI_DEBUG
|
||||||
fSerialNum = ++gLastSerial;
|
fSerialNum = ++gLastSerial;
|
||||||
#endif
|
#endif
|
||||||
@ -94,10 +103,13 @@ RBBINode::RBBINode(const RBBINode &other) : UMemory(other) {
|
|||||||
fVal = other.fVal;
|
fVal = other.fVal;
|
||||||
fRuleRoot = false;
|
fRuleRoot = false;
|
||||||
fChainIn = other.fChainIn;
|
fChainIn = other.fChainIn;
|
||||||
UErrorCode status = U_ZERO_ERROR;
|
|
||||||
fFirstPosSet = new UVector(status); // TODO - get a real status from somewhere
|
fFirstPosSet = new UVector(status); // TODO - get a real status from somewhere
|
||||||
fLastPosSet = new UVector(status);
|
fLastPosSet = new UVector(status);
|
||||||
fFollowPos = new UVector(status);
|
fFollowPos = new UVector(status);
|
||||||
|
if (U_SUCCESS(status) &&
|
||||||
|
(fFirstPosSet == nullptr || fLastPosSet == nullptr || fFollowPos == nullptr)) {
|
||||||
|
status = U_MEMORY_ALLOCATION_ERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -193,27 +205,54 @@ void RBBINode::NRDeleteNode(RBBINode *node) {
|
|||||||
// references in preparation for generating the DFA tables.
|
// references in preparation for generating the DFA tables.
|
||||||
//
|
//
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
RBBINode *RBBINode::cloneTree() {
|
constexpr int kRecursiveDepthLimit = 3500;
|
||||||
|
RBBINode *RBBINode::cloneTree(UErrorCode &status, int depth) {
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
// If the depth of the stack is too deep, we return U_INPUT_TOO_LONG_ERROR
|
||||||
|
// to avoid stack overflow crash.
|
||||||
|
if (depth > kRecursiveDepthLimit) {
|
||||||
|
status = U_INPUT_TOO_LONG_ERROR;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
RBBINode *n;
|
RBBINode *n;
|
||||||
|
|
||||||
if (fType == RBBINode::varRef) {
|
if (fType == RBBINode::varRef) {
|
||||||
// If the current node is a variable reference, skip over it
|
// If the current node is a variable reference, skip over it
|
||||||
// and clone the definition of the variable instead.
|
// and clone the definition of the variable instead.
|
||||||
n = fLeftChild->cloneTree();
|
n = fLeftChild->cloneTree(status, depth+1);
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
} else if (fType == RBBINode::uset) {
|
} else if (fType == RBBINode::uset) {
|
||||||
n = this;
|
n = this;
|
||||||
} else {
|
} else {
|
||||||
n = new RBBINode(*this);
|
n = new RBBINode(*this, status);
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
delete n;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
// Check for null pointer.
|
// Check for null pointer.
|
||||||
if (n != nullptr) {
|
if (n == nullptr) {
|
||||||
if (fLeftChild != nullptr) {
|
status = U_MEMORY_ALLOCATION_ERROR;
|
||||||
n->fLeftChild = fLeftChild->cloneTree();
|
return nullptr;
|
||||||
n->fLeftChild->fParent = n;
|
}
|
||||||
|
if (fLeftChild != nullptr) {
|
||||||
|
n->fLeftChild = fLeftChild->cloneTree(status, depth+1);
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
delete n;
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (fRightChild != nullptr) {
|
n->fLeftChild->fParent = n;
|
||||||
n->fRightChild = fRightChild->cloneTree();
|
}
|
||||||
n->fRightChild->fParent = n;
|
if (fRightChild != nullptr) {
|
||||||
|
n->fRightChild = fRightChild->cloneTree(status, depth+1);
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
delete n;
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
n->fRightChild->fParent = n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
@ -239,7 +278,6 @@ RBBINode *RBBINode::cloneTree() {
|
|||||||
// nested references are handled by cloneTree(), not here.
|
// nested references are handled by cloneTree(), not here.
|
||||||
//
|
//
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
constexpr int kRecursiveDepthLimit = 3500;
|
|
||||||
RBBINode *RBBINode::flattenVariables(UErrorCode& status, int depth) {
|
RBBINode *RBBINode::flattenVariables(UErrorCode& status, int depth) {
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
return this;
|
return this;
|
||||||
@ -251,21 +289,34 @@ RBBINode *RBBINode::flattenVariables(UErrorCode& status, int depth) {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
if (fType == varRef) {
|
if (fType == varRef) {
|
||||||
RBBINode *retNode = fLeftChild->cloneTree();
|
RBBINode *retNode = fLeftChild->cloneTree(status, depth+1);
|
||||||
if (retNode != nullptr) {
|
if (U_FAILURE(status)) {
|
||||||
retNode->fRuleRoot = this->fRuleRoot;
|
return this;
|
||||||
retNode->fChainIn = this->fChainIn;
|
|
||||||
}
|
}
|
||||||
|
retNode->fRuleRoot = this->fRuleRoot;
|
||||||
|
retNode->fChainIn = this->fChainIn;
|
||||||
delete this; // TODO: undefined behavior. Fix.
|
delete this; // TODO: undefined behavior. Fix.
|
||||||
return retNode;
|
return retNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fLeftChild != nullptr) {
|
if (fLeftChild != nullptr) {
|
||||||
fLeftChild = fLeftChild->flattenVariables(status, depth+1);
|
fLeftChild = fLeftChild->flattenVariables(status, depth+1);
|
||||||
|
if (fLeftChild == nullptr) {
|
||||||
|
status = U_MEMORY_ALLOCATION_ERROR;
|
||||||
|
}
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
fLeftChild->fParent = this;
|
fLeftChild->fParent = this;
|
||||||
}
|
}
|
||||||
if (fRightChild != nullptr) {
|
if (fRightChild != nullptr) {
|
||||||
fRightChild = fRightChild->flattenVariables(status, depth+1);
|
fRightChild = fRightChild->flattenVariables(status, depth+1);
|
||||||
|
if (fRightChild == nullptr) {
|
||||||
|
status = U_MEMORY_ALLOCATION_ERROR;
|
||||||
|
}
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
fRightChild->fParent = this;
|
fRightChild->fParent = this;
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
@ -280,7 +331,16 @@ RBBINode *RBBINode::flattenVariables(UErrorCode& status, int depth) {
|
|||||||
// the left child of the uset node.
|
// the left child of the uset node.
|
||||||
//
|
//
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
void RBBINode::flattenSets() {
|
void RBBINode::flattenSets(UErrorCode &status, int depth) {
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// If the depth of the stack is too deep, we return U_INPUT_TOO_LONG_ERROR
|
||||||
|
// to avoid stack overflow crash.
|
||||||
|
if (depth > kRecursiveDepthLimit) {
|
||||||
|
status = U_INPUT_TOO_LONG_ERROR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
U_ASSERT(fType != setRef);
|
U_ASSERT(fType != setRef);
|
||||||
|
|
||||||
if (fLeftChild != nullptr) {
|
if (fLeftChild != nullptr) {
|
||||||
@ -288,11 +348,15 @@ void RBBINode::flattenSets() {
|
|||||||
RBBINode *setRefNode = fLeftChild;
|
RBBINode *setRefNode = fLeftChild;
|
||||||
RBBINode *usetNode = setRefNode->fLeftChild;
|
RBBINode *usetNode = setRefNode->fLeftChild;
|
||||||
RBBINode *replTree = usetNode->fLeftChild;
|
RBBINode *replTree = usetNode->fLeftChild;
|
||||||
fLeftChild = replTree->cloneTree();
|
fLeftChild = replTree->cloneTree(status, depth+1);
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
delete setRefNode;
|
||||||
|
return;
|
||||||
|
}
|
||||||
fLeftChild->fParent = this;
|
fLeftChild->fParent = this;
|
||||||
delete setRefNode;
|
delete setRefNode;
|
||||||
} else {
|
} else {
|
||||||
fLeftChild->flattenSets();
|
fLeftChild->flattenSets(status, depth+1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,11 +365,15 @@ void RBBINode::flattenSets() {
|
|||||||
RBBINode *setRefNode = fRightChild;
|
RBBINode *setRefNode = fRightChild;
|
||||||
RBBINode *usetNode = setRefNode->fLeftChild;
|
RBBINode *usetNode = setRefNode->fLeftChild;
|
||||||
RBBINode *replTree = usetNode->fLeftChild;
|
RBBINode *replTree = usetNode->fLeftChild;
|
||||||
fRightChild = replTree->cloneTree();
|
fRightChild = replTree->cloneTree(status, depth+1);
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
delete setRefNode;
|
||||||
|
return;
|
||||||
|
}
|
||||||
fRightChild->fParent = this;
|
fRightChild->fParent = this;
|
||||||
delete setRefNode;
|
delete setRefNode;
|
||||||
} else {
|
} else {
|
||||||
fRightChild->flattenSets();
|
fRightChild->flattenSets(status, depth+1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
8
deps/icu-small/source/common/rbbinode.h
vendored
8
deps/icu-small/source/common/rbbinode.h
vendored
@ -91,14 +91,14 @@ class RBBINode : public UMemory {
|
|||||||
UVector *fFollowPos;
|
UVector *fFollowPos;
|
||||||
|
|
||||||
|
|
||||||
RBBINode(NodeType t);
|
RBBINode(NodeType t, UErrorCode& status);
|
||||||
RBBINode(const RBBINode &other);
|
RBBINode(const RBBINode &other, UErrorCode& status);
|
||||||
~RBBINode();
|
~RBBINode();
|
||||||
static void NRDeleteNode(RBBINode *node);
|
static void NRDeleteNode(RBBINode *node);
|
||||||
|
|
||||||
RBBINode *cloneTree();
|
RBBINode *cloneTree(UErrorCode &status, int depth=0);
|
||||||
RBBINode *flattenVariables(UErrorCode &status, int depth=0);
|
RBBINode *flattenVariables(UErrorCode &status, int depth=0);
|
||||||
void flattenSets();
|
void flattenSets(UErrorCode &status, int depth=0);
|
||||||
void findNodes(UVector *dest, RBBINode::NodeType kind, UErrorCode &status);
|
void findNodes(UVector *dest, RBBINode::NodeType kind, UErrorCode &status);
|
||||||
|
|
||||||
#ifdef RBBI_DEBUG
|
#ifdef RBBI_DEBUG
|
||||||
|
15
deps/icu-small/source/common/rbbiscan.cpp
vendored
15
deps/icu-small/source/common/rbbiscan.cpp
vendored
@ -767,15 +767,24 @@ void RBBIRuleScanner::findSetFor(const UnicodeString &s, RBBINode *node, Unicode
|
|||||||
c = s.char32At(0);
|
c = s.char32At(0);
|
||||||
setToAdopt = new UnicodeSet(c, c);
|
setToAdopt = new UnicodeSet(c, c);
|
||||||
}
|
}
|
||||||
|
if (setToAdopt == nullptr) {
|
||||||
|
error(U_MEMORY_ALLOCATION_ERROR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Make a new uset node to refer to this UnicodeSet
|
// Make a new uset node to refer to this UnicodeSet
|
||||||
// This new uset node becomes the child of the caller's setReference node.
|
// This new uset node becomes the child of the caller's setReference node.
|
||||||
//
|
//
|
||||||
RBBINode *usetNode = new RBBINode(RBBINode::uset);
|
UErrorCode localStatus = U_ZERO_ERROR;
|
||||||
|
RBBINode *usetNode = new RBBINode(RBBINode::uset, localStatus);
|
||||||
if (usetNode == nullptr) {
|
if (usetNode == nullptr) {
|
||||||
error(U_MEMORY_ALLOCATION_ERROR);
|
localStatus = U_MEMORY_ALLOCATION_ERROR;
|
||||||
|
}
|
||||||
|
if (U_FAILURE(localStatus)) {
|
||||||
|
delete usetNode;
|
||||||
|
error(localStatus);
|
||||||
delete setToAdopt;
|
delete setToAdopt;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1191,7 +1200,7 @@ RBBINode *RBBIRuleScanner::pushNewNode(RBBINode::NodeType t) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
fNodeStackPtr++;
|
fNodeStackPtr++;
|
||||||
fNodeStack[fNodeStackPtr] = new RBBINode(t);
|
fNodeStack[fNodeStackPtr] = new RBBINode(t, *fRB->fStatus);
|
||||||
if (fNodeStack[fNodeStackPtr] == nullptr) {
|
if (fNodeStack[fNodeStackPtr] == nullptr) {
|
||||||
*fRB->fStatus = U_MEMORY_ALLOCATION_ERROR;
|
*fRB->fStatus = U_MEMORY_ALLOCATION_ERROR;
|
||||||
}
|
}
|
||||||
|
12
deps/icu-small/source/common/rbbisetb.cpp
vendored
12
deps/icu-small/source/common/rbbisetb.cpp
vendored
@ -375,7 +375,11 @@ void RBBISetBuilder::addValToSets(UVector *sets, uint32_t val) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RBBISetBuilder::addValToSet(RBBINode *usetNode, uint32_t val) {
|
void RBBISetBuilder::addValToSet(RBBINode *usetNode, uint32_t val) {
|
||||||
RBBINode *leafNode = new RBBINode(RBBINode::leafChar);
|
RBBINode *leafNode = new RBBINode(RBBINode::leafChar, *fStatus);
|
||||||
|
if (U_FAILURE(*fStatus)) {
|
||||||
|
delete leafNode;
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (leafNode == nullptr) {
|
if (leafNode == nullptr) {
|
||||||
*fStatus = U_MEMORY_ALLOCATION_ERROR;
|
*fStatus = U_MEMORY_ALLOCATION_ERROR;
|
||||||
return;
|
return;
|
||||||
@ -388,9 +392,13 @@ void RBBISetBuilder::addValToSet(RBBINode *usetNode, uint32_t val) {
|
|||||||
// There are already input symbols present for this set.
|
// There are already input symbols present for this set.
|
||||||
// Set up an OR node, with the previous stuff as the left child
|
// Set up an OR node, with the previous stuff as the left child
|
||||||
// and the new value as the right child.
|
// and the new value as the right child.
|
||||||
RBBINode *orNode = new RBBINode(RBBINode::opOr);
|
RBBINode *orNode = new RBBINode(RBBINode::opOr, *fStatus);
|
||||||
if (orNode == nullptr) {
|
if (orNode == nullptr) {
|
||||||
*fStatus = U_MEMORY_ALLOCATION_ERROR;
|
*fStatus = U_MEMORY_ALLOCATION_ERROR;
|
||||||
|
}
|
||||||
|
if (U_FAILURE(*fStatus)) {
|
||||||
|
delete orNode;
|
||||||
|
delete leafNode;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
orNode->fLeftChild = usetNode->fLeftChild;
|
orNode->fLeftChild = usetNode->fLeftChild;
|
||||||
|
28
deps/icu-small/source/common/rbbitblb.cpp
vendored
28
deps/icu-small/source/common/rbbitblb.cpp
vendored
@ -99,13 +99,22 @@ void RBBITableBuilder::buildForwardTable() {
|
|||||||
// {bof} fake character.
|
// {bof} fake character.
|
||||||
//
|
//
|
||||||
if (fRB->fSetBuilder->sawBOF()) {
|
if (fRB->fSetBuilder->sawBOF()) {
|
||||||
RBBINode *bofTop = new RBBINode(RBBINode::opCat);
|
RBBINode *bofTop = new RBBINode(RBBINode::opCat, *fStatus);
|
||||||
RBBINode *bofLeaf = new RBBINode(RBBINode::leafChar);
|
if (bofTop == nullptr) {
|
||||||
// Delete and exit if memory allocation failed.
|
|
||||||
if (bofTop == nullptr || bofLeaf == nullptr) {
|
|
||||||
*fStatus = U_MEMORY_ALLOCATION_ERROR;
|
*fStatus = U_MEMORY_ALLOCATION_ERROR;
|
||||||
|
}
|
||||||
|
if (U_FAILURE(*fStatus)) {
|
||||||
delete bofTop;
|
delete bofTop;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
RBBINode *bofLeaf = new RBBINode(RBBINode::leafChar, *fStatus);
|
||||||
|
// Delete and exit if memory allocation failed.
|
||||||
|
if (bofLeaf == nullptr) {
|
||||||
|
*fStatus = U_MEMORY_ALLOCATION_ERROR;
|
||||||
|
}
|
||||||
|
if (U_FAILURE(*fStatus)) {
|
||||||
delete bofLeaf;
|
delete bofLeaf;
|
||||||
|
delete bofTop;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bofTop->fLeftChild = bofLeaf;
|
bofTop->fLeftChild = bofLeaf;
|
||||||
@ -120,18 +129,23 @@ void RBBITableBuilder::buildForwardTable() {
|
|||||||
// Appears as a cat-node, left child being the original tree,
|
// Appears as a cat-node, left child being the original tree,
|
||||||
// right child being the end marker.
|
// right child being the end marker.
|
||||||
//
|
//
|
||||||
RBBINode *cn = new RBBINode(RBBINode::opCat);
|
RBBINode *cn = new RBBINode(RBBINode::opCat, *fStatus);
|
||||||
// Exit if memory allocation failed.
|
// Exit if memory allocation failed.
|
||||||
if (cn == nullptr) {
|
if (cn == nullptr) {
|
||||||
*fStatus = U_MEMORY_ALLOCATION_ERROR;
|
*fStatus = U_MEMORY_ALLOCATION_ERROR;
|
||||||
|
}
|
||||||
|
if (U_FAILURE(*fStatus)) {
|
||||||
|
delete cn;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cn->fLeftChild = fTree;
|
cn->fLeftChild = fTree;
|
||||||
fTree->fParent = cn;
|
fTree->fParent = cn;
|
||||||
RBBINode *endMarkerNode = cn->fRightChild = new RBBINode(RBBINode::endMark);
|
RBBINode *endMarkerNode = cn->fRightChild = new RBBINode(RBBINode::endMark, *fStatus);
|
||||||
// Delete and exit if memory allocation failed.
|
// Delete and exit if memory allocation failed.
|
||||||
if (cn->fRightChild == nullptr) {
|
if (cn->fRightChild == nullptr) {
|
||||||
*fStatus = U_MEMORY_ALLOCATION_ERROR;
|
*fStatus = U_MEMORY_ALLOCATION_ERROR;
|
||||||
|
}
|
||||||
|
if (U_FAILURE(*fStatus)) {
|
||||||
delete cn;
|
delete cn;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -142,7 +156,7 @@ void RBBITableBuilder::buildForwardTable() {
|
|||||||
// Replace all references to UnicodeSets with the tree for the equivalent
|
// Replace all references to UnicodeSets with the tree for the equivalent
|
||||||
// expression.
|
// expression.
|
||||||
//
|
//
|
||||||
fTree->flattenSets();
|
fTree->flattenSets(*fStatus, 0);
|
||||||
#ifdef RBBI_DEBUG
|
#ifdef RBBI_DEBUG
|
||||||
if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "stree")) {
|
if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "stree")) {
|
||||||
RBBIDebugPuts("\nParse tree after flattening Unicode Set references.");
|
RBBIDebugPuts("\nParse tree after flattening Unicode Set references.");
|
||||||
|
2
deps/icu-small/source/common/resbund.cpp
vendored
2
deps/icu-small/source/common/resbund.cpp
vendored
@ -388,7 +388,7 @@ const Locale &ResourceBundle::getLocale() const {
|
|||||||
return ncThis->fLocale != nullptr ? *ncThis->fLocale : Locale::getDefault();
|
return ncThis->fLocale != nullptr ? *ncThis->fLocale : Locale::getDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Locale ResourceBundle::getLocale(ULocDataLocaleType type, UErrorCode &status) const
|
Locale ResourceBundle::getLocale(ULocDataLocaleType type, UErrorCode &status) const
|
||||||
{
|
{
|
||||||
return ures_getLocaleByType(fResource, type, &status);
|
return ures_getLocaleByType(fResource, type, &status);
|
||||||
}
|
}
|
||||||
|
5
deps/icu-small/source/common/ucnvmbcs.cpp
vendored
5
deps/icu-small/source/common/ucnvmbcs.cpp
vendored
@ -3146,11 +3146,8 @@ ucnv_MBCSGetNextUChar(UConverterToUnicodeArgs *pArgs,
|
|||||||
if(c<0) {
|
if(c<0) {
|
||||||
if(U_SUCCESS(*pErrorCode) && source==sourceLimit && lastSource<source) {
|
if(U_SUCCESS(*pErrorCode) && source==sourceLimit && lastSource<source) {
|
||||||
/* incomplete character byte sequence */
|
/* incomplete character byte sequence */
|
||||||
uint8_t *bytes=cnv->toUBytes;
|
|
||||||
cnv->toULength = static_cast<int8_t>(source - lastSource);
|
cnv->toULength = static_cast<int8_t>(source - lastSource);
|
||||||
do {
|
uprv_memcpy(cnv->toUBytes, lastSource, cnv->toULength);
|
||||||
*bytes++=*lastSource++;
|
|
||||||
} while(lastSource<source);
|
|
||||||
*pErrorCode=U_TRUNCATED_CHAR_FOUND;
|
*pErrorCode=U_TRUNCATED_CHAR_FOUND;
|
||||||
} else if(U_FAILURE(*pErrorCode)) {
|
} else if(U_FAILURE(*pErrorCode)) {
|
||||||
/* callback(illegal) */
|
/* callback(illegal) */
|
||||||
|
17
deps/icu-small/source/common/ucurr.cpp
vendored
17
deps/icu-small/source/common/ucurr.cpp
vendored
@ -372,12 +372,8 @@ struct CReg : public icu::UMemory {
|
|||||||
CReg(const char16_t* _iso, const char* _id)
|
CReg(const char16_t* _iso, const char* _id)
|
||||||
: next(nullptr)
|
: next(nullptr)
|
||||||
{
|
{
|
||||||
int32_t len = static_cast<int32_t>(uprv_strlen(_id));
|
uprv_strncpy(id, _id, sizeof(id)-1);
|
||||||
if (len > static_cast<int32_t>(sizeof(id) - 1)) {
|
id[sizeof(id)-1] = 0;
|
||||||
len = (sizeof(id)-1);
|
|
||||||
}
|
|
||||||
uprv_strncpy(id, _id, len);
|
|
||||||
id[len] = 0;
|
|
||||||
u_memcpy(iso, _iso, ISO_CURRENCY_CODE_LENGTH);
|
u_memcpy(iso, _iso, ISO_CURRENCY_CODE_LENGTH);
|
||||||
iso[ISO_CURRENCY_CODE_LENGTH] = 0;
|
iso[ISO_CURRENCY_CODE_LENGTH] = 0;
|
||||||
}
|
}
|
||||||
@ -682,6 +678,9 @@ ucurr_getName(const char16_t* currency,
|
|||||||
// this function.
|
// this function.
|
||||||
UErrorCode ec2 = U_ZERO_ERROR;
|
UErrorCode ec2 = U_ZERO_ERROR;
|
||||||
|
|
||||||
|
if (locale == nullptr) {
|
||||||
|
locale = uloc_getDefault();
|
||||||
|
}
|
||||||
CharString loc = ulocimp_getName(locale, ec2);
|
CharString loc = ulocimp_getName(locale, ec2);
|
||||||
if (U_FAILURE(ec2)) {
|
if (U_FAILURE(ec2)) {
|
||||||
*ec = U_ILLEGAL_ARGUMENT_ERROR;
|
*ec = U_ILLEGAL_ARGUMENT_ERROR;
|
||||||
@ -780,6 +779,9 @@ ucurr_getPluralName(const char16_t* currency,
|
|||||||
// this function.
|
// this function.
|
||||||
UErrorCode ec2 = U_ZERO_ERROR;
|
UErrorCode ec2 = U_ZERO_ERROR;
|
||||||
|
|
||||||
|
if (locale == nullptr) {
|
||||||
|
locale = uloc_getDefault();
|
||||||
|
}
|
||||||
CharString loc = ulocimp_getName(locale, ec2);
|
CharString loc = ulocimp_getName(locale, ec2);
|
||||||
if (U_FAILURE(ec2)) {
|
if (U_FAILURE(ec2)) {
|
||||||
*ec = U_ILLEGAL_ARGUMENT_ERROR;
|
*ec = U_ILLEGAL_ARGUMENT_ERROR;
|
||||||
@ -973,6 +975,9 @@ collectCurrencyNames(const char* locale,
|
|||||||
// Look up the Currencies resource for the given locale.
|
// Look up the Currencies resource for the given locale.
|
||||||
UErrorCode ec2 = U_ZERO_ERROR;
|
UErrorCode ec2 = U_ZERO_ERROR;
|
||||||
|
|
||||||
|
if (locale == nullptr) {
|
||||||
|
locale = uloc_getDefault();
|
||||||
|
}
|
||||||
CharString loc = ulocimp_getName(locale, ec2);
|
CharString loc = ulocimp_getName(locale, ec2);
|
||||||
if (U_FAILURE(ec2)) {
|
if (U_FAILURE(ec2)) {
|
||||||
ec = U_ILLEGAL_ARGUMENT_ERROR;
|
ec = U_ILLEGAL_ARGUMENT_ERROR;
|
||||||
|
551
deps/icu-small/source/common/uloc.cpp
vendored
551
deps/icu-small/source/common/uloc.cpp
vendored
File diff suppressed because it is too large
Load Diff
25
deps/icu-small/source/common/uloc_tag.cpp
vendored
25
deps/icu-small/source/common/uloc_tag.cpp
vendored
@ -1043,7 +1043,7 @@ _initializeULanguageTag(ULanguageTag* langtag) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_appendLanguageToLanguageTag(const char* localeID, icu::ByteSink& sink, bool strict, UErrorCode& status) {
|
_appendLanguageToLanguageTag(std::string_view localeID, icu::ByteSink& sink, bool strict, UErrorCode& status) {
|
||||||
UErrorCode tmpStatus = U_ZERO_ERROR;
|
UErrorCode tmpStatus = U_ZERO_ERROR;
|
||||||
|
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
@ -1088,7 +1088,7 @@ _appendLanguageToLanguageTag(const char* localeID, icu::ByteSink& sink, bool str
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_appendScriptToLanguageTag(const char* localeID, icu::ByteSink& sink, bool strict, UErrorCode& status) {
|
_appendScriptToLanguageTag(std::string_view localeID, icu::ByteSink& sink, bool strict, UErrorCode& status) {
|
||||||
UErrorCode tmpStatus = U_ZERO_ERROR;
|
UErrorCode tmpStatus = U_ZERO_ERROR;
|
||||||
|
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
@ -1118,7 +1118,7 @@ _appendScriptToLanguageTag(const char* localeID, icu::ByteSink& sink, bool stric
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_appendRegionToLanguageTag(const char* localeID, icu::ByteSink& sink, bool strict, UErrorCode& status) {
|
_appendRegionToLanguageTag(std::string_view localeID, icu::ByteSink& sink, bool strict, UErrorCode& status) {
|
||||||
UErrorCode tmpStatus = U_ZERO_ERROR;
|
UErrorCode tmpStatus = U_ZERO_ERROR;
|
||||||
|
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
@ -1169,7 +1169,7 @@ void _sortVariants(VariantListEntry* first) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_appendVariantsToLanguageTag(const char* localeID, icu::ByteSink& sink, bool strict, bool& hadPosix, UErrorCode& status) {
|
_appendVariantsToLanguageTag(std::string_view localeID, icu::ByteSink& sink, bool strict, bool& hadPosix, UErrorCode& status) {
|
||||||
if (U_FAILURE(status)) { return; }
|
if (U_FAILURE(status)) { return; }
|
||||||
|
|
||||||
UErrorCode tmpStatus = U_ZERO_ERROR;
|
UErrorCode tmpStatus = U_ZERO_ERROR;
|
||||||
@ -1872,7 +1872,7 @@ _appendKeywords(ULanguageTag* langtag, icu::ByteSink& sink, UErrorCode& status)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_appendPrivateuseToLanguageTag(const char* localeID, icu::ByteSink& sink, bool strict, bool /*hadPosix*/, UErrorCode& status) {
|
_appendPrivateuseToLanguageTag(std::string_view localeID, icu::ByteSink& sink, bool strict, bool /*hadPosix*/, UErrorCode& status) {
|
||||||
if (U_FAILURE(status)) { return; }
|
if (U_FAILURE(status)) { return; }
|
||||||
|
|
||||||
UErrorCode tmpStatus = U_ZERO_ERROR;
|
UErrorCode tmpStatus = U_ZERO_ERROR;
|
||||||
@ -2596,6 +2596,9 @@ ulocimp_toLanguageTag(const char* localeID,
|
|||||||
bool hadPosix = false;
|
bool hadPosix = false;
|
||||||
const char* pKeywordStart;
|
const char* pKeywordStart;
|
||||||
|
|
||||||
|
if (localeID == nullptr) {
|
||||||
|
localeID = uloc_getDefault();
|
||||||
|
}
|
||||||
/* Note: uloc_canonicalize returns "en_US_POSIX" for input locale ID "". See #6835 */
|
/* Note: uloc_canonicalize returns "en_US_POSIX" for input locale ID "". See #6835 */
|
||||||
icu::CharString canonical = ulocimp_canonicalize(localeID, tmpStatus);
|
icu::CharString canonical = ulocimp_canonicalize(localeID, tmpStatus);
|
||||||
if (U_FAILURE(tmpStatus)) {
|
if (U_FAILURE(tmpStatus)) {
|
||||||
@ -2604,7 +2607,7 @@ ulocimp_toLanguageTag(const char* localeID,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* For handling special case - private use only tag */
|
/* For handling special case - private use only tag */
|
||||||
pKeywordStart = locale_getKeywordsStart(canonical.data());
|
pKeywordStart = locale_getKeywordsStart(canonical.toStringPiece());
|
||||||
if (pKeywordStart == canonical.data()) {
|
if (pKeywordStart == canonical.data()) {
|
||||||
int kwdCnt = 0;
|
int kwdCnt = 0;
|
||||||
bool done = false;
|
bool done = false;
|
||||||
@ -2642,12 +2645,12 @@ ulocimp_toLanguageTag(const char* localeID,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_appendLanguageToLanguageTag(canonical.data(), sink, strict, status);
|
_appendLanguageToLanguageTag(canonical.toStringPiece(), sink, strict, status);
|
||||||
_appendScriptToLanguageTag(canonical.data(), sink, strict, status);
|
_appendScriptToLanguageTag(canonical.toStringPiece(), sink, strict, status);
|
||||||
_appendRegionToLanguageTag(canonical.data(), sink, strict, status);
|
_appendRegionToLanguageTag(canonical.toStringPiece(), sink, strict, status);
|
||||||
_appendVariantsToLanguageTag(canonical.data(), sink, strict, hadPosix, status);
|
_appendVariantsToLanguageTag(canonical.toStringPiece(), sink, strict, hadPosix, status);
|
||||||
_appendKeywordsToLanguageTag(canonical.data(), sink, strict, hadPosix, status);
|
_appendKeywordsToLanguageTag(canonical.data(), sink, strict, hadPosix, status);
|
||||||
_appendPrivateuseToLanguageTag(canonical.data(), sink, strict, hadPosix, status);
|
_appendPrivateuseToLanguageTag(canonical.toStringPiece(), sink, strict, hadPosix, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
5
deps/icu-small/source/common/ulocale.cpp
vendored
5
deps/icu-small/source/common/ulocale.cpp
vendored
@ -10,7 +10,6 @@
|
|||||||
#include "unicode/locid.h"
|
#include "unicode/locid.h"
|
||||||
|
|
||||||
#include "bytesinkutil.h"
|
#include "bytesinkutil.h"
|
||||||
#include "charstr.h"
|
|
||||||
#include "cmemory.h"
|
#include "cmemory.h"
|
||||||
|
|
||||||
U_NAMESPACE_USE
|
U_NAMESPACE_USE
|
||||||
@ -24,9 +23,7 @@ ulocale_openForLocaleID(const char* localeID, int32_t length, UErrorCode* err) {
|
|||||||
if (length < 0) {
|
if (length < 0) {
|
||||||
return EXTERNAL(icu::Locale::createFromName(localeID).clone());
|
return EXTERNAL(icu::Locale::createFromName(localeID).clone());
|
||||||
}
|
}
|
||||||
CharString str(localeID, length, *err); // Make a NUL terminated copy.
|
return EXTERNAL(icu::Locale::createFromName(StringPiece{localeID, length}).clone());
|
||||||
if (U_FAILURE(*err)) { return nullptr; }
|
|
||||||
return EXTERNAL(icu::Locale::createFromName(str.data()).clone());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ULocale*
|
ULocale*
|
||||||
|
32
deps/icu-small/source/common/ulocimp.h
vendored
32
deps/icu-small/source/common/ulocimp.h
vendored
@ -68,42 +68,42 @@ U_EXPORT std::optional<std::string_view>
|
|||||||
ulocimp_toLegacyTypeWithFallback(std::string_view keyword, std::string_view value);
|
ulocimp_toLegacyTypeWithFallback(std::string_view keyword, std::string_view value);
|
||||||
|
|
||||||
U_EXPORT icu::CharString
|
U_EXPORT icu::CharString
|
||||||
ulocimp_getKeywords(const char* localeID,
|
ulocimp_getKeywords(std::string_view localeID,
|
||||||
char prev,
|
char prev,
|
||||||
bool valuesToo,
|
bool valuesToo,
|
||||||
UErrorCode& status);
|
UErrorCode& status);
|
||||||
|
|
||||||
U_EXPORT void
|
U_EXPORT void
|
||||||
ulocimp_getKeywords(const char* localeID,
|
ulocimp_getKeywords(std::string_view localeID,
|
||||||
char prev,
|
char prev,
|
||||||
icu::ByteSink& sink,
|
icu::ByteSink& sink,
|
||||||
bool valuesToo,
|
bool valuesToo,
|
||||||
UErrorCode& status);
|
UErrorCode& status);
|
||||||
|
|
||||||
U_EXPORT icu::CharString
|
U_EXPORT icu::CharString
|
||||||
ulocimp_getName(const char* localeID,
|
ulocimp_getName(std::string_view localeID,
|
||||||
UErrorCode& err);
|
UErrorCode& err);
|
||||||
|
|
||||||
U_EXPORT void
|
U_EXPORT void
|
||||||
ulocimp_getName(const char* localeID,
|
ulocimp_getName(std::string_view localeID,
|
||||||
icu::ByteSink& sink,
|
icu::ByteSink& sink,
|
||||||
UErrorCode& err);
|
UErrorCode& err);
|
||||||
|
|
||||||
U_EXPORT icu::CharString
|
U_EXPORT icu::CharString
|
||||||
ulocimp_getBaseName(const char* localeID,
|
ulocimp_getBaseName(std::string_view localeID,
|
||||||
UErrorCode& err);
|
UErrorCode& err);
|
||||||
|
|
||||||
U_EXPORT void
|
U_EXPORT void
|
||||||
ulocimp_getBaseName(const char* localeID,
|
ulocimp_getBaseName(std::string_view localeID,
|
||||||
icu::ByteSink& sink,
|
icu::ByteSink& sink,
|
||||||
UErrorCode& err);
|
UErrorCode& err);
|
||||||
|
|
||||||
U_EXPORT icu::CharString
|
U_EXPORT icu::CharString
|
||||||
ulocimp_canonicalize(const char* localeID,
|
ulocimp_canonicalize(std::string_view localeID,
|
||||||
UErrorCode& err);
|
UErrorCode& err);
|
||||||
|
|
||||||
U_EXPORT void
|
U_EXPORT void
|
||||||
ulocimp_canonicalize(const char* localeID,
|
ulocimp_canonicalize(std::string_view localeID,
|
||||||
icu::ByteSink& sink,
|
icu::ByteSink& sink,
|
||||||
UErrorCode& err);
|
UErrorCode& err);
|
||||||
|
|
||||||
@ -119,16 +119,16 @@ ulocimp_getKeywordValue(const char* localeID,
|
|||||||
UErrorCode& status);
|
UErrorCode& status);
|
||||||
|
|
||||||
U_EXPORT icu::CharString
|
U_EXPORT icu::CharString
|
||||||
ulocimp_getLanguage(const char* localeID, UErrorCode& status);
|
ulocimp_getLanguage(std::string_view localeID, UErrorCode& status);
|
||||||
|
|
||||||
U_EXPORT icu::CharString
|
U_EXPORT icu::CharString
|
||||||
ulocimp_getScript(const char* localeID, UErrorCode& status);
|
ulocimp_getScript(std::string_view localeID, UErrorCode& status);
|
||||||
|
|
||||||
U_EXPORT icu::CharString
|
U_EXPORT icu::CharString
|
||||||
ulocimp_getRegion(const char* localeID, UErrorCode& status);
|
ulocimp_getRegion(std::string_view localeID, UErrorCode& status);
|
||||||
|
|
||||||
U_EXPORT icu::CharString
|
U_EXPORT icu::CharString
|
||||||
ulocimp_getVariant(const char* localeID, UErrorCode& status);
|
ulocimp_getVariant(std::string_view localeID, UErrorCode& status);
|
||||||
|
|
||||||
U_EXPORT void
|
U_EXPORT void
|
||||||
ulocimp_setKeywordValue(std::string_view keywordName,
|
ulocimp_setKeywordValue(std::string_view keywordName,
|
||||||
@ -145,7 +145,7 @@ ulocimp_setKeywordValue(std::string_view keywords,
|
|||||||
|
|
||||||
U_EXPORT void
|
U_EXPORT void
|
||||||
ulocimp_getSubtags(
|
ulocimp_getSubtags(
|
||||||
const char* localeID,
|
std::string_view localeID,
|
||||||
icu::CharString* language,
|
icu::CharString* language,
|
||||||
icu::CharString* script,
|
icu::CharString* script,
|
||||||
icu::CharString* region,
|
icu::CharString* region,
|
||||||
@ -155,7 +155,7 @@ ulocimp_getSubtags(
|
|||||||
|
|
||||||
U_EXPORT void
|
U_EXPORT void
|
||||||
ulocimp_getSubtags(
|
ulocimp_getSubtags(
|
||||||
const char* localeID,
|
std::string_view localeID,
|
||||||
icu::ByteSink* language,
|
icu::ByteSink* language,
|
||||||
icu::ByteSink* script,
|
icu::ByteSink* script,
|
||||||
icu::ByteSink* region,
|
icu::ByteSink* region,
|
||||||
@ -165,7 +165,7 @@ ulocimp_getSubtags(
|
|||||||
|
|
||||||
inline void
|
inline void
|
||||||
ulocimp_getSubtags(
|
ulocimp_getSubtags(
|
||||||
const char* localeID,
|
std::string_view localeID,
|
||||||
std::nullptr_t,
|
std::nullptr_t,
|
||||||
std::nullptr_t,
|
std::nullptr_t,
|
||||||
std::nullptr_t,
|
std::nullptr_t,
|
||||||
@ -364,7 +364,7 @@ ulocimp_minimizeSubtags(const char* localeID,
|
|||||||
UErrorCode& err);
|
UErrorCode& err);
|
||||||
|
|
||||||
U_CAPI const char * U_EXPORT2
|
U_CAPI const char * U_EXPORT2
|
||||||
locale_getKeywordsStart(const char *localeID);
|
locale_getKeywordsStart(std::string_view localeID);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ultag_isExtensionSubtags(const char* s, int32_t len);
|
ultag_isExtensionSubtags(const char* s, int32_t len);
|
||||||
|
7
deps/icu-small/source/common/umapfile.cpp
vendored
7
deps/icu-small/source/common/umapfile.cpp
vendored
@ -237,8 +237,13 @@ typedef HANDLE MemoryMap;
|
|||||||
pData->map = (char *)data + length;
|
pData->map = (char *)data + length;
|
||||||
pData->pHeader=(const DataHeader *)data;
|
pData->pHeader=(const DataHeader *)data;
|
||||||
pData->mapAddr = data;
|
pData->mapAddr = data;
|
||||||
#if U_PLATFORM == U_PF_IPHONE
|
#if U_PLATFORM == U_PF_IPHONE || U_PLATFORM == U_PF_ANDROID
|
||||||
|
// Apparently supported from Android 23 and higher:
|
||||||
|
// https://github.com/ggml-org/llama.cpp/pull/3631
|
||||||
|
// Checking for the flag itself is safer than checking for __ANDROID_API__.
|
||||||
|
# ifdef POSIX_MADV_RANDOM
|
||||||
posix_madvise(data, length, POSIX_MADV_RANDOM);
|
posix_madvise(data, length, POSIX_MADV_RANDOM);
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,8 @@ U_NAMESPACE_END
|
|||||||
|
|
||||||
U_NAMESPACE_BEGIN
|
U_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
class CharString;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The BreakIterator class implements methods for finding the location
|
* The BreakIterator class implements methods for finding the location
|
||||||
* of boundaries in text. BreakIterator is an abstract base class.
|
* of boundaries in text. BreakIterator is an abstract base class.
|
||||||
@ -646,9 +648,9 @@ protected:
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
/** @internal (private) */
|
/** @internal (private) */
|
||||||
char actualLocale[ULOC_FULLNAME_CAPACITY];
|
CharString* actualLocale = nullptr;
|
||||||
char validLocale[ULOC_FULLNAME_CAPACITY];
|
CharString* validLocale = nullptr;
|
||||||
char requestLocale[ULOC_FULLNAME_CAPACITY];
|
CharString* requestLocale = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef U_HIDE_DEPRECATED_API
|
#ifndef U_HIDE_DEPRECATED_API
|
||||||
|
77
deps/icu-small/source/common/unicode/char16ptr.h
vendored
77
deps/icu-small/source/common/unicode/char16ptr.h
vendored
@ -9,10 +9,13 @@
|
|||||||
|
|
||||||
#include "unicode/utypes.h"
|
#include "unicode/utypes.h"
|
||||||
|
|
||||||
#if U_SHOW_CPLUSPLUS_API
|
#if U_SHOW_CPLUSPLUS_API || U_SHOW_CPLUSPLUS_HEADER_API
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \file
|
* \file
|
||||||
@ -21,8 +24,6 @@
|
|||||||
* Also conversion functions from char16_t * to UChar * and OldUChar *.
|
* Also conversion functions from char16_t * to UChar * and OldUChar *.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
U_NAMESPACE_BEGIN
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \def U_ALIASING_BARRIER
|
* \def U_ALIASING_BARRIER
|
||||||
* Barrier for pointer anti-aliasing optimizations even across function boundaries.
|
* Barrier for pointer anti-aliasing optimizations even across function boundaries.
|
||||||
@ -36,6 +37,11 @@ U_NAMESPACE_BEGIN
|
|||||||
# define U_ALIASING_BARRIER(ptr)
|
# define U_ALIASING_BARRIER(ptr)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// ICU DLL-exported
|
||||||
|
#if U_SHOW_CPLUSPLUS_API
|
||||||
|
|
||||||
|
U_NAMESPACE_BEGIN
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* char16_t * wrapper with implicit conversion from distinct but bit-compatible pointer types.
|
* char16_t * wrapper with implicit conversion from distinct but bit-compatible pointer types.
|
||||||
* @stable ICU 59
|
* @stable ICU 59
|
||||||
@ -251,6 +257,60 @@ const char16_t *ConstChar16Ptr::get() const { return u_.cp; }
|
|||||||
#endif
|
#endif
|
||||||
/// \endcond
|
/// \endcond
|
||||||
|
|
||||||
|
U_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // U_SHOW_CPLUSPLUS_API
|
||||||
|
|
||||||
|
// Usable in header-only definitions
|
||||||
|
#if U_SHOW_CPLUSPLUS_API || U_SHOW_CPLUSPLUS_HEADER_API
|
||||||
|
|
||||||
|
namespace U_ICU_NAMESPACE_OR_INTERNAL {
|
||||||
|
|
||||||
|
#ifndef U_FORCE_HIDE_INTERNAL_API
|
||||||
|
/** @internal */
|
||||||
|
template<typename T, typename = std::enable_if_t<std::is_same_v<T, UChar>>>
|
||||||
|
inline const char16_t *uprv_char16PtrFromUChar(const T *p) {
|
||||||
|
if constexpr (std::is_same_v<UChar, char16_t>) {
|
||||||
|
return p;
|
||||||
|
} else {
|
||||||
|
#if U_SHOW_CPLUSPLUS_API
|
||||||
|
return ConstChar16Ptr(p).get();
|
||||||
|
#else
|
||||||
|
#ifdef U_ALIASING_BARRIER
|
||||||
|
U_ALIASING_BARRIER(p);
|
||||||
|
#endif
|
||||||
|
return reinterpret_cast<const char16_t *>(p);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if !U_CHAR16_IS_TYPEDEF && (!defined(_LIBCPP_VERSION) || _LIBCPP_VERSION < 180000)
|
||||||
|
/** @internal */
|
||||||
|
inline const char16_t *uprv_char16PtrFromUint16(const uint16_t *p) {
|
||||||
|
#if U_SHOW_CPLUSPLUS_API
|
||||||
|
return ConstChar16Ptr(p).get();
|
||||||
|
#else
|
||||||
|
#ifdef U_ALIASING_BARRIER
|
||||||
|
U_ALIASING_BARRIER(p);
|
||||||
|
#endif
|
||||||
|
return reinterpret_cast<const char16_t *>(p);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if U_SIZEOF_WCHAR_T==2
|
||||||
|
/** @internal */
|
||||||
|
inline const char16_t *uprv_char16PtrFromWchar(const wchar_t *p) {
|
||||||
|
#if U_SHOW_CPLUSPLUS_API
|
||||||
|
return ConstChar16Ptr(p).get();
|
||||||
|
#else
|
||||||
|
#ifdef U_ALIASING_BARRIER
|
||||||
|
U_ALIASING_BARRIER(p);
|
||||||
|
#endif
|
||||||
|
return reinterpret_cast<const char16_t *>(p);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts from const char16_t * to const UChar *.
|
* Converts from const char16_t * to const UChar *.
|
||||||
* Includes an aliasing barrier if available.
|
* Includes an aliasing barrier if available.
|
||||||
@ -307,6 +367,15 @@ inline OldUChar *toOldUCharPtr(char16_t *p) {
|
|||||||
return reinterpret_cast<OldUChar *>(p);
|
return reinterpret_cast<OldUChar *>(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // U_ICU_NAMESPACE_OR_INTERNAL
|
||||||
|
|
||||||
|
#endif // U_SHOW_CPLUSPLUS_API || U_SHOW_CPLUSPLUS_HEADER_API
|
||||||
|
|
||||||
|
// ICU DLL-exported
|
||||||
|
#if U_SHOW_CPLUSPLUS_API
|
||||||
|
|
||||||
|
U_NAMESPACE_BEGIN
|
||||||
|
|
||||||
#ifndef U_FORCE_HIDE_INTERNAL_API
|
#ifndef U_FORCE_HIDE_INTERNAL_API
|
||||||
/**
|
/**
|
||||||
* Is T convertible to a std::u16string_view or some other 16-bit string view?
|
* Is T convertible to a std::u16string_view or some other 16-bit string view?
|
||||||
@ -379,6 +448,6 @@ inline std::u16string_view toU16StringViewNullable(const T& text) {
|
|||||||
|
|
||||||
U_NAMESPACE_END
|
U_NAMESPACE_END
|
||||||
|
|
||||||
#endif /* U_SHOW_CPLUSPLUS_API */
|
#endif // U_SHOW_CPLUSPLUS_API
|
||||||
|
|
||||||
#endif // __CHAR16PTR_H__
|
#endif // __CHAR16PTR_H__
|
||||||
|
9
deps/icu-small/source/common/unicode/locid.h
vendored
9
deps/icu-small/source/common/unicode/locid.h
vendored
@ -449,6 +449,11 @@ public:
|
|||||||
*/
|
*/
|
||||||
static Locale U_EXPORT2 createFromName(const char *name);
|
static Locale U_EXPORT2 createFromName(const char *name);
|
||||||
|
|
||||||
|
#ifndef U_HIDE_INTERNAL_API
|
||||||
|
/** @internal */
|
||||||
|
static Locale U_EXPORT2 createFromName(StringPiece name);
|
||||||
|
#endif /* U_HIDE_INTERNAL_API */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a locale from the given string after canonicalizing
|
* Creates a locale from the given string after canonicalizing
|
||||||
* the string according to CLDR by calling uloc_canonicalize().
|
* the string according to CLDR by calling uloc_canonicalize().
|
||||||
@ -1133,7 +1138,9 @@ private:
|
|||||||
* @param cLocaleID The new locale name.
|
* @param cLocaleID The new locale name.
|
||||||
* @param canonicalize whether to call uloc_canonicalize on cLocaleID
|
* @param canonicalize whether to call uloc_canonicalize on cLocaleID
|
||||||
*/
|
*/
|
||||||
Locale& init(const char* cLocaleID, UBool canonicalize);
|
Locale& init(const char* localeID, UBool canonicalize);
|
||||||
|
/** @internal */
|
||||||
|
Locale& init(StringPiece localeID, UBool canonicalize);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Internal constructor to allow construction of a locale object with
|
* Internal constructor to allow construction of a locale object with
|
||||||
|
@ -450,7 +450,7 @@ public:
|
|||||||
* @return a Locale object
|
* @return a Locale object
|
||||||
* @stable ICU 2.8
|
* @stable ICU 2.8
|
||||||
*/
|
*/
|
||||||
const Locale
|
Locale
|
||||||
getLocale(ULocDataLocaleType type, UErrorCode &status) const;
|
getLocale(ULocDataLocaleType type, UErrorCode &status) const;
|
||||||
#ifndef U_HIDE_INTERNAL_API
|
#ifndef U_HIDE_INTERNAL_API
|
||||||
/**
|
/**
|
||||||
|
48
deps/icu-small/source/common/unicode/uchar.h
vendored
48
deps/icu-small/source/common/unicode/uchar.h
vendored
@ -675,14 +675,14 @@ typedef enum UProperty {
|
|||||||
* @stable ICU 63
|
* @stable ICU 63
|
||||||
*/
|
*/
|
||||||
UCHAR_VERTICAL_ORIENTATION=0x1018,
|
UCHAR_VERTICAL_ORIENTATION=0x1018,
|
||||||
#ifndef U_HIDE_DRAFT_API
|
|
||||||
/**
|
/**
|
||||||
* Enumerated property Identifier_Status.
|
* Enumerated property Identifier_Status.
|
||||||
* Used for UTS #39 General Security Profile for Identifiers
|
* Used for UTS #39 General Security Profile for Identifiers
|
||||||
* (https://www.unicode.org/reports/tr39/#General_Security_Profile).
|
* (https://www.unicode.org/reports/tr39/#General_Security_Profile).
|
||||||
* @draft ICU 75
|
* @stable ICU 75
|
||||||
*/
|
*/
|
||||||
UCHAR_IDENTIFIER_STATUS=0x1019,
|
UCHAR_IDENTIFIER_STATUS=0x1019,
|
||||||
|
#ifndef U_HIDE_DRAFT_API
|
||||||
/**
|
/**
|
||||||
* Enumerated property Indic_Conjunct_Break.
|
* Enumerated property Indic_Conjunct_Break.
|
||||||
* Used in the grapheme cluster break algorithm in UAX #29.
|
* Used in the grapheme cluster break algorithm in UAX #29.
|
||||||
@ -796,7 +796,6 @@ typedef enum UProperty {
|
|||||||
UCHAR_SCRIPT_EXTENSIONS=0x7000,
|
UCHAR_SCRIPT_EXTENSIONS=0x7000,
|
||||||
/** First constant for Unicode properties with unusual value types. @stable ICU 4.6 */
|
/** First constant for Unicode properties with unusual value types. @stable ICU 4.6 */
|
||||||
UCHAR_OTHER_PROPERTY_START=UCHAR_SCRIPT_EXTENSIONS,
|
UCHAR_OTHER_PROPERTY_START=UCHAR_SCRIPT_EXTENSIONS,
|
||||||
#ifndef U_HIDE_DRAFT_API
|
|
||||||
/**
|
/**
|
||||||
* Miscellaneous property Identifier_Type.
|
* Miscellaneous property Identifier_Type.
|
||||||
* Used for UTS #39 General Security Profile for Identifiers
|
* Used for UTS #39 General Security Profile for Identifiers
|
||||||
@ -808,10 +807,9 @@ typedef enum UProperty {
|
|||||||
*
|
*
|
||||||
* @see u_hasIDType
|
* @see u_hasIDType
|
||||||
* @see u_getIDTypes
|
* @see u_getIDTypes
|
||||||
* @draft ICU 75
|
* @stable ICU 75
|
||||||
*/
|
*/
|
||||||
UCHAR_IDENTIFIER_TYPE=0x7001,
|
UCHAR_IDENTIFIER_TYPE=0x7001,
|
||||||
#endif // U_HIDE_DRAFT_API
|
|
||||||
#ifndef U_HIDE_DEPRECATED_API
|
#ifndef U_HIDE_DEPRECATED_API
|
||||||
/**
|
/**
|
||||||
* One more than the last constant for Unicode properties with unusual value types.
|
* One more than the last constant for Unicode properties with unusual value types.
|
||||||
@ -2791,13 +2789,12 @@ typedef enum UVerticalOrientation {
|
|||||||
U_VO_UPRIGHT,
|
U_VO_UPRIGHT,
|
||||||
} UVerticalOrientation;
|
} UVerticalOrientation;
|
||||||
|
|
||||||
#ifndef U_HIDE_DRAFT_API
|
|
||||||
/**
|
/**
|
||||||
* Identifier Status constants.
|
* Identifier Status constants.
|
||||||
* See https://www.unicode.org/reports/tr39/#Identifier_Status_and_Type.
|
* See https://www.unicode.org/reports/tr39/#Identifier_Status_and_Type.
|
||||||
*
|
*
|
||||||
* @see UCHAR_IDENTIFIER_STATUS
|
* @see UCHAR_IDENTIFIER_STATUS
|
||||||
* @draft ICU 75
|
* @stable ICU 75
|
||||||
*/
|
*/
|
||||||
typedef enum UIdentifierStatus {
|
typedef enum UIdentifierStatus {
|
||||||
/*
|
/*
|
||||||
@ -2806,9 +2803,9 @@ typedef enum UIdentifierStatus {
|
|||||||
* U_ID_STATUS_<Unicode Identifier_Status value name>
|
* U_ID_STATUS_<Unicode Identifier_Status value name>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @draft ICU 75 */
|
/** @stable ICU 75 */
|
||||||
U_ID_STATUS_RESTRICTED,
|
U_ID_STATUS_RESTRICTED,
|
||||||
/** @draft ICU 75 */
|
/** @stable ICU 75 */
|
||||||
U_ID_STATUS_ALLOWED,
|
U_ID_STATUS_ALLOWED,
|
||||||
} UIdentifierStatus;
|
} UIdentifierStatus;
|
||||||
|
|
||||||
@ -2817,7 +2814,7 @@ typedef enum UIdentifierStatus {
|
|||||||
* See https://www.unicode.org/reports/tr39/#Identifier_Status_and_Type.
|
* See https://www.unicode.org/reports/tr39/#Identifier_Status_and_Type.
|
||||||
*
|
*
|
||||||
* @see UCHAR_IDENTIFIER_TYPE
|
* @see UCHAR_IDENTIFIER_TYPE
|
||||||
* @draft ICU 75
|
* @stable ICU 75
|
||||||
*/
|
*/
|
||||||
typedef enum UIdentifierType {
|
typedef enum UIdentifierType {
|
||||||
/*
|
/*
|
||||||
@ -2826,32 +2823,31 @@ typedef enum UIdentifierType {
|
|||||||
* U_ID_TYPE_<Unicode Identifier_Type value name>
|
* U_ID_TYPE_<Unicode Identifier_Type value name>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @draft ICU 75 */
|
/** @stable ICU 75 */
|
||||||
U_ID_TYPE_NOT_CHARACTER,
|
U_ID_TYPE_NOT_CHARACTER,
|
||||||
/** @draft ICU 75 */
|
/** @stable ICU 75 */
|
||||||
U_ID_TYPE_DEPRECATED,
|
U_ID_TYPE_DEPRECATED,
|
||||||
/** @draft ICU 75 */
|
/** @stable ICU 75 */
|
||||||
U_ID_TYPE_DEFAULT_IGNORABLE,
|
U_ID_TYPE_DEFAULT_IGNORABLE,
|
||||||
/** @draft ICU 75 */
|
/** @stable ICU 75 */
|
||||||
U_ID_TYPE_NOT_NFKC,
|
U_ID_TYPE_NOT_NFKC,
|
||||||
/** @draft ICU 75 */
|
/** @stable ICU 75 */
|
||||||
U_ID_TYPE_NOT_XID,
|
U_ID_TYPE_NOT_XID,
|
||||||
/** @draft ICU 75 */
|
/** @stable ICU 75 */
|
||||||
U_ID_TYPE_EXCLUSION,
|
U_ID_TYPE_EXCLUSION,
|
||||||
/** @draft ICU 75 */
|
/** @stable ICU 75 */
|
||||||
U_ID_TYPE_OBSOLETE,
|
U_ID_TYPE_OBSOLETE,
|
||||||
/** @draft ICU 75 */
|
/** @stable ICU 75 */
|
||||||
U_ID_TYPE_TECHNICAL,
|
U_ID_TYPE_TECHNICAL,
|
||||||
/** @draft ICU 75 */
|
/** @stable ICU 75 */
|
||||||
U_ID_TYPE_UNCOMMON_USE,
|
U_ID_TYPE_UNCOMMON_USE,
|
||||||
/** @draft ICU 75 */
|
/** @stable ICU 75 */
|
||||||
U_ID_TYPE_LIMITED_USE,
|
U_ID_TYPE_LIMITED_USE,
|
||||||
/** @draft ICU 75 */
|
/** @stable ICU 75 */
|
||||||
U_ID_TYPE_INCLUSION,
|
U_ID_TYPE_INCLUSION,
|
||||||
/** @draft ICU 75 */
|
/** @stable ICU 75 */
|
||||||
U_ID_TYPE_RECOMMENDED,
|
U_ID_TYPE_RECOMMENDED,
|
||||||
} UIdentifierType;
|
} UIdentifierType;
|
||||||
#endif // U_HIDE_DRAFT_API
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check a binary Unicode property for a code point.
|
* Check a binary Unicode property for a code point.
|
||||||
@ -4057,7 +4053,6 @@ u_isIDStart(UChar32 c);
|
|||||||
U_CAPI UBool U_EXPORT2
|
U_CAPI UBool U_EXPORT2
|
||||||
u_isIDPart(UChar32 c);
|
u_isIDPart(UChar32 c);
|
||||||
|
|
||||||
#ifndef U_HIDE_DRAFT_API
|
|
||||||
/**
|
/**
|
||||||
* Does the set of Identifier_Type values code point c contain the given type?
|
* Does the set of Identifier_Type values code point c contain the given type?
|
||||||
*
|
*
|
||||||
@ -4069,7 +4064,7 @@ u_isIDPart(UChar32 c);
|
|||||||
* @param c code point
|
* @param c code point
|
||||||
* @param type Identifier_Type to check
|
* @param type Identifier_Type to check
|
||||||
* @return true if type is in Identifier_Type(c)
|
* @return true if type is in Identifier_Type(c)
|
||||||
* @draft ICU 75
|
* @stable ICU 75
|
||||||
*/
|
*/
|
||||||
U_CAPI bool U_EXPORT2
|
U_CAPI bool U_EXPORT2
|
||||||
u_hasIDType(UChar32 c, UIdentifierType type);
|
u_hasIDType(UChar32 c, UIdentifierType type);
|
||||||
@ -4104,11 +4099,10 @@ u_hasIDType(UChar32 c, UIdentifierType type);
|
|||||||
* function chaining. (See User Guide for details.)
|
* function chaining. (See User Guide for details.)
|
||||||
* @return number of values in c's Identifier_Type,
|
* @return number of values in c's Identifier_Type,
|
||||||
* written to types unless U_BUFFER_OVERFLOW_ERROR indicates insufficient capacity
|
* written to types unless U_BUFFER_OVERFLOW_ERROR indicates insufficient capacity
|
||||||
* @draft ICU 75
|
* @stable ICU 75
|
||||||
*/
|
*/
|
||||||
U_CAPI int32_t U_EXPORT2
|
U_CAPI int32_t U_EXPORT2
|
||||||
u_getIDTypes(UChar32 c, UIdentifierType *types, int32_t capacity, UErrorCode *pErrorCode);
|
u_getIDTypes(UChar32 c, UIdentifierType *types, int32_t capacity, UErrorCode *pErrorCode);
|
||||||
#endif // U_HIDE_DRAFT_API
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if the specified character should be regarded
|
* Determines if the specified character should be regarded
|
||||||
|
11
deps/icu-small/source/common/unicode/uniset.h
vendored
11
deps/icu-small/source/common/unicode/uniset.h
vendored
@ -1173,10 +1173,12 @@ public:
|
|||||||
inline U_HEADER_NESTED_NAMESPACE::USetStrings strings() const {
|
inline U_HEADER_NESTED_NAMESPACE::USetStrings strings() const {
|
||||||
return U_HEADER_NESTED_NAMESPACE::USetStrings(toUSet());
|
return U_HEADER_NESTED_NAMESPACE::USetStrings(toUSet());
|
||||||
}
|
}
|
||||||
|
#endif // U_HIDE_DRAFT_API
|
||||||
|
|
||||||
|
#ifndef U_HIDE_DRAFT_API
|
||||||
/**
|
/**
|
||||||
* Returns a C++ iterator for iterating over all of the elements of this set.
|
* Returns a C++ iterator for iterating over all of the elements of this set.
|
||||||
* Convenient all-in one iteration, but creates a UnicodeString for each
|
* Convenient all-in one iteration, but creates a std::u16string for each
|
||||||
* code point or string.
|
* code point or string.
|
||||||
* (Similar to how Java UnicodeSet *is an* Iterable<String>.)
|
* (Similar to how Java UnicodeSet *is an* Iterable<String>.)
|
||||||
*
|
*
|
||||||
@ -1185,13 +1187,14 @@ public:
|
|||||||
* \code
|
* \code
|
||||||
* UnicodeSet set(u"[abcçカ🚴{}{abc}{de}]", errorCode);
|
* UnicodeSet set(u"[abcçカ🚴{}{abc}{de}]", errorCode);
|
||||||
* for (auto el : set) {
|
* for (auto el : set) {
|
||||||
|
* UnicodeString us(el);
|
||||||
* std::string u8;
|
* std::string u8;
|
||||||
* printf("set.string length %ld \"%s\"\n", (long)el.length(), el.toUTF8String(u8).c_str());
|
* printf("set.element length %ld \"%s\"\n", (long)us.length(), us.toUTF8String(u8).c_str());
|
||||||
* }
|
* }
|
||||||
* \endcode
|
* \endcode
|
||||||
*
|
*
|
||||||
* @return an all-elements iterator.
|
* @return an all-elements iterator.
|
||||||
* @draft ICU 76
|
* @draft ICU 77
|
||||||
* @see end
|
* @see end
|
||||||
* @see codePoints
|
* @see codePoints
|
||||||
* @see ranges
|
* @see ranges
|
||||||
@ -1203,7 +1206,7 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @return an exclusive-end sentinel for iterating over all of the elements of this set.
|
* @return an exclusive-end sentinel for iterating over all of the elements of this set.
|
||||||
* @draft ICU 76
|
* @draft ICU 77
|
||||||
* @see begin
|
* @see begin
|
||||||
* @see codePoints
|
* @see codePoints
|
||||||
* @see ranges
|
* @see ranges
|
||||||
|
92
deps/icu-small/source/common/unicode/uset.h
vendored
92
deps/icu-small/source/common/unicode/uset.h
vendored
@ -32,12 +32,13 @@
|
|||||||
#include "unicode/utypes.h"
|
#include "unicode/utypes.h"
|
||||||
#include "unicode/uchar.h"
|
#include "unicode/uchar.h"
|
||||||
|
|
||||||
#if U_SHOW_CPLUSPLUS_API
|
#if U_SHOW_CPLUSPLUS_API || U_SHOW_CPLUSPLUS_HEADER_API
|
||||||
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include "unicode/char16ptr.h"
|
#include "unicode/char16ptr.h"
|
||||||
#include "unicode/localpointer.h"
|
#include "unicode/localpointer.h"
|
||||||
#include "unicode/unistr.h"
|
#include "unicode/utf16.h"
|
||||||
#endif // U_SHOW_CPLUSPLUS_API
|
#endif
|
||||||
|
|
||||||
#ifndef USET_DEFINED
|
#ifndef USET_DEFINED
|
||||||
|
|
||||||
@ -1392,8 +1393,8 @@ public:
|
|||||||
private:
|
private:
|
||||||
friend class USetCodePoints;
|
friend class USetCodePoints;
|
||||||
|
|
||||||
USetCodePointIterator(const USet *uset, int32_t rangeIndex, int32_t rangeCount)
|
USetCodePointIterator(const USet *pUset, int32_t nRangeIndex, int32_t nRangeCount)
|
||||||
: uset(uset), rangeIndex(rangeIndex), rangeCount(rangeCount),
|
: uset(pUset), rangeIndex(nRangeIndex), rangeCount(nRangeCount),
|
||||||
c(U_SENTINEL), end(U_SENTINEL) {
|
c(U_SENTINEL), end(U_SENTINEL) {
|
||||||
// Fetch the first range.
|
// Fetch the first range.
|
||||||
operator++();
|
operator++();
|
||||||
@ -1429,7 +1430,7 @@ public:
|
|||||||
* Constructs a C++ "range" object over the code points of the USet.
|
* Constructs a C++ "range" object over the code points of the USet.
|
||||||
* @draft ICU 76
|
* @draft ICU 76
|
||||||
*/
|
*/
|
||||||
USetCodePoints(const USet *uset) : uset(uset), rangeCount(uset_getRangeCount(uset)) {}
|
USetCodePoints(const USet *pUset) : uset(pUset), rangeCount(uset_getRangeCount(pUset)) {}
|
||||||
|
|
||||||
/** @draft ICU 76 */
|
/** @draft ICU 76 */
|
||||||
USetCodePoints(const USetCodePoints &other) = default;
|
USetCodePoints(const USetCodePoints &other) = default;
|
||||||
@ -1460,7 +1461,7 @@ struct CodePointRange {
|
|||||||
/** @draft ICU 76 */
|
/** @draft ICU 76 */
|
||||||
struct iterator {
|
struct iterator {
|
||||||
/** @draft ICU 76 */
|
/** @draft ICU 76 */
|
||||||
iterator(UChar32 c) : c(c) {}
|
iterator(UChar32 aC) : c(aC) {}
|
||||||
|
|
||||||
/** @draft ICU 76 */
|
/** @draft ICU 76 */
|
||||||
bool operator==(const iterator &other) const { return c == other.c; }
|
bool operator==(const iterator &other) const { return c == other.c; }
|
||||||
@ -1573,8 +1574,8 @@ public:
|
|||||||
private:
|
private:
|
||||||
friend class USetRanges;
|
friend class USetRanges;
|
||||||
|
|
||||||
USetRangeIterator(const USet *uset, int32_t rangeIndex, int32_t rangeCount)
|
USetRangeIterator(const USet *pUset, int32_t nRangeIndex, int32_t nRangeCount)
|
||||||
: uset(uset), rangeIndex(rangeIndex), rangeCount(rangeCount) {}
|
: uset(pUset), rangeIndex(nRangeIndex), rangeCount(nRangeCount) {}
|
||||||
|
|
||||||
const USet *uset;
|
const USet *uset;
|
||||||
int32_t rangeIndex;
|
int32_t rangeIndex;
|
||||||
@ -1610,7 +1611,7 @@ public:
|
|||||||
* Constructs a C++ "range" object over the code point ranges of the USet.
|
* Constructs a C++ "range" object over the code point ranges of the USet.
|
||||||
* @draft ICU 76
|
* @draft ICU 76
|
||||||
*/
|
*/
|
||||||
USetRanges(const USet *uset) : uset(uset), rangeCount(uset_getRangeCount(uset)) {}
|
USetRanges(const USet *pUset) : uset(pUset), rangeCount(uset_getRangeCount(pUset)) {}
|
||||||
|
|
||||||
/** @draft ICU 76 */
|
/** @draft ICU 76 */
|
||||||
USetRanges(const USetRanges &other) = default;
|
USetRanges(const USetRanges &other) = default;
|
||||||
@ -1657,7 +1658,7 @@ public:
|
|||||||
int32_t length;
|
int32_t length;
|
||||||
const UChar *uchars = uset_getString(uset, index, &length);
|
const UChar *uchars = uset_getString(uset, index, &length);
|
||||||
// assert uchars != nullptr;
|
// assert uchars != nullptr;
|
||||||
return {ConstChar16Ptr(uchars), static_cast<uint32_t>(length)};
|
return {uprv_char16PtrFromUChar(uchars), static_cast<size_t>(length)};
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -1684,8 +1685,8 @@ public:
|
|||||||
private:
|
private:
|
||||||
friend class USetStrings;
|
friend class USetStrings;
|
||||||
|
|
||||||
USetStringIterator(const USet *uset, int32_t index, int32_t count)
|
USetStringIterator(const USet *pUset, int32_t nIndex, int32_t nCount)
|
||||||
: uset(uset), index(index), count(count) {}
|
: uset(pUset), index(nIndex), count(nCount) {}
|
||||||
|
|
||||||
const USet *uset;
|
const USet *uset;
|
||||||
int32_t index;
|
int32_t index;
|
||||||
@ -1699,9 +1700,11 @@ private:
|
|||||||
* using U_HEADER_NESTED_NAMESPACE::USetStrings;
|
* using U_HEADER_NESTED_NAMESPACE::USetStrings;
|
||||||
* LocalUSetPointer uset(uset_openPattern(u"[abcçカ🚴{}{abc}{de}]", -1, &errorCode));
|
* LocalUSetPointer uset(uset_openPattern(u"[abcçカ🚴{}{abc}{de}]", -1, &errorCode));
|
||||||
* for (auto s : USetStrings(uset.getAlias())) {
|
* for (auto s : USetStrings(uset.getAlias())) {
|
||||||
* UnicodeString us(s);
|
* int32_t len32 = s.length();
|
||||||
* std::string u8;
|
* char utf8[200];
|
||||||
* printf("uset.string length %ld \"%s\"\n", (long)s.length(), us.toUTF8String(u8).c_str());
|
* u_strToUTF8WithSub(utf8, int32_t{sizeof(utf8) - 1}, nullptr,
|
||||||
|
* s.data(), len32, 0xFFFD, nullptr, errorCode);
|
||||||
|
* printf("uset.string length %ld \"%s\"\n", long{len32}, utf8);
|
||||||
* }
|
* }
|
||||||
* \endcode
|
* \endcode
|
||||||
*
|
*
|
||||||
@ -1718,7 +1721,7 @@ public:
|
|||||||
* Constructs a C++ "range" object over the strings of the USet.
|
* Constructs a C++ "range" object over the strings of the USet.
|
||||||
* @draft ICU 76
|
* @draft ICU 76
|
||||||
*/
|
*/
|
||||||
USetStrings(const USet *uset) : uset(uset), count(uset_getStringCount(uset)) {}
|
USetStrings(const USet *pUset) : uset(pUset), count(uset_getStringCount(pUset)) {}
|
||||||
|
|
||||||
/** @draft ICU 76 */
|
/** @draft ICU 76 */
|
||||||
USetStrings(const USetStrings &other) = default;
|
USetStrings(const USetStrings &other) = default;
|
||||||
@ -1737,17 +1740,19 @@ private:
|
|||||||
const USet *uset;
|
const USet *uset;
|
||||||
int32_t count;
|
int32_t count;
|
||||||
};
|
};
|
||||||
|
#endif // U_HIDE_DRAFT_API
|
||||||
|
|
||||||
|
#ifndef U_HIDE_DRAFT_API
|
||||||
/**
|
/**
|
||||||
* Iterator returned by USetElements.
|
* Iterator returned by USetElements.
|
||||||
* @draft ICU 76
|
* @draft ICU 77
|
||||||
*/
|
*/
|
||||||
class USetElementIterator {
|
class USetElementIterator {
|
||||||
public:
|
public:
|
||||||
/** @draft ICU 76 */
|
/** @draft ICU 77 */
|
||||||
USetElementIterator(const USetElementIterator &other) = default;
|
USetElementIterator(const USetElementIterator &other) = default;
|
||||||
|
|
||||||
/** @draft ICU 76 */
|
/** @draft ICU 77 */
|
||||||
bool operator==(const USetElementIterator &other) const {
|
bool operator==(const USetElementIterator &other) const {
|
||||||
// No need to compare rangeCount & end given private constructor
|
// No need to compare rangeCount & end given private constructor
|
||||||
// and assuming we don't compare iterators across the set being modified.
|
// and assuming we don't compare iterators across the set being modified.
|
||||||
@ -1756,26 +1761,28 @@ public:
|
|||||||
return uset == other.uset && c == other.c && index == other.index;
|
return uset == other.uset && c == other.c && index == other.index;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @draft ICU 76 */
|
/** @draft ICU 77 */
|
||||||
bool operator!=(const USetElementIterator &other) const { return !operator==(other); }
|
bool operator!=(const USetElementIterator &other) const { return !operator==(other); }
|
||||||
|
|
||||||
/** @draft ICU 76 */
|
/** @draft ICU 77 */
|
||||||
UnicodeString operator*() const {
|
std::u16string operator*() const {
|
||||||
if (c >= 0) {
|
if (c >= 0) {
|
||||||
return UnicodeString(c);
|
return c <= 0xffff ?
|
||||||
|
std::u16string({static_cast<char16_t>(c)}) :
|
||||||
|
std::u16string({U16_LEAD(c), U16_TRAIL(c)});
|
||||||
} else if (index < totalCount) {
|
} else if (index < totalCount) {
|
||||||
int32_t length;
|
int32_t length;
|
||||||
const UChar *uchars = uset_getString(uset, index - rangeCount, &length);
|
const UChar *uchars = uset_getString(uset, index - rangeCount, &length);
|
||||||
// assert uchars != nullptr;
|
// assert uchars != nullptr;
|
||||||
return UnicodeString(uchars, length);
|
return {uprv_char16PtrFromUChar(uchars), static_cast<size_t>(length)};
|
||||||
} else {
|
} else {
|
||||||
return UnicodeString();
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pre-increment.
|
* Pre-increment.
|
||||||
* @draft ICU 76
|
* @draft ICU 77
|
||||||
*/
|
*/
|
||||||
USetElementIterator &operator++() {
|
USetElementIterator &operator++() {
|
||||||
if (c < end) {
|
if (c < end) {
|
||||||
@ -1800,7 +1807,7 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Post-increment.
|
* Post-increment.
|
||||||
* @draft ICU 76
|
* @draft ICU 77
|
||||||
*/
|
*/
|
||||||
USetElementIterator operator++(int) {
|
USetElementIterator operator++(int) {
|
||||||
USetElementIterator result(*this);
|
USetElementIterator result(*this);
|
||||||
@ -1811,8 +1818,8 @@ public:
|
|||||||
private:
|
private:
|
||||||
friend class USetElements;
|
friend class USetElements;
|
||||||
|
|
||||||
USetElementIterator(const USet *uset, int32_t index, int32_t rangeCount, int32_t totalCount)
|
USetElementIterator(const USet *pUset, int32_t nIndex, int32_t nRangeCount, int32_t nTotalCount)
|
||||||
: uset(uset), index(index), rangeCount(rangeCount), totalCount(totalCount),
|
: uset(pUset), index(nIndex), rangeCount(nRangeCount), totalCount(nTotalCount),
|
||||||
c(U_SENTINEL), end(U_SENTINEL) {
|
c(U_SENTINEL), end(U_SENTINEL) {
|
||||||
if (index < rangeCount) {
|
if (index < rangeCount) {
|
||||||
// Fetch the first range.
|
// Fetch the first range.
|
||||||
@ -1840,7 +1847,7 @@ private:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A C++ "range" for iterating over all of the elements of a USet.
|
* A C++ "range" for iterating over all of the elements of a USet.
|
||||||
* Convenient all-in one iteration, but creates a UnicodeString for each
|
* Convenient all-in one iteration, but creates a std::u16string for each
|
||||||
* code point or string.
|
* code point or string.
|
||||||
*
|
*
|
||||||
* Code points are returned first, then empty and multi-character strings.
|
* Code points are returned first, then empty and multi-character strings.
|
||||||
@ -1849,15 +1856,18 @@ private:
|
|||||||
* using U_HEADER_NESTED_NAMESPACE::USetElements;
|
* using U_HEADER_NESTED_NAMESPACE::USetElements;
|
||||||
* LocalUSetPointer uset(uset_openPattern(u"[abcçカ🚴{}{abc}{de}]", -1, &errorCode));
|
* LocalUSetPointer uset(uset_openPattern(u"[abcçカ🚴{}{abc}{de}]", -1, &errorCode));
|
||||||
* for (auto el : USetElements(uset.getAlias())) {
|
* for (auto el : USetElements(uset.getAlias())) {
|
||||||
* std::string u8;
|
* int32_t len32 = el.length();
|
||||||
* printf("uset.string length %ld \"%s\"\n", (long)el.length(), el.toUTF8String(u8).c_str());
|
* char utf8[200];
|
||||||
|
* u_strToUTF8WithSub(utf8, int32_t{sizeof(utf8) - 1}, nullptr,
|
||||||
|
* el.data(), len32, 0xFFFD, nullptr, errorCode);
|
||||||
|
* printf("uset.element length %ld \"%s\"\n", long{len32}, utf8);
|
||||||
* }
|
* }
|
||||||
* \endcode
|
* \endcode
|
||||||
*
|
*
|
||||||
* C++ UnicodeSet has member functions for iteration, including begin() and end().
|
* C++ UnicodeSet has member functions for iteration, including begin() and end().
|
||||||
*
|
*
|
||||||
* @return an all-elements iterator.
|
* @return an all-elements iterator.
|
||||||
* @draft ICU 76
|
* @draft ICU 77
|
||||||
* @see USetCodePoints
|
* @see USetCodePoints
|
||||||
* @see USetRanges
|
* @see USetRanges
|
||||||
* @see USetStrings
|
* @see USetStrings
|
||||||
@ -1866,21 +1876,21 @@ class USetElements {
|
|||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Constructs a C++ "range" object over all of the elements of the USet.
|
* Constructs a C++ "range" object over all of the elements of the USet.
|
||||||
* @draft ICU 76
|
* @draft ICU 77
|
||||||
*/
|
*/
|
||||||
USetElements(const USet *uset)
|
USetElements(const USet *pUset)
|
||||||
: uset(uset), rangeCount(uset_getRangeCount(uset)),
|
: uset(pUset), rangeCount(uset_getRangeCount(pUset)),
|
||||||
stringCount(uset_getStringCount(uset)) {}
|
stringCount(uset_getStringCount(pUset)) {}
|
||||||
|
|
||||||
/** @draft ICU 76 */
|
/** @draft ICU 77 */
|
||||||
USetElements(const USetElements &other) = default;
|
USetElements(const USetElements &other) = default;
|
||||||
|
|
||||||
/** @draft ICU 76 */
|
/** @draft ICU 77 */
|
||||||
USetElementIterator begin() const {
|
USetElementIterator begin() const {
|
||||||
return USetElementIterator(uset, 0, rangeCount, rangeCount + stringCount);
|
return USetElementIterator(uset, 0, rangeCount, rangeCount + stringCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @draft ICU 76 */
|
/** @draft ICU 77 */
|
||||||
USetElementIterator end() const {
|
USetElementIterator end() const {
|
||||||
return USetElementIterator(uset, rangeCount + stringCount, rangeCount, rangeCount + stringCount);
|
return USetElementIterator(uset, rangeCount + stringCount, rangeCount, rangeCount + stringCount);
|
||||||
}
|
}
|
||||||
|
4
deps/icu-small/source/common/unicode/utf8.h
vendored
4
deps/icu-small/source/common/unicode/utf8.h
vendored
@ -124,7 +124,7 @@
|
|||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
U_CAPI UChar32 U_EXPORT2
|
U_CAPI UChar32 U_EXPORT2
|
||||||
utf8_nextCharSafeBody(const uint8_t *s, int32_t *pi, int32_t length, UChar32 c, UBool strict);
|
utf8_nextCharSafeBody(const uint8_t *s, int32_t *pi, int32_t length, UChar32 c, int8_t strict);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function for handling "append code point" with error-checking.
|
* Function for handling "append code point" with error-checking.
|
||||||
@ -148,7 +148,7 @@ utf8_appendCharSafeBody(uint8_t *s, int32_t i, int32_t length, UChar32 c, UBool
|
|||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
U_CAPI UChar32 U_EXPORT2
|
U_CAPI UChar32 U_EXPORT2
|
||||||
utf8_prevCharSafeBody(const uint8_t *s, int32_t start, int32_t *pi, UChar32 c, UBool strict);
|
utf8_prevCharSafeBody(const uint8_t *s, int32_t start, int32_t *pi, UChar32 c, int8_t strict);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function for handling "skip backward one code point" with error-checking.
|
* Function for handling "skip backward one code point" with error-checking.
|
||||||
|
@ -598,12 +598,13 @@ typedef enum UErrorCode {
|
|||||||
U_MF_DUPLICATE_DECLARATION_ERROR, /**< The same variable is declared in more than one .local or .input declaration. @internal ICU 75 technology preview @deprecated This API is for technology preview only. */
|
U_MF_DUPLICATE_DECLARATION_ERROR, /**< The same variable is declared in more than one .local or .input declaration. @internal ICU 75 technology preview @deprecated This API is for technology preview only. */
|
||||||
U_MF_OPERAND_MISMATCH_ERROR, /**< An operand provided to a function does not have the required form for that function @internal ICU 75 technology preview @deprecated This API is for technology preview only. */
|
U_MF_OPERAND_MISMATCH_ERROR, /**< An operand provided to a function does not have the required form for that function @internal ICU 75 technology preview @deprecated This API is for technology preview only. */
|
||||||
U_MF_DUPLICATE_VARIANT_ERROR, /**< A message includes a variant with the same key list as another variant. @internal ICU 76 technology preview @deprecated This API is for technology preview only. */
|
U_MF_DUPLICATE_VARIANT_ERROR, /**< A message includes a variant with the same key list as another variant. @internal ICU 76 technology preview @deprecated This API is for technology preview only. */
|
||||||
|
U_MF_BAD_OPTION, /**< An option value provided to a function does not have the required form for that option. @internal ICU 77 technology preview @deprecated This API is for technology preview only. */
|
||||||
#ifndef U_HIDE_DEPRECATED_API
|
#ifndef U_HIDE_DEPRECATED_API
|
||||||
/**
|
/**
|
||||||
* One more than the highest normal formatting API error code.
|
* One more than the highest normal formatting API error code.
|
||||||
* @deprecated ICU 58 The numeric value may change over time, see ICU ticket #12420.
|
* @deprecated ICU 58 The numeric value may change over time, see ICU ticket #12420.
|
||||||
*/
|
*/
|
||||||
U_FMT_PARSE_ERROR_LIMIT = 0x10120,
|
U_FMT_PARSE_ERROR_LIMIT = 0x10121,
|
||||||
#endif // U_HIDE_DEPRECATED_API
|
#endif // U_HIDE_DEPRECATED_API
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
10
deps/icu-small/source/common/unicode/uvernum.h
vendored
10
deps/icu-small/source/common/unicode/uvernum.h
vendored
@ -53,7 +53,7 @@
|
|||||||
* This value will change in the subsequent releases of ICU
|
* This value will change in the subsequent releases of ICU
|
||||||
* @stable ICU 2.4
|
* @stable ICU 2.4
|
||||||
*/
|
*/
|
||||||
#define U_ICU_VERSION_MAJOR_NUM 76
|
#define U_ICU_VERSION_MAJOR_NUM 77
|
||||||
|
|
||||||
/** The current ICU minor version as an integer.
|
/** The current ICU minor version as an integer.
|
||||||
* This value will change in the subsequent releases of ICU
|
* This value will change in the subsequent releases of ICU
|
||||||
@ -79,7 +79,7 @@
|
|||||||
* This value will change in the subsequent releases of ICU
|
* This value will change in the subsequent releases of ICU
|
||||||
* @stable ICU 2.6
|
* @stable ICU 2.6
|
||||||
*/
|
*/
|
||||||
#define U_ICU_VERSION_SUFFIX _76
|
#define U_ICU_VERSION_SUFFIX _77
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \def U_DEF2_ICU_ENTRY_POINT_RENAME
|
* \def U_DEF2_ICU_ENTRY_POINT_RENAME
|
||||||
@ -132,7 +132,7 @@
|
|||||||
* This value will change in the subsequent releases of ICU
|
* This value will change in the subsequent releases of ICU
|
||||||
* @stable ICU 2.4
|
* @stable ICU 2.4
|
||||||
*/
|
*/
|
||||||
#define U_ICU_VERSION "76.1"
|
#define U_ICU_VERSION "77.1"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current ICU library major version number as a string, for library name suffixes.
|
* The current ICU library major version number as a string, for library name suffixes.
|
||||||
@ -145,13 +145,13 @@
|
|||||||
*
|
*
|
||||||
* @stable ICU 2.6
|
* @stable ICU 2.6
|
||||||
*/
|
*/
|
||||||
#define U_ICU_VERSION_SHORT "76"
|
#define U_ICU_VERSION_SHORT "77"
|
||||||
|
|
||||||
#ifndef U_HIDE_INTERNAL_API
|
#ifndef U_HIDE_INTERNAL_API
|
||||||
/** Data version in ICU4C.
|
/** Data version in ICU4C.
|
||||||
* @internal ICU 4.4 Internal Use Only
|
* @internal ICU 4.4 Internal Use Only
|
||||||
**/
|
**/
|
||||||
#define U_ICU_DATA_VERSION "76.1"
|
#define U_ICU_DATA_VERSION "77.1"
|
||||||
#endif /* U_HIDE_INTERNAL_API */
|
#endif /* U_HIDE_INTERNAL_API */
|
||||||
|
|
||||||
/*===========================================================================
|
/*===========================================================================
|
||||||
|
19
deps/icu-small/source/common/unicode/uversion.h
vendored
19
deps/icu-small/source/common/unicode/uversion.h
vendored
@ -125,7 +125,7 @@ typedef uint8_t UVersionInfo[U_MAX_VERSION_LENGTH];
|
|||||||
U_NAMESPACE_USE
|
U_NAMESPACE_USE
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
#ifndef U_HIDE_DRAFT_API
|
#ifndef U_FORCE_HIDE_DRAFT_API
|
||||||
/**
|
/**
|
||||||
* \def U_HEADER_NESTED_NAMESPACE
|
* \def U_HEADER_NESTED_NAMESPACE
|
||||||
* Nested namespace used inside U_ICU_NAMESPACE for header-only APIs.
|
* Nested namespace used inside U_ICU_NAMESPACE for header-only APIs.
|
||||||
@ -150,22 +150,37 @@ typedef uint8_t UVersionInfo[U_MAX_VERSION_LENGTH];
|
|||||||
* @draft ICU 76
|
* @draft ICU 76
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def U_ICU_NAMESPACE_OR_INTERNAL
|
||||||
|
* Namespace used for header-only APIs that used to be regular C++ APIs.
|
||||||
|
* Different when used inside ICU to prevent public use of internal instantiations.
|
||||||
|
* Similar to U_HEADER_ONLY_NAMESPACE, but the public definition is the same as U_ICU_NAMESPACE.
|
||||||
|
* "U_ICU_NAMESPACE" or "U_ICU_NAMESPACE::internal".
|
||||||
|
*
|
||||||
|
* @draft ICU 77
|
||||||
|
*/
|
||||||
|
|
||||||
// The first test is the same as for defining U_EXPORT for Windows.
|
// The first test is the same as for defining U_EXPORT for Windows.
|
||||||
#if defined(_MSC_VER) || (UPRV_HAS_DECLSPEC_ATTRIBUTE(__dllexport__) && \
|
#if defined(_MSC_VER) || (UPRV_HAS_DECLSPEC_ATTRIBUTE(__dllexport__) && \
|
||||||
UPRV_HAS_DECLSPEC_ATTRIBUTE(__dllimport__))
|
UPRV_HAS_DECLSPEC_ATTRIBUTE(__dllimport__))
|
||||||
# define U_HEADER_NESTED_NAMESPACE header
|
# define U_HEADER_NESTED_NAMESPACE header
|
||||||
|
# define U_ICU_NAMESPACE_OR_INTERNAL U_ICU_NAMESPACE
|
||||||
#elif defined(U_COMBINED_IMPLEMENTATION) || defined(U_COMMON_IMPLEMENTATION) || \
|
#elif defined(U_COMBINED_IMPLEMENTATION) || defined(U_COMMON_IMPLEMENTATION) || \
|
||||||
defined(U_I18N_IMPLEMENTATION) || defined(U_IO_IMPLEMENTATION) || \
|
defined(U_I18N_IMPLEMENTATION) || defined(U_IO_IMPLEMENTATION) || \
|
||||||
defined(U_LAYOUTEX_IMPLEMENTATION) || defined(U_TOOLUTIL_IMPLEMENTATION)
|
defined(U_LAYOUTEX_IMPLEMENTATION) || defined(U_TOOLUTIL_IMPLEMENTATION)
|
||||||
# define U_HEADER_NESTED_NAMESPACE internal
|
# define U_HEADER_NESTED_NAMESPACE internal
|
||||||
|
# define U_ICU_NAMESPACE_OR_INTERNAL U_ICU_NAMESPACE::internal
|
||||||
|
namespace U_ICU_NAMESPACE_OR_INTERNAL {}
|
||||||
|
using namespace U_ICU_NAMESPACE_OR_INTERNAL;
|
||||||
#else
|
#else
|
||||||
# define U_HEADER_NESTED_NAMESPACE header
|
# define U_HEADER_NESTED_NAMESPACE header
|
||||||
|
# define U_ICU_NAMESPACE_OR_INTERNAL U_ICU_NAMESPACE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define U_HEADER_ONLY_NAMESPACE U_ICU_NAMESPACE::U_HEADER_NESTED_NAMESPACE
|
#define U_HEADER_ONLY_NAMESPACE U_ICU_NAMESPACE::U_HEADER_NESTED_NAMESPACE
|
||||||
|
|
||||||
namespace U_HEADER_ONLY_NAMESPACE {}
|
namespace U_HEADER_ONLY_NAMESPACE {}
|
||||||
#endif // U_HIDE_DRAFT_API
|
#endif // U_FORCE_HIDE_DRAFT_API
|
||||||
|
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
7
deps/icu-small/source/common/unistr.cpp
vendored
7
deps/icu-small/source/common/unistr.cpp
vendored
@ -1945,6 +1945,13 @@ UnicodeString::cloneArrayIfNeeded(int32_t newCapacity,
|
|||||||
growCapacity = newCapacity;
|
growCapacity = newCapacity;
|
||||||
} else if(newCapacity <= US_STACKBUF_SIZE && growCapacity > US_STACKBUF_SIZE) {
|
} else if(newCapacity <= US_STACKBUF_SIZE && growCapacity > US_STACKBUF_SIZE) {
|
||||||
growCapacity = US_STACKBUF_SIZE;
|
growCapacity = US_STACKBUF_SIZE;
|
||||||
|
} else if(newCapacity > growCapacity) {
|
||||||
|
setToBogus();
|
||||||
|
return false; // bad inputs
|
||||||
|
}
|
||||||
|
if(growCapacity > kMaxCapacity) {
|
||||||
|
setToBogus();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// save old values
|
// save old values
|
||||||
|
8
deps/icu-small/source/common/uresbund.cpp
vendored
8
deps/icu-small/source/common/uresbund.cpp
vendored
@ -2716,6 +2716,9 @@ ures_openWithType(UResourceBundle *r, const char* path, const char* localeID,
|
|||||||
|
|
||||||
UResourceDataEntry *entry;
|
UResourceDataEntry *entry;
|
||||||
if(openType != URES_OPEN_DIRECT) {
|
if(openType != URES_OPEN_DIRECT) {
|
||||||
|
if (localeID == nullptr) {
|
||||||
|
localeID = uloc_getDefault();
|
||||||
|
}
|
||||||
/* first "canonicalize" the locale ID */
|
/* first "canonicalize" the locale ID */
|
||||||
CharString canonLocaleID = ulocimp_getBaseName(localeID, *status);
|
CharString canonLocaleID = ulocimp_getBaseName(localeID, *status);
|
||||||
if(U_FAILURE(*status)) {
|
if(U_FAILURE(*status)) {
|
||||||
@ -3080,6 +3083,9 @@ ures_getFunctionalEquivalent(char *result, int32_t resultCapacity,
|
|||||||
kwVal.clear();
|
kwVal.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (locid == nullptr) {
|
||||||
|
locid = uloc_getDefault();
|
||||||
|
}
|
||||||
CharString base = ulocimp_getBaseName(locid, subStatus);
|
CharString base = ulocimp_getBaseName(locid, subStatus);
|
||||||
#if defined(URES_TREE_DEBUG)
|
#if defined(URES_TREE_DEBUG)
|
||||||
fprintf(stderr, "getFunctionalEquivalent: \"%s\" [%s=%s] in %s - %s\n",
|
fprintf(stderr, "getFunctionalEquivalent: \"%s\" [%s=%s] in %s - %s\n",
|
||||||
@ -3244,7 +3250,7 @@ ures_getFunctionalEquivalent(char *result, int32_t resultCapacity,
|
|||||||
const char *validLoc = ures_getLocaleByType(res, ULOC_VALID_LOCALE, &subStatus);
|
const char *validLoc = ures_getLocaleByType(res, ULOC_VALID_LOCALE, &subStatus);
|
||||||
if (U_SUCCESS(subStatus) && validLoc != nullptr && validLoc[0] != 0 && uprv_strcmp(validLoc, "root") != 0) {
|
if (U_SUCCESS(subStatus) && validLoc != nullptr && validLoc[0] != 0 && uprv_strcmp(validLoc, "root") != 0) {
|
||||||
CharString validLang = ulocimp_getLanguage(validLoc, subStatus);
|
CharString validLang = ulocimp_getLanguage(validLoc, subStatus);
|
||||||
CharString parentLang = ulocimp_getLanguage(parent.data(), subStatus);
|
CharString parentLang = ulocimp_getLanguage(parent.toStringPiece(), subStatus);
|
||||||
if (U_SUCCESS(subStatus) && validLang != parentLang) {
|
if (U_SUCCESS(subStatus) && validLang != parentLang) {
|
||||||
// validLoc is not root and has a different language than parent, use it instead
|
// validLoc is not root and has a different language than parent, use it instead
|
||||||
found.clear().append(validLoc, subStatus);
|
found.clear().append(validLoc, subStatus);
|
||||||
|
3
deps/icu-small/source/common/uscript.cpp
vendored
3
deps/icu-small/source/common/uscript.cpp
vendored
@ -59,6 +59,9 @@ getCodesFromLocale(const char *locale,
|
|||||||
if (U_FAILURE(*err)) { return 0; }
|
if (U_FAILURE(*err)) { return 0; }
|
||||||
icu::CharString lang;
|
icu::CharString lang;
|
||||||
icu::CharString script;
|
icu::CharString script;
|
||||||
|
if (locale == nullptr) {
|
||||||
|
locale = uloc_getDefault();
|
||||||
|
}
|
||||||
ulocimp_getSubtags(locale, &lang, &script, nullptr, nullptr, nullptr, *err);
|
ulocimp_getSubtags(locale, &lang, &script, nullptr, nullptr, nullptr, *err);
|
||||||
if (U_FAILURE(*err)) { return 0; }
|
if (U_FAILURE(*err)) { return 0; }
|
||||||
// Multi-script languages, equivalent to the LocaleScript data
|
// Multi-script languages, equivalent to the LocaleScript data
|
||||||
|
5
deps/icu-small/source/common/ushape.cpp
vendored
5
deps/icu-small/source/common/ushape.cpp
vendored
@ -28,6 +28,7 @@
|
|||||||
#include "ubidi_props.h"
|
#include "ubidi_props.h"
|
||||||
#include "uassert.h"
|
#include "uassert.h"
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
/*
|
/*
|
||||||
* This implementation is designed for 16-bit Unicode strings.
|
* This implementation is designed for 16-bit Unicode strings.
|
||||||
* The main assumption is that the Arabic characters and their
|
* The main assumption is that the Arabic characters and their
|
||||||
@ -747,6 +748,10 @@ handleGeneratedSpaces(char16_t *dest, int32_t sourceLength,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (static_cast<size_t>(sourceLength) + 1 > std::numeric_limits<size_t>::max() / U_SIZEOF_UCHAR) {
|
||||||
|
*pErrorCode = U_INDEX_OUTOFBOUNDS_ERROR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
tempbuffer = static_cast<char16_t*>(uprv_malloc((sourceLength + 1) * U_SIZEOF_UCHAR));
|
tempbuffer = static_cast<char16_t*>(uprv_malloc((sourceLength + 1) * U_SIZEOF_UCHAR));
|
||||||
/* Test for nullptr */
|
/* Test for nullptr */
|
||||||
if(tempbuffer == nullptr) {
|
if(tempbuffer == nullptr) {
|
||||||
|
2
deps/icu-small/source/common/usprep.cpp
vendored
2
deps/icu-small/source/common/usprep.cpp
vendored
@ -126,7 +126,7 @@ compareEntries(const UHashTok p1, const UHashTok p2) {
|
|||||||
name2.pointer = b2->name;
|
name2.pointer = b2->name;
|
||||||
path1.pointer = b1->path;
|
path1.pointer = b1->path;
|
||||||
path2.pointer = b2->path;
|
path2.pointer = b2->path;
|
||||||
return uhash_compareChars(name1, name2) & uhash_compareChars(path1, path2);
|
return uhash_compareChars(name1, name2) && uhash_compareChars(path1, path2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
6
deps/icu-small/source/common/utf_impl.cpp
vendored
6
deps/icu-small/source/common/utf_impl.cpp
vendored
@ -124,11 +124,9 @@ errorValue(int32_t count, int8_t strict) {
|
|||||||
* >0 Obsolete "strict" behavior of UTF8_NEXT_CHAR_SAFE(..., true):
|
* >0 Obsolete "strict" behavior of UTF8_NEXT_CHAR_SAFE(..., true):
|
||||||
* Same as the obsolete "safe" behavior, but non-characters are also treated
|
* Same as the obsolete "safe" behavior, but non-characters are also treated
|
||||||
* like illegal sequences.
|
* like illegal sequences.
|
||||||
*
|
|
||||||
* Note that a UBool is the same as an int8_t.
|
|
||||||
*/
|
*/
|
||||||
U_CAPI UChar32 U_EXPORT2
|
U_CAPI UChar32 U_EXPORT2
|
||||||
utf8_nextCharSafeBody(const uint8_t *s, int32_t *pi, int32_t length, UChar32 c, UBool strict) {
|
utf8_nextCharSafeBody(const uint8_t *s, int32_t *pi, int32_t length, UChar32 c, int8_t strict) {
|
||||||
// *pi is one after byte c.
|
// *pi is one after byte c.
|
||||||
int32_t i=*pi;
|
int32_t i=*pi;
|
||||||
// length can be negative for NUL-terminated strings: Read and validate one byte at a time.
|
// length can be negative for NUL-terminated strings: Read and validate one byte at a time.
|
||||||
@ -233,7 +231,7 @@ utf8_appendCharSafeBody(uint8_t *s, int32_t i, int32_t length, UChar32 c, UBool
|
|||||||
}
|
}
|
||||||
|
|
||||||
U_CAPI UChar32 U_EXPORT2
|
U_CAPI UChar32 U_EXPORT2
|
||||||
utf8_prevCharSafeBody(const uint8_t *s, int32_t start, int32_t *pi, UChar32 c, UBool strict) {
|
utf8_prevCharSafeBody(const uint8_t *s, int32_t start, int32_t *pi, UChar32 c, int8_t strict) {
|
||||||
// *pi is the index of byte c.
|
// *pi is the index of byte c.
|
||||||
int32_t i=*pi;
|
int32_t i=*pi;
|
||||||
if(U8_IS_TRAIL(c) && i>start) {
|
if(U8_IS_TRAIL(c) && i>start) {
|
||||||
|
3
deps/icu-small/source/common/utypes.cpp
vendored
3
deps/icu-small/source/common/utypes.cpp
vendored
@ -140,7 +140,8 @@ _uFmtErrorName[U_FMT_PARSE_ERROR_LIMIT - U_FMT_PARSE_ERROR_START] = {
|
|||||||
"U_MF_MISSING_SELECTOR_ANNOTATION_ERROR",
|
"U_MF_MISSING_SELECTOR_ANNOTATION_ERROR",
|
||||||
"U_MF_DUPLICATE_DECLARATION_ERROR",
|
"U_MF_DUPLICATE_DECLARATION_ERROR",
|
||||||
"U_MF_OPERAND_MISMATCH_ERROR",
|
"U_MF_OPERAND_MISMATCH_ERROR",
|
||||||
"U_MF_DUPLICATE_VARIANT_ERROR"
|
"U_MF_DUPLICATE_VARIANT_ERROR",
|
||||||
|
"U_MF_BAD_OPTION"
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char * const
|
static const char * const
|
||||||
|
Binary file not shown.
12
deps/icu-small/source/i18n/basictz.cpp
vendored
12
deps/icu-small/source/i18n/basictz.cpp
vendored
@ -160,12 +160,13 @@ BasicTimeZone::getSimpleRulesNear(UDate date, InitialTimeZoneRule*& initial,
|
|||||||
|| (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0))
|
|| (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0))
|
||||||
&& (date + MILLIS_PER_YEAR > nextTransitionTime)) {
|
&& (date + MILLIS_PER_YEAR > nextTransitionTime)) {
|
||||||
|
|
||||||
int32_t year, month, dom, dow, doy, mid;
|
int32_t year, mid;
|
||||||
|
int8_t month, dom, dow;
|
||||||
UDate d;
|
UDate d;
|
||||||
|
|
||||||
// Get local wall time for the next transition time
|
// Get local wall time for the next transition time
|
||||||
Grego::timeToFields(nextTransitionTime + initialRaw + initialDst,
|
Grego::timeToFields(nextTransitionTime + initialRaw + initialDst,
|
||||||
year, month, dom, dow, doy, mid, status);
|
year, month, dom, dow, mid, status);
|
||||||
if (U_FAILURE(status)) return;
|
if (U_FAILURE(status)) return;
|
||||||
int32_t weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
|
int32_t weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
|
||||||
// Create DOW rule
|
// Create DOW rule
|
||||||
@ -193,7 +194,7 @@ BasicTimeZone::getSimpleRulesNear(UDate date, InitialTimeZoneRule*& initial,
|
|||||||
|
|
||||||
// Get local wall time for the next transition time
|
// Get local wall time for the next transition time
|
||||||
Grego::timeToFields(tr.getTime() + tr.getFrom()->getRawOffset() + tr.getFrom()->getDSTSavings(),
|
Grego::timeToFields(tr.getTime() + tr.getFrom()->getRawOffset() + tr.getFrom()->getDSTSavings(),
|
||||||
year, month, dom, dow, doy, mid, status);
|
year, month, dom, dow, mid, status);
|
||||||
if (U_FAILURE(status)) return;
|
if (U_FAILURE(status)) return;
|
||||||
weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
|
weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
|
||||||
// Generate another DOW rule
|
// Generate another DOW rule
|
||||||
@ -225,7 +226,7 @@ BasicTimeZone::getSimpleRulesNear(UDate date, InitialTimeZoneRule*& initial,
|
|||||||
|
|
||||||
// Generate another DOW rule
|
// Generate another DOW rule
|
||||||
Grego::timeToFields(tr.getTime() + tr.getFrom()->getRawOffset() + tr.getFrom()->getDSTSavings(),
|
Grego::timeToFields(tr.getTime() + tr.getFrom()->getRawOffset() + tr.getFrom()->getDSTSavings(),
|
||||||
year, month, dom, dow, doy, mid, status);
|
year, month, dom, dow, mid, status);
|
||||||
if (U_FAILURE(status)) return;
|
if (U_FAILURE(status)) return;
|
||||||
weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
|
weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
|
||||||
dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME);
|
dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME);
|
||||||
@ -486,8 +487,7 @@ BasicTimeZone::getTimeZoneRulesAfter(UDate start, InitialTimeZoneRule*& initial,
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Calculate the transition year
|
// Calculate the transition year
|
||||||
int32_t year, month, dom, dow, doy, mid;
|
int32_t year = Grego::timeToYear(tzt.getTime(), status);
|
||||||
Grego::timeToFields(tzt.getTime(), year, month, dom, dow, doy, mid, status);
|
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
7
deps/icu-small/source/i18n/buddhcal.cpp
vendored
7
deps/icu-small/source/i18n/buddhcal.cpp
vendored
@ -36,7 +36,6 @@ static const int32_t kGregorianEpoch = 1970; // used as the default value of
|
|||||||
BuddhistCalendar::BuddhistCalendar(const Locale& aLocale, UErrorCode& success)
|
BuddhistCalendar::BuddhistCalendar(const Locale& aLocale, UErrorCode& success)
|
||||||
: GregorianCalendar(aLocale, success)
|
: GregorianCalendar(aLocale, success)
|
||||||
{
|
{
|
||||||
setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BuddhistCalendar::~BuddhistCalendar()
|
BuddhistCalendar::~BuddhistCalendar()
|
||||||
@ -48,12 +47,6 @@ BuddhistCalendar::BuddhistCalendar(const BuddhistCalendar& source)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
BuddhistCalendar& BuddhistCalendar::operator= ( const BuddhistCalendar& right)
|
|
||||||
{
|
|
||||||
GregorianCalendar::operator=(right);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
BuddhistCalendar* BuddhistCalendar::clone() const
|
BuddhistCalendar* BuddhistCalendar::clone() const
|
||||||
{
|
{
|
||||||
return new BuddhistCalendar(*this);
|
return new BuddhistCalendar(*this);
|
||||||
|
7
deps/icu-small/source/i18n/buddhcal.h
vendored
7
deps/icu-small/source/i18n/buddhcal.h
vendored
@ -82,13 +82,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
BuddhistCalendar(const BuddhistCalendar& source);
|
BuddhistCalendar(const BuddhistCalendar& source);
|
||||||
|
|
||||||
/**
|
|
||||||
* Default assignment operator
|
|
||||||
* @param right the object to be copied.
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
BuddhistCalendar& operator=(const BuddhistCalendar& right);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create and return a polymorphic copy of this calendar.
|
* Create and return a polymorphic copy of this calendar.
|
||||||
* @return return a polymorphic copy of this calendar.
|
* @return return a polymorphic copy of this calendar.
|
||||||
|
162
deps/icu-small/source/i18n/calendar.cpp
vendored
162
deps/icu-small/source/i18n/calendar.cpp
vendored
@ -156,7 +156,7 @@ U_CFUNC void ucal_dump(UCalendar* cal) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Max value for stamp allowable before recalculation */
|
/* Max value for stamp allowable before recalculation */
|
||||||
#define STAMP_MAX 10000
|
#define STAMP_MAX 127
|
||||||
|
|
||||||
static const char * const gCalTypes[] = {
|
static const char * const gCalTypes[] = {
|
||||||
"gregorian",
|
"gregorian",
|
||||||
@ -700,15 +700,10 @@ fIsTimeSet(false),
|
|||||||
fAreFieldsSet(false),
|
fAreFieldsSet(false),
|
||||||
fAreAllFieldsSet(false),
|
fAreAllFieldsSet(false),
|
||||||
fAreFieldsVirtuallySet(false),
|
fAreFieldsVirtuallySet(false),
|
||||||
fNextStamp(static_cast<int32_t>(kMinimumUserStamp)),
|
|
||||||
fTime(0),
|
|
||||||
fLenient(true),
|
fLenient(true),
|
||||||
fZone(nullptr),
|
|
||||||
fRepeatedWallTime(UCAL_WALLTIME_LAST),
|
fRepeatedWallTime(UCAL_WALLTIME_LAST),
|
||||||
fSkippedWallTime(UCAL_WALLTIME_LAST)
|
fSkippedWallTime(UCAL_WALLTIME_LAST)
|
||||||
{
|
{
|
||||||
validLocale[0] = 0;
|
|
||||||
actualLocale[0] = 0;
|
|
||||||
clear();
|
clear();
|
||||||
if (U_FAILURE(success)) {
|
if (U_FAILURE(success)) {
|
||||||
return;
|
return;
|
||||||
@ -722,26 +717,21 @@ fSkippedWallTime(UCAL_WALLTIME_LAST)
|
|||||||
|
|
||||||
// -------------------------------------
|
// -------------------------------------
|
||||||
|
|
||||||
Calendar::Calendar(TimeZone* zone, const Locale& aLocale, UErrorCode& success)
|
Calendar::Calendar(TimeZone* adoptZone, const Locale& aLocale, UErrorCode& success)
|
||||||
: UObject(),
|
: UObject(),
|
||||||
fIsTimeSet(false),
|
fIsTimeSet(false),
|
||||||
fAreFieldsSet(false),
|
fAreFieldsSet(false),
|
||||||
fAreAllFieldsSet(false),
|
fAreAllFieldsSet(false),
|
||||||
fAreFieldsVirtuallySet(false),
|
fAreFieldsVirtuallySet(false),
|
||||||
fNextStamp(static_cast<int32_t>(kMinimumUserStamp)),
|
|
||||||
fTime(0),
|
|
||||||
fLenient(true),
|
fLenient(true),
|
||||||
fZone(nullptr),
|
|
||||||
fRepeatedWallTime(UCAL_WALLTIME_LAST),
|
fRepeatedWallTime(UCAL_WALLTIME_LAST),
|
||||||
fSkippedWallTime(UCAL_WALLTIME_LAST)
|
fSkippedWallTime(UCAL_WALLTIME_LAST)
|
||||||
{
|
{
|
||||||
validLocale[0] = 0;
|
LocalPointer<TimeZone> zone(adoptZone, success);
|
||||||
actualLocale[0] = 0;
|
|
||||||
if (U_FAILURE(success)) {
|
if (U_FAILURE(success)) {
|
||||||
delete zone;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (zone == nullptr) {
|
if (zone.isNull()) {
|
||||||
#if defined (U_DEBUG_CAL)
|
#if defined (U_DEBUG_CAL)
|
||||||
fprintf(stderr, "%s:%d: ILLEGAL ARG because timezone cannot be 0\n",
|
fprintf(stderr, "%s:%d: ILLEGAL ARG because timezone cannot be 0\n",
|
||||||
__FILE__, __LINE__);
|
__FILE__, __LINE__);
|
||||||
@ -751,7 +741,7 @@ fSkippedWallTime(UCAL_WALLTIME_LAST)
|
|||||||
}
|
}
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
fZone = zone;
|
fZone = zone.orphan();
|
||||||
setWeekData(aLocale, nullptr, success);
|
setWeekData(aLocale, nullptr, success);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -763,15 +753,10 @@ fIsTimeSet(false),
|
|||||||
fAreFieldsSet(false),
|
fAreFieldsSet(false),
|
||||||
fAreAllFieldsSet(false),
|
fAreAllFieldsSet(false),
|
||||||
fAreFieldsVirtuallySet(false),
|
fAreFieldsVirtuallySet(false),
|
||||||
fNextStamp(static_cast<int32_t>(kMinimumUserStamp)),
|
|
||||||
fTime(0),
|
|
||||||
fLenient(true),
|
fLenient(true),
|
||||||
fZone(nullptr),
|
|
||||||
fRepeatedWallTime(UCAL_WALLTIME_LAST),
|
fRepeatedWallTime(UCAL_WALLTIME_LAST),
|
||||||
fSkippedWallTime(UCAL_WALLTIME_LAST)
|
fSkippedWallTime(UCAL_WALLTIME_LAST)
|
||||||
{
|
{
|
||||||
validLocale[0] = 0;
|
|
||||||
actualLocale[0] = 0;
|
|
||||||
if (U_FAILURE(success)) {
|
if (U_FAILURE(success)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -779,6 +764,7 @@ fSkippedWallTime(UCAL_WALLTIME_LAST)
|
|||||||
fZone = zone.clone();
|
fZone = zone.clone();
|
||||||
if (fZone == nullptr) {
|
if (fZone == nullptr) {
|
||||||
success = U_MEMORY_ALLOCATION_ERROR;
|
success = U_MEMORY_ALLOCATION_ERROR;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
setWeekData(aLocale, nullptr, success);
|
setWeekData(aLocale, nullptr, success);
|
||||||
}
|
}
|
||||||
@ -788,6 +774,8 @@ fSkippedWallTime(UCAL_WALLTIME_LAST)
|
|||||||
Calendar::~Calendar()
|
Calendar::~Calendar()
|
||||||
{
|
{
|
||||||
delete fZone;
|
delete fZone;
|
||||||
|
delete actualLocale;
|
||||||
|
delete validLocale;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------
|
// -------------------------------------
|
||||||
@ -795,7 +783,6 @@ Calendar::~Calendar()
|
|||||||
Calendar::Calendar(const Calendar &source)
|
Calendar::Calendar(const Calendar &source)
|
||||||
: UObject(source)
|
: UObject(source)
|
||||||
{
|
{
|
||||||
fZone = nullptr;
|
|
||||||
*this = source;
|
*this = source;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -806,7 +793,6 @@ Calendar::operator=(const Calendar &right)
|
|||||||
{
|
{
|
||||||
if (this != &right) {
|
if (this != &right) {
|
||||||
uprv_arrayCopy(right.fFields, fFields, UCAL_FIELD_COUNT);
|
uprv_arrayCopy(right.fFields, fFields, UCAL_FIELD_COUNT);
|
||||||
uprv_arrayCopy(right.fIsSet, fIsSet, UCAL_FIELD_COUNT);
|
|
||||||
uprv_arrayCopy(right.fStamp, fStamp, UCAL_FIELD_COUNT);
|
uprv_arrayCopy(right.fStamp, fStamp, UCAL_FIELD_COUNT);
|
||||||
fTime = right.fTime;
|
fTime = right.fTime;
|
||||||
fIsTimeSet = right.fIsTimeSet;
|
fIsTimeSet = right.fIsTimeSet;
|
||||||
@ -828,10 +814,10 @@ Calendar::operator=(const Calendar &right)
|
|||||||
fWeekendCease = right.fWeekendCease;
|
fWeekendCease = right.fWeekendCease;
|
||||||
fWeekendCeaseMillis = right.fWeekendCeaseMillis;
|
fWeekendCeaseMillis = right.fWeekendCeaseMillis;
|
||||||
fNextStamp = right.fNextStamp;
|
fNextStamp = right.fNextStamp;
|
||||||
uprv_strncpy(validLocale, right.validLocale, sizeof(validLocale));
|
UErrorCode status = U_ZERO_ERROR;
|
||||||
uprv_strncpy(actualLocale, right.actualLocale, sizeof(actualLocale));
|
U_LOCALE_BASED(locBased, *this);
|
||||||
validLocale[sizeof(validLocale)-1] = 0;
|
locBased.setLocaleIDs(right.validLocale, right.actualLocale, status);
|
||||||
actualLocale[sizeof(validLocale)-1] = 0;
|
U_ASSERT(U_SUCCESS(status));
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
@ -1167,13 +1153,9 @@ Calendar::setTimeInMillis( double millis, UErrorCode& status ) {
|
|||||||
fAreFieldsSet = fAreAllFieldsSet = false;
|
fAreFieldsSet = fAreAllFieldsSet = false;
|
||||||
fIsTimeSet = fAreFieldsVirtuallySet = true;
|
fIsTimeSet = fAreFieldsVirtuallySet = true;
|
||||||
|
|
||||||
for (int32_t i=0; i<UCAL_FIELD_COUNT; ++i) {
|
uprv_memset(fFields, 0, sizeof(fFields));
|
||||||
fFields[i] = 0;
|
uprv_memset(fStamp, kUnset, sizeof(fStamp));
|
||||||
fStamp[i] = kUnset;
|
fNextStamp = kMinimumUserStamp;
|
||||||
fIsSet[i] = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------
|
// -------------------------------------
|
||||||
@ -1208,12 +1190,11 @@ Calendar::set(UCalendarDateFields field, int32_t value)
|
|||||||
computeFields(ec);
|
computeFields(ec);
|
||||||
}
|
}
|
||||||
fFields[field] = value;
|
fFields[field] = value;
|
||||||
/* Ensure that the fNextStamp value doesn't go pass max value for int32_t */
|
/* Ensure that the fNextStamp value doesn't go pass max value for int8_t */
|
||||||
if (fNextStamp == STAMP_MAX) {
|
if (fNextStamp == STAMP_MAX) {
|
||||||
recalculateStamp();
|
recalculateStamp();
|
||||||
}
|
}
|
||||||
fStamp[field] = fNextStamp++;
|
fStamp[field] = fNextStamp++;
|
||||||
fIsSet[field] = true; // Remove later
|
|
||||||
fIsTimeSet = fAreFieldsSet = fAreFieldsVirtuallySet = false;
|
fIsTimeSet = fAreFieldsSet = fAreFieldsVirtuallySet = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1270,11 +1251,9 @@ void Calendar::setRelatedYear(int32_t year)
|
|||||||
void
|
void
|
||||||
Calendar::clear()
|
Calendar::clear()
|
||||||
{
|
{
|
||||||
for (int32_t i=0; i<UCAL_FIELD_COUNT; ++i) {
|
uprv_memset(fFields, 0, sizeof(fFields));
|
||||||
fFields[i] = 0; // Must do this; other code depends on it
|
uprv_memset(fStamp, kUnset, sizeof(fStamp));
|
||||||
fStamp[i] = kUnset;
|
fNextStamp = kMinimumUserStamp;
|
||||||
fIsSet[i] = false; // Remove later
|
|
||||||
}
|
|
||||||
fIsTimeSet = fAreFieldsSet = fAreAllFieldsSet = fAreFieldsVirtuallySet = false;
|
fIsTimeSet = fAreFieldsSet = fAreAllFieldsSet = fAreFieldsVirtuallySet = false;
|
||||||
// fTime is not 'cleared' - may be used if no fields are set.
|
// fTime is not 'cleared' - may be used if no fields are set.
|
||||||
}
|
}
|
||||||
@ -1296,12 +1275,10 @@ Calendar::clear(UCalendarDateFields field)
|
|||||||
if (field == UCAL_MONTH) {
|
if (field == UCAL_MONTH) {
|
||||||
fFields[UCAL_ORDINAL_MONTH] = 0;
|
fFields[UCAL_ORDINAL_MONTH] = 0;
|
||||||
fStamp[UCAL_ORDINAL_MONTH] = kUnset;
|
fStamp[UCAL_ORDINAL_MONTH] = kUnset;
|
||||||
fIsSet[UCAL_ORDINAL_MONTH] = false; // Remove later
|
|
||||||
}
|
}
|
||||||
if (field == UCAL_ORDINAL_MONTH) {
|
if (field == UCAL_ORDINAL_MONTH) {
|
||||||
fFields[UCAL_MONTH] = 0;
|
fFields[UCAL_MONTH] = 0;
|
||||||
fStamp[UCAL_MONTH] = kUnset;
|
fStamp[UCAL_MONTH] = kUnset;
|
||||||
fIsSet[UCAL_MONTH] = false; // Remove later
|
|
||||||
}
|
}
|
||||||
fIsTimeSet = fAreFieldsSet = fAreAllFieldsSet = fAreFieldsVirtuallySet = false;
|
fIsTimeSet = fAreFieldsSet = fAreAllFieldsSet = fAreFieldsVirtuallySet = false;
|
||||||
}
|
}
|
||||||
@ -1434,10 +1411,8 @@ void Calendar::computeFields(UErrorCode &ec)
|
|||||||
for (int32_t i=0; i<UCAL_FIELD_COUNT; ++i) {
|
for (int32_t i=0; i<UCAL_FIELD_COUNT; ++i) {
|
||||||
if ((mask & 1) == 0) {
|
if ((mask & 1) == 0) {
|
||||||
fStamp[i] = kInternallySet;
|
fStamp[i] = kInternallySet;
|
||||||
fIsSet[i] = true; // Remove later
|
|
||||||
} else {
|
} else {
|
||||||
fStamp[i] = kUnset;
|
fStamp[i] = kUnset;
|
||||||
fIsSet[i] = false; // Remove later
|
|
||||||
}
|
}
|
||||||
mask >>= 1;
|
mask >>= 1;
|
||||||
}
|
}
|
||||||
@ -1467,7 +1442,7 @@ void Calendar::computeFields(UErrorCode &ec)
|
|||||||
//__FILE__, __LINE__, fFields[UCAL_JULIAN_DAY], localMillis);
|
//__FILE__, __LINE__, fFields[UCAL_JULIAN_DAY], localMillis);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
computeGregorianAndDOWFields(fFields[UCAL_JULIAN_DAY], ec);
|
computeGregorianFields(fFields[UCAL_JULIAN_DAY], ec);
|
||||||
|
|
||||||
// Call framework method to have subclass compute its fields.
|
// Call framework method to have subclass compute its fields.
|
||||||
// These must include, at a minimum, MONTH, DAY_OF_MONTH,
|
// These must include, at a minimum, MONTH, DAY_OF_MONTH,
|
||||||
@ -1538,32 +1513,6 @@ uint8_t Calendar::julianDayToDayOfWeek(int32_t julian)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Compute the Gregorian calendar year, month, and day of month from
|
|
||||||
* the given Julian day. These values are not stored in fields, but in
|
|
||||||
* member variables gregorianXxx. Also compute the DAY_OF_WEEK and
|
|
||||||
* DOW_LOCAL fields.
|
|
||||||
*/
|
|
||||||
void Calendar::computeGregorianAndDOWFields(int32_t julianDay, UErrorCode &ec)
|
|
||||||
{
|
|
||||||
computeGregorianFields(julianDay, ec);
|
|
||||||
if (U_FAILURE(ec)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute day of week: JD 0 = Monday
|
|
||||||
int32_t dow = julianDayToDayOfWeek(julianDay);
|
|
||||||
internalSet(UCAL_DAY_OF_WEEK,dow);
|
|
||||||
|
|
||||||
// Calculate 1-based localized day of week
|
|
||||||
int32_t dowLocal = dow - getFirstDayOfWeek() + 1;
|
|
||||||
if (dowLocal < 1) {
|
|
||||||
dowLocal += 7;
|
|
||||||
}
|
|
||||||
internalSet(UCAL_DOW_LOCAL,dowLocal);
|
|
||||||
fFields[UCAL_DOW_LOCAL] = dowLocal;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compute the Gregorian calendar year, month, and day of month from the
|
* Compute the Gregorian calendar year, month, and day of month from the
|
||||||
* Julian day. These values are not stored in fields, but in member
|
* Julian day. These values are not stored in fields, but in member
|
||||||
@ -1575,14 +1524,13 @@ void Calendar::computeGregorianFields(int32_t julianDay, UErrorCode& ec) {
|
|||||||
if (U_FAILURE(ec)) {
|
if (U_FAILURE(ec)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int32_t gregorianDayOfWeekUnused;
|
|
||||||
if (uprv_add32_overflow(
|
if (uprv_add32_overflow(
|
||||||
julianDay, -kEpochStartAsJulianDay, &julianDay)) {
|
julianDay, -kEpochStartAsJulianDay, &julianDay)) {
|
||||||
ec = U_ILLEGAL_ARGUMENT_ERROR;
|
ec = U_ILLEGAL_ARGUMENT_ERROR;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Grego::dayToFields(julianDay, fGregorianYear, fGregorianMonth,
|
Grego::dayToFields(julianDay, fGregorianYear, fGregorianMonth,
|
||||||
fGregorianDayOfMonth, gregorianDayOfWeekUnused,
|
fGregorianDayOfMonth,
|
||||||
fGregorianDayOfYear, ec);
|
fGregorianDayOfYear, ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1610,8 +1558,19 @@ void Calendar::computeWeekFields(UErrorCode &ec) {
|
|||||||
if(U_FAILURE(ec)) {
|
if(U_FAILURE(ec)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Compute day of week: JD 0 = Monday
|
||||||
|
int32_t dayOfWeek = julianDayToDayOfWeek(fFields[UCAL_JULIAN_DAY]);
|
||||||
|
internalSet(UCAL_DAY_OF_WEEK, dayOfWeek);
|
||||||
|
int32_t firstDayOfWeek = getFirstDayOfWeek();
|
||||||
|
// Calculate 1-based localized day of week
|
||||||
|
int32_t dowLocal = dayOfWeek - firstDayOfWeek + 1;
|
||||||
|
if (dowLocal < 1) {
|
||||||
|
dowLocal += 7;
|
||||||
|
}
|
||||||
|
internalSet(UCAL_DOW_LOCAL,dowLocal);
|
||||||
|
|
||||||
int32_t eyear = fFields[UCAL_EXTENDED_YEAR];
|
int32_t eyear = fFields[UCAL_EXTENDED_YEAR];
|
||||||
int32_t dayOfWeek = fFields[UCAL_DAY_OF_WEEK];
|
|
||||||
int32_t dayOfYear = fFields[UCAL_DAY_OF_YEAR];
|
int32_t dayOfYear = fFields[UCAL_DAY_OF_YEAR];
|
||||||
|
|
||||||
// WEEK_OF_YEAR start
|
// WEEK_OF_YEAR start
|
||||||
@ -1624,10 +1583,11 @@ void Calendar::computeWeekFields(UErrorCode &ec) {
|
|||||||
// first week of the next year. ASSUME that the year length is less than
|
// first week of the next year. ASSUME that the year length is less than
|
||||||
// 7000 days.
|
// 7000 days.
|
||||||
int32_t yearOfWeekOfYear = eyear;
|
int32_t yearOfWeekOfYear = eyear;
|
||||||
int32_t relDow = (dayOfWeek + 7 - getFirstDayOfWeek()) % 7; // 0..6
|
int32_t relDow = (dayOfWeek + 7 - firstDayOfWeek) % 7; // 0..6
|
||||||
int32_t relDowJan1 = (dayOfWeek - dayOfYear + 7001 - getFirstDayOfWeek()) % 7; // 0..6
|
int32_t relDowJan1 = (dayOfWeek - dayOfYear + 7001 - firstDayOfWeek) % 7; // 0..6
|
||||||
int32_t woy = (dayOfYear - 1 + relDowJan1) / 7; // 0..53
|
int32_t woy = (dayOfYear - 1 + relDowJan1) / 7; // 0..53
|
||||||
if ((7 - relDowJan1) >= getMinimalDaysInFirstWeek()) {
|
int32_t minimalDaysInFirstWeek = getMinimalDaysInFirstWeek();
|
||||||
|
if ((7 - relDowJan1) >= minimalDaysInFirstWeek) {
|
||||||
++woy;
|
++woy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1639,11 +1599,13 @@ void Calendar::computeWeekFields(UErrorCode &ec) {
|
|||||||
// to handle the case in which we are the first week of the
|
// to handle the case in which we are the first week of the
|
||||||
// next year.
|
// next year.
|
||||||
|
|
||||||
int32_t prevDoy = dayOfYear + handleGetYearLength(eyear - 1);
|
int32_t prevDoy = dayOfYear + handleGetYearLength(eyear - 1, ec);
|
||||||
|
if(U_FAILURE(ec)) return;
|
||||||
woy = weekNumber(prevDoy, dayOfWeek);
|
woy = weekNumber(prevDoy, dayOfWeek);
|
||||||
yearOfWeekOfYear--;
|
yearOfWeekOfYear--;
|
||||||
} else {
|
} else {
|
||||||
int32_t lastDoy = handleGetYearLength(eyear);
|
int32_t lastDoy = handleGetYearLength(eyear, ec);
|
||||||
|
if(U_FAILURE(ec)) return;
|
||||||
// Fast check: For it to be week 1 of the next year, the DOY
|
// Fast check: For it to be week 1 of the next year, the DOY
|
||||||
// must be on or after L-5, where L is yearLength(), then it
|
// must be on or after L-5, where L is yearLength(), then it
|
||||||
// cannot possibly be week 1 of the next year:
|
// cannot possibly be week 1 of the next year:
|
||||||
@ -1655,7 +1617,7 @@ void Calendar::computeWeekFields(UErrorCode &ec) {
|
|||||||
if (lastRelDow < 0) {
|
if (lastRelDow < 0) {
|
||||||
lastRelDow += 7;
|
lastRelDow += 7;
|
||||||
}
|
}
|
||||||
if (((6 - lastRelDow) >= getMinimalDaysInFirstWeek()) &&
|
if (((6 - lastRelDow) >= minimalDaysInFirstWeek) &&
|
||||||
((dayOfYear + 7 - relDow) > lastDoy)) {
|
((dayOfYear + 7 - relDow) > lastDoy)) {
|
||||||
woy = 1;
|
woy = 1;
|
||||||
yearOfWeekOfYear++;
|
yearOfWeekOfYear++;
|
||||||
@ -2946,7 +2908,7 @@ void Calendar::validateField(UCalendarDateFields field, UErrorCode &status) {
|
|||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
validateField(field, 1, handleGetYearLength(y), status);
|
validateField(field, 1, handleGetYearLength(y, status), status);
|
||||||
break;
|
break;
|
||||||
case UCAL_DAY_OF_WEEK_IN_MONTH:
|
case UCAL_DAY_OF_WEEK_IN_MONTH:
|
||||||
if (internalGet(field) == 0) {
|
if (internalGet(field) == 0) {
|
||||||
@ -3607,9 +3569,19 @@ int32_t Calendar::handleComputeJulianDay(UCalendarDateFields bestField, UErrorCo
|
|||||||
fprintf(stderr, "%s:%d - y=%d, y-1=%d doy%d, njd%d (C.F. %d)\n",
|
fprintf(stderr, "%s:%d - y=%d, y-1=%d doy%d, njd%d (C.F. %d)\n",
|
||||||
__FILE__, __LINE__, year, year-1, testDate, julianDay+testDate, nextJulianDay);
|
__FILE__, __LINE__, year, year-1, testDate, julianDay+testDate, nextJulianDay);
|
||||||
#endif
|
#endif
|
||||||
if(julianDay+testDate > nextJulianDay) { // is it past Dec 31? (nextJulianDay is day BEFORE year+1's Jan 1)
|
if (uprv_add32_overflow(julianDay, testDate, &testDate)) {
|
||||||
|
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(testDate > nextJulianDay) { // is it past Dec 31? (nextJulianDay is day BEFORE year+1's Jan 1)
|
||||||
// Fire up the calculating engines.. retry YWOY = (year-1)
|
// Fire up the calculating engines.. retry YWOY = (year-1)
|
||||||
julianDay = handleComputeMonthStart(year-1, 0, false, status); // jd before Jan 1 of previous year
|
int32_t prevYear;
|
||||||
|
if (uprv_add32_overflow(year, -1, &prevYear)) {
|
||||||
|
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
julianDay = handleComputeMonthStart(prevYear, 0, false, status); // jd before Jan 1 of previous year
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -3834,16 +3806,20 @@ int32_t Calendar::handleGetExtendedYearFromWeekFields(int32_t yearWoy, int32_t w
|
|||||||
|
|
||||||
int32_t Calendar::handleGetMonthLength(int32_t extendedYear, int32_t month, UErrorCode& status) const
|
int32_t Calendar::handleGetMonthLength(int32_t extendedYear, int32_t month, UErrorCode& status) const
|
||||||
{
|
{
|
||||||
return handleComputeMonthStart(extendedYear, month+1, true, status) -
|
int32_t nextMonth;
|
||||||
|
if (uprv_add32_overflow(month, 1, &nextMonth)) {
|
||||||
|
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return handleComputeMonthStart(extendedYear, nextMonth, true, status) -
|
||||||
handleComputeMonthStart(extendedYear, month, true, status);
|
handleComputeMonthStart(extendedYear, month, true, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t Calendar::handleGetYearLength(int32_t eyear) const
|
int32_t Calendar::handleGetYearLength(int32_t eyear, UErrorCode& status) const
|
||||||
{
|
{
|
||||||
UErrorCode status = U_ZERO_ERROR;
|
|
||||||
int32_t result = handleComputeMonthStart(eyear+1, 0, false, status) -
|
int32_t result = handleComputeMonthStart(eyear+1, 0, false, status) -
|
||||||
handleComputeMonthStart(eyear, 0, false, status);
|
handleComputeMonthStart(eyear, 0, false, status);
|
||||||
U_ASSERT(U_SUCCESS(status));
|
if (U_FAILURE(status)) return 0;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3882,7 +3858,7 @@ Calendar::getActualMaximum(UCalendarDateFields field, UErrorCode& status) const
|
|||||||
}
|
}
|
||||||
cal->setLenient(true);
|
cal->setLenient(true);
|
||||||
cal->prepareGetActual(field,false,status);
|
cal->prepareGetActual(field,false,status);
|
||||||
result = handleGetYearLength(cal->get(UCAL_EXTENDED_YEAR, status));
|
result = handleGetYearLength(cal->get(UCAL_EXTENDED_YEAR, status), status);
|
||||||
delete cal;
|
delete cal;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -4141,7 +4117,7 @@ Calendar::setWeekData(const Locale& desiredLocale, const char *type, UErrorCode&
|
|||||||
if (U_SUCCESS(status)) {
|
if (U_SUCCESS(status)) {
|
||||||
U_LOCALE_BASED(locBased,*this);
|
U_LOCALE_BASED(locBased,*this);
|
||||||
locBased.setLocaleIDs(ures_getLocaleByType(monthNames.getAlias(), ULOC_VALID_LOCALE, &status),
|
locBased.setLocaleIDs(ures_getLocaleByType(monthNames.getAlias(), ULOC_VALID_LOCALE, &status),
|
||||||
ures_getLocaleByType(monthNames.getAlias(), ULOC_ACTUAL_LOCALE, &status));
|
ures_getLocaleByType(monthNames.getAlias(), ULOC_ACTUAL_LOCALE, &status), status);
|
||||||
} else {
|
} else {
|
||||||
status = U_USING_FALLBACK_WARNING;
|
status = U_USING_FALLBACK_WARNING;
|
||||||
return;
|
return;
|
||||||
@ -4229,14 +4205,12 @@ Calendar::updateTime(UErrorCode& status)
|
|||||||
|
|
||||||
Locale
|
Locale
|
||||||
Calendar::getLocale(ULocDataLocaleType type, UErrorCode& status) const {
|
Calendar::getLocale(ULocDataLocaleType type, UErrorCode& status) const {
|
||||||
U_LOCALE_BASED(locBased, *this);
|
return LocaleBased::getLocale(validLocale, actualLocale, type, status);
|
||||||
return locBased.getLocale(type, status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
Calendar::getLocaleID(ULocDataLocaleType type, UErrorCode& status) const {
|
Calendar::getLocaleID(ULocDataLocaleType type, UErrorCode& status) const {
|
||||||
U_LOCALE_BASED(locBased, *this);
|
return LocaleBased::getLocaleID(validLocale, actualLocale, type, status);
|
||||||
return locBased.getLocaleID(type, status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -4245,7 +4219,7 @@ Calendar::recalculateStamp() {
|
|||||||
int32_t currentValue;
|
int32_t currentValue;
|
||||||
int32_t j, i;
|
int32_t j, i;
|
||||||
|
|
||||||
fNextStamp = 1;
|
fNextStamp = kInternallySet;
|
||||||
|
|
||||||
for (j = 0; j < UCAL_FIELD_COUNT; j++) {
|
for (j = 0; j < UCAL_FIELD_COUNT; j++) {
|
||||||
currentValue = STAMP_MAX;
|
currentValue = STAMP_MAX;
|
||||||
|
8
deps/icu-small/source/i18n/cecal.cpp
vendored
8
deps/icu-small/source/i18n/cecal.cpp
vendored
@ -53,7 +53,6 @@ static const int32_t LIMITS[UCAL_FIELD_COUNT][4] = {
|
|||||||
CECalendar::CECalendar(const Locale& aLocale, UErrorCode& success)
|
CECalendar::CECalendar(const Locale& aLocale, UErrorCode& success)
|
||||||
: Calendar(TimeZone::forLocaleOrDefault(aLocale), aLocale, success)
|
: Calendar(TimeZone::forLocaleOrDefault(aLocale), aLocale, success)
|
||||||
{
|
{
|
||||||
setTimeInMillis(getNow(), success);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CECalendar::CECalendar (const CECalendar& other)
|
CECalendar::CECalendar (const CECalendar& other)
|
||||||
@ -65,13 +64,6 @@ CECalendar::~CECalendar()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CECalendar&
|
|
||||||
CECalendar::operator=(const CECalendar& right)
|
|
||||||
{
|
|
||||||
Calendar::operator=(right);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
// Calendar framework
|
// Calendar framework
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
|
7
deps/icu-small/source/i18n/cecal.h
vendored
7
deps/icu-small/source/i18n/cecal.h
vendored
@ -82,13 +82,6 @@ protected:
|
|||||||
*/
|
*/
|
||||||
virtual ~CECalendar();
|
virtual ~CECalendar();
|
||||||
|
|
||||||
/**
|
|
||||||
* Default assignment operator
|
|
||||||
* @param right Calendar object to be copied
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
CECalendar& operator=(const CECalendar& right);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
// Calendar framework
|
// Calendar framework
|
||||||
|
69
deps/icu-small/source/i18n/chnsecal.cpp
vendored
69
deps/icu-small/source/i18n/chnsecal.cpp
vendored
@ -130,7 +130,6 @@ ChineseCalendar::ChineseCalendar(const Locale& aLocale, UErrorCode& success)
|
|||||||
: Calendar(TimeZone::forLocaleOrDefault(aLocale), aLocale, success),
|
: Calendar(TimeZone::forLocaleOrDefault(aLocale), aLocale, success),
|
||||||
hasLeapMonthBetweenWinterSolstices(false)
|
hasLeapMonthBetweenWinterSolstices(false)
|
||||||
{
|
{
|
||||||
setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ChineseCalendar::ChineseCalendar(const ChineseCalendar& other) : Calendar(other) {
|
ChineseCalendar::ChineseCalendar(const ChineseCalendar& other) : Calendar(other) {
|
||||||
@ -219,7 +218,9 @@ int32_t ChineseCalendar::handleGetExtendedYear(UErrorCode& status) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int32_t year;
|
int32_t year;
|
||||||
if (newestStamp(UCAL_ERA, UCAL_YEAR, kUnset) <= fStamp[UCAL_EXTENDED_YEAR]) {
|
// if UCAL_EXTENDED_YEAR is not older than UCAL_ERA nor UCAL_YEAR
|
||||||
|
if (newerField(UCAL_EXTENDED_YEAR, newerField(UCAL_ERA, UCAL_YEAR)) ==
|
||||||
|
UCAL_EXTENDED_YEAR) {
|
||||||
year = internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1
|
year = internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1
|
||||||
} else {
|
} else {
|
||||||
// adjust to the instance specific epoch
|
// adjust to the instance specific epoch
|
||||||
@ -252,11 +253,16 @@ int32_t ChineseCalendar::handleGetExtendedYear(UErrorCode& status) {
|
|||||||
* @stable ICU 2.8
|
* @stable ICU 2.8
|
||||||
*/
|
*/
|
||||||
int32_t ChineseCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month, UErrorCode& status) const {
|
int32_t ChineseCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month, UErrorCode& status) const {
|
||||||
|
bool isLeapMonth = internalGet(UCAL_IS_LEAP_MONTH) == 1;
|
||||||
|
return handleGetMonthLengthWithLeap(extendedYear, month, isLeapMonth, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t ChineseCalendar::handleGetMonthLengthWithLeap(int32_t extendedYear, int32_t month, bool leap, UErrorCode& status) const {
|
||||||
const Setting setting = getSetting(status);
|
const Setting setting = getSetting(status);
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int32_t thisStart = handleComputeMonthStart(extendedYear, month, true, status);
|
int32_t thisStart = handleComputeMonthStartWithLeap(extendedYear, month, leap, status);
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -332,18 +338,24 @@ struct MonthInfo computeMonthInfo(
|
|||||||
* @stable ICU 2.8
|
* @stable ICU 2.8
|
||||||
*/
|
*/
|
||||||
int64_t ChineseCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, UBool useMonth, UErrorCode& status) const {
|
int64_t ChineseCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, UBool useMonth, UErrorCode& status) const {
|
||||||
|
bool isLeapMonth = false;
|
||||||
|
if (useMonth) {
|
||||||
|
isLeapMonth = internalGet(UCAL_IS_LEAP_MONTH) != 0;
|
||||||
|
}
|
||||||
|
return handleComputeMonthStartWithLeap(eyear, month, isLeapMonth, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t ChineseCalendar::handleComputeMonthStartWithLeap(int32_t eyear, int32_t month, bool isLeapMonth, UErrorCode& status) const {
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// If the month is out of range, adjust it into range, and
|
// If the month is out of range, adjust it into range, and
|
||||||
// modify the extended year value accordingly.
|
// modify the extended year value accordingly.
|
||||||
if (month < 0 || month > 11) {
|
if (month < 0 || month > 11) {
|
||||||
double m = month;
|
if (uprv_add32_overflow(eyear, ClockMath::floorDivide(month, 12, &month), &eyear)) {
|
||||||
if (uprv_add32_overflow(eyear, ClockMath::floorDivide(m, 12.0, &m), &eyear)) {
|
|
||||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
month = static_cast<int32_t>(m);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Setting setting = getSetting(status);
|
const Setting setting = getSetting(status);
|
||||||
@ -362,19 +374,9 @@ int64_t ChineseCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, U
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore IS_LEAP_MONTH field if useMonth is false
|
int32_t newMonthYear = Grego::dayToYear(newMoon, status);
|
||||||
bool isLeapMonth = false;
|
|
||||||
if (useMonth) {
|
|
||||||
isLeapMonth = internalGet(UCAL_IS_LEAP_MONTH) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t unusedMonth;
|
struct MonthInfo monthInfo = computeMonthInfo(setting, newMonthYear, newMoon, status);
|
||||||
int32_t unusedDayOfWeek;
|
|
||||||
int32_t unusedDayOfMonth;
|
|
||||||
int32_t unusedDayOfYear;
|
|
||||||
Grego::dayToFields(newMoon, gyear, unusedMonth, unusedDayOfWeek, unusedDayOfMonth, unusedDayOfYear, status);
|
|
||||||
|
|
||||||
struct MonthInfo monthInfo = computeMonthInfo(setting, gyear, newMoon, status);
|
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -794,6 +796,9 @@ struct MonthInfo computeMonthInfo(
|
|||||||
solsticeBefore = solsticeAfter;
|
solsticeBefore = solsticeAfter;
|
||||||
solsticeAfter = winterSolstice(setting, gyear + 1, status);
|
solsticeAfter = winterSolstice(setting, gyear + 1, status);
|
||||||
}
|
}
|
||||||
|
if (!(solsticeBefore <= days && days < solsticeAfter)) {
|
||||||
|
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||||
|
}
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
@ -1043,7 +1048,12 @@ void ChineseCalendar::offsetMonth(int32_t newMoon, int32_t dayOfMonth, int32_t d
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find the target dayOfMonth
|
// Find the target dayOfMonth
|
||||||
int32_t jd = newMoon + kEpochStartAsJulianDay - 1 + dayOfMonth;
|
int32_t jd;
|
||||||
|
if (uprv_add32_overflow(newMoon, kEpochStartAsJulianDay - 1, &jd) ||
|
||||||
|
uprv_add32_overflow(jd, dayOfMonth, &jd)) {
|
||||||
|
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Pin the dayOfMonth. In this calendar all months are 29 or 30 days
|
// Pin the dayOfMonth. In this calendar all months are 29 or 30 days
|
||||||
// so pinning just means handling dayOfMonth 30.
|
// so pinning just means handling dayOfMonth 30.
|
||||||
@ -1182,6 +1192,27 @@ ChineseCalendar::Setting ChineseCalendar::getSetting(UErrorCode&) const {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t
|
||||||
|
ChineseCalendar::getActualMaximum(UCalendarDateFields field, UErrorCode& status) const
|
||||||
|
{
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (field == UCAL_DATE) {
|
||||||
|
LocalPointer<ChineseCalendar> cal(clone(), status);
|
||||||
|
if(U_FAILURE(status)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
cal->setLenient(true);
|
||||||
|
cal->prepareGetActual(field,false,status);
|
||||||
|
int32_t year = cal->get(UCAL_EXTENDED_YEAR, status);
|
||||||
|
int32_t month = cal->get(UCAL_MONTH, status);
|
||||||
|
bool leap = cal->get(UCAL_IS_LEAP_MONTH, status) != 0;
|
||||||
|
return handleGetMonthLengthWithLeap(year, month, leap, status);
|
||||||
|
}
|
||||||
|
return Calendar::getActualMaximum(field, status);
|
||||||
|
}
|
||||||
|
|
||||||
U_NAMESPACE_END
|
U_NAMESPACE_END
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
6
deps/icu-small/source/i18n/chnsecal.h
vendored
6
deps/icu-small/source/i18n/chnsecal.h
vendored
@ -194,6 +194,10 @@ class U_I18N_API ChineseCalendar : public Calendar {
|
|||||||
virtual void handleComputeFields(int32_t julianDay, UErrorCode &status) override;
|
virtual void handleComputeFields(int32_t julianDay, UErrorCode &status) override;
|
||||||
virtual const UFieldResolutionTable* getFieldResolutionTable() const override;
|
virtual const UFieldResolutionTable* getFieldResolutionTable() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int32_t handleGetMonthLengthWithLeap(int32_t extendedYear, int32_t month, bool isLeap, UErrorCode& status) const;
|
||||||
|
int64_t handleComputeMonthStartWithLeap(int32_t eyear, int32_t month, bool isLeap, UErrorCode& status) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void add(UCalendarDateFields field, int32_t amount, UErrorCode &status) override;
|
virtual void add(UCalendarDateFields field, int32_t amount, UErrorCode &status) override;
|
||||||
virtual void add(EDateFields field, int32_t amount, UErrorCode &status) override;
|
virtual void add(EDateFields field, int32_t amount, UErrorCode &status) override;
|
||||||
@ -254,6 +258,8 @@ class U_I18N_API ChineseCalendar : public Calendar {
|
|||||||
*/
|
*/
|
||||||
virtual const char * getType() const override;
|
virtual const char * getType() const override;
|
||||||
|
|
||||||
|
virtual int32_t getActualMaximum(UCalendarDateFields field, UErrorCode& status) const override;
|
||||||
|
|
||||||
struct Setting {
|
struct Setting {
|
||||||
int32_t epochYear;
|
int32_t epochYear;
|
||||||
const TimeZone* zoneAstroCalc;
|
const TimeZone* zoneAstroCalc;
|
||||||
|
@ -613,18 +613,24 @@ CollationRuleParser::parseSetting(UErrorCode &errorCode) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// localeID minus all keywords
|
// localeID minus all keywords
|
||||||
char baseID[ULOC_FULLNAME_CAPACITY];
|
CharString baseID = ulocimp_getBaseName(localeID.toStringPiece(), errorCode);
|
||||||
int32_t length = uloc_getBaseName(localeID.data(), baseID, ULOC_FULLNAME_CAPACITY, &errorCode);
|
if (U_FAILURE(errorCode)) {
|
||||||
if(U_FAILURE(errorCode) || length >= ULOC_KEYWORDS_CAPACITY) {
|
|
||||||
errorCode = U_ZERO_ERROR;
|
errorCode = U_ZERO_ERROR;
|
||||||
setParseError("expected language tag in [import langTag]", errorCode);
|
setParseError("expected language tag in [import langTag]", errorCode);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(length == 0) {
|
if (baseID.isEmpty()) {
|
||||||
uprv_strcpy(baseID, "root");
|
baseID.copyFrom("root", errorCode);
|
||||||
} else if(*baseID == '_') {
|
} else if (baseID[0] == '_') {
|
||||||
uprv_memmove(baseID + 3, baseID, length + 1);
|
// CharString doesn't have any insert() method, only append().
|
||||||
uprv_memcpy(baseID, "und", 3);
|
constexpr char und[] = "und";
|
||||||
|
constexpr int32_t length = sizeof und - 1;
|
||||||
|
int32_t dummy;
|
||||||
|
char* tail = baseID.getAppendBuffer(length, length, dummy, errorCode);
|
||||||
|
char* head = baseID.data();
|
||||||
|
uprv_memmove(head + length, head, baseID.length());
|
||||||
|
uprv_memcpy(head, und, length);
|
||||||
|
baseID.append(tail, length, errorCode);
|
||||||
}
|
}
|
||||||
// @collation=type, or length=0 if not specified
|
// @collation=type, or length=0 if not specified
|
||||||
CharString collationType = ulocimp_getKeywordValue(localeID.data(), "collation", errorCode);
|
CharString collationType = ulocimp_getKeywordValue(localeID.data(), "collation", errorCode);
|
||||||
@ -637,7 +643,7 @@ CollationRuleParser::parseSetting(UErrorCode &errorCode) {
|
|||||||
setParseError("[import langTag] is not supported", errorCode);
|
setParseError("[import langTag] is not supported", errorCode);
|
||||||
} else {
|
} else {
|
||||||
UnicodeString importedRules;
|
UnicodeString importedRules;
|
||||||
importer->getRules(baseID,
|
importer->getRules(baseID.data(),
|
||||||
!collationType.isEmpty() ? collationType.data() : "standard",
|
!collationType.isEmpty() ? collationType.data() : "standard",
|
||||||
importedRules, errorReason, errorCode);
|
importedRules, errorReason, errorCode);
|
||||||
if(U_FAILURE(errorCode)) {
|
if(U_FAILURE(errorCode)) {
|
||||||
|
7
deps/icu-small/source/i18n/datefmt.cpp
vendored
7
deps/icu-small/source/i18n/datefmt.cpp
vendored
@ -40,6 +40,7 @@
|
|||||||
#if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL)
|
#if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL)
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include <typeinfo>
|
||||||
|
|
||||||
// *****************************************************************************
|
// *****************************************************************************
|
||||||
// class DateFormat
|
// class DateFormat
|
||||||
@ -279,9 +280,8 @@ UnicodeString&
|
|||||||
DateFormat::format(UDate date, UnicodeString& appendTo, FieldPosition& fieldPosition) const {
|
DateFormat::format(UDate date, UnicodeString& appendTo, FieldPosition& fieldPosition) const {
|
||||||
if (fCalendar != nullptr) {
|
if (fCalendar != nullptr) {
|
||||||
UErrorCode ec = U_ZERO_ERROR;
|
UErrorCode ec = U_ZERO_ERROR;
|
||||||
const auto* calType = fCalendar->getType();
|
|
||||||
// Avoid a heap allocation and corresponding free for the common case
|
// Avoid a heap allocation and corresponding free for the common case
|
||||||
if (uprv_strcmp(calType, "gregorian") == 0) {
|
if (typeid(*fCalendar) == typeid(GregorianCalendar)) {
|
||||||
GregorianCalendar cal(*static_cast<GregorianCalendar*>(fCalendar));
|
GregorianCalendar cal(*static_cast<GregorianCalendar*>(fCalendar));
|
||||||
cal.setTime(date, ec);
|
cal.setTime(date, ec);
|
||||||
if (U_SUCCESS(ec)) {
|
if (U_SUCCESS(ec)) {
|
||||||
@ -309,9 +309,8 @@ DateFormat::format(UDate date, UnicodeString& appendTo, FieldPositionIterator* p
|
|||||||
UErrorCode& status) const {
|
UErrorCode& status) const {
|
||||||
if (fCalendar != nullptr) {
|
if (fCalendar != nullptr) {
|
||||||
UErrorCode ec = U_ZERO_ERROR;
|
UErrorCode ec = U_ZERO_ERROR;
|
||||||
const auto* calType = fCalendar->getType();
|
|
||||||
// Avoid a heap allocation and corresponding free for the common case
|
// Avoid a heap allocation and corresponding free for the common case
|
||||||
if (uprv_strcmp(calType, "gregorian") == 0) {
|
if (typeid(*fCalendar) == typeid(GregorianCalendar)) {
|
||||||
GregorianCalendar cal(*static_cast<GregorianCalendar*>(fCalendar));
|
GregorianCalendar cal(*static_cast<GregorianCalendar*>(fCalendar));
|
||||||
cal.setTime(date, ec);
|
cal.setTime(date, ec);
|
||||||
if (U_SUCCESS(ec)) {
|
if (U_SUCCESS(ec)) {
|
||||||
|
22
deps/icu-small/source/i18n/dcfmtsym.cpp
vendored
22
deps/icu-small/source/i18n/dcfmtsym.cpp
vendored
@ -118,7 +118,6 @@ DecimalFormatSymbols::DecimalFormatSymbols(const Locale& loc, const NumberingSys
|
|||||||
|
|
||||||
DecimalFormatSymbols::DecimalFormatSymbols()
|
DecimalFormatSymbols::DecimalFormatSymbols()
|
||||||
: UObject(), locale(Locale::getRoot()) {
|
: UObject(), locale(Locale::getRoot()) {
|
||||||
*validLocale = *actualLocale = 0;
|
|
||||||
initialize();
|
initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,6 +135,8 @@ DecimalFormatSymbols::createWithLastResortData(UErrorCode& status) {
|
|||||||
|
|
||||||
DecimalFormatSymbols::~DecimalFormatSymbols()
|
DecimalFormatSymbols::~DecimalFormatSymbols()
|
||||||
{
|
{
|
||||||
|
delete actualLocale;
|
||||||
|
delete validLocale;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------
|
// -------------------------------------
|
||||||
@ -163,8 +164,12 @@ DecimalFormatSymbols::operator=(const DecimalFormatSymbols& rhs)
|
|||||||
currencySpcAfterSym[i].fastCopyFrom(rhs.currencySpcAfterSym[i]);
|
currencySpcAfterSym[i].fastCopyFrom(rhs.currencySpcAfterSym[i]);
|
||||||
}
|
}
|
||||||
locale = rhs.locale;
|
locale = rhs.locale;
|
||||||
uprv_strcpy(validLocale, rhs.validLocale);
|
|
||||||
uprv_strcpy(actualLocale, rhs.actualLocale);
|
UErrorCode status = U_ZERO_ERROR;
|
||||||
|
U_LOCALE_BASED(locBased, *this);
|
||||||
|
locBased.setLocaleIDs(rhs.validLocale, rhs.actualLocale, status);
|
||||||
|
U_ASSERT(U_SUCCESS(status));
|
||||||
|
|
||||||
fIsCustomCurrencySymbol = rhs.fIsCustomCurrencySymbol;
|
fIsCustomCurrencySymbol = rhs.fIsCustomCurrencySymbol;
|
||||||
fIsCustomIntlCurrencySymbol = rhs.fIsCustomIntlCurrencySymbol;
|
fIsCustomIntlCurrencySymbol = rhs.fIsCustomIntlCurrencySymbol;
|
||||||
fCodePointZero = rhs.fCodePointZero;
|
fCodePointZero = rhs.fCodePointZero;
|
||||||
@ -203,8 +208,8 @@ DecimalFormatSymbols::operator==(const DecimalFormatSymbols& that) const
|
|||||||
}
|
}
|
||||||
// No need to check fCodePointZero since it is based on fSymbols
|
// No need to check fCodePointZero since it is based on fSymbols
|
||||||
return locale == that.locale &&
|
return locale == that.locale &&
|
||||||
uprv_strcmp(validLocale, that.validLocale) == 0 &&
|
LocaleBased::equalIDs(actualLocale, that.actualLocale) &&
|
||||||
uprv_strcmp(actualLocale, that.actualLocale) == 0;
|
LocaleBased::equalIDs(validLocale, that.validLocale);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------
|
// -------------------------------------
|
||||||
@ -353,7 +358,6 @@ DecimalFormatSymbols::initialize(const Locale& loc, UErrorCode& status,
|
|||||||
UBool useLastResortData, const NumberingSystem* ns)
|
UBool useLastResortData, const NumberingSystem* ns)
|
||||||
{
|
{
|
||||||
if (U_FAILURE(status)) { return; }
|
if (U_FAILURE(status)) { return; }
|
||||||
*validLocale = *actualLocale = 0;
|
|
||||||
|
|
||||||
// First initialize all the symbols to the fallbacks for anything we can't find
|
// First initialize all the symbols to the fallbacks for anything we can't find
|
||||||
initialize();
|
initialize();
|
||||||
@ -409,7 +413,8 @@ DecimalFormatSymbols::initialize(const Locale& loc, UErrorCode& status,
|
|||||||
ULOC_VALID_LOCALE, &status),
|
ULOC_VALID_LOCALE, &status),
|
||||||
ures_getLocaleByType(
|
ures_getLocaleByType(
|
||||||
numberElementsRes.getAlias(),
|
numberElementsRes.getAlias(),
|
||||||
ULOC_ACTUAL_LOCALE, &status));
|
ULOC_ACTUAL_LOCALE, &status),
|
||||||
|
status);
|
||||||
|
|
||||||
// Now load the rest of the data from the data sink.
|
// Now load the rest of the data from the data sink.
|
||||||
// Start with loading this nsName if it is not Latin.
|
// Start with loading this nsName if it is not Latin.
|
||||||
@ -568,8 +573,7 @@ void DecimalFormatSymbols::setCurrency(const char16_t* currency, UErrorCode& sta
|
|||||||
|
|
||||||
Locale
|
Locale
|
||||||
DecimalFormatSymbols::getLocale(ULocDataLocaleType type, UErrorCode& status) const {
|
DecimalFormatSymbols::getLocale(ULocDataLocaleType type, UErrorCode& status) const {
|
||||||
U_LOCALE_BASED(locBased, *this);
|
return LocaleBased::getLocale(validLocale, actualLocale, type, status);
|
||||||
return locBased.getLocale(type, status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const UnicodeString&
|
const UnicodeString&
|
||||||
|
16
deps/icu-small/source/i18n/dtfmtsym.cpp
vendored
16
deps/icu-small/source/i18n/dtfmtsym.cpp
vendored
@ -402,9 +402,8 @@ void
|
|||||||
DateFormatSymbols::copyData(const DateFormatSymbols& other) {
|
DateFormatSymbols::copyData(const DateFormatSymbols& other) {
|
||||||
UErrorCode status = U_ZERO_ERROR;
|
UErrorCode status = U_ZERO_ERROR;
|
||||||
U_LOCALE_BASED(locBased, *this);
|
U_LOCALE_BASED(locBased, *this);
|
||||||
locBased.setLocaleIDs(
|
locBased.setLocaleIDs(other.validLocale, other.actualLocale, status);
|
||||||
other.getLocale(ULOC_VALID_LOCALE, status),
|
U_ASSERT(U_SUCCESS(status));
|
||||||
other.getLocale(ULOC_ACTUAL_LOCALE, status));
|
|
||||||
assignArray(fEras, fErasCount, other.fEras, other.fErasCount);
|
assignArray(fEras, fErasCount, other.fEras, other.fErasCount);
|
||||||
assignArray(fEraNames, fEraNamesCount, other.fEraNames, other.fEraNamesCount);
|
assignArray(fEraNames, fEraNamesCount, other.fEraNames, other.fEraNamesCount);
|
||||||
assignArray(fNarrowEras, fNarrowErasCount, other.fNarrowEras, other.fNarrowErasCount);
|
assignArray(fNarrowEras, fNarrowErasCount, other.fNarrowEras, other.fNarrowErasCount);
|
||||||
@ -497,6 +496,8 @@ DateFormatSymbols& DateFormatSymbols::operator=(const DateFormatSymbols& other)
|
|||||||
DateFormatSymbols::~DateFormatSymbols()
|
DateFormatSymbols::~DateFormatSymbols()
|
||||||
{
|
{
|
||||||
dispose();
|
dispose();
|
||||||
|
delete actualLocale;
|
||||||
|
delete validLocale;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DateFormatSymbols::dispose()
|
void DateFormatSymbols::dispose()
|
||||||
@ -536,6 +537,10 @@ void DateFormatSymbols::dispose()
|
|||||||
delete[] fStandaloneWideDayPeriods;
|
delete[] fStandaloneWideDayPeriods;
|
||||||
delete[] fStandaloneNarrowDayPeriods;
|
delete[] fStandaloneNarrowDayPeriods;
|
||||||
|
|
||||||
|
delete actualLocale;
|
||||||
|
actualLocale = nullptr;
|
||||||
|
delete validLocale;
|
||||||
|
validLocale = nullptr;
|
||||||
disposeZoneStrings();
|
disposeZoneStrings();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2302,7 +2307,7 @@ DateFormatSymbols::initializeData(const Locale& locale, const char *type, UError
|
|||||||
// of it that we need except for the time-zone and localized-pattern data, which
|
// of it that we need except for the time-zone and localized-pattern data, which
|
||||||
// are stored in a separate file
|
// are stored in a separate file
|
||||||
locBased.setLocaleIDs(ures_getLocaleByType(cb.getAlias(), ULOC_VALID_LOCALE, &status),
|
locBased.setLocaleIDs(ures_getLocaleByType(cb.getAlias(), ULOC_VALID_LOCALE, &status),
|
||||||
ures_getLocaleByType(cb.getAlias(), ULOC_ACTUAL_LOCALE, &status));
|
ures_getLocaleByType(cb.getAlias(), ULOC_ACTUAL_LOCALE, &status), status);
|
||||||
|
|
||||||
// Load eras
|
// Load eras
|
||||||
initField(&fEras, fErasCount, calendarSink, buildResourcePath(path, gErasTag, gNamesAbbrTag, status), status);
|
initField(&fEras, fErasCount, calendarSink, buildResourcePath(path, gErasTag, gNamesAbbrTag, status), status);
|
||||||
@ -2528,8 +2533,7 @@ DateFormatSymbols::initializeData(const Locale& locale, const char *type, UError
|
|||||||
|
|
||||||
Locale
|
Locale
|
||||||
DateFormatSymbols::getLocale(ULocDataLocaleType type, UErrorCode& status) const {
|
DateFormatSymbols::getLocale(ULocDataLocaleType type, UErrorCode& status) const {
|
||||||
U_LOCALE_BASED(locBased, *this);
|
return LocaleBased::getLocale(validLocale, actualLocale, type, status);
|
||||||
return locBased.getLocale(type, status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
U_NAMESPACE_END
|
U_NAMESPACE_END
|
||||||
|
5
deps/icu-small/source/i18n/erarules.cpp
vendored
5
deps/icu-small/source/i18n/erarules.cpp
vendored
@ -305,8 +305,9 @@ void EraRules::initCurrentEra() {
|
|||||||
localMillis += (rawOffset + dstOffset);
|
localMillis += (rawOffset + dstOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
int year, month0, dom, dow, doy, mid;
|
int32_t year, mid;
|
||||||
Grego::timeToFields(localMillis, year, month0, dom, dow, doy, mid, ec);
|
int8_t month0, dom;
|
||||||
|
Grego::timeToFields(localMillis, year, month0, dom, mid, ec);
|
||||||
if (U_FAILURE(ec)) return;
|
if (U_FAILURE(ec)) return;
|
||||||
int currentEncodedDate = encodeDate(year, month0 + 1 /* changes to 1-base */, dom);
|
int currentEncodedDate = encodeDate(year, month0 + 1 /* changes to 1-base */, dom);
|
||||||
int eraIdx = numEras - 1;
|
int eraIdx = numEras - 1;
|
||||||
|
20
deps/icu-small/source/i18n/format.cpp
vendored
20
deps/icu-small/source/i18n/format.cpp
vendored
@ -24,6 +24,7 @@
|
|||||||
#include "utypeinfo.h" // for 'typeid' to work
|
#include "utypeinfo.h" // for 'typeid' to work
|
||||||
|
|
||||||
#include "unicode/utypes.h"
|
#include "unicode/utypes.h"
|
||||||
|
#include "charstr.h"
|
||||||
|
|
||||||
#ifndef U_I18N_IMPLEMENTATION
|
#ifndef U_I18N_IMPLEMENTATION
|
||||||
#error U_I18N_IMPLEMENTATION not set - must be set for all ICU source files in i18n/ - see https://unicode-org.github.io/icu/userguide/howtouseicu
|
#error U_I18N_IMPLEMENTATION not set - must be set for all ICU source files in i18n/ - see https://unicode-org.github.io/icu/userguide/howtouseicu
|
||||||
@ -72,13 +73,14 @@ FieldPosition::clone() const {
|
|||||||
Format::Format()
|
Format::Format()
|
||||||
: UObject()
|
: UObject()
|
||||||
{
|
{
|
||||||
*validLocale = *actualLocale = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------
|
// -------------------------------------
|
||||||
|
|
||||||
Format::~Format()
|
Format::~Format()
|
||||||
{
|
{
|
||||||
|
delete actualLocale;
|
||||||
|
delete validLocale;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------
|
// -------------------------------------
|
||||||
@ -97,8 +99,10 @@ Format&
|
|||||||
Format::operator=(const Format& that)
|
Format::operator=(const Format& that)
|
||||||
{
|
{
|
||||||
if (this != &that) {
|
if (this != &that) {
|
||||||
uprv_strcpy(validLocale, that.validLocale);
|
UErrorCode status = U_ZERO_ERROR;
|
||||||
uprv_strcpy(actualLocale, that.actualLocale);
|
U_LOCALE_BASED(locBased, *this);
|
||||||
|
locBased.setLocaleIDs(that.validLocale, that.actualLocale, status);
|
||||||
|
U_ASSERT(U_SUCCESS(status));
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -196,20 +200,20 @@ void Format::syntaxError(const UnicodeString& pattern,
|
|||||||
|
|
||||||
Locale
|
Locale
|
||||||
Format::getLocale(ULocDataLocaleType type, UErrorCode& status) const {
|
Format::getLocale(ULocDataLocaleType type, UErrorCode& status) const {
|
||||||
U_LOCALE_BASED(locBased, *this);
|
return LocaleBased::getLocale(validLocale, actualLocale, type, status);
|
||||||
return locBased.getLocale(type, status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
Format::getLocaleID(ULocDataLocaleType type, UErrorCode& status) const {
|
Format::getLocaleID(ULocDataLocaleType type, UErrorCode& status) const {
|
||||||
U_LOCALE_BASED(locBased, *this);
|
return LocaleBased::getLocaleID(validLocale,actualLocale, type, status);
|
||||||
return locBased.getLocaleID(type, status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Format::setLocaleIDs(const char* valid, const char* actual) {
|
Format::setLocaleIDs(const char* valid, const char* actual) {
|
||||||
U_LOCALE_BASED(locBased, *this);
|
U_LOCALE_BASED(locBased, *this);
|
||||||
locBased.setLocaleIDs(valid, actual);
|
UErrorCode status = U_ZERO_ERROR;
|
||||||
|
locBased.setLocaleIDs(valid, actual, status);
|
||||||
|
U_ASSERT(U_SUCCESS(status));
|
||||||
}
|
}
|
||||||
|
|
||||||
U_NAMESPACE_END
|
U_NAMESPACE_END
|
||||||
|
@ -193,6 +193,11 @@ ucfpos_close(UConstrainedFieldPosition* ptr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// -Wreturn-local-addr first found in https://gcc.gnu.org/onlinedocs/gcc-4.8.5/gcc/Warning-Options.html#Warning-Options
|
||||||
|
#if U_GCC_MAJOR_MINOR >= 409
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wreturn-local-addr"
|
||||||
|
#endif
|
||||||
U_CAPI const char16_t* U_EXPORT2
|
U_CAPI const char16_t* U_EXPORT2
|
||||||
ufmtval_getString(
|
ufmtval_getString(
|
||||||
const UFormattedValue* ufmtval,
|
const UFormattedValue* ufmtval,
|
||||||
@ -213,6 +218,9 @@ ufmtval_getString(
|
|||||||
// defined to return memory owned by the ufmtval argument.
|
// defined to return memory owned by the ufmtval argument.
|
||||||
return readOnlyAlias.getBuffer();
|
return readOnlyAlias.getBuffer();
|
||||||
}
|
}
|
||||||
|
#if U_GCC_MAJOR_MINOR >= 409
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
U_CAPI UBool U_EXPORT2
|
U_CAPI UBool U_EXPORT2
|
||||||
|
66
deps/icu-small/source/i18n/gregocal.cpp
vendored
66
deps/icu-small/source/i18n/gregocal.cpp
vendored
@ -147,6 +147,7 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(GregorianCalendar)
|
|||||||
// in Java, -12219292800000L
|
// in Java, -12219292800000L
|
||||||
//const UDate GregorianCalendar::kPapalCutover = -12219292800000L;
|
//const UDate GregorianCalendar::kPapalCutover = -12219292800000L;
|
||||||
static const uint32_t kCutoverJulianDay = 2299161;
|
static const uint32_t kCutoverJulianDay = 2299161;
|
||||||
|
static const int32_t kDefaultCutoverYear = 1582;
|
||||||
static const UDate kPapalCutover = (2299161.0 - kEpochStartAsJulianDay) * U_MILLIS_PER_DAY;
|
static const UDate kPapalCutover = (2299161.0 - kEpochStartAsJulianDay) * U_MILLIS_PER_DAY;
|
||||||
//static const UDate kPapalCutoverJulian = (2299161.0 - kEpochStartAsJulianDay);
|
//static const UDate kPapalCutoverJulian = (2299161.0 - kEpochStartAsJulianDay);
|
||||||
|
|
||||||
@ -155,7 +156,7 @@ static const UDate kPapalCutover = (2299161.0 - kEpochStartAsJulianDay) * U_MILL
|
|||||||
GregorianCalendar::GregorianCalendar(UErrorCode& status)
|
GregorianCalendar::GregorianCalendar(UErrorCode& status)
|
||||||
: Calendar(status),
|
: Calendar(status),
|
||||||
fGregorianCutover(kPapalCutover),
|
fGregorianCutover(kPapalCutover),
|
||||||
fCutoverJulianDay(kCutoverJulianDay), fNormalizedGregorianCutover(fGregorianCutover), fGregorianCutoverYear(1582),
|
fCutoverJulianDay(kCutoverJulianDay), fNormalizedGregorianCutover(fGregorianCutover), fGregorianCutoverYear(kDefaultCutoverYear),
|
||||||
fIsGregorian(true), fInvertGregorian(false)
|
fIsGregorian(true), fInvertGregorian(false)
|
||||||
{
|
{
|
||||||
setTimeInMillis(getNow(), status);
|
setTimeInMillis(getNow(), status);
|
||||||
@ -164,34 +165,22 @@ fIsGregorian(true), fInvertGregorian(false)
|
|||||||
// -------------------------------------
|
// -------------------------------------
|
||||||
|
|
||||||
GregorianCalendar::GregorianCalendar(TimeZone* zone, UErrorCode& status)
|
GregorianCalendar::GregorianCalendar(TimeZone* zone, UErrorCode& status)
|
||||||
: Calendar(zone, Locale::getDefault(), status),
|
: GregorianCalendar(zone, Locale::getDefault(), status)
|
||||||
fGregorianCutover(kPapalCutover),
|
|
||||||
fCutoverJulianDay(kCutoverJulianDay), fNormalizedGregorianCutover(fGregorianCutover), fGregorianCutoverYear(1582),
|
|
||||||
fIsGregorian(true), fInvertGregorian(false)
|
|
||||||
{
|
{
|
||||||
setTimeInMillis(getNow(), status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------
|
// -------------------------------------
|
||||||
|
|
||||||
GregorianCalendar::GregorianCalendar(const TimeZone& zone, UErrorCode& status)
|
GregorianCalendar::GregorianCalendar(const TimeZone& zone, UErrorCode& status)
|
||||||
: Calendar(zone, Locale::getDefault(), status),
|
: GregorianCalendar(zone, Locale::getDefault(), status)
|
||||||
fGregorianCutover(kPapalCutover),
|
|
||||||
fCutoverJulianDay(kCutoverJulianDay), fNormalizedGregorianCutover(fGregorianCutover), fGregorianCutoverYear(1582),
|
|
||||||
fIsGregorian(true), fInvertGregorian(false)
|
|
||||||
{
|
{
|
||||||
setTimeInMillis(getNow(), status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------
|
// -------------------------------------
|
||||||
|
|
||||||
GregorianCalendar::GregorianCalendar(const Locale& aLocale, UErrorCode& status)
|
GregorianCalendar::GregorianCalendar(const Locale& aLocale, UErrorCode& status)
|
||||||
: Calendar(TimeZone::forLocaleOrDefault(aLocale), aLocale, status),
|
: GregorianCalendar(TimeZone::forLocaleOrDefault(aLocale), aLocale, status)
|
||||||
fGregorianCutover(kPapalCutover),
|
|
||||||
fCutoverJulianDay(kCutoverJulianDay), fNormalizedGregorianCutover(fGregorianCutover), fGregorianCutoverYear(1582),
|
|
||||||
fIsGregorian(true), fInvertGregorian(false)
|
|
||||||
{
|
{
|
||||||
setTimeInMillis(getNow(), status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------
|
// -------------------------------------
|
||||||
@ -200,7 +189,7 @@ GregorianCalendar::GregorianCalendar(TimeZone* zone, const Locale& aLocale,
|
|||||||
UErrorCode& status)
|
UErrorCode& status)
|
||||||
: Calendar(zone, aLocale, status),
|
: Calendar(zone, aLocale, status),
|
||||||
fGregorianCutover(kPapalCutover),
|
fGregorianCutover(kPapalCutover),
|
||||||
fCutoverJulianDay(kCutoverJulianDay), fNormalizedGregorianCutover(fGregorianCutover), fGregorianCutoverYear(1582),
|
fCutoverJulianDay(kCutoverJulianDay), fNormalizedGregorianCutover(fGregorianCutover), fGregorianCutoverYear(kDefaultCutoverYear),
|
||||||
fIsGregorian(true), fInvertGregorian(false)
|
fIsGregorian(true), fInvertGregorian(false)
|
||||||
{
|
{
|
||||||
setTimeInMillis(getNow(), status);
|
setTimeInMillis(getNow(), status);
|
||||||
@ -212,7 +201,7 @@ GregorianCalendar::GregorianCalendar(const TimeZone& zone, const Locale& aLocale
|
|||||||
UErrorCode& status)
|
UErrorCode& status)
|
||||||
: Calendar(zone, aLocale, status),
|
: Calendar(zone, aLocale, status),
|
||||||
fGregorianCutover(kPapalCutover),
|
fGregorianCutover(kPapalCutover),
|
||||||
fCutoverJulianDay(kCutoverJulianDay), fNormalizedGregorianCutover(fGregorianCutover), fGregorianCutoverYear(1582),
|
fCutoverJulianDay(kCutoverJulianDay), fNormalizedGregorianCutover(fGregorianCutover), fGregorianCutoverYear(kDefaultCutoverYear),
|
||||||
fIsGregorian(true), fInvertGregorian(false)
|
fIsGregorian(true), fInvertGregorian(false)
|
||||||
{
|
{
|
||||||
setTimeInMillis(getNow(), status);
|
setTimeInMillis(getNow(), status);
|
||||||
@ -224,7 +213,7 @@ GregorianCalendar::GregorianCalendar(int32_t year, int32_t month, int32_t date,
|
|||||||
UErrorCode& status)
|
UErrorCode& status)
|
||||||
: Calendar(TimeZone::createDefault(), Locale::getDefault(), status),
|
: Calendar(TimeZone::createDefault(), Locale::getDefault(), status),
|
||||||
fGregorianCutover(kPapalCutover),
|
fGregorianCutover(kPapalCutover),
|
||||||
fCutoverJulianDay(kCutoverJulianDay), fNormalizedGregorianCutover(fGregorianCutover), fGregorianCutoverYear(1582),
|
fCutoverJulianDay(kCutoverJulianDay), fNormalizedGregorianCutover(fGregorianCutover), fGregorianCutoverYear(kDefaultCutoverYear),
|
||||||
fIsGregorian(true), fInvertGregorian(false)
|
fIsGregorian(true), fInvertGregorian(false)
|
||||||
{
|
{
|
||||||
set(UCAL_ERA, AD);
|
set(UCAL_ERA, AD);
|
||||||
@ -237,15 +226,8 @@ GregorianCalendar::GregorianCalendar(int32_t year, int32_t month, int32_t date,
|
|||||||
|
|
||||||
GregorianCalendar::GregorianCalendar(int32_t year, int32_t month, int32_t date,
|
GregorianCalendar::GregorianCalendar(int32_t year, int32_t month, int32_t date,
|
||||||
int32_t hour, int32_t minute, UErrorCode& status)
|
int32_t hour, int32_t minute, UErrorCode& status)
|
||||||
: Calendar(TimeZone::createDefault(), Locale::getDefault(), status),
|
: GregorianCalendar(year, month, date, status)
|
||||||
fGregorianCutover(kPapalCutover),
|
|
||||||
fCutoverJulianDay(kCutoverJulianDay), fNormalizedGregorianCutover(fGregorianCutover), fGregorianCutoverYear(1582),
|
|
||||||
fIsGregorian(true), fInvertGregorian(false)
|
|
||||||
{
|
{
|
||||||
set(UCAL_ERA, AD);
|
|
||||||
set(UCAL_YEAR, year);
|
|
||||||
set(UCAL_MONTH, month);
|
|
||||||
set(UCAL_DATE, date);
|
|
||||||
set(UCAL_HOUR_OF_DAY, hour);
|
set(UCAL_HOUR_OF_DAY, hour);
|
||||||
set(UCAL_MINUTE, minute);
|
set(UCAL_MINUTE, minute);
|
||||||
}
|
}
|
||||||
@ -255,17 +237,8 @@ GregorianCalendar::GregorianCalendar(int32_t year, int32_t month, int32_t date,
|
|||||||
GregorianCalendar::GregorianCalendar(int32_t year, int32_t month, int32_t date,
|
GregorianCalendar::GregorianCalendar(int32_t year, int32_t month, int32_t date,
|
||||||
int32_t hour, int32_t minute, int32_t second,
|
int32_t hour, int32_t minute, int32_t second,
|
||||||
UErrorCode& status)
|
UErrorCode& status)
|
||||||
: Calendar(TimeZone::createDefault(), Locale::getDefault(), status),
|
: GregorianCalendar(year, month, date, hour, minute, status)
|
||||||
fGregorianCutover(kPapalCutover),
|
|
||||||
fCutoverJulianDay(kCutoverJulianDay), fNormalizedGregorianCutover(fGregorianCutover), fGregorianCutoverYear(1582),
|
|
||||||
fIsGregorian(true), fInvertGregorian(false)
|
|
||||||
{
|
{
|
||||||
set(UCAL_ERA, AD);
|
|
||||||
set(UCAL_YEAR, year);
|
|
||||||
set(UCAL_MONTH, month);
|
|
||||||
set(UCAL_DATE, date);
|
|
||||||
set(UCAL_HOUR_OF_DAY, hour);
|
|
||||||
set(UCAL_MINUTE, minute);
|
|
||||||
set(UCAL_SECOND, second);
|
set(UCAL_SECOND, second);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -601,7 +574,8 @@ int32_t GregorianCalendar::handleGetMonthLength(int32_t extendedYear, int32_t mo
|
|||||||
return isLeapYear(extendedYear) ? kLeapMonthLength[month] : kMonthLength[month];
|
return isLeapYear(extendedYear) ? kLeapMonthLength[month] : kMonthLength[month];
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t GregorianCalendar::handleGetYearLength(int32_t eyear) const {
|
int32_t GregorianCalendar::handleGetYearLength(int32_t eyear, UErrorCode& status) const {
|
||||||
|
if (U_FAILURE(status)) return 0;
|
||||||
return isLeapYear(eyear) ? 366 : 365;
|
return isLeapYear(eyear) ? 366 : 365;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -871,13 +845,14 @@ GregorianCalendar::roll(UCalendarDateFields field, int32_t amount, UErrorCode& s
|
|||||||
}
|
}
|
||||||
if (month == UCAL_JANUARY) {
|
if (month == UCAL_JANUARY) {
|
||||||
if (woy >= 52) {
|
if (woy >= 52) {
|
||||||
isoDoy += handleGetYearLength(isoYear);
|
isoDoy += handleGetYearLength(isoYear, status);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (woy == 1) {
|
if (woy == 1) {
|
||||||
isoDoy -= handleGetYearLength(isoYear - 1);
|
isoDoy -= handleGetYearLength(isoYear - 1, status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (U_FAILURE(status)) return;
|
||||||
if (uprv_add32_overflow(woy, amount, &woy)) {
|
if (uprv_add32_overflow(woy, amount, &woy)) {
|
||||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||||
return;
|
return;
|
||||||
@ -890,7 +865,8 @@ GregorianCalendar::roll(UCalendarDateFields field, int32_t amount, UErrorCode& s
|
|||||||
// days at the end of the year are going to fall into
|
// days at the end of the year are going to fall into
|
||||||
// week 1 of the next year, we drop the last week by
|
// week 1 of the next year, we drop the last week by
|
||||||
// subtracting 7 from the last day of the year.
|
// subtracting 7 from the last day of the year.
|
||||||
int32_t lastDoy = handleGetYearLength(isoYear);
|
int32_t lastDoy = handleGetYearLength(isoYear, status);
|
||||||
|
if (U_FAILURE(status)) return;
|
||||||
int32_t lastRelDow = (lastDoy - isoDoy + internalGet(UCAL_DAY_OF_WEEK) -
|
int32_t lastRelDow = (lastDoy - isoDoy + internalGet(UCAL_DAY_OF_WEEK) -
|
||||||
getFirstDayOfWeek()) % 7;
|
getFirstDayOfWeek()) % 7;
|
||||||
if (lastRelDow < 0) lastRelDow += 7;
|
if (lastRelDow < 0) lastRelDow += 7;
|
||||||
@ -1186,14 +1162,10 @@ int32_t GregorianCalendar::handleGetExtendedYear(UErrorCode& status) {
|
|||||||
int32_t year = kEpochYear;
|
int32_t year = kEpochYear;
|
||||||
|
|
||||||
// year field to use
|
// year field to use
|
||||||
int32_t yearField = UCAL_EXTENDED_YEAR;
|
|
||||||
|
|
||||||
// There are three separate fields which could be used to
|
// There are three separate fields which could be used to
|
||||||
// derive the proper year. Use the one most recently set.
|
// derive the proper year. Use the one most recently set.
|
||||||
if (fStamp[yearField] < fStamp[UCAL_YEAR])
|
UCalendarDateFields yearField = newerField(
|
||||||
yearField = UCAL_YEAR;
|
newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR), UCAL_YEAR_WOY);
|
||||||
if (fStamp[yearField] < fStamp[UCAL_YEAR_WOY])
|
|
||||||
yearField = UCAL_YEAR_WOY;
|
|
||||||
|
|
||||||
// based on the "best" year field, get the year
|
// based on the "best" year field, get the year
|
||||||
switch(yearField) {
|
switch(yearField) {
|
||||||
|
111
deps/icu-small/source/i18n/gregoimp.cpp
vendored
111
deps/icu-small/source/i18n/gregoimp.cpp
vendored
@ -117,57 +117,110 @@ int64_t Grego::fieldsToDay(int32_t year, int32_t month, int32_t dom) {
|
|||||||
return julian - JULIAN_1970_CE; // JD => epoch day
|
return julian - JULIAN_1970_CE; // JD => epoch day
|
||||||
}
|
}
|
||||||
|
|
||||||
void Grego::dayToFields(int32_t day, int32_t& year, int32_t& month,
|
void Grego::dayToFields(int32_t day, int32_t& year, int8_t& month,
|
||||||
int32_t& dom, int32_t& dow, int32_t& doy, UErrorCode& status) {
|
int8_t& dom, int8_t& dow, int16_t& doy, UErrorCode& status) {
|
||||||
|
year = dayToYear(day, doy, status); // one-based doy
|
||||||
if (U_FAILURE(status)) return;
|
if (U_FAILURE(status)) return;
|
||||||
|
|
||||||
// Convert from 1970 CE epoch to 1 CE epoch (Gregorian calendar)
|
// Convert from 1970 CE epoch to 1 CE epoch (Gregorian calendar)
|
||||||
if (uprv_add32_overflow(day, JULIAN_1970_CE - JULIAN_1_CE, &day)) {
|
if (uprv_add32_overflow(day, JULIAN_1970_CE - JULIAN_1_CE, &day)) {
|
||||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert from the day number to the multiple radix
|
|
||||||
// representation. We use 400-year, 100-year, and 4-year cycles.
|
|
||||||
// For example, the 4-year cycle has 4 years + 1 leap day; giving
|
|
||||||
// 1461 == 365*4 + 1 days.
|
|
||||||
int32_t n400 = ClockMath::floorDivide(day, 146097, &doy); // 400-year cycle length
|
|
||||||
int32_t n100 = ClockMath::floorDivide(doy, 36524, &doy); // 100-year cycle length
|
|
||||||
int32_t n4 = ClockMath::floorDivide(doy, 1461, &doy); // 4-year cycle length
|
|
||||||
int32_t n1 = ClockMath::floorDivide(doy, 365, &doy);
|
|
||||||
year = 400*n400 + 100*n100 + 4*n4 + n1;
|
|
||||||
if (n100 == 4 || n1 == 4) {
|
|
||||||
doy = 365; // Dec 31 at end of 4- or 400-year cycle
|
|
||||||
} else {
|
|
||||||
++year;
|
|
||||||
}
|
|
||||||
|
|
||||||
UBool isLeap = isLeapYear(year);
|
|
||||||
|
|
||||||
// Gregorian day zero is a Monday.
|
// Gregorian day zero is a Monday.
|
||||||
dow = (day + 1) % 7;
|
dow = (day + 1) % 7;
|
||||||
dow += (dow < 0) ? (UCAL_SUNDAY + 7) : UCAL_SUNDAY;
|
dow += (dow < 0) ? (UCAL_SUNDAY + 7) : UCAL_SUNDAY;
|
||||||
|
|
||||||
// Common Julian/Gregorian calculation
|
// Common Julian/Gregorian calculation
|
||||||
int32_t correction = 0;
|
int32_t correction = 0;
|
||||||
|
bool isLeap = isLeapYear(year);
|
||||||
int32_t march1 = isLeap ? 60 : 59; // zero-based DOY for March 1
|
int32_t march1 = isLeap ? 60 : 59; // zero-based DOY for March 1
|
||||||
if (doy >= march1) {
|
if (doy > march1) {
|
||||||
correction = isLeap ? 1 : 2;
|
correction = isLeap ? 1 : 2;
|
||||||
}
|
}
|
||||||
month = (12 * (doy + correction) + 6) / 367; // zero-based month
|
month = (12 * (doy - 1 + correction) + 6) / 367; // zero-based month
|
||||||
dom = doy - DAYS_BEFORE[month + (isLeap ? 12 : 0)] + 1; // one-based DOM
|
dom = doy - DAYS_BEFORE[month + (isLeap ? 12 : 0)]; // one-based DOM
|
||||||
doy++; // one-based doy
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Grego::timeToFields(UDate time, int32_t& year, int32_t& month,
|
int32_t Grego::dayToYear(int32_t day, UErrorCode& status) {
|
||||||
int32_t& dom, int32_t& dow, int32_t& doy, int32_t& mid, UErrorCode& status) {
|
int16_t unusedDOY;
|
||||||
|
return dayToYear(day, unusedDOY, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t Grego::dayToYear(int32_t day, int16_t& doy, UErrorCode& status) {
|
||||||
|
if (U_FAILURE(status)) return 0;
|
||||||
|
// Convert from 1970 CE epoch to 1 CE epoch (Gregorian calendar)
|
||||||
|
if (uprv_add32_overflow(day, JULIAN_1970_CE - JULIAN_1_CE, &day)) {
|
||||||
|
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert from the day number to the multiple radix
|
||||||
|
// representation. We use 400-year, 100-year, and 4-year cycles.
|
||||||
|
// For example, the 4-year cycle has 4 years + 1 leap day; giving
|
||||||
|
// 1461 == 365*4 + 1 days.
|
||||||
|
int32_t doy32;
|
||||||
|
int32_t n400 = ClockMath::floorDivide(day, 146097, &doy32); // 400-year cycle length
|
||||||
|
int32_t n100 = ClockMath::floorDivide(doy32, 36524, &doy32); // 100-year cycle length
|
||||||
|
int32_t n4 = ClockMath::floorDivide(doy32, 1461, &doy32); // 4-year cycle length
|
||||||
|
int32_t n1 = ClockMath::floorDivide(doy32, 365, &doy32);
|
||||||
|
int32_t year = 400*n400 + 100*n100 + 4*n4 + n1;
|
||||||
|
if (n100 == 4 || n1 == 4) {
|
||||||
|
doy = 365; // Dec 31 at end of 4- or 400-year cycle
|
||||||
|
} else {
|
||||||
|
doy = doy32;
|
||||||
|
++year;
|
||||||
|
}
|
||||||
|
doy++; // one-based doy
|
||||||
|
return year;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Grego::dayToFields(int32_t day, int32_t& year, int8_t& month,
|
||||||
|
int8_t& dom, int8_t& dow, UErrorCode& status) {
|
||||||
|
int16_t unusedDOY;
|
||||||
|
dayToFields(day, year, month, dom, dow, unusedDOY, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Grego::dayToFields(int32_t day, int32_t& year, int8_t& month,
|
||||||
|
int8_t& dom, int16_t& doy, UErrorCode& status) {
|
||||||
|
int8_t unusedDOW;
|
||||||
|
dayToFields(day, year, month, dom, unusedDOW, doy, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Grego::timeToFields(UDate time, int32_t& year, int8_t& month,
|
||||||
|
int8_t& dom, int32_t& mid, UErrorCode& status) {
|
||||||
|
int8_t unusedDOW;
|
||||||
|
timeToFields(time, year, month, dom, unusedDOW, mid, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Grego::timeToFields(UDate time, int32_t& year, int8_t& month,
|
||||||
|
int8_t& dom, int8_t& dow, int32_t& mid, UErrorCode& status) {
|
||||||
|
int16_t unusedDOY;
|
||||||
|
timeToFields(time, year, month, dom, dow, unusedDOY, mid, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Grego::timeToFields(UDate time, int32_t& year, int8_t& month,
|
||||||
|
int8_t& dom, int8_t& dow, int16_t& doy, int32_t& mid, UErrorCode& status) {
|
||||||
if (U_FAILURE(status)) return;
|
if (U_FAILURE(status)) return;
|
||||||
double millisInDay;
|
double day = ClockMath::floorDivide(time, U_MILLIS_PER_DAY, &mid);
|
||||||
double day = ClockMath::floorDivide(static_cast<double>(time), static_cast<double>(U_MILLIS_PER_DAY), &millisInDay);
|
if (day > INT32_MAX || day < INT32_MIN) {
|
||||||
mid = static_cast<int32_t>(millisInDay);
|
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
dayToFields(day, year, month, dom, dow, doy, status);
|
dayToFields(day, year, month, dom, dow, doy, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t Grego::timeToYear(UDate time, UErrorCode& status) {
|
||||||
|
if (U_FAILURE(status)) return 0;
|
||||||
|
double day = ClockMath::floorDivide(time, double(U_MILLIS_PER_DAY));
|
||||||
|
if (day > INT32_MAX || day < INT32_MIN) {
|
||||||
|
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return Grego::dayToYear(day, status);
|
||||||
|
}
|
||||||
|
|
||||||
int32_t Grego::dayOfWeek(int32_t day) {
|
int32_t Grego::dayOfWeek(int32_t day) {
|
||||||
int32_t dow;
|
int32_t dow;
|
||||||
ClockMath::floorDivide(day + int{UCAL_THURSDAY}, 7, &dow);
|
ClockMath::floorDivide(day + int{UCAL_THURSDAY}, 7, &dow);
|
||||||
|
82
deps/icu-small/source/i18n/gregoimp.h
vendored
82
deps/icu-small/source/i18n/gregoimp.h
vendored
@ -210,8 +210,21 @@ class Grego {
|
|||||||
* @param doy output parameter to receive day-of-year (1-based)
|
* @param doy output parameter to receive day-of-year (1-based)
|
||||||
* @param status error code.
|
* @param status error code.
|
||||||
*/
|
*/
|
||||||
static void dayToFields(int32_t day, int32_t& year, int32_t& month,
|
static void dayToFields(int32_t day, int32_t& year, int8_t& month,
|
||||||
int32_t& dom, int32_t& dow, int32_t& doy, UErrorCode& status);
|
int8_t& dom, int8_t& dow, int16_t& doy, UErrorCode& status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a 1970-epoch day number to proleptic Gregorian year,
|
||||||
|
* month, day-of-month, and day-of-week.
|
||||||
|
* @param day 1970-epoch day
|
||||||
|
* @param year output parameter to receive year
|
||||||
|
* @param month output parameter to receive month (0-based, 0==Jan)
|
||||||
|
* @param dom output parameter to receive day-of-month (1-based)
|
||||||
|
* @param doy output parameter to receive day-of-year (1-based)
|
||||||
|
* @param status error code.
|
||||||
|
*/
|
||||||
|
static void dayToFields(int32_t day, int32_t& year, int8_t& month,
|
||||||
|
int8_t& dom, int16_t& doy, UErrorCode& status);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a 1970-epoch day number to proleptic Gregorian year,
|
* Convert a 1970-epoch day number to proleptic Gregorian year,
|
||||||
@ -223,8 +236,24 @@ class Grego {
|
|||||||
* @param dow output parameter to receive day-of-week (1-based, 1==Sun)
|
* @param dow output parameter to receive day-of-week (1-based, 1==Sun)
|
||||||
* @param status error code.
|
* @param status error code.
|
||||||
*/
|
*/
|
||||||
static inline void dayToFields(int32_t day, int32_t& year, int32_t& month,
|
static void dayToFields(int32_t day, int32_t& year, int8_t& month,
|
||||||
int32_t& dom, int32_t& dow, UErrorCode& status);
|
int8_t& dom, int8_t& dow, UErrorCode& status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a 1970-epoch day number to proleptic Gregorian year.
|
||||||
|
* @param day 1970-epoch day
|
||||||
|
* @param status error code.
|
||||||
|
* @return year.
|
||||||
|
*/
|
||||||
|
static int32_t dayToYear(int32_t day, UErrorCode& status);
|
||||||
|
/**
|
||||||
|
* Convert a 1970-epoch day number to proleptic Gregorian year.
|
||||||
|
* @param day 1970-epoch day
|
||||||
|
* @param doy output parameter to receive day-of-year (1-based)
|
||||||
|
* @param status error code.
|
||||||
|
* @return year.
|
||||||
|
*/
|
||||||
|
static int32_t dayToYear(int32_t day, int16_t& doy, UErrorCode& status);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a 1970-epoch milliseconds to proleptic Gregorian year,
|
* Convert a 1970-epoch milliseconds to proleptic Gregorian year,
|
||||||
@ -238,8 +267,43 @@ class Grego {
|
|||||||
* @param mid output parameter to receive millis-in-day
|
* @param mid output parameter to receive millis-in-day
|
||||||
* @param status error code.
|
* @param status error code.
|
||||||
*/
|
*/
|
||||||
static void timeToFields(UDate time, int32_t& year, int32_t& month,
|
static void timeToFields(UDate time, int32_t& year, int8_t& month,
|
||||||
int32_t& dom, int32_t& dow, int32_t& doy, int32_t& mid, UErrorCode& status);
|
int8_t& dom, int8_t& dow, int16_t& doy, int32_t& mid, UErrorCode& status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a 1970-epoch milliseconds to proleptic Gregorian year,
|
||||||
|
* month, day-of-month, and day-of-week, day of year and millis-in-day.
|
||||||
|
* @param time 1970-epoch milliseconds
|
||||||
|
* @param year output parameter to receive year
|
||||||
|
* @param month output parameter to receive month (0-based, 0==Jan)
|
||||||
|
* @param dom output parameter to receive day-of-month (1-based)
|
||||||
|
* @param dow output parameter to receive day-of-week (1-based, 1==Sun)
|
||||||
|
* @param mid output parameter to receive millis-in-day
|
||||||
|
* @param status error code.
|
||||||
|
*/
|
||||||
|
static void timeToFields(UDate time, int32_t& year, int8_t& month,
|
||||||
|
int8_t& dom, int8_t& dow, int32_t& mid, UErrorCode& status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a 1970-epoch milliseconds to proleptic Gregorian year,
|
||||||
|
* month, day-of-month, and day-of-week, day of year and millis-in-day.
|
||||||
|
* @param time 1970-epoch milliseconds
|
||||||
|
* @param year output parameter to receive year
|
||||||
|
* @param month output parameter to receive month (0-based, 0==Jan)
|
||||||
|
* @param dom output parameter to receive day-of-month (1-based)
|
||||||
|
* @param mid output parameter to receive millis-in-day
|
||||||
|
* @param status error code.
|
||||||
|
*/
|
||||||
|
static void timeToFields(UDate time, int32_t& year, int8_t& month,
|
||||||
|
int8_t& dom, int32_t& mid, UErrorCode& status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a 1970-epoch milliseconds to proleptic Gregorian year.
|
||||||
|
* @param time 1970-epoch milliseconds
|
||||||
|
* @param status error code.
|
||||||
|
* @return year.
|
||||||
|
*/
|
||||||
|
static int32_t timeToYear(UDate time, UErrorCode& status);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the day of week on the 1970-epoch day
|
* Return the day of week on the 1970-epoch day
|
||||||
@ -305,12 +369,6 @@ Grego::previousMonthLength(int y, int m) {
|
|||||||
return (m > 0) ? monthLength(y, m-1) : 31;
|
return (m > 0) ? monthLength(y, m-1) : 31;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Grego::dayToFields(int32_t day, int32_t& year, int32_t& month,
|
|
||||||
int32_t& dom, int32_t& dow, UErrorCode& status) {
|
|
||||||
int32_t doy_unused;
|
|
||||||
dayToFields(day,year,month,dom,dow,doy_unused, status);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline double Grego::julianDayToMillis(int32_t julian)
|
inline double Grego::julianDayToMillis(int32_t julian)
|
||||||
{
|
{
|
||||||
return (static_cast<double>(julian) - kEpochStartAsJulianDay) * kOneDay;
|
return (static_cast<double>(julian) - kEpochStartAsJulianDay) * kOneDay;
|
||||||
|
10
deps/icu-small/source/i18n/hebrwcal.cpp
vendored
10
deps/icu-small/source/i18n/hebrwcal.cpp
vendored
@ -164,7 +164,6 @@ HebrewCalendar::HebrewCalendar(const Locale& aLocale, UErrorCode& success)
|
|||||||
: Calendar(TimeZone::forLocaleOrDefault(aLocale), aLocale, success)
|
: Calendar(TimeZone::forLocaleOrDefault(aLocale), aLocale, success)
|
||||||
|
|
||||||
{
|
{
|
||||||
setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -591,13 +590,8 @@ int32_t HebrewCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month
|
|||||||
* Returns the number of days in the given Hebrew year
|
* Returns the number of days in the given Hebrew year
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
int32_t HebrewCalendar::handleGetYearLength(int32_t eyear) const {
|
int32_t HebrewCalendar::handleGetYearLength(int32_t eyear, UErrorCode& status) const {
|
||||||
UErrorCode status = U_ZERO_ERROR;
|
return daysInYear(eyear, status);
|
||||||
int32_t len = daysInYear(eyear, status);
|
|
||||||
if (U_FAILURE(status)) {
|
|
||||||
return 12;
|
|
||||||
}
|
|
||||||
return len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HebrewCalendar::validateField(UCalendarDateFields field, UErrorCode &status) {
|
void HebrewCalendar::validateField(UCalendarDateFields field, UErrorCode &status) {
|
||||||
|
4
deps/icu-small/source/i18n/hebrwcal.h
vendored
4
deps/icu-small/source/i18n/hebrwcal.h
vendored
@ -326,9 +326,9 @@ public:
|
|||||||
* calendar system. Subclasses should override this method if they can
|
* calendar system. Subclasses should override this method if they can
|
||||||
* provide a more correct or more efficient implementation than the
|
* provide a more correct or more efficient implementation than the
|
||||||
* default implementation in Calendar.
|
* default implementation in Calendar.
|
||||||
* @stable ICU 2.0
|
* @internal
|
||||||
*/
|
*/
|
||||||
virtual int32_t handleGetYearLength(int32_t eyear) const override;
|
virtual int32_t handleGetYearLength(int32_t eyear, UErrorCode& status) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subclasses may override this method to compute several fields
|
* Subclasses may override this method to compute several fields
|
||||||
|
21
deps/icu-small/source/i18n/indiancal.cpp
vendored
21
deps/icu-small/source/i18n/indiancal.cpp
vendored
@ -41,7 +41,6 @@ IndianCalendar* IndianCalendar::clone() const {
|
|||||||
IndianCalendar::IndianCalendar(const Locale& aLocale, UErrorCode& success)
|
IndianCalendar::IndianCalendar(const Locale& aLocale, UErrorCode& success)
|
||||||
: Calendar(TimeZone::forLocaleOrDefault(aLocale), aLocale, success)
|
: Calendar(TimeZone::forLocaleOrDefault(aLocale), aLocale, success)
|
||||||
{
|
{
|
||||||
setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IndianCalendar::IndianCalendar(const IndianCalendar& other) : Calendar(other) {
|
IndianCalendar::IndianCalendar(const IndianCalendar& other) : Calendar(other) {
|
||||||
@ -129,7 +128,8 @@ int32_t IndianCalendar::handleGetMonthLength(int32_t eyear, int32_t month, UErro
|
|||||||
*
|
*
|
||||||
* @param eyear The year in Saka Era.
|
* @param eyear The year in Saka Era.
|
||||||
*/
|
*/
|
||||||
int32_t IndianCalendar::handleGetYearLength(int32_t eyear) const {
|
int32_t IndianCalendar::handleGetYearLength(int32_t eyear, UErrorCode& status) const {
|
||||||
|
if (U_FAILURE(status)) return 0;
|
||||||
return isGregorianLeap(eyear + INDIAN_ERA_START) ? 366 : 365;
|
return isGregorianLeap(eyear + INDIAN_ERA_START) ? 366 : 365;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -143,18 +143,6 @@ static double gregorianToJD(int32_t year, int32_t month, int32_t date) {
|
|||||||
return Grego::fieldsToDay(year, month, date) + kEpochStartAsJulianDay - 0.5;
|
return Grego::fieldsToDay(year, month, date) + kEpochStartAsJulianDay - 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns the Gregorian Date corresponding to a given Julian Day
|
|
||||||
* Month is 0 based.
|
|
||||||
* @param jd The Julian Day
|
|
||||||
*/
|
|
||||||
static int32_t* jdToGregorian(double jd, int32_t gregorianDate[3], UErrorCode& status) {
|
|
||||||
int32_t gdow;
|
|
||||||
Grego::dayToFields(jd - kEpochStartAsJulianDay,
|
|
||||||
gregorianDate[0], gregorianDate[1], gregorianDate[2], gdow, status);
|
|
||||||
return gregorianDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
// Functions for converting from field values to milliseconds....
|
// Functions for converting from field values to milliseconds....
|
||||||
@ -266,10 +254,9 @@ int32_t IndianCalendar::handleGetExtendedYear(UErrorCode& status) {
|
|||||||
void IndianCalendar::handleComputeFields(int32_t julianDay, UErrorCode& status) {
|
void IndianCalendar::handleComputeFields(int32_t julianDay, UErrorCode& status) {
|
||||||
double jdAtStartOfGregYear;
|
double jdAtStartOfGregYear;
|
||||||
int32_t leapMonth, IndianYear, yday, IndianMonth, IndianDayOfMonth, mday;
|
int32_t leapMonth, IndianYear, yday, IndianMonth, IndianDayOfMonth, mday;
|
||||||
int32_t gregorianYear; // Stores gregorian date corresponding to Julian day;
|
// Stores gregorian date corresponding to Julian day;
|
||||||
int32_t gd[3];
|
int32_t gregorianYear = Grego::dayToYear(julianDay - kEpochStartAsJulianDay, status);
|
||||||
|
|
||||||
gregorianYear = jdToGregorian(julianDay, gd, status)[0]; // Gregorian date for Julian day
|
|
||||||
if (U_FAILURE(status)) return;
|
if (U_FAILURE(status)) return;
|
||||||
IndianYear = gregorianYear - INDIAN_ERA_START; // Year in Saka era
|
IndianYear = gregorianYear - INDIAN_ERA_START; // Year in Saka era
|
||||||
jdAtStartOfGregYear = gregorianToJD(gregorianYear, 0, 1); // JD at start of Gregorian year
|
jdAtStartOfGregYear = gregorianToJD(gregorianYear, 0, 1); // JD at start of Gregorian year
|
||||||
|
2
deps/icu-small/source/i18n/indiancal.h
vendored
2
deps/icu-small/source/i18n/indiancal.h
vendored
@ -215,7 +215,7 @@ public:
|
|||||||
* Return the number of days in the given Indian year
|
* Return the number of days in the given Indian year
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
virtual int32_t handleGetYearLength(int32_t extendedYear) const override;
|
virtual int32_t handleGetYearLength(int32_t extendedYear, UErrorCode& status) const override;
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
// Functions for converting from field values to milliseconds....
|
// Functions for converting from field values to milliseconds....
|
||||||
|
28
deps/icu-small/source/i18n/islamcal.cpp
vendored
28
deps/icu-small/source/i18n/islamcal.cpp
vendored
@ -202,7 +202,6 @@ IslamicCalendar* IslamicCalendar::clone() const {
|
|||||||
IslamicCalendar::IslamicCalendar(const Locale& aLocale, UErrorCode& success)
|
IslamicCalendar::IslamicCalendar(const Locale& aLocale, UErrorCode& success)
|
||||||
: Calendar(TimeZone::forLocaleOrDefault(aLocale), aLocale, success)
|
: Calendar(TimeZone::forLocaleOrDefault(aLocale), aLocale, success)
|
||||||
{
|
{
|
||||||
setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IslamicCalendar::~IslamicCalendar()
|
IslamicCalendar::~IslamicCalendar()
|
||||||
@ -444,15 +443,8 @@ int32_t yearLength(int32_t extendedYear, UErrorCode& status) {
|
|||||||
* Return the number of days in the given Islamic year
|
* Return the number of days in the given Islamic year
|
||||||
* @draft ICU 2.4
|
* @draft ICU 2.4
|
||||||
*/
|
*/
|
||||||
int32_t IslamicCalendar::handleGetYearLength(int32_t extendedYear) const {
|
int32_t IslamicCalendar::handleGetYearLength(int32_t extendedYear, UErrorCode& status) const {
|
||||||
UErrorCode status = U_ZERO_ERROR;
|
return yearLength(extendedYear, status);
|
||||||
int32_t length = yearLength(extendedYear, status);
|
|
||||||
if (U_FAILURE(status)) {
|
|
||||||
// fallback to normal Islamic calendar length 355 day a year if we
|
|
||||||
// encounter error and cannot propagate.
|
|
||||||
return 355;
|
|
||||||
}
|
|
||||||
return length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
@ -706,7 +698,8 @@ int32_t IslamicCivilCalendar::handleGetMonthLength(int32_t extendedYear, int32_t
|
|||||||
* Return the number of days in the given Islamic year
|
* Return the number of days in the given Islamic year
|
||||||
* @draft ICU 2.4
|
* @draft ICU 2.4
|
||||||
*/
|
*/
|
||||||
int32_t IslamicCivilCalendar::handleGetYearLength(int32_t extendedYear) const {
|
int32_t IslamicCivilCalendar::handleGetYearLength(int32_t extendedYear, UErrorCode& status) const {
|
||||||
|
if (U_FAILURE(status)) return 0;
|
||||||
return 354 + (civilLeapYear(extendedYear) ? 1 : 0);
|
return 354 + (civilLeapYear(extendedYear) ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -872,7 +865,7 @@ int32_t IslamicUmalquraCalendar::handleGetMonthLength(int32_t extendedYear, int3
|
|||||||
|
|
||||||
int32_t IslamicUmalquraCalendar::yearLength(int32_t extendedYear, UErrorCode& status) const {
|
int32_t IslamicUmalquraCalendar::yearLength(int32_t extendedYear, UErrorCode& status) const {
|
||||||
if (extendedYear<UMALQURA_YEAR_START || extendedYear>UMALQURA_YEAR_END) {
|
if (extendedYear<UMALQURA_YEAR_START || extendedYear>UMALQURA_YEAR_END) {
|
||||||
return IslamicCivilCalendar::handleGetYearLength(extendedYear);
|
return IslamicCivilCalendar::handleGetYearLength(extendedYear, status);
|
||||||
}
|
}
|
||||||
int length = 0;
|
int length = 0;
|
||||||
for(int i=0; i<12; i++) {
|
for(int i=0; i<12; i++) {
|
||||||
@ -888,15 +881,8 @@ int32_t IslamicUmalquraCalendar::yearLength(int32_t extendedYear, UErrorCode& st
|
|||||||
* Return the number of days in the given Islamic year
|
* Return the number of days in the given Islamic year
|
||||||
* @draft ICU 2.4
|
* @draft ICU 2.4
|
||||||
*/
|
*/
|
||||||
int32_t IslamicUmalquraCalendar::handleGetYearLength(int32_t extendedYear) const {
|
int32_t IslamicUmalquraCalendar::handleGetYearLength(int32_t extendedYear, UErrorCode& status) const {
|
||||||
UErrorCode status = U_ZERO_ERROR;
|
return yearLength(extendedYear, status);
|
||||||
int32_t length = yearLength(extendedYear, status);
|
|
||||||
if (U_FAILURE(status)) {
|
|
||||||
// fallback to normal Islamic calendar length 355 day a year if we
|
|
||||||
// encounter error and cannot propagate.
|
|
||||||
return 355;
|
|
||||||
}
|
|
||||||
return length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
6
deps/icu-small/source/i18n/islamcal.h
vendored
6
deps/icu-small/source/i18n/islamcal.h
vendored
@ -235,7 +235,7 @@ class U_I18N_API IslamicCalendar : public Calendar {
|
|||||||
* Return the number of days in the given Islamic year
|
* Return the number of days in the given Islamic year
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
virtual int32_t handleGetYearLength(int32_t extendedYear) const override;
|
virtual int32_t handleGetYearLength(int32_t extendedYear, UErrorCode& status) const override;
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
// Functions for converting from field values to milliseconds....
|
// Functions for converting from field values to milliseconds....
|
||||||
@ -438,7 +438,7 @@ class U_I18N_API IslamicCivilCalendar : public IslamicCalendar {
|
|||||||
* Return the number of days in the given Islamic year
|
* Return the number of days in the given Islamic year
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
virtual int32_t handleGetYearLength(int32_t extendedYear) const override;
|
virtual int32_t handleGetYearLength(int32_t extendedYear, UErrorCode& status) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override Calendar to compute several fields specific to the Islamic
|
* Override Calendar to compute several fields specific to the Islamic
|
||||||
@ -621,7 +621,7 @@ class U_I18N_API IslamicUmalquraCalendar : public IslamicCivilCalendar {
|
|||||||
* Return the number of days in the given Islamic year
|
* Return the number of days in the given Islamic year
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
virtual int32_t handleGetYearLength(int32_t extendedYear) const override;
|
virtual int32_t handleGetYearLength(int32_t extendedYear, UErrorCode& status) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override Calendar to compute several fields specific to the Islamic
|
* Override Calendar to compute several fields specific to the Islamic
|
||||||
|
7
deps/icu-small/source/i18n/japancal.cpp
vendored
7
deps/icu-small/source/i18n/japancal.cpp
vendored
@ -115,7 +115,6 @@ JapaneseCalendar::JapaneseCalendar(const Locale& aLocale, UErrorCode& success)
|
|||||||
: GregorianCalendar(aLocale, success)
|
: GregorianCalendar(aLocale, success)
|
||||||
{
|
{
|
||||||
init(success);
|
init(success);
|
||||||
setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JapaneseCalendar::~JapaneseCalendar()
|
JapaneseCalendar::~JapaneseCalendar()
|
||||||
@ -130,12 +129,6 @@ JapaneseCalendar::JapaneseCalendar(const JapaneseCalendar& source)
|
|||||||
U_ASSERT(U_SUCCESS(status));
|
U_ASSERT(U_SUCCESS(status));
|
||||||
}
|
}
|
||||||
|
|
||||||
JapaneseCalendar& JapaneseCalendar::operator= ( const JapaneseCalendar& right)
|
|
||||||
{
|
|
||||||
GregorianCalendar::operator=(right);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
JapaneseCalendar* JapaneseCalendar::clone() const
|
JapaneseCalendar* JapaneseCalendar::clone() const
|
||||||
{
|
{
|
||||||
return new JapaneseCalendar(*this);
|
return new JapaneseCalendar(*this);
|
||||||
|
7
deps/icu-small/source/i18n/japancal.h
vendored
7
deps/icu-small/source/i18n/japancal.h
vendored
@ -104,13 +104,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
JapaneseCalendar(const JapaneseCalendar& source);
|
JapaneseCalendar(const JapaneseCalendar& source);
|
||||||
|
|
||||||
/**
|
|
||||||
* Default assignment operator
|
|
||||||
* @param right the object to be copied.
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
JapaneseCalendar& operator=(const JapaneseCalendar& right);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create and return a polymorphic copy of this calendar.
|
* Create and return a polymorphic copy of this calendar.
|
||||||
* @return return a polymorphic copy of this calendar.
|
* @return return a polymorphic copy of this calendar.
|
||||||
|
48
deps/icu-small/source/i18n/measunit.cpp
vendored
48
deps/icu-small/source/i18n/measunit.cpp
vendored
@ -41,26 +41,26 @@ static const int32_t gOffsets[] = {
|
|||||||
2,
|
2,
|
||||||
7,
|
7,
|
||||||
17,
|
17,
|
||||||
27,
|
28,
|
||||||
31,
|
32,
|
||||||
333,
|
334,
|
||||||
344,
|
345,
|
||||||
362,
|
363,
|
||||||
366,
|
367,
|
||||||
375,
|
376,
|
||||||
378,
|
379,
|
||||||
382,
|
383,
|
||||||
390,
|
391,
|
||||||
412,
|
413,
|
||||||
416,
|
417,
|
||||||
431,
|
|
||||||
432,
|
432,
|
||||||
438,
|
433,
|
||||||
449,
|
439,
|
||||||
455,
|
450,
|
||||||
459,
|
456,
|
||||||
461,
|
460,
|
||||||
495
|
462,
|
||||||
|
496
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int32_t kCurrencyOffset = 5;
|
static const int32_t kCurrencyOffset = 5;
|
||||||
@ -121,6 +121,7 @@ static const char * const gSubTypes[] = {
|
|||||||
"permille",
|
"permille",
|
||||||
"permillion",
|
"permillion",
|
||||||
"permyriad",
|
"permyriad",
|
||||||
|
"portion-per-1e9",
|
||||||
"liter-per-100-kilometer",
|
"liter-per-100-kilometer",
|
||||||
"liter-per-kilometer",
|
"liter-per-kilometer",
|
||||||
"mile-per-gallon",
|
"mile-per-gallon",
|
||||||
@ -811,6 +812,14 @@ MeasureUnit MeasureUnit::getPermyriad() {
|
|||||||
return MeasureUnit(3, 9);
|
return MeasureUnit(3, 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MeasureUnit *MeasureUnit::createPortionPer1E9(UErrorCode &status) {
|
||||||
|
return MeasureUnit::create(3, 10, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
MeasureUnit MeasureUnit::getPortionPer1E9() {
|
||||||
|
return MeasureUnit(3, 10);
|
||||||
|
}
|
||||||
|
|
||||||
MeasureUnit *MeasureUnit::createLiterPer100Kilometers(UErrorCode &status) {
|
MeasureUnit *MeasureUnit::createLiterPer100Kilometers(UErrorCode &status) {
|
||||||
return MeasureUnit::create(4, 0, status);
|
return MeasureUnit::create(4, 0, status);
|
||||||
}
|
}
|
||||||
@ -2400,6 +2409,7 @@ MeasureUnitImpl MeasureUnitImpl::copy(UErrorCode &status) const {
|
|||||||
MeasureUnitImpl result;
|
MeasureUnitImpl result;
|
||||||
result.complexity = complexity;
|
result.complexity = complexity;
|
||||||
result.identifier.append(identifier, status);
|
result.identifier.append(identifier, status);
|
||||||
|
result.constantDenominator = constantDenominator;
|
||||||
for (int32_t i = 0; i < singleUnits.length(); i++) {
|
for (int32_t i = 0; i < singleUnits.length(); i++) {
|
||||||
SingleUnitImpl *item = result.singleUnits.emplaceBack(*singleUnits[i]);
|
SingleUnitImpl *item = result.singleUnits.emplaceBack(*singleUnits[i]);
|
||||||
if (!item) {
|
if (!item) {
|
||||||
|
446
deps/icu-small/source/i18n/measunit_extra.cpp
vendored
446
deps/icu-small/source/i18n/measunit_extra.cpp
vendored
@ -15,6 +15,7 @@
|
|||||||
#include "charstr.h"
|
#include "charstr.h"
|
||||||
#include "cmemory.h"
|
#include "cmemory.h"
|
||||||
#include "cstring.h"
|
#include "cstring.h"
|
||||||
|
#include "double-conversion-string-to-double.h"
|
||||||
#include "measunit_impl.h"
|
#include "measunit_impl.h"
|
||||||
#include "resource.h"
|
#include "resource.h"
|
||||||
#include "uarrsort.h"
|
#include "uarrsort.h"
|
||||||
@ -30,13 +31,15 @@
|
|||||||
#include "unicode/ustringtrie.h"
|
#include "unicode/ustringtrie.h"
|
||||||
#include "uresimp.h"
|
#include "uresimp.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include <limits.h>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
U_NAMESPACE_BEGIN
|
U_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
using icu::double_conversion::StringToDoubleConverter;
|
||||||
|
|
||||||
// TODO: Propose a new error code for this?
|
// TODO: Propose a new error code for this?
|
||||||
constexpr UErrorCode kUnitIdentifierSyntaxError = U_ILLEGAL_ARGUMENT_ERROR;
|
constexpr UErrorCode kUnitIdentifierSyntaxError = U_ILLEGAL_ARGUMENT_ERROR;
|
||||||
|
|
||||||
@ -467,37 +470,55 @@ void U_CALLCONV initUnitExtras(UErrorCode& status) {
|
|||||||
|
|
||||||
class Token {
|
class Token {
|
||||||
public:
|
public:
|
||||||
Token(int32_t match) : fMatch(match) {}
|
Token(int64_t match) : fMatch(match) {
|
||||||
|
if (fMatch < kCompoundPartOffset) {
|
||||||
|
this->fType = TYPE_PREFIX;
|
||||||
|
} else if (fMatch < kInitialCompoundPartOffset) {
|
||||||
|
this->fType = TYPE_COMPOUND_PART;
|
||||||
|
} else if (fMatch < kPowerPartOffset) {
|
||||||
|
this->fType = TYPE_INITIAL_COMPOUND_PART;
|
||||||
|
} else if (fMatch < kSimpleUnitOffset) {
|
||||||
|
this->fType = TYPE_POWER_PART;
|
||||||
|
} else {
|
||||||
|
this->fType = TYPE_SIMPLE_UNIT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum Type {
|
static Token constantToken(StringPiece str, UErrorCode &status) {
|
||||||
TYPE_UNDEFINED,
|
Token result;
|
||||||
TYPE_PREFIX,
|
auto value = Token::parseStringToLong(str, status);
|
||||||
// Token type for "-per-", "-", and "-and-".
|
if (U_FAILURE(status)) {
|
||||||
TYPE_COMPOUND_PART,
|
return result;
|
||||||
// Token type for "per-".
|
}
|
||||||
TYPE_INITIAL_COMPOUND_PART,
|
result.fMatch = value;
|
||||||
TYPE_POWER_PART,
|
result.fType = TYPE_CONSTANT_DENOMINATOR;
|
||||||
TYPE_SIMPLE_UNIT,
|
return result;
|
||||||
};
|
}
|
||||||
|
|
||||||
// Calling getType() is invalid, resulting in an assertion failure, if Token
|
enum Type {
|
||||||
// value isn't positive.
|
TYPE_UNDEFINED,
|
||||||
Type getType() const {
|
TYPE_PREFIX,
|
||||||
U_ASSERT(fMatch > 0);
|
// Token type for "-per-", "-", and "-and-".
|
||||||
if (fMatch < kCompoundPartOffset) {
|
TYPE_COMPOUND_PART,
|
||||||
return TYPE_PREFIX;
|
// Token type for "per-".
|
||||||
}
|
TYPE_INITIAL_COMPOUND_PART,
|
||||||
if (fMatch < kInitialCompoundPartOffset) {
|
TYPE_POWER_PART,
|
||||||
return TYPE_COMPOUND_PART;
|
TYPE_SIMPLE_UNIT,
|
||||||
}
|
TYPE_CONSTANT_DENOMINATOR,
|
||||||
if (fMatch < kPowerPartOffset) {
|
};
|
||||||
return TYPE_INITIAL_COMPOUND_PART;
|
|
||||||
}
|
// Calling getType() is invalid, resulting in an assertion failure, if Token
|
||||||
if (fMatch < kSimpleUnitOffset) {
|
// value isn't positive.
|
||||||
return TYPE_POWER_PART;
|
Type getType() const {
|
||||||
}
|
U_ASSERT(fMatch >= 0);
|
||||||
return TYPE_SIMPLE_UNIT;
|
return this->fType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Retrieve the value of the constant denominator if the token is of type TYPE_CONSTANT_DENOMINATOR.
|
||||||
|
uint64_t getConstantDenominator() const {
|
||||||
|
U_ASSERT(getType() == TYPE_CONSTANT_DENOMINATOR);
|
||||||
|
return static_cast<uint64_t>(fMatch);
|
||||||
|
}
|
||||||
|
|
||||||
UMeasurePrefix getUnitPrefix() const {
|
UMeasurePrefix getUnitPrefix() const {
|
||||||
U_ASSERT(getType() == TYPE_PREFIX);
|
U_ASSERT(getType() == TYPE_PREFIX);
|
||||||
@ -530,8 +551,41 @@ public:
|
|||||||
return fMatch - kSimpleUnitOffset;
|
return fMatch - kSimpleUnitOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Consider moving this to a separate utility class.
|
||||||
|
// Utility function to parse a string into an unsigned long value.
|
||||||
|
// The value must be a positive integer within the range [1, INT64_MAX].
|
||||||
|
// The input can be in integer or scientific notation.
|
||||||
|
static uint64_t parseStringToLong(const 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;
|
||||||
|
double double_result = converter.StringToDouble(strNum.data(), strNum.length(), &count);
|
||||||
|
if (count != strNum.length()) {
|
||||||
|
status = kUnitIdentifierSyntaxError;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (U_FAILURE(status) || double_result < 1.0 || double_result > static_cast<double>(INT64_MAX)) {
|
||||||
|
status = kUnitIdentifierSyntaxError;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the value is integer.
|
||||||
|
uint64_t int_result = static_cast<uint64_t>(double_result);
|
||||||
|
const double kTolerance = 1e-9;
|
||||||
|
if (abs(double_result - int_result) > kTolerance) {
|
||||||
|
status = kUnitIdentifierSyntaxError;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return int_result;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int32_t fMatch;
|
Token() = default;
|
||||||
|
int64_t fMatch;
|
||||||
|
Type fType = TYPE_UNDEFINED;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Parser {
|
class Parser {
|
||||||
@ -555,6 +609,50 @@ public:
|
|||||||
return {source};
|
return {source};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A single unit or a constant denominator.
|
||||||
|
*/
|
||||||
|
struct SingleUnitOrConstant {
|
||||||
|
enum ValueType {
|
||||||
|
kSingleUnit,
|
||||||
|
kConstantDenominator,
|
||||||
|
};
|
||||||
|
|
||||||
|
ValueType type = kSingleUnit;
|
||||||
|
SingleUnitImpl singleUnit;
|
||||||
|
uint64_t constantDenominator;
|
||||||
|
|
||||||
|
static SingleUnitOrConstant singleUnitValue(SingleUnitImpl singleUnit) {
|
||||||
|
SingleUnitOrConstant result;
|
||||||
|
result.type = kSingleUnit;
|
||||||
|
result.singleUnit = singleUnit;
|
||||||
|
result.constantDenominator = 0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SingleUnitOrConstant constantDenominatorValue(uint64_t constant) {
|
||||||
|
SingleUnitOrConstant result;
|
||||||
|
result.type = kConstantDenominator;
|
||||||
|
result.singleUnit = {};
|
||||||
|
result.constantDenominator = constant;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t getConstantDenominator() const {
|
||||||
|
U_ASSERT(type == kConstantDenominator);
|
||||||
|
return constantDenominator;
|
||||||
|
}
|
||||||
|
|
||||||
|
SingleUnitImpl getSingleUnit() const {
|
||||||
|
U_ASSERT(type == kSingleUnit);
|
||||||
|
return singleUnit;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isSingleUnit() const { return type == kSingleUnit; }
|
||||||
|
|
||||||
|
bool isConstantDenominator() const { return type == kConstantDenominator; }
|
||||||
|
};
|
||||||
|
|
||||||
MeasureUnitImpl parse(UErrorCode& status) {
|
MeasureUnitImpl parse(UErrorCode& status) {
|
||||||
MeasureUnitImpl result;
|
MeasureUnitImpl result;
|
||||||
|
|
||||||
@ -569,12 +667,19 @@ public:
|
|||||||
while (hasNext()) {
|
while (hasNext()) {
|
||||||
bool sawAnd = false;
|
bool sawAnd = false;
|
||||||
|
|
||||||
SingleUnitImpl singleUnit = nextSingleUnit(sawAnd, status);
|
auto singleUnitOrConstant = nextSingleUnitOrConstant(sawAnd, status);
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool added = result.appendSingleUnit(singleUnit, status);
|
if (singleUnitOrConstant.isConstantDenominator()) {
|
||||||
|
result.constantDenominator = singleUnitOrConstant.getConstantDenominator();
|
||||||
|
result.complexity = UMEASURE_UNIT_COMPOUND;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
U_ASSERT(singleUnitOrConstant.isSingleUnit());
|
||||||
|
bool added = result.appendSingleUnit(singleUnitOrConstant.getSingleUnit(), status);
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -604,6 +709,12 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (result.singleUnits.length() == 0) {
|
||||||
|
// The identifier was empty or only had a constant denominator.
|
||||||
|
status = kUnitIdentifierSyntaxError;
|
||||||
|
return result; // add it for code consistency.
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -622,6 +733,10 @@ private:
|
|||||||
// identifier is invalid pending TODO(CLDR-13701).
|
// identifier is invalid pending TODO(CLDR-13701).
|
||||||
bool fAfterPer = false;
|
bool fAfterPer = false;
|
||||||
|
|
||||||
|
// Set to true when we've just seen a "per-". This is used to determine if
|
||||||
|
// the next token can be a constant denominator token.
|
||||||
|
bool fJustSawPer = false;
|
||||||
|
|
||||||
Parser() : fSource(""), fTrie(u"") {}
|
Parser() : fSource(""), fTrie(u"") {}
|
||||||
|
|
||||||
Parser(StringPiece source)
|
Parser(StringPiece source)
|
||||||
@ -640,6 +755,10 @@ private:
|
|||||||
// Saves the position in the fSource string for the end of the most
|
// Saves the position in the fSource string for the end of the most
|
||||||
// recent matching token.
|
// recent matching token.
|
||||||
int32_t previ = -1;
|
int32_t previ = -1;
|
||||||
|
|
||||||
|
// Saves the position in the fSource string for later use in case of unit constant found.
|
||||||
|
int32_t currentFIndex = fIndex;
|
||||||
|
|
||||||
// Find the longest token that matches a value in the trie:
|
// Find the longest token that matches a value in the trie:
|
||||||
while (fIndex < fSource.length()) {
|
while (fIndex < fSource.length()) {
|
||||||
auto result = fTrie.next(fSource.data()[fIndex++]);
|
auto result = fTrie.next(fSource.data()[fIndex++]);
|
||||||
@ -658,12 +777,25 @@ private:
|
|||||||
// continue;
|
// continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match < 0) {
|
if (match >= 0) {
|
||||||
status = kUnitIdentifierSyntaxError;
|
|
||||||
} else {
|
|
||||||
fIndex = previ;
|
fIndex = previ;
|
||||||
|
return {match};
|
||||||
}
|
}
|
||||||
return {match};
|
|
||||||
|
// If no match was found, we check if the token is a constant denominator.
|
||||||
|
// 1. We find the index of the start of the next token or the end of the string.
|
||||||
|
int32_t endOfConstantIndex = fSource.find("-", currentFIndex);
|
||||||
|
endOfConstantIndex = (endOfConstantIndex == -1) ? fSource.length() : endOfConstantIndex;
|
||||||
|
if (endOfConstantIndex <= currentFIndex) {
|
||||||
|
status = kUnitIdentifierSyntaxError;
|
||||||
|
return {match};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. We extract the substring from the start of the constant to the end of the constant.
|
||||||
|
StringPiece constantDenominatorStr =
|
||||||
|
fSource.substr(currentFIndex, endOfConstantIndex - currentFIndex);
|
||||||
|
fIndex = endOfConstantIndex;
|
||||||
|
return Token::constantToken(constantDenominatorStr, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -680,10 +812,10 @@ private:
|
|||||||
* unit", sawAnd is set to true. If not, it is left as is.
|
* unit", sawAnd is set to true. If not, it is left as is.
|
||||||
* @param status ICU error code.
|
* @param status ICU error code.
|
||||||
*/
|
*/
|
||||||
SingleUnitImpl nextSingleUnit(bool &sawAnd, UErrorCode &status) {
|
SingleUnitOrConstant nextSingleUnitOrConstant(bool &sawAnd, UErrorCode &status) {
|
||||||
SingleUnitImpl result;
|
SingleUnitImpl singleUnitResult;
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
return result;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// state:
|
// state:
|
||||||
@ -695,19 +827,22 @@ private:
|
|||||||
bool atStart = fIndex == 0;
|
bool atStart = fIndex == 0;
|
||||||
Token token = nextToken(status);
|
Token token = nextToken(status);
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
return result;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fJustSawPer = false;
|
||||||
|
|
||||||
if (atStart) {
|
if (atStart) {
|
||||||
// Identifiers optionally start with "per-".
|
// Identifiers optionally start with "per-".
|
||||||
if (token.getType() == Token::TYPE_INITIAL_COMPOUND_PART) {
|
if (token.getType() == Token::TYPE_INITIAL_COMPOUND_PART) {
|
||||||
U_ASSERT(token.getInitialCompoundPart() == INITIAL_COMPOUND_PART_PER);
|
U_ASSERT(token.getInitialCompoundPart() == INITIAL_COMPOUND_PART_PER);
|
||||||
fAfterPer = true;
|
fAfterPer = true;
|
||||||
result.dimensionality = -1;
|
fJustSawPer = true;
|
||||||
|
singleUnitResult.dimensionality = -1;
|
||||||
|
|
||||||
token = nextToken(status);
|
token = nextToken(status);
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
return result;
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -715,7 +850,7 @@ private:
|
|||||||
// via a compound part:
|
// via a compound part:
|
||||||
if (token.getType() != Token::TYPE_COMPOUND_PART) {
|
if (token.getType() != Token::TYPE_COMPOUND_PART) {
|
||||||
status = kUnitIdentifierSyntaxError;
|
status = kUnitIdentifierSyntaxError;
|
||||||
return result;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (token.getMatch()) {
|
switch (token.getMatch()) {
|
||||||
@ -724,15 +859,16 @@ private:
|
|||||||
// Mixed compound units not yet supported,
|
// Mixed compound units not yet supported,
|
||||||
// TODO(CLDR-13701).
|
// TODO(CLDR-13701).
|
||||||
status = kUnitIdentifierSyntaxError;
|
status = kUnitIdentifierSyntaxError;
|
||||||
return result;
|
return {};
|
||||||
}
|
}
|
||||||
fAfterPer = true;
|
fAfterPer = true;
|
||||||
result.dimensionality = -1;
|
fJustSawPer = true;
|
||||||
|
singleUnitResult.dimensionality = -1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case COMPOUND_PART_TIMES:
|
case COMPOUND_PART_TIMES:
|
||||||
if (fAfterPer) {
|
if (fAfterPer) {
|
||||||
result.dimensionality = -1;
|
singleUnitResult.dimensionality = -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -741,7 +877,7 @@ private:
|
|||||||
// Can't start with "-and-", and mixed compound units
|
// Can't start with "-and-", and mixed compound units
|
||||||
// not yet supported, TODO(CLDR-13701).
|
// not yet supported, TODO(CLDR-13701).
|
||||||
status = kUnitIdentifierSyntaxError;
|
status = kUnitIdentifierSyntaxError;
|
||||||
return result;
|
return {};
|
||||||
}
|
}
|
||||||
sawAnd = true;
|
sawAnd = true;
|
||||||
break;
|
break;
|
||||||
@ -749,52 +885,65 @@ private:
|
|||||||
|
|
||||||
token = nextToken(status);
|
token = nextToken(status);
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
return result;
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (token.getType() == Token::TYPE_CONSTANT_DENOMINATOR) {
|
||||||
|
if (!fJustSawPer) {
|
||||||
|
status = kUnitIdentifierSyntaxError;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return SingleUnitOrConstant::constantDenominatorValue(token.getConstantDenominator());
|
||||||
|
}
|
||||||
|
|
||||||
// Read tokens until we have a complete SingleUnit or we reach the end.
|
// Read tokens until we have a complete SingleUnit or we reach the end.
|
||||||
while (true) {
|
while (true) {
|
||||||
switch (token.getType()) {
|
switch (token.getType()) {
|
||||||
case Token::TYPE_POWER_PART:
|
case Token::TYPE_POWER_PART:
|
||||||
if (state > 0) {
|
if (state > 0) {
|
||||||
status = kUnitIdentifierSyntaxError;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
result.dimensionality *= token.getPower();
|
|
||||||
state = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Token::TYPE_PREFIX:
|
|
||||||
if (state > 1) {
|
|
||||||
status = kUnitIdentifierSyntaxError;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
result.unitPrefix = token.getUnitPrefix();
|
|
||||||
state = 2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Token::TYPE_SIMPLE_UNIT:
|
|
||||||
result.index = token.getSimpleUnitIndex();
|
|
||||||
return result;
|
|
||||||
|
|
||||||
default:
|
|
||||||
status = kUnitIdentifierSyntaxError;
|
status = kUnitIdentifierSyntaxError;
|
||||||
return result;
|
return {};
|
||||||
|
}
|
||||||
|
singleUnitResult.dimensionality *= token.getPower();
|
||||||
|
state = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Token::TYPE_PREFIX:
|
||||||
|
if (state > 1) {
|
||||||
|
status = kUnitIdentifierSyntaxError;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
singleUnitResult.unitPrefix = token.getUnitPrefix();
|
||||||
|
state = 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Token::TYPE_SIMPLE_UNIT:
|
||||||
|
singleUnitResult.index = token.getSimpleUnitIndex();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
status = kUnitIdentifierSyntaxError;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token.getType() == Token::TYPE_SIMPLE_UNIT) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasNext()) {
|
if (!hasNext()) {
|
||||||
// We ran out of tokens before finding a complete single unit.
|
// We ran out of tokens before finding a complete single unit.
|
||||||
status = kUnitIdentifierSyntaxError;
|
status = kUnitIdentifierSyntaxError;
|
||||||
return result;
|
return {};
|
||||||
}
|
}
|
||||||
token = nextToken(status);
|
token = nextToken(status);
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
return result;
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return SingleUnitOrConstant::singleUnitValue(singleUnitResult);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1120,6 +1269,51 @@ MeasureUnitImpl::extractIndividualUnitsWithIndices(UErrorCode &status) const {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t countCharacter(const CharString &str, char c) {
|
||||||
|
int32_t count = 0;
|
||||||
|
for (int32_t i = 0, n = str.length(); i < n; i++) {
|
||||||
|
if (str[i] == c) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal function that returns a string of the constants in the correct
|
||||||
|
* format.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* 1000 --> "-per-1000"
|
||||||
|
* 1000000 --> "-per-1e6"
|
||||||
|
*
|
||||||
|
* NOTE: this function is only used when the constant denominator is greater
|
||||||
|
* than 0.
|
||||||
|
*/
|
||||||
|
CharString getConstantsString(uint64_t constantDenominator, UErrorCode &status) {
|
||||||
|
U_ASSERT(constantDenominator > 0 && constantDenominator <= LLONG_MAX);
|
||||||
|
|
||||||
|
CharString result;
|
||||||
|
result.appendNumber(constantDenominator, status);
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (constantDenominator <= 1000) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the constant is a power of 10.
|
||||||
|
int32_t zeros = countCharacter(result, '0');
|
||||||
|
if (zeros == result.length() - 1 && result[0] == '1') {
|
||||||
|
result.clear();
|
||||||
|
result.append(StringPiece("1e"), status);
|
||||||
|
result.appendNumber(zeros, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normalize a MeasureUnitImpl and generate the identifier string in place.
|
* Normalize a MeasureUnitImpl and generate the identifier string in place.
|
||||||
*/
|
*/
|
||||||
@ -1128,7 +1322,7 @@ void MeasureUnitImpl::serialize(UErrorCode &status) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->singleUnits.length() == 0) {
|
if (this->singleUnits.length() == 0 && this->constantDenominator == 0) {
|
||||||
// Dimensionless, constructed by the default constructor.
|
// Dimensionless, constructed by the default constructor.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1145,6 +1339,7 @@ void MeasureUnitImpl::serialize(UErrorCode &status) {
|
|||||||
CharString result;
|
CharString result;
|
||||||
bool beforePer = true;
|
bool beforePer = true;
|
||||||
bool firstTimeNegativeDimension = false;
|
bool firstTimeNegativeDimension = false;
|
||||||
|
bool constantDenominatorAppended = false;
|
||||||
for (int32_t i = 0; i < this->singleUnits.length(); i++) {
|
for (int32_t i = 0; i < this->singleUnits.length(); i++) {
|
||||||
if (beforePer && (*this->singleUnits[i]).dimensionality < 0) {
|
if (beforePer && (*this->singleUnits[i]).dimensionality < 0) {
|
||||||
beforePer = false;
|
beforePer = false;
|
||||||
@ -1168,43 +1363,103 @@ void MeasureUnitImpl::serialize(UErrorCode &status) {
|
|||||||
} else {
|
} else {
|
||||||
result.append(StringPiece("-per-"), status);
|
result.append(StringPiece("-per-"), status);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (result.length() != 0) {
|
if (this->constantDenominator > 0) {
|
||||||
|
result.append(getConstantsString(this->constantDenominator, status), status);
|
||||||
result.append(StringPiece("-"), status);
|
result.append(StringPiece("-"), status);
|
||||||
|
constantDenominatorAppended = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if (result.length() != 0) {
|
||||||
|
result.append(StringPiece("-"), status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this->singleUnits[i]->appendNeutralIdentifier(result, status);
|
this->singleUnits[i]->appendNeutralIdentifier(result, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!constantDenominatorAppended && this->constantDenominator > 0) {
|
||||||
|
result.append(StringPiece("-per-"), status);
|
||||||
|
result.append(getConstantsString(this->constantDenominator, status), status);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this->identifier = CharString(result, status);
|
this->identifier = CharString(result, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
MeasureUnit MeasureUnitImpl::build(UErrorCode& status) && {
|
MeasureUnit MeasureUnitImpl::build(UErrorCode &status) && {
|
||||||
this->serialize(status);
|
this->serialize(status);
|
||||||
return MeasureUnit(std::move(*this));
|
return MeasureUnit(std::move(*this));
|
||||||
}
|
}
|
||||||
|
|
||||||
MeasureUnit MeasureUnit::forIdentifier(StringPiece identifier, UErrorCode& status) {
|
MeasureUnit MeasureUnit::forIdentifier(StringPiece identifier, UErrorCode &status) {
|
||||||
return Parser::from(identifier, status).parse(status).build(status);
|
return Parser::from(identifier, status).parse(status).build(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
UMeasureUnitComplexity MeasureUnit::getComplexity(UErrorCode& status) const {
|
UMeasureUnitComplexity MeasureUnit::getComplexity(UErrorCode &status) const {
|
||||||
MeasureUnitImpl temp;
|
MeasureUnitImpl temp;
|
||||||
return MeasureUnitImpl::forMeasureUnit(*this, temp, status).complexity;
|
return MeasureUnitImpl::forMeasureUnit(*this, temp, status).complexity;
|
||||||
}
|
}
|
||||||
|
|
||||||
UMeasurePrefix MeasureUnit::getPrefix(UErrorCode& status) const {
|
UMeasurePrefix MeasureUnit::getPrefix(UErrorCode &status) const {
|
||||||
return SingleUnitImpl::forMeasureUnit(*this, status).unitPrefix;
|
return SingleUnitImpl::forMeasureUnit(*this, status).unitPrefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
MeasureUnit MeasureUnit::withPrefix(UMeasurePrefix prefix, UErrorCode& status) const UPRV_NO_SANITIZE_UNDEFINED {
|
MeasureUnit MeasureUnit::withPrefix(UMeasurePrefix prefix,
|
||||||
|
UErrorCode &status) const UPRV_NO_SANITIZE_UNDEFINED {
|
||||||
SingleUnitImpl singleUnit = SingleUnitImpl::forMeasureUnit(*this, status);
|
SingleUnitImpl singleUnit = SingleUnitImpl::forMeasureUnit(*this, status);
|
||||||
singleUnit.unitPrefix = prefix;
|
singleUnit.unitPrefix = prefix;
|
||||||
return singleUnit.build(status);
|
return singleUnit.build(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t MeasureUnit::getConstantDenominator(UErrorCode &status) const {
|
||||||
|
auto complexity = this->getComplexity(status);
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (complexity != UMEASURE_UNIT_SINGLE && complexity != UMEASURE_UNIT_COMPOUND) {
|
||||||
|
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->fImpl == nullptr) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this->fImpl->constantDenominator;
|
||||||
|
}
|
||||||
|
|
||||||
|
MeasureUnit MeasureUnit::withConstantDenominator(uint64_t denominator, UErrorCode &status) const {
|
||||||
|
// To match the behavior of the Java API, we do not allow a constant denominator
|
||||||
|
// bigger than LONG_MAX.
|
||||||
|
if (denominator > LONG_MAX) {
|
||||||
|
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto complexity = this->getComplexity(status);
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (complexity != UMEASURE_UNIT_SINGLE && complexity != UMEASURE_UNIT_COMPOUND) {
|
||||||
|
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
MeasureUnitImpl impl = MeasureUnitImpl::forMeasureUnitMaybeCopy(*this, status);
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl.constantDenominator = denominator;
|
||||||
|
impl.complexity = (impl.singleUnits.length() < 2 && denominator == 0) ? UMEASURE_UNIT_SINGLE
|
||||||
|
: UMEASURE_UNIT_COMPOUND;
|
||||||
|
return std::move(impl).build(status);
|
||||||
|
}
|
||||||
|
|
||||||
int32_t MeasureUnit::getDimensionality(UErrorCode& status) const {
|
int32_t MeasureUnit::getDimensionality(UErrorCode& status) const {
|
||||||
SingleUnitImpl singleUnit = SingleUnitImpl::forMeasureUnit(*this, status);
|
SingleUnitImpl singleUnit = SingleUnitImpl::forMeasureUnit(*this, status);
|
||||||
if (U_FAILURE(status)) { return 0; }
|
if (U_FAILURE(status)) { return 0; }
|
||||||
@ -1222,6 +1477,11 @@ MeasureUnit MeasureUnit::withDimensionality(int32_t dimensionality, UErrorCode&
|
|||||||
|
|
||||||
MeasureUnit MeasureUnit::reciprocal(UErrorCode& status) const {
|
MeasureUnit MeasureUnit::reciprocal(UErrorCode& status) const {
|
||||||
MeasureUnitImpl impl = MeasureUnitImpl::forMeasureUnitMaybeCopy(*this, status);
|
MeasureUnitImpl impl = MeasureUnitImpl::forMeasureUnitMaybeCopy(*this, status);
|
||||||
|
// The reciprocal of a unit that has a constant denominator is not allowed.
|
||||||
|
if (impl.constantDenominator != 0) {
|
||||||
|
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
impl.takeReciprocal(status);
|
impl.takeReciprocal(status);
|
||||||
return std::move(impl).build(status);
|
return std::move(impl).build(status);
|
||||||
}
|
}
|
||||||
@ -1237,9 +1497,25 @@ MeasureUnit MeasureUnit::product(const MeasureUnit& other, UErrorCode& status) c
|
|||||||
for (int32_t i = 0; i < otherImpl.singleUnits.length(); i++) {
|
for (int32_t i = 0; i < otherImpl.singleUnits.length(); i++) {
|
||||||
impl.appendSingleUnit(*otherImpl.singleUnits[i], status);
|
impl.appendSingleUnit(*otherImpl.singleUnits[i], status);
|
||||||
}
|
}
|
||||||
if (impl.singleUnits.length() > 1) {
|
|
||||||
|
uint64_t currentConstatDenominator = this->getConstantDenominator(status);
|
||||||
|
uint64_t otherConstantDenominator = other.getConstantDenominator(status);
|
||||||
|
|
||||||
|
// TODO: we can also multiply the constant denominators instead of returning an error.
|
||||||
|
if (currentConstatDenominator != 0 && otherConstantDenominator != 0) {
|
||||||
|
// There is only `one` constant denominator in a compound unit.
|
||||||
|
// Therefore, we Cannot multiply units that both of them have a constant denominator
|
||||||
|
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Because either one of the constant denominators is zero, we can use the maximum of them.
|
||||||
|
impl.constantDenominator = uprv_max(currentConstatDenominator, otherConstantDenominator);
|
||||||
|
|
||||||
|
if (impl.singleUnits.length() > 1 || impl.constantDenominator > 0) {
|
||||||
impl.complexity = UMEASURE_UNIT_COMPOUND;
|
impl.complexity = UMEASURE_UNIT_COMPOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::move(impl).build(status);
|
return std::move(impl).build(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
8
deps/icu-small/source/i18n/measunit_impl.h
vendored
8
deps/icu-small/source/i18n/measunit_impl.h
vendored
@ -328,6 +328,14 @@ class U_I18N_API MeasureUnitImpl : public UMemory {
|
|||||||
*/
|
*/
|
||||||
CharString identifier;
|
CharString identifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the unit constant denominator.
|
||||||
|
*
|
||||||
|
* NOTE:
|
||||||
|
* if set to 0, it means that the constant is not set.
|
||||||
|
*/
|
||||||
|
uint64_t constantDenominator = 0;
|
||||||
|
|
||||||
// For calling serialize
|
// For calling serialize
|
||||||
// TODO(icu-units#147): revisit serialization
|
// TODO(icu-units#147): revisit serialization
|
||||||
friend class number::impl::LongNameHandler;
|
friend class number::impl::LongNameHandler;
|
||||||
|
434
deps/icu-small/source/i18n/messageformat2.cpp
vendored
434
deps/icu-small/source/i18n/messageformat2.cpp
vendored
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include "unicode/utypes.h"
|
#include "unicode/utypes.h"
|
||||||
|
|
||||||
|
#if !UCONFIG_NO_NORMALIZATION
|
||||||
|
|
||||||
#if !UCONFIG_NO_FORMATTING
|
#if !UCONFIG_NO_FORMATTING
|
||||||
|
|
||||||
#if !UCONFIG_NO_MF2
|
#if !UCONFIG_NO_MF2
|
||||||
@ -11,8 +13,10 @@
|
|||||||
#include "unicode/messageformat2_data_model.h"
|
#include "unicode/messageformat2_data_model.h"
|
||||||
#include "unicode/messageformat2_formattable.h"
|
#include "unicode/messageformat2_formattable.h"
|
||||||
#include "unicode/messageformat2.h"
|
#include "unicode/messageformat2.h"
|
||||||
|
#include "unicode/normalizer2.h"
|
||||||
#include "unicode/unistr.h"
|
#include "unicode/unistr.h"
|
||||||
#include "messageformat2_allocation.h"
|
#include "messageformat2_allocation.h"
|
||||||
|
#include "messageformat2_checker.h"
|
||||||
#include "messageformat2_evaluation.h"
|
#include "messageformat2_evaluation.h"
|
||||||
#include "messageformat2_macros.h"
|
#include "messageformat2_macros.h"
|
||||||
|
|
||||||
@ -37,7 +41,7 @@ static Formattable evalLiteral(const Literal& lit) {
|
|||||||
// The fallback for a variable name is itself.
|
// The fallback for a variable name is itself.
|
||||||
UnicodeString str(DOLLAR);
|
UnicodeString str(DOLLAR);
|
||||||
str += var;
|
str += var;
|
||||||
const Formattable* val = context.getGlobal(var, errorCode);
|
const Formattable* val = context.getGlobal(*this, var, errorCode);
|
||||||
if (U_SUCCESS(errorCode)) {
|
if (U_SUCCESS(errorCode)) {
|
||||||
return (FormattedPlaceholder(*val, str));
|
return (FormattedPlaceholder(*val, str));
|
||||||
}
|
}
|
||||||
@ -51,16 +55,16 @@ static Formattable evalLiteral(const Literal& lit) {
|
|||||||
return FormattedPlaceholder(evalLiteral(lit), lit.quoted());
|
return FormattedPlaceholder(evalLiteral(lit), lit.quoted());
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] FormattedPlaceholder MessageFormatter::formatOperand(const Environment& env,
|
[[nodiscard]] InternalValue* MessageFormatter::formatOperand(const Environment& env,
|
||||||
const Operand& rand,
|
const Operand& rand,
|
||||||
MessageContext& context,
|
MessageContext& context,
|
||||||
UErrorCode &status) const {
|
UErrorCode &status) const {
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rand.isNull()) {
|
if (rand.isNull()) {
|
||||||
return FormattedPlaceholder();
|
return create<InternalValue>(InternalValue(FormattedPlaceholder()), status);
|
||||||
}
|
}
|
||||||
if (rand.isVariable()) {
|
if (rand.isVariable()) {
|
||||||
// Check if it's local or global
|
// Check if it's local or global
|
||||||
@ -71,15 +75,19 @@ static Formattable evalLiteral(const Literal& lit) {
|
|||||||
// Eager vs. lazy evaluation is an open issue:
|
// Eager vs. lazy evaluation is an open issue:
|
||||||
// see https://github.com/unicode-org/message-format-wg/issues/299
|
// see https://github.com/unicode-org/message-format-wg/issues/299
|
||||||
|
|
||||||
|
// NFC-normalize the variable name. See
|
||||||
|
// https://github.com/unicode-org/message-format-wg/blob/main/spec/syntax.md#names-and-identifiers
|
||||||
|
const VariableName normalized = normalizeNFC(var);
|
||||||
|
|
||||||
// Look up the variable in the environment
|
// Look up the variable in the environment
|
||||||
if (env.has(var)) {
|
if (env.has(normalized)) {
|
||||||
// `var` is a local -- look it up
|
// `var` is a local -- look it up
|
||||||
const Closure& rhs = env.lookup(var);
|
const Closure& rhs = env.lookup(normalized);
|
||||||
// Format the expression using the environment from the closure
|
// Format the expression using the environment from the closure
|
||||||
return formatExpression(rhs.getEnv(), rhs.getExpr(), context, status);
|
return formatExpression(rhs.getEnv(), rhs.getExpr(), context, status);
|
||||||
}
|
}
|
||||||
// Variable wasn't found in locals -- check if it's global
|
// Variable wasn't found in locals -- check if it's global
|
||||||
FormattedPlaceholder result = evalArgument(var, context, status);
|
FormattedPlaceholder result = evalArgument(normalized, context, status);
|
||||||
if (status == U_ILLEGAL_ARGUMENT_ERROR) {
|
if (status == U_ILLEGAL_ARGUMENT_ERROR) {
|
||||||
status = U_ZERO_ERROR;
|
status = U_ZERO_ERROR;
|
||||||
// Unbound variable -- set a resolution error
|
// Unbound variable -- set a resolution error
|
||||||
@ -88,12 +96,12 @@ static Formattable evalLiteral(const Literal& lit) {
|
|||||||
// https://github.com/unicode-org/message-format-wg/blob/main/spec/formatting.md#fallback-resolution
|
// https://github.com/unicode-org/message-format-wg/blob/main/spec/formatting.md#fallback-resolution
|
||||||
UnicodeString str(DOLLAR);
|
UnicodeString str(DOLLAR);
|
||||||
str += var;
|
str += var;
|
||||||
return FormattedPlaceholder(str);
|
return create<InternalValue>(InternalValue(FormattedPlaceholder(str)), status);
|
||||||
}
|
}
|
||||||
return result;
|
return create<InternalValue>(InternalValue(std::move(result)), status);
|
||||||
} else {
|
} else {
|
||||||
U_ASSERT(rand.isLiteral());
|
U_ASSERT(rand.isLiteral());
|
||||||
return formatLiteral(rand.asLiteral());
|
return create<InternalValue>(InternalValue(formatLiteral(rand.asLiteral())), status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,28 +122,32 @@ FunctionOptions MessageFormatter::resolveOptions(const Environment& env, const O
|
|||||||
|
|
||||||
// Options are fully evaluated before calling the function
|
// Options are fully evaluated before calling the function
|
||||||
// Format the operand
|
// Format the operand
|
||||||
FormattedPlaceholder rhsVal = formatOperand(env, v, context, status);
|
LocalPointer<InternalValue> rhsVal(formatOperand(env, v, context, status));
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (!rhsVal.isFallback()) {
|
// Note: this means option values are "eagerly" evaluated.
|
||||||
resolvedOpt.adoptInstead(create<ResolvedFunctionOption>(ResolvedFunctionOption(k, rhsVal.asFormattable()), status));
|
// Currently, options don't have options. This will be addressed by the
|
||||||
if (U_FAILURE(status)) {
|
// full FormattedPlaceholder redesign.
|
||||||
return {};
|
FormattedPlaceholder optValue = rhsVal->forceFormatting(context.getErrors(), status);
|
||||||
}
|
resolvedOpt.adoptInstead(create<ResolvedFunctionOption>
|
||||||
optionsVector->adoptElement(resolvedOpt.orphan(), status);
|
(ResolvedFunctionOption(k,
|
||||||
|
optValue.asFormattable()),
|
||||||
|
status));
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
optionsVector->adoptElement(resolvedOpt.orphan(), status);
|
||||||
}
|
}
|
||||||
|
|
||||||
return FunctionOptions(std::move(*optionsVector), status);
|
return FunctionOptions(std::move(*optionsVector), status);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overload that dispatches on argument type. Syntax doesn't provide for options in this case.
|
// Overload that dispatches on argument type. Syntax doesn't provide for options in this case.
|
||||||
[[nodiscard]] FormattedPlaceholder MessageFormatter::evalFormatterCall(FormattedPlaceholder&& argument,
|
[[nodiscard]] InternalValue* MessageFormatter::evalFunctionCall(FormattedPlaceholder&& argument,
|
||||||
MessageContext& context,
|
MessageContext& context,
|
||||||
UErrorCode& status) const {
|
UErrorCode& status) const {
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
return {};
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// These cases should have been checked for already
|
// These cases should have been checked for already
|
||||||
@ -153,11 +165,11 @@ FunctionOptions MessageFormatter::resolveOptions(const Environment& env, const O
|
|||||||
// No formatter for this type -- follow default behavior
|
// No formatter for this type -- follow default behavior
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return evalFormatterCall(functionName,
|
return evalFunctionCall(functionName,
|
||||||
std::move(argument),
|
create<InternalValue>(std::move(argument), status),
|
||||||
FunctionOptions(),
|
FunctionOptions(),
|
||||||
context,
|
context,
|
||||||
status);
|
status);
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
// TODO: The array case isn't handled yet; not sure whether it's desirable
|
// TODO: The array case isn't handled yet; not sure whether it's desirable
|
||||||
@ -167,104 +179,76 @@ FunctionOptions MessageFormatter::resolveOptions(const Environment& env, const O
|
|||||||
}
|
}
|
||||||
// No formatter for this type, or it's a primitive type (which will be formatted later)
|
// No formatter for this type, or it's a primitive type (which will be formatted later)
|
||||||
// -- just return the argument itself
|
// -- just return the argument itself
|
||||||
return std::move(argument);
|
return create<InternalValue>(std::move(argument), status);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overload that dispatches on function name
|
// Overload that dispatches on function name
|
||||||
[[nodiscard]] FormattedPlaceholder MessageFormatter::evalFormatterCall(const FunctionName& functionName,
|
// Adopts `arg`
|
||||||
FormattedPlaceholder&& argument,
|
[[nodiscard]] InternalValue* MessageFormatter::evalFunctionCall(const FunctionName& functionName,
|
||||||
FunctionOptions&& options,
|
InternalValue* arg_,
|
||||||
MessageContext& context,
|
FunctionOptions&& options,
|
||||||
UErrorCode& status) const {
|
MessageContext& context,
|
||||||
|
UErrorCode& status) const {
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
DynamicErrors& errs = context.getErrors();
|
LocalPointer<InternalValue> arg(arg_);
|
||||||
|
|
||||||
UnicodeString fallback(COLON);
|
|
||||||
fallback += functionName;
|
|
||||||
if (!argument.isNullOperand()) {
|
|
||||||
fallback = argument.fallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Look up the formatter or selector
|
||||||
|
LocalPointer<Formatter> formatterImpl(nullptr);
|
||||||
|
LocalPointer<Selector> selectorImpl(nullptr);
|
||||||
if (isFormatter(functionName)) {
|
if (isFormatter(functionName)) {
|
||||||
LocalPointer<Formatter> formatterImpl(getFormatter(functionName, status));
|
formatterImpl.adoptInstead(getFormatter(functionName, status));
|
||||||
if (U_FAILURE(status)) {
|
U_ASSERT(U_SUCCESS(status));
|
||||||
if (status == U_MF_FORMATTING_ERROR) {
|
|
||||||
errs.setFormattingError(functionName, status);
|
|
||||||
status = U_ZERO_ERROR;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
if (status == U_MF_UNKNOWN_FUNCTION_ERROR) {
|
|
||||||
errs.setUnknownFunction(functionName, status);
|
|
||||||
status = U_ZERO_ERROR;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
// Other errors are non-recoverable
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
U_ASSERT(formatterImpl != nullptr);
|
|
||||||
|
|
||||||
UErrorCode savedStatus = status;
|
|
||||||
FormattedPlaceholder result = formatterImpl->format(std::move(argument), std::move(options), status);
|
|
||||||
// Update errors
|
|
||||||
if (savedStatus != status) {
|
|
||||||
if (U_FAILURE(status)) {
|
|
||||||
if (status == U_MF_OPERAND_MISMATCH_ERROR) {
|
|
||||||
status = U_ZERO_ERROR;
|
|
||||||
errs.setOperandMismatchError(functionName, status);
|
|
||||||
} else {
|
|
||||||
status = U_ZERO_ERROR;
|
|
||||||
// Convey any error generated by the formatter
|
|
||||||
// as a formatting error, except for operand mismatch errors
|
|
||||||
errs.setFormattingError(functionName, status);
|
|
||||||
}
|
|
||||||
return FormattedPlaceholder(fallback);
|
|
||||||
} else {
|
|
||||||
// Ignore warnings
|
|
||||||
status = savedStatus;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Ignore the output if any errors occurred
|
|
||||||
if (errs.hasFormattingError()) {
|
|
||||||
return FormattedPlaceholder(fallback);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
// No formatter with this name -- set error
|
|
||||||
if (isSelector(functionName)) {
|
if (isSelector(functionName)) {
|
||||||
errs.setFormattingError(functionName, status);
|
selectorImpl.adoptInstead(getSelector(context, functionName, status));
|
||||||
} else {
|
U_ASSERT(U_SUCCESS(status));
|
||||||
errs.setUnknownFunction(functionName, status);
|
|
||||||
}
|
}
|
||||||
return FormattedPlaceholder(fallback);
|
if (formatterImpl == nullptr && selectorImpl == nullptr) {
|
||||||
|
// Unknown function error
|
||||||
|
context.getErrors().setUnknownFunction(functionName, status);
|
||||||
|
|
||||||
|
if (arg->hasNullOperand()) {
|
||||||
|
// Non-selector used as selector; an error would have been recorded earlier
|
||||||
|
UnicodeString fallback(COLON);
|
||||||
|
fallback += functionName;
|
||||||
|
return new InternalValue(FormattedPlaceholder(fallback));
|
||||||
|
} else {
|
||||||
|
return new InternalValue(FormattedPlaceholder(arg->getFallback()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new InternalValue(arg.orphan(),
|
||||||
|
std::move(options),
|
||||||
|
functionName,
|
||||||
|
formatterImpl.isValid() ? formatterImpl.orphan() : nullptr,
|
||||||
|
selectorImpl.isValid() ? selectorImpl.orphan() : nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Formats an expression using `globalEnv` for the values of variables
|
// Formats an expression using `globalEnv` for the values of variables
|
||||||
[[nodiscard]] FormattedPlaceholder MessageFormatter::formatExpression(const Environment& globalEnv,
|
[[nodiscard]] InternalValue* MessageFormatter::formatExpression(const Environment& globalEnv,
|
||||||
const Expression& expr,
|
const Expression& expr,
|
||||||
MessageContext& context,
|
MessageContext& context,
|
||||||
UErrorCode &status) const {
|
UErrorCode &status) const {
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const Operand& rand = expr.getOperand();
|
const Operand& rand = expr.getOperand();
|
||||||
// Format the operand (formatOperand handles the case of a null operand)
|
// Format the operand (formatOperand handles the case of a null operand)
|
||||||
FormattedPlaceholder randVal = formatOperand(globalEnv, rand, context, status);
|
LocalPointer<InternalValue> randVal(formatOperand(globalEnv, rand, context, status));
|
||||||
|
|
||||||
// Don't call the function on error values
|
FormattedPlaceholder maybeRand = randVal->takeArgument(status);
|
||||||
if (randVal.isFallback()) {
|
|
||||||
return randVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!expr.isFunctionCall()) {
|
if (!expr.isFunctionCall() && U_SUCCESS(status)) {
|
||||||
// Dispatch based on type of `randVal`
|
// Dispatch based on type of `randVal`
|
||||||
return evalFormatterCall(std::move(randVal),
|
if (maybeRand.isFallback()) {
|
||||||
context,
|
return randVal.orphan();
|
||||||
status);
|
}
|
||||||
} else {
|
return evalFunctionCall(std::move(maybeRand), context, status);
|
||||||
|
} else if (expr.isFunctionCall()) {
|
||||||
|
status = U_ZERO_ERROR;
|
||||||
const Operator* rator = expr.getOperator(status);
|
const Operator* rator = expr.getOperator(status);
|
||||||
U_ASSERT(U_SUCCESS(status));
|
U_ASSERT(U_SUCCESS(status));
|
||||||
const FunctionName& functionName = rator->getFunctionName();
|
const FunctionName& functionName = rator->getFunctionName();
|
||||||
@ -273,19 +257,14 @@ FunctionOptions MessageFormatter::resolveOptions(const Environment& env, const O
|
|||||||
FunctionOptions resolvedOptions = resolveOptions(globalEnv, options, context, status);
|
FunctionOptions resolvedOptions = resolveOptions(globalEnv, options, context, status);
|
||||||
|
|
||||||
// Call the formatter function
|
// Call the formatter function
|
||||||
// The fallback for a nullary function call is the function name
|
return evalFunctionCall(functionName,
|
||||||
UnicodeString fallback;
|
randVal.orphan(),
|
||||||
if (rand.isNull()) {
|
std::move(resolvedOptions),
|
||||||
fallback = UnicodeString(COLON);
|
context,
|
||||||
fallback += functionName;
|
status);
|
||||||
} else {
|
} else {
|
||||||
fallback = randVal.fallback;
|
status = U_ZERO_ERROR;
|
||||||
}
|
return randVal.orphan();
|
||||||
return evalFormatterCall(functionName,
|
|
||||||
std::move(randVal),
|
|
||||||
std::move(resolvedOptions),
|
|
||||||
context,
|
|
||||||
status);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,11 +280,13 @@ void MessageFormatter::formatPattern(MessageContext& context, const Environment&
|
|||||||
// Markup is ignored
|
// Markup is ignored
|
||||||
} else {
|
} else {
|
||||||
// Format the expression
|
// Format the expression
|
||||||
FormattedPlaceholder partVal = formatExpression(globalEnv, part.contents(), context, status);
|
LocalPointer<InternalValue> partVal(
|
||||||
// Force full evaluation, e.g. applying default formatters to
|
formatExpression(globalEnv, part.contents(), context, status));
|
||||||
|
FormattedPlaceholder partResult = partVal->forceFormatting(context.getErrors(),
|
||||||
|
status);
|
||||||
|
// Force full evaluation, e.g. applying default formatters to
|
||||||
// unformatted input (or formatting numbers as strings)
|
// unformatted input (or formatting numbers as strings)
|
||||||
UnicodeString partResult = partVal.formatToString(locale, status);
|
result += partResult.formatToString(locale, status);
|
||||||
result += partResult;
|
|
||||||
// Handle formatting errors. `formatToString()` can't take a context and thus can't
|
// Handle formatting errors. `formatToString()` can't take a context and thus can't
|
||||||
// register an error directly
|
// register an error directly
|
||||||
if (status == U_MF_FORMATTING_ERROR) {
|
if (status == U_MF_FORMATTING_ERROR) {
|
||||||
@ -328,14 +309,14 @@ void MessageFormatter::resolveSelectors(MessageContext& context, const Environme
|
|||||||
CHECK_ERROR(status);
|
CHECK_ERROR(status);
|
||||||
U_ASSERT(!dataModel.hasPattern());
|
U_ASSERT(!dataModel.hasPattern());
|
||||||
|
|
||||||
const Expression* selectors = dataModel.getSelectorsInternal();
|
const VariableName* selectors = dataModel.getSelectorsInternal();
|
||||||
// 1. Let res be a new empty list of resolved values that support selection.
|
// 1. Let res be a new empty list of resolved values that support selection.
|
||||||
// (Implicit, since `res` is an out-parameter)
|
// (Implicit, since `res` is an out-parameter)
|
||||||
// 2. For each expression exp of the message's selectors
|
// 2. For each expression exp of the message's selectors
|
||||||
for (int32_t i = 0; i < dataModel.numSelectors(); i++) {
|
for (int32_t i = 0; i < dataModel.numSelectors(); i++) {
|
||||||
// 2i. Let rv be the resolved value of exp.
|
// 2i. Let rv be the resolved value of exp.
|
||||||
ResolvedSelector rv = formatSelectorExpression(env, selectors[i], context, status);
|
LocalPointer<InternalValue> rv(formatOperand(env, Operand(selectors[i]), context, status));
|
||||||
if (rv.hasSelector()) {
|
if (rv->canSelect()) {
|
||||||
// 2ii. If selection is supported for rv:
|
// 2ii. If selection is supported for rv:
|
||||||
// (True if this code has been reached)
|
// (True if this code has been reached)
|
||||||
} else {
|
} else {
|
||||||
@ -344,17 +325,17 @@ void MessageFormatter::resolveSelectors(MessageContext& context, const Environme
|
|||||||
// Append nomatch as the last element of the list res.
|
// Append nomatch as the last element of the list res.
|
||||||
// Emit a Selection Error.
|
// Emit a Selection Error.
|
||||||
// (Note: in this case, rv, being a fallback, serves as `nomatch`)
|
// (Note: in this case, rv, being a fallback, serves as `nomatch`)
|
||||||
#if U_DEBUG
|
DynamicErrors& err = context.getErrors();
|
||||||
const DynamicErrors& err = context.getErrors();
|
err.setSelectorError(rv->getFunctionName(), status);
|
||||||
U_ASSERT(err.hasError());
|
rv.adoptInstead(new InternalValue(FormattedPlaceholder(rv->getFallback())));
|
||||||
U_ASSERT(rv.argument().isFallback());
|
if (!rv.isValid()) {
|
||||||
#endif
|
status = U_MEMORY_ALLOCATION_ERROR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// 2ii(a). Append rv as the last element of the list res.
|
// 2ii(a). Append rv as the last element of the list res.
|
||||||
// (Also fulfills 2iii)
|
// (Also fulfills 2iii)
|
||||||
LocalPointer<ResolvedSelector> v(create<ResolvedSelector>(std::move(rv), status));
|
res.adoptElement(rv.orphan(), status);
|
||||||
CHECK_ERROR(status);
|
|
||||||
res.adoptElement(v.orphan(), status);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -362,18 +343,17 @@ void MessageFormatter::resolveSelectors(MessageContext& context, const Environme
|
|||||||
// `keys` and `matches` are vectors of strings
|
// `keys` and `matches` are vectors of strings
|
||||||
void MessageFormatter::matchSelectorKeys(const UVector& keys,
|
void MessageFormatter::matchSelectorKeys(const UVector& keys,
|
||||||
MessageContext& context,
|
MessageContext& context,
|
||||||
ResolvedSelector&& rv,
|
InternalValue* rv, // Does not adopt `rv`
|
||||||
UVector& keysOut,
|
UVector& keysOut,
|
||||||
UErrorCode& status) const {
|
UErrorCode& status) const {
|
||||||
CHECK_ERROR(status);
|
CHECK_ERROR(status);
|
||||||
|
|
||||||
if (!rv.hasSelector()) {
|
if (U_FAILURE(status)) {
|
||||||
// Return an empty list of matches
|
// Return an empty list of matches
|
||||||
|
status = U_ZERO_ERROR;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto selectorImpl = rv.getSelector();
|
|
||||||
U_ASSERT(selectorImpl != nullptr);
|
|
||||||
UErrorCode savedStatus = status;
|
UErrorCode savedStatus = status;
|
||||||
|
|
||||||
// Convert `keys` to an array
|
// Convert `keys` to an array
|
||||||
@ -400,15 +380,17 @@ void MessageFormatter::matchSelectorKeys(const UVector& keys,
|
|||||||
int32_t prefsLen = 0;
|
int32_t prefsLen = 0;
|
||||||
|
|
||||||
// Call the selector
|
// Call the selector
|
||||||
selectorImpl->selectKey(rv.takeArgument(), rv.takeOptions(),
|
FunctionName name = rv->getFunctionName();
|
||||||
adoptedKeys.getAlias(), keysLen, adoptedPrefs.getAlias(), prefsLen,
|
rv->forceSelection(context.getErrors(),
|
||||||
status);
|
adoptedKeys.getAlias(), keysLen,
|
||||||
|
adoptedPrefs.getAlias(), prefsLen,
|
||||||
|
status);
|
||||||
|
|
||||||
// Update errors
|
// Update errors
|
||||||
if (savedStatus != status) {
|
if (savedStatus != status) {
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
status = U_ZERO_ERROR;
|
status = U_ZERO_ERROR;
|
||||||
context.getErrors().setSelectorError(rv.getSelectorName(), status);
|
context.getErrors().setSelectorError(name, status);
|
||||||
} else {
|
} else {
|
||||||
// Ignore warnings
|
// Ignore warnings
|
||||||
status = savedStatus;
|
status = savedStatus;
|
||||||
@ -461,8 +443,8 @@ void MessageFormatter::resolvePreferences(MessageContext& context, UVector& res,
|
|||||||
if (!key.isWildcard()) {
|
if (!key.isWildcard()) {
|
||||||
// 2ii(b)(a) Assert that key is a literal.
|
// 2ii(b)(a) Assert that key is a literal.
|
||||||
// (Not needed)
|
// (Not needed)
|
||||||
// 2ii(b)(b) Let `ks` be the resolved value of `key`.
|
// 2ii(b)(b) Let `ks` be the resolved value of `key` in Unicode Normalization Form C.
|
||||||
ks = key.asLiteral().unquoted();
|
ks = normalizeNFC(key.asLiteral().unquoted());
|
||||||
// 2ii(b)(c) Append `ks` as the last element of the list `keys`.
|
// 2ii(b)(c) Append `ks` as the last element of the list `keys`.
|
||||||
ksP.adoptInstead(create<UnicodeString>(std::move(ks), status));
|
ksP.adoptInstead(create<UnicodeString>(std::move(ks), status));
|
||||||
CHECK_ERROR(status);
|
CHECK_ERROR(status);
|
||||||
@ -471,7 +453,7 @@ void MessageFormatter::resolvePreferences(MessageContext& context, UVector& res,
|
|||||||
}
|
}
|
||||||
// 2iii. Let `rv` be the resolved value at index `i` of `res`.
|
// 2iii. Let `rv` be the resolved value at index `i` of `res`.
|
||||||
U_ASSERT(i < res.size());
|
U_ASSERT(i < res.size());
|
||||||
ResolvedSelector rv = std::move(*(static_cast<ResolvedSelector*>(res[i])));
|
InternalValue* rv = static_cast<InternalValue*>(res[i]);
|
||||||
// 2iv. Let matches be the result of calling the method MatchSelectorKeys(rv, keys)
|
// 2iv. Let matches be the result of calling the method MatchSelectorKeys(rv, keys)
|
||||||
LocalPointer<UVector> matches(createUVector(status));
|
LocalPointer<UVector> matches(createUVector(status));
|
||||||
matchSelectorKeys(*keys, context, std::move(rv), *matches, status);
|
matchSelectorKeys(*keys, context, std::move(rv), *matches, status);
|
||||||
@ -523,7 +505,7 @@ void MessageFormatter::filterVariants(const UVector& pref, UVector& vars, UError
|
|||||||
// 2i(c). Assert that `key` is a literal.
|
// 2i(c). Assert that `key` is a literal.
|
||||||
// (Not needed)
|
// (Not needed)
|
||||||
// 2i(d). Let `ks` be the resolved value of `key`.
|
// 2i(d). Let `ks` be the resolved value of `key`.
|
||||||
UnicodeString ks = key.asLiteral().unquoted();
|
UnicodeString ks = normalizeNFC(key.asLiteral().unquoted());
|
||||||
// 2i(e). Let `matches` be the list of strings at index `i` of `pref`.
|
// 2i(e). Let `matches` be the list of strings at index `i` of `pref`.
|
||||||
const UVector& matches = *(static_cast<UVector*>(pref[i])); // `matches` is a vector of strings
|
const UVector& matches = *(static_cast<UVector*>(pref[i])); // `matches` is a vector of strings
|
||||||
// 2i(f). If `matches` includes `ks`
|
// 2i(f). If `matches` includes `ks`
|
||||||
@ -585,7 +567,7 @@ void MessageFormatter::sortVariants(const UVector& pref, UVector& vars, UErrorCo
|
|||||||
// 5iii(c)(a). Assert that `key` is a literal.
|
// 5iii(c)(a). Assert that `key` is a literal.
|
||||||
// (Not needed)
|
// (Not needed)
|
||||||
// 5iii(c)(b). Let `ks` be the resolved value of `key`.
|
// 5iii(c)(b). Let `ks` be the resolved value of `key`.
|
||||||
UnicodeString ks = key.asLiteral().unquoted();
|
UnicodeString ks = normalizeNFC(key.asLiteral().unquoted());
|
||||||
// 5iii(c)(c) Let matchpref be the integer position of ks in `matches`.
|
// 5iii(c)(c) Let matchpref be the integer position of ks in `matches`.
|
||||||
matchpref = vectorFind(matches, ks);
|
matchpref = vectorFind(matches, ks);
|
||||||
U_ASSERT(matchpref >= 0);
|
U_ASSERT(matchpref >= 0);
|
||||||
@ -604,123 +586,13 @@ void MessageFormatter::sortVariants(const UVector& pref, UVector& vars, UErrorCo
|
|||||||
// 7. Select the pattern of `var`
|
// 7. Select the pattern of `var`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Evaluate the operand
|
|
||||||
ResolvedSelector MessageFormatter::resolveVariables(const Environment& env, const Operand& rand, MessageContext& context, UErrorCode &status) const {
|
|
||||||
if (U_FAILURE(status)) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rand.isNull()) {
|
|
||||||
return ResolvedSelector(FormattedPlaceholder());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rand.isLiteral()) {
|
|
||||||
return ResolvedSelector(formatLiteral(rand.asLiteral()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Must be variable
|
|
||||||
const VariableName& var = rand.asVariable();
|
|
||||||
// Resolve the variable
|
|
||||||
if (env.has(var)) {
|
|
||||||
const Closure& referent = env.lookup(var);
|
|
||||||
// Resolve the referent
|
|
||||||
return resolveVariables(referent.getEnv(), referent.getExpr(), context, status);
|
|
||||||
}
|
|
||||||
// Either this is a global var or an unbound var --
|
|
||||||
// either way, it can't be bound to a function call.
|
|
||||||
// Check globals
|
|
||||||
FormattedPlaceholder val = evalArgument(var, context, status);
|
|
||||||
if (status == U_ILLEGAL_ARGUMENT_ERROR) {
|
|
||||||
status = U_ZERO_ERROR;
|
|
||||||
// Unresolved variable -- could be a previous warning. Nothing to resolve
|
|
||||||
U_ASSERT(context.getErrors().hasUnresolvedVariableError());
|
|
||||||
return ResolvedSelector(FormattedPlaceholder(var));
|
|
||||||
}
|
|
||||||
// Pass through other errors
|
|
||||||
return ResolvedSelector(std::move(val));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate the expression except for not performing the top-level function call
|
|
||||||
// (which is expected to be a selector, but may not be, in error cases)
|
|
||||||
ResolvedSelector MessageFormatter::resolveVariables(const Environment& env,
|
|
||||||
const Expression& expr,
|
|
||||||
MessageContext& context,
|
|
||||||
UErrorCode &status) const {
|
|
||||||
if (U_FAILURE(status)) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function call -- resolve the operand and options
|
|
||||||
if (expr.isFunctionCall()) {
|
|
||||||
const Operator* rator = expr.getOperator(status);
|
|
||||||
U_ASSERT(U_SUCCESS(status));
|
|
||||||
// Already checked that rator is non-reserved
|
|
||||||
const FunctionName& selectorName = rator->getFunctionName();
|
|
||||||
if (isSelector(selectorName)) {
|
|
||||||
auto selector = getSelector(context, selectorName, status);
|
|
||||||
if (U_SUCCESS(status)) {
|
|
||||||
FunctionOptions resolvedOptions = resolveOptions(env, rator->getOptionsInternal(), context, status);
|
|
||||||
// Operand may be the null argument, but resolveVariables() handles that
|
|
||||||
FormattedPlaceholder argument = formatOperand(env, expr.getOperand(), context, status);
|
|
||||||
return ResolvedSelector(selectorName, selector, std::move(resolvedOptions), std::move(argument));
|
|
||||||
}
|
|
||||||
} else if (isFormatter(selectorName)) {
|
|
||||||
context.getErrors().setSelectorError(selectorName, status);
|
|
||||||
} else {
|
|
||||||
context.getErrors().setUnknownFunction(selectorName, status);
|
|
||||||
}
|
|
||||||
// Non-selector used as selector; an error would have been recorded earlier
|
|
||||||
UnicodeString fallback(COLON);
|
|
||||||
fallback += selectorName;
|
|
||||||
if (!expr.getOperand().isNull()) {
|
|
||||||
fallback = formatOperand(env, expr.getOperand(), context, status).fallback;
|
|
||||||
}
|
|
||||||
return ResolvedSelector(FormattedPlaceholder(fallback));
|
|
||||||
} else {
|
|
||||||
// Might be a variable reference, so expand one more level of variable
|
|
||||||
return resolveVariables(env, expr.getOperand(), context, status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ResolvedSelector MessageFormatter::formatSelectorExpression(const Environment& globalEnv, const Expression& expr, MessageContext& context, UErrorCode &status) const {
|
|
||||||
if (U_FAILURE(status)) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resolve expression to determine if it's a function call
|
|
||||||
ResolvedSelector exprResult = resolveVariables(globalEnv, expr, context, status);
|
|
||||||
|
|
||||||
DynamicErrors& err = context.getErrors();
|
|
||||||
|
|
||||||
// If there is a selector, then `resolveVariables()` recorded it in the context
|
|
||||||
if (exprResult.hasSelector()) {
|
|
||||||
// Check if there was an error
|
|
||||||
if (exprResult.argument().isFallback()) {
|
|
||||||
// Use a null expression if it's a syntax or data model warning;
|
|
||||||
// create a valid (non-fallback) formatted placeholder from the
|
|
||||||
// fallback string otherwise
|
|
||||||
if (err.hasSyntaxError() || err.hasDataModelError()) {
|
|
||||||
return ResolvedSelector(FormattedPlaceholder()); // Null operand
|
|
||||||
} else {
|
|
||||||
return ResolvedSelector(exprResult.takeArgument());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return exprResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
// No selector was found; error should already have been set
|
|
||||||
U_ASSERT(err.hasMissingSelectorAnnotationError() || err.hasUnknownFunctionError() || err.hasSelectorError());
|
|
||||||
return ResolvedSelector(FormattedPlaceholder(exprResult.argument().fallback));
|
|
||||||
}
|
|
||||||
|
|
||||||
void MessageFormatter::formatSelectors(MessageContext& context, const Environment& env, UErrorCode &status, UnicodeString& result) const {
|
void MessageFormatter::formatSelectors(MessageContext& context, const Environment& env, UErrorCode &status, UnicodeString& result) const {
|
||||||
CHECK_ERROR(status);
|
CHECK_ERROR(status);
|
||||||
|
|
||||||
// See https://github.com/unicode-org/message-format-wg/blob/main/spec/formatting.md#pattern-selection
|
// See https://github.com/unicode-org/message-format-wg/blob/main/spec/formatting.md#pattern-selection
|
||||||
|
|
||||||
// Resolve Selectors
|
// Resolve Selectors
|
||||||
// res is a vector of FormattedPlaceholders
|
// res is a vector of InternalValues
|
||||||
LocalPointer<UVector> res(createUVector(status));
|
LocalPointer<UVector> res(createUVector(status));
|
||||||
CHECK_ERROR(status);
|
CHECK_ERROR(status);
|
||||||
resolveSelectors(context, env, status, *res);
|
resolveSelectors(context, env, status, *res);
|
||||||
@ -761,28 +633,35 @@ void MessageFormatter::formatSelectors(MessageContext& context, const Environmen
|
|||||||
UnicodeString MessageFormatter::formatToString(const MessageArguments& arguments, UErrorCode &status) {
|
UnicodeString MessageFormatter::formatToString(const MessageArguments& arguments, UErrorCode &status) {
|
||||||
EMPTY_ON_ERROR(status);
|
EMPTY_ON_ERROR(status);
|
||||||
|
|
||||||
// Create a new environment that will store closures for all local variables
|
|
||||||
Environment* env = Environment::create(status);
|
|
||||||
// Create a new context with the given arguments and the `errors` structure
|
// Create a new context with the given arguments and the `errors` structure
|
||||||
MessageContext context(arguments, *errors, status);
|
MessageContext context(arguments, *errors, status);
|
||||||
|
|
||||||
// Check for unresolved variable errors
|
|
||||||
checkDeclarations(context, env, status);
|
|
||||||
LocalPointer<Environment> globalEnv(env);
|
|
||||||
|
|
||||||
UnicodeString result;
|
UnicodeString result;
|
||||||
if (dataModel.hasPattern()) {
|
|
||||||
formatPattern(context, *globalEnv, dataModel.getPattern(), status, result);
|
if (!(errors->hasSyntaxError() || errors->hasDataModelError())) {
|
||||||
} else {
|
// Create a new environment that will store closures for all local variables
|
||||||
// Check for errors/warnings -- if so, then the result of pattern selection is the fallback value
|
// Check for unresolved variable errors
|
||||||
// See https://github.com/unicode-org/message-format-wg/blob/main/spec/formatting.md#pattern-selection
|
// checkDeclarations needs a reference to the pointer to the environment
|
||||||
const DynamicErrors& err = context.getErrors();
|
// since it uses its `env` argument as an out-parameter. So it needs to be
|
||||||
if (err.hasSyntaxError() || err.hasDataModelError()) {
|
// temporarily not a LocalPointer...
|
||||||
result += REPLACEMENT;
|
Environment* env(Environment::create(status));
|
||||||
|
checkDeclarations(context, env, status);
|
||||||
|
// ...and then it's adopted to avoid leaks
|
||||||
|
LocalPointer<Environment> globalEnv(env);
|
||||||
|
|
||||||
|
if (dataModel.hasPattern()) {
|
||||||
|
formatPattern(context, *globalEnv, dataModel.getPattern(), status, result);
|
||||||
} else {
|
} else {
|
||||||
formatSelectors(context, *globalEnv, status, result);
|
// Check for errors/warnings -- if so, then the result of pattern selection is the fallback value
|
||||||
|
// See https://github.com/unicode-org/message-format-wg/blob/main/spec/formatting.md#pattern-selection
|
||||||
|
const DynamicErrors& err = context.getErrors();
|
||||||
|
if (err.hasSyntaxError() || err.hasDataModelError()) {
|
||||||
|
result += REPLACEMENT;
|
||||||
|
} else {
|
||||||
|
formatSelectors(context, *globalEnv, status, result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update status according to all errors seen while formatting
|
// Update status according to all errors seen while formatting
|
||||||
if (signalErrors) {
|
if (signalErrors) {
|
||||||
context.checkErrors(status);
|
context.checkErrors(status);
|
||||||
@ -813,12 +692,14 @@ void MessageFormatter::check(MessageContext& context, const Environment& localEn
|
|||||||
|
|
||||||
// Check that variable is in scope
|
// Check that variable is in scope
|
||||||
const VariableName& var = rand.asVariable();
|
const VariableName& var = rand.asVariable();
|
||||||
|
UnicodeString normalized = normalizeNFC(var);
|
||||||
|
|
||||||
// Check local scope
|
// Check local scope
|
||||||
if (localEnv.has(var)) {
|
if (localEnv.has(normalized)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Check global scope
|
// Check global scope
|
||||||
context.getGlobal(var, status);
|
context.getGlobal(*this, normalized, status);
|
||||||
if (status == U_ILLEGAL_ARGUMENT_ERROR) {
|
if (status == U_ILLEGAL_ARGUMENT_ERROR) {
|
||||||
status = U_ZERO_ERROR;
|
status = U_ZERO_ERROR;
|
||||||
context.getErrors().setUnresolvedVariable(var, status);
|
context.getErrors().setUnresolvedVariable(var, status);
|
||||||
@ -855,7 +736,10 @@ void MessageFormatter::checkDeclarations(MessageContext& context, Environment*&
|
|||||||
// memoizing the value of localEnv up to this point
|
// memoizing the value of localEnv up to this point
|
||||||
|
|
||||||
// Add the LHS to the environment for checking the next declaration
|
// Add the LHS to the environment for checking the next declaration
|
||||||
env = Environment::create(decl.getVariable(), Closure(rhs, *env), env, status);
|
env = Environment::create(normalizeNFC(decl.getVariable()),
|
||||||
|
Closure(rhs, *env),
|
||||||
|
env,
|
||||||
|
status);
|
||||||
CHECK_ERROR(status);
|
CHECK_ERROR(status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -866,3 +750,5 @@ U_NAMESPACE_END
|
|||||||
#endif /* #if !UCONFIG_NO_MF2 */
|
#endif /* #if !UCONFIG_NO_MF2 */
|
||||||
|
|
||||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||||
|
|
||||||
|
#endif /* #if !UCONFIG_NO_NORMALIZATION */
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
#if U_SHOW_CPLUSPLUS_API
|
#if U_SHOW_CPLUSPLUS_API
|
||||||
|
|
||||||
|
#if !UCONFIG_NO_NORMALIZATION
|
||||||
|
|
||||||
#if !UCONFIG_NO_FORMATTING
|
#if !UCONFIG_NO_FORMATTING
|
||||||
|
|
||||||
#if !UCONFIG_NO_MF2
|
#if !UCONFIG_NO_MF2
|
||||||
@ -139,6 +141,8 @@ U_NAMESPACE_END
|
|||||||
|
|
||||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||||
|
|
||||||
|
#endif /* #if !UCONFIG_NO_NORMALIZATION */
|
||||||
|
|
||||||
#endif /* U_SHOW_CPLUSPLUS_API */
|
#endif /* U_SHOW_CPLUSPLUS_API */
|
||||||
|
|
||||||
#endif // MESSAGEFORMAT2_UTILS_H
|
#endif // MESSAGEFORMAT2_UTILS_H
|
||||||
|
@ -3,12 +3,16 @@
|
|||||||
|
|
||||||
#include "unicode/utypes.h"
|
#include "unicode/utypes.h"
|
||||||
|
|
||||||
|
#if !UCONFIG_NO_NORMALIZATION
|
||||||
|
|
||||||
#if !UCONFIG_NO_FORMATTING
|
#if !UCONFIG_NO_FORMATTING
|
||||||
|
|
||||||
#if !UCONFIG_NO_MF2
|
#if !UCONFIG_NO_MF2
|
||||||
|
|
||||||
|
#include "unicode/messageformat2.h"
|
||||||
#include "unicode/messageformat2_arguments.h"
|
#include "unicode/messageformat2_arguments.h"
|
||||||
#include "unicode/messageformat2_data_model_names.h"
|
#include "unicode/messageformat2_data_model_names.h"
|
||||||
|
#include "messageformat2_evaluation.h"
|
||||||
#include "uvector.h" // U_ASSERT
|
#include "uvector.h" // U_ASSERT
|
||||||
|
|
||||||
U_NAMESPACE_BEGIN
|
U_NAMESPACE_BEGIN
|
||||||
@ -22,11 +26,15 @@ namespace message2 {
|
|||||||
|
|
||||||
using Arguments = MessageArguments;
|
using Arguments = MessageArguments;
|
||||||
|
|
||||||
const Formattable* Arguments::getArgument(const VariableName& arg, UErrorCode& errorCode) const {
|
const Formattable* Arguments::getArgument(const MessageFormatter& context,
|
||||||
|
const VariableName& arg,
|
||||||
|
UErrorCode& errorCode) const {
|
||||||
if (U_SUCCESS(errorCode)) {
|
if (U_SUCCESS(errorCode)) {
|
||||||
U_ASSERT(argsLen == 0 || arguments.isValid());
|
U_ASSERT(argsLen == 0 || arguments.isValid());
|
||||||
for (int32_t i = 0; i < argsLen; i++) {
|
for (int32_t i = 0; i < argsLen; i++) {
|
||||||
if (argumentNames[i] == arg) {
|
UnicodeString normalized = context.normalizeNFC(argumentNames[i]);
|
||||||
|
// arg already assumed to be normalized
|
||||||
|
if (normalized == arg) {
|
||||||
return &arguments[i];
|
return &arguments[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -57,3 +65,5 @@ U_NAMESPACE_END
|
|||||||
#endif /* #if !UCONFIG_NO_MF2 */
|
#endif /* #if !UCONFIG_NO_MF2 */
|
||||||
|
|
||||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||||
|
|
||||||
|
#endif /* #if !UCONFIG_NO_NORMALIZATION */
|
||||||
|
@ -3,12 +3,16 @@
|
|||||||
|
|
||||||
#include "unicode/utypes.h"
|
#include "unicode/utypes.h"
|
||||||
|
|
||||||
|
#if !UCONFIG_NO_NORMALIZATION
|
||||||
|
|
||||||
#if !UCONFIG_NO_FORMATTING
|
#if !UCONFIG_NO_FORMATTING
|
||||||
|
|
||||||
#if !UCONFIG_NO_MF2
|
#if !UCONFIG_NO_MF2
|
||||||
|
|
||||||
|
#include "unicode/messageformat2.h"
|
||||||
#include "messageformat2_allocation.h"
|
#include "messageformat2_allocation.h"
|
||||||
#include "messageformat2_checker.h"
|
#include "messageformat2_checker.h"
|
||||||
|
#include "messageformat2_evaluation.h"
|
||||||
#include "messageformat2_macros.h"
|
#include "messageformat2_macros.h"
|
||||||
#include "uvector.h" // U_ASSERT
|
#include "uvector.h" // U_ASSERT
|
||||||
|
|
||||||
@ -104,6 +108,14 @@ TypeEnvironment::~TypeEnvironment() {}
|
|||||||
|
|
||||||
// ---------------------
|
// ---------------------
|
||||||
|
|
||||||
|
Key Checker::normalizeNFC(const Key& k) const {
|
||||||
|
if (k.isWildcard()) {
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
return Key(Literal(k.asLiteral().isQuoted(),
|
||||||
|
context.normalizeNFC(k.asLiteral().unquoted())));
|
||||||
|
}
|
||||||
|
|
||||||
static bool areDefaultKeys(const Key* keys, int32_t len) {
|
static bool areDefaultKeys(const Key* keys, int32_t len) {
|
||||||
U_ASSERT(len > 0);
|
U_ASSERT(len > 0);
|
||||||
for (int32_t i = 0; i < len; i++) {
|
for (int32_t i = 0; i < len; i++) {
|
||||||
@ -185,7 +197,7 @@ void Checker::checkVariants(UErrorCode& status) {
|
|||||||
// This variant was already checked,
|
// This variant was already checked,
|
||||||
// so we know keys1.len == len
|
// so we know keys1.len == len
|
||||||
for (int32_t kk = 0; kk < len; kk++) {
|
for (int32_t kk = 0; kk < len; kk++) {
|
||||||
if (!(keys[kk] == keys1[kk])) {
|
if (!(normalizeNFC(keys[kk]) == normalizeNFC(keys1[kk]))) {
|
||||||
allEqual = false;
|
allEqual = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -205,18 +217,14 @@ void Checker::checkVariants(UErrorCode& status) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Checker::requireAnnotated(const TypeEnvironment& t, const Expression& selectorExpr, UErrorCode& status) {
|
void Checker::requireAnnotated(const TypeEnvironment& t,
|
||||||
|
const VariableName& selectorVar,
|
||||||
|
UErrorCode& status) {
|
||||||
CHECK_ERROR(status);
|
CHECK_ERROR(status);
|
||||||
|
|
||||||
if (selectorExpr.isFunctionCall()) {
|
if (t.get(selectorVar) == TypeEnvironment::Type::Annotated) {
|
||||||
return; // No error
|
return; // No error
|
||||||
}
|
}
|
||||||
const Operand& rand = selectorExpr.getOperand();
|
|
||||||
if (rand.isVariable()) {
|
|
||||||
if (t.get(rand.asVariable()) == TypeEnvironment::Type::Annotated) {
|
|
||||||
return; // No error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If this code is reached, an error was detected
|
// If this code is reached, an error was detected
|
||||||
errors.addError(StaticErrorType::MissingSelectorAnnotation, status);
|
errors.addError(StaticErrorType::MissingSelectorAnnotation, status);
|
||||||
}
|
}
|
||||||
@ -226,7 +234,7 @@ void Checker::checkSelectors(const TypeEnvironment& t, UErrorCode& status) {
|
|||||||
|
|
||||||
// Check each selector; if it's not annotated, emit a
|
// Check each selector; if it's not annotated, emit a
|
||||||
// "missing selector annotation" error
|
// "missing selector annotation" error
|
||||||
const Expression* selectors = dataModel.getSelectorsInternal();
|
const VariableName* selectors = dataModel.getSelectorsInternal();
|
||||||
for (int32_t i = 0; i < dataModel.numSelectors(); i++) {
|
for (int32_t i = 0; i < dataModel.numSelectors(); i++) {
|
||||||
requireAnnotated(t, selectors[i], status);
|
requireAnnotated(t, selectors[i], status);
|
||||||
}
|
}
|
||||||
@ -312,3 +320,5 @@ U_NAMESPACE_END
|
|||||||
#endif /* #if !UCONFIG_NO_MF2 */
|
#endif /* #if !UCONFIG_NO_MF2 */
|
||||||
|
|
||||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||||
|
|
||||||
|
#endif /* #if !UCONFIG_NO_NORMALIZATION */
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
#if U_SHOW_CPLUSPLUS_API
|
#if U_SHOW_CPLUSPLUS_API
|
||||||
|
|
||||||
|
#if !UCONFIG_NO_NORMALIZATION
|
||||||
|
|
||||||
#if !UCONFIG_NO_FORMATTING
|
#if !UCONFIG_NO_FORMATTING
|
||||||
|
|
||||||
#if !UCONFIG_NO_MF2
|
#if !UCONFIG_NO_MF2
|
||||||
@ -56,15 +58,20 @@ namespace message2 {
|
|||||||
// an explicit declaration
|
// an explicit declaration
|
||||||
}; // class TypeEnvironment
|
}; // class TypeEnvironment
|
||||||
|
|
||||||
|
class MessageFormatter;
|
||||||
|
|
||||||
// Checks a data model for semantic errors
|
// Checks a data model for semantic errors
|
||||||
// (Errors are defined in https://github.com/unicode-org/message-format-wg/blob/main/spec/formatting.md )
|
// (Errors are defined in https://github.com/unicode-org/message-format-wg/blob/main/spec/formatting.md )
|
||||||
class Checker {
|
class Checker {
|
||||||
public:
|
public:
|
||||||
void check(UErrorCode&);
|
void check(UErrorCode&);
|
||||||
Checker(const MFDataModel& m, StaticErrors& e) : dataModel(m), errors(e) {}
|
Checker(const MFDataModel& d, StaticErrors& e, const MessageFormatter& mf)
|
||||||
|
: dataModel(d), errors(e), context(mf) {}
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void requireAnnotated(const TypeEnvironment&, const Expression&, UErrorCode&);
|
Key normalizeNFC(const Key&) const;
|
||||||
|
|
||||||
|
void requireAnnotated(const TypeEnvironment&, const VariableName&, UErrorCode&);
|
||||||
void addFreeVars(TypeEnvironment& t, const Operand&, UErrorCode&);
|
void addFreeVars(TypeEnvironment& t, const Operand&, UErrorCode&);
|
||||||
void addFreeVars(TypeEnvironment& t, const Operator&, UErrorCode&);
|
void addFreeVars(TypeEnvironment& t, const Operator&, UErrorCode&);
|
||||||
void addFreeVars(TypeEnvironment& t, const OptionMap&, UErrorCode&);
|
void addFreeVars(TypeEnvironment& t, const OptionMap&, UErrorCode&);
|
||||||
@ -78,6 +85,9 @@ namespace message2 {
|
|||||||
void check(const Pattern&);
|
void check(const Pattern&);
|
||||||
const MFDataModel& dataModel;
|
const MFDataModel& dataModel;
|
||||||
StaticErrors& errors;
|
StaticErrors& errors;
|
||||||
|
|
||||||
|
// Used for NFC normalization
|
||||||
|
const MessageFormatter& context;
|
||||||
}; // class Checker
|
}; // class Checker
|
||||||
|
|
||||||
} // namespace message2
|
} // namespace message2
|
||||||
@ -88,6 +98,8 @@ U_NAMESPACE_END
|
|||||||
|
|
||||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||||
|
|
||||||
|
#endif /* #if !UCONFIG_NO_NORMALIZATION */
|
||||||
|
|
||||||
#endif /* U_SHOW_CPLUSPLUS_API */
|
#endif /* U_SHOW_CPLUSPLUS_API */
|
||||||
|
|
||||||
#endif // MESSAGEFORMAT_CHECKER_H
|
#endif // MESSAGEFORMAT_CHECKER_H
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include "unicode/utypes.h"
|
#include "unicode/utypes.h"
|
||||||
|
|
||||||
|
#if !UCONFIG_NO_NORMALIZATION
|
||||||
|
|
||||||
#if !UCONFIG_NO_FORMATTING
|
#if !UCONFIG_NO_FORMATTING
|
||||||
|
|
||||||
#if !UCONFIG_NO_MF2
|
#if !UCONFIG_NO_MF2
|
||||||
@ -691,9 +693,9 @@ Matcher::Matcher(const Matcher& other) {
|
|||||||
numSelectors = other.numSelectors;
|
numSelectors = other.numSelectors;
|
||||||
numVariants = other.numVariants;
|
numVariants = other.numVariants;
|
||||||
UErrorCode localErrorCode = U_ZERO_ERROR;
|
UErrorCode localErrorCode = U_ZERO_ERROR;
|
||||||
selectors.adoptInstead(copyArray<Expression>(other.selectors.getAlias(),
|
selectors.adoptInstead(copyArray<VariableName>(other.selectors.getAlias(),
|
||||||
numSelectors,
|
numSelectors,
|
||||||
localErrorCode));
|
localErrorCode));
|
||||||
variants.adoptInstead(copyArray<Variant>(other.variants.getAlias(),
|
variants.adoptInstead(copyArray<Variant>(other.variants.getAlias(),
|
||||||
numVariants,
|
numVariants,
|
||||||
localErrorCode));
|
localErrorCode));
|
||||||
@ -702,7 +704,7 @@ Matcher::Matcher(const Matcher& other) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Matcher::Matcher(Expression* ss, int32_t ns, Variant* vs, int32_t nv)
|
Matcher::Matcher(VariableName* ss, int32_t ns, Variant* vs, int32_t nv)
|
||||||
: selectors(ss), numSelectors(ns), variants(vs), numVariants(nv) {}
|
: selectors(ss), numSelectors(ns), variants(vs), numVariants(nv) {}
|
||||||
|
|
||||||
Matcher::~Matcher() {}
|
Matcher::~Matcher() {}
|
||||||
@ -724,7 +726,7 @@ const Binding* MFDataModel::getLocalVariablesInternal() const {
|
|||||||
return bindings.getAlias();
|
return bindings.getAlias();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Expression* MFDataModel::getSelectorsInternal() const {
|
const VariableName* MFDataModel::getSelectorsInternal() const {
|
||||||
U_ASSERT(!bogus);
|
U_ASSERT(!bogus);
|
||||||
U_ASSERT(!hasPattern());
|
U_ASSERT(!hasPattern());
|
||||||
return std::get_if<Matcher>(&body)->selectors.getAlias();
|
return std::get_if<Matcher>(&body)->selectors.getAlias();
|
||||||
@ -786,15 +788,13 @@ MFDataModel::Builder& MFDataModel::Builder::addBinding(Binding&& b, UErrorCode&
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
MFDataModel::Builder& MFDataModel::Builder::addSelector(VariableName&& selector,
|
||||||
selector must be non-null
|
UErrorCode& status) {
|
||||||
*/
|
|
||||||
MFDataModel::Builder& MFDataModel::Builder::addSelector(Expression&& selector, UErrorCode& status) noexcept {
|
|
||||||
THIS_ON_ERROR(status);
|
THIS_ON_ERROR(status);
|
||||||
|
|
||||||
buildSelectorsMessage(status);
|
buildSelectorsMessage(status);
|
||||||
U_ASSERT(selectors != nullptr);
|
U_ASSERT(selectors != nullptr);
|
||||||
selectors->adoptElement(create<Expression>(std::move(selector), status), status);
|
selectors->adoptElement(create<VariableName>(std::move(selector), status), status);
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -830,11 +830,11 @@ MFDataModel::MFDataModel(const MFDataModel& other) : body(Pattern()) {
|
|||||||
if (other.hasPattern()) {
|
if (other.hasPattern()) {
|
||||||
body = *std::get_if<Pattern>(&other.body);
|
body = *std::get_if<Pattern>(&other.body);
|
||||||
} else {
|
} else {
|
||||||
const Expression* otherSelectors = other.getSelectorsInternal();
|
const VariableName* otherSelectors = other.getSelectorsInternal();
|
||||||
const Variant* otherVariants = other.getVariantsInternal();
|
const Variant* otherVariants = other.getVariantsInternal();
|
||||||
int32_t numSelectors = other.numSelectors();
|
int32_t numSelectors = other.numSelectors();
|
||||||
int32_t numVariants = other.numVariants();
|
int32_t numVariants = other.numVariants();
|
||||||
Expression* copiedSelectors = copyArray(otherSelectors, numSelectors, localErrorCode);
|
VariableName* copiedSelectors = copyArray(otherSelectors, numSelectors, localErrorCode);
|
||||||
Variant* copiedVariants = copyArray(otherVariants, numVariants, localErrorCode);
|
Variant* copiedVariants = copyArray(otherVariants, numVariants, localErrorCode);
|
||||||
if (U_FAILURE(localErrorCode)) {
|
if (U_FAILURE(localErrorCode)) {
|
||||||
bogus = true;
|
bogus = true;
|
||||||
@ -863,7 +863,9 @@ MFDataModel::MFDataModel(const MFDataModel::Builder& builder, UErrorCode& errorC
|
|||||||
int32_t numVariants = builder.variants->size();
|
int32_t numVariants = builder.variants->size();
|
||||||
int32_t numSelectors = builder.selectors->size();
|
int32_t numSelectors = builder.selectors->size();
|
||||||
LocalArray<Variant> variants(copyVectorToArray<Variant>(*builder.variants, errorCode), errorCode);
|
LocalArray<Variant> variants(copyVectorToArray<Variant>(*builder.variants, errorCode), errorCode);
|
||||||
LocalArray<Expression> selectors(copyVectorToArray<Expression>(*builder.selectors, errorCode), errorCode);
|
LocalArray<VariableName> selectors(copyVectorToArray<VariableName>(*builder.selectors,
|
||||||
|
errorCode),
|
||||||
|
errorCode);
|
||||||
if (U_FAILURE(errorCode)) {
|
if (U_FAILURE(errorCode)) {
|
||||||
bogus = true;
|
bogus = true;
|
||||||
return;
|
return;
|
||||||
@ -918,3 +920,5 @@ U_NAMESPACE_END
|
|||||||
#endif /* #if !UCONFIG_NO_MF2 */
|
#endif /* #if !UCONFIG_NO_MF2 */
|
||||||
|
|
||||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||||
|
|
||||||
|
#endif /* #if !UCONFIG_NO_NORMALIZATION */
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include "unicode/utypes.h"
|
#include "unicode/utypes.h"
|
||||||
|
|
||||||
|
#if !UCONFIG_NO_NORMALIZATION
|
||||||
|
|
||||||
#if !UCONFIG_NO_FORMATTING
|
#if !UCONFIG_NO_FORMATTING
|
||||||
|
|
||||||
#if !UCONFIG_NO_MF2
|
#if !UCONFIG_NO_MF2
|
||||||
@ -290,3 +292,5 @@ U_NAMESPACE_END
|
|||||||
#endif /* #if !UCONFIG_NO_MF2 */
|
#endif /* #if !UCONFIG_NO_MF2 */
|
||||||
|
|
||||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||||
|
|
||||||
|
#endif /* #if !UCONFIG_NO_NORMALIZATION */
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
* \brief C++ API: Formats messages using the draft MessageFormat 2.0.
|
* \brief C++ API: Formats messages using the draft MessageFormat 2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#if !UCONFIG_NO_NORMALIZATION
|
||||||
|
|
||||||
#if !UCONFIG_NO_FORMATTING
|
#if !UCONFIG_NO_FORMATTING
|
||||||
|
|
||||||
#if !UCONFIG_NO_MF2
|
#if !UCONFIG_NO_MF2
|
||||||
@ -151,6 +153,8 @@ U_NAMESPACE_END
|
|||||||
|
|
||||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||||
|
|
||||||
|
#endif /* #if !UCONFIG_NO_NORMALIZATION */
|
||||||
|
|
||||||
#endif /* U_SHOW_CPLUSPLUS_API */
|
#endif /* U_SHOW_CPLUSPLUS_API */
|
||||||
|
|
||||||
#endif // MESSAGEFORMAT2_ERRORS_H
|
#endif // MESSAGEFORMAT2_ERRORS_H
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include "unicode/utypes.h"
|
#include "unicode/utypes.h"
|
||||||
|
|
||||||
|
#if !UCONFIG_NO_NORMALIZATION
|
||||||
|
|
||||||
#if !UCONFIG_NO_FORMATTING
|
#if !UCONFIG_NO_FORMATTING
|
||||||
|
|
||||||
#if !UCONFIG_NO_MF2
|
#if !UCONFIG_NO_MF2
|
||||||
@ -89,35 +91,54 @@ FunctionOptions::FunctionOptions(FunctionOptions&& other) {
|
|||||||
FunctionOptions::~FunctionOptions() {
|
FunctionOptions::~FunctionOptions() {
|
||||||
if (options != nullptr) {
|
if (options != nullptr) {
|
||||||
delete[] options;
|
delete[] options;
|
||||||
|
options = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ResolvedSelector
|
|
||||||
// ----------------
|
|
||||||
|
|
||||||
ResolvedSelector::ResolvedSelector(const FunctionName& fn,
|
static bool containsOption(const UVector& opts, const ResolvedFunctionOption& opt) {
|
||||||
Selector* sel,
|
for (int32_t i = 0; i < opts.size(); i++) {
|
||||||
FunctionOptions&& opts,
|
if (static_cast<ResolvedFunctionOption*>(opts[i])->getName()
|
||||||
FormattedPlaceholder&& val)
|
== opt.getName()) {
|
||||||
: selectorName(fn), selector(sel), options(std::move(opts)), value(std::move(val)) {
|
return true;
|
||||||
U_ASSERT(sel != nullptr);
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResolvedSelector::ResolvedSelector(FormattedPlaceholder&& val) : value(std::move(val)) {}
|
// Options in `this` take precedence
|
||||||
|
// `this` can't be used after mergeOptions is called
|
||||||
|
FunctionOptions FunctionOptions::mergeOptions(FunctionOptions&& other,
|
||||||
|
UErrorCode& status) {
|
||||||
|
UVector mergedOptions(status);
|
||||||
|
mergedOptions.setDeleter(uprv_deleteUObject);
|
||||||
|
|
||||||
ResolvedSelector& ResolvedSelector::operator=(ResolvedSelector&& other) noexcept {
|
if (U_FAILURE(status)) {
|
||||||
selectorName = std::move(other.selectorName);
|
return {};
|
||||||
selector.adoptInstead(other.selector.orphan());
|
}
|
||||||
options = std::move(other.options);
|
|
||||||
value = std::move(other.value);
|
// Create a new vector consisting of the options from this `FunctionOptions`
|
||||||
return *this;
|
for (int32_t i = 0; i < functionOptionsLen; i++) {
|
||||||
|
mergedOptions.adoptElement(create<ResolvedFunctionOption>(std::move(options[i]), status),
|
||||||
|
status);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add each option from `other` that doesn't appear in this `FunctionOptions`
|
||||||
|
for (int i = 0; i < other.functionOptionsLen; i++) {
|
||||||
|
// Note: this is quadratic in the length of `options`
|
||||||
|
if (!containsOption(mergedOptions, other.options[i])) {
|
||||||
|
mergedOptions.adoptElement(create<ResolvedFunctionOption>(std::move(other.options[i]),
|
||||||
|
status),
|
||||||
|
status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] options;
|
||||||
|
options = nullptr;
|
||||||
|
functionOptionsLen = 0;
|
||||||
|
|
||||||
|
return FunctionOptions(std::move(mergedOptions), status);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResolvedSelector::ResolvedSelector(ResolvedSelector&& other) {
|
|
||||||
*this = std::move(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
ResolvedSelector::~ResolvedSelector() {}
|
|
||||||
|
|
||||||
// PrioritizedVariant
|
// PrioritizedVariant
|
||||||
// ------------------
|
// ------------------
|
||||||
|
|
||||||
@ -190,18 +211,210 @@ PrioritizedVariant::~PrioritizedVariant() {}
|
|||||||
errors.checkErrors(status);
|
errors.checkErrors(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Formattable* MessageContext::getGlobal(const VariableName& v, UErrorCode& errorCode) const {
|
const Formattable* MessageContext::getGlobal(const MessageFormatter& context,
|
||||||
return arguments.getArgument(v, errorCode);
|
const VariableName& v,
|
||||||
|
UErrorCode& errorCode) const {
|
||||||
|
return arguments.getArgument(context, v, errorCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageContext::MessageContext(const MessageArguments& args,
|
MessageContext::MessageContext(const MessageArguments& args,
|
||||||
const StaticErrors& e,
|
const StaticErrors& e,
|
||||||
UErrorCode& status) : arguments(args), errors(e, status) {}
|
UErrorCode& status) : arguments(args), errors(e, status) {}
|
||||||
|
|
||||||
MessageContext::~MessageContext() {}
|
MessageContext::~MessageContext() {}
|
||||||
|
|
||||||
|
// InternalValue
|
||||||
|
// -------------
|
||||||
|
|
||||||
|
bool InternalValue::isFallback() const {
|
||||||
|
return std::holds_alternative<FormattedPlaceholder>(argument)
|
||||||
|
&& std::get_if<FormattedPlaceholder>(&argument)->isFallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InternalValue::hasNullOperand() const {
|
||||||
|
return std::holds_alternative<FormattedPlaceholder>(argument)
|
||||||
|
&& std::get_if<FormattedPlaceholder>(&argument)->isNullOperand();
|
||||||
|
}
|
||||||
|
|
||||||
|
FormattedPlaceholder InternalValue::takeArgument(UErrorCode& errorCode) {
|
||||||
|
if (U_FAILURE(errorCode)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::holds_alternative<FormattedPlaceholder>(argument)) {
|
||||||
|
return std::move(*std::get_if<FormattedPlaceholder>(&argument));
|
||||||
|
}
|
||||||
|
errorCode = U_ILLEGAL_ARGUMENT_ERROR;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const UnicodeString& InternalValue::getFallback() const {
|
||||||
|
if (std::holds_alternative<FormattedPlaceholder>(argument)) {
|
||||||
|
return std::get_if<FormattedPlaceholder>(&argument)->getFallback();
|
||||||
|
}
|
||||||
|
return (*std::get_if<InternalValue*>(&argument))->getFallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
const Selector* InternalValue::getSelector(UErrorCode& errorCode) const {
|
||||||
|
if (U_FAILURE(errorCode)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selector == nullptr) {
|
||||||
|
errorCode = U_ILLEGAL_ARGUMENT_ERROR;
|
||||||
|
}
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
|
||||||
|
InternalValue::InternalValue(FormattedPlaceholder&& arg) {
|
||||||
|
argument = std::move(arg);
|
||||||
|
selector = nullptr;
|
||||||
|
formatter = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
InternalValue::InternalValue(InternalValue* operand,
|
||||||
|
FunctionOptions&& opts,
|
||||||
|
const FunctionName& functionName,
|
||||||
|
const Formatter* f,
|
||||||
|
const Selector* s) {
|
||||||
|
argument = operand;
|
||||||
|
options = std::move(opts);
|
||||||
|
name = functionName;
|
||||||
|
selector = s;
|
||||||
|
formatter = f;
|
||||||
|
U_ASSERT(selector != nullptr || formatter != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// `this` cannot be used after calling this method
|
||||||
|
void InternalValue::forceSelection(DynamicErrors& errs,
|
||||||
|
const UnicodeString* keys,
|
||||||
|
int32_t keysLen,
|
||||||
|
UnicodeString* prefs,
|
||||||
|
int32_t& prefsLen,
|
||||||
|
UErrorCode& errorCode) {
|
||||||
|
if (U_FAILURE(errorCode)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!canSelect()) {
|
||||||
|
errorCode = U_ILLEGAL_ARGUMENT_ERROR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Find the argument and complete set of options by traversing `argument`
|
||||||
|
FunctionOptions opts;
|
||||||
|
InternalValue* p = this;
|
||||||
|
FunctionName selectorName = name;
|
||||||
|
while (std::holds_alternative<InternalValue*>(p->argument)) {
|
||||||
|
if (p->name != selectorName) {
|
||||||
|
// Can only compose calls to the same selector
|
||||||
|
errorCode = U_ILLEGAL_ARGUMENT_ERROR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// First argument to mergeOptions takes precedence
|
||||||
|
opts = opts.mergeOptions(std::move(p->options), errorCode);
|
||||||
|
if (U_FAILURE(errorCode)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
InternalValue* next = *std::get_if<InternalValue*>(&p->argument);
|
||||||
|
p = next;
|
||||||
|
}
|
||||||
|
FormattedPlaceholder arg = std::move(*std::get_if<FormattedPlaceholder>(&p->argument));
|
||||||
|
|
||||||
|
selector->selectKey(std::move(arg), std::move(opts),
|
||||||
|
keys, keysLen,
|
||||||
|
prefs, prefsLen, errorCode);
|
||||||
|
if (U_FAILURE(errorCode)) {
|
||||||
|
errorCode = U_ZERO_ERROR;
|
||||||
|
errs.setSelectorError(selectorName, errorCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FormattedPlaceholder InternalValue::forceFormatting(DynamicErrors& errs, UErrorCode& errorCode) {
|
||||||
|
if (U_FAILURE(errorCode)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (formatter == nullptr && selector == nullptr) {
|
||||||
|
U_ASSERT(std::holds_alternative<FormattedPlaceholder>(argument));
|
||||||
|
return std::move(*std::get_if<FormattedPlaceholder>(&argument));
|
||||||
|
}
|
||||||
|
if (formatter == nullptr) {
|
||||||
|
errorCode = U_ILLEGAL_ARGUMENT_ERROR;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
FormattedPlaceholder arg;
|
||||||
|
|
||||||
|
if (std::holds_alternative<FormattedPlaceholder>(argument)) {
|
||||||
|
arg = std::move(*std::get_if<FormattedPlaceholder>(&argument));
|
||||||
|
} else {
|
||||||
|
arg = (*std::get_if<InternalValue*>(&argument))->forceFormatting(errs,
|
||||||
|
errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (U_FAILURE(errorCode)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// The fallback for a nullary function call is the function name
|
||||||
|
UnicodeString fallback;
|
||||||
|
if (arg.isNullOperand()) {
|
||||||
|
fallback = u":";
|
||||||
|
fallback += name;
|
||||||
|
} else {
|
||||||
|
fallback = arg.getFallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call the function with the argument
|
||||||
|
FormattedPlaceholder result = formatter->format(std::move(arg), std::move(options), errorCode);
|
||||||
|
if (U_FAILURE(errorCode)) {
|
||||||
|
if (errorCode == U_MF_OPERAND_MISMATCH_ERROR) {
|
||||||
|
errorCode = U_ZERO_ERROR;
|
||||||
|
errs.setOperandMismatchError(name, errorCode);
|
||||||
|
} else {
|
||||||
|
errorCode = U_ZERO_ERROR;
|
||||||
|
// Convey any error generated by the formatter
|
||||||
|
// as a formatting error, except for operand mismatch errors
|
||||||
|
errs.setFormattingError(name, errorCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Ignore the output if any error occurred
|
||||||
|
if (errs.hasFormattingError()) {
|
||||||
|
return FormattedPlaceholder(fallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
InternalValue& InternalValue::operator=(InternalValue&& other) noexcept {
|
||||||
|
argument = std::move(other.argument);
|
||||||
|
other.argument = nullptr;
|
||||||
|
options = std::move(other.options);
|
||||||
|
name = other.name;
|
||||||
|
selector = other.selector;
|
||||||
|
formatter = other.formatter;
|
||||||
|
other.selector = nullptr;
|
||||||
|
other.formatter = nullptr;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
InternalValue::~InternalValue() {
|
||||||
|
delete selector;
|
||||||
|
selector = nullptr;
|
||||||
|
delete formatter;
|
||||||
|
formatter = nullptr;
|
||||||
|
if (std::holds_alternative<InternalValue*>(argument)) {
|
||||||
|
delete *std::get_if<InternalValue*>(&argument);
|
||||||
|
argument = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace message2
|
} // namespace message2
|
||||||
U_NAMESPACE_END
|
U_NAMESPACE_END
|
||||||
|
|
||||||
#endif /* #if !UCONFIG_NO_MF2 */
|
#endif /* #if !UCONFIG_NO_MF2 */
|
||||||
|
|
||||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||||
|
|
||||||
|
#endif /* #if !UCONFIG_NO_NORMALIZATION */
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
* \file
|
* \file
|
||||||
* \brief C++ API: Formats messages using the draft MessageFormat 2.0.
|
* \brief C++ API: Formats messages using the draft MessageFormat 2.0.
|
||||||
*/
|
*/
|
||||||
|
#if !UCONFIG_NO_NORMALIZATION
|
||||||
|
|
||||||
#if !UCONFIG_NO_FORMATTING
|
#if !UCONFIG_NO_FORMATTING
|
||||||
|
|
||||||
@ -63,38 +64,6 @@ namespace message2 {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encapsulates a value to be scrutinized by a `match` with its resolved
|
|
||||||
// options and the name of the selector
|
|
||||||
class ResolvedSelector : public UObject {
|
|
||||||
public:
|
|
||||||
ResolvedSelector() {}
|
|
||||||
ResolvedSelector(const FunctionName& fn,
|
|
||||||
Selector* selector,
|
|
||||||
FunctionOptions&& options,
|
|
||||||
FormattedPlaceholder&& value);
|
|
||||||
// Used either for errors, or when selector isn't yet known
|
|
||||||
explicit ResolvedSelector(FormattedPlaceholder&& value);
|
|
||||||
bool hasSelector() const { return selector.isValid(); }
|
|
||||||
const FormattedPlaceholder& argument() const { return value; }
|
|
||||||
FormattedPlaceholder&& takeArgument() { return std::move(value); }
|
|
||||||
const Selector* getSelector() {
|
|
||||||
U_ASSERT(selector.isValid());
|
|
||||||
return selector.getAlias();
|
|
||||||
}
|
|
||||||
FunctionOptions&& takeOptions() {
|
|
||||||
return std::move(options);
|
|
||||||
}
|
|
||||||
const FunctionName& getSelectorName() const { return selectorName; }
|
|
||||||
virtual ~ResolvedSelector();
|
|
||||||
ResolvedSelector& operator=(ResolvedSelector&&) noexcept;
|
|
||||||
ResolvedSelector(ResolvedSelector&&);
|
|
||||||
private:
|
|
||||||
FunctionName selectorName; // For error reporting
|
|
||||||
LocalPointer<Selector> selector;
|
|
||||||
FunctionOptions options;
|
|
||||||
FormattedPlaceholder value;
|
|
||||||
}; // class ResolvedSelector
|
|
||||||
|
|
||||||
// Closures and environments
|
// Closures and environments
|
||||||
// -------------------------
|
// -------------------------
|
||||||
|
|
||||||
@ -174,11 +143,15 @@ namespace message2 {
|
|||||||
// The context contains all the information needed to process
|
// The context contains all the information needed to process
|
||||||
// an entire message: arguments, formatter cache, and error list
|
// an entire message: arguments, formatter cache, and error list
|
||||||
|
|
||||||
|
class MessageFormatter;
|
||||||
|
|
||||||
class MessageContext : public UMemory {
|
class MessageContext : public UMemory {
|
||||||
public:
|
public:
|
||||||
MessageContext(const MessageArguments&, const StaticErrors&, UErrorCode&);
|
MessageContext(const MessageArguments&, const StaticErrors&, UErrorCode&);
|
||||||
|
|
||||||
const Formattable* getGlobal(const VariableName&, UErrorCode&) const;
|
const Formattable* getGlobal(const MessageFormatter&,
|
||||||
|
const VariableName&,
|
||||||
|
UErrorCode&) const;
|
||||||
|
|
||||||
// If any errors were set, update `status` accordingly
|
// If any errors were set, update `status` accordingly
|
||||||
void checkErrors(UErrorCode& status) const;
|
void checkErrors(UErrorCode& status) const;
|
||||||
@ -191,8 +164,47 @@ namespace message2 {
|
|||||||
const MessageArguments& arguments; // External message arguments
|
const MessageArguments& arguments; // External message arguments
|
||||||
// Errors accumulated during parsing/formatting
|
// Errors accumulated during parsing/formatting
|
||||||
DynamicErrors errors;
|
DynamicErrors errors;
|
||||||
|
|
||||||
}; // class MessageContext
|
}; // class MessageContext
|
||||||
|
|
||||||
|
// InternalValue
|
||||||
|
// ----------------
|
||||||
|
|
||||||
|
class InternalValue : public UObject {
|
||||||
|
public:
|
||||||
|
const FunctionName& getFunctionName() const { return name; }
|
||||||
|
bool canSelect() const { return selector != nullptr; }
|
||||||
|
const Selector* getSelector(UErrorCode&) const;
|
||||||
|
FormattedPlaceholder forceFormatting(DynamicErrors& errs,
|
||||||
|
UErrorCode& errorCode);
|
||||||
|
void forceSelection(DynamicErrors& errs,
|
||||||
|
const UnicodeString* keys,
|
||||||
|
int32_t keysLen,
|
||||||
|
UnicodeString* prefs,
|
||||||
|
int32_t& prefsLen,
|
||||||
|
UErrorCode& errorCode);
|
||||||
|
// Needs to be deep-copyable and movable
|
||||||
|
virtual ~InternalValue();
|
||||||
|
InternalValue(FormattedPlaceholder&&);
|
||||||
|
// Formatter and selector may be null
|
||||||
|
InternalValue(InternalValue*, FunctionOptions&&, const FunctionName&, const Formatter*,
|
||||||
|
const Selector*);
|
||||||
|
const UnicodeString& getFallback() const;
|
||||||
|
bool isFallback() const;
|
||||||
|
bool hasNullOperand() const;
|
||||||
|
// Can't be used anymore after calling this
|
||||||
|
FormattedPlaceholder takeArgument(UErrorCode& errorCode);
|
||||||
|
InternalValue(InternalValue&& other) { *this = std::move(other); }
|
||||||
|
InternalValue& operator=(InternalValue&& other) noexcept;
|
||||||
|
private:
|
||||||
|
// InternalValue is owned (if present)
|
||||||
|
std::variant<InternalValue*, FormattedPlaceholder> argument;
|
||||||
|
FunctionOptions options;
|
||||||
|
FunctionName name;
|
||||||
|
const Selector* selector; // May be null
|
||||||
|
const Formatter* formatter; // May be null, but one or the other should be non-null unless argument is a FormattedPlaceholder
|
||||||
|
}; // class InternalValue
|
||||||
|
|
||||||
} // namespace message2
|
} // namespace message2
|
||||||
|
|
||||||
U_NAMESPACE_END
|
U_NAMESPACE_END
|
||||||
@ -201,6 +213,8 @@ U_NAMESPACE_END
|
|||||||
|
|
||||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||||
|
|
||||||
|
#endif /* #if !UCONFIG_NO_NORMALIZATION */
|
||||||
|
|
||||||
#endif /* U_SHOW_CPLUSPLUS_API */
|
#endif /* U_SHOW_CPLUSPLUS_API */
|
||||||
|
|
||||||
#endif // MESSAGEFORMAT2_EVALUATION_H
|
#endif // MESSAGEFORMAT2_EVALUATION_H
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include "unicode/utypes.h"
|
#include "unicode/utypes.h"
|
||||||
|
|
||||||
|
#if !UCONFIG_NO_NORMALIZATION
|
||||||
|
|
||||||
#if !UCONFIG_NO_FORMATTING
|
#if !UCONFIG_NO_FORMATTING
|
||||||
|
|
||||||
#if !UCONFIG_NO_MF2
|
#if !UCONFIG_NO_MF2
|
||||||
@ -336,3 +338,5 @@ U_NAMESPACE_END
|
|||||||
#endif /* #if !UCONFIG_NO_MF2 */
|
#endif /* #if !UCONFIG_NO_MF2 */
|
||||||
|
|
||||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||||
|
|
||||||
|
#endif /* #if !UCONFIG_NO_NORMALIZATION */
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include "unicode/utypes.h"
|
#include "unicode/utypes.h"
|
||||||
|
|
||||||
|
#if !UCONFIG_NO_NORMALIZATION
|
||||||
|
|
||||||
#if !UCONFIG_NO_FORMATTING
|
#if !UCONFIG_NO_FORMATTING
|
||||||
|
|
||||||
#if !UCONFIG_NO_MF2
|
#if !UCONFIG_NO_MF2
|
||||||
@ -43,7 +45,8 @@ namespace message2 {
|
|||||||
|
|
||||||
// Parse the pattern
|
// Parse the pattern
|
||||||
MFDataModel::Builder tree(errorCode);
|
MFDataModel::Builder tree(errorCode);
|
||||||
Parser(pat, tree, *errors, normalizedInput).parse(parseError, errorCode);
|
Parser(pat, tree, *errors, normalizedInput, errorCode)
|
||||||
|
.parse(parseError, errorCode);
|
||||||
|
|
||||||
// Fail on syntax errors
|
// Fail on syntax errors
|
||||||
if (errors->hasSyntaxError()) {
|
if (errors->hasSyntaxError()) {
|
||||||
@ -116,6 +119,24 @@ namespace message2 {
|
|||||||
|
|
||||||
// MessageFormatter
|
// MessageFormatter
|
||||||
|
|
||||||
|
// Returns the NFC-normalized version of s, returning s itself
|
||||||
|
// if it's already normalized.
|
||||||
|
UnicodeString MessageFormatter::normalizeNFC(const UnicodeString& s) const {
|
||||||
|
UErrorCode status = U_ZERO_ERROR;
|
||||||
|
// Check if string is already normalized
|
||||||
|
UNormalizationCheckResult result = nfcNormalizer->quickCheck(s, status);
|
||||||
|
// If so, return it
|
||||||
|
if (U_SUCCESS(status) && result == UNORM_YES) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
// Otherwise, normalize it
|
||||||
|
UnicodeString normalized = nfcNormalizer->normalize(s, status);
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
MessageFormatter::MessageFormatter(const MessageFormatter::Builder& builder, UErrorCode &success) : locale(builder.locale), customMFFunctionRegistry(builder.customMFFunctionRegistry) {
|
MessageFormatter::MessageFormatter(const MessageFormatter::Builder& builder, UErrorCode &success) : locale(builder.locale), customMFFunctionRegistry(builder.customMFFunctionRegistry) {
|
||||||
CHECK_ERROR(success);
|
CHECK_ERROR(success);
|
||||||
|
|
||||||
@ -132,9 +153,13 @@ namespace message2 {
|
|||||||
.adoptFormatter(FunctionName(UnicodeString("time")), time, success)
|
.adoptFormatter(FunctionName(UnicodeString("time")), time, success)
|
||||||
.adoptFormatter(FunctionName(UnicodeString("number")), number, success)
|
.adoptFormatter(FunctionName(UnicodeString("number")), number, success)
|
||||||
.adoptFormatter(FunctionName(UnicodeString("integer")), integer, success)
|
.adoptFormatter(FunctionName(UnicodeString("integer")), integer, success)
|
||||||
|
.adoptFormatter(FunctionName(UnicodeString("test:function")), new StandardFunctions::TestFormatFactory(), success)
|
||||||
|
.adoptFormatter(FunctionName(UnicodeString("test:format")), new StandardFunctions::TestFormatFactory(), success)
|
||||||
.adoptSelector(FunctionName(UnicodeString("number")), new StandardFunctions::PluralFactory(UPLURAL_TYPE_CARDINAL), success)
|
.adoptSelector(FunctionName(UnicodeString("number")), new StandardFunctions::PluralFactory(UPLURAL_TYPE_CARDINAL), success)
|
||||||
.adoptSelector(FunctionName(UnicodeString("integer")), new StandardFunctions::PluralFactory(StandardFunctions::PluralFactory::integer()), success)
|
.adoptSelector(FunctionName(UnicodeString("integer")), new StandardFunctions::PluralFactory(StandardFunctions::PluralFactory::integer()), success)
|
||||||
.adoptSelector(FunctionName(UnicodeString("string")), new StandardFunctions::TextFactory(), success);
|
.adoptSelector(FunctionName(UnicodeString("string")), new StandardFunctions::TextFactory(), success)
|
||||||
|
.adoptSelector(FunctionName(UnicodeString("test:function")), new StandardFunctions::TestSelectFactory(), success)
|
||||||
|
.adoptSelector(FunctionName(UnicodeString("test:select")), new StandardFunctions::TestSelectFactory(), success);
|
||||||
CHECK_ERROR(success);
|
CHECK_ERROR(success);
|
||||||
standardMFFunctionRegistry = standardFunctionsBuilder.build();
|
standardMFFunctionRegistry = standardFunctionsBuilder.build();
|
||||||
CHECK_ERROR(success);
|
CHECK_ERROR(success);
|
||||||
@ -163,6 +188,8 @@ namespace message2 {
|
|||||||
errors = errorsNew.orphan();
|
errors = errorsNew.orphan();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nfcNormalizer = Normalizer2::getNFCInstance(success);
|
||||||
|
|
||||||
// Note: we currently evaluate variables lazily,
|
// Note: we currently evaluate variables lazily,
|
||||||
// without memoization. This call is still necessary
|
// without memoization. This call is still necessary
|
||||||
// to check out-of-scope uses of local variables in
|
// to check out-of-scope uses of local variables in
|
||||||
@ -170,7 +197,7 @@ namespace message2 {
|
|||||||
// only be checked when arguments are known)
|
// only be checked when arguments are known)
|
||||||
|
|
||||||
// Check for resolution errors
|
// Check for resolution errors
|
||||||
Checker(dataModel, *errors).check(success);
|
Checker(dataModel, *errors, *this).check(success);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessageFormatter::cleanup() noexcept {
|
void MessageFormatter::cleanup() noexcept {
|
||||||
@ -191,6 +218,7 @@ namespace message2 {
|
|||||||
signalErrors = other.signalErrors;
|
signalErrors = other.signalErrors;
|
||||||
errors = other.errors;
|
errors = other.errors;
|
||||||
other.errors = nullptr;
|
other.errors = nullptr;
|
||||||
|
nfcNormalizer = other.nfcNormalizer;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,8 +284,11 @@ namespace message2 {
|
|||||||
return formatter;
|
return formatter;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MessageFormatter::getDefaultFormatterNameByType(const UnicodeString& type, FunctionName& name) const {
|
bool MessageFormatter::getDefaultFormatterNameByType(const UnicodeString& type,
|
||||||
U_ASSERT(hasCustomMFFunctionRegistry());
|
FunctionName& name) const {
|
||||||
|
if (!hasCustomMFFunctionRegistry()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
const MFFunctionRegistry& reg = getCustomMFFunctionRegistry();
|
const MFFunctionRegistry& reg = getCustomMFFunctionRegistry();
|
||||||
return reg.getDefaultFormatterNameByType(type, name);
|
return reg.getDefaultFormatterNameByType(type, name);
|
||||||
}
|
}
|
||||||
@ -352,3 +383,5 @@ U_NAMESPACE_END
|
|||||||
#endif /* #if !UCONFIG_NO_MF2 */
|
#endif /* #if !UCONFIG_NO_MF2 */
|
||||||
|
|
||||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||||
|
|
||||||
|
#endif /* #if !UCONFIG_NO_NORMALIZATION */
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include "unicode/utypes.h"
|
#include "unicode/utypes.h"
|
||||||
|
|
||||||
|
#if !UCONFIG_NO_NORMALIZATION
|
||||||
|
|
||||||
#if !UCONFIG_NO_FORMATTING
|
#if !UCONFIG_NO_FORMATTING
|
||||||
|
|
||||||
#if !UCONFIG_NO_MF2
|
#if !UCONFIG_NO_MF2
|
||||||
@ -85,10 +87,11 @@ MFFunctionRegistry::Builder::Builder(UErrorCode& errorCode) {
|
|||||||
formattersByType = new Hashtable();
|
formattersByType = new Hashtable();
|
||||||
if (!(formatters != nullptr && selectors != nullptr && formattersByType != nullptr)) {
|
if (!(formatters != nullptr && selectors != nullptr && formattersByType != nullptr)) {
|
||||||
errorCode = U_MEMORY_ALLOCATION_ERROR;
|
errorCode = U_MEMORY_ALLOCATION_ERROR;
|
||||||
|
} else {
|
||||||
|
formatters->setValueDeleter(uprv_deleteUObject);
|
||||||
|
selectors->setValueDeleter(uprv_deleteUObject);
|
||||||
|
formattersByType->setValueDeleter(uprv_deleteUObject);
|
||||||
}
|
}
|
||||||
formatters->setValueDeleter(uprv_deleteUObject);
|
|
||||||
selectors->setValueDeleter(uprv_deleteUObject);
|
|
||||||
formattersByType->setValueDeleter(uprv_deleteUObject);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MFFunctionRegistry::Builder::~Builder() {
|
MFFunctionRegistry::Builder::~Builder() {
|
||||||
@ -158,9 +161,13 @@ void MFFunctionRegistry::checkStandard() const {
|
|||||||
checkFormatter("time");
|
checkFormatter("time");
|
||||||
checkFormatter("number");
|
checkFormatter("number");
|
||||||
checkFormatter("integer");
|
checkFormatter("integer");
|
||||||
|
checkFormatter("test:function");
|
||||||
|
checkFormatter("test:format");
|
||||||
checkSelector("number");
|
checkSelector("number");
|
||||||
checkSelector("integer");
|
checkSelector("integer");
|
||||||
checkSelector("string");
|
checkSelector("string");
|
||||||
|
checkSelector("test:function");
|
||||||
|
checkSelector("test:select");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Formatter/selector helpers
|
// Formatter/selector helpers
|
||||||
@ -424,14 +431,14 @@ static FormattedPlaceholder notANumber(const FormattedPlaceholder& input) {
|
|||||||
return FormattedPlaceholder(input, FormattedValue(UnicodeString("NaN")));
|
return FormattedPlaceholder(input, FormattedValue(UnicodeString("NaN")));
|
||||||
}
|
}
|
||||||
|
|
||||||
static double parseNumberLiteral(const FormattedPlaceholder& input, UErrorCode& errorCode) {
|
static double parseNumberLiteral(const Formattable& input, UErrorCode& errorCode) {
|
||||||
if (U_FAILURE(errorCode)) {
|
if (U_FAILURE(errorCode)) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copying string to avoid GCC dangling-reference warning
|
// Copying string to avoid GCC dangling-reference warning
|
||||||
// (although the reference is safe)
|
// (although the reference is safe)
|
||||||
UnicodeString inputStr = input.asFormattable().getString(errorCode);
|
UnicodeString inputStr = input.getString(errorCode);
|
||||||
// Precondition: `input`'s source Formattable has type string
|
// Precondition: `input`'s source Formattable has type string
|
||||||
if (U_FAILURE(errorCode)) {
|
if (U_FAILURE(errorCode)) {
|
||||||
return {};
|
return {};
|
||||||
@ -463,8 +470,42 @@ static double parseNumberLiteral(const FormattedPlaceholder& input, UErrorCode&
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static UChar32 digitToChar(int32_t val, UErrorCode errorCode) {
|
||||||
|
if (U_FAILURE(errorCode)) {
|
||||||
|
return '0';
|
||||||
|
}
|
||||||
|
if (val < 0 || val > 9) {
|
||||||
|
errorCode = U_ILLEGAL_ARGUMENT_ERROR;
|
||||||
|
}
|
||||||
|
switch(val) {
|
||||||
|
case 0:
|
||||||
|
return '0';
|
||||||
|
case 1:
|
||||||
|
return '1';
|
||||||
|
case 2:
|
||||||
|
return '2';
|
||||||
|
case 3:
|
||||||
|
return '3';
|
||||||
|
case 4:
|
||||||
|
return '4';
|
||||||
|
case 5:
|
||||||
|
return '5';
|
||||||
|
case 6:
|
||||||
|
return '6';
|
||||||
|
case 7:
|
||||||
|
return '7';
|
||||||
|
case 8:
|
||||||
|
return '8';
|
||||||
|
case 9:
|
||||||
|
return '9';
|
||||||
|
default:
|
||||||
|
errorCode = U_ILLEGAL_ARGUMENT_ERROR;
|
||||||
|
return '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static FormattedPlaceholder tryParsingNumberLiteral(const number::LocalizedNumberFormatter& nf, const FormattedPlaceholder& input, UErrorCode& errorCode) {
|
static FormattedPlaceholder tryParsingNumberLiteral(const number::LocalizedNumberFormatter& nf, const FormattedPlaceholder& input, UErrorCode& errorCode) {
|
||||||
double numberValue = parseNumberLiteral(input, errorCode);
|
double numberValue = parseNumberLiteral(input.asFormattable(), errorCode);
|
||||||
if (U_FAILURE(errorCode)) {
|
if (U_FAILURE(errorCode)) {
|
||||||
return notANumber(input);
|
return notANumber(input);
|
||||||
}
|
}
|
||||||
@ -1235,6 +1276,273 @@ void StandardFunctions::TextSelector::selectKey(FormattedPlaceholder&& toFormat,
|
|||||||
StandardFunctions::TextFactory::~TextFactory() {}
|
StandardFunctions::TextFactory::~TextFactory() {}
|
||||||
StandardFunctions::TextSelector::~TextSelector() {}
|
StandardFunctions::TextSelector::~TextSelector() {}
|
||||||
|
|
||||||
|
// ------------ TestFormatFactory
|
||||||
|
|
||||||
|
Formatter* StandardFunctions::TestFormatFactory::createFormatter(const Locale& locale, UErrorCode& errorCode) {
|
||||||
|
NULL_ON_ERROR(errorCode);
|
||||||
|
|
||||||
|
// Results are not locale-dependent
|
||||||
|
(void) locale;
|
||||||
|
|
||||||
|
Formatter* result = new TestFormat();
|
||||||
|
if (result == nullptr) {
|
||||||
|
errorCode = U_MEMORY_ALLOCATION_ERROR;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
StandardFunctions::TestFormatFactory::~TestFormatFactory() {}
|
||||||
|
StandardFunctions::TestFormat::~TestFormat() {}
|
||||||
|
|
||||||
|
// Extract numeric value from a Formattable or, if it's a string,
|
||||||
|
// parse it as a number according to the MF2 `number-literal` grammar production
|
||||||
|
double formattableToNumber(const Formattable& arg, UErrorCode& status) {
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double result = 0;
|
||||||
|
|
||||||
|
switch (arg.getType()) {
|
||||||
|
case UFMT_DOUBLE: {
|
||||||
|
result = arg.getDouble(status);
|
||||||
|
U_ASSERT(U_SUCCESS(status));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case UFMT_LONG: {
|
||||||
|
result = (double) arg.getLong(status);
|
||||||
|
U_ASSERT(U_SUCCESS(status));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case UFMT_INT64: {
|
||||||
|
result = (double) arg.getInt64(status);
|
||||||
|
U_ASSERT(U_SUCCESS(status));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case UFMT_STRING: {
|
||||||
|
// Try to parse the string as a number
|
||||||
|
result = parseNumberLiteral(arg, status);
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
status = U_MF_OPERAND_MISMATCH_ERROR;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
// Other types can't be parsed as a number
|
||||||
|
status = U_MF_OPERAND_MISMATCH_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* static */ void StandardFunctions::TestFormat::testFunctionParameters(const FormattedPlaceholder& arg,
|
||||||
|
const FunctionOptions& options,
|
||||||
|
int32_t& decimalPlaces,
|
||||||
|
bool& failsFormat,
|
||||||
|
bool& failsSelect,
|
||||||
|
double& input,
|
||||||
|
UErrorCode& status) {
|
||||||
|
CHECK_ERROR(status);
|
||||||
|
|
||||||
|
// 1. Let DecimalPlaces be 0.
|
||||||
|
decimalPlaces = 0;
|
||||||
|
|
||||||
|
// 2. Let FailsFormat be false.
|
||||||
|
failsFormat = false;
|
||||||
|
|
||||||
|
// 3. Let FailsSelect be false.
|
||||||
|
failsSelect = false;
|
||||||
|
|
||||||
|
// 4. Let arg be the resolved value of the expression operand.
|
||||||
|
// (already true)
|
||||||
|
|
||||||
|
// Step 5 omitted because composition isn't fully implemented yet
|
||||||
|
// 6. Else if arg is a numerical value or a string matching the number-literal production, then
|
||||||
|
input = formattableToNumber(arg.asFormattable(), status);
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
// 7. Else,
|
||||||
|
// 7i. Emit "bad-input" Resolution Error.
|
||||||
|
status = U_MF_OPERAND_MISMATCH_ERROR;
|
||||||
|
// 7ii. Use a fallback value as the resolved value of the expression.
|
||||||
|
// Further steps of this algorithm are not followed.
|
||||||
|
}
|
||||||
|
// 8. If the decimalPlaces option is set, then
|
||||||
|
Formattable opt;
|
||||||
|
if (options.getFunctionOption(UnicodeString("decimalPlaces"), opt)) {
|
||||||
|
// 8i. If its value resolves to a numerical integer value 0 or 1
|
||||||
|
// or their corresponding string representations '0' or '1', then
|
||||||
|
double decimalPlacesInput = formattableToNumber(opt, status);
|
||||||
|
if (U_SUCCESS(status)) {
|
||||||
|
if (decimalPlacesInput == 0 || decimalPlacesInput == 1) {
|
||||||
|
// 8ia. Set DecimalPlaces to be the numerical value of the option.
|
||||||
|
decimalPlaces = decimalPlacesInput;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 8ii. Else if its value is not an unresolved value set by option resolution,
|
||||||
|
else {
|
||||||
|
// 8iia. Emit "bad-option" Resolution Error.
|
||||||
|
status = U_MF_BAD_OPTION;
|
||||||
|
// 8iib. Use a fallback value as the resolved value of the expression.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 9. If the fails option is set, then
|
||||||
|
Formattable failsOpt;
|
||||||
|
if (options.getFunctionOption(UnicodeString("fails"), failsOpt)) {
|
||||||
|
UnicodeString failsString = failsOpt.getString(status);
|
||||||
|
if (U_SUCCESS(status)) {
|
||||||
|
// 9i. If its value resolves to the string 'always', then
|
||||||
|
if (failsString == u"always") {
|
||||||
|
// 9ia. Set FailsFormat to be true
|
||||||
|
failsFormat = true;
|
||||||
|
// 9ib. Set FailsSelect to be true.
|
||||||
|
failsSelect = true;
|
||||||
|
}
|
||||||
|
// 9ii. Else if its value resolves to the string "format", then
|
||||||
|
else if (failsString == u"format") {
|
||||||
|
// 9ia. Set FailsFormat to be true
|
||||||
|
failsFormat = true;
|
||||||
|
}
|
||||||
|
// 9iii. Else if its value resolves to the string "select", then
|
||||||
|
else if (failsString == u"select") {
|
||||||
|
// 9iiia. Set FailsSelect to be true.
|
||||||
|
failsSelect = true;
|
||||||
|
}
|
||||||
|
// 9iv. Else if its value does not resolve to the string "never", then
|
||||||
|
else if (failsString != u"never") {
|
||||||
|
// 9iv(a). Emit "bad-option" Resolution Error.
|
||||||
|
status = U_MF_BAD_OPTION;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 9iv. again
|
||||||
|
status = U_MF_BAD_OPTION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FormattedPlaceholder StandardFunctions::TestFormat::format(FormattedPlaceholder&& arg,
|
||||||
|
FunctionOptions&& options,
|
||||||
|
UErrorCode& status) const{
|
||||||
|
|
||||||
|
int32_t decimalPlaces;
|
||||||
|
bool failsFormat;
|
||||||
|
bool failsSelect;
|
||||||
|
double input;
|
||||||
|
|
||||||
|
testFunctionParameters(arg, options, decimalPlaces,
|
||||||
|
failsFormat, failsSelect, input, status);
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return FormattedPlaceholder(arg.getFallback());
|
||||||
|
}
|
||||||
|
|
||||||
|
// If FailsFormat is true, attempting to format the placeholder to any
|
||||||
|
// formatting target will fail.
|
||||||
|
if (failsFormat) {
|
||||||
|
status = U_MF_FORMATTING_ERROR;
|
||||||
|
return FormattedPlaceholder(arg.getFallback());
|
||||||
|
}
|
||||||
|
UnicodeString result;
|
||||||
|
// When :test:function is used as a formatter, a placeholder resolving to a value
|
||||||
|
// with a :test:function expression is formatted as a concatenation of the following parts:
|
||||||
|
// 1. If Input is less than 0, the character - U+002D Hyphen-Minus.
|
||||||
|
if (input < 0) {
|
||||||
|
result += HYPHEN;
|
||||||
|
}
|
||||||
|
// 2. The truncated absolute integer value of Input, i.e. floor(abs(Input)), formatted as a
|
||||||
|
// sequence of decimal digit characters (U+0030...U+0039).
|
||||||
|
char buffer[256];
|
||||||
|
bool ignore;
|
||||||
|
int ignoreLen;
|
||||||
|
int ignorePoint;
|
||||||
|
double_conversion::DoubleToStringConverter::DoubleToAscii(floor(abs(input)),
|
||||||
|
double_conversion::DoubleToStringConverter::DtoaMode::SHORTEST,
|
||||||
|
0,
|
||||||
|
buffer,
|
||||||
|
256,
|
||||||
|
&ignore,
|
||||||
|
&ignoreLen,
|
||||||
|
&ignorePoint);
|
||||||
|
result += UnicodeString(buffer);
|
||||||
|
// 3. If DecimalPlaces is 1, then
|
||||||
|
if (decimalPlaces == 1) {
|
||||||
|
// 3i. The character . U+002E Full Stop.
|
||||||
|
result += u".";
|
||||||
|
// 3ii. The single decimal digit character representing the value
|
||||||
|
// floor((abs(Input) - floor(abs(Input))) * 10)
|
||||||
|
int32_t val = floor((abs(input) - floor(abs(input)) * 10));
|
||||||
|
result += digitToChar(val, status);
|
||||||
|
U_ASSERT(U_SUCCESS(status));
|
||||||
|
}
|
||||||
|
return FormattedPlaceholder(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------ TestSelectFactory
|
||||||
|
|
||||||
|
StandardFunctions::TestSelectFactory::~TestSelectFactory() {}
|
||||||
|
StandardFunctions::TestSelect::~TestSelect() {}
|
||||||
|
|
||||||
|
Selector* StandardFunctions::TestSelectFactory::createSelector(const Locale& locale,
|
||||||
|
UErrorCode& errorCode) const {
|
||||||
|
NULL_ON_ERROR(errorCode);
|
||||||
|
|
||||||
|
// Results are not locale-dependent
|
||||||
|
(void) locale;
|
||||||
|
|
||||||
|
Selector* result = new TestSelect();
|
||||||
|
if (result == nullptr) {
|
||||||
|
errorCode = U_MEMORY_ALLOCATION_ERROR;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StandardFunctions::TestSelect::selectKey(FormattedPlaceholder&& val,
|
||||||
|
FunctionOptions&& options,
|
||||||
|
const UnicodeString* keys,
|
||||||
|
int32_t keysLen,
|
||||||
|
UnicodeString* prefs,
|
||||||
|
int32_t& prefsLen,
|
||||||
|
UErrorCode& status) const {
|
||||||
|
int32_t decimalPlaces;
|
||||||
|
bool failsFormat;
|
||||||
|
bool failsSelect;
|
||||||
|
double input;
|
||||||
|
|
||||||
|
TestFormat::testFunctionParameters(val, options, decimalPlaces,
|
||||||
|
failsFormat, failsSelect, input, status);
|
||||||
|
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (failsSelect) {
|
||||||
|
status = U_MF_SELECTOR_ERROR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the Input is 1 and DecimalPlaces is 1, the method will return some slice
|
||||||
|
// of the list « '1.0', '1' », depending on whether those values are included in keys.
|
||||||
|
bool include1point0 = false;
|
||||||
|
bool include1 = false;
|
||||||
|
if (input == 1 && decimalPlaces == 1) {
|
||||||
|
include1point0 = true;
|
||||||
|
include1 = true;
|
||||||
|
} else if (input == 1 && decimalPlaces == 0) {
|
||||||
|
include1 = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the Input is 1 and DecimalPlaces is 0, the method will return the list « '1' » if
|
||||||
|
// keys includes '1', or an empty list otherwise.
|
||||||
|
// If the Input is any other value, the method will return an empty list.
|
||||||
|
for (int32_t i = 0; i < keysLen; i++) {
|
||||||
|
if ((keys[i] == u"1" && include1)
|
||||||
|
|| (keys[i] == u"1.0" && include1point0)) {
|
||||||
|
prefs[prefsLen] = keys[i];
|
||||||
|
prefsLen++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace message2
|
} // namespace message2
|
||||||
U_NAMESPACE_END
|
U_NAMESPACE_END
|
||||||
|
|
||||||
@ -1242,3 +1550,4 @@ U_NAMESPACE_END
|
|||||||
|
|
||||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||||
|
|
||||||
|
#endif /* #if !UCONFIG_NO_NORMALIZATION */
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
#if U_SHOW_CPLUSPLUS_API
|
#if U_SHOW_CPLUSPLUS_API
|
||||||
|
|
||||||
|
#if !UCONFIG_NO_NORMALIZATION
|
||||||
|
|
||||||
#if !UCONFIG_NO_FORMATTING
|
#if !UCONFIG_NO_FORMATTING
|
||||||
|
|
||||||
#if !UCONFIG_NO_MF2
|
#if !UCONFIG_NO_MF2
|
||||||
@ -209,6 +211,60 @@ namespace message2 {
|
|||||||
|
|
||||||
TextSelector(const Locale& l) : locale(l) {}
|
TextSelector(const Locale& l) : locale(l) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// See https://github.com/unicode-org/message-format-wg/blob/main/test/README.md
|
||||||
|
class TestFormatFactory : public FormatterFactory {
|
||||||
|
public:
|
||||||
|
Formatter* createFormatter(const Locale& locale, UErrorCode& status) override;
|
||||||
|
TestFormatFactory() {}
|
||||||
|
virtual ~TestFormatFactory();
|
||||||
|
};
|
||||||
|
|
||||||
|
class TestSelect;
|
||||||
|
|
||||||
|
class TestFormat : public Formatter {
|
||||||
|
public:
|
||||||
|
FormattedPlaceholder format(FormattedPlaceholder&& toFormat, FunctionOptions&& options, UErrorCode& status) const override;
|
||||||
|
virtual ~TestFormat();
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class TestFormatFactory;
|
||||||
|
friend class TestSelect;
|
||||||
|
TestFormat() {}
|
||||||
|
static void testFunctionParameters(const FormattedPlaceholder& arg,
|
||||||
|
const FunctionOptions& options,
|
||||||
|
int32_t& decimalPlaces,
|
||||||
|
bool& failsFormat,
|
||||||
|
bool& failsSelect,
|
||||||
|
double& input,
|
||||||
|
UErrorCode& status);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// See https://github.com/unicode-org/message-format-wg/blob/main/test/README.md
|
||||||
|
class TestSelectFactory : public SelectorFactory {
|
||||||
|
public:
|
||||||
|
Selector* createSelector(const Locale& locale, UErrorCode& status) const override;
|
||||||
|
TestSelectFactory() {}
|
||||||
|
virtual ~TestSelectFactory();
|
||||||
|
};
|
||||||
|
|
||||||
|
class TestSelect : public Selector {
|
||||||
|
public:
|
||||||
|
void selectKey(FormattedPlaceholder&& val,
|
||||||
|
FunctionOptions&& options,
|
||||||
|
const UnicodeString* keys,
|
||||||
|
int32_t keysLen,
|
||||||
|
UnicodeString* prefs,
|
||||||
|
int32_t& prefsLen,
|
||||||
|
UErrorCode& status) const override;
|
||||||
|
virtual ~TestSelect();
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class TestSelectFactory;
|
||||||
|
TestSelect() {}
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern void formatDateWithDefaults(const Locale& locale, UDate date, UnicodeString&, UErrorCode& errorCode);
|
extern void formatDateWithDefaults(const Locale& locale, UDate date, UnicodeString&, UErrorCode& errorCode);
|
||||||
@ -226,6 +282,8 @@ U_NAMESPACE_END
|
|||||||
|
|
||||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||||
|
|
||||||
|
#endif /* #if !UCONFIG_NO_NORMALIZATION */
|
||||||
|
|
||||||
#endif /* U_SHOW_CPLUSPLUS_API */
|
#endif /* U_SHOW_CPLUSPLUS_API */
|
||||||
|
|
||||||
#endif // MESSAGEFORMAT2_FUNCTION_REGISTRY_INTERNAL_H
|
#endif // MESSAGEFORMAT2_FUNCTION_REGISTRY_INTERNAL_H
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
#if U_SHOW_CPLUSPLUS_API
|
#if U_SHOW_CPLUSPLUS_API
|
||||||
|
|
||||||
|
#if !UCONFIG_NO_NORMALIZATION
|
||||||
|
|
||||||
#if !UCONFIG_NO_FORMATTING
|
#if !UCONFIG_NO_FORMATTING
|
||||||
|
|
||||||
#if !UCONFIG_NO_MF2
|
#if !UCONFIG_NO_MF2
|
||||||
@ -97,6 +99,8 @@ U_NAMESPACE_END
|
|||||||
|
|
||||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||||
|
|
||||||
|
#endif /* #if !UCONFIG_NO_NORMALIZATION */
|
||||||
|
|
||||||
#endif /* U_SHOW_CPLUSPLUS_API */
|
#endif /* U_SHOW_CPLUSPLUS_API */
|
||||||
|
|
||||||
#endif // MESSAGEFORMAT2_MACROS_H
|
#endif // MESSAGEFORMAT2_MACROS_H
|
||||||
|
574
deps/icu-small/source/i18n/messageformat2_parser.cpp
vendored
574
deps/icu-small/source/i18n/messageformat2_parser.cpp
vendored
@ -3,13 +3,18 @@
|
|||||||
|
|
||||||
#include "unicode/utypes.h"
|
#include "unicode/utypes.h"
|
||||||
|
|
||||||
|
#if !UCONFIG_NO_NORMALIZATION
|
||||||
|
|
||||||
#if !UCONFIG_NO_FORMATTING
|
#if !UCONFIG_NO_FORMATTING
|
||||||
|
|
||||||
#if !UCONFIG_NO_MF2
|
#if !UCONFIG_NO_MF2
|
||||||
|
|
||||||
|
#include "unicode/uniset.h"
|
||||||
#include "messageformat2_errors.h"
|
#include "messageformat2_errors.h"
|
||||||
#include "messageformat2_macros.h"
|
#include "messageformat2_macros.h"
|
||||||
#include "messageformat2_parser.h"
|
#include "messageformat2_parser.h"
|
||||||
|
#include "ucln_in.h"
|
||||||
|
#include "umutex.h"
|
||||||
#include "uvector.h" // U_ASSERT
|
#include "uvector.h" // U_ASSERT
|
||||||
|
|
||||||
U_NAMESPACE_BEGIN
|
U_NAMESPACE_BEGIN
|
||||||
@ -91,14 +96,282 @@ static void copyContext(const UChar in[U_PARSE_CONTEXT_LEN], UChar out[U_PARSE_C
|
|||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------
|
// -------------------------------------
|
||||||
// Predicates
|
// Initialization of UnicodeSets
|
||||||
|
|
||||||
// Returns true if `c` is in the interval [`first`, `last`]
|
namespace unisets {
|
||||||
static bool inRange(UChar32 c, UChar32 first, UChar32 last) {
|
|
||||||
U_ASSERT(first < last);
|
UnicodeSet* gUnicodeSets[unisets::UNISETS_KEY_COUNT] = {};
|
||||||
return c >= first && c <= last;
|
|
||||||
|
inline UnicodeSet* getImpl(Key key) {
|
||||||
|
return gUnicodeSets[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
icu::UInitOnce gMF2ParseUniSetsInitOnce {};
|
||||||
|
}
|
||||||
|
|
||||||
|
UnicodeSet* initContentChars(UErrorCode& status) {
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnicodeSet* result = new UnicodeSet(0x0001, 0x0008); // Omit NULL, HTAB and LF
|
||||||
|
if (result == nullptr) {
|
||||||
|
status = U_MEMORY_ALLOCATION_ERROR;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
result->add(0x000B, 0x000C); // Omit CR
|
||||||
|
result->add(0x000E, 0x001F); // Omit SP
|
||||||
|
result->add(0x0021, 0x002D); // Omit '.'
|
||||||
|
result->add(0x002F, 0x003F); // Omit '@'
|
||||||
|
result->add(0x0041, 0x005B); // Omit '\'
|
||||||
|
result->add(0x005D, 0x007A); // Omit { | }
|
||||||
|
result->add(0x007E, 0x2FFF); // Omit IDEOGRAPHIC_SPACE
|
||||||
|
result->add(0x3001, 0x10FFFF); // Allowing surrogates is intentional
|
||||||
|
result->freeze();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnicodeSet* initWhitespace(UErrorCode& status) {
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnicodeSet* result = new UnicodeSet();
|
||||||
|
if (result == nullptr) {
|
||||||
|
status = U_MEMORY_ALLOCATION_ERROR;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
result->add(SPACE);
|
||||||
|
result->add(HTAB);
|
||||||
|
result->add(CR);
|
||||||
|
result->add(LF);
|
||||||
|
result->add(IDEOGRAPHIC_SPACE);
|
||||||
|
result->freeze();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnicodeSet* initBidiControls(UErrorCode& status) {
|
||||||
|
UnicodeSet* result = new UnicodeSet(UnicodeString("[\\u061C]"), status);
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
result->add(0x200E, 0x200F);
|
||||||
|
result->add(0x2066, 0x2069);
|
||||||
|
result->freeze();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnicodeSet* initAlpha(UErrorCode& status) {
|
||||||
|
UnicodeSet* result = new UnicodeSet(UnicodeString("[:letter:]"), status);
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
result->freeze();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnicodeSet* initDigits(UErrorCode& status) {
|
||||||
|
UnicodeSet* result = new UnicodeSet(UnicodeString("[:number:]"), status);
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
result->freeze();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnicodeSet* initNameStartChars(UErrorCode& status) {
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnicodeSet* isAlpha = unisets::gUnicodeSets[unisets::ALPHA] = initAlpha(status);
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
UnicodeSet* result = new UnicodeSet(*isAlpha);
|
||||||
|
if (result == nullptr) {
|
||||||
|
status = U_MEMORY_ALLOCATION_ERROR;
|
||||||
|
return nullptr;
|
||||||
|
};
|
||||||
|
result->add(UNDERSCORE);
|
||||||
|
result->add(0x00C0, 0x00D6);
|
||||||
|
result->add(0x00D8, 0x00F6);
|
||||||
|
result->add(0x00F8, 0x02FF);
|
||||||
|
result->add(0x0370, 0x037D);
|
||||||
|
result->add(0x037F, 0x061B);
|
||||||
|
result->add(0x061D, 0x1FFF);
|
||||||
|
result->add(0x200C, 0x200D);
|
||||||
|
result->add(0x2070, 0x218F);
|
||||||
|
result->add(0x2C00, 0x2FEF);
|
||||||
|
result->add(0x3001, 0xD7FF);
|
||||||
|
result->add(0xF900, 0xFDCF);
|
||||||
|
result->add(0xFDF0, 0xFFFD);
|
||||||
|
result->add(0x100000, 0xEFFFF);
|
||||||
|
result->freeze();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnicodeSet* initNameChars(UErrorCode& status) {
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnicodeSet* nameStart = unisets::gUnicodeSets[unisets::NAME_START] = initNameStartChars(status);
|
||||||
|
UnicodeSet* digit = unisets::gUnicodeSets[unisets::DIGIT] = initDigits(status);
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
UnicodeSet* result = new UnicodeSet();
|
||||||
|
if (result == nullptr) {
|
||||||
|
status = U_MEMORY_ALLOCATION_ERROR;
|
||||||
|
return nullptr;
|
||||||
|
};
|
||||||
|
result->addAll(*nameStart);
|
||||||
|
result->addAll(*digit);
|
||||||
|
result->add(HYPHEN);
|
||||||
|
result->add(PERIOD);
|
||||||
|
result->add(0x00B7);
|
||||||
|
result->add(0x0300, 0x036F);
|
||||||
|
result->add(0x203F, 0x2040);
|
||||||
|
result->freeze();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnicodeSet* initTextChars(UErrorCode& status) {
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnicodeSet* content = unisets::gUnicodeSets[unisets::CONTENT] = initContentChars(status);
|
||||||
|
UnicodeSet* whitespace = unisets::gUnicodeSets[unisets::WHITESPACE] = initWhitespace(status);
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
UnicodeSet* result = new UnicodeSet();
|
||||||
|
if (result == nullptr) {
|
||||||
|
status = U_MEMORY_ALLOCATION_ERROR;
|
||||||
|
return nullptr;
|
||||||
|
};
|
||||||
|
result->addAll(*content);
|
||||||
|
result->addAll(*whitespace);
|
||||||
|
result->add(PERIOD);
|
||||||
|
result->add(AT);
|
||||||
|
result->add(PIPE);
|
||||||
|
result->freeze();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnicodeSet* initQuotedChars(UErrorCode& status) {
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
unisets::gUnicodeSets[unisets::TEXT] = initTextChars(status);
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
UnicodeSet* result = new UnicodeSet();
|
||||||
|
if (result == nullptr) {
|
||||||
|
status = U_MEMORY_ALLOCATION_ERROR;
|
||||||
|
return nullptr;
|
||||||
|
};
|
||||||
|
// content and whitespace were initialized by `initTextChars()`
|
||||||
|
UnicodeSet* content = unisets::getImpl(unisets::CONTENT);
|
||||||
|
if (content == nullptr) {
|
||||||
|
status = U_MEMORY_ALLOCATION_ERROR;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
result->addAll(*content);
|
||||||
|
UnicodeSet* whitespace = unisets::getImpl(unisets::WHITESPACE);
|
||||||
|
if (whitespace == nullptr) {
|
||||||
|
status = U_MEMORY_ALLOCATION_ERROR;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
result->addAll(*whitespace);
|
||||||
|
result->add(PERIOD);
|
||||||
|
result->add(AT);
|
||||||
|
result->add(LEFT_CURLY_BRACE);
|
||||||
|
result->add(RIGHT_CURLY_BRACE);
|
||||||
|
result->freeze();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnicodeSet* initEscapableChars(UErrorCode& status) {
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnicodeSet* result = new UnicodeSet();
|
||||||
|
if (result == nullptr) {
|
||||||
|
status = U_MEMORY_ALLOCATION_ERROR;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
result->add(PIPE);
|
||||||
|
result->add(BACKSLASH);
|
||||||
|
result->add(LEFT_CURLY_BRACE);
|
||||||
|
result->add(RIGHT_CURLY_BRACE);
|
||||||
|
result->freeze();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace unisets {
|
||||||
|
|
||||||
|
UBool U_CALLCONV cleanupMF2ParseUniSets() {
|
||||||
|
for (int32_t i = 0; i < UNISETS_KEY_COUNT; i++) {
|
||||||
|
delete gUnicodeSets[i];
|
||||||
|
gUnicodeSets[i] = nullptr;
|
||||||
|
}
|
||||||
|
gMF2ParseUniSetsInitOnce.reset();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void U_CALLCONV initMF2ParseUniSets(UErrorCode& status) {
|
||||||
|
ucln_i18n_registerCleanup(UCLN_I18N_MF2_UNISETS, cleanupMF2ParseUniSets);
|
||||||
|
/*
|
||||||
|
Each of the init functions initializes the UnicodeSets
|
||||||
|
that it depends on.
|
||||||
|
|
||||||
|
initBidiControls (no dependencies)
|
||||||
|
|
||||||
|
initEscapableChars (no dependencies)
|
||||||
|
|
||||||
|
initNameChars depends on
|
||||||
|
initDigits
|
||||||
|
initNameStartChars depends on
|
||||||
|
initAlpha
|
||||||
|
|
||||||
|
initQuotedChars depends on
|
||||||
|
initTextChars depends on
|
||||||
|
initContentChars
|
||||||
|
initWhitespace
|
||||||
|
*/
|
||||||
|
gUnicodeSets[unisets::BIDI] = initBidiControls(status);
|
||||||
|
gUnicodeSets[unisets::NAME_CHAR] = initNameChars(status);
|
||||||
|
gUnicodeSets[unisets::QUOTED] = initQuotedChars(status);
|
||||||
|
gUnicodeSets[unisets::ESCAPABLE] = initEscapableChars(status);
|
||||||
|
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
cleanupMF2ParseUniSets();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const UnicodeSet* get(Key key, UErrorCode& status) {
|
||||||
|
umtx_initOnce(gMF2ParseUniSetsInitOnce, &initMF2ParseUniSets, status);
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
UnicodeSet* result = getImpl(key);
|
||||||
|
if (result == nullptr) {
|
||||||
|
status = U_MEMORY_ALLOCATION_ERROR;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------
|
||||||
|
// Predicates
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The following helper predicates should exactly match nonterminals in the MessageFormat 2 grammar:
|
The following helper predicates should exactly match nonterminals in the MessageFormat 2 grammar:
|
||||||
|
|
||||||
@ -113,76 +386,50 @@ static bool inRange(UChar32 c, UChar32 first, UChar32 last) {
|
|||||||
`isWhitespace()` : `s`
|
`isWhitespace()` : `s`
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static bool isContentChar(UChar32 c) {
|
bool Parser::isContentChar(UChar32 c) const {
|
||||||
return inRange(c, 0x0001, 0x0008) // Omit NULL, HTAB and LF
|
return contentChars->contains(c);
|
||||||
|| inRange(c, 0x000B, 0x000C) // Omit CR
|
|
||||||
|| inRange(c, 0x000E, 0x001F) // Omit SP
|
|
||||||
|| inRange(c, 0x0021, 0x002D) // Omit '.'
|
|
||||||
|| inRange(c, 0x002F, 0x003F) // Omit '@'
|
|
||||||
|| inRange(c, 0x0041, 0x005B) // Omit '\'
|
|
||||||
|| inRange(c, 0x005D, 0x007A) // Omit { | }
|
|
||||||
|| inRange(c, 0x007E, 0xD7FF) // Omit surrogates
|
|
||||||
|| inRange(c, 0xE000, 0x10FFFF);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// See `s` in the MessageFormat 2 grammar
|
// See `bidi` in the MF2 grammar
|
||||||
inline bool isWhitespace(UChar32 c) {
|
bool Parser::isBidiControl(UChar32 c) const {
|
||||||
switch (c) {
|
return bidiControlChars->contains(c);
|
||||||
case SPACE:
|
|
||||||
case HTAB:
|
|
||||||
case CR:
|
|
||||||
case LF:
|
|
||||||
case IDEOGRAPHIC_SPACE:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isTextChar(UChar32 c) {
|
// See `ws` in the MessageFormat 2 grammar
|
||||||
return isContentChar(c)
|
bool Parser::isWhitespace(UChar32 c) const {
|
||||||
|| isWhitespace(c)
|
return whitespaceChars->contains(c);
|
||||||
|| c == PERIOD
|
|
||||||
|| c == AT
|
|
||||||
|| c == PIPE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isAlpha(UChar32 c) { return inRange(c, 0x0041, 0x005A) || inRange(c, 0x0061, 0x007A); }
|
bool Parser::isTextChar(UChar32 c) const {
|
||||||
|
return textChars->contains(c);
|
||||||
static bool isDigit(UChar32 c) { return inRange(c, 0x0030, 0x0039); }
|
|
||||||
|
|
||||||
static bool isNameStart(UChar32 c) {
|
|
||||||
return isAlpha(c) || c == UNDERSCORE || inRange(c, 0x00C0, 0x00D6) || inRange(c, 0x00D8, 0x00F6) ||
|
|
||||||
inRange(c, 0x00F8, 0x02FF) || inRange(c, 0x0370, 0x037D) || inRange(c, 0x037F, 0x1FFF) ||
|
|
||||||
inRange(c, 0x200C, 0x200D) || inRange(c, 0x2070, 0x218F) || inRange(c, 0x2C00, 0x2FEF) ||
|
|
||||||
inRange(c, 0x3001, 0xD7FF) || inRange(c, 0xF900, 0xFDCF) || inRange(c, 0xFDF0, 0xFFFD) ||
|
|
||||||
inRange(c, 0x10000, 0xEFFFF);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isNameChar(UChar32 c) {
|
bool Parser::isAlpha(UChar32 c) const {
|
||||||
return isNameStart(c) || isDigit(c) || c == HYPHEN || c == PERIOD || c == 0x00B7 ||
|
return alphaChars->contains(c);
|
||||||
inRange(c, 0x0300, 0x036F) || inRange(c, 0x203F, 0x2040);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isUnquotedStart(UChar32 c) {
|
bool Parser::isDigit(UChar32 c) const {
|
||||||
return isNameStart(c) || isDigit(c) || c == HYPHEN || c == PERIOD || c == 0x00B7 ||
|
return digitChars->contains(c);
|
||||||
inRange(c, 0x0300, 0x036F) || inRange(c, 0x203F, 0x2040);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isQuotedChar(UChar32 c) {
|
bool Parser::isNameStart(UChar32 c) const {
|
||||||
return isContentChar(c)
|
return nameStartChars->contains(c);
|
||||||
|| isWhitespace(c)
|
|
||||||
|| c == PERIOD
|
|
||||||
|| c == AT
|
|
||||||
|| c == LEFT_CURLY_BRACE
|
|
||||||
|| c == RIGHT_CURLY_BRACE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isEscapableChar(UChar32 c) {
|
bool Parser::isNameChar(UChar32 c) const {
|
||||||
return c == PIPE
|
return nameChars->contains(c);
|
||||||
|| c == BACKSLASH
|
}
|
||||||
|| c == LEFT_CURLY_BRACE
|
|
||||||
|| c == RIGHT_CURLY_BRACE;
|
bool Parser::isUnquotedStart(UChar32 c) const {
|
||||||
|
return isNameChar(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Parser::isQuotedChar(UChar32 c) const {
|
||||||
|
return quotedChars->contains(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Parser::isEscapableChar(UChar32 c) const {
|
||||||
|
return escapableChars->contains(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true iff `c` can begin a `function` nonterminal
|
// Returns true iff `c` can begin a `function` nonterminal
|
||||||
@ -203,12 +450,12 @@ static bool isAnnotationStart(UChar32 c) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns true iff `c` can begin a `literal` nonterminal
|
// Returns true iff `c` can begin a `literal` nonterminal
|
||||||
static bool isLiteralStart(UChar32 c) {
|
bool Parser::isLiteralStart(UChar32 c) const {
|
||||||
return (c == PIPE || isNameStart(c) || c == HYPHEN || isDigit(c));
|
return (c == PIPE || isNameStart(c) || c == HYPHEN || isDigit(c));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true iff `c` can begin a `key` nonterminal
|
// Returns true iff `c` can begin a `key` nonterminal
|
||||||
static bool isKeyStart(UChar32 c) {
|
bool Parser::isKeyStart(UChar32 c) const {
|
||||||
return (c == ASTERISK || isLiteralStart(c));
|
return (c == ASTERISK || isLiteralStart(c));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -347,7 +594,7 @@ option, or the optional space before an attribute.
|
|||||||
No pre, no post.
|
No pre, no post.
|
||||||
A message may end with whitespace, so `index` may equal `len()` on exit.
|
A message may end with whitespace, so `index` may equal `len()` on exit.
|
||||||
*/
|
*/
|
||||||
void Parser::parseWhitespaceMaybeRequired(bool required, UErrorCode& errorCode) {
|
void Parser::parseRequiredWS(UErrorCode& errorCode) {
|
||||||
bool sawWhitespace = false;
|
bool sawWhitespace = false;
|
||||||
|
|
||||||
// The loop exits either when we consume all the input,
|
// The loop exits either when we consume all the input,
|
||||||
@ -358,7 +605,7 @@ void Parser::parseWhitespaceMaybeRequired(bool required, UErrorCode& errorCode)
|
|||||||
// If whitespace isn't required -- or if we saw it already --
|
// If whitespace isn't required -- or if we saw it already --
|
||||||
// then the caller is responsible for checking this case and
|
// then the caller is responsible for checking this case and
|
||||||
// setting an error if necessary.
|
// setting an error if necessary.
|
||||||
if (!required || sawWhitespace) {
|
if (sawWhitespace) {
|
||||||
// Not an error.
|
// Not an error.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -380,24 +627,51 @@ void Parser::parseWhitespaceMaybeRequired(bool required, UErrorCode& errorCode)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sawWhitespace && required) {
|
if (!sawWhitespace) {
|
||||||
ERROR(errorCode);
|
ERROR(errorCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Parser::parseOptionalBidi() {
|
||||||
|
while (true) {
|
||||||
|
if (!inBounds()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isBidiControl(peek())) {
|
||||||
|
next();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
No pre, no post, for the same reason as `parseWhitespaceMaybeRequired()`.
|
No pre, no post, because a message may end with whitespace
|
||||||
|
Matches `s` in the MF2 grammar
|
||||||
*/
|
*/
|
||||||
void Parser::parseRequiredWhitespace(UErrorCode& errorCode) {
|
void Parser::parseRequiredWhitespace(UErrorCode& errorCode) {
|
||||||
parseWhitespaceMaybeRequired(true, errorCode);
|
parseOptionalBidi();
|
||||||
|
parseRequiredWS(errorCode);
|
||||||
|
parseOptionalWhitespace();
|
||||||
normalizedInput += SPACE;
|
normalizedInput += SPACE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
No pre, no post, for the same reason as `parseWhitespaceMaybeRequired()`.
|
No pre, no post, for the same reason as `parseWhitespaceMaybeRequired()`.
|
||||||
*/
|
*/
|
||||||
void Parser::parseOptionalWhitespace(UErrorCode& errorCode) {
|
void Parser::parseOptionalWhitespace() {
|
||||||
parseWhitespaceMaybeRequired(false, errorCode);
|
while (true) {
|
||||||
|
if (!inBounds()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto cp = peek();
|
||||||
|
if (isWhitespace(cp) || isBidiControl(cp)) {
|
||||||
|
maybeAdvanceLine();
|
||||||
|
next();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Consumes a single character, signaling an error if `peek()` != `c`
|
// Consumes a single character, signaling an error if `peek()` != `c`
|
||||||
@ -442,11 +716,11 @@ void Parser::parseToken(const std::u16string_view& token, UErrorCode& errorCode)
|
|||||||
*/
|
*/
|
||||||
void Parser::parseTokenWithWhitespace(const std::u16string_view& token, UErrorCode& errorCode) {
|
void Parser::parseTokenWithWhitespace(const std::u16string_view& token, UErrorCode& errorCode) {
|
||||||
// No need for error check or bounds check before parseOptionalWhitespace
|
// No need for error check or bounds check before parseOptionalWhitespace
|
||||||
parseOptionalWhitespace(errorCode);
|
parseOptionalWhitespace();
|
||||||
// Establish precondition
|
// Establish precondition
|
||||||
CHECK_BOUNDS(errorCode);
|
CHECK_BOUNDS(errorCode);
|
||||||
parseToken(token, errorCode);
|
parseToken(token, errorCode);
|
||||||
parseOptionalWhitespace(errorCode);
|
parseOptionalWhitespace();
|
||||||
// Guarantee postcondition
|
// Guarantee postcondition
|
||||||
CHECK_BOUNDS(errorCode);
|
CHECK_BOUNDS(errorCode);
|
||||||
}
|
}
|
||||||
@ -458,12 +732,12 @@ void Parser::parseTokenWithWhitespace(const std::u16string_view& token, UErrorCo
|
|||||||
then consumes optional whitespace again
|
then consumes optional whitespace again
|
||||||
*/
|
*/
|
||||||
void Parser::parseTokenWithWhitespace(UChar32 c, UErrorCode& errorCode) {
|
void Parser::parseTokenWithWhitespace(UChar32 c, UErrorCode& errorCode) {
|
||||||
// No need for error check or bounds check before parseOptionalWhitespace(errorCode)
|
// No need for error check or bounds check before parseOptionalWhitespace()
|
||||||
parseOptionalWhitespace(errorCode);
|
parseOptionalWhitespace();
|
||||||
// Establish precondition
|
// Establish precondition
|
||||||
CHECK_BOUNDS(errorCode);
|
CHECK_BOUNDS(errorCode);
|
||||||
parseToken(c, errorCode);
|
parseToken(c, errorCode);
|
||||||
parseOptionalWhitespace(errorCode);
|
parseOptionalWhitespace();
|
||||||
// Guarantee postcondition
|
// Guarantee postcondition
|
||||||
CHECK_BOUNDS(errorCode);
|
CHECK_BOUNDS(errorCode);
|
||||||
}
|
}
|
||||||
@ -482,11 +756,17 @@ UnicodeString Parser::parseName(UErrorCode& errorCode) {
|
|||||||
|
|
||||||
U_ASSERT(inBounds());
|
U_ASSERT(inBounds());
|
||||||
|
|
||||||
if (!isNameStart(peek())) {
|
if (!(isNameStart(peek()) || isBidiControl(peek()))) {
|
||||||
ERROR(errorCode);
|
ERROR(errorCode);
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// name = [bidi] name-start *name-char [bidi]
|
||||||
|
|
||||||
|
// [bidi]
|
||||||
|
parseOptionalBidi();
|
||||||
|
|
||||||
|
// name-start *name-char
|
||||||
while (isNameChar(peek())) {
|
while (isNameChar(peek())) {
|
||||||
UChar32 c = peek();
|
UChar32 c = peek();
|
||||||
name += c;
|
name += c;
|
||||||
@ -497,6 +777,10 @@ UnicodeString Parser::parseName(UErrorCode& errorCode) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// [bidi]
|
||||||
|
parseOptionalBidi();
|
||||||
|
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -510,21 +794,13 @@ VariableName Parser::parseVariableName(UErrorCode& errorCode) {
|
|||||||
VariableName result;
|
VariableName result;
|
||||||
|
|
||||||
U_ASSERT(inBounds());
|
U_ASSERT(inBounds());
|
||||||
// If the '$' is missing, we don't want a binding
|
|
||||||
// for this variable to be created.
|
|
||||||
bool valid = peek() == DOLLAR;
|
|
||||||
parseToken(DOLLAR, errorCode);
|
parseToken(DOLLAR, errorCode);
|
||||||
if (!inBounds()) {
|
if (!inBounds()) {
|
||||||
ERROR(errorCode);
|
ERROR(errorCode);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
UnicodeString varName = parseName(errorCode);
|
return VariableName(parseName(errorCode));
|
||||||
// Set the name to "" if the variable wasn't
|
|
||||||
// declared correctly
|
|
||||||
if (!valid) {
|
|
||||||
varName.remove();
|
|
||||||
}
|
|
||||||
return VariableName(varName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -853,7 +1129,7 @@ void Parser::parseAttribute(AttributeAdder<T>& attrAdder, UErrorCode& errorCode)
|
|||||||
// about whether whitespace precedes another
|
// about whether whitespace precedes another
|
||||||
// attribute, or the '=' sign
|
// attribute, or the '=' sign
|
||||||
int32_t savedIndex = index;
|
int32_t savedIndex = index;
|
||||||
parseOptionalWhitespace(errorCode);
|
parseOptionalWhitespace();
|
||||||
|
|
||||||
Operand rand;
|
Operand rand;
|
||||||
if (peek() == EQUALS) {
|
if (peek() == EQUALS) {
|
||||||
@ -861,19 +1137,9 @@ void Parser::parseAttribute(AttributeAdder<T>& attrAdder, UErrorCode& errorCode)
|
|||||||
parseTokenWithWhitespace(EQUALS, errorCode);
|
parseTokenWithWhitespace(EQUALS, errorCode);
|
||||||
|
|
||||||
UnicodeString rhsStr;
|
UnicodeString rhsStr;
|
||||||
// Parse RHS, which is either a literal or variable
|
// Parse RHS, which must be a literal
|
||||||
switch (peek()) {
|
// attribute = "@" identifier [o "=" o literal]
|
||||||
case DOLLAR: {
|
rand = Operand(parseLiteral(errorCode));
|
||||||
rand = Operand(parseVariableName(errorCode));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
// Must be a literal
|
|
||||||
rand = Operand(parseLiteral(errorCode));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
U_ASSERT(!rand.isNull());
|
|
||||||
} else {
|
} else {
|
||||||
// attribute -> "@" identifier [[s] "=" [s]]
|
// attribute -> "@" identifier [[s] "=" [s]]
|
||||||
// Use null operand, which `rand` is already set to
|
// Use null operand, which `rand` is already set to
|
||||||
@ -881,7 +1147,7 @@ void Parser::parseAttribute(AttributeAdder<T>& attrAdder, UErrorCode& errorCode)
|
|||||||
index = savedIndex;
|
index = savedIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
attrAdder.addAttribute(lhs, std::move(rand), errorCode);
|
attrAdder.addAttribute(lhs, std::move(Operand(rand)), errorCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1149,7 +1415,7 @@ the comment in `parseOptions()` for details.
|
|||||||
// (the character is either the required space before an annotation, or optional
|
// (the character is either the required space before an annotation, or optional
|
||||||
// trailing space after the literal or variable). It's still ambiguous which
|
// trailing space after the literal or variable). It's still ambiguous which
|
||||||
// one does apply.
|
// one does apply.
|
||||||
parseOptionalWhitespace(status);
|
parseOptionalWhitespace();
|
||||||
// Restore precondition
|
// Restore precondition
|
||||||
CHECK_BOUNDS(status);
|
CHECK_BOUNDS(status);
|
||||||
|
|
||||||
@ -1220,7 +1486,7 @@ Expression Parser::parseExpression(UErrorCode& status) {
|
|||||||
// Parse opening brace
|
// Parse opening brace
|
||||||
parseToken(LEFT_CURLY_BRACE, status);
|
parseToken(LEFT_CURLY_BRACE, status);
|
||||||
// Optional whitespace after opening brace
|
// Optional whitespace after opening brace
|
||||||
parseOptionalWhitespace(status);
|
parseOptionalWhitespace();
|
||||||
|
|
||||||
Expression::Builder exprBuilder(status);
|
Expression::Builder exprBuilder(status);
|
||||||
// Restore precondition
|
// Restore precondition
|
||||||
@ -1263,7 +1529,7 @@ Expression Parser::parseExpression(UErrorCode& status) {
|
|||||||
|
|
||||||
// Parse optional space
|
// Parse optional space
|
||||||
// (the last [s] in e.g. "{" [s] literal [s annotation] *(s attribute) [s] "}")
|
// (the last [s] in e.g. "{" [s] literal [s annotation] *(s attribute) [s] "}")
|
||||||
parseOptionalWhitespace(status);
|
parseOptionalWhitespace();
|
||||||
|
|
||||||
// Either an operand or operator (or both) must have been set already,
|
// Either an operand or operator (or both) must have been set already,
|
||||||
// so there can't be an error
|
// so there can't be an error
|
||||||
@ -1339,7 +1605,7 @@ void Parser::parseInputDeclaration(UErrorCode& status) {
|
|||||||
CHECK_BOUNDS(status);
|
CHECK_BOUNDS(status);
|
||||||
|
|
||||||
parseToken(ID_INPUT, status);
|
parseToken(ID_INPUT, status);
|
||||||
parseOptionalWhitespace(status);
|
parseOptionalWhitespace();
|
||||||
|
|
||||||
// Restore precondition before calling parseExpression()
|
// Restore precondition before calling parseExpression()
|
||||||
CHECK_BOUNDS(status);
|
CHECK_BOUNDS(status);
|
||||||
@ -1400,7 +1666,7 @@ void Parser::parseDeclarations(UErrorCode& status) {
|
|||||||
// Avoid looping infinitely
|
// Avoid looping infinitely
|
||||||
CHECK_ERROR(status);
|
CHECK_ERROR(status);
|
||||||
|
|
||||||
parseOptionalWhitespace(status);
|
parseOptionalWhitespace();
|
||||||
// Restore precondition
|
// Restore precondition
|
||||||
CHECK_BOUNDS(status);
|
CHECK_BOUNDS(status);
|
||||||
}
|
}
|
||||||
@ -1510,8 +1776,8 @@ This is addressed using "backtracking" (similarly to `parseOptions()`).
|
|||||||
|
|
||||||
// We've seen at least one whitespace-key pair, so now we can parse
|
// We've seen at least one whitespace-key pair, so now we can parse
|
||||||
// *(s key) [s]
|
// *(s key) [s]
|
||||||
while (peek() != LEFT_CURLY_BRACE || isWhitespace(peek())) { // Try to recover from errors
|
while (peek() != LEFT_CURLY_BRACE || isWhitespace(peek()) || isBidiControl(peek())) {
|
||||||
bool wasWhitespace = isWhitespace(peek());
|
bool wasWhitespace = isWhitespace(peek()) || isBidiControl(peek());
|
||||||
parseRequiredWhitespace(status);
|
parseRequiredWhitespace(status);
|
||||||
if (!wasWhitespace) {
|
if (!wasWhitespace) {
|
||||||
// Avoid infinite loop when parsing something like:
|
// Avoid infinite loop when parsing something like:
|
||||||
@ -1569,7 +1835,7 @@ Markup Parser::parseMarkup(UErrorCode& status) {
|
|||||||
// Consume the '{'
|
// Consume the '{'
|
||||||
next();
|
next();
|
||||||
normalizedInput += LEFT_CURLY_BRACE;
|
normalizedInput += LEFT_CURLY_BRACE;
|
||||||
parseOptionalWhitespace(status);
|
parseOptionalWhitespace();
|
||||||
bool closing = false;
|
bool closing = false;
|
||||||
switch (peek()) {
|
switch (peek()) {
|
||||||
case NUMBER_SIGN: {
|
case NUMBER_SIGN: {
|
||||||
@ -1596,19 +1862,19 @@ Markup Parser::parseMarkup(UErrorCode& status) {
|
|||||||
|
|
||||||
// Parse the options, which must begin with a ' '
|
// Parse the options, which must begin with a ' '
|
||||||
// if present
|
// if present
|
||||||
if (inBounds() && isWhitespace(peek())) {
|
if (inBounds() && (isWhitespace(peek()) || isBidiControl(peek()))) {
|
||||||
OptionAdder<Markup::Builder> optionAdder(builder);
|
OptionAdder<Markup::Builder> optionAdder(builder);
|
||||||
parseOptions(optionAdder, status);
|
parseOptions(optionAdder, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the attributes, which also must begin
|
// Parse the attributes, which also must begin
|
||||||
// with a ' '
|
// with a ' '
|
||||||
if (inBounds() && isWhitespace(peek())) {
|
if (inBounds() && (isWhitespace(peek()) || isBidiControl(peek()))) {
|
||||||
AttributeAdder<Markup::Builder> attrAdder(builder);
|
AttributeAdder<Markup::Builder> attrAdder(builder);
|
||||||
parseAttributes(attrAdder, status);
|
parseAttributes(attrAdder, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
parseOptionalWhitespace(status);
|
parseOptionalWhitespace();
|
||||||
|
|
||||||
bool standalone = false;
|
bool standalone = false;
|
||||||
// Check if this is a standalone or not
|
// Check if this is a standalone or not
|
||||||
@ -1656,7 +1922,7 @@ std::variant<Expression, Markup> Parser::parsePlaceholder(UErrorCode& status) {
|
|||||||
isMarkup = true;
|
isMarkup = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!isWhitespace(c)){
|
if (!(isWhitespace(c) || isBidiControl(c))) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tempIndex++;
|
tempIndex++;
|
||||||
@ -1712,7 +1978,7 @@ Pattern Parser::parseSimpleMessage(UErrorCode& status) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Don't loop infinitely
|
// Don't loop infinitely
|
||||||
if (errors.hasSyntaxError()) {
|
if (errors.hasSyntaxError() || U_FAILURE(status)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1720,6 +1986,22 @@ Pattern Parser::parseSimpleMessage(UErrorCode& status) {
|
|||||||
return result.build(status);
|
return result.build(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Parser::parseVariant(UErrorCode& status) {
|
||||||
|
CHECK_ERROR(status);
|
||||||
|
|
||||||
|
// At least one key is required
|
||||||
|
SelectorKeys keyList(parseNonEmptyKeys(status));
|
||||||
|
|
||||||
|
// parseNonEmptyKeys() consumes any trailing whitespace,
|
||||||
|
// so the pattern can be consumed next.
|
||||||
|
|
||||||
|
// Restore precondition before calling parsePattern()
|
||||||
|
// (which must return a non-null value)
|
||||||
|
CHECK_BOUNDS(status);
|
||||||
|
Pattern rhs = parseQuotedPattern(status);
|
||||||
|
|
||||||
|
dataModel.addVariant(std::move(keyList), std::move(rhs), status);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Consume a `selectors` (matching the nonterminal in the grammar),
|
Consume a `selectors` (matching the nonterminal in the grammar),
|
||||||
@ -1739,22 +2021,25 @@ void Parser::parseSelectors(UErrorCode& status) {
|
|||||||
// Parse selectors
|
// Parse selectors
|
||||||
// "Backtracking" is required here. It's not clear if whitespace is
|
// "Backtracking" is required here. It's not clear if whitespace is
|
||||||
// (`[s]` selector) or (`[s]` variant)
|
// (`[s]` selector) or (`[s]` variant)
|
||||||
while (isWhitespace(peek()) || peek() == LEFT_CURLY_BRACE) {
|
while (isWhitespace(peek()) || peek() == DOLLAR) {
|
||||||
parseOptionalWhitespace(status);
|
int32_t whitespaceStart = index;
|
||||||
|
parseRequiredWhitespace(status);
|
||||||
// Restore precondition
|
// Restore precondition
|
||||||
CHECK_BOUNDS(status);
|
CHECK_BOUNDS(status);
|
||||||
if (peek() != LEFT_CURLY_BRACE) {
|
if (peek() != DOLLAR) {
|
||||||
// This is not necessarily an error, but rather,
|
// This is not necessarily an error, but rather,
|
||||||
// means the whitespace we parsed was the optional
|
// means the whitespace we parsed was the optional
|
||||||
// whitespace preceding the first variant, not the
|
// whitespace preceding the first variant, not the
|
||||||
// optional whitespace preceding a subsequent expression.
|
// required whitespace preceding a subsequent variable.
|
||||||
|
// In that case, "push back" the whitespace.
|
||||||
|
normalizedInput.truncate(normalizedInput.length() - 1);
|
||||||
|
index = whitespaceStart;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Expression expression;
|
VariableName var = parseVariableName(status);
|
||||||
expression = parseExpression(status);
|
|
||||||
empty = false;
|
empty = false;
|
||||||
|
|
||||||
dataModel.addSelector(std::move(expression), status);
|
dataModel.addSelector(std::move(var), status);
|
||||||
CHECK_ERROR(status);
|
CHECK_ERROR(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1770,27 +2055,29 @@ void Parser::parseSelectors(UErrorCode& status) {
|
|||||||
} \
|
} \
|
||||||
|
|
||||||
// Parse variants
|
// Parse variants
|
||||||
while (isWhitespace(peek()) || isKeyStart(peek())) {
|
// matcher = match-statement s variant *(o variant)
|
||||||
// Trailing whitespace is allowed
|
|
||||||
parseOptionalWhitespace(status);
|
// Parse first variant
|
||||||
|
parseRequiredWhitespace(status);
|
||||||
|
if (!inBounds()) {
|
||||||
|
ERROR(status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
parseVariant(status);
|
||||||
|
if (!inBounds()) {
|
||||||
|
// Not an error; there might be only one variant
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (isWhitespace(peek()) || isBidiControl(peek()) || isKeyStart(peek())) {
|
||||||
|
parseOptionalWhitespace();
|
||||||
|
// Restore the precondition.
|
||||||
|
// Trailing whitespace is allowed.
|
||||||
if (!inBounds()) {
|
if (!inBounds()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// At least one key is required
|
parseVariant(status);
|
||||||
SelectorKeys keyList(parseNonEmptyKeys(status));
|
|
||||||
|
|
||||||
CHECK_ERROR(status);
|
|
||||||
|
|
||||||
// parseNonEmptyKeys() consumes any trailing whitespace,
|
|
||||||
// so the pattern can be consumed next.
|
|
||||||
|
|
||||||
// Restore precondition before calling parsePattern()
|
|
||||||
// (which must return a non-null value)
|
|
||||||
CHECK_BOUNDS(status);
|
|
||||||
Pattern rhs = parseQuotedPattern(status);
|
|
||||||
|
|
||||||
dataModel.addVariant(std::move(keyList), std::move(rhs), status);
|
|
||||||
|
|
||||||
// Restore the precondition, *without* erroring out if we've
|
// Restore the precondition, *without* erroring out if we've
|
||||||
// reached the end of input. That's because it's valid for the
|
// reached the end of input. That's because it's valid for the
|
||||||
@ -1799,6 +2086,10 @@ void Parser::parseSelectors(UErrorCode& status) {
|
|||||||
// Because if we don't check it here, the `isWhitespace()` call in
|
// Because if we don't check it here, the `isWhitespace()` call in
|
||||||
// the loop head will read off the end of the input string.
|
// the loop head will read off the end of the input string.
|
||||||
CHECK_END_OF_INPUT
|
CHECK_END_OF_INPUT
|
||||||
|
|
||||||
|
if (errors.hasSyntaxError() || U_FAILURE(status)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1871,7 +2162,7 @@ void Parser::parse(UParseError &parseErrorResult, UErrorCode& status) {
|
|||||||
bool complex = false;
|
bool complex = false;
|
||||||
// First, "look ahead" to determine if this is a simple or complex
|
// First, "look ahead" to determine if this is a simple or complex
|
||||||
// message. To do that, check the first non-whitespace character.
|
// message. To do that, check the first non-whitespace character.
|
||||||
while (inBounds(index) && isWhitespace(peek())) {
|
while (inBounds(index) && (isWhitespace(peek()) || isBidiControl(peek()))) {
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1891,10 +2182,10 @@ void Parser::parse(UParseError &parseErrorResult, UErrorCode& status) {
|
|||||||
// Message can be empty, so we need to only look ahead
|
// Message can be empty, so we need to only look ahead
|
||||||
// if we know it's non-empty
|
// if we know it's non-empty
|
||||||
if (complex) {
|
if (complex) {
|
||||||
parseOptionalWhitespace(status);
|
parseOptionalWhitespace();
|
||||||
parseDeclarations(status);
|
parseDeclarations(status);
|
||||||
parseBody(status);
|
parseBody(status);
|
||||||
parseOptionalWhitespace(status);
|
parseOptionalWhitespace();
|
||||||
} else {
|
} else {
|
||||||
// Simple message
|
// Simple message
|
||||||
// For normalization, quote the pattern
|
// For normalization, quote the pattern
|
||||||
@ -1926,3 +2217,4 @@ U_NAMESPACE_END
|
|||||||
|
|
||||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||||
|
|
||||||
|
#endif /* #if !UCONFIG_NO_NORMALIZATION */
|
||||||
|
@ -10,12 +10,15 @@
|
|||||||
|
|
||||||
#include "unicode/messageformat2_data_model.h"
|
#include "unicode/messageformat2_data_model.h"
|
||||||
#include "unicode/parseerr.h"
|
#include "unicode/parseerr.h"
|
||||||
|
#include "unicode/uniset.h"
|
||||||
|
|
||||||
#include "messageformat2_allocation.h"
|
#include "messageformat2_allocation.h"
|
||||||
#include "messageformat2_errors.h"
|
#include "messageformat2_errors.h"
|
||||||
|
|
||||||
#if U_SHOW_CPLUSPLUS_API
|
#if U_SHOW_CPLUSPLUS_API
|
||||||
|
|
||||||
|
#if !UCONFIG_NO_NORMALIZATION
|
||||||
|
|
||||||
#if !UCONFIG_NO_FORMATTING
|
#if !UCONFIG_NO_FORMATTING
|
||||||
|
|
||||||
#if !UCONFIG_NO_MF2
|
#if !UCONFIG_NO_MF2
|
||||||
@ -54,6 +57,26 @@ namespace message2 {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Initialization of UnicodeSets
|
||||||
|
namespace unisets {
|
||||||
|
enum Key {
|
||||||
|
CONTENT,
|
||||||
|
WHITESPACE,
|
||||||
|
BIDI,
|
||||||
|
ALPHA,
|
||||||
|
DIGIT,
|
||||||
|
NAME_START,
|
||||||
|
NAME_CHAR,
|
||||||
|
TEXT,
|
||||||
|
QUOTED,
|
||||||
|
ESCAPABLE,
|
||||||
|
UNISETS_KEY_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
U_I18N_API const UnicodeSet* get(Key key, UErrorCode& status);
|
||||||
|
}
|
||||||
|
|
||||||
// Parser class (private)
|
// Parser class (private)
|
||||||
class Parser : public UMemory {
|
class Parser : public UMemory {
|
||||||
public:
|
public:
|
||||||
@ -82,8 +105,23 @@ namespace message2 {
|
|||||||
UChar postContext[U_PARSE_CONTEXT_LEN];
|
UChar postContext[U_PARSE_CONTEXT_LEN];
|
||||||
} MessageParseError;
|
} MessageParseError;
|
||||||
|
|
||||||
Parser(const UnicodeString &input, MFDataModel::Builder& dataModelBuilder, StaticErrors& e, UnicodeString& normalizedInputRef)
|
Parser(const UnicodeString &input,
|
||||||
: source(input), index(0), errors(e), normalizedInput(normalizedInputRef), dataModel(dataModelBuilder) {
|
MFDataModel::Builder& dataModelBuilder,
|
||||||
|
StaticErrors& e,
|
||||||
|
UnicodeString& normalizedInputRef,
|
||||||
|
UErrorCode& status)
|
||||||
|
: contentChars(unisets::get(unisets::CONTENT, status)),
|
||||||
|
whitespaceChars(unisets::get(unisets::WHITESPACE, status)),
|
||||||
|
bidiControlChars(unisets::get(unisets::BIDI, status)),
|
||||||
|
alphaChars(unisets::get(unisets::ALPHA, status)),
|
||||||
|
digitChars(unisets::get(unisets::DIGIT, status)),
|
||||||
|
nameStartChars(unisets::get(unisets::NAME_START, status)),
|
||||||
|
nameChars(unisets::get(unisets::NAME_CHAR, status)),
|
||||||
|
textChars(unisets::get(unisets::TEXT, status)),
|
||||||
|
quotedChars(unisets::get(unisets::QUOTED, status)),
|
||||||
|
escapableChars(unisets::get(unisets::ESCAPABLE, status)),
|
||||||
|
source(input), index(0), errors(e), normalizedInput(normalizedInputRef), dataModel(dataModelBuilder) {
|
||||||
|
(void) status;
|
||||||
parseError.line = 0;
|
parseError.line = 0;
|
||||||
parseError.offset = 0;
|
parseError.offset = 0;
|
||||||
parseError.lengthBeforeCurrentLine = 0;
|
parseError.lengthBeforeCurrentLine = 0;
|
||||||
@ -91,6 +129,20 @@ namespace message2 {
|
|||||||
parseError.postContext[0] = '\0';
|
parseError.postContext[0] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isContentChar(UChar32) const;
|
||||||
|
bool isBidiControl(UChar32) const;
|
||||||
|
bool isWhitespace(UChar32) const;
|
||||||
|
bool isTextChar(UChar32) const;
|
||||||
|
bool isQuotedChar(UChar32) const;
|
||||||
|
bool isEscapableChar(UChar32) const;
|
||||||
|
bool isAlpha(UChar32) const;
|
||||||
|
bool isDigit(UChar32) const;
|
||||||
|
bool isNameStart(UChar32) const;
|
||||||
|
bool isNameChar(UChar32) const;
|
||||||
|
bool isUnquotedStart(UChar32) const;
|
||||||
|
bool isLiteralStart(UChar32) const;
|
||||||
|
bool isKeyStart(UChar32) const;
|
||||||
|
|
||||||
static void translateParseError(const MessageParseError&, UParseError&);
|
static void translateParseError(const MessageParseError&, UParseError&);
|
||||||
static void setParseError(MessageParseError&, uint32_t);
|
static void setParseError(MessageParseError&, uint32_t);
|
||||||
void maybeAdvanceLine();
|
void maybeAdvanceLine();
|
||||||
@ -100,11 +152,13 @@ namespace message2 {
|
|||||||
void parseUnsupportedStatement(UErrorCode&);
|
void parseUnsupportedStatement(UErrorCode&);
|
||||||
void parseLocalDeclaration(UErrorCode&);
|
void parseLocalDeclaration(UErrorCode&);
|
||||||
void parseInputDeclaration(UErrorCode&);
|
void parseInputDeclaration(UErrorCode&);
|
||||||
void parseSelectors(UErrorCode&);
|
void parseSelectors(UErrorCode&);
|
||||||
|
void parseVariant(UErrorCode&);
|
||||||
|
|
||||||
void parseWhitespaceMaybeRequired(bool, UErrorCode&);
|
void parseRequiredWS(UErrorCode&);
|
||||||
void parseRequiredWhitespace(UErrorCode&);
|
void parseRequiredWhitespace(UErrorCode&);
|
||||||
void parseOptionalWhitespace(UErrorCode&);
|
void parseOptionalBidi();
|
||||||
|
void parseOptionalWhitespace();
|
||||||
void parseToken(UChar32, UErrorCode&);
|
void parseToken(UChar32, UErrorCode&);
|
||||||
void parseTokenWithWhitespace(UChar32, UErrorCode&);
|
void parseTokenWithWhitespace(UChar32, UErrorCode&);
|
||||||
void parseToken(const std::u16string_view&, UErrorCode&);
|
void parseToken(const std::u16string_view&, UErrorCode&);
|
||||||
@ -149,6 +203,18 @@ namespace message2 {
|
|||||||
bool inBounds(uint32_t i) const { return source.moveIndex32(index, i) < source.length(); }
|
bool inBounds(uint32_t i) const { return source.moveIndex32(index, i) < source.length(); }
|
||||||
bool allConsumed() const { return (int32_t) index == source.length(); }
|
bool allConsumed() const { return (int32_t) index == source.length(); }
|
||||||
|
|
||||||
|
// UnicodeSets for checking character ranges
|
||||||
|
const UnicodeSet* contentChars;
|
||||||
|
const UnicodeSet* whitespaceChars;
|
||||||
|
const UnicodeSet* bidiControlChars;
|
||||||
|
const UnicodeSet* alphaChars;
|
||||||
|
const UnicodeSet* digitChars;
|
||||||
|
const UnicodeSet* nameStartChars;
|
||||||
|
const UnicodeSet* nameChars;
|
||||||
|
const UnicodeSet* textChars;
|
||||||
|
const UnicodeSet* quotedChars;
|
||||||
|
const UnicodeSet* escapableChars;
|
||||||
|
|
||||||
// The input string
|
// The input string
|
||||||
const UnicodeString &source;
|
const UnicodeString &source;
|
||||||
// The current position within the input string -- counting in UChar32
|
// The current position within the input string -- counting in UChar32
|
||||||
@ -165,8 +231,8 @@ namespace message2 {
|
|||||||
|
|
||||||
// The parent builder
|
// The parent builder
|
||||||
MFDataModel::Builder &dataModel;
|
MFDataModel::Builder &dataModel;
|
||||||
}; // class Parser
|
|
||||||
|
|
||||||
|
}; // class Parser
|
||||||
} // namespace message2
|
} // namespace message2
|
||||||
|
|
||||||
U_NAMESPACE_END
|
U_NAMESPACE_END
|
||||||
@ -175,6 +241,8 @@ U_NAMESPACE_END
|
|||||||
|
|
||||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||||
|
|
||||||
|
#endif /* #if !UCONFIG_NO_NORMALIZATION */
|
||||||
|
|
||||||
#endif /* U_SHOW_CPLUSPLUS_API */
|
#endif /* U_SHOW_CPLUSPLUS_API */
|
||||||
|
|
||||||
#endif // MESSAGEFORMAT_PARSER_H
|
#endif // MESSAGEFORMAT_PARSER_H
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include "unicode/utypes.h"
|
#include "unicode/utypes.h"
|
||||||
|
|
||||||
|
#if !UCONFIG_NO_NORMALIZATION
|
||||||
|
|
||||||
#if !UCONFIG_NO_FORMATTING
|
#if !UCONFIG_NO_FORMATTING
|
||||||
|
|
||||||
#if !UCONFIG_NO_MF2
|
#if !UCONFIG_NO_MF2
|
||||||
@ -244,11 +246,12 @@ void Serializer::serializeDeclarations() {
|
|||||||
|
|
||||||
void Serializer::serializeSelectors() {
|
void Serializer::serializeSelectors() {
|
||||||
U_ASSERT(!dataModel.hasPattern());
|
U_ASSERT(!dataModel.hasPattern());
|
||||||
const Expression* selectors = dataModel.getSelectorsInternal();
|
const VariableName* selectors = dataModel.getSelectorsInternal();
|
||||||
|
|
||||||
emit(ID_MATCH);
|
emit(ID_MATCH);
|
||||||
for (int32_t i = 0; i < dataModel.numSelectors(); i++) {
|
for (int32_t i = 0; i < dataModel.numSelectors(); i++) {
|
||||||
// No whitespace needed here -- see `selectors` in the grammar
|
whitespace();
|
||||||
|
emit(DOLLAR);
|
||||||
emit(selectors[i]);
|
emit(selectors[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -256,6 +259,7 @@ void Serializer::serializeSelectors() {
|
|||||||
void Serializer::serializeVariants() {
|
void Serializer::serializeVariants() {
|
||||||
U_ASSERT(!dataModel.hasPattern());
|
U_ASSERT(!dataModel.hasPattern());
|
||||||
const Variant* variants = dataModel.getVariantsInternal();
|
const Variant* variants = dataModel.getVariantsInternal();
|
||||||
|
whitespace();
|
||||||
for (int32_t i = 0; i < dataModel.numVariants(); i++) {
|
for (int32_t i = 0; i < dataModel.numVariants(); i++) {
|
||||||
const Variant& v = variants[i];
|
const Variant& v = variants[i];
|
||||||
emit(v.getKeys());
|
emit(v.getKeys());
|
||||||
@ -285,3 +289,4 @@ U_NAMESPACE_END
|
|||||||
|
|
||||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||||
|
|
||||||
|
#endif /* #if !UCONFIG_NO_NORMALIZATION */
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
#if U_SHOW_CPLUSPLUS_API
|
#if U_SHOW_CPLUSPLUS_API
|
||||||
|
|
||||||
|
#if !UCONFIG_NO_NORMALIZATION
|
||||||
|
|
||||||
#if !UCONFIG_NO_FORMATTING
|
#if !UCONFIG_NO_FORMATTING
|
||||||
|
|
||||||
#if !UCONFIG_NO_MF2
|
#if !UCONFIG_NO_MF2
|
||||||
@ -63,6 +65,8 @@ U_NAMESPACE_END
|
|||||||
|
|
||||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||||
|
|
||||||
|
#endif /* #if !UCONFIG_NO_NORMALIZATION */
|
||||||
|
|
||||||
#endif /* U_SHOW_CPLUSPLUS_API */
|
#endif /* U_SHOW_CPLUSPLUS_API */
|
||||||
|
|
||||||
#endif // MESSAGEFORMAT_SERIALIZER_H
|
#endif // MESSAGEFORMAT_SERIALIZER_H
|
||||||
|
8
deps/icu-small/source/i18n/nfrs.cpp
vendored
8
deps/icu-small/source/i18n/nfrs.cpp
vendored
@ -152,7 +152,7 @@ NFRuleSet::NFRuleSet(RuleBasedNumberFormat *_owner, UnicodeString* descriptions,
|
|||||||
|
|
||||||
UnicodeString& description = descriptions[index]; // !!! make sure index is valid
|
UnicodeString& description = descriptions[index]; // !!! make sure index is valid
|
||||||
|
|
||||||
if (description.length() == 0) {
|
if (description.isEmpty()) {
|
||||||
// throw new IllegalArgumentException("Empty rule set description");
|
// throw new IllegalArgumentException("Empty rule set description");
|
||||||
status = U_PARSE_ERROR;
|
status = U_PARSE_ERROR;
|
||||||
return;
|
return;
|
||||||
@ -177,16 +177,16 @@ NFRuleSet::NFRuleSet(RuleBasedNumberFormat *_owner, UnicodeString* descriptions,
|
|||||||
name.setTo(UNICODE_STRING_SIMPLE("%default"));
|
name.setTo(UNICODE_STRING_SIMPLE("%default"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (description.length() == 0) {
|
if (description.isEmpty()) {
|
||||||
// throw new IllegalArgumentException("Empty rule set description");
|
// throw new IllegalArgumentException("Empty rule set description");
|
||||||
status = U_PARSE_ERROR;
|
status = U_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
fIsPublic = name.indexOf(gPercentPercent, 2, 0) != 0;
|
fIsPublic = name.indexOf(gPercentPercent, 2, 0) != 0;
|
||||||
|
|
||||||
if ( name.endsWith(gNoparse,8) ) {
|
if (name.endsWith(gNoparse, 8)) {
|
||||||
fIsParseable = false;
|
fIsParseable = false;
|
||||||
name.truncate(name.length()-8); // remove the @noparse from the name
|
name.truncate(name.length() - 8); // remove the @noparse from the name
|
||||||
}
|
}
|
||||||
|
|
||||||
// all of the other members of NFRuleSet are initialized
|
// all of the other members of NFRuleSet are initialized
|
||||||
|
39
deps/icu-small/source/i18n/nfrule.cpp
vendored
39
deps/icu-small/source/i18n/nfrule.cpp
vendored
@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
#if U_HAVE_RBNF
|
#if U_HAVE_RBNF
|
||||||
|
|
||||||
#include <limits>
|
|
||||||
#include "unicode/localpointer.h"
|
#include "unicode/localpointer.h"
|
||||||
#include "unicode/rbnf.h"
|
#include "unicode/rbnf.h"
|
||||||
#include "unicode/tblcoll.h"
|
#include "unicode/tblcoll.h"
|
||||||
@ -65,6 +64,7 @@ NFRule::~NFRule()
|
|||||||
|
|
||||||
static const char16_t gLeftBracket = 0x005b;
|
static const char16_t gLeftBracket = 0x005b;
|
||||||
static const char16_t gRightBracket = 0x005d;
|
static const char16_t gRightBracket = 0x005d;
|
||||||
|
static const char16_t gVerticalLine = 0x007C;
|
||||||
static const char16_t gColon = 0x003a;
|
static const char16_t gColon = 0x003a;
|
||||||
static const char16_t gZero = 0x0030;
|
static const char16_t gZero = 0x0030;
|
||||||
static const char16_t gNine = 0x0039;
|
static const char16_t gNine = 0x0039;
|
||||||
@ -147,6 +147,7 @@ NFRule::makeRules(UnicodeString& description,
|
|||||||
// then it's really shorthand for two rules (with one exception)
|
// then it's really shorthand for two rules (with one exception)
|
||||||
LocalPointer<NFRule> rule2;
|
LocalPointer<NFRule> rule2;
|
||||||
UnicodeString sbuf;
|
UnicodeString sbuf;
|
||||||
|
int32_t orElseOp = description.indexOf(gVerticalLine);
|
||||||
|
|
||||||
// we'll actually only split the rule into two rules if its
|
// we'll actually only split the rule into two rules if its
|
||||||
// base value is an even multiple of its divisor (or it's one
|
// base value is an even multiple of its divisor (or it's one
|
||||||
@ -194,9 +195,13 @@ NFRule::makeRules(UnicodeString& description,
|
|||||||
rule2->radix = rule1->radix;
|
rule2->radix = rule1->radix;
|
||||||
rule2->exponent = rule1->exponent;
|
rule2->exponent = rule1->exponent;
|
||||||
|
|
||||||
// rule2's rule text omits the stuff in brackets: initialize
|
// By default, rule2's rule text omits the stuff in brackets,
|
||||||
// its rule text and substitutions accordingly
|
// unless it contains a | between the brackets.
|
||||||
|
// Initialize its rule text and substitutions accordingly.
|
||||||
sbuf.append(description, 0, brack1);
|
sbuf.append(description, 0, brack1);
|
||||||
|
if (orElseOp >= 0) {
|
||||||
|
sbuf.append(description, orElseOp + 1, brack2 - orElseOp - 1);
|
||||||
|
}
|
||||||
if (brack2 + 1 < description.length()) {
|
if (brack2 + 1 < description.length()) {
|
||||||
sbuf.append(description, brack2 + 1, description.length() - brack2 - 1);
|
sbuf.append(description, brack2 + 1, description.length() - brack2 - 1);
|
||||||
}
|
}
|
||||||
@ -207,7 +212,12 @@ NFRule::makeRules(UnicodeString& description,
|
|||||||
// the brackets themselves: initialize _its_ rule text and
|
// the brackets themselves: initialize _its_ rule text and
|
||||||
// substitutions accordingly
|
// substitutions accordingly
|
||||||
sbuf.setTo(description, 0, brack1);
|
sbuf.setTo(description, 0, brack1);
|
||||||
sbuf.append(description, brack1 + 1, brack2 - brack1 - 1);
|
if (orElseOp >= 0) {
|
||||||
|
sbuf.append(description, brack1 + 1, orElseOp - brack1 - 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sbuf.append(description, brack1 + 1, brack2 - brack1 - 1);
|
||||||
|
}
|
||||||
if (brack2 + 1 < description.length()) {
|
if (brack2 + 1 < description.length()) {
|
||||||
sbuf.append(description, brack2 + 1, description.length() - brack2 - 1);
|
sbuf.append(description, brack2 + 1, description.length() - brack2 - 1);
|
||||||
}
|
}
|
||||||
@ -286,18 +296,17 @@ NFRule::parseRuleDescriptor(UnicodeString& description, UErrorCode& status)
|
|||||||
// into "tempValue", skip periods, commas, and spaces,
|
// into "tempValue", skip periods, commas, and spaces,
|
||||||
// stop on a slash or > sign (or at the end of the string),
|
// stop on a slash or > sign (or at the end of the string),
|
||||||
// and throw an exception on any other character
|
// and throw an exception on any other character
|
||||||
int64_t ll_10 = 10;
|
|
||||||
while (p < descriptorLength) {
|
while (p < descriptorLength) {
|
||||||
c = descriptor.charAt(p);
|
c = descriptor.charAt(p);
|
||||||
if (c >= gZero && c <= gNine) {
|
if (c >= gZero && c <= gNine) {
|
||||||
int32_t single_digit = static_cast<int32_t>(c - gZero);
|
int64_t digit = static_cast<int64_t>(c - gZero);
|
||||||
if ((val > 0 && val > (std::numeric_limits<int64_t>::max() - single_digit) / 10) ||
|
if ((val > 0 && val > (INT64_MAX - digit) / 10) ||
|
||||||
(val < 0 && val < (std::numeric_limits<int64_t>::min() - single_digit) / 10)) {
|
(val < 0 && val < (INT64_MIN - digit) / 10)) {
|
||||||
// out of int64_t range
|
// out of int64_t range
|
||||||
status = U_PARSE_ERROR;
|
status = U_PARSE_ERROR;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
val = val * ll_10 + single_digit;
|
val = val * 10 + digit;
|
||||||
}
|
}
|
||||||
else if (c == gSlash || c == gGreaterThan) {
|
else if (c == gSlash || c == gGreaterThan) {
|
||||||
break;
|
break;
|
||||||
@ -322,11 +331,17 @@ NFRule::parseRuleDescriptor(UnicodeString& description, UErrorCode& status)
|
|||||||
if (c == gSlash) {
|
if (c == gSlash) {
|
||||||
val = 0;
|
val = 0;
|
||||||
++p;
|
++p;
|
||||||
ll_10 = 10;
|
|
||||||
while (p < descriptorLength) {
|
while (p < descriptorLength) {
|
||||||
c = descriptor.charAt(p);
|
c = descriptor.charAt(p);
|
||||||
if (c >= gZero && c <= gNine) {
|
if (c >= gZero && c <= gNine) {
|
||||||
val = val * ll_10 + static_cast<int32_t>(c - gZero);
|
int64_t digit = static_cast<int64_t>(c - gZero);
|
||||||
|
if ((val > 0 && val > (INT64_MAX - digit) / 10) ||
|
||||||
|
(val < 0 && val < (INT64_MIN - digit) / 10)) {
|
||||||
|
// out of int64_t range
|
||||||
|
status = U_PARSE_ERROR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
val = val * 10 + digit;
|
||||||
}
|
}
|
||||||
else if (c == gGreaterThan) {
|
else if (c == gGreaterThan) {
|
||||||
break;
|
break;
|
||||||
@ -400,7 +415,7 @@ NFRule::parseRuleDescriptor(UnicodeString& description, UErrorCode& status)
|
|||||||
// finally, if the rule body begins with an apostrophe, strip it off
|
// finally, if the rule body begins with an apostrophe, strip it off
|
||||||
// (this is generally used to put whitespace at the beginning of
|
// (this is generally used to put whitespace at the beginning of
|
||||||
// a rule's rule text)
|
// a rule's rule text)
|
||||||
if (description.length() > 0 && description.charAt(0) == gTick) {
|
if (!description.isEmpty() && description.charAt(0) == gTick) {
|
||||||
description.removeBetween(0, 1);
|
description.removeBetween(0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1133,7 +1133,7 @@ void DecimalQuantity::setDigitPos(int32_t position, int8_t value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DecimalQuantity::shiftLeft(int32_t numDigits) {
|
void DecimalQuantity::shiftLeft(int32_t numDigits) {
|
||||||
if (!usingBytes && precision + numDigits > 16) {
|
if (!usingBytes && precision + numDigits >= 16) {
|
||||||
switchStorage();
|
switchStorage();
|
||||||
}
|
}
|
||||||
if (usingBytes) {
|
if (usingBytes) {
|
||||||
|
50
deps/icu-small/source/i18n/number_longnames.cpp
vendored
50
deps/icu-small/source/i18n/number_longnames.cpp
vendored
@ -48,8 +48,12 @@ constexpr int32_t PER_INDEX = StandardPlural::Form::COUNT + 1;
|
|||||||
* Gender of the word, in languages with grammatical gender.
|
* Gender of the word, in languages with grammatical gender.
|
||||||
*/
|
*/
|
||||||
constexpr int32_t GENDER_INDEX = StandardPlural::Form::COUNT + 2;
|
constexpr int32_t GENDER_INDEX = StandardPlural::Form::COUNT + 2;
|
||||||
|
/**
|
||||||
|
* Denominator constant of the unit.
|
||||||
|
*/
|
||||||
|
constexpr int32_t CONSTANT_DENOMINATOR_INDEX = StandardPlural::Form::COUNT + 3;
|
||||||
// Number of keys in the array populated by PluralTableSink.
|
// Number of keys in the array populated by PluralTableSink.
|
||||||
constexpr int32_t ARRAY_LENGTH = StandardPlural::Form::COUNT + 3;
|
constexpr int32_t ARRAY_LENGTH = StandardPlural::Form::COUNT + 4;
|
||||||
|
|
||||||
// TODO(icu-units#28): load this list from resources, after creating a "&set"
|
// TODO(icu-units#28): load this list from resources, after creating a "&set"
|
||||||
// function for use in ldml2icu rules.
|
// function for use in ldml2icu rules.
|
||||||
@ -1010,6 +1014,11 @@ void LongNameHandler::forArbitraryUnit(const Locale &loc,
|
|||||||
// denominator (the part after the "-per-). If both are empty, fail
|
// denominator (the part after the "-per-). If both are empty, fail
|
||||||
MeasureUnitImpl unit;
|
MeasureUnitImpl unit;
|
||||||
MeasureUnitImpl perUnit;
|
MeasureUnitImpl perUnit;
|
||||||
|
|
||||||
|
if (unitRef.getConstantDenominator(status) != 0) {
|
||||||
|
perUnit.constantDenominator = unitRef.getConstantDenominator(status);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
MeasureUnitImpl fullUnit = MeasureUnitImpl::forMeasureUnitMaybeCopy(unitRef, status);
|
MeasureUnitImpl fullUnit = MeasureUnitImpl::forMeasureUnitMaybeCopy(unitRef, status);
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
@ -1196,6 +1205,12 @@ void LongNameHandler::processPatternTimes(MeasureUnitImpl &&productUnit,
|
|||||||
DerivedComponents derivedTimesCases(loc, "case", "times");
|
DerivedComponents derivedTimesCases(loc, "case", "times");
|
||||||
DerivedComponents derivedPowerCases(loc, "case", "power");
|
DerivedComponents derivedPowerCases(loc, "case", "power");
|
||||||
|
|
||||||
|
if (productUnit.constantDenominator != 0) {
|
||||||
|
CharString constantString;
|
||||||
|
constantString.appendNumber(productUnit.constantDenominator, status);
|
||||||
|
outArray[CONSTANT_DENOMINATOR_INDEX] = UnicodeString::fromUTF8(constantString.toStringPiece());
|
||||||
|
}
|
||||||
|
|
||||||
// 4. For each single_unit in product_unit
|
// 4. For each single_unit in product_unit
|
||||||
for (int32_t singleUnitIndex = 0; singleUnitIndex < productUnit.singleUnits.length();
|
for (int32_t singleUnitIndex = 0; singleUnitIndex < productUnit.singleUnits.length();
|
||||||
singleUnitIndex++) {
|
singleUnitIndex++) {
|
||||||
@ -1454,6 +1469,39 @@ void LongNameHandler::processPatternTimes(MeasureUnitImpl &&productUnit,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 5. Handling constant denominator if it exists.
|
||||||
|
if (productUnit.constantDenominator != 0) {
|
||||||
|
int32_t pluralIndex = -1;
|
||||||
|
for (int32_t index = 0; index < StandardPlural::Form::COUNT; index++) {
|
||||||
|
if (!outArray[index].isBogus()) {
|
||||||
|
pluralIndex = index;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
U_ASSERT(pluralIndex >= 0); // "No plural form found for constant denominator"
|
||||||
|
|
||||||
|
// TODO(ICU-23039):
|
||||||
|
// Improve the handling of constant_denominator representation.
|
||||||
|
// For instance, a constant_denominator of 1000000 should be adaptable to
|
||||||
|
// formats like
|
||||||
|
// 1,000,000, 1e6, or 1 million.
|
||||||
|
// Furthermore, ensure consistent pluralization rules for units. For example,
|
||||||
|
// "meter per 100 seconds" should be evaluated for correct singular/plural
|
||||||
|
// usage: "second" or "seconds"?
|
||||||
|
// Similarly, "kilogram per 1000 meters" should be checked for "meter" or
|
||||||
|
// "meters"?
|
||||||
|
if (outArray[pluralIndex].length() == 0) {
|
||||||
|
outArray[pluralIndex] = outArray[CONSTANT_DENOMINATOR_INDEX];
|
||||||
|
} else {
|
||||||
|
UnicodeString tmp;
|
||||||
|
timesPatternFormatter.format(outArray[CONSTANT_DENOMINATOR_INDEX], outArray[pluralIndex],
|
||||||
|
tmp, status);
|
||||||
|
outArray[pluralIndex] = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (int32_t pluralIndex = 0; pluralIndex < StandardPlural::Form::COUNT; pluralIndex++) {
|
for (int32_t pluralIndex = 0; pluralIndex < StandardPlural::Form::COUNT; pluralIndex++) {
|
||||||
if (globalPlaceholder[pluralIndex] == PH_BEGINNING) {
|
if (globalPlaceholder[pluralIndex] == PH_BEGINNING) {
|
||||||
UnicodeString tmp;
|
UnicodeString tmp;
|
||||||
|
9
deps/icu-small/source/i18n/number_mapper.cpp
vendored
9
deps/icu-small/source/i18n/number_mapper.cpp
vendored
@ -74,9 +74,11 @@ MacroProps NumberPropertyMapper::oldToNew(const DecimalFormatProperties& propert
|
|||||||
!properties.currencyPluralInfo.fPtr.isNull() ||
|
!properties.currencyPluralInfo.fPtr.isNull() ||
|
||||||
!properties.currencyUsage.isNull() ||
|
!properties.currencyUsage.isNull() ||
|
||||||
warehouse.affixProvider.get().hasCurrencySign());
|
warehouse.affixProvider.get().hasCurrencySign());
|
||||||
CurrencyUnit currency = resolveCurrency(properties, locale, status);
|
CurrencyUnit currency;
|
||||||
UCurrencyUsage currencyUsage = properties.currencyUsage.getOrDefault(UCURR_USAGE_STANDARD);
|
UCurrencyUsage currencyUsage;
|
||||||
if (useCurrency) {
|
if (useCurrency) {
|
||||||
|
currency = resolveCurrency(properties, locale, status);
|
||||||
|
currencyUsage = properties.currencyUsage.getOrDefault(UCURR_USAGE_STANDARD);
|
||||||
// NOTE: Slicing is OK.
|
// NOTE: Slicing is OK.
|
||||||
macros.unit = currency; // NOLINT
|
macros.unit = currency; // NOLINT
|
||||||
}
|
}
|
||||||
@ -129,6 +131,7 @@ MacroProps NumberPropertyMapper::oldToNew(const DecimalFormatProperties& propert
|
|||||||
}
|
}
|
||||||
Precision precision;
|
Precision precision;
|
||||||
if (!properties.currencyUsage.isNull()) {
|
if (!properties.currencyUsage.isNull()) {
|
||||||
|
U_ASSERT(useCurrency);
|
||||||
precision = Precision::constructCurrency(currencyUsage).withCurrency(currency);
|
precision = Precision::constructCurrency(currencyUsage).withCurrency(currency);
|
||||||
} else if (roundingIncrement != 0.0) {
|
} else if (roundingIncrement != 0.0) {
|
||||||
if (PatternStringUtils::ignoreRoundingIncrement(roundingIncrement, maxFrac)) {
|
if (PatternStringUtils::ignoreRoundingIncrement(roundingIncrement, maxFrac)) {
|
||||||
@ -276,7 +279,7 @@ MacroProps NumberPropertyMapper::oldToNew(const DecimalFormatProperties& propert
|
|||||||
exportedProperties->maximumIntegerDigits = maxInt == -1 ? INT32_MAX : maxInt;
|
exportedProperties->maximumIntegerDigits = maxInt == -1 ? INT32_MAX : maxInt;
|
||||||
|
|
||||||
Precision rounding_;
|
Precision rounding_;
|
||||||
if (precision.fType == Precision::PrecisionType::RND_CURRENCY) {
|
if (useCurrency && precision.fType == Precision::PrecisionType::RND_CURRENCY) {
|
||||||
rounding_ = precision.withCurrency(currency, status);
|
rounding_ = precision.withCurrency(currency, status);
|
||||||
} else {
|
} else {
|
||||||
rounding_ = precision;
|
rounding_ = precision;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user