Start work on multibyte-support in locale backend.
* add ICUThreadLocaleStorageValue, which will be used to maintain per-thread ICU converters * add ICUConverterManager
This commit is contained in:
@@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, Oliver Tappe, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef _ICU_CONVERTER_MANAGER_H
|
||||||
|
#define _ICU_CONVERTER_MANAGER_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <unicode/ucnv.h>
|
||||||
|
|
||||||
|
#include <SupportDefs.h>
|
||||||
|
|
||||||
|
#include <locks.h>
|
||||||
|
#include <Referenceable.h>
|
||||||
|
#include <util/DoublyLinkedList.h>
|
||||||
|
//#include <util/OpenHashTable.h>
|
||||||
|
|
||||||
|
#include "ICUThreadLocalStorageValue.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace BPrivate {
|
||||||
|
namespace Libroot {
|
||||||
|
|
||||||
|
|
||||||
|
class ICUConverterInfo : public BReferenceable {
|
||||||
|
public:
|
||||||
|
ICUConverterInfo(UConverter* converter,
|
||||||
|
const char* charset, ICUConverterID id);
|
||||||
|
virtual ~ICUConverterInfo();
|
||||||
|
|
||||||
|
UConverter* Converter() const
|
||||||
|
{ return fConverter; }
|
||||||
|
|
||||||
|
const char* Charset() const
|
||||||
|
{ return fCharset; }
|
||||||
|
|
||||||
|
ICUConverterID ID() const
|
||||||
|
{ return fID; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
UConverter* fConverter;
|
||||||
|
char fCharset[UCNV_MAX_CONVERTER_NAME_LENGTH];
|
||||||
|
ICUConverterID fID;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef BReference<ICUConverterInfo> ICUConverterRef;
|
||||||
|
|
||||||
|
|
||||||
|
class ICUConverterManager {
|
||||||
|
public:
|
||||||
|
ICUConverterManager();
|
||||||
|
~ICUConverterManager();
|
||||||
|
|
||||||
|
status_t CreateConverter(const char* charset,
|
||||||
|
ICUConverterRef& converterRefOut,
|
||||||
|
ICUConverterID& idOut);
|
||||||
|
|
||||||
|
status_t GetConverter(ICUConverterID id,
|
||||||
|
ICUConverterRef& converterRefOut);
|
||||||
|
|
||||||
|
status_t DropConverter(ICUConverterID id);
|
||||||
|
|
||||||
|
static ICUConverterManager* Instance();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void _CreateInstance();
|
||||||
|
|
||||||
|
static ICUConverterManager* sInstance;
|
||||||
|
|
||||||
|
static const size_t skMaxConvertersPerProcess = 1024;
|
||||||
|
|
||||||
|
private:
|
||||||
|
class LinkedConverterInfo
|
||||||
|
:
|
||||||
|
public ICUConverterInfo,
|
||||||
|
public DoublyLinkedListLinkImpl<LinkedConverterInfo>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LinkedConverterInfo(UConverter* converter, const char* charset,
|
||||||
|
ICUConverterID id)
|
||||||
|
:
|
||||||
|
ICUConverterInfo(converter, charset, id)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
typedef std::map<ICUConverterID, LinkedConverterInfo*> ConverterMap;
|
||||||
|
typedef DoublyLinkedList<LinkedConverterInfo> ConverterList;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ConverterMap fConverterMap;
|
||||||
|
ConverterList fLRUConverters;
|
||||||
|
mutex fMutex;
|
||||||
|
ICUConverterID fNextConverterID;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace Libroot
|
||||||
|
} // namespace BPrivate
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _ICU_CONVERTER_MANAGER_H
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Oliver Tappe, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef _ICU_THREAD_LOCAL_STORAGE_VALUE_H
|
||||||
|
#define _ICU_THREAD_LOCAL_STORAGE_VALUE_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include <SupportDefs.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace BPrivate {
|
||||||
|
namespace Libroot {
|
||||||
|
|
||||||
|
|
||||||
|
typedef unsigned int ICUConverterID;
|
||||||
|
|
||||||
|
|
||||||
|
struct ICUThreadLocalStorageValue {
|
||||||
|
ICUConverterID converterID;
|
||||||
|
|
||||||
|
ICUThreadLocalStorageValue();
|
||||||
|
~ICUThreadLocalStorageValue();
|
||||||
|
|
||||||
|
static status_t GetInstanceForKey(pthread_key_t tlsKey,
|
||||||
|
ICUThreadLocalStorageValue*& instanceOut);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace Libroot
|
||||||
|
} // namespace BPrivate
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _ICU_THREAD_LOCAL_STORAGE_VALUE_H
|
||||||
@@ -0,0 +1,174 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Oliver Tappe, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "ICUConverterManager.h"
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
|
||||||
|
namespace BPrivate {
|
||||||
|
namespace Libroot {
|
||||||
|
|
||||||
|
|
||||||
|
static pthread_once_t sManagerInitOnce = PTHREAD_ONCE_INIT;
|
||||||
|
|
||||||
|
|
||||||
|
ICUConverterInfo::ICUConverterInfo(UConverter* converter, const char* charset,
|
||||||
|
ICUConverterID id)
|
||||||
|
:
|
||||||
|
fConverter(converter),
|
||||||
|
fID(id)
|
||||||
|
{
|
||||||
|
strlcpy(fCharset, charset, sizeof(fCharset));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ICUConverterInfo::~ICUConverterInfo()
|
||||||
|
{
|
||||||
|
if (fConverter != NULL)
|
||||||
|
ucnv_close(fConverter);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ICUConverterManager* ICUConverterManager::sInstance = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
ICUConverterManager::ICUConverterManager()
|
||||||
|
:
|
||||||
|
fNextConverterID(1)
|
||||||
|
{
|
||||||
|
mutex_init(&fMutex, "ConverterManagerMutex");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ICUConverterManager::~ICUConverterManager()
|
||||||
|
{
|
||||||
|
ConverterMap::iterator iter;
|
||||||
|
for (iter = fConverterMap.begin(); iter != fConverterMap.end(); ++iter)
|
||||||
|
iter->second->ReleaseReference();
|
||||||
|
|
||||||
|
mutex_destroy(&fMutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
ICUConverterManager::CreateConverter(const char* charset,
|
||||||
|
ICUConverterRef& converterRefOut, ICUConverterID& idOut)
|
||||||
|
{
|
||||||
|
MutexLocker lock(fMutex);
|
||||||
|
if (!lock.IsLocked())
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
UErrorCode icuStatus = U_ZERO_ERROR;
|
||||||
|
UConverter* icuConverter = ucnv_open(charset, &icuStatus);
|
||||||
|
if (icuConverter == NULL)
|
||||||
|
return B_NAME_NOT_FOUND;
|
||||||
|
|
||||||
|
LinkedConverterInfo* converterInfo = new (std::nothrow) LinkedConverterInfo(
|
||||||
|
icuConverter, charset, fNextConverterID);
|
||||||
|
if (converterInfo == NULL) {
|
||||||
|
ucnv_close(icuConverter);
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
ICUConverterRef converterRef(converterInfo, true);
|
||||||
|
|
||||||
|
// setup the new converter to stop upon any errors
|
||||||
|
icuStatus = U_ZERO_ERROR;
|
||||||
|
ucnv_setToUCallBack(icuConverter, UCNV_TO_U_CALLBACK_STOP, NULL, NULL, NULL,
|
||||||
|
&icuStatus);
|
||||||
|
if (!U_SUCCESS(icuStatus))
|
||||||
|
return B_ERROR;
|
||||||
|
icuStatus = U_ZERO_ERROR;
|
||||||
|
ucnv_setFromUCallBack(icuConverter, UCNV_FROM_U_CALLBACK_STOP, NULL, NULL,
|
||||||
|
NULL, &icuStatus);
|
||||||
|
if (!U_SUCCESS(icuStatus))
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
// ok, we've got the converter, add it to our map
|
||||||
|
try {
|
||||||
|
if (fConverterMap.size() >= skMaxConvertersPerProcess) {
|
||||||
|
// make room by dropping the least recently used converter
|
||||||
|
LinkedConverterInfo* leastUsedConverter = fLRUConverters.Head();
|
||||||
|
fLRUConverters.Remove(leastUsedConverter);
|
||||||
|
fConverterMap.erase(leastUsedConverter->ID());
|
||||||
|
leastUsedConverter->ReleaseReference();
|
||||||
|
}
|
||||||
|
fConverterMap[fNextConverterID] = converterInfo;
|
||||||
|
fLRUConverters.Insert(converterInfo);
|
||||||
|
} catch (...) {
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
converterRefOut = converterRef;
|
||||||
|
idOut = fNextConverterID++;
|
||||||
|
|
||||||
|
converterRef.Detach();
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
ICUConverterManager::GetConverter(ICUConverterID id,
|
||||||
|
ICUConverterRef& converterRefOut)
|
||||||
|
{
|
||||||
|
MutexLocker lock(fMutex);
|
||||||
|
if (!lock.IsLocked())
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
ConverterMap::iterator iter = fConverterMap.find(id);
|
||||||
|
if (iter == fConverterMap.end())
|
||||||
|
return B_NAME_NOT_FOUND;
|
||||||
|
|
||||||
|
converterRefOut.SetTo(iter->second);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
ICUConverterManager::DropConverter(ICUConverterID id)
|
||||||
|
{
|
||||||
|
MutexLocker lock(fMutex);
|
||||||
|
if (!lock.IsLocked())
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
ConverterMap::iterator iter = fConverterMap.find(id);
|
||||||
|
if (iter == fConverterMap.end())
|
||||||
|
return B_NAME_NOT_FOUND;
|
||||||
|
|
||||||
|
fLRUConverters.Remove(iter->second);
|
||||||
|
fConverterMap.erase(iter);
|
||||||
|
iter->second->ReleaseReference();
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ ICUConverterManager*
|
||||||
|
ICUConverterManager::Instance()
|
||||||
|
{
|
||||||
|
if (sInstance != NULL)
|
||||||
|
return sInstance;
|
||||||
|
|
||||||
|
pthread_once(&sManagerInitOnce,
|
||||||
|
&BPrivate::Libroot::ICUConverterManager::_CreateInstance);
|
||||||
|
|
||||||
|
return sInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ void
|
||||||
|
ICUConverterManager::_CreateInstance()
|
||||||
|
{
|
||||||
|
sInstance = new (std::nothrow) ICUConverterManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace Libroot
|
||||||
|
} // namespace BPrivate
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Oliver Tappe, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "ICUThreadLocalStorageValue.h"
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#include "ICUConverterManager.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace BPrivate {
|
||||||
|
namespace Libroot {
|
||||||
|
|
||||||
|
|
||||||
|
ICUThreadLocalStorageValue::ICUThreadLocalStorageValue()
|
||||||
|
: converterID(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ICUThreadLocalStorageValue::~ICUThreadLocalStorageValue()
|
||||||
|
{
|
||||||
|
if (converterID != 0)
|
||||||
|
ICUConverterManager::Instance()->DropConverter(converterID);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
ICUThreadLocalStorageValue::GetInstanceForKey(pthread_key_t tlsKey,
|
||||||
|
ICUThreadLocalStorageValue*& instanceOut)
|
||||||
|
{
|
||||||
|
ICUThreadLocalStorageValue* tlsValue = NULL;
|
||||||
|
void* value = pthread_getspecific(tlsKey);
|
||||||
|
if (value == NULL) {
|
||||||
|
tlsValue = new (std::nothrow) ICUThreadLocalStorageValue();
|
||||||
|
if (tlsValue == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
pthread_setspecific(tlsKey, tlsValue);
|
||||||
|
} else
|
||||||
|
tlsValue = static_cast<ICUThreadLocalStorageValue*>(value);
|
||||||
|
|
||||||
|
instanceOut = tlsValue;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace Libroot
|
||||||
|
} // namespace BPrivate
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
SubDir HAIKU_TOP src system libroot add-ons icu ;
|
SubDir HAIKU_TOP src system libroot add-ons icu ;
|
||||||
|
|
||||||
UsePrivateHeaders
|
UsePrivateHeaders
|
||||||
|
kernel
|
||||||
libroot
|
libroot
|
||||||
[ FDirName libroot locale ]
|
[ FDirName libroot locale ]
|
||||||
[ FDirName libroot time ]
|
[ FDirName libroot time ]
|
||||||
@@ -10,12 +11,14 @@ UsePrivateHeaders
|
|||||||
local sources =
|
local sources =
|
||||||
ICUCategoryData.cpp
|
ICUCategoryData.cpp
|
||||||
ICUCollateData.cpp
|
ICUCollateData.cpp
|
||||||
|
ICUConverterManager.cpp
|
||||||
ICUCtypeData.cpp
|
ICUCtypeData.cpp
|
||||||
ICULocaleBackend.cpp
|
ICULocaleBackend.cpp
|
||||||
ICULocaleconvData.cpp
|
ICULocaleconvData.cpp
|
||||||
ICUMessagesData.cpp
|
ICUMessagesData.cpp
|
||||||
ICUMonetaryData.cpp
|
ICUMonetaryData.cpp
|
||||||
ICUNumericData.cpp
|
ICUNumericData.cpp
|
||||||
|
ICUThreadLocalStorageValue.cpp
|
||||||
ICUTimeConversion.cpp
|
ICUTimeConversion.cpp
|
||||||
ICUTimeData.cpp
|
ICUTimeData.cpp
|
||||||
;
|
;
|
||||||
@@ -28,6 +31,6 @@ Includes [ FGristFiles $(sources) ] : $(HAIKU_ICU_HEADERS_DEPENDENCY) ;
|
|||||||
SharedLibrary libroot-addon-icu.so
|
SharedLibrary libroot-addon-icu.so
|
||||||
: $(sources)
|
: $(sources)
|
||||||
:
|
:
|
||||||
$(TARGET_LIBSTDC++) $(HAIKU_ICU_LIBS)
|
libreferenceable.a $(TARGET_LIBSTDC++) $(HAIKU_ICU_LIBS)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user