FIFE 2008.0
|
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 }