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_ */