resource: remove the requirement to use shared_ptr (close #679)

This commit is contained in:
Michele Caini
2021-03-23 17:19:31 +01:00
parent a936f7cdbe
commit 0e2afe4f98
6 changed files with 27 additions and 26 deletions

1
TODO
View File

@@ -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<T...>{registry} model (long term goal)
* HP: review registry::get, registry::try_get

View File

@@ -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.<br/>
environments.<br/>
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.

View File

@@ -2,7 +2,6 @@
#define ENTT_RESOURCE_CACHE_HPP
#include <memory>
#include <type_traits>
#include <unordered_map>
#include <utility>
@@ -93,18 +92,16 @@ struct resource_cache {
template<typename Loader, typename... Args>
resource_handle<Resource> load(const id_type id, Args &&... args) {
static_assert(std::is_base_of_v<resource_loader<Loader, Resource>, Loader>, "Invalid loader type");
resource_handle<Resource> resource{};
if(auto it = resources.find(id); it == resources.cend()) {
if(auto instance = Loader{}.get(std::forward<Args>(args)...); instance) {
resources[id] = instance;
resource = std::move(instance);
if(auto handle = temp<Loader>(std::forward<Args>(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<typename Loader, typename... Args>
[[nodiscard]] resource_handle<Resource> temp(Args &&... args) const {
return { Loader{}.get(std::forward<Args>(args)...) };
return Loader{}.get(std::forward<Args>(args)...);
}
/**
@@ -166,8 +163,11 @@ struct resource_cache {
* @return A handle for the given resource.
*/
[[nodiscard]] resource_handle<Resource> 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, id_type>) {
func(curr->first);
} else if constexpr(std::is_invocable_v<Func, resource_handle<Resource>>) {
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<id_type, std::shared_ptr<Resource>> resources;
std::unordered_map<id_type, resource_handle<Resource>> resources;
};

View File

@@ -10,7 +10,7 @@ struct resource_cache;
template<typename>
class resource_handle;
struct resource_handle;
template<typename, typename>

View File

@@ -24,18 +24,18 @@ namespace entt {
* @tparam Resource Type of resource managed by a handle.
*/
template<typename Resource>
class resource_handle {
/*! @brief Resource handles are friends of their caches. */
friend struct resource_cache<Resource>;
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<Resource> res) ENTT_NOEXCEPT
: resource{std::move(res)}
{}
public:
/*! @brief Default constructor. */
resource_handle() ENTT_NOEXCEPT = default;
/**
* @brief Gets a reference to the managed resource.
*

View File

@@ -2,8 +2,8 @@
#define ENTT_RESOURCE_LOADER_HPP
#include <memory>
#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.<br/>
* a handle to the resource just created.<br/>
* As an example:
*
* @code{.cpp}
* struct my_resource {};
*
* struct my_loader: entt::resource_loader<my_loader, my_resource> {
* std::shared_ptr<my_resource> load(int) const {
* resource_handle<my_resource> load(int value) const {
* // use the integer value somehow
* return std::make_shared<my_resource>();
* }
@@ -53,7 +53,7 @@ class resource_loader {
* @return The resource just loaded or an empty pointer in case of errors.
*/
template<typename... Args>
[[nodiscard]] std::shared_ptr<Resource> get(Args &&... args) const {
[[nodiscard]] resource_handle<Resource> get(Args &&... args) const {
return static_cast<const Loader *>(this)->load(std::forward<Args>(args)...);
}
};