Game of Ur 0.3.3
This is a computer adaptation of Game of Ur, written in C++ mainly using SDL and OpenGL.
Loading...
Searching...
No Matches
resource_database.hpp
Go to the documentation of this file.
1
16
22
23#ifndef FOOLSENGINE_RESOURCEDATABASE_H
24#define FOOLSENGINE_RESOURCEDATABASE_H
25
26#include <memory>
27#include <string>
28#include <vector>
29#include <tuple>
30#include <map>
31#include <iostream>
32#include <type_traits>
33
34#include <nlohmann/json.hpp>
35
36#include "../registrator.hpp"
37
38namespace ToyMaker {
39 class IResource;
40 class IResourceFactory;
42
43 class ResourceDatabase;
44 template <typename TResource> class ResourceFactory;
45 template <typename TResource> class Resource;
46 template <typename TResource, typename TMethod> class ResourceConstructor;
47
54 class IResource {
55 public:
60 virtual ~IResource()=default;
61
67 virtual std::string getResourceTypeName_() const=0;
68 protected:
69
74 IResource()=default;
75
81 template <typename TResource>
82 static void RegisterResource();
83 private:
84 };
85
92 public:
93
98 virtual ~IResourceFactory()=default;
99
106 virtual std::shared_ptr<IResource> createResource(const nlohmann::json& resourceDescription)=0;
107 protected:
108
113 std::map<std::string, std::unique_ptr<IResourceConstructor>> mFactoryMethods {};
114 private:
115 friend class ResourceDatabase;
116 };
117
124 public:
130 virtual std::string getResourceConstructorName_() const=0;
131
138 virtual std::shared_ptr<IResource> createResource(const nlohmann::json& methodParameters)=0;
139
144 virtual ~IResourceConstructor()=default;
145
146 protected:
147
153
160 template <typename TResource, typename TResourceConstructor>
161 static void RegisterResourceConstructor();
162 private:
163 friend class ResourceDatabase;
164 };
165
217 public:
224
232 template <typename TResource>
233 static std::shared_ptr<TResource> GetRegisteredResource(const std::string& resourceName);
234
242 template <typename TResource>
243 static std::shared_ptr<TResource> ConstructAnonymousResource(const nlohmann::json& resourceDescription);
244
252 static bool HasResourceDescription(const std::string& resourceName);
253
262 template <typename TResource>
263 static bool HasResource(const std::string& resourceName);
264
272 template <typename TResource>
273 void registerFactory (const std::string& factoryName, std::unique_ptr<IResourceFactory> pFactory);
274
284 template <typename TResource, typename TResourceConstructor>
285 void registerResourceConstructor (const std::string& resourceType, const std::string& methodName, std::unique_ptr<IResourceConstructor> pFactoryMethod);
286
296 static void AddResourceDescription (const nlohmann::json& resourceDescription);
297
298
299 private:
305 static void AssertResourceDescriptionValidity(const nlohmann::json& resourceDescription);
306
313 std::map<std::string, std::unique_ptr<IResourceFactory>> mFactories {};
314
319 std::map<std::string, std::weak_ptr<IResource>> mResources {};
320
325 std::map<std::string, nlohmann::json> mResourceDescriptions {};
326
331 ResourceDatabase() = default;
332 };
333
371 template <typename TDerived>
372 class Resource: public IResource {
373 public:
381 inline std::string getResourceTypeName_() const override { return TDerived::getResourceTypeName(); }
382
383 protected:
389 explicit Resource(int explicitlyInitializeMe) { (void)explicitlyInitializeMe/* prevent unused parameter warnings */; s_registrator.emptyFunc();/* Ensures that the registrator for this resource type is not optimized out (I think) */ }
390 private:
391
398 static void registerSelf();
399
409
410 friend class Registrator<Resource<TDerived>>;
411 };
412
421 template<typename TResource>
423 public:
427 ResourceFactory() { /* IMPORTANT: do not remove */ }
428 private:
436 std::shared_ptr<IResource> createResource(const nlohmann::json& resourceDescription) override;
437 };
438
473 template<typename TResource, typename TResourceFactoryMethod>
475 public:
483 inline std::string getResourceConstructorName_() const override { return TResourceFactoryMethod::getResourceConstructorName(); }
484
485 protected:
491 explicit ResourceConstructor(int explicitlyInitializeMe) {
492 (void)explicitlyInitializeMe; // prevent unused parameter warnings
493 s_registrator.emptyFunc(); // required to prevent this class' registrator object from being optimized away
494 }
495
496 private:
501 static void registerSelf();
502
511
512 friend class Registrator<ResourceConstructor<TResource, TResourceFactoryMethod>>;
513 friend class ResourceFactory<TResource>;
514 };
515
516 // ##########################################################################################
517 // FUNCTION DEFINITIONS
518 // ##########################################################################################
519
520 template <typename TResource>
521 std::shared_ptr<TResource> ResourceDatabase::GetRegisteredResource(const std::string& resourceName) {
522 ResourceDatabase& resourceDatabase { ResourceDatabase::GetInstance() };
523 std::shared_ptr<IResource> pResource { nullptr };
524
525 // Search known resources first and validate it against the requested type
526 std::map<std::string, nlohmann::json>::iterator resourceDescPair { resourceDatabase.mResourceDescriptions.find(resourceName) };
527 assert(
528 resourceDescPair != resourceDatabase.mResourceDescriptions.end()
529 && "No resource with this name was found amongst known resources"
530 );
531 assert(
532 resourceDescPair->second["type"].get<std::string>() == TResource::getResourceTypeName()
533 && "The type of resource requested does not match the type of resource as declared \
534 in its description"
535 );
536
537 // Look through resources currently in memory
538 {
539 std::map<std::string, std::weak_ptr<IResource>>::iterator resourcePair { resourceDatabase.mResources.find(resourceName) };
540 if(resourcePair != resourceDatabase.mResources.end()) {
541 // If a corresponding entry was found but the resource itself had already been moved
542 // out of memory, remove the entry
543 if(resourcePair->second.expired()) {
544 resourceDatabase.mResources.erase(resourcePair->first);
545
546 // We got lucky, and this resource is still in memory
547 } else {
548 pResource = resourcePair->second.lock();
549 }
550 }
551 }
552
553 // If we still haven't got an in-memory copy, construct this resource using its description,
554 // as registered in our resource description table
555 if(!pResource) {
556 pResource = std::static_pointer_cast<typename Resource<TResource>::IResource, TResource>(
558 );
559 resourceDatabase.mResources[resourceName] = std::weak_ptr<IResource>{ pResource };
560 }
561
562 // Finally, cast it down to the requested type and hand it over to whoever asked
563 //
564 // TODO: how can we prevent unwanted modification of the resource by one of its
565 // users?
566 return std::static_pointer_cast<TResource>(std::static_pointer_cast<Resource<TResource>>(pResource));
567 }
568
569 template<typename TResource>
570 std::shared_ptr<TResource> ResourceDatabase::ConstructAnonymousResource(const nlohmann::json& resourceDescription) {
571 ResourceDatabase& resourceDatabase { ResourceDatabase::GetInstance() };
572 std::shared_ptr<IResource> pResource { nullptr };
573
574 AssertResourceDescriptionValidity(resourceDescription);
575
576 // Construct this resource using its description
577 pResource = resourceDatabase
578 .mFactories.at(resourceDescription.at("type").get<std::string>())
579 ->createResource(resourceDescription);
580 assert(pResource && "Resource could not be constructed");
581
582 // Finally, cast it down to the requested type and hand it over to whoever asked
583 //
584 // TODO: how can we prevent unwanted modification of the resource by one of its
585 // users?
586 return std::static_pointer_cast<TResource>(std::static_pointer_cast<Resource<TResource>>(pResource));
587 }
588
589 template<typename TResource>
590 bool ResourceDatabase::HasResource(const std::string& resourceName) {
591 ResourceDatabase& resourceDatabase { GetInstance() };
592 bool descriptionPresent { HasResourceDescription(resourceName) };
593 bool typeMatched { false };
594 bool objectLoaded { false };
595 if(descriptionPresent){
596 typeMatched = (
597 TResource::getResourceTypeName()
598 == resourceDatabase.mResourceDescriptions.at(resourceName).at("type").get<std::string>()
599 );
600 objectLoaded = (
601 resourceDatabase.mResources.find(resourceName)
602 != resourceDatabase.mResources.end()
603 );
604 }
605 return (
606 descriptionPresent && typeMatched && objectLoaded
607 );
608 }
609
610 template <typename TResource>
611 std::shared_ptr<IResource> ResourceFactory<TResource>::createResource(const nlohmann::json& resourceDescription) {
612 std::cout << "Loading resource (" << TResource::getResourceTypeName() << ") : " << nlohmann::to_string(resourceDescription["parameters"]) << "\n";
613 return mFactoryMethods.at(resourceDescription["method"].get<std::string>())->createResource(
614 resourceDescription["parameters"].get<nlohmann::json>()
615 );
616 }
617
618 template <typename TDerived>
622
623 template <typename TResource, typename TResourceFactoryMethod>
625 // ensure that the associated factory is registered before methods are added to it
626 Registrator<Resource<TResource>>& resourceRegistrator { Registrator<Resource<TResource>>::getRegistrator() };
627 resourceRegistrator.emptyFunc();
628 // actually register this method now
630 }
631
632 template <typename TResource>
634 ResourceDatabase::GetInstance().registerFactory<TResource>(TResource::getResourceTypeName(), std::make_unique<ResourceFactory<TResource>>());
635 }
636
637 template <typename TResource, typename TResourceConstructor>
639 ResourceDatabase::GetInstance().registerResourceConstructor<TResource, TResourceConstructor>(TResource::getResourceTypeName(), TResourceConstructor::getResourceConstructorName(), std::make_unique<TResourceConstructor>());
640 }
641
642 template <typename TResource>
643 void ResourceDatabase::registerFactory(const std::string& factoryName, std::unique_ptr<IResourceFactory> pFactory) {
644 assert((std::is_base_of<IResource, TResource>::value) && "Resource must be subclass of IResource");
645 mFactories[factoryName] = std::move(pFactory);
646 }
647
648 template <typename TResource, typename TResourceConstructor>
649 void ResourceDatabase::registerResourceConstructor(const std::string& resourceType, const std::string& methodName, std::unique_ptr<IResourceConstructor> pFactoryMethod) {
650 assert((std::is_base_of<IResource, TResource>::value) && "Resource must be subclass of IResource");
651 assert((std::is_base_of<IResourceConstructor, TResourceConstructor>::value) && "Resource must be subclass of IResourceConstructor");
652 mFactories.at(resourceType)->mFactoryMethods[methodName] = std::move(pFactoryMethod);
653 }
654
655}
656
657#endif
A single way that a resource may be constructed.
Definition resource_database.hpp:123
IResourceConstructor()=default
Construct a new IResourceConstructor object.
static void RegisterResourceConstructor()
Registers this resource constructor against its respective ResourceFactory during static initializati...
Definition resource_database.hpp:638
virtual std::shared_ptr< IResource > createResource(const nlohmann::json &methodParameters)=0
Creates a resource object using the parameters specified in methodParameters.
virtual ~IResourceConstructor()=default
Destroys this resource constructor (when the application is terminated.)
virtual std::string getResourceConstructorName_() const =0
Get the Resource Constructor type string for this constructor.
A class that holds references to all constructors for a type of Resource object.
Definition resource_database.hpp:91
std::map< std::string, std::unique_ptr< IResourceConstructor > > mFactoryMethods
A list of constructors that may be used to create a Resource of this kind.
Definition resource_database.hpp:113
virtual ~IResourceFactory()=default
Destroy the IResourceFactory object.
virtual std::shared_ptr< IResource > createResource(const nlohmann::json &resourceDescription)=0
Creates a resource object of a specific type using its JSON resource description.
Base class of all Resource types.
Definition resource_database.hpp:54
static void RegisterResource()
Registers this resource as a Resource type with the ResourceDatabase.
Definition resource_database.hpp:633
IResource()=default
Construct a new IResource object.
virtual ~IResource()=default
Destroy the IResource object.
virtual std::string getResourceTypeName_() const =0
Get the Resource Type string for this resource.
Helper class for registering a class at program startup.
Definition registrator.hpp:64
An object representing one method for creating a resource of a given kind.
Definition resource_database.hpp:474
static void registerSelf()
A helper function that informs the ResourceDatabase that this constructor type exists.
Definition resource_database.hpp:624
std::string getResourceConstructorName_() const override
Gets the resource constructor type string of the constructor.
Definition resource_database.hpp:483
ResourceConstructor(int explicitlyInitializeMe)
Construct a new ResourceConstructor object.
Definition resource_database.hpp:491
static Registrator< ResourceConstructor< TResource, TResourceFactoryMethod > > s_registrator
A helper class responsible for calling this class' registerSelf() method at during the static initial...
Definition resource_database.hpp:508
A database of all Resource types available for this project, and the various ResourceConstructors res...
Definition resource_database.hpp:216
static ResourceDatabase & GetInstance()
Returns the sole instance of the ResourceDatabase used by this application.
Definition resource_database.cpp:72
static std::shared_ptr< TResource > ConstructAnonymousResource(const nlohmann::json &resourceDescription)
Constructs a fresh anonymous resource using a registered constructor according to its description in ...
Definition resource_database.hpp:570
std::map< std::string, std::weak_ptr< IResource > > mResources
References to all resources that have been loaded and are being held in memory.
Definition resource_database.hpp:319
void registerResourceConstructor(const std::string &resourceType, const std::string &methodName, std::unique_ptr< IResourceConstructor > pFactoryMethod)
Registers a particular ResourceConstructor for a Resource.
Definition resource_database.hpp:649
static bool HasResource(const std::string &resourceName)
Tests whether a particular resource has already been loaded into memory.
Definition resource_database.hpp:590
static void AssertResourceDescriptionValidity(const nlohmann::json &resourceDescription)
Asserts the correctness of a resource's description, per the Resource types and constructors known to...
Definition resource_database.cpp:7
ResourceDatabase()=default
Construct a new ResourceDatabase object.
std::map< std::string, nlohmann::json > mResourceDescriptions
A list of all Resources that are known to the database, including details of how they may be construc...
Definition resource_database.hpp:325
void registerFactory(const std::string &factoryName, std::unique_ptr< IResourceFactory > pFactory)
Registers a factory responsible for tracking valid ResourceConstructors for a particular type of Reso...
Definition resource_database.hpp:643
std::map< std::string, std::unique_ptr< IResourceFactory > > mFactories
Pointers to different factories, each responsible for the creation of different kinds of resources.
Definition resource_database.hpp:313
static std::shared_ptr< TResource > GetRegisteredResource(const std::string &resourceName)
Gets a reference to or constructs a Resource by name whose description has been stored in this Resour...
Definition resource_database.hpp:521
static bool HasResourceDescription(const std::string &resourceName)
Tests whether the description of a particular named resource exists in this project's ResourceDatabas...
Definition resource_database.cpp:66
static void AddResourceDescription(const nlohmann::json &resourceDescription)
Adds the description (name, constructor, related parameters) to the resource database.
Definition resource_database.cpp:43
Tracks pointers to all ResourceConstructors responsible for creating a resource of one type.
Definition resource_database.hpp:422
ResourceFactory()
Construct a new Resource Factory object.
Definition resource_database.hpp:427
std::shared_ptr< IResource > createResource(const nlohmann::json &resourceDescription) override
Create an object of type Resource, specifying its constructor and the constructor's parameters in JSO...
Definition resource_database.hpp:611
The base class for any type whose creation and storage should be managed by the ResourceDatabase.
Definition resource_database.hpp:372
std::string getResourceTypeName_() const override
Get the resource type string for this resource.
Definition resource_database.hpp:381
Resource(int explicitlyInitializeMe)
Construct a new resource object.
Definition resource_database.hpp:389
static Registrator< Resource< TDerived > > & s_registrator
A static variable to this classes Registrator.
Definition resource_database.hpp:408
static void registerSelf()
A helper function that actually performs the task of registering this class with the ResourceDatabase...
Definition resource_database.hpp:619
Namespace containing all class definitions and functions related to the ToyMaker engine.
Definition camera_system.hpp:20
Contains the definition for the Registrator<T> utility class, used anywhere that automatic registrati...