Use TLS and converter manager in locale backend.
This commit is contained in:
parent
bcadc4ca66
commit
bf5ff48092
@ -5,6 +5,7 @@
|
||||
#ifndef _ICU_CATEGORY_DATA_H
|
||||
#define _ICU_CATEGORY_DATA_H
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include <unicode/locid.h>
|
||||
#include <unicode/ucnv.h>
|
||||
@ -12,6 +13,8 @@
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
#include "ICUConverterManager.h"
|
||||
|
||||
|
||||
namespace BPrivate {
|
||||
namespace Libroot {
|
||||
@ -19,14 +22,14 @@ namespace Libroot {
|
||||
|
||||
class ICUCategoryData {
|
||||
public:
|
||||
ICUCategoryData();
|
||||
ICUCategoryData(pthread_key_t tlsKey);
|
||||
virtual ~ICUCategoryData();
|
||||
|
||||
virtual status_t SetTo(const Locale& locale,
|
||||
const char* posixLocaleName);
|
||||
virtual status_t SetToPosix();
|
||||
|
||||
const char * PosixLocaleName()
|
||||
const char* PosixLocaleName()
|
||||
{ return fPosixLocaleName; }
|
||||
|
||||
protected:
|
||||
@ -35,16 +38,18 @@ protected:
|
||||
char* destination, int destinationSize,
|
||||
const char* defaultValue = "");
|
||||
|
||||
status_t _GetConverter(ICUConverterRef& converterRefOut);
|
||||
|
||||
static const uint16 skMaxPosixLocaleNameLen = 128;
|
||||
static const size_t skLCBufSize = 16;
|
||||
|
||||
pthread_key_t fThreadLocalStorageKey;
|
||||
Locale fLocale;
|
||||
UConverter* fConverter;
|
||||
char fPosixLocaleName[skMaxPosixLocaleNameLen];
|
||||
char fGivenCharset[UCNV_MAX_CONVERTER_NAME_LENGTH];
|
||||
|
||||
private:
|
||||
status_t _SetupConverter();
|
||||
status_t _SetupConverter();
|
||||
};
|
||||
|
||||
|
||||
|
@ -19,7 +19,7 @@ class ICUCollateData : public ICUCategoryData {
|
||||
typedef ICUCategoryData inherited;
|
||||
|
||||
public:
|
||||
ICUCollateData();
|
||||
ICUCollateData(pthread_key_t tlsKey);
|
||||
virtual ~ICUCollateData();
|
||||
|
||||
virtual status_t SetTo(const Locale& locale,
|
||||
|
@ -17,7 +17,7 @@ namespace Libroot {
|
||||
class ICUCtypeData : public ICUCategoryData {
|
||||
typedef ICUCategoryData inherited;
|
||||
public:
|
||||
ICUCtypeData();
|
||||
ICUCtypeData(pthread_key_t tlsKey);
|
||||
virtual ~ICUCtypeData();
|
||||
|
||||
void Initialize(LocaleCtypeDataBridge* dataBridge);
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "LocaleBackend.h"
|
||||
|
||||
#include <locale.h>
|
||||
#include <pthread.h>
|
||||
#include <timelocal.h>
|
||||
|
||||
#include "ICUCollateData.h"
|
||||
@ -57,6 +58,9 @@ private:
|
||||
const char* _QueryLocale(int category);
|
||||
const char* _SetPosixLocale(int category);
|
||||
|
||||
static pthread_key_t _CreateThreadLocalStorageKey();
|
||||
static void _DestroyThreadLocalStorageValue(void* value);
|
||||
|
||||
// buffer for locale names (up to one per category)
|
||||
char fLocaleDescription[512];
|
||||
|
||||
@ -64,6 +68,9 @@ private:
|
||||
struct lconv fLocaleConv;
|
||||
struct lc_time_t fLCTimeInfo;
|
||||
|
||||
//
|
||||
pthread_key_t fThreadLocalStorageKey;
|
||||
|
||||
// these work on the data containers above
|
||||
ICUCollateData fCollateData;
|
||||
ICUCtypeData fCtypeData;
|
||||
|
@ -21,6 +21,8 @@ class ICULocaleconvData : public ICUCategoryData {
|
||||
typedef ICUCategoryData inherited;
|
||||
|
||||
protected:
|
||||
ICULocaleconvData(pthread_key_t tlsKey);
|
||||
|
||||
status_t _SetLocaleconvEntry(
|
||||
const DecimalFormatSymbols* formatSymbols,
|
||||
char* destination, FormatSymbol symbol,
|
||||
|
@ -16,7 +16,10 @@ namespace Libroot {
|
||||
|
||||
class ICUMessagesData : public ICUCategoryData {
|
||||
typedef ICUCategoryData inherited;
|
||||
|
||||
public:
|
||||
ICUMessagesData(pthread_key_t tlsKey);
|
||||
|
||||
virtual status_t SetTo(const Locale& locale,
|
||||
const char* posixLocaleName);
|
||||
virtual status_t SetToPosix();
|
||||
|
@ -18,6 +18,7 @@ namespace Libroot {
|
||||
|
||||
class ICUMonetaryData : public ICULocaleconvData {
|
||||
typedef ICULocaleconvData inherited;
|
||||
|
||||
public:
|
||||
static const int32 kParenthesesAroundCurrencyAndValue = 0;
|
||||
static const int32 kSignPrecedesCurrencyAndValue = 1;
|
||||
@ -25,7 +26,8 @@ public:
|
||||
static const int32 kSignImmediatelyPrecedesCurrency = 3;
|
||||
static const int32 kSignImmediatelySucceedsCurrency = 4;
|
||||
|
||||
ICUMonetaryData(struct lconv& localeConv);
|
||||
ICUMonetaryData(pthread_key_t tlsKey,
|
||||
struct lconv& localeConv);
|
||||
|
||||
void Initialize(
|
||||
LocaleMonetaryDataBridge* dataBridge);
|
||||
|
@ -18,7 +18,8 @@ class ICUNumericData : public ICULocaleconvData {
|
||||
typedef ICULocaleconvData inherited;
|
||||
|
||||
public:
|
||||
ICUNumericData(struct lconv& localeConv);
|
||||
ICUNumericData(pthread_key_t tlsKey,
|
||||
struct lconv& localeConv);
|
||||
|
||||
void Initialize(LocaleNumericDataBridge* dataBridge);
|
||||
|
||||
|
@ -21,7 +21,8 @@ namespace Libroot {
|
||||
class ICUTimeData : public ICUCategoryData {
|
||||
typedef ICUCategoryData inherited;
|
||||
public:
|
||||
ICUTimeData(struct lc_time_t& lcTimeInfo);
|
||||
ICUTimeData(pthread_key_t tlsKey,
|
||||
struct lc_time_t& lcTimeInfo);
|
||||
~ICUTimeData();
|
||||
|
||||
void Initialize(LocaleTimeDataBridge* dataBridge);
|
||||
|
@ -15,9 +15,7 @@ namespace BPrivate {
|
||||
namespace Libroot {
|
||||
|
||||
|
||||
ICUCategoryData::ICUCategoryData()
|
||||
:
|
||||
fConverter(NULL)
|
||||
ICUCategoryData::ICUCategoryData(pthread_key_t tlsKey)
|
||||
{
|
||||
*fPosixLocaleName = '\0';
|
||||
*fGivenCharset = '\0';
|
||||
@ -26,32 +24,42 @@ ICUCategoryData::ICUCategoryData()
|
||||
|
||||
ICUCategoryData::~ICUCategoryData()
|
||||
{
|
||||
if (fConverter)
|
||||
ucnv_close(fConverter);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ICUCategoryData::_SetupConverter()
|
||||
ICUCategoryData::_GetConverter(ICUConverterRef& converterRefOut)
|
||||
{
|
||||
if (fConverter != NULL) {
|
||||
ucnv_close(fConverter);
|
||||
fConverter = NULL;
|
||||
// we use different converter-IDs per thread in order to avoid converters
|
||||
// being used by more than one thread
|
||||
ICUThreadLocalStorageValue* tlsValue = NULL;
|
||||
status_t result = ICUThreadLocalStorageValue::GetInstanceForKey(
|
||||
fThreadLocalStorageKey, tlsValue);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
ICUConverterRef converterRef;
|
||||
result = ICUConverterManager::Instance()->GetConverter(
|
||||
tlsValue->converterID, converterRef);
|
||||
if (result == B_OK) {
|
||||
if (strcmp(converterRef->Charset(), fGivenCharset) == 0) {
|
||||
converterRefOut = converterRef;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// charset no longer matches the converter, we need to dump it and
|
||||
// create a new one
|
||||
ICUConverterManager::Instance()->DropConverter(tlsValue->converterID);
|
||||
tlsValue->converterID = 0;
|
||||
}
|
||||
|
||||
UErrorCode icuStatus = U_ZERO_ERROR;
|
||||
fConverter = ucnv_open(fGivenCharset, &icuStatus);
|
||||
if (fConverter == NULL)
|
||||
return B_NAME_NOT_FOUND;
|
||||
// create a new converter for the current charset
|
||||
result = ICUConverterManager::Instance()->CreateConverter(fGivenCharset,
|
||||
converterRef, tlsValue->converterID);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
icuStatus = U_ZERO_ERROR;
|
||||
ucnv_setToUCallBack(fConverter, UCNV_TO_U_CALLBACK_STOP, NULL, NULL,
|
||||
NULL, &icuStatus);
|
||||
icuStatus = U_ZERO_ERROR;
|
||||
ucnv_setFromUCallBack(fConverter, UCNV_FROM_U_CALLBACK_STOP, NULL, NULL,
|
||||
NULL, &icuStatus);
|
||||
if (!U_SUCCESS(icuStatus))
|
||||
return B_ERROR;
|
||||
converterRefOut = converterRef;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@ -105,10 +113,13 @@ ICUCategoryData::_ConvertUnicodeStringToLocaleconvEntry(
|
||||
const UnicodeString& string, char* destination, int destinationSize,
|
||||
const char* defaultValue)
|
||||
{
|
||||
status_t result = B_OK;
|
||||
UErrorCode icuStatus = U_ZERO_ERROR;
|
||||
ICUConverterRef converterRef;
|
||||
status_t result = _GetConverter(converterRef);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
ucnv_fromUChars(fConverter, destination, destinationSize,
|
||||
UErrorCode icuStatus = U_ZERO_ERROR;
|
||||
ucnv_fromUChars(converterRef->Converter(), destination, destinationSize,
|
||||
string.getBuffer(), string.length(), &icuStatus);
|
||||
if (!U_SUCCESS(icuStatus)) {
|
||||
switch (icuStatus) {
|
||||
@ -131,5 +142,13 @@ ICUCategoryData::_ConvertUnicodeStringToLocaleconvEntry(
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ICUCategoryData::_SetupConverter()
|
||||
{
|
||||
ICUConverterRef converterRef;
|
||||
return _GetConverter(converterRef);
|
||||
}
|
||||
|
||||
|
||||
} // namespace Libroot
|
||||
} // namespace BPrivate
|
||||
|
@ -10,13 +10,16 @@
|
||||
|
||||
#include <unicode/unistr.h>
|
||||
|
||||
#include "ICUConverterManager.h"
|
||||
|
||||
|
||||
namespace BPrivate {
|
||||
namespace Libroot {
|
||||
|
||||
|
||||
ICUCollateData::ICUCollateData()
|
||||
ICUCollateData::ICUCollateData(pthread_key_t tlsKey)
|
||||
:
|
||||
inherited(tlsKey),
|
||||
fCollator(NULL)
|
||||
{
|
||||
}
|
||||
@ -150,8 +153,14 @@ ICUCollateData::_ToUnicodeString(const char* in, UnicodeString& out)
|
||||
if (inLen == 0)
|
||||
return B_OK;
|
||||
|
||||
ICUConverterRef converterRef;
|
||||
status_t result = _GetConverter(converterRef);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
UErrorCode icuStatus = U_ZERO_ERROR;
|
||||
int32_t outLen = ucnv_toUChars(fConverter, NULL, 0, in, inLen, &icuStatus);
|
||||
int32_t outLen = ucnv_toUChars(converterRef->Converter(), NULL, 0, in,
|
||||
inLen, &icuStatus);
|
||||
if (icuStatus != U_BUFFER_OVERFLOW_ERROR)
|
||||
return B_BAD_VALUE;
|
||||
if (outLen < 0)
|
||||
@ -161,8 +170,8 @@ ICUCollateData::_ToUnicodeString(const char* in, UnicodeString& out)
|
||||
|
||||
UChar* outBuf = out.getBuffer(outLen + 1);
|
||||
icuStatus = U_ZERO_ERROR;
|
||||
outLen
|
||||
= ucnv_toUChars(fConverter, outBuf, outLen + 1, in, inLen, &icuStatus);
|
||||
outLen = ucnv_toUChars(converterRef->Converter(), outBuf, outLen + 1, in,
|
||||
inLen, &icuStatus);
|
||||
if (!U_SUCCESS(icuStatus)) {
|
||||
out.releaseBuffer(0);
|
||||
return B_BAD_VALUE;
|
||||
|
@ -16,8 +16,9 @@ namespace BPrivate {
|
||||
namespace Libroot {
|
||||
|
||||
|
||||
ICUCtypeData::ICUCtypeData()
|
||||
ICUCtypeData::ICUCtypeData(pthread_key_t tlsKey)
|
||||
:
|
||||
inherited(tlsKey),
|
||||
fDataBridge(NULL)
|
||||
{
|
||||
}
|
||||
@ -47,7 +48,14 @@ ICUCtypeData::SetTo(const Locale& locale, const char* posixLocaleName)
|
||||
|
||||
UErrorCode icuStatus = U_ZERO_ERROR;
|
||||
|
||||
ucnv_reset(fConverter);
|
||||
ICUConverterRef converterRef;
|
||||
result = _GetConverter(converterRef);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
UConverter* converter = converterRef->Converter();
|
||||
|
||||
ucnv_reset(converter);
|
||||
char buffer[] = { 0, 0 };
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
const char* source = buffer;
|
||||
@ -55,7 +63,7 @@ ICUCtypeData::SetTo(const Locale& locale, const char* posixLocaleName)
|
||||
buffer[1] = '\0';
|
||||
icuStatus = U_ZERO_ERROR;
|
||||
UChar32 unicodeChar
|
||||
= ucnv_getNextUChar(fConverter, &source, source + 1, &icuStatus);
|
||||
= ucnv_getNextUChar(converter, &source, source + 1, &icuStatus);
|
||||
|
||||
unsigned short classInfo = 0;
|
||||
unsigned int toLower = i;
|
||||
@ -88,13 +96,13 @@ ICUCtypeData::SetTo(const Locale& locale, const char* posixLocaleName)
|
||||
|
||||
UChar lowerChar = u_tolower(unicodeChar);
|
||||
icuStatus = U_ZERO_ERROR;
|
||||
ucnv_fromUChars(fConverter, buffer, 1, &lowerChar, 1, &icuStatus);
|
||||
ucnv_fromUChars(converter, buffer, 1, &lowerChar, 1, &icuStatus);
|
||||
if (U_SUCCESS(icuStatus))
|
||||
toLower = (unsigned char)buffer[0];
|
||||
|
||||
UChar upperChar = u_toupper(unicodeChar);
|
||||
icuStatus = U_ZERO_ERROR;
|
||||
ucnv_fromUChars(fConverter, buffer, 1, &upperChar, 1, &icuStatus);
|
||||
ucnv_fromUChars(converter, buffer, 1, &upperChar, 1, &icuStatus);
|
||||
if (U_SUCCESS(icuStatus))
|
||||
toUpper = (unsigned char)buffer[0];
|
||||
}
|
||||
|
@ -28,9 +28,13 @@ CreateInstance()
|
||||
|
||||
ICULocaleBackend::ICULocaleBackend()
|
||||
:
|
||||
fMonetaryData(fLocaleConv),
|
||||
fNumericData(fLocaleConv),
|
||||
fTimeData(fLCTimeInfo),
|
||||
fThreadLocalStorageKey(_CreateThreadLocalStorageKey()),
|
||||
fCollateData(fThreadLocalStorageKey),
|
||||
fCtypeData(fThreadLocalStorageKey),
|
||||
fMessagesData(fThreadLocalStorageKey),
|
||||
fMonetaryData(fThreadLocalStorageKey, fLocaleConv),
|
||||
fNumericData(fThreadLocalStorageKey, fLocaleConv),
|
||||
fTimeData(fThreadLocalStorageKey, fLCTimeInfo),
|
||||
fTimeConversion(fTimeData)
|
||||
{
|
||||
}
|
||||
@ -38,6 +42,7 @@ ICULocaleBackend::ICULocaleBackend()
|
||||
|
||||
ICULocaleBackend::~ICULocaleBackend()
|
||||
{
|
||||
pthread_key_delete(fThreadLocalStorageKey);
|
||||
}
|
||||
|
||||
|
||||
@ -371,5 +376,25 @@ ICULocaleBackend::_SetPosixLocale(int category)
|
||||
}
|
||||
|
||||
|
||||
pthread_key_t
|
||||
ICULocaleBackend::_CreateThreadLocalStorageKey()
|
||||
{
|
||||
pthread_key_t key;
|
||||
|
||||
pthread_key_create(&key, ICULocaleBackend::_DestroyThreadLocalStorageValue);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
void ICULocaleBackend::_DestroyThreadLocalStorageValue(void* value)
|
||||
{
|
||||
ICUThreadLocalStorageValue* tlsValue
|
||||
= static_cast<ICUThreadLocalStorageValue*>(value);
|
||||
|
||||
delete tlsValue;
|
||||
}
|
||||
|
||||
|
||||
} // namespace Libroot
|
||||
} // namespace BPrivate
|
||||
|
@ -13,6 +13,12 @@ namespace BPrivate {
|
||||
namespace Libroot {
|
||||
|
||||
|
||||
ICULocaleconvData::ICULocaleconvData(pthread_key_t tlsKey)
|
||||
: inherited(tlsKey)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ICULocaleconvData::_SetLocaleconvEntry(const DecimalFormatSymbols* formatSymbols,
|
||||
char* destination, FormatSymbol symbol, const char* defaultValue)
|
||||
|
@ -14,6 +14,12 @@ namespace BPrivate {
|
||||
namespace Libroot {
|
||||
|
||||
|
||||
ICUMessagesData::ICUMessagesData(pthread_key_t tlsKey)
|
||||
: inherited(tlsKey)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ICUMessagesData::Initialize(LocaleMessagesDataBridge* dataBridge)
|
||||
{
|
||||
|
@ -15,8 +15,9 @@ namespace BPrivate {
|
||||
namespace Libroot {
|
||||
|
||||
|
||||
ICUMonetaryData::ICUMonetaryData(struct lconv& localeConv)
|
||||
ICUMonetaryData::ICUMonetaryData(pthread_key_t tlsKey, struct lconv& localeConv)
|
||||
:
|
||||
inherited(tlsKey),
|
||||
fLocaleConv(localeConv),
|
||||
fPosixLocaleConv(NULL)
|
||||
{
|
||||
|
@ -15,8 +15,9 @@ namespace BPrivate {
|
||||
namespace Libroot {
|
||||
|
||||
|
||||
ICUNumericData::ICUNumericData(struct lconv& localeConv)
|
||||
ICUNumericData::ICUNumericData(pthread_key_t tlsKey, struct lconv& localeConv)
|
||||
:
|
||||
inherited(tlsKey),
|
||||
fLocaleConv(localeConv),
|
||||
fDataBridge(NULL)
|
||||
{
|
||||
|
@ -20,8 +20,9 @@ namespace BPrivate {
|
||||
namespace Libroot {
|
||||
|
||||
|
||||
ICUTimeData::ICUTimeData(struct lc_time_t& lcTimeInfo)
|
||||
ICUTimeData::ICUTimeData(pthread_key_t tlsKey, struct lc_time_t& lcTimeInfo)
|
||||
:
|
||||
inherited(tlsKey),
|
||||
fLCTimeInfo(lcTimeInfo),
|
||||
fDataBridge(NULL)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user