FIFE  2008.0
 All Classes Namespaces Functions Variables Enumerations Enumerator Pages
pool.cpp
1 /***************************************************************************
2  * Copyright (C) 2005-2008 by the FIFE team *
3  * http://www.fifengine.de *
4  * This file is part of FIFE. *
5  * *
6  * FIFE is free software; you can redistribute it and/or *
7  * modify it under the terms of the GNU Lesser General Public *
8  * License as published by the Free Software Foundation; either *
9  * version 2.1 of the License, or (at your option) any later version. *
10  * *
11  * This library is distributed in the hope that it will be useful, *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
14  * Lesser General Public License for more details. *
15  * *
16  * You should have received a copy of the GNU Lesser General Public *
17  * License along with this library; if not, write to the *
18  * Free Software Foundation, Inc., *
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
20  ***************************************************************************/
21 
22 // Standard C++ library includes
23 
24 // 3rd party library includes
25 
26 // FIFE includes
27 // These includes are split up in two parts, separated by one empty line
28 // First block: files included from the FIFE root src directory
29 // Second block: files included from the same folder
30 #include "util/base/exception.h"
31 #include "util/log/logger.h"
32 
33 #include "pool.h"
34 
35 namespace FIFE {
36  static Logger _log(LM_POOL);
37 
38  Pool::Pool(const std::string& name):
39  m_entries(),
40  m_location_to_entry(),
41  m_loaders(),
42  m_name(name)
43  {
44  }
45 
47  FL_LOG(_log, LMsg("Pool destroyed: ") << m_name);
49  // This is only usefull for debugging
50  //sanityCheck();
51  reset();
52  std::vector<ResourceLoader*>::iterator loader;
53  for (loader = m_loaders.begin(); loader != m_loaders.end(); loader++) {
54  delete (*loader);
55  }
56  }
57 
58  void Pool::reset() {
59  std::vector<PoolEntry*>::iterator entry;
60  for (entry = m_entries.begin(); entry != m_entries.end(); entry++) {
61  // Warn about leaks, but at least display ALL of them
62  // Instead of bailing out with an exception in the FifeClass destructor.
63  if( (*entry)->resource && (*entry)->resource->getRefCount() > 0 ) {
64  FL_WARN(_log, LMsg(m_name + " leak: ") << (*entry)->location->getFilename());
65  (*entry)->resource = 0;
66  }
67  delete (*entry);
68  }
69  m_entries.clear();
70  m_location_to_entry.clear();
71  }
72 
74  int count = 0;
75  std::vector<PoolEntry*>::iterator it;
76  for (it = m_entries.begin(); it != m_entries.end(); it++) {
77  PoolEntry* entry = *it;
78  if( entry->resource && entry->resource->getRefCount() == 0 ) {
79  delete entry->resource;
80  entry->resource = 0;
81  ++count;
82  }
83  }
84  return count;
85  }
86 
88  m_loaders.push_back(loader);
89  }
90 
92  m_loaders.clear();
93  }
94 
96  ResourceLocationToEntry::const_iterator it = m_location_to_entry.find(loc);
97  if (it != m_location_to_entry.end()) {
98  return it->second;
99  }
100 
101  PoolEntry* entry = new PoolEntry();
102  entry->location = loc->clone();
103  m_entries.push_back(entry);
104  size_t index = m_entries.size() - 1;
105  m_location_to_entry[entry->location] = index;
106  return index;
107  }
108 
109  int Pool::addResourceFromFile(const std::string& filename) {
110  ResourceLocation r = ResourceLocation(filename);
111  return addResourceFromLocation(&r);
112  }
113 
114  IResource& Pool::get(unsigned int index, bool inc) {
115  if (index >= m_entries.size()) {
116  FL_ERR(_log, LMsg("Tried to get with index ") << index << ", only " << m_entries.size() << " items in pool " + m_name);
117  throw IndexOverflow( __FUNCTION__ );
118  }
119  IResource* res = NULL;
120  PoolEntry* entry = m_entries[index];
121  if (entry->resource) {
122  res = entry->resource;
123  } else {
124  if (!entry->loader) {
125  findAndSetProvider(*entry);
126  } else {
127  entry->resource = entry->loader->loadResource(*entry->location);
128  }
129 
130  if (!entry->loader) {
131  LMsg msg("No suitable loader was found for resource ");
132  msg << "#" << index << "<" << entry->location->getFilename()
133  << "> in pool " << m_name;
134  FL_ERR(_log, msg);
135 
136  throw NotFound(msg.str);
137  }
138 
139  // This branch will only be relevant if the resource has been
140  // loaded successfully before, but for some reason the loader
141  // can't load the resource anymore.
142  // Maybe someone deleted a file under FIFE's hands?
143  if (!entry->resource) {
144  LMsg msg("The loader was unable to load the resource ");
145  msg << "#" << index << "<" << entry->location->getFilename()
146  << "> in pool " << m_name;
147  FL_ERR(_log, msg);
148  throw NotFound(msg.str);
149  }
150  res = entry->resource;
151  }
152  if (inc) {
153  res->addRef();
154  }
155  res->setPoolId(index);
156  return *res;
157  }
158 
159  void Pool::release(unsigned int index, bool dec) {
160  if (index >= m_entries.size()) {
161  throw IndexOverflow( __FUNCTION__ );
162  }
163 
164  IResource* res = NULL;
165  PoolEntry* entry = m_entries[index];
166  if (entry->resource) {
167  res = entry->resource;
168  if (dec) {
169  res->decRef();
170  }
171  if(res->getRefCount() == 0) {
172  delete entry->resource;
173  entry->resource = 0;
174  }
175  }
176  }
177 
178  int Pool::getResourceCount(int status) {
179  int amount = 0;
180  std::vector<PoolEntry*>::iterator entry;
181  for (entry = m_entries.begin(); entry != m_entries.end(); entry++) {
182  if (status & RES_LOADED) {
183  if ((*entry)->resource) {
184  amount++;
185  }
186  }
187  if (status & RES_NON_LOADED) {
188  if (!(*entry)->resource) {
189  amount++;
190  }
191  }
192  }
193  return amount;
194  }
195 
196  void Pool::findAndSetProvider(PoolEntry& entry) {
197  std::vector<ResourceLoader*>::iterator it = m_loaders.begin();
198  std::vector<ResourceLoader*>::iterator end = m_loaders.end();
199  if( it == end ) {
200  FL_PANIC(_log, "no loader constructors given for resource pool");
201  }
202  for(; it != end; ++it) {
203  IResource* res = (*it)->loadResource(*entry.location);
204  if (res) {
205  entry.resource = res;
206  entry.loader = *it;
207  return;
208  }
209  };
210  }
211 
213  FL_LOG(_log, LMsg("Pool not loaded =") << getResourceCount(RES_NON_LOADED));
214  FL_LOG(_log, LMsg("Pool loaded =") << getResourceCount(RES_LOADED));
215  int amount = 0;
216  std::vector<PoolEntry*>::iterator entry;
217  for (entry = m_entries.begin(); entry != m_entries.end(); entry++) {
218  if ((*entry)->resource) {
219  if ((*entry)->resource->getRefCount() > 0) {
220  amount++;
221  }
222  }
223  }
224  FL_LOG(_log, LMsg("Pool locked =") << amount);
225  FL_LOG(_log, LMsg("Pool total size =") << m_entries.size());
226  }
227 
229  // It is easy to mess up the important consistent
230  // less-than operator for the location classes.
231  // This will check if according to the '==' operator
232  // entries are duplicate (=memory leaks).
233  // Slow and inaccurate. But should barf at real messups.
234  for(unsigned i = 0; i != m_entries.size(); ++i) {
235  int count = 0;
236  for(unsigned j = i+1; j < m_entries.size(); ++j) {
237  if( *m_entries[i]->location == *m_entries[j]->location )
238  count ++;
239  }
240  if( 0 == count )
241  continue;
242  FL_WARN(_log, LMsg("Multiple entries: ") << m_entries[i]->location->getFilename()
243  << " #entries = " << (count+1) );
244  }
245  }
246 
247 }