-
-
Notifications
You must be signed in to change notification settings - Fork 897
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added user-defined context variable guard #800
base: v3.8.x
Are you sure you want to change the base?
Added user-defined context variable guard #800
Conversation
Unfortunately, this PR is no longer valid (if we consider branch I've no problem merging or reproducing the intent of this PR on a branch, adapting it and then porting it to |
Actually, another option could be to turn the context type in a template parameter. |
@skypjack I actually had to comment out the
section as include ordering was messing with it - some files/libraries would get to config via various utilities and I was struggling to always keep my own header/define before it. I think there's probably a better solution on the cards, but I'd definitely like some way to inject a custom lock either way. A template param could be nice - means the user can typedef entt::registry and use it in their code without worrying about include order shenanigans. I would just be worried about for example having that type replace the entire map and machinery and force the user to re-implement it - I want exactly what the context vars do, just with a lil' interception ;) |
A little late to the party, but I think the best way to solve this is by having a mixin on top of the context. Here's the best I could get so far. The idea is that you create a "locked context" on each thread and use it instead of the regular context. This context would be lock the given mutex on each call to entt::registry registry;
my::mutex ctx_mutex;
entt::locked_context ctx{registry.ctx(), ctx_mutex};
// use ctx just like you would before |
Dang. Completely forgot about this one! 😲 template<typename Entity, typename Allocator>
class basic_registry; Vs: template<typename Entity, typename Context, typename Allocator>
class basic_registry; The registry doesn't use it after all, therefore it doesn't really care about the API or whatever. |
Makes sense to me and looks better than the mixin solution. I'm assuming if this happens, the default context type would be the one we have now, right? |
Yeah, sure thing. We can also make it a trait actually 🤔 not sure it's worth it though, but I don't like much to dirty the class declaration. |
If this becomes a trait, I think the trait should be passed to the registry as a template parameter. This way you can pick a custom context for every registry, which might be useful for "blueprint registries" (ie. having only blueprint entities). The code would then look something like the following: namespace entt {
struct default_registry_traits {
using entity_type = entity;
template <typename RegistryAlloc>
using context_type = default_context<RegistryAlloc>;
};
template <
typename Traits, // it's a trait now
typename Allocator = std::allocator<typename Traits::entity_type>>
class basic_registry;
}
struct my_traits : entt::default_registry_traits {
using entity_type = uint64_t;
}; The reason why the
struct my_traits : entt::default_registry_traits {
using entity_type = uint64_t;
// oops, using the allocator for entt::entity...
}; |
The other option is to use something on the line of custom data in meta. That is: auto &elem = registry.ctx<my_context_type>();
elem.emplace<my_type>(42, 'c'); Where the current type is also the default type. This means that |
I keep saying it again and again, but I like this idea better than the traits. The only thing worth to discuss is the lifetime of the context. Given that now the context type will be dynamic internally, there could be an option to change it at runtime, similar to custom data in meta (eg. the context is initially an If one truly needs the feature, it can easily be emulated by making the context represent several states within the type: struct context final
{
// represent states in one type, instead of having separate types of contexts
bool is_state_1() const;
bool is_state_2() const;
// ...
private:
// internal data
}; However, this means the only way to set the context value (not modify, just set) is when constructing the registry. To me, the simplest way to do this is to have a |
Yes and no actually. Imagine the following: template<typename Type = DefaultType>
auto & ctx() {
ENTT_ASSERT(context_pair.second == nullptr || context_pair.first == type_id<Type>(), "Mismatch");
if(context_pair.second == nullptr) {
context_pair.first = type_id<Type>();
context_pair.second = std::make_shared<Type>();
}
return *static_pointer_cast<Type>(context_pair.second);
} Where |
I have a slightly different idea. I'm guessing that Having said that, I think it's best to drop the pair for a Here's the code. |
This is REALLY smart. I'd probably use a class with an extra member rather than the same |
Ah! You know why this could be tricky maybe? Because of uses-allocator construction and because we should use the registry allocator to instantiate the context. 🤔 |
Thanks, good to hear that. 🙂
That's fine by me. I only did it like this because it's shorter. Also probably worth mentioning, but I just remembered that EDIT
We can always store a pointer to the allocator in the deleter and use it to destroy/deallocate the context. The type of allocator is already known so there is no much (if any) type-erasure needed for this. |
Yeah, I'm trying to figure out if we can make |
It's probably better to leave |
Fitting with the "don't pay for what you don't use" concept, I wanted to have an optional way of injecting some kind of lock/guard around context variables in the registry.
I let the user define how the lock is created since, for me, I use a fiber mutex rather than std::mutex, so I need to be able to define it myself. I'm using the lock in the 'leaf nodes' of the function calls since I can't support recursive mutexes and the end result is the same.
Addresses #799
(Let me know if you want a PR against another branch; maybe main?)