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