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:
parent
02606f712c
commit
bcadc4ca66
106
headers/private/libroot/locale/ICUConverterManager.h
Normal file
106
headers/private/libroot/locale/ICUConverterManager.h
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 2010, Oliver Tappe, zooey@hirschkaefer.de.
|
||||
* 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
|
36
headers/private/libroot/locale/ICUThreadLocalStorageValue.h
Normal file
36
headers/private/libroot/locale/ICUThreadLocalStorageValue.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2011, Oliver Tappe, zooey@hirschkaefer.de.
|
||||
* 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
|
174
src/system/libroot/add-ons/icu/ICUConverterManager.cpp
Normal file
174
src/system/libroot/add-ons/icu/ICUConverterManager.cpp
Normal file
@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright 2011, Oliver Tappe, zooey@hirschkaefer.de.
|
||||
* 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, zooey@hirschkaefer.de.
|
||||
* 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 ;
|
||||
|
||||
UsePrivateHeaders
|
||||
kernel
|
||||
libroot
|
||||
[ FDirName libroot locale ]
|
||||
[ FDirName libroot time ]
|
||||
@ -10,12 +11,14 @@ UsePrivateHeaders
|
||||
local sources =
|
||||
ICUCategoryData.cpp
|
||||
ICUCollateData.cpp
|
||||
ICUConverterManager.cpp
|
||||
ICUCtypeData.cpp
|
||||
ICULocaleBackend.cpp
|
||||
ICULocaleconvData.cpp
|
||||
ICUMessagesData.cpp
|
||||
ICUMonetaryData.cpp
|
||||
ICUNumericData.cpp
|
||||
ICUThreadLocalStorageValue.cpp
|
||||
ICUTimeConversion.cpp
|
||||
ICUTimeData.cpp
|
||||
;
|
||||
@ -28,6 +31,6 @@ Includes [ FGristFiles $(sources) ] : $(HAIKU_ICU_HEADERS_DEPENDENCY) ;
|
||||
SharedLibrary libroot-addon-icu.so
|
||||
: $(sources)
|
||||
:
|
||||
$(TARGET_LIBSTDC++) $(HAIKU_ICU_LIBS)
|
||||
libreferenceable.a $(TARGET_LIBSTDC++) $(HAIKU_ICU_LIBS)
|
||||
;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user