Skip to content

Commit f746aec

Browse files
authored
feat: replaced unordered_maps with optimized id_map (#169)
1 parent d28fe63 commit f746aec

File tree

7 files changed

+214
-11
lines changed

7 files changed

+214
-11
lines changed

ecsact/entt/detail/id_map.hh

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#pragma once
2+
3+
#include <type_traits>
4+
#include <concepts>
5+
#include <array>
6+
7+
namespace ecsact::entt::detail {
8+
9+
/**
10+
*
11+
*/
12+
template<typename KeyT, typename ValueT, KeyT MinKeyValue, KeyT MaxKeyValue>
13+
class id_map {
14+
public:
15+
using key_type = KeyT;
16+
using value_type = ValueT;
17+
using underlying_key_type = std::underlying_type_t<key_type>;
18+
19+
static constexpr auto min_key_value() -> underlying_key_type {
20+
return static_cast<underlying_key_type>(MinKeyValue);
21+
}
22+
23+
static constexpr auto max_key_value() -> underlying_key_type {
24+
return static_cast<underlying_key_type>(MaxKeyValue);
25+
}
26+
27+
static_assert(
28+
max_key_value() > min_key_value(),
29+
"id_map MaxKeyValue must be > MinKeyValue"
30+
);
31+
32+
std::array<ValueT, max_key_value() - min_key_value()> _data;
33+
34+
constexpr auto key_index(const key_type& key) const -> size_t {
35+
auto index = static_cast<size_t>(key);
36+
index -= static_cast<size_t>(min_key_value());
37+
return index;
38+
}
39+
40+
constexpr auto operator[](const key_type& key) -> value_type& {
41+
return _data[key_index(key)];
42+
}
43+
44+
constexpr auto operator[](const key_type& key) const -> const value_type& {
45+
return _data[key_index(key)];
46+
}
47+
};
48+
} // namespace ecsact::entt::detail

rt_entt_codegen/core/execution_options.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ inline auto print_static_maps(
3737

3838
block(
3939
ctx,
40-
"static const auto execution_update_fns="
40+
"static const auto execution_update_fns ="
4141
"std::unordered_map<ecsact_component_like_id, "
4242
"decltype(&ecsact_update_component)>\n",
4343
[&] {

rt_entt_codegen/core/system_provider/system_ctx_functions.cc

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ using ecsact::cc_lang_support::cpp_identifier;
99
using ecsact::cpp_codegen_plugin_util::block;
1010
using ecsact::meta::decl_full_name;
1111
using ecsact::rt_entt_codegen::util::is_transient_component;
12+
using ecsact::rt_entt_codegen::util::make_id_map_type;
1213

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

227228
block(ctx, "", [&] {
228-
ctx.write(
229-
"auto result = std::unordered_map<ecsact_component_like_id, "
230-
"get_fn_t>{};\n"
229+
ctx.writef(
230+
"auto result = {}{{}};\n",
231+
make_id_map_type<ecsact_component_like_id>("get_fn_t")
231232
);
232233
for(const auto comp_id : details.readable_comps) {
233234
auto type_name = cpp_identifier(decl_full_name(comp_id));
@@ -245,8 +246,8 @@ auto ecsact::rt_entt_codegen::core::provider::context_get_impl(
245246
ctx.write("();\n");
246247

247248
ctx.write(
248-
"get_fns.at("
249-
"component_id)(this, component_id, out_component_data, nullptr, *view"
249+
"get_fns[component_id]"
250+
"(this, component_id, out_component_data, nullptr, *view"
250251
");\n"
251252
);
252253
}
@@ -295,9 +296,9 @@ auto ecsact::rt_entt_codegen::core::provider::context_update_impl(
295296
ctx.write("static const auto update_fns = []()\n");
296297

297298
block(ctx, "", [&] {
298-
ctx.write(
299-
"auto result = std::unordered_map<ecsact_component_like_id, "
300-
"update_fn_t>{};\n"
299+
ctx.writef(
300+
"auto result = {}{{}};\n",
301+
make_id_map_type<ecsact_component_like_id>("update_fn_t")
301302
);
302303
for(const auto comp_id : details.writable_comps) {
303304
auto type_name = cpp_identifier(decl_full_name(comp_id));
@@ -315,8 +316,8 @@ auto ecsact::rt_entt_codegen::core::provider::context_update_impl(
315316
ctx.write("();\n");
316317

317318
ctx.write(
318-
"update_fns.at(component_id)(this, component_id, component_data, nullptr, "
319-
"*view);\n"
319+
"update_fns[component_id]"
320+
"(this, component_id, component_data, nullptr, *view);\n"
320321
);
321322
}
322323

rt_entt_codegen/rt_entt_codegen.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ void ecsact_codegen_plugin(
138138
inc_header(ctx, "ecsact/entt/wrapper/core.hh");
139139
inc_header(ctx, "ecsact/entt/wrapper/dynamic.hh");
140140
inc_header(ctx, "ecsact/entt/error_check.hh");
141+
inc_header(ctx, "ecsact/entt/detail/id_map.hh");
141142
inc_header(ctx, "xxhash.h");
142143
ctx.write("#include <execution>\n");
143144

rt_entt_codegen/shared/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ cc_library(
3131

3232
cc_library(
3333
name = "util",
34+
srcs = ["util.cc"],
3435
hdrs = ["util.hh"],
3536
copts = copts,
3637
defines = ["ECSACT_META_API_LOAD_AT_RUNTIME"],

rt_entt_codegen/shared/util.cc

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#include "rt_entt_codegen/shared/util.hh"
2+
3+
#include <unordered_set>
4+
#include <algorithm>
5+
#include "ecsact/runtime/meta.hh"
6+
7+
static auto collect_pkg_deps(
8+
ecsact_package_id pkg_id,
9+
std::unordered_set<ecsact_package_id>& out_set
10+
) -> void {
11+
auto deps = ecsact::meta::get_dependencies(pkg_id);
12+
for(auto dep : deps) {
13+
if(out_set.contains(dep)) {
14+
continue;
15+
}
16+
out_set.insert(dep);
17+
collect_pkg_deps(dep, out_set);
18+
}
19+
}
20+
21+
static auto all_pkg_ids() -> std::unordered_set<ecsact_package_id> {
22+
auto ids = std::unordered_set<ecsact_package_id>{};
23+
auto main_pkg_id = ecsact::meta::main_package();
24+
ids.insert(*main_pkg_id);
25+
collect_pkg_deps(*main_pkg_id, ids);
26+
return ids;
27+
}
28+
29+
template<typename ID>
30+
constexpr auto default_id_min() -> ID {
31+
return static_cast<ID>(std::numeric_limits<std::underlying_type_t<ID>>::max()
32+
);
33+
}
34+
35+
template<typename ID>
36+
constexpr auto default_id_max() -> ID {
37+
return static_cast<ID>(std::numeric_limits<std::underlying_type_t<ID>>::min()
38+
);
39+
}
40+
41+
template<>
42+
auto ecsact::rt_entt_codegen::util::ecsact_id_min_max<ecsact_component_id>()
43+
-> std::tuple<ecsact_component_id, ecsact_component_id> {
44+
auto min = default_id_min<ecsact_component_id>();
45+
auto max = default_id_max<ecsact_component_id>();
46+
for(auto pkg_id : all_pkg_ids()) {
47+
auto comp_ids = ecsact::meta::get_component_ids(pkg_id);
48+
for(auto comp_id : comp_ids) {
49+
if(static_cast<int>(comp_id) < static_cast<int>(min)) {
50+
min = comp_id;
51+
}
52+
53+
if(static_cast<int>(comp_id) > static_cast<int>(max)) {
54+
max = comp_id;
55+
}
56+
}
57+
}
58+
59+
if(min == default_id_min<ecsact_component_id>()) {
60+
return {};
61+
}
62+
63+
return {min, max};
64+
}
65+
66+
template<>
67+
auto ecsact::rt_entt_codegen::util::ecsact_id_min_max<ecsact_transient_id>()
68+
-> std::tuple<ecsact_transient_id, ecsact_transient_id> {
69+
auto min = default_id_min<ecsact_transient_id>();
70+
auto max = default_id_max<ecsact_transient_id>();
71+
for(auto pkg_id : all_pkg_ids()) {
72+
auto trans_ids = ecsact::meta::get_transient_ids(pkg_id);
73+
for(auto trans_id : trans_ids) {
74+
if(static_cast<int>(trans_id) < static_cast<int>(min)) {
75+
min = trans_id;
76+
}
77+
78+
if(static_cast<int>(trans_id) > static_cast<int>(max)) {
79+
max = trans_id;
80+
}
81+
}
82+
}
83+
84+
if(min == default_id_min<ecsact_transient_id>()) {
85+
return {};
86+
}
87+
88+
return {min, max};
89+
}
90+
91+
template<>
92+
auto ecsact::rt_entt_codegen::util::ecsact_id_min_max<ecsact_component_like_id>(
93+
) -> std::tuple<ecsact_component_like_id, ecsact_component_like_id> {
94+
auto [transient_min, transient_max] =
95+
ecsact_id_min_max<ecsact_transient_id>();
96+
auto [component_min, component_max] =
97+
ecsact_id_min_max<ecsact_component_id>();
98+
99+
return {
100+
static_cast<ecsact_component_like_id>(
101+
std::min(static_cast<int>(transient_min), static_cast<int>(component_min))
102+
),
103+
static_cast<ecsact_component_like_id>(
104+
std::max(static_cast<int>(transient_max), static_cast<int>(component_max))
105+
)
106+
};
107+
}

rt_entt_codegen/shared/util.hh

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,4 +326,49 @@ auto make_view( //
326326
ctx.write(");\n");
327327
}
328328

329+
template<typename ID>
330+
constexpr auto ecsact_id_type_to_string() -> std::string_view;
331+
332+
template<>
333+
constexpr auto ecsact_id_type_to_string<ecsact_component_like_id>()
334+
-> std::string_view {
335+
return "ecsact_component_like_id";
336+
}
337+
338+
/**
339+
* Get the smallest and largest ID by number.
340+
* Used when creating and id_map
341+
*/
342+
template<typename ID>
343+
auto ecsact_id_min_max() -> std::tuple<ID, ID>;
344+
345+
template<>
346+
auto ecsact_id_min_max<ecsact_component_id>()
347+
-> std::tuple<ecsact_component_id, ecsact_component_id>;
348+
349+
template<>
350+
auto ecsact_id_min_max<ecsact_transient_id>()
351+
-> std::tuple<ecsact_transient_id, ecsact_transient_id>;
352+
353+
template<>
354+
auto ecsact_id_min_max<ecsact_component_like_id>()
355+
-> std::tuple<ecsact_component_like_id, ecsact_component_like_id>;
356+
357+
/**
358+
* Helper function for printing an ecsact::entt::detail::id_map in codegen
359+
*/
360+
template<typename ID>
361+
auto make_id_map_type(std::string value_type) -> std::string {
362+
auto id_type_str = ecsact_id_type_to_string<ID>();
363+
auto [min, max] = ecsact_id_min_max<ID>();
364+
return std::format(
365+
"::ecsact::entt::detail::id_map<{0}, {1}, "
366+
"static_cast<{0}>({2}), "
367+
"static_cast<{0}>({3})>",
368+
id_type_str,
369+
value_type,
370+
static_cast<int>(min),
371+
static_cast<int>(max)
372+
);
373+
}
329374
} // namespace ecsact::rt_entt_codegen::util

0 commit comments

Comments
 (0)