mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-14 17:24:01 +00:00
ICU-8464 Add Suggested changes from Markus.
X-SVN-Rev: 34875
This commit is contained in:
parent
8067293d35
commit
132ff6d742
12 changed files with 476 additions and 326 deletions
2
.gitattributes
vendored
2
.gitattributes
vendored
|
@ -55,6 +55,8 @@ icu4c/source/common/common.vcxproj -text
|
|||
icu4c/source/common/common.vcxproj.filters -text
|
||||
icu4c/source/common/lrucache.cpp -text
|
||||
icu4c/source/common/lrucache.h -text
|
||||
icu4c/source/common/sharedobject.cpp -text
|
||||
icu4c/source/common/sharedobject.h -text
|
||||
icu4c/source/common/sharedptr.h -text
|
||||
icu4c/source/data/curr/pool.res -text
|
||||
icu4c/source/data/in/coll/invuca.icu -text
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#******************************************************************************
|
||||
#
|
||||
# Copyright (C) 1999-2013, International Business Machines
|
||||
# Copyright (C) 1999-2014, International Business Machines
|
||||
# Corporation and others. All Rights Reserved.
|
||||
#
|
||||
#******************************************************************************
|
||||
|
@ -104,7 +104,8 @@ rbbi.o rbbidata.o rbbinode.o rbbirb.o rbbiscan.o rbbisetb.o rbbistbl.o rbbitblb.
|
|||
serv.o servnotf.o servls.o servlk.o servlkf.o servrbf.o servslkf.o \
|
||||
uidna.o usprep.o uts46.o punycode.o \
|
||||
util.o util_props.o parsepos.o locbased.o cwchar.o wintz.o dtintrv.o ucnvsel.o propsvec.o \
|
||||
ulist.o uloc_tag.o icudataver.o icuplug.o listformatter.o lrucache.o
|
||||
ulist.o uloc_tag.o icudataver.o icuplug.o listformatter.o lrucache.o \
|
||||
sharedobject.o
|
||||
|
||||
## Header files to install
|
||||
HEADERS = $(srcdir)/unicode/*.h
|
||||
|
|
|
@ -1084,6 +1084,8 @@
|
|||
</Command>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
|
||||
</CustomBuild>
|
||||
<ClInclude Include="sharedobject.h" />
|
||||
<ClCompile Include="sharedobject.cpp" />
|
||||
<ClInclude Include="sharedptr.h" />
|
||||
<CustomBuild Include="unicode\ucat.h">
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
|
||||
|
|
|
@ -244,6 +244,9 @@
|
|||
<ClCompile Include="cmemory.c">
|
||||
<Filter>data & memory</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="sharedobject.cpp">
|
||||
<Filter>data & memory</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ucln_cmn.c">
|
||||
<Filter>data & memory</Filter>
|
||||
</ClCompile>
|
||||
|
@ -702,6 +705,9 @@
|
|||
<ClInclude Include="cmemory.h">
|
||||
<Filter>data & memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="sharedobject.h">
|
||||
<Filter>data & memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="sharedptr.h">
|
||||
<Filter>data & memory</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
@ -1,50 +1,33 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2013, International Business Machines Corporation and
|
||||
******************************************************************************
|
||||
* Copyright (C) 2014, International Business Machines Corporation and
|
||||
* others. All Rights Reserved.
|
||||
*******************************************************************************
|
||||
******************************************************************************
|
||||
*
|
||||
* File LRUCACHE.CPP
|
||||
*******************************************************************************
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "lrucache.h"
|
||||
#include "uhash.h"
|
||||
#include "cstring.h"
|
||||
#include "uassert.h"
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
// Named CacheEntry2 to avoid conflict with CacheEntry in serv.cpp
|
||||
// Don't know how to make truly private class that the linker can't see.
|
||||
class CacheEntry2 : public UMemory {
|
||||
public:
|
||||
CacheEntry2 *moreRecent;
|
||||
CacheEntry2 *lessRecent;
|
||||
char *localeId;
|
||||
SharedPtr<UObject> cachedData;
|
||||
UErrorCode status; // This is the error if any from creating cachedData.
|
||||
// TODO (Travis Keep): Consider building synchronization into this cache
|
||||
// instead of leaving synchronization up to the clients.
|
||||
|
||||
CacheEntry2();
|
||||
~CacheEntry2();
|
||||
|
||||
void unlink();
|
||||
void uninit();
|
||||
UBool init(const char *localeId, UObject *dataToAdopt, UErrorCode err);
|
||||
private:
|
||||
CacheEntry2(const CacheEntry2& other);
|
||||
CacheEntry2 &operator=(const CacheEntry2& other);
|
||||
};
|
||||
|
||||
CacheEntry2::CacheEntry2()
|
||||
: moreRecent(NULL), lessRecent(NULL), localeId(NULL), cachedData(),
|
||||
LRUCache::CacheEntry::CacheEntry()
|
||||
: moreRecent(NULL), lessRecent(NULL), localeId(NULL), cachedData(NULL),
|
||||
status(U_ZERO_ERROR) {
|
||||
}
|
||||
|
||||
CacheEntry2::~CacheEntry2() {
|
||||
uninit();
|
||||
LRUCache::CacheEntry::~CacheEntry() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void CacheEntry2::unlink() {
|
||||
void LRUCache::CacheEntry::unlink() {
|
||||
if (moreRecent != NULL) {
|
||||
moreRecent->lessRecent = lessRecent;
|
||||
}
|
||||
|
@ -55,8 +38,8 @@ void CacheEntry2::unlink() {
|
|||
lessRecent = NULL;
|
||||
}
|
||||
|
||||
void CacheEntry2::uninit() {
|
||||
cachedData.clear();
|
||||
void LRUCache::CacheEntry::reset() {
|
||||
SharedObject::clearPtr(cachedData);
|
||||
status = U_ZERO_ERROR;
|
||||
if (localeId != NULL) {
|
||||
uprv_free(localeId);
|
||||
|
@ -64,23 +47,18 @@ void CacheEntry2::uninit() {
|
|||
localeId = NULL;
|
||||
}
|
||||
|
||||
UBool CacheEntry2::init(const char *locId, UObject *dataToAdopt, UErrorCode err) {
|
||||
uninit();
|
||||
localeId = (char *) uprv_malloc(strlen(locId) + 1);
|
||||
if (localeId == NULL) {
|
||||
delete dataToAdopt;
|
||||
return FALSE;
|
||||
}
|
||||
uprv_strcpy(localeId, locId);
|
||||
if (!cachedData.adoptInstead(dataToAdopt)) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return TRUE;
|
||||
}
|
||||
void LRUCache::CacheEntry::init(
|
||||
char *adoptedLocId, SharedObject *dataToAdopt, UErrorCode err) {
|
||||
U_ASSERT(localeId == NULL);
|
||||
localeId = adoptedLocId;
|
||||
SharedObject::copyPtr(dataToAdopt, cachedData);
|
||||
status = err;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void LRUCache::moveToMostRecent(CacheEntry2 *entry) {
|
||||
void LRUCache::moveToMostRecent(LRUCache::CacheEntry *entry) {
|
||||
if (entry->moreRecent == mostRecentlyUsedMarker) {
|
||||
return;
|
||||
}
|
||||
entry->unlink();
|
||||
entry->moreRecent = mostRecentlyUsedMarker;
|
||||
entry->lessRecent = mostRecentlyUsedMarker->lessRecent;
|
||||
|
@ -88,29 +66,10 @@ void LRUCache::moveToMostRecent(CacheEntry2 *entry) {
|
|||
mostRecentlyUsedMarker->lessRecent = entry;
|
||||
}
|
||||
|
||||
UObject *LRUCache::safeCreate(const char *localeId, UErrorCode &status) {
|
||||
UObject *result = create(localeId, status);
|
||||
|
||||
// Safe guard to ensure that some error is reported for missing data in
|
||||
// case subclass forgets to set status.
|
||||
if (result == NULL && U_SUCCESS(status)) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Safe guard to ensure that if subclass reports an error and returns
|
||||
// data that we don't leak memory.
|
||||
if (result != NULL && U_FAILURE(status)) {
|
||||
delete result;
|
||||
return NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
UBool LRUCache::init(const char *localeId, CacheEntry2 *entry) {
|
||||
void LRUCache::init(char *adoptedLocId, LRUCache::CacheEntry *entry) {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
UObject *result = safeCreate(localeId, status);
|
||||
return entry->init(localeId, result, status);
|
||||
SharedObject *result = create(adoptedLocId, status);
|
||||
entry->init(adoptedLocId, result, status);
|
||||
}
|
||||
|
||||
UBool LRUCache::contains(const char *localeId) const {
|
||||
|
@ -118,56 +77,53 @@ UBool LRUCache::contains(const char *localeId) const {
|
|||
}
|
||||
|
||||
|
||||
void LRUCache::_get(const char *localeId, SharedPtr<UObject>& ptr, UErrorCode &status) {
|
||||
CacheEntry2 *entry = (CacheEntry2 *) uhash_get(localeIdToEntries, localeId);
|
||||
if (entry != NULL) {
|
||||
moveToMostRecent(entry);
|
||||
} else {
|
||||
const SharedObject *LRUCache::_get(const char *localeId, UErrorCode &status) {
|
||||
// TODO (Travis Keep): Consider stripping irrelevant locale keywords.
|
||||
LRUCache::CacheEntry *entry = (LRUCache::CacheEntry *) uhash_get(
|
||||
localeIdToEntries, localeId);
|
||||
if (entry == NULL) {
|
||||
// Its a cache miss.
|
||||
|
||||
if (uhash_count(localeIdToEntries) < maxSize) {
|
||||
entry = new CacheEntry2;
|
||||
// Cache not full. There is room for a new entry.
|
||||
entry = new LRUCache::CacheEntry;
|
||||
if (entry == NULL) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
// Cache full. Must evict an entry and re-use it.
|
||||
entry = leastRecentlyUsedMarker->moreRecent;
|
||||
uhash_remove(localeIdToEntries, entry->localeId);
|
||||
entry->unlink();
|
||||
entry->uninit();
|
||||
entry->reset();
|
||||
}
|
||||
|
||||
// entry is an uninitialized, unlinked cache entry
|
||||
// or entry is null if memory could not be allocated.
|
||||
if (entry != NULL) {
|
||||
if (!init(localeId, entry)) {
|
||||
delete entry;
|
||||
entry = NULL;
|
||||
}
|
||||
char *dupLocaleId = uprv_strdup(localeId);
|
||||
if (dupLocaleId == NULL) {
|
||||
delete entry;
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
init(dupLocaleId, entry);
|
||||
|
||||
// Entry is initialized, but unlinked or entry is null on
|
||||
// memory allocation error.
|
||||
if (entry != NULL) {
|
||||
// Add to hashtable
|
||||
uhash_put(localeIdToEntries, entry->localeId, entry, &status);
|
||||
if (U_FAILURE(status)) {
|
||||
delete entry;
|
||||
entry = NULL;
|
||||
}
|
||||
}
|
||||
if (entry != NULL) {
|
||||
moveToMostRecent(entry);
|
||||
// Entry is initialized, add to hashtable
|
||||
uhash_put(localeIdToEntries, entry->localeId, entry, &status);
|
||||
if (U_FAILURE(status)) {
|
||||
delete entry;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (entry == NULL) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
// If we get here our data is cached.
|
||||
// Re-link entry so that it is the most recent.
|
||||
moveToMostRecent(entry);
|
||||
|
||||
if (U_FAILURE(entry->status)) {
|
||||
status = entry->status;
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
ptr = entry->cachedData;
|
||||
return entry->cachedData;
|
||||
}
|
||||
|
||||
LRUCache::LRUCache(int32_t size, UErrorCode &status) :
|
||||
|
@ -178,8 +134,8 @@ LRUCache::LRUCache(int32_t size, UErrorCode &status) :
|
|||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
mostRecentlyUsedMarker = new CacheEntry2;
|
||||
leastRecentlyUsedMarker = new CacheEntry2;
|
||||
mostRecentlyUsedMarker = new LRUCache::CacheEntry;
|
||||
leastRecentlyUsedMarker = new LRUCache::CacheEntry;
|
||||
if (mostRecentlyUsedMarker == NULL || leastRecentlyUsedMarker == NULL) {
|
||||
delete mostRecentlyUsedMarker;
|
||||
delete leastRecentlyUsedMarker;
|
||||
|
@ -204,8 +160,8 @@ LRUCache::LRUCache(int32_t size, UErrorCode &status) :
|
|||
|
||||
LRUCache::~LRUCache() {
|
||||
uhash_close(localeIdToEntries);
|
||||
for (CacheEntry2 *i = mostRecentlyUsedMarker; i != NULL;) {
|
||||
CacheEntry2 *next = i->lessRecent;
|
||||
for (LRUCache::CacheEntry *i = mostRecentlyUsedMarker; i != NULL;) {
|
||||
LRUCache::CacheEntry *next = i->lessRecent;
|
||||
delete i;
|
||||
i = next;
|
||||
}
|
||||
|
@ -214,7 +170,7 @@ LRUCache::~LRUCache() {
|
|||
SimpleLRUCache::~SimpleLRUCache() {
|
||||
}
|
||||
|
||||
UObject *SimpleLRUCache::create(const char *localeId, UErrorCode &status) {
|
||||
SharedObject *SimpleLRUCache::create(const char *localeId, UErrorCode &status) {
|
||||
return createFunc(localeId, status);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2013, International Business Machines Corporation and
|
||||
******************************************************************************
|
||||
* Copyright (C) 2014, International Business Machines Corporation and
|
||||
* others. All Rights Reserved.
|
||||
*******************************************************************************
|
||||
******************************************************************************
|
||||
*
|
||||
* File LRUCACHE.H
|
||||
*******************************************************************************
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __LRU_CACHE_H__
|
||||
#define __LRU_CACHE_H__
|
||||
|
||||
#include "unicode/uobject.h"
|
||||
#include "sharedptr.h"
|
||||
#include "sharedobject.h"
|
||||
|
||||
struct UHashtable;
|
||||
|
||||
|
@ -22,40 +22,60 @@ U_NAMESPACE_BEGIN
|
|||
* LRUCache keyed by locale ID.
|
||||
*/
|
||||
|
||||
class CacheEntry2;
|
||||
class SharedObject;
|
||||
|
||||
class U_COMMON_API LRUCache : public UObject {
|
||||
public:
|
||||
public:
|
||||
template<typename T>
|
||||
void get(const char *localeId, SharedPtr<T> &ptr, UErrorCode &status) {
|
||||
SharedPtr<UObject> p;
|
||||
_get(localeId, p, status);
|
||||
void get(const char *localeId, const T *&ptr, UErrorCode &status) {
|
||||
const T *value = (const T *) _get(localeId, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
ptr = p;
|
||||
SharedObject::copyPtr(value, ptr);
|
||||
}
|
||||
UBool contains(const char *localeId) const;
|
||||
virtual ~LRUCache();
|
||||
protected:
|
||||
virtual UObject *create(const char *localeId, UErrorCode &status)=0;
|
||||
protected:
|
||||
virtual SharedObject *create(const char *localeId, UErrorCode &status)=0;
|
||||
LRUCache(int32_t maxSize, UErrorCode &status);
|
||||
private:
|
||||
private:
|
||||
class CacheEntry : public UMemory {
|
||||
public:
|
||||
CacheEntry *moreRecent;
|
||||
CacheEntry *lessRecent;
|
||||
char *localeId;
|
||||
const SharedObject *cachedData;
|
||||
UErrorCode status; // This is the error if any from creating
|
||||
// cachedData.
|
||||
CacheEntry();
|
||||
~CacheEntry();
|
||||
|
||||
void unlink();
|
||||
void reset();
|
||||
void init(
|
||||
char *adoptedLocId, SharedObject *dataToAdopt, UErrorCode err);
|
||||
private:
|
||||
CacheEntry(const CacheEntry& other);
|
||||
CacheEntry &operator=(const CacheEntry& other);
|
||||
};
|
||||
LRUCache();
|
||||
LRUCache(const LRUCache &other);
|
||||
LRUCache &operator=(const LRUCache &other);
|
||||
UObject *safeCreate(const char *localeId, UErrorCode &status);
|
||||
CacheEntry2 *mostRecentlyUsedMarker;
|
||||
CacheEntry2 *leastRecentlyUsedMarker;
|
||||
|
||||
// TODO (Travis Keep): Consider replacing both of these end nodes with a
|
||||
// single sentinel.
|
||||
CacheEntry *mostRecentlyUsedMarker;
|
||||
CacheEntry *leastRecentlyUsedMarker;
|
||||
UHashtable *localeIdToEntries;
|
||||
int32_t maxSize;
|
||||
|
||||
void moveToMostRecent(CacheEntry2 *cacheEntry);
|
||||
UBool init(const char *localeId, CacheEntry2 *cacheEntry);
|
||||
void _get(const char *localeId, SharedPtr<UObject> &ptr, UErrorCode &status);
|
||||
void moveToMostRecent(CacheEntry *cacheEntry);
|
||||
void init(char *localeId, CacheEntry *cacheEntry);
|
||||
const SharedObject *_get(const char *localeId, UErrorCode &status);
|
||||
};
|
||||
|
||||
typedef UObject *(*CreateFunc)(const char *localeId, UErrorCode &status);
|
||||
typedef SharedObject *CreateFunc(const char *localeId, UErrorCode &status);
|
||||
|
||||
class U_COMMON_API SimpleLRUCache : public LRUCache {
|
||||
public:
|
||||
|
@ -67,9 +87,9 @@ public:
|
|||
}
|
||||
virtual ~SimpleLRUCache();
|
||||
protected:
|
||||
virtual UObject *create(const char *localeId, UErrorCode &status);
|
||||
virtual SharedObject *create(const char *localeId, UErrorCode &status);
|
||||
private:
|
||||
CreateFunc createFunc;
|
||||
CreateFunc *createFunc;
|
||||
};
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
|
37
icu4c/source/common/sharedobject.cpp
Normal file
37
icu4c/source/common/sharedobject.cpp
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
******************************************************************************
|
||||
* Copyright (C) 2014, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
******************************************************************************
|
||||
* sharedobject.cpp
|
||||
*/
|
||||
#include "sharedobject.h"
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
SharedObject::~SharedObject() {}
|
||||
|
||||
void
|
||||
SharedObject::addRef() const {
|
||||
umtx_atomic_inc(&refCount);
|
||||
}
|
||||
|
||||
void
|
||||
SharedObject::removeRef() const {
|
||||
if(umtx_atomic_dec(&refCount) == 0) {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t
|
||||
SharedObject::getRefCount() const {
|
||||
return umtx_loadAcquire(refCount);
|
||||
}
|
||||
|
||||
void
|
||||
SharedObject::deleteIfZeroRefCount() const {
|
||||
if(getRefCount() == 0) {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
U_NAMESPACE_END
|
111
icu4c/source/common/sharedobject.h
Normal file
111
icu4c/source/common/sharedobject.h
Normal file
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
******************************************************************************
|
||||
* Copyright (C) 2014, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
******************************************************************************
|
||||
* sharedobject.h
|
||||
*/
|
||||
|
||||
#ifndef __SHAREDOBJECT_H__
|
||||
#define __SHAREDOBJECT_H__
|
||||
|
||||
|
||||
#include "unicode/uobject.h"
|
||||
#include "umutex.h"
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
/**
|
||||
* Base class for shared, reference-counted, auto-deleted objects.
|
||||
* Subclasses can be immutable.
|
||||
* If they are mutable, then they must implement their copy constructor
|
||||
* so that copyOnWrite() works.
|
||||
*
|
||||
* Either stack-allocate, use LocalPointer, or use addRef()/removeRef().
|
||||
* Sharing requires reference-counting.
|
||||
*/
|
||||
class U_COMMON_API SharedObject : public UObject {
|
||||
public:
|
||||
/** Initializes refCount to 0. */
|
||||
SharedObject() : refCount(0) {}
|
||||
|
||||
/** Initializes refCount to 0. */
|
||||
SharedObject(const SharedObject &/*other*/) : refCount(0) {}
|
||||
virtual ~SharedObject();
|
||||
|
||||
/**
|
||||
* Increments the number of references to this object. Thread-safe.
|
||||
*/
|
||||
void addRef() const;
|
||||
|
||||
/**
|
||||
* Decrements the number of references to this object,
|
||||
* and auto-deletes "this" if the number becomes 0. Thread-safe.
|
||||
*/
|
||||
void removeRef() const;
|
||||
|
||||
/**
|
||||
* Returns the reference counter. Uses a memory barrier.
|
||||
*/
|
||||
int32_t getRefCount() const;
|
||||
|
||||
void deleteIfZeroRefCount() const;
|
||||
|
||||
/**
|
||||
* Returns a writable version of ptr.
|
||||
* If there is exactly one owner, then ptr itself is returned as a
|
||||
* non-const pointer.
|
||||
* If there are multiple owners, then ptr is replaced with a
|
||||
* copy-constructed clone,
|
||||
* and that is returned.
|
||||
* Returns NULL if cloning failed.
|
||||
*
|
||||
* T must be a subclass of SharedObject.
|
||||
*/
|
||||
template<typename T>
|
||||
static T *copyOnWrite(const T *&ptr) {
|
||||
const T *p = ptr;
|
||||
if(p->getRefCount() <= 1) { return const_cast<T *>(p); }
|
||||
T *p2 = new T(*p);
|
||||
if(p2 == NULL) { return NULL; }
|
||||
p->removeRef();
|
||||
ptr = p2;
|
||||
p2->addRef();
|
||||
return p2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes dest an owner of the object pointed to by src while adjusting
|
||||
* reference counts and deleting the previous object dest pointed to
|
||||
* if necessary. Before this call is made, dest must either be NULL or
|
||||
* own its object.
|
||||
*
|
||||
* T must be a subclass of SharedObject.
|
||||
*/
|
||||
template<typename T>
|
||||
static void copyPtr(const T *src, const T *&dest) {
|
||||
if(src != dest) {
|
||||
if(dest != NULL) { dest->removeRef(); }
|
||||
dest = src;
|
||||
if(src != NULL) { src->addRef(); }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to copy(NULL, dest).
|
||||
*/
|
||||
template<typename T>
|
||||
static void clearPtr(const T *&ptr) {
|
||||
if (ptr != NULL) {
|
||||
ptr->removeRef();
|
||||
ptr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
mutable u_atomic_int32_t refCount;
|
||||
};
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2013, International Business Machines Corporation and
|
||||
* Copyright (C) 2014, International Business Machines Corporation and
|
||||
* others. All Rights Reserved.
|
||||
*******************************************************************************
|
||||
*
|
||||
|
@ -28,8 +28,8 @@ struct _AtomicInt : public UMemory {
|
|||
* SharedPtr makes the act of copying large objects cheap by deferring the
|
||||
* cost of the copy to the first write operation after the copy.
|
||||
*
|
||||
* A SharedPtr<T> instance can refer to no object or an object of type T where
|
||||
* T is a subclass of UObject. T must also have a clone() method that copies
|
||||
* A SharedPtr<T> instance can refer to no object or an object of type T.
|
||||
* T must have a clone() method that copies
|
||||
* the object and returns a pointer to the copy. Copy and assignment of
|
||||
* SharedPtr instances are cheap because they only involve copying or
|
||||
* assigning the SharedPtr instance, not the T object which could be large.
|
||||
|
@ -44,6 +44,9 @@ struct _AtomicInt : public UMemory {
|
|||
* management by reference counting their T objects. T objects that are
|
||||
* referenced by no SharedPtr<T> instances get deleted automatically.
|
||||
*/
|
||||
|
||||
// TODO (Travis Keep): Leave interface the same, but find a more efficient
|
||||
// implementation that is easier to understand.
|
||||
template<typename T>
|
||||
class SharedPtr {
|
||||
public:
|
||||
|
@ -61,13 +64,13 @@ public:
|
|||
delete ptr;
|
||||
ptr = NULL;
|
||||
} else {
|
||||
umtx_storeRelease(refPtr->value, 1);
|
||||
refPtr->value = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Non-templated copy costructor. Needed to keep compiler from
|
||||
* Non-templated copy constructor. Needed to keep compiler from
|
||||
* creating its own.
|
||||
*/
|
||||
SharedPtr(const SharedPtr<T> &other) :
|
||||
|
@ -82,7 +85,7 @@ public:
|
|||
*/
|
||||
template<typename U>
|
||||
SharedPtr(const SharedPtr<U> &other) :
|
||||
ptr((T *) other.ptr), refPtr(other.refPtr) {
|
||||
ptr(other.ptr), refPtr(other.refPtr) {
|
||||
if (refPtr != NULL) {
|
||||
umtx_atomic_inc(&refPtr->value);
|
||||
}
|
||||
|
@ -118,9 +121,7 @@ public:
|
|||
~SharedPtr() {
|
||||
if (refPtr != NULL) {
|
||||
if (umtx_atomic_dec(&refPtr->value) == 0) {
|
||||
// Cast to UObject to avoid compiler warnings about incomplete
|
||||
// type T.
|
||||
delete (UObject *) ptr;
|
||||
delete ptr;
|
||||
delete refPtr;
|
||||
}
|
||||
}
|
||||
|
@ -142,9 +143,9 @@ public:
|
|||
}
|
||||
|
||||
/**
|
||||
* clear makes this instance refer to no object.
|
||||
* release makes this instance refer to no object.
|
||||
*/
|
||||
void clear() {
|
||||
void release() {
|
||||
adoptInstead(NULL);
|
||||
}
|
||||
|
||||
|
@ -205,7 +206,7 @@ public:
|
|||
*/
|
||||
T *readWrite() {
|
||||
int32_t refCount = count();
|
||||
if (refCount == 0 || refCount == 1) {
|
||||
if (refCount <= 1) {
|
||||
return ptr;
|
||||
}
|
||||
T *result = (T *) ptr->clone();
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2013, International Business Machines Corporation and
|
||||
******************************************************************************
|
||||
* Copyright (C) 2014, International Business Machines Corporation and
|
||||
* others. All Rights Reserved.
|
||||
*******************************************************************************
|
||||
******************************************************************************
|
||||
*
|
||||
* File RELDATEFMT.CPP
|
||||
*******************************************************************************
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "unicode/reldatefmt.h"
|
||||
|
@ -24,9 +24,13 @@
|
|||
#include "plurrule_impl.h"
|
||||
#include "ucln_in.h"
|
||||
#include "mutex.h"
|
||||
#include "charstr.h"
|
||||
|
||||
#include "sharedptr.h"
|
||||
|
||||
// Copied from uscript_props.cpp
|
||||
#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
|
||||
|
||||
static icu::LRUCache *gCache = NULL;
|
||||
static UMutex gCacheMutex = U_MUTEX_INITIALIZER;
|
||||
static icu::UInitOnce gCacheInitOnce = U_INITONCE_INITIALIZER;
|
||||
|
@ -46,105 +50,77 @@ U_NAMESPACE_BEGIN
|
|||
|
||||
// other must always be first.
|
||||
static const char * const gPluralForms[] = {
|
||||
"other", "zero", "one", "two", "few", "many", NULL};
|
||||
"other", "zero", "one", "two", "few", "many"};
|
||||
|
||||
// Must be equal to number of plural forms just above.
|
||||
#define MAX_PLURAL_FORMS 6
|
||||
static const UChar gPlaceholder[] = { 0x7b, 0x30, 0x7d}; /* {0} */
|
||||
|
||||
|
||||
class QualitativeUnits : public UObject {
|
||||
class QualitativeUnits : public UMemory {
|
||||
public:
|
||||
QualitativeUnits() { }
|
||||
UnicodeString data[UDAT_ABSOLUTE_UNIT_COUNT][UDAT_DIRECTION_COUNT];
|
||||
virtual ~QualitativeUnits() {
|
||||
}
|
||||
private:
|
||||
QualitativeUnits(const QualitativeUnits &other);
|
||||
QualitativeUnits &operator=(const QualitativeUnits& other);
|
||||
};
|
||||
|
||||
struct UnitPattern {
|
||||
UnicodeString prefix;
|
||||
UnicodeString suffix;
|
||||
UBool prefixOnly;
|
||||
UBool valid;
|
||||
UnicodeString pattern;
|
||||
int32_t offset; // Offset of "{0}". -1 means no {0}.
|
||||
UBool valid; // True if initialize, false otherwise.
|
||||
|
||||
UnitPattern() : prefix(), suffix(), prefixOnly(FALSE), valid(FALSE) {
|
||||
UnitPattern() : pattern(), offset(0), valid(FALSE) {
|
||||
}
|
||||
|
||||
void set(const UnicodeString &patternStr) {
|
||||
UnicodeString placeholder("{0}");
|
||||
int32_t idx = patternStr.indexOf(placeholder);
|
||||
pattern = patternStr;
|
||||
offset = patternStr.indexOf(gPlaceholder, LENGTHOF(gPlaceholder), 0);
|
||||
valid = TRUE;
|
||||
if (idx == -1) {
|
||||
prefixOnly = TRUE;
|
||||
prefix = patternStr;
|
||||
} else {
|
||||
prefixOnly = FALSE;
|
||||
prefix = patternStr.tempSubStringBetween(0, idx);
|
||||
suffix = patternStr.tempSubStringBetween(idx + placeholder.length());
|
||||
}
|
||||
}
|
||||
|
||||
UnicodeString& append(double quantity, const NumberFormat &nf, UnicodeString &appendTo) const {
|
||||
UnicodeString& append(
|
||||
double quantity,
|
||||
const NumberFormat &nf,
|
||||
UnicodeString &appendTo) const {
|
||||
if (!valid) {
|
||||
return appendTo;
|
||||
}
|
||||
appendTo.append(prefix);
|
||||
if (!prefixOnly) {
|
||||
nf.format(quantity, appendTo);
|
||||
appendTo.append(suffix);
|
||||
if (offset == -1) {
|
||||
appendTo.append(pattern);
|
||||
return appendTo;
|
||||
}
|
||||
appendTo.append(pattern.tempSubStringBetween(0, offset));
|
||||
nf.format(quantity, appendTo);
|
||||
appendTo.append(pattern.tempSubStringBetween(
|
||||
offset + LENGTHOF(gPlaceholder)));
|
||||
return appendTo;
|
||||
}
|
||||
};
|
||||
|
||||
class QuantitativeUnits : public UObject {
|
||||
class QuantitativeUnits : public UMemory {
|
||||
public:
|
||||
QuantitativeUnits() { }
|
||||
UnitPattern data[UDAT_RELATIVE_UNIT_COUNT][2][MAX_PLURAL_FORMS];
|
||||
virtual ~QuantitativeUnits() {
|
||||
}
|
||||
UnitPattern data[UDAT_RELATIVE_UNIT_COUNT][2][LENGTHOF(gPluralForms)];
|
||||
private:
|
||||
QuantitativeUnits(const QuantitativeUnits &other);
|
||||
QuantitativeUnits &operator=(const QuantitativeUnits& other);
|
||||
};
|
||||
|
||||
class RelativeDateTimeData : public UObject {
|
||||
class RelativeDateTimeData : public SharedObject {
|
||||
public:
|
||||
RelativeDateTimeData() {
|
||||
}
|
||||
SharedPtr<QualitativeUnits> qualitativeUnits;
|
||||
SharedPtr<QuantitativeUnits> quantitativeUnits;
|
||||
SharedPtr<MessageFormat> combinedDateAndTime;
|
||||
SharedPtr<PluralRules> pluralRules;
|
||||
SharedPtr<NumberFormat> numberFormat;
|
||||
RelativeDateTimeData *clone() const {
|
||||
return new RelativeDateTimeData(*this);
|
||||
}
|
||||
virtual ~RelativeDateTimeData() {
|
||||
}
|
||||
virtual ~RelativeDateTimeData();
|
||||
private:
|
||||
RelativeDateTimeData(const RelativeDateTimeData &other);
|
||||
RelativeDateTimeData &operator=(const RelativeDateTimeData& other);
|
||||
};
|
||||
|
||||
RelativeDateTimeData::RelativeDateTimeData(
|
||||
const RelativeDateTimeData &other) :
|
||||
qualitativeUnits(other.qualitativeUnits),
|
||||
quantitativeUnits(other.quantitativeUnits),
|
||||
combinedDateAndTime(other.combinedDateAndTime),
|
||||
pluralRules(other.pluralRules),
|
||||
numberFormat(other.numberFormat) {
|
||||
RelativeDateTimeData::~RelativeDateTimeData() {
|
||||
}
|
||||
|
||||
static char *UnicodeString2Char(
|
||||
const UnicodeString &source, char *buffer, int32_t bufCapacity) {
|
||||
source.extract(0, source.length(), buffer, bufCapacity, US_INV);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static void getStringWithFallback(
|
||||
static UBool getStringWithFallback(
|
||||
const UResourceBundle *resource,
|
||||
const char *key,
|
||||
UnicodeString &result,
|
||||
|
@ -153,18 +129,19 @@ static void getStringWithFallback(
|
|||
const UChar *resStr = ures_getStringByKeyWithFallback(
|
||||
resource, key, &len, &status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
return FALSE;
|
||||
}
|
||||
result.setTo(TRUE, resStr, len);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void getOptionalStringWithFallback(
|
||||
static UBool getOptionalStringWithFallback(
|
||||
const UResourceBundle *resource,
|
||||
const char *key,
|
||||
UnicodeString &result,
|
||||
UErrorCode &status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
return FALSE;
|
||||
}
|
||||
int32_t len = 0;
|
||||
const UChar *resStr = ures_getStringByKey(
|
||||
|
@ -172,42 +149,44 @@ static void getOptionalStringWithFallback(
|
|||
if (status == U_MISSING_RESOURCE_ERROR) {
|
||||
result.remove();
|
||||
status = U_ZERO_ERROR;
|
||||
return;
|
||||
return TRUE;
|
||||
}
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
return FALSE;
|
||||
}
|
||||
result.setTo(TRUE, resStr, len);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void getString(
|
||||
static UBool getString(
|
||||
const UResourceBundle *resource,
|
||||
UnicodeString &result,
|
||||
UErrorCode &status) {
|
||||
int32_t len = 0;
|
||||
const UChar *resStr = ures_getString(resource, &len, &status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
return FALSE;
|
||||
}
|
||||
result.setTo(TRUE, resStr, len);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void getUnitPattern(
|
||||
static UBool getUnitPattern(
|
||||
const UResourceBundle *resource,
|
||||
UnitPattern &result,
|
||||
UErrorCode &status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
return FALSE;
|
||||
}
|
||||
UnicodeString rawPattern;
|
||||
getString(resource, rawPattern, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
if (!getString(resource, rawPattern, status)) {
|
||||
return FALSE;
|
||||
}
|
||||
result.set(rawPattern);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void getStringByIndex(
|
||||
static UBool getStringByIndex(
|
||||
const UResourceBundle *resource,
|
||||
int32_t idx,
|
||||
UnicodeString &result,
|
||||
|
@ -216,9 +195,10 @@ static void getStringByIndex(
|
|||
const UChar *resStr = ures_getStringByIndex(
|
||||
resource, idx, &len, &status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
return FALSE;
|
||||
}
|
||||
result.setTo(TRUE, resStr, len);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void addQualitativeUnit(
|
||||
|
@ -256,7 +236,8 @@ static void addQualitativeUnit(
|
|||
}
|
||||
|
||||
static int32_t getPluralIndex(const char *pluralForm) {
|
||||
for (int32_t i = 0; gPluralForms[i] != NULL; ++i) {
|
||||
int32_t len = LENGTHOF(gPluralForms);
|
||||
for (int32_t i = 0; i < len; ++i) {
|
||||
if (uprv_strcmp(pluralForm, gPluralForms[i]) == 0) {
|
||||
return i;
|
||||
}
|
||||
|
@ -283,11 +264,10 @@ static void addTimeUnit(
|
|||
int32_t pluralIndex = getPluralIndex(
|
||||
ures_getKey(pluralBundle.getAlias()));
|
||||
if (pluralIndex != -1) {
|
||||
getUnitPattern(
|
||||
if (!getUnitPattern(
|
||||
pluralBundle.getAlias(),
|
||||
quantitativeUnits.data[relativeUnit][pastOrFuture][pluralIndex],
|
||||
status);
|
||||
if (U_FAILURE(status)) {
|
||||
status)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -300,7 +280,8 @@ static void addTimeUnit(
|
|||
QuantitativeUnits &quantitativeUnits,
|
||||
UErrorCode &status) {
|
||||
LocalUResourceBundlePointer topLevel(
|
||||
ures_getByKeyWithFallback(resource, "relativeTime", NULL, &status));
|
||||
ures_getByKeyWithFallback(
|
||||
resource, "relativeTime", NULL, &status));
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
|
@ -357,8 +338,7 @@ static void addTimeUnit(
|
|||
}
|
||||
addTimeUnit(topLevel.getAlias(), relativeUnit, quantitativeUnits, status);
|
||||
UnicodeString unitName;
|
||||
getStringWithFallback(topLevel.getAlias(), "dn", unitName, status);
|
||||
if (U_FAILURE(status)) {
|
||||
if (!getStringWithFallback(topLevel.getAlias(), "dn", unitName, status)) {
|
||||
return;
|
||||
}
|
||||
// TODO(Travis Keep): This is a hack to get around CLDR bug 6818.
|
||||
|
@ -401,8 +381,7 @@ static void readDaysOfWeek(
|
|||
return;
|
||||
}
|
||||
for (int32_t i = 0; i < size; ++i) {
|
||||
getStringByIndex(topLevel.getAlias(), i, daysOfWeek[i], status);
|
||||
if (U_FAILURE(status)) {
|
||||
if (!getStringByIndex(topLevel.getAlias(), i, daysOfWeek[i], status)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -428,7 +407,7 @@ static void addWeekDay(
|
|||
status);
|
||||
}
|
||||
|
||||
static void load(
|
||||
static UBool load(
|
||||
const UResourceBundle *resource,
|
||||
QualitativeUnits &qualitativeUnits,
|
||||
QuantitativeUnits &quantitativeUnits,
|
||||
|
@ -543,46 +522,43 @@ static void load(
|
|||
UDAT_ABSOLUTE_SUNDAY,
|
||||
qualitativeUnits,
|
||||
status);
|
||||
return U_SUCCESS(status);
|
||||
}
|
||||
|
||||
static void getDateTimePattern(
|
||||
static UBool getDateTimePattern(
|
||||
const UResourceBundle *resource,
|
||||
UnicodeString &result,
|
||||
UErrorCode &status) {
|
||||
UnicodeString defaultCalendarName;
|
||||
getStringWithFallback(
|
||||
if (!getStringWithFallback(
|
||||
resource,
|
||||
"calendar/default",
|
||||
defaultCalendarName,
|
||||
status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
status)) {
|
||||
return FALSE;
|
||||
}
|
||||
char calendarNameBuffer[128];
|
||||
char pathBuffer[256];
|
||||
sprintf(
|
||||
pathBuffer,
|
||||
"calendar/%s/DateTimePatterns",
|
||||
UnicodeString2Char(
|
||||
defaultCalendarName,
|
||||
calendarNameBuffer,
|
||||
128));
|
||||
CharString pathBuffer;
|
||||
pathBuffer.append("calendar/", status)
|
||||
.appendInvariantChars(defaultCalendarName, status)
|
||||
.append("/DateTimePatterns", status);
|
||||
LocalUResourceBundlePointer topLevel(
|
||||
ures_getByKeyWithFallback(resource, pathBuffer, NULL, &status));
|
||||
ures_getByKeyWithFallback(
|
||||
resource, pathBuffer.data(), NULL, &status));
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
return FALSE;
|
||||
}
|
||||
int32_t size = ures_getSize(topLevel.getAlias());
|
||||
if (size < 9) {
|
||||
if (size <= 8) {
|
||||
// Oops, size is to small to access the index that we want, fallback
|
||||
// to a hard-coded value.
|
||||
result = UNICODE_STRING_SIMPLE("{1} {0}");
|
||||
return;
|
||||
return TRUE;
|
||||
}
|
||||
getStringByIndex(topLevel.getAlias(), 8, result, status);
|
||||
return getStringByIndex(topLevel.getAlias(), 8, result, status);
|
||||
}
|
||||
|
||||
static UObject *U_CALLCONV createData(const char *localeId, UErrorCode &status) {
|
||||
static SharedObject *U_CALLCONV createData(
|
||||
const char *localeId, UErrorCode &status) {
|
||||
LocalUResourceBundlePointer topLevel(ures_open(NULL, localeId, &status));
|
||||
if (U_FAILURE(status)) {
|
||||
return NULL;
|
||||
|
@ -590,12 +566,17 @@ static UObject *U_CALLCONV createData(const char *localeId, UErrorCode &status)
|
|||
LocalPointer<RelativeDateTimeData> result(new RelativeDateTimeData());
|
||||
LocalPointer<QualitativeUnits> qualitativeUnits(new QualitativeUnits());
|
||||
LocalPointer<QuantitativeUnits> quantitativeUnits(new QuantitativeUnits());
|
||||
if (qualitativeUnits.getAlias() == NULL || quantitativeUnits.getAlias() == NULL) {
|
||||
if (result.getAlias() == NULL
|
||||
|| qualitativeUnits.getAlias() == NULL
|
||||
|| quantitativeUnits.getAlias() == NULL) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
load(topLevel.getAlias(), *qualitativeUnits, *quantitativeUnits, status);
|
||||
if (U_FAILURE(status)) {
|
||||
if (!load(
|
||||
topLevel.getAlias(),
|
||||
*qualitativeUnits,
|
||||
*quantitativeUnits,
|
||||
status)) {
|
||||
return NULL;
|
||||
}
|
||||
if (!result->qualitativeUnits.adoptInstead(qualitativeUnits.orphan())) {
|
||||
|
@ -609,12 +590,16 @@ static UObject *U_CALLCONV createData(const char *localeId, UErrorCode &status)
|
|||
|
||||
|
||||
UnicodeString dateTimePattern;
|
||||
getDateTimePattern(topLevel.getAlias(), dateTimePattern, status);
|
||||
if (!getDateTimePattern(topLevel.getAlias(), dateTimePattern, status)) {
|
||||
return NULL;
|
||||
}
|
||||
LocalPointer<MessageFormat> mf(
|
||||
new MessageFormat(dateTimePattern, localeId, status));
|
||||
if (U_FAILURE(status)) {
|
||||
return NULL;
|
||||
}
|
||||
LocalPointer<MessageFormat> mf(new MessageFormat(dateTimePattern, localeId, status));
|
||||
if (U_FAILURE(status)) {
|
||||
if (mf.getAlias() == NULL) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
if (!result->combinedDateAndTime.adoptInstead(mf.orphan())) {
|
||||
|
@ -651,7 +636,10 @@ static void U_CALLCONV cacheInit(UErrorCode &status) {
|
|||
}
|
||||
}
|
||||
|
||||
static void getFromCache(const char *locale, SharedPtr<RelativeDateTimeData>& ptr, UErrorCode &status) {
|
||||
static void getFromCache(
|
||||
const char *locale,
|
||||
const RelativeDateTimeData *&ptr,
|
||||
UErrorCode &status) {
|
||||
umtx_initOnce(gCacheInitOnce, &cacheInit, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
|
@ -660,21 +648,24 @@ static void getFromCache(const char *locale, SharedPtr<RelativeDateTimeData>& pt
|
|||
gCache->get(locale, ptr, status);
|
||||
}
|
||||
|
||||
RelativeDateTimeFormatter::RelativeDateTimeFormatter(UErrorCode& status) {
|
||||
RelativeDateTimeFormatter::RelativeDateTimeFormatter(UErrorCode& status)
|
||||
: ptr(NULL) {
|
||||
getFromCache(Locale::getDefault().getName(), ptr, status);
|
||||
}
|
||||
|
||||
RelativeDateTimeFormatter::RelativeDateTimeFormatter(const Locale& locale, UErrorCode& status) {
|
||||
RelativeDateTimeFormatter::RelativeDateTimeFormatter(
|
||||
const Locale& locale, UErrorCode& status) : ptr(NULL) {
|
||||
getFromCache(locale.getName(), ptr, status);
|
||||
}
|
||||
|
||||
RelativeDateTimeFormatter::RelativeDateTimeFormatter(
|
||||
const Locale& locale, NumberFormat *nfToAdopt, UErrorCode& status) {
|
||||
const Locale& locale, NumberFormat *nfToAdopt, UErrorCode& status)
|
||||
: ptr(NULL) {
|
||||
getFromCache(locale.getName(), ptr, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
RelativeDateTimeData* wptr = ptr.readWrite();
|
||||
RelativeDateTimeData* wptr = SharedObject::copyOnWrite(ptr);
|
||||
if (wptr == NULL) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return;
|
||||
|
@ -685,23 +676,26 @@ RelativeDateTimeFormatter::RelativeDateTimeFormatter(
|
|||
}
|
||||
}
|
||||
|
||||
const NumberFormat& RelativeDateTimeFormatter::getNumberFormat() const {
|
||||
return *ptr->numberFormat;
|
||||
RelativeDateTimeFormatter::RelativeDateTimeFormatter(
|
||||
const RelativeDateTimeFormatter& other) : ptr(other.ptr) {
|
||||
ptr->addRef();
|
||||
}
|
||||
|
||||
RelativeDateTimeFormatter::RelativeDateTimeFormatter(const RelativeDateTimeFormatter& other) : ptr(other.ptr) {
|
||||
}
|
||||
|
||||
RelativeDateTimeFormatter& RelativeDateTimeFormatter::operator=(const RelativeDateTimeFormatter& other) {
|
||||
RelativeDateTimeFormatter& RelativeDateTimeFormatter::operator=(
|
||||
const RelativeDateTimeFormatter& other) {
|
||||
if (this != &other) {
|
||||
ptr = other.ptr;
|
||||
SharedObject::copyPtr(other.ptr, ptr);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
RelativeDateTimeFormatter::~RelativeDateTimeFormatter() {
|
||||
ptr->removeRef();
|
||||
}
|
||||
|
||||
const NumberFormat& RelativeDateTimeFormatter::getNumberFormat() const {
|
||||
return *ptr->numberFormat;
|
||||
}
|
||||
|
||||
UnicodeString& RelativeDateTimeFormatter::format(
|
||||
double quantity, UDateDirection direction, UDateRelativeUnit unit,
|
||||
|
@ -719,12 +713,13 @@ UnicodeString& RelativeDateTimeFormatter::format(
|
|||
if (decFmt != NULL) {
|
||||
dec = decFmt->getFixedDecimal(quantity, status);
|
||||
}
|
||||
CharString buffer;
|
||||
buffer.appendInvariantChars(ptr->pluralRules->select(dec), status);
|
||||
if (U_FAILURE(status)) {
|
||||
return appendTo;
|
||||
}
|
||||
char buffer[256];
|
||||
int32_t pluralIndex = getPluralIndex(
|
||||
UnicodeString2Char(ptr->pluralRules->select(dec), buffer, 256));
|
||||
|
||||
int32_t pluralIndex = getPluralIndex(buffer.data());
|
||||
if (pluralIndex == -1) {
|
||||
pluralIndex = 0;
|
||||
}
|
||||
|
@ -752,11 +747,9 @@ UnicodeString& RelativeDateTimeFormatter::format(
|
|||
UnicodeString& RelativeDateTimeFormatter::combineDateAndTime(
|
||||
const UnicodeString& relativeDateString, const UnicodeString& timeString,
|
||||
UnicodeString& appendTo, UErrorCode& status) const {
|
||||
Formattable formattable[2];
|
||||
formattable[0].setString(timeString);
|
||||
formattable[1].setString(relativeDateString);
|
||||
Formattable args[2] = {timeString, relativeDateString};
|
||||
FieldPosition fpos(0);
|
||||
return ptr->combinedDateAndTime->format(formattable, 2, appendTo, fpos, status);
|
||||
return ptr->combinedDateAndTime->format(args, 2, appendTo, fpos, status);
|
||||
}
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
/*
|
||||
********************************************************************************
|
||||
* Copyright (C) 2013, International Business Machines Corporation and
|
||||
*****************************************************************************
|
||||
* Copyright (C) 2014, International Business Machines Corporation and
|
||||
* others.
|
||||
* All Rights Reserved.
|
||||
********************************************************************************
|
||||
*****************************************************************************
|
||||
*
|
||||
* File RELDATEFMT.H
|
||||
********************************************************************************
|
||||
*****************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __RELDATEFMT_H
|
||||
|
@ -14,10 +14,14 @@
|
|||
|
||||
#include "unicode/utypes.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \brief C++ API: Formats relative dates such as "1 day ago" or "tomorrow"
|
||||
*/
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
|
||||
#include "unicode/locid.h"
|
||||
#include "sharedptr.h"
|
||||
|
||||
|
||||
/**
|
||||
|
@ -234,7 +238,7 @@ class NumberFormat;
|
|||
* caller's responsibility to handle cut-off logic such as deciding between
|
||||
* displaying "in 7 days" or "in 1 week." This API supports relative dates
|
||||
* involving one single unit. This API does not support relative dates
|
||||
* involving compound units.
|
||||
* involving compound units,
|
||||
* e.g "in 5 days and 4 hours" nor does it support parsing.
|
||||
* <p>
|
||||
* This class is mostly thread safe and immutable with the following caveats:
|
||||
|
@ -327,7 +331,8 @@ public:
|
|||
* Assignment operator.
|
||||
* @draft ICU 53
|
||||
*/
|
||||
RelativeDateTimeFormatter& operator=(const RelativeDateTimeFormatter& other);
|
||||
RelativeDateTimeFormatter& operator=(
|
||||
const RelativeDateTimeFormatter& other);
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
|
@ -350,7 +355,12 @@ public:
|
|||
* @return appendTo
|
||||
* @draft ICU 53
|
||||
*/
|
||||
UnicodeString& format(double quantity, UDateDirection direction, UDateRelativeUnit unit, UnicodeString& appendTo, UErrorCode& status) const;
|
||||
UnicodeString& format(
|
||||
double quantity,
|
||||
UDateDirection direction,
|
||||
UDateRelativeUnit unit,
|
||||
UnicodeString& appendTo,
|
||||
UErrorCode& status) const;
|
||||
|
||||
/**
|
||||
* Formats a relative date without a quantity.
|
||||
|
@ -364,7 +374,11 @@ public:
|
|||
* @return appendTo
|
||||
* @draft ICU 53
|
||||
*/
|
||||
UnicodeString& format(UDateDirection direction, UDateAbsoluteUnit unit, UnicodeString& appendTo, UErrorCode& status) const;
|
||||
UnicodeString& format(
|
||||
UDateDirection direction,
|
||||
UDateAbsoluteUnit unit,
|
||||
UnicodeString& appendTo,
|
||||
UErrorCode& status) const;
|
||||
|
||||
/**
|
||||
* Combines a relative date string and a time string in this object's
|
||||
|
@ -379,8 +393,10 @@ public:
|
|||
* @draft ICU 53
|
||||
*/
|
||||
UnicodeString& combineDateAndTime(
|
||||
const UnicodeString& relativeDateString, const UnicodeString& timeString,
|
||||
UnicodeString& appendTo, UErrorCode& status) const;
|
||||
const UnicodeString& relativeDateString,
|
||||
const UnicodeString& timeString,
|
||||
UnicodeString& appendTo,
|
||||
UErrorCode& status) const;
|
||||
|
||||
/**
|
||||
* Returns the NumberFormat this object is using.
|
||||
|
@ -391,7 +407,7 @@ public:
|
|||
|
||||
private:
|
||||
RelativeDateTimeFormatter();
|
||||
SharedPtr<icu::RelativeDateTimeData> ptr;
|
||||
const RelativeDateTimeData* ptr;
|
||||
};
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2013, International Business Machines Corporation and *
|
||||
* Copyright (C) 2014, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*
|
||||
|
@ -11,25 +11,27 @@
|
|||
#include "cstring.h"
|
||||
#include "intltest.h"
|
||||
#include "lrucache.h"
|
||||
#include "sharedptr.h"
|
||||
|
||||
class CopyOnWriteForTesting : public UObject {
|
||||
class CopyOnWriteForTesting : public SharedObject {
|
||||
public:
|
||||
CopyOnWriteForTesting() : localeNamePtr(), formatStrPtr(), length(0) {
|
||||
CopyOnWriteForTesting() : SharedObject(), localeNamePtr(), formatStrPtr(), length(0) {
|
||||
}
|
||||
UObject *clone() const {
|
||||
return new CopyOnWriteForTesting(*this);
|
||||
}
|
||||
virtual ~CopyOnWriteForTesting() {
|
||||
}
|
||||
SharedPtr<UnicodeString> localeNamePtr;
|
||||
SharedPtr<UnicodeString> formatStrPtr;
|
||||
int32_t length;
|
||||
private:
|
||||
|
||||
CopyOnWriteForTesting(const CopyOnWriteForTesting &other) :
|
||||
SharedObject(other),
|
||||
localeNamePtr(other.localeNamePtr),
|
||||
formatStrPtr(other.formatStrPtr),
|
||||
length(other.length) {
|
||||
}
|
||||
|
||||
virtual ~CopyOnWriteForTesting() {
|
||||
}
|
||||
|
||||
SharedPtr<UnicodeString> localeNamePtr;
|
||||
SharedPtr<UnicodeString> formatStrPtr;
|
||||
int32_t length;
|
||||
private:
|
||||
CopyOnWriteForTesting &operator=(const CopyOnWriteForTesting &rhs);
|
||||
};
|
||||
|
||||
|
@ -41,7 +43,7 @@ public:
|
|||
virtual ~LRUCacheForTesting() {
|
||||
}
|
||||
protected:
|
||||
virtual UObject *create(const char *localeId, UErrorCode &status);
|
||||
virtual SharedObject *create(const char *localeId, UErrorCode &status);
|
||||
private:
|
||||
SharedPtr<UnicodeString> defaultFormatStr;
|
||||
};
|
||||
|
@ -56,7 +58,7 @@ LRUCacheForTesting::LRUCacheForTesting(
|
|||
defaultFormatStr.adoptInstead(new UnicodeString(dfs));
|
||||
}
|
||||
|
||||
UObject *LRUCacheForTesting::create(const char *localeId, UErrorCode &status) {
|
||||
SharedObject *LRUCacheForTesting::create(const char *localeId, UErrorCode &status) {
|
||||
if (uprv_strcmp(localeId, "error") == 0) {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return NULL;
|
||||
|
@ -79,14 +81,13 @@ private:
|
|||
void TestLRUCache();
|
||||
void TestLRUCacheError();
|
||||
void verifySharedPointer(
|
||||
const SharedPtr<CopyOnWriteForTesting>& ptr,
|
||||
const CopyOnWriteForTesting* ptr,
|
||||
const UnicodeString& name,
|
||||
const UnicodeString& format);
|
||||
void verifyString(
|
||||
const UnicodeString &expected, const UnicodeString &actual);
|
||||
void verifyPtr(const void *expected, const void *actual);
|
||||
void verifyReferences(
|
||||
const SharedPtr<CopyOnWriteForTesting>& ptr,
|
||||
const CopyOnWriteForTesting* ptr,
|
||||
int32_t count, int32_t nameCount, int32_t formatCount);
|
||||
};
|
||||
|
||||
|
@ -102,27 +103,28 @@ void LRUCacheTest::runIndexedTest(int32_t index, UBool exec, const char* &name,
|
|||
void LRUCacheTest::TestSharedPointer() {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
LRUCacheForTesting cache(3, "little", status);
|
||||
SharedPtr<CopyOnWriteForTesting> ptr;
|
||||
const CopyOnWriteForTesting* ptr = NULL;
|
||||
cache.get("boo", ptr, status);
|
||||
verifySharedPointer(ptr, "boo", "little");
|
||||
SharedPtr<CopyOnWriteForTesting> ptrCopy = ptr;
|
||||
verifyPtr(ptr.readOnly(), ptrCopy.readOnly());
|
||||
const CopyOnWriteForTesting* ptrCopy = ptr;
|
||||
ptrCopy->addRef();
|
||||
{
|
||||
SharedPtr<CopyOnWriteForTesting> ptrCopy2(ptrCopy);
|
||||
const CopyOnWriteForTesting* ptrCopy2(ptrCopy);
|
||||
ptrCopy2->addRef();
|
||||
verifyReferences(ptr, 4, 1, 2);
|
||||
ptrCopy2->removeRef();
|
||||
}
|
||||
|
||||
// Test identity assignment
|
||||
ptr = ptr;
|
||||
|
||||
verifyReferences(ptr, 3, 1, 2);
|
||||
verifyReferences(ptrCopy, 3, 1, 2);
|
||||
*ptrCopy.readWrite()->localeNamePtr.readWrite() = UnicodeString("hi there");
|
||||
*ptrCopy.readWrite()->formatStrPtr.readWrite() = UnicodeString("see you");
|
||||
CopyOnWriteForTesting *wPtrCopy = SharedObject::copyOnWrite(ptrCopy);
|
||||
*wPtrCopy->localeNamePtr.readWrite() = UnicodeString("hi there");
|
||||
*wPtrCopy->formatStrPtr.readWrite() = UnicodeString("see you");
|
||||
verifyReferences(ptr, 2, 1, 2);
|
||||
verifyReferences(ptrCopy, 1, 1, 1);
|
||||
verifySharedPointer(ptr, "boo", "little");
|
||||
verifySharedPointer(ptrCopy, "hi there", "see you");
|
||||
ptrCopy->removeRef();
|
||||
ptr->removeRef();
|
||||
}
|
||||
|
||||
void LRUCacheTest::TestErrorCallingConstructor() {
|
||||
|
@ -133,11 +135,11 @@ void LRUCacheTest::TestErrorCallingConstructor() {
|
|||
void LRUCacheTest::TestLRUCache() {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
LRUCacheForTesting cache(3, "little", status);
|
||||
SharedPtr<CopyOnWriteForTesting> ptr1;
|
||||
SharedPtr<CopyOnWriteForTesting> ptr2;
|
||||
SharedPtr<CopyOnWriteForTesting> ptr3;
|
||||
SharedPtr<CopyOnWriteForTesting> ptr4;
|
||||
SharedPtr<CopyOnWriteForTesting> ptr5;
|
||||
const CopyOnWriteForTesting* ptr1 = NULL;
|
||||
const CopyOnWriteForTesting* ptr2 = NULL;
|
||||
const CopyOnWriteForTesting* ptr3 = NULL;
|
||||
const CopyOnWriteForTesting* ptr4 = NULL;
|
||||
const CopyOnWriteForTesting* ptr5 = NULL;
|
||||
cache.get("foo", ptr1, status);
|
||||
cache.get("bar", ptr2, status);
|
||||
cache.get("baz", ptr3, status);
|
||||
|
@ -166,7 +168,8 @@ void LRUCacheTest::TestLRUCache() {
|
|||
verifyReferences(ptr5, 3, 1, 5);
|
||||
|
||||
// This should delete foo data since it got evicted from cache.
|
||||
ptr1.clear();
|
||||
ptr1->removeRef();
|
||||
ptr1 = NULL;
|
||||
// Reference count for little drops to 4 because foo data was deleted.
|
||||
verifyReferences(ptr5, 3, 1, 4);
|
||||
|
||||
|
@ -186,7 +189,8 @@ void LRUCacheTest::TestLRUCache() {
|
|||
|
||||
// Since bar was evicted, clearing its pointer should delete its data.
|
||||
// Notice that the reference count to 'little' dropped from 5 to 4.
|
||||
ptr2.clear();
|
||||
ptr2->removeRef();
|
||||
ptr2 = NULL;
|
||||
verifyReferences(ptr5, 2, 1, 4);
|
||||
if (cache.contains("bar") || !cache.contains("full")) {
|
||||
errln("Unexpected 'bar' in cache.");
|
||||
|
@ -199,7 +203,8 @@ void LRUCacheTest::TestLRUCache() {
|
|||
verifyReferences(ptr5, 2, 1, 5);
|
||||
|
||||
// since "full" was evicted, clearing its pointer should delete its data.
|
||||
ptr4.clear();
|
||||
ptr4->removeRef();
|
||||
ptr4 = NULL;
|
||||
verifyReferences(ptr5, 2, 1, 4);
|
||||
if (cache.contains("full") || !cache.contains("baz")) {
|
||||
errln("Unexpected 'full' in cache.");
|
||||
|
@ -212,17 +217,23 @@ void LRUCacheTest::TestLRUCache() {
|
|||
verifyReferences(ptr5, 2, 1, 5);
|
||||
|
||||
// since "baz" was evicted, clearing its pointer should delete its data.
|
||||
ptr3.clear();
|
||||
ptr3->removeRef();
|
||||
ptr3 = NULL;
|
||||
verifyReferences(ptr5, 2, 1, 4);
|
||||
if (cache.contains("baz") || !cache.contains("new3")) {
|
||||
errln("Unexpected 'baz' in cache.");
|
||||
}
|
||||
SharedObject::clearPtr(ptr1);
|
||||
SharedObject::clearPtr(ptr2);
|
||||
SharedObject::clearPtr(ptr3);
|
||||
SharedObject::clearPtr(ptr4);
|
||||
SharedObject::clearPtr(ptr5);
|
||||
}
|
||||
|
||||
void LRUCacheTest::TestLRUCacheError() {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
LRUCacheForTesting cache(3, "little", status);
|
||||
SharedPtr<CopyOnWriteForTesting> ptr1;
|
||||
const CopyOnWriteForTesting *ptr1;
|
||||
cache.get("error", ptr1, status);
|
||||
if (status != U_ILLEGAL_ARGUMENT_ERROR) {
|
||||
errln("Expected an error.");
|
||||
|
@ -230,7 +241,7 @@ void LRUCacheTest::TestLRUCacheError() {
|
|||
}
|
||||
|
||||
void LRUCacheTest::verifySharedPointer(
|
||||
const SharedPtr<CopyOnWriteForTesting>& ptr,
|
||||
const CopyOnWriteForTesting* ptr,
|
||||
const UnicodeString& name,
|
||||
const UnicodeString& format) {
|
||||
const UnicodeString *strPtr = ptr->localeNamePtr.readOnly();
|
||||
|
@ -245,14 +256,8 @@ void LRUCacheTest::verifyString(const UnicodeString &expected, const UnicodeStri
|
|||
}
|
||||
}
|
||||
|
||||
void LRUCacheTest::verifyPtr(const void *expected, const void *actual) {
|
||||
if (expected != actual) {
|
||||
errln("Pointer mismatch.");
|
||||
}
|
||||
}
|
||||
|
||||
void LRUCacheTest::verifyReferences(const SharedPtr<CopyOnWriteForTesting>& ptr, int32_t count, int32_t nameCount, int32_t formatCount) {
|
||||
int32_t actual = ptr.count();
|
||||
void LRUCacheTest::verifyReferences(const CopyOnWriteForTesting* ptr, int32_t count, int32_t nameCount, int32_t formatCount) {
|
||||
int32_t actual = ptr->getRefCount();
|
||||
if (count != actual) {
|
||||
errln("Main reference count wrong: Expected %d, got %d", count, actual);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue