FIFE  2008.0
 All Classes Namespaces Functions Variables Enumerations Enumerator
pool.cpp
00001 /***************************************************************************
00002  *   Copyright (C) 2005-2008 by the FIFE team                              *
00003  *   http://www.fifengine.de                                               *
00004  *   This file is part of FIFE.                                            *
00005  *                                                                         *
00006  *   FIFE is free software; you can redistribute it and/or                 *
00007  *   modify it under the terms of the GNU Lesser General Public            *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2.1 of the License, or (at your option) any later version.    *
00010  *                                                                         *
00011  *   This library is distributed in the hope that it will be useful,       *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00014  *   Lesser General Public License for more details.                       *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Lesser General Public      *
00017  *   License along with this library; if not, write to the                 *
00018  *   Free Software Foundation, Inc.,                                       *
00019  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
00020  ***************************************************************************/
00021 
00022 // Standard C++ library includes
00023 
00024 // 3rd party library includes
00025 
00026 // FIFE includes
00027 // These includes are split up in two parts, separated by one empty line
00028 // First block: files included from the FIFE root src directory
00029 // Second block: files included from the same folder
00030 #include "util/base/exception.h"
00031 #include "util/log/logger.h"
00032 
00033 #include "pool.h"
00034 
00035 namespace FIFE {
00036     static Logger _log(LM_POOL);
00037 
00038     Pool::Pool(const std::string& name):
00039         m_entries(),
00040         m_location_to_entry(),
00041         m_loaders(),
00042         m_name(name)
00043     {
00044     }
00045 
00046     Pool::~Pool() {
00047         FL_LOG(_log, LMsg("Pool destroyed: ") << m_name);
00048         printStatistics();
00049         // This is only usefull for debugging
00050         //sanityCheck();
00051         reset();
00052         std::vector<ResourceLoader*>::iterator loader;
00053         for (loader = m_loaders.begin(); loader != m_loaders.end(); loader++) {
00054             delete (*loader);
00055         }
00056     }
00057 
00058     void Pool::reset() {
00059         std::vector<PoolEntry*>::iterator entry;
00060         for (entry = m_entries.begin(); entry != m_entries.end(); entry++) {
00061             // Warn about leaks, but at least display ALL of them
00062             // Instead of bailing out with an exception in the FifeClass destructor.
00063             if( (*entry)->resource && (*entry)->resource->getRefCount() > 0 ) {
00064                 FL_WARN(_log, LMsg(m_name + " leak: ") << (*entry)->location->getFilename());
00065                 (*entry)->resource = 0;
00066             }
00067             delete (*entry);
00068         }
00069         m_entries.clear();
00070         m_location_to_entry.clear();
00071     }
00072 
00073     int Pool::purgeLoadedResources() {
00074         int count = 0;
00075         std::vector<PoolEntry*>::iterator it;
00076         for (it = m_entries.begin(); it != m_entries.end(); it++) {
00077             PoolEntry* entry = *it;
00078             if( entry->resource && entry->resource->getRefCount() == 0 ) {
00079                 delete entry->resource;
00080                 entry->resource = 0;
00081                 ++count;
00082             }
00083         }
00084         return count;
00085     }
00086 
00087     void Pool::addResourceLoader(ResourceLoader* loader) {
00088         m_loaders.push_back(loader);
00089     }
00090 
00091     void Pool::clearResourceLoaders() {
00092         m_loaders.clear();
00093     }
00094 
00095     int Pool::addResourceFromLocation(ResourceLocation* loc) {
00096         ResourceLocationToEntry::const_iterator it = m_location_to_entry.find(loc);
00097         if (it != m_location_to_entry.end()) {
00098             return it->second;
00099         }
00100 
00101         PoolEntry* entry = new PoolEntry();
00102         entry->location = loc->clone();
00103         m_entries.push_back(entry);
00104         size_t index = m_entries.size() - 1;
00105         m_location_to_entry[entry->location] = index;
00106         return index;
00107     }
00108 
00109     int Pool::addResourceFromFile(const std::string& filename) {
00110         ResourceLocation r = ResourceLocation(filename);
00111         return addResourceFromLocation(&r);
00112     }
00113 
00114     IResource& Pool::get(unsigned int index, bool inc) {
00115         if (index >= m_entries.size()) {
00116             FL_ERR(_log, LMsg("Tried to get with index ") << index << ", only " << m_entries.size() << " items in pool " + m_name);
00117             throw IndexOverflow( __FUNCTION__ );
00118         }
00119         IResource* res = NULL;
00120         PoolEntry* entry = m_entries[index];
00121         if (entry->resource) {
00122             res = entry->resource;
00123         } else {
00124             if (!entry->loader) {
00125                 findAndSetProvider(*entry);
00126             } else {
00127                 entry->resource = entry->loader->loadResource(*entry->location);
00128             }
00129 
00130             if (!entry->loader) {
00131                 LMsg msg("No suitable loader was found for resource ");
00132                 msg << "#" << index << "<" << entry->location->getFilename()
00133                     << "> in pool " << m_name;
00134                 FL_ERR(_log, msg);
00135 
00136                 throw NotFound(msg.str);
00137             }
00138 
00139             // This branch will only be relevant if the resource has been
00140             // loaded successfully before, but for some reason the loader
00141             // can't load the resource anymore.
00142             // Maybe someone deleted a file under FIFE's hands?
00143             if (!entry->resource) {
00144                 LMsg msg("The loader was unable to load the resource ");
00145                 msg << "#" << index << "<" << entry->location->getFilename()
00146                     << "> in pool " << m_name;
00147                 FL_ERR(_log, msg);
00148                 throw NotFound(msg.str);
00149             }
00150             res = entry->resource;
00151         }
00152         if (inc) {
00153             res->addRef();
00154         }
00155         res->setPoolId(index);
00156         return *res;
00157     }
00158 
00159     void Pool::release(unsigned int index, bool dec) {
00160         if (index >= m_entries.size()) {
00161             throw IndexOverflow( __FUNCTION__ );
00162         }
00163 
00164         IResource* res = NULL;
00165         PoolEntry* entry = m_entries[index];
00166         if (entry->resource) {
00167             res = entry->resource;
00168             if (dec) {
00169                 res->decRef();
00170             }
00171             if(res->getRefCount() == 0) {
00172                 delete entry->resource;
00173                 entry->resource = 0;
00174             }
00175         }
00176     }
00177 
00178     int Pool::getResourceCount(int status) {
00179         int amount = 0;
00180         std::vector<PoolEntry*>::iterator entry;
00181         for (entry = m_entries.begin(); entry != m_entries.end(); entry++) {
00182             if (status & RES_LOADED) {
00183                 if ((*entry)->resource) {
00184                     amount++;
00185                 }
00186             }
00187             if (status & RES_NON_LOADED) {
00188                 if (!(*entry)->resource) {
00189                     amount++;
00190                 }
00191             }
00192         }
00193         return amount;
00194     }
00195 
00196     void Pool::findAndSetProvider(PoolEntry& entry) {
00197         std::vector<ResourceLoader*>::iterator it = m_loaders.begin();
00198         std::vector<ResourceLoader*>::iterator end = m_loaders.end();
00199         if( it == end ) {
00200             FL_PANIC(_log, "no loader constructors given for resource pool");
00201         }
00202         for(; it != end; ++it) {
00203             IResource* res = (*it)->loadResource(*entry.location);
00204             if (res) {
00205                 entry.resource = res;
00206                 entry.loader = *it;
00207                 return;
00208             }
00209         };
00210     }
00211 
00212     void Pool::printStatistics() {
00213         FL_LOG(_log, LMsg("Pool not loaded =") << getResourceCount(RES_NON_LOADED));
00214         FL_LOG(_log, LMsg("Pool loaded     =") << getResourceCount(RES_LOADED));
00215         int amount = 0;
00216         std::vector<PoolEntry*>::iterator entry;
00217         for (entry = m_entries.begin(); entry != m_entries.end(); entry++) {
00218             if ((*entry)->resource) {
00219                 if ((*entry)->resource->getRefCount() > 0) {
00220                     amount++;
00221                 }
00222             }
00223         }
00224         FL_LOG(_log, LMsg("Pool locked     =") << amount);
00225         FL_LOG(_log, LMsg("Pool total size =") << m_entries.size());
00226     }
00227 
00228     void Pool::sanityCheck() {
00229         // It is easy to mess up the important consistent
00230         // less-than operator for the location classes.
00231         // This will check if according to the '==' operator
00232         // entries are duplicate (=memory leaks).
00233         // Slow and inaccurate. But should barf at real messups.
00234         for(unsigned i = 0; i != m_entries.size(); ++i) {
00235             int count = 0;
00236             for(unsigned j = i+1; j < m_entries.size(); ++j) {
00237                 if( *m_entries[i]->location == *m_entries[j]->location )
00238                     count ++;
00239             }
00240             if( 0 == count )
00241                 continue;
00242             FL_WARN(_log, LMsg("Multiple entries: ") << m_entries[i]->location->getFilename()
00243               << " #entries = " << (count+1) );
00244         }
00245     }
00246 
00247 }