diff --git a/.gitattributes b/.gitattributes index 2a429b777a7..d65a91be7bf 100644 --- a/.gitattributes +++ b/.gitattributes @@ -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 diff --git a/icu4c/source/common/Makefile.in b/icu4c/source/common/Makefile.in index 20381e1d139..fb9207db208 100644 --- a/icu4c/source/common/Makefile.in +++ b/icu4c/source/common/Makefile.in @@ -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 diff --git a/icu4c/source/common/common.vcxproj b/icu4c/source/common/common.vcxproj index d1065f6e49c..57b052a547a 100644 --- a/icu4c/source/common/common.vcxproj +++ b/icu4c/source/common/common.vcxproj @@ -1084,6 +1084,8 @@ ..\..\include\unicode\%(Filename)%(Extension);%(Outputs) + + copy "%(FullPath)" ..\..\include\unicode diff --git a/icu4c/source/common/common.vcxproj.filters b/icu4c/source/common/common.vcxproj.filters index 37fe45f23c1..5b9690ebee1 100644 --- a/icu4c/source/common/common.vcxproj.filters +++ b/icu4c/source/common/common.vcxproj.filters @@ -244,6 +244,9 @@ data & memory + + data & memory + data & memory @@ -702,6 +705,9 @@ data & memory + + data & memory + data & memory diff --git a/icu4c/source/common/lrucache.cpp b/icu4c/source/common/lrucache.cpp index c94d35371b4..0b61f4ef953 100644 --- a/icu4c/source/common/lrucache.cpp +++ b/icu4c/source/common/lrucache.cpp @@ -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 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& 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); } diff --git a/icu4c/source/common/lrucache.h b/icu4c/source/common/lrucache.h index 3814e41d112..d67ee885d11 100644 --- a/icu4c/source/common/lrucache.h +++ b/icu4c/source/common/lrucache.h @@ -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 - void get(const char *localeId, SharedPtr &ptr, UErrorCode &status) { - SharedPtr 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 &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 diff --git a/icu4c/source/common/sharedobject.cpp b/icu4c/source/common/sharedobject.cpp new file mode 100644 index 00000000000..bad79801d7d --- /dev/null +++ b/icu4c/source/common/sharedobject.cpp @@ -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 diff --git a/icu4c/source/common/sharedobject.h b/icu4c/source/common/sharedobject.h new file mode 100644 index 00000000000..671bab137f6 --- /dev/null +++ b/icu4c/source/common/sharedobject.h @@ -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 + static T *copyOnWrite(const T *&ptr) { + const T *p = ptr; + if(p->getRefCount() <= 1) { return const_cast(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 + 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 + static void clearPtr(const T *&ptr) { + if (ptr != NULL) { + ptr->removeRef(); + ptr = NULL; + } + } + +private: + mutable u_atomic_int32_t refCount; +}; + +U_NAMESPACE_END + +#endif diff --git a/icu4c/source/common/sharedptr.h b/icu4c/source/common/sharedptr.h index 1fdeecca07b..d1c42e29611 100644 --- a/icu4c/source/common/sharedptr.h +++ b/icu4c/source/common/sharedptr.h @@ -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 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 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 instances get deleted automatically. */ + +// TODO (Travis Keep): Leave interface the same, but find a more efficient +// implementation that is easier to understand. template 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 &other) : @@ -82,7 +85,7 @@ public: */ template SharedPtr(const SharedPtr &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(); diff --git a/icu4c/source/i18n/reldatefmt.cpp b/icu4c/source/i18n/reldatefmt.cpp index 1652ea1fa4a..5d653e01c05 100644 --- a/icu4c/source/i18n/reldatefmt.cpp +++ b/icu4c/source/i18n/reldatefmt.cpp @@ -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; SharedPtr quantitativeUnits; SharedPtr combinedDateAndTime; SharedPtr pluralRules; SharedPtr 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 result(new RelativeDateTimeData()); LocalPointer qualitativeUnits(new QualitativeUnits()); LocalPointer 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 mf( + new MessageFormat(dateTimePattern, localeId, status)); if (U_FAILURE(status)) { return NULL; } - LocalPointer 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& 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& 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 diff --git a/icu4c/source/i18n/unicode/reldatefmt.h b/icu4c/source/i18n/unicode/reldatefmt.h index 0bf6ed630e4..6e9a98d647a 100644 --- a/icu4c/source/i18n/unicode/reldatefmt.h +++ b/icu4c/source/i18n/unicode/reldatefmt.h @@ -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. *

* 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 ptr; + const RelativeDateTimeData* ptr; }; U_NAMESPACE_END diff --git a/icu4c/source/test/intltest/lrucachetest.cpp b/icu4c/source/test/intltest/lrucachetest.cpp index de324f2f394..1c7a337fec9 100644 --- a/icu4c/source/test/intltest/lrucachetest.cpp +++ b/icu4c/source/test/intltest/lrucachetest.cpp @@ -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 localeNamePtr; - SharedPtr formatStrPtr; - int32_t length; -private: + CopyOnWriteForTesting(const CopyOnWriteForTesting &other) : + SharedObject(other), localeNamePtr(other.localeNamePtr), formatStrPtr(other.formatStrPtr), length(other.length) { } + + virtual ~CopyOnWriteForTesting() { + } + + SharedPtr localeNamePtr; + SharedPtr 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 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& 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& 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 ptr; + const CopyOnWriteForTesting* ptr = NULL; cache.get("boo", ptr, status); verifySharedPointer(ptr, "boo", "little"); - SharedPtr ptrCopy = ptr; - verifyPtr(ptr.readOnly(), ptrCopy.readOnly()); + const CopyOnWriteForTesting* ptrCopy = ptr; + ptrCopy->addRef(); { - SharedPtr 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 ptr1; - SharedPtr ptr2; - SharedPtr ptr3; - SharedPtr ptr4; - SharedPtr 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 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& 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& 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); }