Blender V2.61 - r43446

MEM_CacheLimiter.h

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * Contributor(s): Peter Schlaile <peter@schlaile.de> 2005
00019  *
00020  * ***** END GPL LICENSE BLOCK *****
00021  */
00022 
00028 #ifndef MEM_CACHELIMITER_H
00029 #define MEM_CACHELIMITER_H
00030 
00060 #include <list>
00061 #include "MEM_Allocator.h"
00062 
00063 template<class T>
00064 class MEM_CacheLimiter;
00065 
00066 #ifndef __MEM_cache_limiter_c_api_h_included__
00067 extern "C" {
00068     extern void MEM_CacheLimiter_set_maximum(intptr_t m);
00069     extern intptr_t MEM_CacheLimiter_get_maximum();
00070 };
00071 #endif
00072 
00073 template<class T>
00074 class MEM_CacheLimiterHandle {
00075 public:
00076     explicit MEM_CacheLimiterHandle(T * data_, 
00077                      MEM_CacheLimiter<T> * parent_) 
00078         : data(data_), refcount(0), parent(parent_) { }
00079 
00080     void ref() { 
00081         refcount++; 
00082     }
00083     void unref() { 
00084         refcount--; 
00085     }
00086     T * get() { 
00087         return data; 
00088     }
00089     const T * get() const { 
00090         return data; 
00091     }
00092     int get_refcount() const { 
00093         return refcount; 
00094     }
00095     bool can_destroy() const { 
00096         return !data || !refcount; 
00097     }
00098     bool destroy_if_possible() {
00099         if (can_destroy()) {
00100             delete data;
00101             data = 0;
00102             unmanage();
00103             return true;
00104         }
00105         return false;
00106     }
00107     void unmanage() {
00108         parent->unmanage(this);
00109     }
00110     void touch() {
00111         parent->touch(this);
00112     }
00113 private:
00114     friend class MEM_CacheLimiter<T>;
00115 
00116     T * data;
00117     int refcount;
00118     typename std::list<MEM_CacheLimiterHandle<T> *,
00119       MEM_Allocator<MEM_CacheLimiterHandle<T> *> >::iterator me;
00120     MEM_CacheLimiter<T> * parent;
00121 };
00122 
00123 template<class T>
00124 class MEM_CacheLimiter {
00125 public:
00126     typedef typename std::list<MEM_CacheLimiterHandle<T> *,
00127       MEM_Allocator<MEM_CacheLimiterHandle<T> *> >::iterator iterator;
00128     typedef intptr_t (*MEM_CacheLimiter_DataSize_Func) (void *data);
00129     MEM_CacheLimiter(MEM_CacheLimiter_DataSize_Func getDataSize_)
00130         : getDataSize(getDataSize_) {
00131     }
00132     ~MEM_CacheLimiter() {
00133         for (iterator it = queue.begin(); it != queue.end(); it++) {
00134             delete *it;
00135         }
00136     }
00137     MEM_CacheLimiterHandle<T> * insert(T * elem) {
00138         queue.push_back(new MEM_CacheLimiterHandle<T>(elem, this));
00139         iterator it = queue.end();
00140         --it;
00141         queue.back()->me = it;
00142         return queue.back();
00143     }
00144     void unmanage(MEM_CacheLimiterHandle<T> * handle) {
00145         queue.erase(handle->me);
00146         delete handle;
00147     }
00148     void enforce_limits() {
00149         intptr_t max = MEM_CacheLimiter_get_maximum();
00150         intptr_t mem_in_use, cur_size;
00151 
00152         if (max == 0) {
00153             return;
00154         }
00155 
00156         if(getDataSize) {
00157             mem_in_use = total_size();
00158         } else {
00159             mem_in_use = MEM_get_memory_in_use();
00160         }
00161 
00162         for (iterator it = queue.begin(); 
00163              it != queue.end() && mem_in_use > max;)
00164         {
00165             iterator jt = it;
00166             ++it;
00167 
00168             if(getDataSize) {
00169                 cur_size= getDataSize((*jt)->get()->get_data());
00170             } else {
00171                 cur_size= mem_in_use;
00172             }
00173 
00174             (*jt)->destroy_if_possible();
00175 
00176             if(getDataSize) {
00177                 mem_in_use-= cur_size;
00178             } else {
00179                 mem_in_use-= cur_size - MEM_get_memory_in_use();
00180             }
00181         }
00182     }
00183     void touch(MEM_CacheLimiterHandle<T> * handle) {
00184         queue.push_back(handle);
00185         queue.erase(handle->me);
00186         iterator it = queue.end();
00187         --it;
00188         handle->me = it;
00189     }
00190 private:
00191     intptr_t total_size() {
00192         intptr_t size = 0;
00193         for (iterator it = queue.begin(); it != queue.end(); it++) {
00194             size+= getDataSize((*it)->get()->get_data());
00195         }
00196         return size;
00197     }
00198 
00199     std::list<MEM_CacheLimiterHandle<T>*,
00200       MEM_Allocator<MEM_CacheLimiterHandle<T> *> > queue;
00201     MEM_CacheLimiter_DataSize_Func getDataSize;
00202 };
00203 
00204 #endif // MEM_CACHELIMITER_H