ICU-11075 Remove dead code including LRUCache and tests and sharedptr.h
X-SVN-Rev: 36226
This commit is contained in:
parent
6f9dd8c75a
commit
9c4a5db353
@ -104,7 +104,7 @@ 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 \
|
||||
sharedobject.o simplepatternformatter.o unifiedcache.o
|
||||
|
||||
## Header files to install
|
||||
|
@ -368,9 +368,6 @@
|
||||
<ClCompile Include="locresdata.cpp" />
|
||||
<ClCompile Include="locutil.cpp">
|
||||
</ClCompile>
|
||||
<ClCompile Include="lrucache.cpp">
|
||||
<DisableLanguageExtensions>false</DisableLanguageExtensions>
|
||||
</ClCompile>
|
||||
<ClCompile Include="resbund.cpp">
|
||||
</ClCompile>
|
||||
<ClCompile Include="resbund_cnv.cpp" />
|
||||
@ -1069,7 +1066,6 @@
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
|
||||
</CustomBuild>
|
||||
<ClInclude Include="locutil.h" />
|
||||
<ClInclude Include="lrucache.h" />
|
||||
<CustomBuild Include="unicode\resbund.h">
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
|
||||
</Command>
|
||||
@ -1086,7 +1082,6 @@
|
||||
</CustomBuild>
|
||||
<ClInclude Include="sharedobject.h" />
|
||||
<ClCompile Include="sharedobject.cpp" />
|
||||
<ClInclude Include="sharedptr.h" />
|
||||
<ClInclude Include="simplepatternformatter.h" />
|
||||
<CustomBuild Include="unicode\ucat.h">
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
|
||||
|
@ -103,9 +103,6 @@
|
||||
<ClCompile Include="ucol_swp.cpp">
|
||||
<Filter>collation</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="lrucache.cpp">
|
||||
<Filter>collections</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="propsvec.c">
|
||||
<Filter>collections</Filter>
|
||||
</ClCompile>
|
||||
@ -618,9 +615,6 @@
|
||||
<ClInclude Include="hash.h">
|
||||
<Filter>collections</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="lrucache.h">
|
||||
<Filter>collections</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="propsvec.h">
|
||||
<Filter>collections</Filter>
|
||||
</ClInclude>
|
||||
@ -714,9 +708,6 @@
|
||||
<ClInclude Include="sharedobject.h">
|
||||
<Filter>data & memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="sharedptr.h">
|
||||
<Filter>data & memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ucln.h">
|
||||
<Filter>data & memory</Filter>
|
||||
</ClInclude>
|
||||
|
@ -1,178 +0,0 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
* 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
|
||||
|
||||
// TODO (Travis Keep): Consider building synchronization into this cache
|
||||
// instead of leaving synchronization up to the clients.
|
||||
|
||||
LRUCache::CacheEntry::CacheEntry()
|
||||
: moreRecent(NULL), lessRecent(NULL), localeId(NULL), cachedData(NULL),
|
||||
status(U_ZERO_ERROR) {
|
||||
}
|
||||
|
||||
LRUCache::CacheEntry::~CacheEntry() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void LRUCache::CacheEntry::unlink() {
|
||||
if (moreRecent != NULL) {
|
||||
moreRecent->lessRecent = lessRecent;
|
||||
}
|
||||
if (lessRecent != NULL) {
|
||||
lessRecent->moreRecent = moreRecent;
|
||||
}
|
||||
moreRecent = NULL;
|
||||
lessRecent = NULL;
|
||||
}
|
||||
|
||||
void LRUCache::CacheEntry::reset() {
|
||||
SharedObject::clearPtr(cachedData);
|
||||
status = U_ZERO_ERROR;
|
||||
uprv_free(localeId);
|
||||
localeId = NULL;
|
||||
}
|
||||
|
||||
void LRUCache::CacheEntry::init(
|
||||
char *adoptedLocId, SharedObject *dataToAdopt, UErrorCode err) {
|
||||
U_ASSERT(localeId == NULL);
|
||||
localeId = adoptedLocId;
|
||||
SharedObject::copyPtr(dataToAdopt, cachedData);
|
||||
status = err;
|
||||
}
|
||||
|
||||
void LRUCache::moveToMostRecent(CacheEntry *entry) {
|
||||
if (entry->moreRecent == mostRecentlyUsedMarker) {
|
||||
return;
|
||||
}
|
||||
entry->unlink();
|
||||
entry->moreRecent = mostRecentlyUsedMarker;
|
||||
entry->lessRecent = mostRecentlyUsedMarker->lessRecent;
|
||||
mostRecentlyUsedMarker->lessRecent->moreRecent = entry;
|
||||
mostRecentlyUsedMarker->lessRecent = entry;
|
||||
}
|
||||
|
||||
void LRUCache::init(char *adoptedLocId, CacheEntry *entry) {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
SharedObject *result = create(adoptedLocId, status);
|
||||
entry->init(adoptedLocId, result, status);
|
||||
}
|
||||
|
||||
UBool LRUCache::contains(const char *localeId) const {
|
||||
return (uhash_get(localeIdToEntries, localeId) != NULL);
|
||||
}
|
||||
|
||||
|
||||
const SharedObject *LRUCache::_get(const char *localeId, UErrorCode &status) {
|
||||
// TODO (Travis Keep): Consider stripping irrelevant locale keywords.
|
||||
if (U_FAILURE(status)) {
|
||||
return NULL;
|
||||
}
|
||||
CacheEntry *entry = static_cast<CacheEntry *>(uhash_get(
|
||||
localeIdToEntries, localeId));
|
||||
if (entry == NULL) {
|
||||
// Its a cache miss.
|
||||
|
||||
if (uhash_count(localeIdToEntries) < maxSize) {
|
||||
// Cache not full. There is room for a new entry.
|
||||
entry = new 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->reset();
|
||||
}
|
||||
|
||||
// entry is an uninitialized, unlinked cache entry
|
||||
char *dupLocaleId = uprv_strdup(localeId);
|
||||
if (dupLocaleId == NULL) {
|
||||
delete entry;
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
init(dupLocaleId, entry);
|
||||
|
||||
// Entry is initialized, add to hashtable
|
||||
uhash_put(localeIdToEntries, entry->localeId, entry, &status);
|
||||
if (U_FAILURE(status)) {
|
||||
delete entry;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Re-link entry so that it is the most recent.
|
||||
moveToMostRecent(entry);
|
||||
|
||||
if (U_FAILURE(entry->status)) {
|
||||
status = entry->status;
|
||||
return NULL;
|
||||
}
|
||||
return entry->cachedData;
|
||||
}
|
||||
|
||||
LRUCache::LRUCache(int32_t size, UErrorCode &status) :
|
||||
mostRecentlyUsedMarker(NULL),
|
||||
leastRecentlyUsedMarker(NULL),
|
||||
localeIdToEntries(NULL),
|
||||
maxSize(size) {
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
mostRecentlyUsedMarker = new CacheEntry;
|
||||
leastRecentlyUsedMarker = new CacheEntry;
|
||||
if (mostRecentlyUsedMarker == NULL || leastRecentlyUsedMarker == NULL) {
|
||||
delete mostRecentlyUsedMarker;
|
||||
delete leastRecentlyUsedMarker;
|
||||
mostRecentlyUsedMarker = leastRecentlyUsedMarker = NULL;
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return;
|
||||
}
|
||||
mostRecentlyUsedMarker->moreRecent = NULL;
|
||||
mostRecentlyUsedMarker->lessRecent = leastRecentlyUsedMarker;
|
||||
leastRecentlyUsedMarker->moreRecent = mostRecentlyUsedMarker;
|
||||
leastRecentlyUsedMarker->lessRecent = NULL;
|
||||
localeIdToEntries = uhash_openSize(
|
||||
uhash_hashChars,
|
||||
uhash_compareChars,
|
||||
NULL,
|
||||
maxSize + maxSize / 5,
|
||||
&status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LRUCache::~LRUCache() {
|
||||
uhash_close(localeIdToEntries);
|
||||
for (CacheEntry *i = mostRecentlyUsedMarker; i != NULL;) {
|
||||
CacheEntry *next = i->lessRecent;
|
||||
delete i;
|
||||
i = next;
|
||||
}
|
||||
}
|
||||
|
||||
SimpleLRUCache::~SimpleLRUCache() {
|
||||
}
|
||||
|
||||
SharedObject *SimpleLRUCache::create(const char *localeId, UErrorCode &status) {
|
||||
return createFunc(localeId, status);
|
||||
}
|
||||
|
||||
U_NAMESPACE_END
|
@ -1,147 +0,0 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
* 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 "sharedobject.h"
|
||||
|
||||
struct UHashtable;
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
/**
|
||||
* A cache of SharedObjects keyed by locale ID.
|
||||
*
|
||||
* LRUCache has one main method, get(), which fetches a SharedObject by
|
||||
* locale ID. If no such SharedObject is cached, get() creates the new
|
||||
* SharedObject and caches it behind the scenes.
|
||||
*
|
||||
* Each LRUCache has a maximum size. Whenever adding a new item to the cache
|
||||
* would exceed this maximum size, LRUCache evicts the SharedObject that was
|
||||
* least recently fetched via the get() method.
|
||||
*
|
||||
* LRUCache is designed to be subclassed. Subclasses must override the create()
|
||||
* method to create a new SharedObject by localeId. If only locale ID is
|
||||
* needed to create the SharedObject, a client can use SimpleLRUCache.
|
||||
*/
|
||||
class U_COMMON_API LRUCache : public UObject {
|
||||
public:
|
||||
/**
|
||||
* Fetches a SharedObject by locale ID. On success, get() makes ptr point
|
||||
* to the fetched SharedObject while automatically updating reference
|
||||
* counts; on failure, get() leaves ptr unchanged and sets status.
|
||||
* When get() is called, ptr must either be NULL or be included in the
|
||||
* reference count of what it points to. After get() returns successfully,
|
||||
* caller must eventually call removeRef() on ptr to avoid memory leaks.
|
||||
*
|
||||
* T must be a subclass of SharedObject.
|
||||
*/
|
||||
template<typename T>
|
||||
void get(const char *localeId, const T *&ptr, UErrorCode &status) {
|
||||
const T *value = (const T *) _get(localeId, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
SharedObject::copyPtr(value, ptr);
|
||||
}
|
||||
/**
|
||||
* Returns TRUE if a SharedObject for given ID is cached. Used
|
||||
* primarily for testing purposes.
|
||||
*/
|
||||
UBool contains(const char *localeId) const;
|
||||
virtual ~LRUCache();
|
||||
protected:
|
||||
/**
|
||||
* Subclasses override to create a new SharedObject for given localeID.
|
||||
* get() calls this to resolve cache misses. create() must either return
|
||||
* a SharedObject with 0 reference count and no error in status or return
|
||||
* NULL and set an error in status.
|
||||
*/
|
||||
virtual SharedObject *create(const char *localeId, UErrorCode &status)=0;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param maxSize the maximum size of the LRUCache
|
||||
* @param status any error is set here.
|
||||
*/
|
||||
LRUCache(int32_t maxSize, UErrorCode &status);
|
||||
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);
|
||||
|
||||
// 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(CacheEntry *cacheEntry);
|
||||
void init(char *localeId, CacheEntry *cacheEntry);
|
||||
const SharedObject *_get(const char *localeId, UErrorCode &status);
|
||||
};
|
||||
|
||||
/**
|
||||
* A function type that creates a SharedObject from a locale ID. Functions of
|
||||
* this type must return a SharedObject with 0 reference count and no error in
|
||||
* status or return NULL and set an error in status.
|
||||
*/
|
||||
typedef SharedObject *CreateFunc(const char *localeId, UErrorCode &status);
|
||||
|
||||
/**
|
||||
* A concrete subclass of LRUCache that creates SharedObjects using a
|
||||
* function of type CreateFunc.
|
||||
*/
|
||||
class U_COMMON_API SimpleLRUCache : public LRUCache {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param maxSize the maximum cache size.
|
||||
* @param cf creates SharedObject on cache miss.
|
||||
* @param status error reported here.
|
||||
*/
|
||||
SimpleLRUCache(
|
||||
int32_t maxSize,
|
||||
CreateFunc cf,
|
||||
UErrorCode &status) :
|
||||
LRUCache(maxSize, status), createFunc(cf) {
|
||||
}
|
||||
virtual ~SimpleLRUCache();
|
||||
protected:
|
||||
virtual SharedObject *create(const char *localeId, UErrorCode &status);
|
||||
private:
|
||||
CreateFunc *createFunc;
|
||||
};
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif
|
@ -1,225 +0,0 @@
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2014, International Business Machines Corporation and
|
||||
* others. All Rights Reserved.
|
||||
*******************************************************************************
|
||||
*
|
||||
* File SHAREDPTR.H
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __SHARED_PTR_H__
|
||||
#define __SHARED_PTR_H__
|
||||
|
||||
#include "unicode/uobject.h"
|
||||
#include "umutex.h"
|
||||
#include "uassert.h"
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
// Wrap u_atomic_int32_t in a UMemory so that we allocate them in the same
|
||||
// way we allocate all other ICU objects.
|
||||
struct AtomicInt : public UMemory {
|
||||
u_atomic_int32_t value;
|
||||
};
|
||||
|
||||
/**
|
||||
* SharedPtr are shared pointers that support copy-on-write sematics.
|
||||
* 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.
|
||||
* 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.
|
||||
* Although many SharedPtr<T> instances may refer to the same T object,
|
||||
* clients can still assume that each SharedPtr<T> instance has its own
|
||||
* private instance of T because each SharedPtr<T> instance offers only a
|
||||
* const view of its T object through normal pointer operations. If a caller
|
||||
* must change a T object through its SharedPtr<T>, it can do so by calling
|
||||
* readWrite() on the SharedPtr instance. readWrite() ensures that the
|
||||
* SharedPtr<T> really does have its own private T object by cloning it if
|
||||
* it is shared by using its clone() method. SharedPtr<T> instances handle
|
||||
* 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:
|
||||
/**
|
||||
* Constructor. If there is a memory allocation error creating
|
||||
* reference counter then this object will contain NULL, and adopted
|
||||
* pointer will be freed. Note that when passing NULL or no argument to
|
||||
* constructor, no memory allocation error can happen as NULL pointers
|
||||
* are never reference counted.
|
||||
*/
|
||||
explicit SharedPtr(T *adopted=NULL) : ptr(adopted), refPtr(NULL) {
|
||||
if (ptr != NULL) {
|
||||
refPtr = new AtomicInt();
|
||||
if (refPtr == NULL) {
|
||||
delete ptr;
|
||||
ptr = NULL;
|
||||
} else {
|
||||
refPtr->value = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
*/
|
||||
SharedPtr(const SharedPtr<T> &other) :
|
||||
ptr(other.ptr), refPtr(other.refPtr) {
|
||||
if (refPtr != NULL) {
|
||||
umtx_atomic_inc(&refPtr->value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* assignment operator.
|
||||
*/
|
||||
SharedPtr<T> &operator=(const SharedPtr<T> &other) {
|
||||
if (ptr != other.ptr) {
|
||||
SharedPtr<T> newValue(other);
|
||||
swap(newValue);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~SharedPtr() {
|
||||
if (refPtr != NULL) {
|
||||
if (umtx_atomic_dec(&refPtr->value) == 0) {
|
||||
delete ptr;
|
||||
delete refPtr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* reset adopts a new pointer. On success, returns TRUE.
|
||||
* On memory allocation error creating reference counter for adopted
|
||||
* pointer, returns FALSE while leaving this instance unchanged.
|
||||
*/
|
||||
bool reset(T *adopted) {
|
||||
SharedPtr<T> newValue(adopted);
|
||||
if (adopted != NULL && newValue.ptr == NULL) {
|
||||
// We couldn't allocate ref counter.
|
||||
return FALSE;
|
||||
}
|
||||
swap(newValue);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* reset makes this instance refer to no object.
|
||||
*/
|
||||
void reset() {
|
||||
reset(NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* count returns how many SharedPtr instances, including this one,
|
||||
* refer to the T object. Used for testing. Clients need not use in
|
||||
* practice.
|
||||
*/
|
||||
int32_t count() const {
|
||||
if (refPtr == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return umtx_loadAcquire(refPtr->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Swaps this instance with other.
|
||||
*/
|
||||
void swap(SharedPtr<T> &other) {
|
||||
T *tempPtr = other.ptr;
|
||||
AtomicInt *tempRefPtr = other.refPtr;
|
||||
other.ptr = ptr;
|
||||
other.refPtr = refPtr;
|
||||
ptr = tempPtr;
|
||||
refPtr = tempRefPtr;
|
||||
}
|
||||
|
||||
const T *operator->() const {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
const T &operator*() const {
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
bool operator==(const T *other) const {
|
||||
return ptr == other;
|
||||
}
|
||||
|
||||
bool operator!=(const T *other) const {
|
||||
return ptr != other;
|
||||
}
|
||||
|
||||
/**
|
||||
* readOnly gives const access to this instance's T object. If this
|
||||
* instance refers to no object, returns NULL.
|
||||
*/
|
||||
const T *readOnly() const {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* readWrite returns a writable pointer to its T object copying it first
|
||||
* using its clone() method if it is shared.
|
||||
* On memory allocation error or if this instance refers to no object,
|
||||
* this method returns NULL leaving this instance unchanged.
|
||||
* <p>
|
||||
* If readWrite() returns a non NULL pointer, it guarantees that this
|
||||
* object holds the only reference to its T object enabling the caller to
|
||||
* perform mutations using the returned pointer without affecting other
|
||||
* SharedPtr objects. However, the non-constness of readWrite continues as
|
||||
* long as the returned pointer is in scope. Therefore it is an API
|
||||
* violation to call readWrite() on A; perform B = A; and then proceed to
|
||||
* mutate A via its writeable pointer as that would be the same as setting
|
||||
* B = A while A is changing. The returned pointer is guaranteed to be
|
||||
* valid only while this object is in scope because this object maintains
|
||||
* ownership of its T object. Therefore, callers must never attempt to
|
||||
* delete the returned writeable pointer. The best practice with readWrite
|
||||
* is this: callers should use the returned pointer from readWrite() only
|
||||
* within the same scope as that call to readWrite, and that scope should
|
||||
* be made as small as possible avoiding overlap with other operatios on
|
||||
* this object.
|
||||
*/
|
||||
T *readWrite() {
|
||||
int32_t refCount = count();
|
||||
if (refCount <= 1) {
|
||||
return ptr;
|
||||
}
|
||||
T *result = (T *) ptr->clone();
|
||||
if (result == NULL) {
|
||||
// Memory allocation error
|
||||
return NULL;
|
||||
}
|
||||
if (!reset(result)) {
|
||||
return NULL;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
private:
|
||||
T *ptr;
|
||||
AtomicInt *refPtr;
|
||||
// No heap allocation. Use only stack.
|
||||
static void * U_EXPORT2 operator new(size_t size);
|
||||
static void * U_EXPORT2 operator new[](size_t size);
|
||||
#if U_HAVE_PLACEMENT_NEW
|
||||
static void * U_EXPORT2 operator new(size_t, void *ptr);
|
||||
#endif
|
||||
};
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif
|
@ -57,7 +57,7 @@ uobjtest.o idnaref.o idnaconf.o nptrans.o punyref.o testidn.o testidna.o uts46te
|
||||
incaltst.o calcasts.o v32test.o uvectest.o textfile.o tokiter.o utxttest.o \
|
||||
windttst.o winnmtst.o winutil.o csdetest.o tzrulets.o tzoffloc.o tzfmttst.o ssearch.o dtifmtts.o \
|
||||
tufmtts.o itspoof.o simplethread.o bidiconf.o locnmtst.o dcfmtest.o alphaindextst.o listformattertest.o genderinfotest.o compactdecimalformattest.o regiontst.o \
|
||||
reldatefmttest.o lrucachetest.o simplepatternformattertest.o measfmttest.o scientificformathelpertest.o numfmtspectest.o unifiedcachetest.o
|
||||
reldatefmttest.o simplepatternformattertest.o measfmttest.o scientificformathelpertest.o numfmtspectest.o unifiedcachetest.o
|
||||
|
||||
DEPS = $(OBJECTS:.o=.d)
|
||||
|
||||
|
@ -309,9 +309,6 @@
|
||||
<ClCompile Include="itrbnfp.cpp" />
|
||||
<ClCompile Include="itrbnfrt.cpp" />
|
||||
<ClCompile Include="locnmtst.cpp" />
|
||||
<ClCompile Include="lrucachetest.cpp">
|
||||
<DisableLanguageExtensions>false</DisableLanguageExtensions>
|
||||
</ClCompile>
|
||||
<ClCompile Include="measfmttest.cpp" />
|
||||
<ClCompile Include="miscdtfm.cpp" />
|
||||
<ClCompile Include="msfmrgts.cpp" />
|
||||
|
@ -136,9 +136,6 @@
|
||||
<ClCompile Include="ucaconf.cpp">
|
||||
<Filter>collation</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="lrucachetest.cpp">
|
||||
<Filter>collections</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="unifiedcachetest.cpp">
|
||||
<Filter>collections</Filter>
|
||||
</ClCompile>
|
||||
|
@ -33,7 +33,6 @@ extern IntlTest *createBytesTrieTest();
|
||||
static IntlTest *createLocalPointerTest();
|
||||
extern IntlTest *createUCharsTrieTest();
|
||||
static IntlTest *createEnumSetTest();
|
||||
extern IntlTest *createLRUCacheTest();
|
||||
extern IntlTest *createSimplePatternFormatterTest();
|
||||
extern IntlTest *createUnifiedCacheTest();
|
||||
|
||||
@ -99,14 +98,6 @@ void IntlTestUtilities::runIndexedTest( int32_t index, UBool exec, const char* &
|
||||
}
|
||||
break;
|
||||
case 20:
|
||||
name = "LRUCacheTest";
|
||||
if (exec) {
|
||||
logln("TestSuite LRUCacheTest---"); logln();
|
||||
LocalPointer<IntlTest> test(createLRUCacheTest());
|
||||
callTest(*test, par);
|
||||
}
|
||||
break;
|
||||
case 21:
|
||||
name = "SimplePatternFormatterTest";
|
||||
if (exec) {
|
||||
logln("TestSuite SimplePatternFormatterTest---"); logln();
|
||||
@ -114,7 +105,7 @@ void IntlTestUtilities::runIndexedTest( int32_t index, UBool exec, const char* &
|
||||
callTest(*test, par);
|
||||
}
|
||||
break;
|
||||
case 22:
|
||||
case 21:
|
||||
name = "UnifiedCacheTest";
|
||||
if (exec) {
|
||||
logln("TestSuite UnifiedCacheTest---"); logln();
|
||||
|
@ -1,276 +0,0 @@
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2014, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*
|
||||
* File LRUCACHETEST.CPP
|
||||
*
|
||||
********************************************************************************
|
||||
*/
|
||||
#include "cstring.h"
|
||||
#include "intltest.h"
|
||||
#include "lrucache.h"
|
||||
#include "sharedptr.h"
|
||||
|
||||
class CopyOnWriteForTesting : public SharedObject {
|
||||
public:
|
||||
CopyOnWriteForTesting() : SharedObject(), localeNamePtr(), formatStrPtr(), length(0) {
|
||||
}
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
class LRUCacheForTesting : public LRUCache {
|
||||
public:
|
||||
LRUCacheForTesting(
|
||||
int32_t maxSize,
|
||||
const UnicodeString &dfs, UErrorCode &status);
|
||||
virtual ~LRUCacheForTesting() {
|
||||
}
|
||||
protected:
|
||||
virtual SharedObject *create(const char *localeId, UErrorCode &status);
|
||||
private:
|
||||
SharedPtr<UnicodeString> defaultFormatStr;
|
||||
};
|
||||
|
||||
LRUCacheForTesting::LRUCacheForTesting(
|
||||
int32_t maxSize,
|
||||
const UnicodeString &dfs, UErrorCode &status) :
|
||||
LRUCache(maxSize, status), defaultFormatStr() {
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
defaultFormatStr.reset(new UnicodeString(dfs));
|
||||
}
|
||||
|
||||
SharedObject *LRUCacheForTesting::create(const char *localeId, UErrorCode &status) {
|
||||
if (uprv_strcmp(localeId, "error") == 0) {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
CopyOnWriteForTesting *result = new CopyOnWriteForTesting;
|
||||
result->localeNamePtr.reset(new UnicodeString(localeId));
|
||||
result->formatStrPtr = defaultFormatStr;
|
||||
result->length = 5;
|
||||
return result;
|
||||
}
|
||||
|
||||
class LRUCacheTest : public IntlTest {
|
||||
public:
|
||||
LRUCacheTest() {
|
||||
}
|
||||
void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par=0);
|
||||
private:
|
||||
void TestSharedPointer();
|
||||
void TestErrorCallingConstructor();
|
||||
void TestLRUCache();
|
||||
void TestLRUCacheError();
|
||||
void verifySharedPointer(
|
||||
const CopyOnWriteForTesting* ptr,
|
||||
const UnicodeString& name,
|
||||
const UnicodeString& format);
|
||||
void verifyString(
|
||||
const UnicodeString &expected, const UnicodeString &actual);
|
||||
void verifyReferences(
|
||||
const CopyOnWriteForTesting* ptr,
|
||||
int32_t count, int32_t nameCount, int32_t formatCount);
|
||||
};
|
||||
|
||||
void LRUCacheTest::runIndexedTest(int32_t index, UBool exec, const char* &name, char* /*par*/) {
|
||||
TESTCASE_AUTO_BEGIN;
|
||||
TESTCASE_AUTO(TestSharedPointer);
|
||||
TESTCASE_AUTO(TestErrorCallingConstructor);
|
||||
TESTCASE_AUTO(TestLRUCache);
|
||||
TESTCASE_AUTO(TestLRUCacheError);
|
||||
TESTCASE_AUTO_END;
|
||||
}
|
||||
|
||||
void LRUCacheTest::TestSharedPointer() {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
LRUCacheForTesting cache(3, "little", status);
|
||||
const CopyOnWriteForTesting* ptr = NULL;
|
||||
cache.get("boo", ptr, status);
|
||||
verifySharedPointer(ptr, "boo", "little");
|
||||
const CopyOnWriteForTesting* ptrCopy = ptr;
|
||||
ptrCopy->addRef();
|
||||
{
|
||||
const CopyOnWriteForTesting* ptrCopy2(ptrCopy);
|
||||
ptrCopy2->addRef();
|
||||
verifyReferences(ptr, 4, 1, 2);
|
||||
ptrCopy2->removeRef();
|
||||
}
|
||||
|
||||
verifyReferences(ptr, 3, 1, 2);
|
||||
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() {
|
||||
UErrorCode status = U_MEMORY_ALLOCATION_ERROR;
|
||||
LRUCacheForTesting cache(3, "little", status);
|
||||
}
|
||||
|
||||
void LRUCacheTest::TestLRUCache() {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
LRUCacheForTesting cache(3, "little", status);
|
||||
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);
|
||||
verifySharedPointer(ptr1, "foo", "little");
|
||||
verifySharedPointer(ptr2, "bar", "little");
|
||||
verifySharedPointer(ptr3, "baz", "little");
|
||||
|
||||
// Cache holds a reference to returned data which explains the 2s
|
||||
// Note the '4'. each cached data has a reference to "little" and the
|
||||
// cache itself also has a reference to "little"
|
||||
verifyReferences(ptr1, 2, 1, 4);
|
||||
verifyReferences(ptr2, 2, 1, 4);
|
||||
verifyReferences(ptr3, 2, 1, 4);
|
||||
|
||||
// (Most recent) "baz", "bar", "foo" (Least Recent)
|
||||
// Cache is now full but thanks to shared pointers we can still evict.
|
||||
cache.get("full", ptr4, status);
|
||||
verifySharedPointer(ptr4, "full", "little");
|
||||
|
||||
verifyReferences(ptr4, 2, 1, 5);
|
||||
|
||||
// (Most Recent) "full" "baz", "bar" (Least Recent)
|
||||
cache.get("baz", ptr5, status);
|
||||
verifySharedPointer(ptr5, "baz", "little");
|
||||
// ptr5, ptr3, and cache have baz data
|
||||
verifyReferences(ptr5, 3, 1, 5);
|
||||
|
||||
// This should delete foo data since it got evicted from cache.
|
||||
ptr1->removeRef();
|
||||
ptr1 = NULL;
|
||||
// Reference count for little drops to 4 because foo data was deleted.
|
||||
verifyReferences(ptr5, 3, 1, 4);
|
||||
|
||||
// (Most Recent) "baz" "full" "bar" (Least Recent)
|
||||
cache.get("baz", ptr5, status);
|
||||
verifySharedPointer(ptr5, "baz", "little");
|
||||
verifyReferences(ptr5, 3, 1, 4);
|
||||
|
||||
// (Most Recent) "baz", "full", "bar" (Least Recent)
|
||||
// ptr3, ptr5 -> "baz" ptr4 -> "full" ptr2 -> "bar"
|
||||
if (!cache.contains("baz") || !cache.contains("full") || !cache.contains("bar") || cache.contains("foo")) {
|
||||
errln("Unexpected keys in cache.");
|
||||
}
|
||||
cache.get("new1", ptr5, status);
|
||||
verifySharedPointer(ptr5, "new1", "little");
|
||||
verifyReferences(ptr5, 2, 1, 5);
|
||||
|
||||
// Since bar was evicted, clearing its pointer should delete its data.
|
||||
// Notice that the reference count to 'little' dropped from 5 to 4.
|
||||
ptr2->removeRef();
|
||||
ptr2 = NULL;
|
||||
verifyReferences(ptr5, 2, 1, 4);
|
||||
if (cache.contains("bar") || !cache.contains("full")) {
|
||||
errln("Unexpected 'bar' in cache.");
|
||||
}
|
||||
|
||||
// (Most Recent) "new1", "baz", "full" (Least Recent)
|
||||
// ptr3 -> "baz" ptr4 -> "full" ptr5 -> "new1"
|
||||
cache.get("new2", ptr5, status);
|
||||
verifySharedPointer(ptr5, "new2", "little");
|
||||
verifyReferences(ptr5, 2, 1, 5);
|
||||
|
||||
// since "full" was evicted, clearing its pointer should delete its data.
|
||||
ptr4->removeRef();
|
||||
ptr4 = NULL;
|
||||
verifyReferences(ptr5, 2, 1, 4);
|
||||
if (cache.contains("full") || !cache.contains("baz")) {
|
||||
errln("Unexpected 'full' in cache.");
|
||||
}
|
||||
|
||||
// (Most Recent) "new2", "new1", "baz" (Least Recent)
|
||||
// ptr3 -> "baz" ptr5 -> "new2"
|
||||
cache.get("new3", ptr5, status);
|
||||
verifySharedPointer(ptr5, "new3", "little");
|
||||
verifyReferences(ptr5, 2, 1, 5);
|
||||
|
||||
// since "baz" was evicted, clearing its pointer should delete its data.
|
||||
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);
|
||||
const CopyOnWriteForTesting *ptr1;
|
||||
cache.get("error", ptr1, status);
|
||||
if (status != U_ILLEGAL_ARGUMENT_ERROR) {
|
||||
errln("Expected an error.");
|
||||
}
|
||||
}
|
||||
|
||||
void LRUCacheTest::verifySharedPointer(
|
||||
const CopyOnWriteForTesting* ptr,
|
||||
const UnicodeString& name,
|
||||
const UnicodeString& format) {
|
||||
const UnicodeString *strPtr = ptr->localeNamePtr.readOnly();
|
||||
verifyString(name, *strPtr);
|
||||
strPtr = ptr->formatStrPtr.readOnly();
|
||||
verifyString(format, *strPtr);
|
||||
}
|
||||
|
||||
void LRUCacheTest::verifyString(const UnicodeString &expected, const UnicodeString &actual) {
|
||||
if (expected != actual) {
|
||||
errln(UnicodeString("Expected '") + expected + "', got '"+ actual+"'");
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
actual = ptr->localeNamePtr.count();
|
||||
if (nameCount != actual) {
|
||||
errln("name reference count wrong: Expected %d, got %d", nameCount, actual);
|
||||
}
|
||||
actual = ptr->formatStrPtr.count();
|
||||
if (formatCount != actual) {
|
||||
errln("format reference count wrong: Expected %d, got %d", formatCount, actual);
|
||||
}
|
||||
}
|
||||
|
||||
extern IntlTest *createLRUCacheTest() {
|
||||
return new LRUCacheTest();
|
||||
}
|
Loading…
Reference in New Issue
Block a user