Skip to content

feat: replaced unordered_maps with optimized id_map #169

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

Merged
merged 2 commits into from
Apr 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
48 changes: 48 additions & 0 deletions ecsact/entt/detail/id_map.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#pragma once

#include <type_traits>
#include <concepts>
#include <array>

namespace ecsact::entt::detail {

/**
*
*/
template<typename KeyT, typename ValueT, KeyT MinKeyValue, KeyT MaxKeyValue>
class id_map {
public:
using key_type = KeyT;
using value_type = ValueT;
using underlying_key_type = std::underlying_type_t<key_type>;

static constexpr auto min_key_value() -> underlying_key_type {
return static_cast<underlying_key_type>(MinKeyValue);
}

static constexpr auto max_key_value() -> underlying_key_type {
return static_cast<underlying_key_type>(MaxKeyValue);
}

static_assert(
max_key_value() > min_key_value(),
"id_map MaxKeyValue must be > MinKeyValue"
);

std::array<ValueT, max_key_value() - min_key_value()> _data;

constexpr auto key_index(const key_type& key) const -> size_t {
auto index = static_cast<size_t>(key);
index -= static_cast<size_t>(min_key_value());
return index;
}

constexpr auto operator[](const key_type& key) -> value_type& {
return _data[key_index(key)];
}

constexpr auto operator[](const key_type& key) const -> const value_type& {
return _data[key_index(key)];
}
};
} // namespace ecsact::entt::detail
2 changes: 1 addition & 1 deletion rt_entt_codegen/core/execution_options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ inline auto print_static_maps(

block(
ctx,
"static const auto execution_update_fns="
"static const auto execution_update_fns ="
"std::unordered_map<ecsact_component_like_id, "
"decltype(&ecsact_update_component)>\n",
[&] {
Expand Down
21 changes: 11 additions & 10 deletions rt_entt_codegen/core/system_provider/system_ctx_functions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ using ecsact::cc_lang_support::cpp_identifier;
using ecsact::cpp_codegen_plugin_util::block;
using ecsact::meta::decl_full_name;
using ecsact::rt_entt_codegen::util::is_transient_component;
using ecsact::rt_entt_codegen::util::make_id_map_type;

auto ecsact::rt_entt_codegen::core::provider::context_action_impl(
ecsact::codegen_plugin_context& ctx,
Expand Down Expand Up @@ -225,9 +226,9 @@ auto ecsact::rt_entt_codegen::core::provider::context_get_impl(
ctx.write("static const auto get_fns = []()\n");

block(ctx, "", [&] {
ctx.write(
"auto result = std::unordered_map<ecsact_component_like_id, "
"get_fn_t>{};\n"
ctx.writef(
"auto result = {}{{}};\n",
make_id_map_type<ecsact_component_like_id>("get_fn_t")
);
for(const auto comp_id : details.readable_comps) {
auto type_name = cpp_identifier(decl_full_name(comp_id));
Expand All @@ -245,8 +246,8 @@ auto ecsact::rt_entt_codegen::core::provider::context_get_impl(
ctx.write("();\n");

ctx.write(
"get_fns.at("
"component_id)(this, component_id, out_component_data, nullptr, *view"
"get_fns[component_id]"
"(this, component_id, out_component_data, nullptr, *view"
");\n"
);
}
Expand Down Expand Up @@ -295,9 +296,9 @@ auto ecsact::rt_entt_codegen::core::provider::context_update_impl(
ctx.write("static const auto update_fns = []()\n");

block(ctx, "", [&] {
ctx.write(
"auto result = std::unordered_map<ecsact_component_like_id, "
"update_fn_t>{};\n"
ctx.writef(
"auto result = {}{{}};\n",
make_id_map_type<ecsact_component_like_id>("update_fn_t")
);
for(const auto comp_id : details.writable_comps) {
auto type_name = cpp_identifier(decl_full_name(comp_id));
Expand All @@ -315,8 +316,8 @@ auto ecsact::rt_entt_codegen::core::provider::context_update_impl(
ctx.write("();\n");

ctx.write(
"update_fns.at(component_id)(this, component_id, component_data, nullptr, "
"*view);\n"
"update_fns[component_id]"
"(this, component_id, component_data, nullptr, *view);\n"
);
}

Expand Down
1 change: 1 addition & 0 deletions rt_entt_codegen/rt_entt_codegen.cc
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ void ecsact_codegen_plugin(
inc_header(ctx, "ecsact/entt/wrapper/core.hh");
inc_header(ctx, "ecsact/entt/wrapper/dynamic.hh");
inc_header(ctx, "ecsact/entt/error_check.hh");
inc_header(ctx, "ecsact/entt/detail/id_map.hh");
inc_header(ctx, "xxhash.h");
ctx.write("#include <execution>\n");

Expand Down
1 change: 1 addition & 0 deletions rt_entt_codegen/shared/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ cc_library(

cc_library(
name = "util",
srcs = ["util.cc"],
hdrs = ["util.hh"],
copts = copts,
defines = ["ECSACT_META_API_LOAD_AT_RUNTIME"],
Expand Down
107 changes: 107 additions & 0 deletions rt_entt_codegen/shared/util.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#include "rt_entt_codegen/shared/util.hh"

#include <unordered_set>
#include <algorithm>
#include "ecsact/runtime/meta.hh"

static auto collect_pkg_deps(
ecsact_package_id pkg_id,
std::unordered_set<ecsact_package_id>& out_set
) -> void {
auto deps = ecsact::meta::get_dependencies(pkg_id);
for(auto dep : deps) {
if(out_set.contains(dep)) {
continue;
}
out_set.insert(dep);
collect_pkg_deps(dep, out_set);
}
}

static auto all_pkg_ids() -> std::unordered_set<ecsact_package_id> {
auto ids = std::unordered_set<ecsact_package_id>{};
auto main_pkg_id = ecsact::meta::main_package();
ids.insert(*main_pkg_id);
collect_pkg_deps(*main_pkg_id, ids);
return ids;
}

template<typename ID>
constexpr auto default_id_min() -> ID {
return static_cast<ID>(std::numeric_limits<std::underlying_type_t<ID>>::max()
);
}

template<typename ID>
constexpr auto default_id_max() -> ID {
return static_cast<ID>(std::numeric_limits<std::underlying_type_t<ID>>::min()
);
}

template<>
auto ecsact::rt_entt_codegen::util::ecsact_id_min_max<ecsact_component_id>()
-> std::tuple<ecsact_component_id, ecsact_component_id> {
auto min = default_id_min<ecsact_component_id>();
auto max = default_id_max<ecsact_component_id>();
for(auto pkg_id : all_pkg_ids()) {
auto comp_ids = ecsact::meta::get_component_ids(pkg_id);
for(auto comp_id : comp_ids) {
if(static_cast<int>(comp_id) < static_cast<int>(min)) {
min = comp_id;
}

if(static_cast<int>(comp_id) > static_cast<int>(max)) {
max = comp_id;
}
}
}

if(min == default_id_min<ecsact_component_id>()) {
return {};
}

return {min, max};
}

template<>
auto ecsact::rt_entt_codegen::util::ecsact_id_min_max<ecsact_transient_id>()
-> std::tuple<ecsact_transient_id, ecsact_transient_id> {
auto min = default_id_min<ecsact_transient_id>();
auto max = default_id_max<ecsact_transient_id>();
for(auto pkg_id : all_pkg_ids()) {
auto trans_ids = ecsact::meta::get_transient_ids(pkg_id);
for(auto trans_id : trans_ids) {
if(static_cast<int>(trans_id) < static_cast<int>(min)) {
min = trans_id;
}

if(static_cast<int>(trans_id) > static_cast<int>(max)) {
max = trans_id;
}
}
}

if(min == default_id_min<ecsact_transient_id>()) {
return {};
}

return {min, max};
}

template<>
auto ecsact::rt_entt_codegen::util::ecsact_id_min_max<ecsact_component_like_id>(
) -> std::tuple<ecsact_component_like_id, ecsact_component_like_id> {
auto [transient_min, transient_max] =
ecsact_id_min_max<ecsact_transient_id>();
auto [component_min, component_max] =
ecsact_id_min_max<ecsact_component_id>();

return {
static_cast<ecsact_component_like_id>(
std::min(static_cast<int>(transient_min), static_cast<int>(component_min))
),
static_cast<ecsact_component_like_id>(
std::max(static_cast<int>(transient_max), static_cast<int>(component_max))
)
};
}
45 changes: 45 additions & 0 deletions rt_entt_codegen/shared/util.hh
Original file line number Diff line number Diff line change
Expand Up @@ -326,4 +326,49 @@ auto make_view( //
ctx.write(");\n");
}

template<typename ID>
constexpr auto ecsact_id_type_to_string() -> std::string_view;

template<>
constexpr auto ecsact_id_type_to_string<ecsact_component_like_id>()
-> std::string_view {
return "ecsact_component_like_id";
}

/**
* Get the smallest and largest ID by number.
* Used when creating and id_map
*/
template<typename ID>
auto ecsact_id_min_max() -> std::tuple<ID, ID>;

template<>
auto ecsact_id_min_max<ecsact_component_id>()
-> std::tuple<ecsact_component_id, ecsact_component_id>;

template<>
auto ecsact_id_min_max<ecsact_transient_id>()
-> std::tuple<ecsact_transient_id, ecsact_transient_id>;

template<>
auto ecsact_id_min_max<ecsact_component_like_id>()
-> std::tuple<ecsact_component_like_id, ecsact_component_like_id>;

/**
* Helper function for printing an ecsact::entt::detail::id_map in codegen
*/
template<typename ID>
auto make_id_map_type(std::string value_type) -> std::string {
auto id_type_str = ecsact_id_type_to_string<ID>();
auto [min, max] = ecsact_id_min_max<ID>();
return std::format(
"::ecsact::entt::detail::id_map<{0}, {1}, "
"static_cast<{0}>({2}), "
"static_cast<{0}>({3})>",
id_type_str,
value_type,
static_cast<int>(min),
static_cast<int>(max)
);
}
} // namespace ecsact::rt_entt_codegen::util