From 0e2afe4f98936dfee087570b719317fd6200a090 Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Tue, 23 Mar 2021 17:19:31 +0100 Subject: [PATCH] resource: remove the requirement to use shared_ptr (close #679) --- TODO | 1 + docs/md/resource.md | 2 +- src/entt/resource/cache.hpp | 26 +++++++++++++------------- src/entt/resource/fwd.hpp | 2 +- src/entt/resource/handle.hpp | 14 +++++++------- src/entt/resource/loader.hpp | 8 ++++---- 6 files changed, 27 insertions(+), 26 deletions(-) diff --git a/TODO b/TODO index 2321851bd..4a76bb112 100644 --- a/TODO +++ b/TODO @@ -7,6 +7,7 @@ * custom pools example (multi instance, tables, enable/disable, and so on...) WIP: +* HP: resource, forward the id to the loader from the cache and if constexpr the call to load, update doc and describe customization points * HP: any_vector for context variables * HP: make const registry::view thread safe, switch to a view{registry} model (long term goal) * HP: review registry::get, registry::try_get diff --git a/docs/md/resource.md b/docs/md/resource.md index e8be11b82..29328edd5 100644 --- a/docs/md/resource.md +++ b/docs/md/resource.md @@ -23,7 +23,7 @@ loading, and so on. `EnTT` doesn't pretend to offer a _one-fits-all_ solution for the different cases. Instead, it offers a minimal and perhaps trivial cache that can be useful most of the time during prototyping and sometimes even in a production -environment.
+environments.
For those interested in the subject, the plan is to improve it considerably over time in terms of performance, memory usage and functionalities. Hoping to make it, of course, one step at a time. diff --git a/src/entt/resource/cache.hpp b/src/entt/resource/cache.hpp index b9a554b9b..3da2be9bd 100644 --- a/src/entt/resource/cache.hpp +++ b/src/entt/resource/cache.hpp @@ -2,7 +2,6 @@ #define ENTT_RESOURCE_CACHE_HPP -#include #include #include #include @@ -93,18 +92,16 @@ struct resource_cache { template resource_handle load(const id_type id, Args &&... args) { static_assert(std::is_base_of_v, Loader>, "Invalid loader type"); - resource_handle resource{}; if(auto it = resources.find(id); it == resources.cend()) { - if(auto instance = Loader{}.get(std::forward(args)...); instance) { - resources[id] = instance; - resource = std::move(instance); + if(auto handle = temp(std::forward(args)...); handle) { + return (resources[id] = std::move(handle)); } } else { - resource = it->second; + return it->second; } - return resource; + return {}; } /** @@ -149,7 +146,7 @@ struct resource_cache { */ template [[nodiscard]] resource_handle temp(Args &&... args) const { - return { Loader{}.get(std::forward(args)...) }; + return Loader{}.get(std::forward(args)...); } /** @@ -166,8 +163,11 @@ struct resource_cache { * @return A handle for the given resource. */ [[nodiscard]] resource_handle handle(const id_type id) const { - auto it = resources.find(id); - return { it == resources.end() ? nullptr : it->second }; + if(auto it = resources.find(id); it != resources.cend()) { + return it->second; + } + + return {}; } /** @@ -221,15 +221,15 @@ struct resource_cache { if constexpr(std::is_invocable_v) { func(curr->first); } else if constexpr(std::is_invocable_v>) { - func(resource_handle{ curr->second }); + func(curr->second); } else { - func(curr->first, resource_handle{ curr->second }); + func(curr->first, curr->second); } } } private: - std::unordered_map> resources; + std::unordered_map> resources; }; diff --git a/src/entt/resource/fwd.hpp b/src/entt/resource/fwd.hpp index 8a2c9e901..d3c794625 100644 --- a/src/entt/resource/fwd.hpp +++ b/src/entt/resource/fwd.hpp @@ -10,7 +10,7 @@ struct resource_cache; template -class resource_handle; +struct resource_handle; template diff --git a/src/entt/resource/handle.hpp b/src/entt/resource/handle.hpp index f132e957a..d97c33d46 100644 --- a/src/entt/resource/handle.hpp +++ b/src/entt/resource/handle.hpp @@ -24,18 +24,18 @@ namespace entt { * @tparam Resource Type of resource managed by a handle. */ template -class resource_handle { - /*! @brief Resource handles are friends of their caches. */ - friend struct resource_cache; +struct resource_handle { + /*! @brief Default constructor. */ + resource_handle() ENTT_NOEXCEPT = default; + /** + * @brief Creates a handle from a shared pointer, namely a resource. + * @param res A pointer to a properly initialized resource. + */ resource_handle(std::shared_ptr res) ENTT_NOEXCEPT : resource{std::move(res)} {} -public: - /*! @brief Default constructor. */ - resource_handle() ENTT_NOEXCEPT = default; - /** * @brief Gets a reference to the managed resource. * diff --git a/src/entt/resource/loader.hpp b/src/entt/resource/loader.hpp index 365921126..d6b4ead29 100644 --- a/src/entt/resource/loader.hpp +++ b/src/entt/resource/loader.hpp @@ -2,8 +2,8 @@ #define ENTT_RESOURCE_LOADER_HPP -#include #include "fwd.hpp" +#include "handle.hpp" namespace entt { @@ -15,14 +15,14 @@ namespace entt { * Resource loaders must inherit from this class and stay true to the CRTP * idiom. Moreover, a resource loader must expose a public, const member * function named `load` that accepts a variable number of arguments and returns - * a shared pointer to the resource just created.
+ * a handle to the resource just created.
* As an example: * * @code{.cpp} * struct my_resource {}; * * struct my_loader: entt::resource_loader { - * std::shared_ptr load(int) const { + * resource_handle load(int value) const { * // use the integer value somehow * return std::make_shared(); * } @@ -53,7 +53,7 @@ class resource_loader { * @return The resource just loaded or an empty pointer in case of errors. */ template - [[nodiscard]] std::shared_ptr get(Args &&... args) const { + [[nodiscard]] resource_handle get(Args &&... args) const { return static_cast(this)->load(std::forward(args)...); } };