Skip to content
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

[core] operator== hook #1455

Open
wants to merge 23 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
987 changes: 885 additions & 102 deletions distr/flecs.c

Large diffs are not rendered by default.

314 changes: 280 additions & 34 deletions distr/flecs.h

Large diffs are not rendered by default.

63 changes: 44 additions & 19 deletions include/flecs.h
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,18 @@ typedef void (*ecs_move_t)(
int32_t count,
const ecs_type_info_t *type_info);

/** Compare hook to compare component instances */
typedef int (*ecs_cmp_t)(
const void *a_ptr,
const void *b_ptr,
const ecs_type_info_t *type_info);

/** Equals operator hook */
typedef bool (*ecs_equals_t)(
const void *a_ptr,
const void *b_ptr,
const ecs_type_info_t *type_info);

/** Destructor function for poly objects. */
typedef void (*flecs_poly_dtor_t)(
ecs_poly_t *poly);
Expand Down Expand Up @@ -863,38 +875,44 @@ struct ecs_observer_t {
*/

/* Flags that can be used to check which hooks a type has set */
#define ECS_TYPE_HOOK_CTOR (1 << 0)
#define ECS_TYPE_HOOK_DTOR (1 << 1)
#define ECS_TYPE_HOOK_COPY (1 << 2)
#define ECS_TYPE_HOOK_MOVE (1 << 3)
#define ECS_TYPE_HOOK_COPY_CTOR (1 << 4)
#define ECS_TYPE_HOOK_MOVE_CTOR (1 << 5)
#define ECS_TYPE_HOOK_CTOR_MOVE_DTOR (1 << 6)
#define ECS_TYPE_HOOK_MOVE_DTOR (1 << 7)
#define ECS_TYPE_HOOK_CTOR ECS_CAST(ecs_flags32_t, 1 << 0)
#define ECS_TYPE_HOOK_DTOR ECS_CAST(ecs_flags32_t, 1 << 1)
#define ECS_TYPE_HOOK_COPY ECS_CAST(ecs_flags32_t, 1 << 2)
#define ECS_TYPE_HOOK_MOVE ECS_CAST(ecs_flags32_t, 1 << 3)
#define ECS_TYPE_HOOK_COPY_CTOR ECS_CAST(ecs_flags32_t, 1 << 4)
#define ECS_TYPE_HOOK_MOVE_CTOR ECS_CAST(ecs_flags32_t, 1 << 5)
#define ECS_TYPE_HOOK_CTOR_MOVE_DTOR ECS_CAST(ecs_flags32_t, 1 << 6)
#define ECS_TYPE_HOOK_MOVE_DTOR ECS_CAST(ecs_flags32_t, 1 << 7)
#define ECS_TYPE_HOOK_CMP ECS_CAST(ecs_flags32_t, 1 << 8)
#define ECS_TYPE_HOOK_EQUALS ECS_CAST(ecs_flags32_t, 1 << 9)


/* Flags that can be used to set/check which hooks of a type are invalid */
#define ECS_TYPE_HOOK_CTOR_ILLEGAL (1 << 8)
#define ECS_TYPE_HOOK_DTOR_ILLEGAL (1 << 9)
#define ECS_TYPE_HOOK_COPY_ILLEGAL (1 << 10)
#define ECS_TYPE_HOOK_MOVE_ILLEGAL (1 << 11)
#define ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL (1 << 12)
#define ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL (1 << 13)
#define ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL (1 << 14)
#define ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL (1 << 15)
#define ECS_TYPE_HOOK_CTOR_ILLEGAL ECS_CAST(ecs_flags32_t, 1 << 10)
#define ECS_TYPE_HOOK_DTOR_ILLEGAL ECS_CAST(ecs_flags32_t, 1 << 12)
#define ECS_TYPE_HOOK_COPY_ILLEGAL ECS_CAST(ecs_flags32_t, 1 << 13)
#define ECS_TYPE_HOOK_MOVE_ILLEGAL ECS_CAST(ecs_flags32_t, 1 << 14)
#define ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL ECS_CAST(ecs_flags32_t, 1 << 15)
#define ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL ECS_CAST(ecs_flags32_t, 1 << 16)
#define ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL ECS_CAST(ecs_flags32_t, 1 << 17)
#define ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL ECS_CAST(ecs_flags32_t, 1 << 18)
#define ECS_TYPE_HOOK_CMP_ILLEGAL ECS_CAST(ecs_flags32_t, 1 << 19)
#define ECS_TYPE_HOOK_EQUALS_ILLEGAL ECS_CAST(ecs_flags32_t, 1 << 20)


/* All valid hook flags */
#define ECS_TYPE_HOOKS (ECS_TYPE_HOOK_CTOR|ECS_TYPE_HOOK_DTOR|\
ECS_TYPE_HOOK_COPY|ECS_TYPE_HOOK_MOVE|ECS_TYPE_HOOK_COPY_CTOR|\
ECS_TYPE_HOOK_MOVE_CTOR|ECS_TYPE_HOOK_CTOR_MOVE_DTOR|\
ECS_TYPE_HOOK_MOVE_DTOR)
ECS_TYPE_HOOK_MOVE_DTOR|ECS_TYPE_HOOK_CMP|ECS_TYPE_HOOK_EQUALS)

/* All invalid hook flags */
#define ECS_TYPE_HOOKS_ILLEGAL (ECS_TYPE_HOOK_CTOR_ILLEGAL|\
ECS_TYPE_HOOK_DTOR_ILLEGAL|ECS_TYPE_HOOK_COPY_ILLEGAL|\
ECS_TYPE_HOOK_MOVE_ILLEGAL|ECS_TYPE_HOOK_COPY_CTOR_ILLEGAL|\
ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL|ECS_TYPE_HOOK_CTOR_MOVE_DTOR_ILLEGAL|\
ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL)

ECS_TYPE_HOOK_MOVE_DTOR_ILLEGAL|ECS_TYPE_HOOK_CMP_ILLEGAL|\
ECS_TYPE_HOOK_EQUALS_ILLEGAL)
struct ecs_type_hooks_t {
ecs_xtor_t ctor; /**< ctor */
ecs_xtor_t dtor; /**< dtor */
Expand All @@ -919,11 +937,18 @@ struct ecs_type_hooks_t {
* not set explicitly it will be derived from other callbacks. */
ecs_move_t move_dtor;

/** Compare hook */
ecs_cmp_t cmp;

/** Equals hook */
ecs_equals_t equals;

/** Hook flags.
* Indicates which hooks are set for the type, and which hooks are illegal.
* When an ILLEGAL flag is set when calling ecs_set_hooks() a hook callback
* will be set that panics when called. */
ecs_flags32_t flags;


/** Callback that is invoked when an instance of a component is added. This
* callback is invoked before triggers are invoked. */
Expand Down
100 changes: 85 additions & 15 deletions include/flecs/addons/cpp/component.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ void register_lifecycle_actions(
cl.ctor_move_dtor = ctor_move_dtor<T>(cl.flags);
cl.move_dtor = move_dtor<T>(cl.flags);

cl.flags &= ECS_TYPE_HOOKS_ILLEGAL;
ecs_set_hooks_id(world, component, &cl);

if (cl.flags & (ECS_TYPE_HOOK_MOVE_ILLEGAL|ECS_TYPE_HOOK_MOVE_CTOR_ILLEGAL))
Expand Down Expand Up @@ -351,6 +352,50 @@ struct type<T, if_t< is_pair<T>::value >>
struct untyped_component : entity {
using entity::entity;

protected:

flecs::type_hooks_t get_hooks() const {
const flecs::type_hooks_t* h = ecs_get_hooks_id(world_, id_);
if (h) {
return *h;
} else {
return {};
}
}

void set_hooks(flecs::type_hooks_t &h) {
h.flags &= ECS_TYPE_HOOKS_ILLEGAL;
ecs_set_hooks_id(world_, id_, &h);
}

public:

untyped_component& op_compare(
ecs_cmp_t compare_callback)
{
ecs_assert(compare_callback, ECS_INVALID_PARAMETER, NULL);
flecs::type_hooks_t h = get_hooks();
h.cmp = compare_callback;
h.flags &= ~ECS_TYPE_HOOK_CMP_ILLEGAL;
if(h.flags & ECS_TYPE_HOOK_EQUALS_ILLEGAL) {
h.flags &= ~ECS_TYPE_HOOK_EQUALS_ILLEGAL;
h.equals = NULL;
}
set_hooks(h);
return *this;
}

untyped_component& op_equals(
ecs_equals_t equals_callback)
{
ecs_assert(equals_callback, ECS_INVALID_PARAMETER, NULL);
flecs::type_hooks_t h = get_hooks();
h.equals = equals_callback;
h.flags &= ~ECS_TYPE_HOOK_EQUALS_ILLEGAL;
set_hooks(h);
return *this;
}

# ifdef FLECS_META
# include "mixins/meta/untyped_component.inl"
# endif
Expand Down Expand Up @@ -448,14 +493,14 @@ struct component : untyped_component {
template <typename Func>
component<T>& on_add(Func&& func) {
using Delegate = typename _::each_delegate<typename std::decay<Func>::type, T>;
flecs::type_hooks_t h = get_hooks();
flecs::type_hooks_t h = this->get_hooks();
ecs_assert(h.on_add == nullptr, ECS_INVALID_OPERATION,
"on_add hook is already set");
BindingCtx *ctx = get_binding_ctx(h);
h.on_add = Delegate::run_add;
ctx->on_add = FLECS_NEW(Delegate)(FLECS_FWD(func));
ctx->free_on_add = _::free_obj<Delegate>;
ecs_set_hooks_id(world_, id_, &h);
set_hooks(h);
return *this;
}

Expand All @@ -464,14 +509,14 @@ struct component : untyped_component {
component<T>& on_remove(Func&& func) {
using Delegate = typename _::each_delegate<
typename std::decay<Func>::type, T>;
flecs::type_hooks_t h = get_hooks();
flecs::type_hooks_t h = this->get_hooks();
ecs_assert(h.on_remove == nullptr, ECS_INVALID_OPERATION,
"on_remove hook is already set");
BindingCtx *ctx = get_binding_ctx(h);
h.on_remove = Delegate::run_remove;
ctx->on_remove = FLECS_NEW(Delegate)(FLECS_FWD(func));
ctx->free_on_remove = _::free_obj<Delegate>;
ecs_set_hooks_id(world_, id_, &h);
set_hooks(h);
return *this;
}

Expand All @@ -480,14 +525,48 @@ struct component : untyped_component {
component<T>& on_set(Func&& func) {
using Delegate = typename _::each_delegate<
typename std::decay<Func>::type, T>;
flecs::type_hooks_t h = get_hooks();
flecs::type_hooks_t h = this->get_hooks();
ecs_assert(h.on_set == nullptr, ECS_INVALID_OPERATION,
"on_set hook is already set");
BindingCtx *ctx = get_binding_ctx(h);
h.on_set = Delegate::run_set;
ctx->on_set = FLECS_NEW(Delegate)(FLECS_FWD(func));
ctx->free_on_set = _::free_obj<Delegate>;
ecs_set_hooks_id(world_, id_, &h);
set_hooks(h);
return *this;
}

/** Register operator compare hook. */
using untyped_component::op_compare;
component<T>& op_compare() {
ecs_cmp_t handler = _::compare<T>();
ecs_assert(handler != NULL, ECS_INVALID_OPERATION,
"Type does not have operator> or operator< const or is inaccessible");
op_compare(handler);
return *this;
}

/** Type safe variant of compare op function */
using cmp_hook = int(*)(const T* a, const T* b, const ecs_type_info_t *ti);
component<T>& op_compare(cmp_hook callback) {
op_compare(reinterpret_cast<ecs_cmp_t>(callback));
return *this;
}

/** Register operator equals hook. */
using untyped_component::op_equals;
component<T>& op_equals() {
ecs_equals_t handler = _::equals<T>();
ecs_assert(handler != NULL, ECS_INVALID_OPERATION,
"Type does not have operator== const or is inaccessible");
op_equals(handler);
return *this;
}

/** Type safe variant of equals op function */
using equals_hook = bool(*)(const T* a, const T* b, const ecs_type_info_t *ti);
component<T>& op_equals(equals_hook callback) {
op_equals(reinterpret_cast<ecs_equals_t>(callback));
return *this;
}

Expand All @@ -507,15 +586,6 @@ struct component : untyped_component {
}
return result;
}

flecs::type_hooks_t get_hooks() {
const flecs::type_hooks_t* h = ecs_get_hooks_id(world_, id_);
if (h) {
return *h;
} else {
return {};
}
}
};

/** Get id currently assigned to component. If no world has registered the
Expand Down
Loading
Loading