2 ******************************************************************************
3 * Copyright (C) 2014, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 ******************************************************************************
8 ******************************************************************************
18 // TODO (Travis Keep): Consider building synchronization into this cache
19 // instead of leaving synchronization up to the clients.
21 LRUCache::CacheEntry::CacheEntry()
22 : moreRecent(NULL
), lessRecent(NULL
), localeId(NULL
), cachedData(NULL
),
23 status(U_ZERO_ERROR
) {
26 LRUCache::CacheEntry::~CacheEntry() {
30 void LRUCache::CacheEntry::unlink() {
31 if (moreRecent
!= NULL
) {
32 moreRecent
->lessRecent
= lessRecent
;
34 if (lessRecent
!= NULL
) {
35 lessRecent
->moreRecent
= moreRecent
;
41 void LRUCache::CacheEntry::reset() {
42 SharedObject::clearPtr(cachedData
);
43 status
= U_ZERO_ERROR
;
48 void LRUCache::CacheEntry::init(
49 char *adoptedLocId
, SharedObject
*dataToAdopt
, UErrorCode err
) {
50 U_ASSERT(localeId
== NULL
);
51 localeId
= adoptedLocId
;
52 SharedObject::copyPtr(dataToAdopt
, cachedData
);
56 void LRUCache::moveToMostRecent(CacheEntry
*entry
) {
57 if (entry
->moreRecent
== mostRecentlyUsedMarker
) {
61 entry
->moreRecent
= mostRecentlyUsedMarker
;
62 entry
->lessRecent
= mostRecentlyUsedMarker
->lessRecent
;
63 mostRecentlyUsedMarker
->lessRecent
->moreRecent
= entry
;
64 mostRecentlyUsedMarker
->lessRecent
= entry
;
67 void LRUCache::init(char *adoptedLocId
, CacheEntry
*entry
) {
68 UErrorCode status
= U_ZERO_ERROR
;
69 SharedObject
*result
= create(adoptedLocId
, status
);
70 entry
->init(adoptedLocId
, result
, status
);
73 UBool
LRUCache::contains(const char *localeId
) const {
74 return (uhash_get(localeIdToEntries
, localeId
) != NULL
);
78 const SharedObject
*LRUCache::_get(const char *localeId
, UErrorCode
&status
) {
79 // TODO (Travis Keep): Consider stripping irrelevant locale keywords.
80 if (U_FAILURE(status
)) {
83 CacheEntry
*entry
= static_cast<CacheEntry
*>(uhash_get(
84 localeIdToEntries
, localeId
));
88 if (uhash_count(localeIdToEntries
) < maxSize
) {
89 // Cache not full. There is room for a new entry.
90 entry
= new CacheEntry
;
92 status
= U_MEMORY_ALLOCATION_ERROR
;
96 // Cache full. Must evict an entry and re-use it.
97 entry
= leastRecentlyUsedMarker
->moreRecent
;
98 uhash_remove(localeIdToEntries
, entry
->localeId
);
103 // entry is an uninitialized, unlinked cache entry
104 char *dupLocaleId
= uprv_strdup(localeId
);
105 if (dupLocaleId
== NULL
) {
107 status
= U_MEMORY_ALLOCATION_ERROR
;
110 init(dupLocaleId
, entry
);
112 // Entry is initialized, add to hashtable
113 uhash_put(localeIdToEntries
, entry
->localeId
, entry
, &status
);
114 if (U_FAILURE(status
)) {
120 // Re-link entry so that it is the most recent.
121 moveToMostRecent(entry
);
123 if (U_FAILURE(entry
->status
)) {
124 status
= entry
->status
;
127 return entry
->cachedData
;
130 LRUCache::LRUCache(int32_t size
, UErrorCode
&status
) :
131 mostRecentlyUsedMarker(NULL
),
132 leastRecentlyUsedMarker(NULL
),
133 localeIdToEntries(NULL
),
135 if (U_FAILURE(status
)) {
138 mostRecentlyUsedMarker
= new CacheEntry
;
139 leastRecentlyUsedMarker
= new CacheEntry
;
140 if (mostRecentlyUsedMarker
== NULL
|| leastRecentlyUsedMarker
== NULL
) {
141 delete mostRecentlyUsedMarker
;
142 delete leastRecentlyUsedMarker
;
143 mostRecentlyUsedMarker
= leastRecentlyUsedMarker
= NULL
;
144 status
= U_MEMORY_ALLOCATION_ERROR
;
147 mostRecentlyUsedMarker
->moreRecent
= NULL
;
148 mostRecentlyUsedMarker
->lessRecent
= leastRecentlyUsedMarker
;
149 leastRecentlyUsedMarker
->moreRecent
= mostRecentlyUsedMarker
;
150 leastRecentlyUsedMarker
->lessRecent
= NULL
;
151 localeIdToEntries
= uhash_openSize(
155 maxSize
+ maxSize
/ 5,
157 if (U_FAILURE(status
)) {
162 LRUCache::~LRUCache() {
163 uhash_close(localeIdToEntries
);
164 for (CacheEntry
*i
= mostRecentlyUsedMarker
; i
!= NULL
;) {
165 CacheEntry
*next
= i
->lessRecent
;
171 SimpleLRUCache::~SimpleLRUCache() {
174 SharedObject
*SimpleLRUCache::create(const char *localeId
, UErrorCode
&status
) {
175 return createFunc(localeId
, status
);