File indexing completed on 2024-05-05 16:57:02
0001 /*************************************************************************** 0002 * Copyright (C) 2013 by Linuxstopmotion contributors; * 0003 * see the AUTHORS file for details. * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 2 of the License, or * 0008 * (at your option) any later version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, * 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0013 * GNU General Public License for more details. * 0014 * * 0015 * You should have received a copy of the GNU General Public License * 0016 * along with this program; if not, write to the * 0017 * Free Software Foundation, Inc., * 0018 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * 0019 ***************************************************************************/ 0020 0021 #ifndef LOADCACHE_H_ 0022 #define LOADCACHE_H_ 0023 0024 #include <string> 0025 #include <string.h> 0026 0027 /** 0028 * Type parameter {@c T} has the following members: 0029 * {@c T::value_t} Type of value loaded. 0030 * {@code{.cpp} T::value_t* T::load(const char* path) @endcode} Load the file. 0031 * {@code{.cpp} T::free(T::value_t*) @endcode} Free the value. 0032 */ 0033 template<typename T> class LoadCache { 0034 public: 0035 /** 0036 * Constructs an image cache. 0037 * @param cacheSize The number of images that the cache should hold. 0038 */ 0039 LoadCache(int cacheSize); 0040 ~LoadCache(); 0041 /** 0042 * Pulls the named image into the cache, if necessary, and returns it. 0043 * @param path The path of the file. 0044 */ 0045 typename T::value_t* get(const char* path); 0046 /** 0047 * Removes the named image from the cache, if it is present. 0048 * @param path The path of the file. 0049 */ 0050 void drop(const char* path); 0051 /** 0052 * Clears the cache. 0053 */ 0054 void clear(); 0055 private: 0056 class Item { 0057 std::string n; 0058 typename T::value_t* v; 0059 Item* next; 0060 Item(const Item&); 0061 Item& operator=(const Item&); 0062 public: 0063 Item(); 0064 ~Item(); 0065 /** 0066 * Clear the path and value (so both will return null). 0067 * Any previously returned path and value is destroyed. 0068 */ 0069 void clear(); 0070 /** 0071 * @return Ownership is not returned. 0072 */ 0073 const char* path() const; 0074 /** 0075 * @return Ownership is not returned. 0076 */ 0077 typename T::value_t* value() const; 0078 /** 0079 * Sets the path and value. 0080 * @param path A copy is taken, so ownership is not passed and the 0081 * lifetime of the original is immaterial. 0082 * @param value Ownership is passed. 0083 */ 0084 void set(const char* path, typename T::value_t* value); 0085 /** 0086 * Find the item in a list and move it to the front, if it exists. 0087 * @param [in] path The path to find. 0088 * @param [in,out] head Pointer to the head of the list. On exit, 0089 * this will point to the found element (if found). 0090 * @return The found element, or NULL if no such element. 0091 */ 0092 static Item* find(const char* path, Item*& head); 0093 /** 0094 * Find the item in a list and move it to freeHead front, if it exists. 0095 * If not, move the last element to {@c free} and clear it. 0096 * @param [in] path The path to find. 0097 * @param [in,out] head Pointer to the head of the list. On exit, 0098 * this will point to the found element (if found). 0099 * @param [in,out] freeHead Pointer to pointer to the head of the list 0100 * to receive a cleared element if not found. If NULL acts the same as 0101 * {@ref find} (i.e. does not move the last element on failure to find) 0102 * @return The found element, or NULL if no such element. 0103 */ 0104 static Item* findOrFree(const char* path, Item*& head, 0105 Item** freeHead); 0106 /** 0107 * Move the head of one list to another. 0108 * @param [in,out] to The head of the list to receive the element. 0109 * On return, this will hold the transferred element. 0110 * @param [in,out] from The head of the list that needs its head 0111 * removed. On return this will point to the second element in the 0112 * list, or be NULL if there is none. 0113 * @note if to and from are the same, this function has no effect. 0114 */ 0115 static void move(Item*& to, Item*& from); 0116 }; 0117 Item* buffer; 0118 Item* cacheHead; 0119 Item* freeHead; 0120 }; 0121 0122 template<typename T> 0123 LoadCache<T>::LoadCache(int cacheSize) 0124 : buffer(0), cacheHead(0), freeHead(0) { 0125 buffer = new Item[cacheSize < 1? 1 : cacheSize]; 0126 // construct the free list 0127 for (int i = 0; i != cacheSize; ++i) { 0128 Item* p = buffer + i; 0129 Item::move(freeHead, p); 0130 } 0131 } 0132 0133 template<typename T> 0134 LoadCache<T>::~LoadCache() { 0135 clear(); 0136 delete[] buffer; 0137 } 0138 0139 template<typename T> 0140 typename T::value_t* LoadCache<T>::get(const char* path) { 0141 Item* p = Item::findOrFree(path, cacheHead, &freeHead); 0142 if (p) 0143 return p->value(); 0144 typename T::value_t* value = T::load(path); 0145 freeHead->set(path, value); 0146 Item::move(cacheHead, freeHead); 0147 return cacheHead->value(); 0148 } 0149 0150 template<typename T> 0151 void LoadCache<T>::drop(const char* path) { 0152 Item* p = Item::find(path, cacheHead); 0153 if (p) { 0154 cacheHead->clear(); 0155 Item::move(freeHead, cacheHead); 0156 } 0157 } 0158 0159 template<typename T> 0160 void LoadCache<T>::clear() { 0161 while (cacheHead) { 0162 cacheHead->clear(); 0163 Item::move(freeHead, cacheHead); 0164 } 0165 } 0166 0167 template<typename T> 0168 LoadCache<T>::Item::Item() : v(0), next(0) { 0169 } 0170 0171 template<typename T> 0172 LoadCache<T>::Item::~Item() { 0173 clear(); 0174 } 0175 0176 template<typename T> 0177 void LoadCache<T>::Item::clear() { 0178 n.clear(); 0179 T::free(v); 0180 v = 0; 0181 } 0182 0183 template<typename T> 0184 const char* LoadCache<T>::Item::path() const { 0185 return n.c_str(); 0186 } 0187 0188 template<typename T> 0189 typename T::value_t* LoadCache<T>::Item::value() const { 0190 return v; 0191 } 0192 0193 template<typename T> 0194 void LoadCache<T>::Item::set(const char* path, typename T::value_t* value) { 0195 clear(); 0196 n = path; 0197 v = value; 0198 } 0199 0200 template<typename T> 0201 typename LoadCache<T>::Item* LoadCache<T>::Item::find( 0202 const char* path, Item*& head) { 0203 return findOrFree(path, head, 0); 0204 } 0205 0206 template<typename T> 0207 typename LoadCache<T>::Item* LoadCache<T>::Item::findOrFree( 0208 const char* path, Item*& head, Item** freeHead) { 0209 Item** pp = &head; 0210 Item** pLast = 0; 0211 while (*pp) { 0212 if (0 == strcmp((*pp)->n.c_str(), path)) { 0213 move(head, *pp); 0214 return head; 0215 } 0216 pLast = pp; 0217 pp = &(*pp)->next; 0218 } 0219 if (freeHead && !*freeHead && pLast) { 0220 move(*freeHead, *pLast); 0221 } 0222 return 0; 0223 } 0224 0225 template<typename T> 0226 void LoadCache<T>::Item::move(Item*& to, Item*& from) { 0227 if (from && from != to) { 0228 Item* moving = from; 0229 from = moving->next; 0230 moving->next = to; 0231 to = moving; 0232 } 0233 } 0234 0235 #endif /* LOADCACHE_H_ */