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
<ClCompile Include="locresdata.cpp" />\r
<ClCompile Include="locutil.cpp">\r
</ClCompile>\r
- <ClCompile Include="lrucache.cpp">\r
- <DisableLanguageExtensions>false</DisableLanguageExtensions>\r
- </ClCompile>\r
<ClCompile Include="resbund.cpp">\r
</ClCompile>\r
<ClCompile Include="resbund_cnv.cpp" />\r
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>\r
</CustomBuild>\r
<ClInclude Include="locutil.h" />\r
- <ClInclude Include="lrucache.h" />\r
<CustomBuild Include="unicode\resbund.h">\r
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode\r
</Command>\r
</CustomBuild>\r
<ClInclude Include="sharedobject.h" />\r
<ClCompile Include="sharedobject.cpp" />\r
- <ClInclude Include="sharedptr.h" />\r
<ClInclude Include="simplepatternformatter.h" />\r
<CustomBuild Include="unicode\ucat.h">\r
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode\r
<ClCompile Include="ucol_swp.cpp">\r
<Filter>collation</Filter>\r
</ClCompile>\r
- <ClCompile Include="lrucache.cpp">\r
- <Filter>collections</Filter>\r
- </ClCompile>\r
<ClCompile Include="propsvec.c">\r
<Filter>collections</Filter>\r
</ClCompile>\r
<ClInclude Include="hash.h">\r
<Filter>collections</Filter>\r
</ClInclude>\r
- <ClInclude Include="lrucache.h">\r
- <Filter>collections</Filter>\r
- </ClInclude>\r
<ClInclude Include="propsvec.h">\r
<Filter>collections</Filter>\r
</ClInclude>\r
<ClInclude Include="sharedobject.h">\r
<Filter>data & memory</Filter>\r
</ClInclude>\r
- <ClInclude Include="sharedptr.h">\r
- <Filter>data & memory</Filter>\r
- </ClInclude>\r
<ClInclude Include="ucln.h">\r
<Filter>data & memory</Filter>\r
</ClInclude>\r
+++ /dev/null
-/*
-******************************************************************************
-* 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
+++ /dev/null
-/*
-******************************************************************************
-* 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
+++ /dev/null
-/*
-*******************************************************************************
-* 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
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)
<ClCompile Include="itrbnfp.cpp" />\r
<ClCompile Include="itrbnfrt.cpp" />\r
<ClCompile Include="locnmtst.cpp" />\r
- <ClCompile Include="lrucachetest.cpp">\r
- <DisableLanguageExtensions>false</DisableLanguageExtensions>\r
- </ClCompile>\r
<ClCompile Include="measfmttest.cpp" />\r
<ClCompile Include="miscdtfm.cpp" />\r
<ClCompile Include="msfmrgts.cpp" />\r
<ClCompile Include="ucaconf.cpp">\r
<Filter>collation</Filter>\r
</ClCompile>\r
- <ClCompile Include="lrucachetest.cpp">\r
- <Filter>collections</Filter>\r
- </ClCompile>\r
<ClCompile Include="unifiedcachetest.cpp">\r
<Filter>collections</Filter>\r
</ClCompile>\r
static IntlTest *createLocalPointerTest();
extern IntlTest *createUCharsTrieTest();
static IntlTest *createEnumSetTest();
-extern IntlTest *createLRUCacheTest();
extern IntlTest *createSimplePatternFormatterTest();
extern IntlTest *createUnifiedCacheTest();
}
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();
callTest(*test, par);
}
break;
- case 22:
+ case 21:
name = "UnifiedCacheTest";
if (exec) {
logln("TestSuite UnifiedCacheTest---"); logln();
+++ /dev/null
-/*
-*******************************************************************************
-* 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();
-}