TurtleBrains  0.3.5
High quality, portable, C++ framework for rapid 2D game development.
tb_resource_cache.hpp
1 
10 #ifndef _TurtleBraines_ResourceCache_hpp
11 #define _TurtleBraines_ResourceCache_hpp
12 
13 #include <turtle_brains/core/tb_noncopyable.hpp>
14 #include <turtle_brains/core/tb_string.hpp>
15 #include <turtle_brains/core/tb_types.hpp>
16 
17 #include <vector>
18 #include <utility>
19 #include <unordered_map>
20 #include <functional>
21 
22 namespace TurtleBrains
23 {
24  namespace Core
25  {
31  template <typename ResourceType, typename HandleType> class ResourceCache : public tbCore::Noncopyable
32  {
33  public:
37  static HandleType InvalidResource(void);
38 
53  HandleType CreateResource(const ResourceType& resource, const tbCore::tbString& resourceName = "");
54 
63  void DestroyResource(const HandleType& handle);
64 
72  void ClearCache(void);
73 
83  void IncrementReferenceOf(const HandleType& handle);
84 
95  bool DecrementReferenceOf(const HandleType& handle);
96 
106  ResourceType GetResource(const HandleType& handle) const;
107 
115  void SetResource(const HandleType& handle, const ResourceType& resource);
116 
127  const ResourceType& GetResourceReference(const HandleType& handle) const;
128 
139  ResourceType& GetResourceReference(const HandleType& handle);
140 
149  HandleType GetResourceHandle(const tbCore::tbString& resourceName) const;
150 
157  bool IsValidHandle(const HandleType& handle) const;
158 
173  size_t ForEachValidResource(std::function<void(ResourceType&, HandleType)> callbackFunction)
174  {
175  size_t currentIndex = 0;
176  size_t validResourceCount = 0;
177  for (auto& resourcePair : mResources)
178  {
179  if (resourcePair.first > 0)
180  {
181  callbackFunction(resourcePair.second, HandleType(currentIndex));
182  ++validResourceCount;
183  }
184 
185  ++currentIndex;
186  }
187  return validResourceCount;
188  }
189 
190  private:
191  std::unordered_map<tbCore::tbString, HandleType> mResourceCache;
192  std::vector<std::pair<int, ResourceType>> mResources;
193  };
194 
195  }; /* namespace Core */
196 }; /* namespace TurtleBrains */
197 
198 namespace tbCore = TurtleBrains::Core;
199 
200 //-------------------------------------------------------------------------------------------------------------------//
201 //-------------------------------------------------------------------------------------------------------------------//
202 //-------------------------------------------------------------------------------------------------------------------//
203 
204 template<typename ResourceType, typename HandleType> HandleType
206 {
207  return HandleType();
208 }
209 
210 //-------------------------------------------------------------------------------------------------------------------//
211 
212 template<typename ResourceType, typename HandleType> HandleType
214 {
215  //does resourceName already point to something [this maybe required elsewhere].
216  const auto& resourceIterator = mResourceCache.find(resourceName);
217  if (resourceIterator == mResourceCache.end())
218  {
219  size_t searchedHandle = 0;
220  for (; searchedHandle < mResources.size(); ++searchedHandle)
221  {
222  if (0 == mResources[searchedHandle].first)
223  {
224  mResources[searchedHandle].first = 1;
225  mResources[searchedHandle].second = resource;
226  break;
227  }
228  }
229 
230  if (searchedHandle == mResources.size())
231  {
232  mResources.emplace_back(1, resource);
233  }
234 
235  if (false == resourceName.empty())
236  {
237  tb_error_if(mResourceCache.end() != mResourceCache.find(resourceName), "tbInternalError: Resource name already found in cache!");
238  //mResourceCache.insert(std::unordered_map<tbCore::tbString, HandleType>::value_type(resourceName, searchedHandle));
239  mResourceCache.emplace(resourceName, HandleType(searchedHandle));
240  }
241 
242  return searchedHandle;
243  }
244 
245  //Going to return to thinking about this, but I believe CreateResource should ALWAYS add a new resource
246  //to the cache, and that it was the managers (user) responsibility to ensure the item did NOT exist and
247  //if it did exist to increment ref count.
248  tb_error("This probably should never happen...");
249  IncrementReferenceOf(resourceIterator->second);
250  return resourceIterator->second;
251 }
252 
253 //-------------------------------------------------------------------------------------------------------------------//
254 
255 template<typename ResourceType, typename HandleType> void
257 {
258  tb_error_if(InvalidResource() == handle, "tbExternalError: Attempting to destroy a resource with an invalid handle.");
259  tb_error_if(handle.mValue >= mResources.size(), "tbExternalError: Attempting to destroy a resource with an out-of-bounds handle.");
260 
261  mResources[handle.mValue].first = 0;
262 
263  for (auto cacheIter = mResourceCache.begin(), cacheEnd = mResourceCache.end(); cacheIter != cacheEnd; /* in loop */)
264  {
265  if (cacheIter->second == handle)
266  {
267  cacheIter = mResourceCache.erase(cacheIter);
268  }
269  else
270  {
271  ++cacheIter;
272  }
273  }
274 }
275 
276 //-------------------------------------------------------------------------------------------------------------------//
277 
278 template<typename ResourceType, typename HandleType> void
280 {
281  mResources.clear();
282  mResourceCache.clear();
283 }
284 
285 //-------------------------------------------------------------------------------------------------------------------//
286 
287 template<typename ResourceType, typename HandleType> void
289 {
290  tb_error_if(mResources[handle.mValue].first == 0, "tbExternalError: Attempting to increment reference count of object with 0 references.");
291  ++mResources[handle.mValue].first;
292 }
293 
294 //-------------------------------------------------------------------------------------------------------------------//
295 
296 template<typename ResourceType, typename HandleType> bool
298 {
299  tb_error_if(mResources[handle.mValue].first == 0, "tbInternalError: Attempting to decrement reference count of object with 0 references.");
300  --mResources[handle.mValue].first;
301  return 0 == mResources[handle.mValue].first;
302 }
303 
304 //-------------------------------------------------------------------------------------------------------------------//
305 
306 template<typename ResourceType, typename HandleType> ResourceType
308 {
309  //TODO: TurtleBrains: Could use a tb_with_optimize to remove debug helper checks.
310  tb_error_if(InvalidResource() == handle, "tbExternalError: Attempting to access a resource with an invalid handle.");
311  tb_error_if(handle.mValue >= mResources.size(), "tbInternalError: Invalid handle, access out of range.");
312  return mResources[handle.mValue].second;
313 }
314 
315 //-------------------------------------------------------------------------------------------------------------------//
316 
317 template<typename ResourceType, typename HandleType> void
318 TurtleBrains::Core::ResourceCache<ResourceType, HandleType>::SetResource(const HandleType& handle, const ResourceType& resource)
319 {
320  tb_error_if(InvalidResource() == handle, "tbExternalError: Attempting to access a resource with an invalid handle.");
321  tb_error_if(handle.mValue >= mResources.size(), "tbInternalError: Invalid handle, access out of range.");
322  mResources[handle.mValue].second = resource;
323 }
324 
325 //-------------------------------------------------------------------------------------------------------------------//
326 
327 template<typename ResourceType, typename HandleType> const ResourceType&
329 {
330  //TODO: TurtleBrains: Could use a tb_with_optimize to remove debug helper checks.
331  tb_error_if(InvalidResource() == handle, "tbExternalError: Attempting to access a resource with an invalid handle.");
332  tb_error_if(handle.mValue >= mResources.size(), "tbInternalError: Invalid handle, access out of range.");
333  return mResources[handle.mValue].second;
334 }
335 
336 //-------------------------------------------------------------------------------------------------------------------//
337 
338 template<typename ResourceType, typename HandleType> ResourceType&
340 {
341  //TODO: TurtleBrains: Could use a tb_with_optimize to remove debug helper checks.
342  tb_error_if(InvalidResource() == handle, "tbExternalError: Attempting to access a resource with an invalid handle.");
343  tb_error_if(handle.mValue >= mResources.size(), "tbInternalError: Invalid handle, access out of range.");
344  return mResources[handle.mValue].second;
345 }
346 
347 //-------------------------------------------------------------------------------------------------------------------//
348 
349 template<typename ResourceType, typename HandleType> HandleType
351 {
352  const auto& resourceIterator = mResourceCache.find(resourceName);
353  if (mResourceCache.end() != resourceIterator)
354  {
355  return resourceIterator->second;
356  }
357 
358  return HandleType();
359 }
360 
361 //-------------------------------------------------------------------------------------------------------------------//
362 
363 template<typename ResourceType, typename HandleType> bool
365  const HandleType& handle) const
366 {
367  if (handle.mValue < mResources.size() && mResources[handle.mValue].first > 0)
368  {
369  return true;
370  }
371 
372  return false;
373 }
374 
375 //-------------------------------------------------------------------------------------------------------------------//
376 
377 #endif /* _TurtleBraines_ResourceCache_hpp */
HandleType GetResourceHandle(const tbCore::tbString &resourceName) const
Definition: tb_resource_cache.hpp:350
const ResourceType & GetResourceReference(const HandleType &handle) const
Definition: tb_resource_cache.hpp:328
#define tb_error(message,...)
Definition: tb_error.hpp:23
void ClearCache(void)
Definition: tb_resource_cache.hpp:279
Definition: tb_noncopyable.hpp:22
Here is some information about the primary namespace.
Definition: tb_application_dialog.hpp:21
ResourceType GetResource(const HandleType &handle) const
Definition: tb_resource_cache.hpp:307
void IncrementReferenceOf(const HandleType &handle)
Definition: tb_resource_cache.hpp:288
void SetResource(const HandleType &handle, const ResourceType &resource)
Definition: tb_resource_cache.hpp:318
void DestroyResource(const HandleType &handle)
Definition: tb_resource_cache.hpp:256
Definition: tb_resource_cache.hpp:31
Contains core functionality for each component of the API.
Definition: tb_debug_logger.hpp:88
#define tb_error_if(errorTest, message,...)
Definition: tb_error.hpp:42
static HandleType InvalidResource(void)
Definition: tb_resource_cache.hpp:205
bool IsValidHandle(const HandleType &handle) const
Definition: tb_resource_cache.hpp:364
HandleType CreateResource(const ResourceType &resource, const tbCore::tbString &resourceName="")
Definition: tb_resource_cache.hpp:213
std::string tbString
Definition: tb_string.hpp:335
bool DecrementReferenceOf(const HandleType &handle)
Definition: tb_resource_cache.hpp:297