Compare commits

..
500 Commits
Author SHA1 Message Date
skypjack b4e58bdd36 *: updated TODO 2025-11-19 10:10:18 +01:00
skypjack 8375ee0910 update single include file 2025-11-17 09:27:48 +01:00
skypjack 137339f48c build: refine clang-tidy setup for local use 2025-11-15 19:11:57 +01:00
skypjack 713bcd50a3 test: explicit nullptr check 2025-11-15 19:11:54 +01:00
skypjack 03a45d9cca test: clang-tidy friendly tests 2025-11-15 18:51:35 +01:00
skypjack cffbf89d9b test: refine lib tests 2025-11-15 18:50:57 +01:00
skypjack f48d16a6e6 meta: linter friendly extra pointer check 2025-11-15 17:52:29 +01:00
skypjack 4905da2637 test: internal changes to make clang-tidy happy 2025-11-15 16:02:36 +01:00
skypjack 558109bbe1 doc: add OneArc to the EnTT in Action list 2025-11-14 17:30:45 +01:00
skypjack a505d41266 meta: explicit nullptr checks 2025-11-14 17:04:34 +01:00
skypjack 9381900b00 meta: get around bugprone assignment warning 2025-11-14 16:59:14 +01:00
skypjack f6a3b09ec2 dense set: suppress conversion warning 2025-11-14 16:58:25 +01:00
skypjack 51c7533265 meta: use find_member to slightly reduce symbol size 2025-11-14 16:58:10 +01:00
skypjack d502bf18da dense map: avoid implicit conversions 2025-11-14 16:10:50 +01:00
skypjack db263d2ff9 any: reorder ctor warning 2025-11-14 16:10:30 +01:00
skypjack 16fae2d625 doc: cleanup 2025-11-14 15:14:52 +01:00
skypjack 4e3a1a8428 meta: internal changes 2025-11-14 15:14:42 +01:00
skypjack aec8a6588c meta: cleanup 2025-11-13 18:41:31 +01:00
skypjack 3160d991f7 meta: drop unnecessary remove_reference_t 2025-11-13 18:34:45 +01:00
skypjack 7359018880 dense_map: refine constrained_find (perf) 2025-11-13 12:02:36 +01:00
skypjack 17fb301636 dense_set: refine constrained_find (perf) 2025-11-13 12:02:28 +01:00
skypjack 7dac5af05d meta: skip fetch_node if possible 2025-11-12 15:39:59 +01:00
skypjack d15e514f10 meta: allow unsetting flags from meta factory 2025-11-12 10:08:31 +01:00
skypjack fe8320c66f any: plugin-friendly, faster quick check 2025-11-10 14:34:39 +01:00
skypjack 7111549c7c meta:: minor changes 2025-11-10 00:01:54 +01:00
skypjack e8e5f5ee2b dense_[map|set]: internal changes 2025-11-09 23:38:26 +01:00
skypjack 9caaf569e6 config: drop attribute.h, merge it with config.h 2025-11-07 10:21:02 +01:00
skypjack 03bf0f90b4 meta: minor changes 2025-11-06 00:16:15 +01:00
skypjack 5df7142f51 *: move attribute.h to config 2025-11-05 23:47:16 +01:00
skypjack 4d95793123 meta: minor changes 2025-11-05 12:12:10 +01:00
skypjack 0aa503e69e meta: use the right guard 2025-11-04 15:12:17 +01:00
skypjack 02323e814a meta: missing template keyword 2025-11-04 15:10:59 +01:00
skypjack 440fed990d doc: cleanup 2025-11-04 15:08:37 +01:00
skypjack c2dcd7257f meta: deprecate const meta_handle::operator-> 2025-11-04 15:08:24 +01:00
skypjack 716e3257b1 meta: refine meta_any::as_ref 2025-11-04 15:01:39 +01:00
skypjack f781441bcd meta: oops :) 2025-11-04 14:54:37 +01:00
skypjack 3c0aa4d300 meta: minor changes 2025-11-04 14:42:25 +01:00
skypjack a57e1a971d meta: minor changes 2025-11-04 14:19:57 +01:00
skypjack dc8da9e42c meta: minor changes 2025-11-04 14:11:44 +01:00
skypjack 7eeb828980 meta: further refine typed allow_cast 2025-11-04 14:06:53 +01:00
skypjack b0d7490829 meta: replace try_convert to squeeze more perf from allow_cast 2025-11-04 13:34:22 +01:00
skypjack 0d678442a0 cmake: profile prop 2025-11-03 23:37:43 +01:00
skypjack 2dff7c9d55 container: prepare for some optimizations 2025-11-03 18:16:28 +01:00
skypjack 3fc5de2916 doc: meta 2025-11-03 14:32:12 +01:00
skypjack a572671947 doc: meta 2025-11-03 08:30:04 +01:00
skypjack 2a6f769092 any: internal changes 2025-10-31 18:02:53 +01:00
skypjack 6a25c0df84 *: updated TODO 2025-10-31 17:50:13 +01:00
skypjack 72127d699a meta: avoid invoking twice the same function 2025-10-31 16:19:54 +01:00
skypjack b52d0aa133 *: updated TODO 2025-10-31 15:35:09 +01:00
skypjack 5d006fefcc meta: drop redundant (wrong) const 2025-10-31 15:00:48 +01:00
skypjack d7c58d00b4 test: make the linter happy again 2025-10-31 14:44:38 +01:00
skypjack 9198a27c25 meta: avoid resetting nodes on meta_any::emplace if not needed 2025-10-31 14:37:16 +01:00
skypjack 31d5d5ff1c meta: top-level only searches for data and functions 2025-10-31 11:36:26 +01:00
skypjack f3fa359edf natvis: meta 2025-10-30 12:32:22 +01:00
skypjack cba31e00ea meta: as_is -> as_value / as_auto -> as_is (breaking) 2025-10-29 17:40:18 +01:00
skypjack d366a5ed92 meta: as_auto policy 2025-10-28 15:34:45 +01:00
skypjack d92bea4afd test: non-regression tests for meta_type::lookup constness 2025-10-27 00:01:13 +01:00
skypjack bbfd458d2d test: more about overloaded meta functions 2025-10-26 23:51:18 +01:00
skypjack 87a114ccc6 test: more about meta_func 2025-10-26 23:37:43 +01:00
skypjack 6852415ffc test: minor changes 2025-10-26 15:11:04 +01:00
skypjack 15f65bd58e core/meta: minor changes 2025-10-26 13:59:09 +01:00
skypjack 54c7c47e3d .*: updated TODO 2025-10-26 13:58:58 +01:00
skypjack 5e6ccdedc8 meta: not going to drop policy anymore, we can use it safely 2025-10-24 10:19:42 +02:00
skypjack dadf493aca meta: cleanup 2025-10-23 18:39:30 +02:00
skypjack 3e5842a467 meta: try to make the linter happy 2025-10-23 18:32:19 +02:00
skypjack 75ae0a10d0 any: cleanup 2025-10-23 18:19:54 +02:00
skypjack e87a8e4b63 storage: NOLINT odissey :) 2025-10-23 17:58:55 +02:00
skypjack 41282b0ecc entity: reduce number of NOLINT 2025-10-23 17:28:13 +02:00
skypjack 030095f48d .*: updated TODO 2025-10-23 17:27:47 +02:00
skypjack e18061bf86 any: avoid vtable calls to release trivially destructible objects (perf) 2025-10-23 11:58:29 +02:00
Michele Caini 38bcbf41a3 any: discard pointless NOLINT 2025-10-22 23:21:27 +02:00
Michele Caini 602626c840 .*: cleanup TODO 2025-10-22 23:17:03 +02:00
skypjack 41e359502d any: avoid vtable calls to get data (perf) 2025-10-22 17:09:41 +02:00
skypjack 8e64f8accf any: info request to get rid of descriptor 2025-10-22 15:58:15 +02:00
skypjack 0afab946da meta: reduce uses of basic_any<...>::policy() 2025-10-21 15:10:52 +02:00
skypjack 20d77024f7 *: updated TODO 2025-10-21 15:10:23 +02:00
skypjack b1bb9b4b5b test: reduce uses of basic_any<...>::policy() 2025-10-21 15:10:17 +02:00
skypjack 978e003dbc meta: internal changes 2025-10-21 15:09:51 +02:00
skypjack 47c65a20a1 any: clang-tidy docet 2025-10-20 17:20:29 +02:00
skypjack 31d845a5f5 meta: clang-tidy docet 2025-10-20 17:18:26 +02:00
skypjack 03c5661df9 meta: rework internal fake vtable 2025-10-20 15:57:32 +02:00
skypjack 48644e568f meta: cleanup 2025-10-20 15:54:35 +02:00
skypjack 19c0e8029d meta: remove the resolve function from meta_any to reduce the footprint 2025-10-20 15:14:08 +02:00
skypjack 3562bec4a7 meta: reduce internal uses of meta_any::resolve 2025-10-18 23:11:35 +02:00
skypjack e863e4fe54 meta: reduce internal uses of meta_any::resolve 2025-10-18 12:43:39 +02:00
skypjack c5d89597fc meta: avoid using meta_any::resolve when comparing 2025-10-18 12:40:33 +02:00
skypjack 091eef0e4c any: void fake vtable for the win 2025-10-18 11:48:32 +02:00
skypjack 96b56ca630 any: try to make all compilers happy again 2025-10-17 16:50:19 +02:00
skypjack 56d78c767a any: no delete for const void * 2025-10-17 16:49:22 +02:00
skypjack 1f57b2795f any: cleanup 2025-10-17 16:46:08 +02:00
skypjack de054655ab any: doc 2025-10-17 16:41:27 +02:00
skypjack bee74568e5 *; updated TODO 2025-10-17 08:18:14 +02:00
skypjack ebb2af1225 any: make ::initialize fully support void 2025-10-17 08:13:41 +02:00
skypjack 1487ad292b any: avoid using vtable ptr with has_value 2025-10-16 23:31:55 +02:00
skypjack d3b8e92294 any: cleanup 2025-10-16 13:59:08 +02:00
skypjack ab1d7d0126 any: make vtable void-friendly 2025-10-15 17:48:09 +02:00
skypjack 01b21afca0 any: make in_situ void-friendly 2025-10-15 17:46:25 +02:00
skypjack ef0056908a core: doc 2025-10-15 11:13:27 +02:00
skypjack b021c78550 natvis: update basic_any view 2025-10-14 15:23:27 +02:00
skypjack aedaa7f6a4 any: cleanup 2025-10-13 14:56:36 +02:00
skypjack e15af7b500 doc: minor changes 2025-10-10 15:11:24 +02:00
skypjack 38b34eb986 any: add comments for things to cleanup :) 2025-10-10 12:58:14 +02:00
skypjack b4fc627c99 any: use vtable instead of descriptor 2025-10-10 12:54:54 +02:00
skypjack c9364d3af5 *: updated TODO 2025-10-10 12:49:49 +02:00
skypjack baa0d2c23c any: use vtable instead of descriptor for early exit 2025-10-10 10:53:25 +02:00
skypjack dc154a4b8a build: also test toolset v143 for backward compatibility 2025-10-10 10:24:22 +02:00
skypjack ba0e9fab45 any: reduce direct uses of descriptor 2025-10-10 10:08:44 +02:00
skypjack 4ab5a375e8 *: updated TODO 2025-10-10 10:08:18 +02:00
skypjack f63f36a411 any: basic_any_storage, prepare for vtable-less optimizations 2025-10-09 15:52:43 +02:00
skypjack f2b8177aaf any: avoid name clashing if possible 2025-10-09 09:24:18 +02:00
skypjack 53fab33423 core: cleanup headers 2025-10-08 15:41:26 +02:00
skypjack 4a252bdb84 any: minor changes 2025-10-08 14:24:33 +02:00
skypjack cece4be1ec any: prepare for ebco 2025-10-08 14:20:48 +02:00
skypjack 8f23d743ca *: updated TODO 2025-10-08 12:29:30 +02:00
skypjack 0fa1bc5999 test: cleanup 2025-10-08 12:28:22 +02:00
skypjack 281276e84e meta: rollback some stuff to make everything clang-tidy friendly 2025-10-07 18:52:46 +02:00
skypjack f73409e9ad meta: safe self-assignment for meta_any 2025-10-07 17:33:45 +02:00
skypjack 740cf006d9 any: safe self-assignment 2025-10-07 17:33:32 +02:00
skypjack 828ecb57e6 any: internal changes 2025-10-07 17:24:22 +02:00
skypjack 8794888c98 meta: cleanup 2025-10-07 17:23:29 +02:00
skypjack dd7b96fc9e test: make them clang-tidy friendly 2025-10-07 15:59:01 +02:00
skypjack 1116c33ada test: minor changes 2025-10-07 15:30:58 +02:00
skypjack 38fe05db85 meta: minor changes 2025-10-07 12:47:35 +02:00
skypjack b2d4832842 clang-tidy: typo 2025-10-07 12:37:29 +02:00
skypjack 4c19d2844e clang-tidy: refine config to match my tastes too :) 2025-10-07 11:46:27 +02:00
skypjack 6f2e5090e1 any: [[nodiscard]] 2025-10-07 11:45:20 +02:00
skypjack 25e5123128 meta: remove redundant initializer 2025-10-07 11:23:38 +02:00
skypjack 8c3ca20d19 clang-tidy: I do actually prefer else-after-return style 2025-10-07 11:21:45 +02:00
skypjack ee7f24be63 meta: no else after return 2025-10-07 11:15:17 +02:00
skypjack a5f58ef49f meta: clang-tidy 2025-10-07 11:11:01 +02:00
skypjack ba5c4ba121 meta: use any::has_value (perf) 2025-10-07 09:53:52 +02:00
skypjack fcf455f7ef any: ::has_value overloads 2025-10-07 09:24:21 +02:00
skypjack 6836d5b024 meta: refine meta_any::assign 2025-10-06 17:07:09 +02:00
skypjack 8142136940 meta: internal changes 2025-10-03 17:42:41 +02:00
skypjack e76bbb2015 test: code coverage 2025-10-03 17:36:50 +02:00
skypjack 6f57622eff *: updated TODO 2025-10-03 17:32:16 +02:00
skypjack 0c5cab164a any: missing template keywords 2025-10-03 14:21:22 +02:00
skypjack c67a62de81 *: updated TODO 2025-10-03 14:13:59 +02:00
skypjack 80eba8afb4 any: typed ::data with fallback (perf) 2025-10-03 14:12:46 +02:00
skypjack 0d6615a767 meta: cleanup 2025-10-02 17:05:00 +02:00
skypjack fc4d18ce44 meta: cleanup 2025-10-02 15:42:18 +02:00
skypjack ddf28480dc *: internal changes 2025-10-01 13:12:11 +02:00
skypjack f49f2331ba doc: minor changes 2025-10-01 13:12:00 +02:00
skypjack 6526d67d16 any: internal changes 2025-09-30 15:13:15 +02:00
skypjack 4d90521fcf *: updated TODO 2025-09-30 14:58:05 +02:00
skypjack 9165a1df1e meta: minor changes 2025-09-30 14:57:33 +02:00
skypjack a1406baf61 meta: cleanup 2025-09-29 18:56:41 +02:00
skypjack 645b3563a9 natvis: meta 2025-09-29 08:38:12 +02:00
skypjack 91eecc1efd sparse set: minor changes 2025-09-29 08:38:03 +02:00
skypjack 0782855880 meta: internal changes 2025-09-28 17:43:34 +02:00
skypjack b9bfeb9b3d meta: bring meta custom back in place 2025-09-26 16:56:03 +02:00
skypjack 0409aab6bb meta: cleanup 2025-09-26 15:09:10 +02:00
skypjack 947d89844b *: no entt:: namespace 2025-09-26 15:05:39 +02:00
Ted de Munnik ff8544f97d sparse set: simplify try_emplace iterator computation to improve MSVC codegen (#1286) 2025-09-26 11:20:58 +02:00
skypjack c777cda857 meta: support {} on static calls 2025-09-25 16:37:29 +02:00
skypjack a90584f1ce meta: update meta_handle context propagation (with non-regression tests) 2025-09-25 15:44:01 +02:00
skypjack 4e47c535c4 meta: meta_any -> meta_handle 2025-09-24 15:52:32 +02:00
skypjack 84fee2848f tools: update davey 2025-09-24 15:42:37 +02:00
skypjack 42259fb1ce meta: reintroduce meta_handle default ctor for utilities 2025-09-24 15:41:40 +02:00
skypjack e38e88362f meta: cleanup meta_handle further (breaking change) 2025-09-24 15:30:16 +02:00
skypjack 14be4141fa meta: strip deprecated ctor from meta_handle (breaking change) 2025-09-24 15:29:47 +02:00
skypjack 6a4ca4c4ba tools: update davey 2025-09-24 15:19:51 +02:00
skypjack 71e61b5270 meta: make meta_handle support empty construction from nullptr 2025-09-24 15:14:33 +02:00
skypjack affe6ca7b8 meta: internal changes 2025-09-24 15:13:03 +02:00
skypjack f0a07c4530 meta: avoid shadow warnings 2025-09-24 15:01:03 +02:00
skypjack a003575811 meta: avoid useless moves 2025-09-24 14:58:47 +02:00
skypjack be3f022445 meta: struct -> class 2025-09-24 14:57:04 +02:00
skypjack 4b5b3fec41 meta: deferred meta handle creation (perf) 2025-09-24 14:55:41 +02:00
skypjack 4debb79a60 meta: improved meta_handle support to meta_any 2025-09-24 13:07:24 +02:00
skypjack f3b763d973 meta: deprecate ctors that should not exist 2025-09-24 13:06:05 +02:00
skypjack 356024ed6e doc: cleanup 2025-09-24 12:38:57 +02:00
skypjack e8e62638fc meta: deprecate meta_handle ctor 2025-09-24 12:33:54 +02:00
skypjack 6ecf1f35c0 meta: revert automatic policy (too convenient a feature) 2025-09-24 12:30:21 +02:00
skypjack 05863c6a15 meta: automatic policy (perf, breaking change) 2025-09-24 12:02:56 +02:00
skypjack 1a02b6ad57 meta: refine meta_any move ctor 2025-09-23 15:53:50 +02:00
skypjack 5ee1f3fec1 meta: internal changes 2025-09-23 15:53:18 +02:00
skypjack f44c9a1c05 meta: deprecate a few functions that should not be there 2025-09-23 09:12:34 +02:00
skypjack 715e5318de meta: refine try_convert/allow_cast 2025-09-22 16:35:11 +02:00
Tobias Backer Dirks 211e5fddc1 doc: add Game link to EnTT In Action (#1284) 2025-09-22 09:15:21 +02:00
skypjack 9347e91db6 meta: stable meta types 2025-09-19 11:30:21 +02:00
skypjack bebfbada68 meta: refine factory init step 2025-09-19 11:28:26 +02:00
skypjack c239821d12 meta: keep supporting invalid types 2025-09-19 10:46:28 +02:00
skypjack 293cbe2769 meta: avoid copying meta type nodes 2025-09-19 09:49:33 +02:00
skypjack 3587eaed9a meta: deprecate meta_type::operator bool, meta types are never invalid 2025-09-19 08:54:45 +02:00
skypjack cb9d8ac3f0 meta: meta_type is void (and safe again) when empty 2025-09-18 17:44:32 +02:00
skypjack e544755bbc meta: refine meta_any::fetch_node function 2025-09-18 17:33:56 +02:00
skypjack e2003ff17a natvis: meta_any view 2025-09-18 17:33:16 +02:00
skypjack 6232c93907 meta: a bunch of [[nodiscard]] 2025-09-18 17:26:34 +02:00
skypjack 6153cdcbbe meta: lazy_node -> node 2025-09-18 17:25:21 +02:00
skypjack 89af917748 natvis: updated meta_any/meta_type_node views 2025-09-18 14:25:23 +02:00
skypjack 28466a7316 meta: lighter meta type objects (perf) 2025-09-18 14:11:24 +02:00
skypjack 33efea3f03 meta: avoid moving meta handles again and again (perf) 2025-09-17 09:13:42 +02:00
skypjack 55f1a47fcc meta: lazy_node pointer in meta_any (perf) 2025-09-16 10:44:35 +02:00
skypjack e9b3eee6d3 meta: static local meta type node fallback 2025-09-15 14:48:15 +02:00
skypjack b400927f02 meta: missing [[nodiscard]] 2025-09-12 18:06:07 +02:00
skypjack a6d566ae4a natvis: update meta type and meta type descriptor views 2025-09-12 17:44:13 +02:00
skypjack 93979e13ac meta: typo 2025-09-12 17:43:50 +02:00
skypjack a77e40093d meta: cleanup 2025-09-12 17:00:24 +02:00
skypjack 695ac44673 meta: prepare for more perf improvements 2025-09-12 16:23:37 +02:00
skypjack 1cc078e4fb test: cleanup 2025-09-12 16:11:00 +02:00
skypjack 94cd89a72a doc: typo 2025-09-12 14:38:58 +02:00
skypjack 5497291c29 meta: avoid copying meta_custom_node as not needed (perf) 2025-09-11 17:54:10 +02:00
skypjack 3c75f7e2fd meta: move custom data to meta type node details (perf) 2025-09-11 17:52:26 +02:00
skypjack 03d8cccc86 meta: use unique_ptr internall for meta_func_node 2025-09-11 17:30:31 +02:00
skypjack 47bfffc7cc meta: avoid moving handles if not needed 2025-09-10 19:09:02 +02:00
skypjack 9795f60bc1 meta: use ctx only for return type 2025-09-10 19:08:31 +02:00
skypjack b3b48db957 meta: cleanup 2025-09-09 18:21:30 +02:00
skypjack 7d2b4fcf57 meta: internal changes 2025-09-09 17:30:09 +02:00
skypjack 3af8525eb8 natvis: refine meta_any view 2025-09-09 08:27:30 +02:00
skypjack 3306b72f87 natvis: refine basic_any view 2025-09-09 08:27:14 +02:00
skypjack 91a239a277 meta: typo 2025-09-09 08:13:22 +02:00
skypjack fdaaeea52d meta: lazy initialization for nodes in meta_any 2025-09-08 15:43:01 +02:00
skypjack d81e57daa1 meta: use fwd ctors internally 2025-09-08 08:39:57 +02:00
skypjack ed84c6e9ff meta: early exit from allow_cast 2025-09-05 15:34:04 +02:00
skypjack fe872f6a0d test: cleanup 2025-09-05 15:00:42 +02:00
skypjack d8aa90234a meta: cleanup internal::try_convert 2025-09-05 13:04:20 +02:00
skypjack 28d8041da6 doc: typo 2025-09-05 12:58:35 +02:00
skypjack 1f53d163b7 meta: prepare internal::try_cast for lazy load on nodes 2025-09-05 12:57:30 +02:00
skypjack 7f38b7668e meta: break pointless meta destructors support for perf reasons (breaking change, use type destructors instead) 2025-09-04 15:05:15 +02:00
skypjack dc70d97760 *: updated TODO 2025-09-04 15:03:59 +02:00
skypjack 4d0d48f7d9 test: delete meta_drop.cpp 2025-09-04 15:03:42 +02:00
skypjack 4ecaf18b20 doc: update meta, drop reference to meta destructors 2025-09-04 14:57:28 +02:00
skypjack 30a66cf513 bazel: cleanup 2025-09-04 14:57:10 +02:00
skypjack 9bbc8ad014 natvis: remove view for meta_dtor_node 2025-09-04 14:55:35 +02:00
skypjack 626b882f26 meta: reduce uses of node in meta_any 2025-09-03 17:00:22 +02:00
skypjack 9b44fa47d0 meta: guard try_cast to reduce uses of the internal node 2025-09-02 17:53:42 +02:00
skypjack 9170fc850b meta: cleanup 2025-09-02 14:29:39 +02:00
skypjack 973f010d85 meta: early exit when assigning 2025-09-02 14:20:18 +02:00
skypjack 6241543fe2 meta: cleanup 2025-09-02 10:33:31 +02:00
skypjack 5e99452cf3 meta: avoid using node in meta_any if not necessary 2025-09-01 18:41:34 +02:00
skypjack d058ccd084 meta: avoid using node in meta_any if not necessary 2025-09-01 14:23:26 +02:00
skypjack 7e4694ce69 meta: prepare for lazy node initialization 2025-09-01 13:47:15 +02:00
skypjack b3b7975290 *: updated TODO 2025-08-29 17:33:57 +02:00
skypjack 5ee0a39616 meta: review allow_cast 2025-08-29 15:24:24 +02:00
skypjack 27b9a25d06 meta: cleanup comparison operator 2025-08-29 11:41:54 +02:00
skypjack 9f5a6260ce meta: node_or_assert for data/func 2025-08-29 09:59:28 +02:00
skypjack b4b85c8d53 meta: remove unnecessary checks 2025-08-29 09:55:27 +02:00
skypjack 4bc11e4297 natvis: meta 2025-08-29 09:34:32 +02:00
skypjack ad291d4280 natvis: core 2025-08-29 09:34:26 +02:00
skypjack f61fd4584a meta: skip unnecessary resolve calls (perf) 2025-08-28 16:56:31 +02:00
skypjack 536dba3048 meta: rollback safe mode for meta data and functions (perf, not necessary) 2025-08-28 13:38:41 +02:00
skypjack 4760a09d61 meta: avoid creating a new shared_ptr if not needed (perf) 2025-08-28 12:53:01 +02:00
skypjack 47ff98e25b storage: quit accepting (and silently discarding) arguments for empty types when invoking ::insert 2025-08-27 12:08:25 +02:00
skypjack a638df6cae storage: quit accepting (and silently discarding) arguments for empty types when invoking ::emplace 2025-08-26 11:05:01 +02:00
skypjack 4f1626fce9 runtime view: rework/get rid of NOLINT 2025-08-26 10:56:02 +02:00
skypjack 9b3965c2c9 family: rework/get rid of NOLINT 2025-08-26 10:51:45 +02:00
skypjack 536a43be90 storage: add proper swap function to entity specialization - close #1273 2025-08-25 15:18:00 +02:00
Christoph 09b0e7f528 meta: add parentheses around max to prevent conflicts with max macro on Windows (#1278) 2025-08-25 08:59:16 +02:00
skypjack 76b6841c51 organizer: make graph() const - close #1274 2025-08-25 08:57:41 +02:00
skypjack 4507c546c1 meta: reduce instantiations on meta containers 2025-08-07 11:04:27 +02:00
skypjack add999d105 meta: internal changes 2025-08-06 12:20:57 +02:00
skypjack 9cefbc3c79 meta: reduce size of fake vtable/template functions 2025-08-06 12:20:44 +02:00
skypjack 22347cfbd0 meta: remove pointless check 2025-08-05 14:47:39 +02:00
skypjack 6966eabd25 resource: minor changes 2025-08-05 13:59:23 +02:00
skypjack a32e004c92 test: a few more 2025-08-05 13:59:09 +02:00
skypjack 49d9385aa4 process: handle_type to make the type opaque for future changes 2025-08-05 13:36:13 +02:00
skypjack 9970ba2284 davey: remove useless macro 2025-08-04 16:33:08 +02:00
skypjack 20cc85011e davey: no more entt:: 2025-08-04 16:21:22 +02:00
skypjack 7f5d4fb8d2 davey: minor changes 2025-08-04 16:19:13 +02:00
skypjack 03e046f880 davey: revert recent changes, move towards multiple tools with shared functions instead 2025-08-04 16:13:52 +02:00
skypjack 436f077e0b *: updated TODO 2025-08-04 16:12:14 +02:00
skypjack d76cfb06f0 davey: prepare to support editor mode 2025-08-04 15:06:11 +02:00
Aaron Heysse 2bb947f6de doc: fixed variadic template args on a resource loader example (#1272) 2025-08-01 11:55:28 +02:00
skypjack 8a8f8dfd1b test: refine tests for dense_map 2025-07-31 14:49:47 +02:00
skypjack 15b8db6f61 doc: dense map 2025-07-31 14:49:38 +02:00
Terens 05e0a22fb3 dense_map: transparent lookup for at (#1270) 2025-07-31 14:29:44 +02:00
skypjack ada11c4be1 test: headers cleanup 2025-07-30 14:09:56 +02:00
skypjack 7dbb59adc9 test: increase code coverage 2025-07-30 12:04:57 +02:00
skypjack 02440e17ae test: code coverage 2025-07-30 10:35:11 +02:00
skypjack fa234af36b gh: update iwyu version 2025-07-30 10:24:36 +02:00
skypjack 40fdd26788 test: make clang-tidy happy 2025-07-30 10:21:10 +02:00
skypjack 6fa668900e natvis: sparse_set/storage/handle 2025-07-29 09:27:16 +02:00
skypjack 17e88e506c test: scheduler - close #1257 2025-07-28 15:10:11 +02:00
skypjack 3bcbea785a test: process 2025-07-28 14:32:42 +02:00
skypjack 3bac3d4bbe process: make inheritance from enable_shared_from_this public 2025-07-28 14:28:54 +02:00
skypjack abdb293106 doc: a note about shared processes 2025-07-28 14:28:29 +02:00
skypjack f4b960dc93 process: enable_shared_from_this to allow callers to get valid references 2025-07-28 14:20:38 +02:00
skypjack 71c217da28 *: updated TODO 2025-07-25 18:17:40 +02:00
skypjack 4777ca2980 doc: process 2025-07-25 18:17:20 +02:00
skypjack 4aabca2f0b natvis: process 2025-07-25 18:02:42 +02:00
skypjack 5c31fda9bd process/scheduler: refine API (finally), add allocator support - see #1257 2025-07-25 14:59:39 +02:00
skypjack eecd1dc636 doc: process (draft) 2025-07-24 18:48:16 +02:00
Michele Caini 998f4b45da doc: process (wip - tbd) 2025-07-23 18:11:14 +02:00
Michele Caini fb0b7e2aab *: updated TODO 2025-07-23 18:01:07 +02:00
Michele Caini cbb50c1292 process: prepare migration to allocator-aware model 2025-07-23 16:05:13 +02:00
Michele Caini fcd265a6ed process: shared_from_this is no longer required 2025-07-23 10:55:42 +02:00
Michele Caini 357ee3f994 scheduler: remove unnecessary template parameter 2025-07-22 10:59:40 +02:00
Michele Caini e35eed905b process: safety net 2025-07-22 10:58:00 +02:00
Michele Caini 7942648035 process/scheduler: refine API - see #1257 2025-07-22 10:51:15 +02:00
Michele Caini 93dca93616 process: prepare for a more user-friendly attach/then API 2025-07-21 12:51:38 +02:00
Michele Caini 9f10d32b73 meta: move meta_dynamic_extent to fwd.hpp 2025-07-21 12:02:35 +02:00
Michele Caini 21e82abfa7 scheduler: cleanup API 2025-07-18 18:59:08 +02:00
Michele Caini 7b48069bd5 process: process_from utility 2025-07-18 18:58:46 +02:00
Michele Caini 5721e62ed0 *: updated TODO 2025-07-18 18:10:55 +02:00
Michele Caini e140399725 doc: cleanup 2025-07-17 18:23:45 +02:00
Michele Caini 7f1a2b1887 doc: refine doc for process adaptor 2025-07-17 18:22:35 +02:00
Michele Caini 0fd70878b3 doc: process_adaptor 2025-07-17 18:17:14 +02:00
Michele Caini 06e88ce062 test: prepare to refactor scheduler API 2025-07-17 18:06:08 +02:00
Michele Caini b5201a56df scheduler: add a plain attach for shared processes - see #1257 2025-07-16 15:26:18 +02:00
Michele Caini 9c05f1d8f3 natvis: process 2025-07-16 15:08:58 +02:00
Michele Caini 093718a1c6 process: add base_type alias to process_adaptor 2025-07-16 15:08:47 +02:00
skypjack c07cb32ef8 *: updated TODO 2025-07-15 18:56:14 +02:00
skypjack 04da178800 process; process as first argument in process_adaptor 2025-07-15 09:47:55 +02:00
skypjack 5ab8da50cb *: updated TODO 2025-07-15 09:47:31 +02:00
skypjack da684a4159 process: basic_process_adaptor -> process_adaptor 2025-07-15 09:31:44 +02:00
skypjack ba20bde250 process: refine basic_process_adaptor implementation to use deduction guides 2025-07-15 09:30:04 +02:00
skypjack cec550ad11 process: pass directly the base process to callbacks 2025-07-14 18:00:05 +02:00
skypjack 62b56e1b56 process: move basic_process_adaptor design from base class functor to member 2025-07-14 17:20:34 +02:00
skypjack b045846579 test: minor changes 2025-07-14 16:48:03 +02:00
skypjack 665aa3c4cf *: updated TODO 2025-07-02 16:31:53 +02:00
skypjack 0f49a1fe27 davey: initial doc (despite the work-in-progress nature) 2025-07-02 09:41:20 +02:00
skypjack ad4ab9dc08 davey: fix entry points for storage types 2025-07-02 09:37:15 +02:00
skypjack 1293990605 davey: comment out internals to avoid warnings due to missing doc 2025-07-01 16:43:26 +02:00
skypjack c71bf6e8d9 process: avoid unqualified lookup 2025-07-01 16:37:42 +02:00
skypjack 716c67d3a5 process: enable_shared_from_this was actually useful here 2025-07-01 15:32:37 +02:00
skypjack 33b1daafa0 process: refine then return type 2025-06-30 17:32:27 +02:00
skypjack 2532158860 scheduler: process type 2025-06-30 17:32:04 +02:00
skypjack da65e347b3 doc: typo 2025-06-30 08:35:01 +02:00
skypjack c940bc8015 process: enable_shared_from_this is no longer required 2025-06-30 08:33:25 +02:00
skypjack 9c4676f4c0 process: merge peek/release, no need for two functions 2025-06-30 08:26:24 +02:00
skypjack 3b64dae13e natvis: process 2025-06-30 08:18:09 +02:00
skypjack 3126b3efbf scheduler: review internals to use peek/release/whatever - see #1257 2025-06-27 11:27:12 +02:00
skypjack 01e12fa011 doc: cleanup 2025-06-27 11:26:28 +02:00
skypjack 1d163ee113 process: then/release/peek for child processes 2025-06-27 09:12:02 +02:00
skypjack f97ecd3ba4 process: rollback token based ctor, prep to move continuation to process 2025-06-25 19:16:29 +02:00
skypjack 3d66676c1b doc: a note about ENTT_INSTALL - close #1265 2025-06-25 18:13:26 +02:00
skypjack bf28bab7ba natvis: basic_scheduler 2025-06-25 16:43:53 +02:00
skypjack a6c2dc89ac scheduler/process: abort immediate param does not propagate anymore 2025-06-24 18:12:27 +02:00
skypjack e36ff3d50e build: move tools to source dir 2025-06-24 17:41:01 +02:00
skypjack dd4c36333b natvis: basic_process 2025-06-24 17:12:04 +02:00
skypjack 9e328ce232 build: remove extra > from HEADERS_FILES 2025-06-23 13:53:53 +02:00
skypjack 624d0994ff build: BUILD_INTERFACE vs INSTALL_INTERFACE for headers 2025-06-23 10:38:35 +02:00
skypjack 6ec1ee6072 build: refine cmake natvis to reduce boilerplate 2025-06-23 10:37:57 +02:00
skypjack 5642788046 process: struct vs class decl 2025-06-23 08:48:38 +02:00
skypjack e8e77bf011 build: minor changes 2025-06-23 08:13:07 +02:00
skypjack 964dc6ec87 build: BUILD_INTERFACE vs INSTALL_INTERFACE 2025-06-20 16:24:41 +02:00
skypjack a0d738215a build: move natvis files to source dir 2025-06-20 15:17:39 +02:00
skypjack 9ae1181ca7 build: also install natvis files 2025-06-20 15:09:39 +02:00
skypjack 3b89567d77 type_info: wrap ENTT_PRETTY_FUNCTION_PREFIX/SUFFIX with an ifdef 2025-06-20 13:26:13 +02:00
skypjack 09bb10377b process: basic_process_adaptor vs process_adaptor 2025-06-19 17:16:56 +02:00
skypjack ffbc5519c1 process: start refining process_adaptor 2025-06-19 13:02:12 +02:00
skypjack c80b634497 process: basic_process vs process 2025-06-18 12:22:41 +02:00
skypjack db6c6573af scheduler: suppress warnings due to shadow variables 2025-06-17 15:27:11 +02:00
skypjack 7257dd50c6 process: single allocate ::function 2025-06-17 15:26:27 +02:00
skypjack 5f0af48b4c *: updated TODO 2025-06-17 08:16:10 +02:00
skypjack 41ebe0e779 scheduler/process: factory-like model, first draft, work in progress - see #1257 2025-06-17 08:16:05 +02:00
skypjack 0cc95c947e scheduler: further cleanup 2025-06-16 14:49:01 +02:00
skypjack 991f66e1a3 scheduler: cleanup to reduce allocations 2025-06-16 14:42:43 +02:00
skypjack d75efb9f16 *: updated TODO 2025-06-13 18:31:32 +02:00
skypjack 3575f00bb4 doc: minor changes 2025-06-13 18:31:18 +02:00
skypjack f532221685 doc: You are Circle 2025-06-13 08:02:30 +02:00
skypjack f502827e88 tests: update to match the last changes to the process and scheduler classes 2025-06-11 17:11:21 +02:00
skypjack 50c842883f scheduler: init calls are no longer required 2025-06-11 17:10:59 +02:00
skypjack 2f5b25b189 process: minor changes 2025-06-11 17:10:37 +02:00
skypjack fb0fedf8fc doc: process 2025-06-11 14:10:07 +02:00
skypjack 45e9c12b29 process: remove init, we have constructors already 2025-06-11 14:10:01 +02:00
skypjack e52957fabb scheduler: reduce process_handler to a single class 2025-06-10 08:04:50 +02:00
skypjack 209f333252 scheduler: keep removing logic from process handler 2025-06-09 14:50:47 +02:00
skypjack aa5c0d14ed scheduler: prepare to get rid of process handler 2025-06-09 14:46:15 +02:00
skypjack ca40a3e62f process: move away from the crtp idiom - see #1257 2025-06-06 15:15:20 +02:00
skypjack 8574335fe6 process: make succeed and fail functions public 2025-06-05 15:12:21 +02:00
skypjack 9493756895 test: cleanup 2025-06-05 15:10:52 +02:00
skypjack df5e57f381 process: make pause/unpause public - see #1257 2025-06-04 19:04:56 +02:00
skypjack 62e05abc77 doc: process 2025-06-03 10:50:37 +02:00
skypjack d7d63b09b7 registry: context .clear() function - close #1262 2025-06-03 10:49:10 +02:00
skypjack ae7b3d87ee test: avoid shadow variable warning 2025-05-29 17:49:13 +02:00
skypjack e2ef08f129 clang-tidy: suppress ok-ish warning 2025-05-29 17:45:10 +02:00
skypjack 8dfa4aa677 test: cleanup 2025-05-29 17:39:29 +02:00
skypjack 31522ce703 *: updated TODO 2025-05-29 14:23:17 +02:00
skypjack 25cad2543d test: reduce NOLINT usage 2025-05-29 14:23:12 +02:00
skypjack 34e50d6550 organizer: a const registry is not a sync point - close #1258 2025-05-28 18:28:22 +02:00
skypjack b7a06c535d hashed string: suppress linter warning 2025-05-27 15:36:49 +02:00
skypjack bf5b188b13 test: missing include 2025-05-27 09:20:47 +02:00
skypjack 20af487ea9 test: minor changes 2025-05-27 09:10:22 +02:00
skypjack d037976bcd hashed string: suppress warnings due to pointer arithmetic 2025-05-27 09:07:34 +02:00
skypjack 330bf8e120 sparse set: avoid warning due to missing [[nodiscard]] 2025-05-27 08:58:23 +02:00
skypjack 7064415265 *: updated TODO 2025-05-27 08:58:05 +02:00
skypjack df07350a46 gh: typo in a workflow 2025-05-27 08:46:44 +02:00
skypjack 66e80820c9 doc: meta built-in names support 2025-05-26 09:20:09 +02:00
skypjack 5d3173f1b4 doc: updated links 2025-05-26 09:19:52 +02:00
skypjack 3b977186ed runtime view: swap-only policy support - close #1252 2025-05-23 15:03:09 +02:00
skypjack 38caafd999 test: runtime view and storage entity with exclude 2025-05-22 15:35:15 +02:00
skypjack d7232dcf56 test: runtime view and storage entity 2025-05-22 15:32:09 +02:00
skypjack 825f73df6b test: more on the runtime view 2025-05-22 14:48:50 +02:00
skypjack 696e084b02 davey: refine pointer-like path 2025-05-21 17:40:43 +02:00
skypjack fcc7306407 *: cleanup 2025-05-21 17:40:35 +02:00
skypjack 1f182a25db doc: minor changes 2025-05-21 16:29:02 +02:00
andre-caldas 995018f1a7 doc: improve documentation on for ENTT_USE_ATOMIC (#1251) 2025-05-21 16:23:23 +02:00
skypjack a6fa6f6122 doc: auto-binding mechanism for signals 2025-05-19 19:26:22 +02:00
skypjack 1b6462a327 davey: better enum support 2025-05-19 13:38:41 +02:00
skypjack 6054e93ecc *: updated TODO 2025-05-19 13:38:39 +02:00
skypjack 3acf03ae1c testbed: more bindings 2025-05-16 11:46:56 +02:00
skypjack 42f4d28715 testbed: cleanup 2025-05-16 09:43:54 +02:00
skypjack 4ee86d8456 meta: forward declare meta_ctx 2025-05-16 09:43:47 +02:00
skypjack 3b2adc999d davey: davey_data is no longer required 2025-05-15 10:52:21 +02:00
skypjack 87ec44d3ee natvis: meta 2025-05-15 09:41:37 +02:00
skypjack 182a6d5fe4 meta: refine label support implementation 2025-05-14 14:53:02 +02:00
skypjack 49b5b5b2b1 hashed_string: make const char * conversion explicit 2025-05-12 16:05:35 +02:00
skypjack f984ae4930 hashed_string: break the dependency with string_view 2025-05-12 09:09:35 +02:00
skypjack e6ef506f2f natvis: label on meta elements 2025-05-09 17:33:29 +02:00
skypjack 2d1ae3d5eb *: updated TODO 2025-05-09 17:23:24 +02:00
skypjack d775841457 meta: built-in labels for meta data 2025-05-09 17:22:57 +02:00
skypjack 2f60398892 *: updated TODO 2025-05-09 17:20:17 +02:00
skypjack 393a347bad meta: prepare factory for labels on data 2025-05-09 14:57:48 +02:00
skypjack 6a4c594792 doc: cleanup 2025-05-09 09:29:56 +02:00
skypjack 154c16a9d3 meta: built-in labels for meta functions 2025-05-08 16:46:54 +02:00
skypjack 9536039932 meta: refine type label impl and tests 2025-05-08 10:17:49 +02:00
skypjack cad91fd0d1 *: updated TODO 2025-05-05 18:31:30 +02:00
skypjack 7615e55e96 meta: built-in labels for meta types 2025-05-05 18:31:22 +02:00
skypjack 0f54af1a11 doc: typo 2025-05-05 18:30:16 +02:00
skypjack a439cf476c meta: prepare for built-in name support 2025-05-05 17:50:24 +02:00
skypjack 121e5a0ca8 hashed_string: minor changes 2025-05-05 17:49:59 +02:00
skypjack 328e53bd7b testbed: use meta info 2025-05-02 14:13:03 +02:00
skypjack 4dd03da2e2 testbed: meta setup function proto 2025-05-02 11:36:45 +02:00
skypjack ebab67c314 davey: davey_data constructor 2025-05-02 11:10:32 +02:00
skypjack 5ddab2b9d9 testbed: refine a couple of components 2025-05-02 09:12:03 +02:00
skypjack 265f00becf testbed: setup some components to start with... 2025-04-30 16:24:16 +02:00
skypjack 340888e4e2 testbed: bare minimum rendering system 2025-04-30 16:24:01 +02:00
skypjack f5bbc895b5 testbed: updated components 2025-04-30 16:23:47 +02:00
skypjack 57a6c6b238 testbed: bare minimal input system 2025-04-30 16:06:55 +02:00
skypjack cb10854bc8 testbed: a bunch of components to start with 2025-04-30 16:06:17 +02:00
skypjack 1796b18284 testbed: setup hud system for later use 2025-04-29 14:48:23 +02:00
skypjack f505050391 testbed: prepare input system 2025-04-28 17:01:53 +02:00
skypjack b0afed4bd0 davey: present_view function (with quick test example) 2025-04-24 19:15:36 +02:00
skypjack 292cbd3d95 davey: use right entity type 2025-04-24 19:03:47 +02:00
skypjack 756e861346 davey: internal changes 2025-04-24 17:35:41 +02:00
skypjack 6db98b40a1 davey: cleanup 2025-04-24 17:31:41 +02:00
skypjack a9852a2d2f testbed: quick check for storage window 2025-04-23 17:49:41 +02:00
skypjack 7302b1544d davey: swap entity and storage in registry view 2025-04-23 17:48:06 +02:00
skypjack 491956a69e davey: typo 2025-04-23 17:46:32 +02:00
skypjack 2b94080ee5 davey: missing template keyword 2025-04-23 09:30:58 +02:00
skypjack 4732bd1bf7 davey: entry point for views 2025-04-23 08:59:06 +02:00
skypjack 2bdb44e3ba davey: typo 2025-04-23 08:54:40 +02:00
skypjack d805c29b73 davey: minor changes 2025-04-22 19:03:43 +02:00
skypjack a9187c1f45 davey: rework storage path 2025-04-22 18:56:10 +02:00
skypjack 4e76ae5cc6 davey: refine storage tab 2025-04-22 14:07:04 +02:00
skypjack 54b6ee0f27 davey: view entry point (draft) 2025-04-22 13:56:57 +02:00
skypjack bf8c83e798 davey: make registry tab bar embeddable 2025-04-17 11:51:16 +02:00
skypjack 4aed49b371 davey: context-less single storage overload 2025-04-17 11:50:18 +02:00
skypjack c1df295845 davey: break entity_tab dependency on registry class 2025-04-17 11:44:58 +02:00
skypjack 265057be83 davey: break storage_tab dependency on registry class 2025-04-17 11:38:03 +02:00
skypjack 021fbb6c69 davey: break present_entity dependency on registry class 2025-04-17 11:33:22 +02:00
skypjack 843480fdf6 davey: missing template keywords 2025-04-17 11:15:09 +02:00
skypjack 3eb78a175e davey: add missing template keyword 2025-04-16 19:40:31 +02:00
skypjack de1ae66966 davey: refine specifiers 2025-04-16 19:39:43 +02:00
skypjack ab9a62bcd8 davey: avoid using deprecated members 2025-04-16 19:31:51 +02:00
skypjack 41d9e44a23 davey: present_element (first draft, read-only) 2025-04-15 19:27:18 +02:00
skypjack 693b85fe40 davey: DAVEY_OR macro (for later uses) 2025-04-15 19:15:25 +02:00
skypjack 7a90e2a93b type_info: rename things for the best 2025-04-14 15:35:34 +02:00
skypjack 11c3ea2fdb type_info: full_type_name returns a non-null name in all cases 2025-04-14 15:32:14 +02:00
skypjack 57d604bcb2 type_info: full_type_name vs stripped_type_name 2025-04-14 15:24:00 +02:00
skypjack 63e38e40dd type_info: stripped_type_name returns empty views if name is not available 2025-04-14 15:20:27 +02:00
skypjack c66f116449 build: refine cmake for testbed 2025-04-11 18:27:25 +02:00
skypjack 55fb754614 davey: work in progress 2025-04-11 18:16:25 +02:00
skypjack afe687e9d7 testbed: temp init function for test purposes 2025-04-11 18:16:03 +02:00
Michele Caini 6ca9c77b26 davey: missing includes 2025-04-10 16:59:50 +02:00
Michele Caini 990956980b *: updated TODO 2025-04-10 16:59:42 +02:00
Michele Caini f7f30bc5b6 davey: work in progress... 2025-04-10 13:01:53 +02:00
Michele Caini 81b8d01e96 testbed: try to use gha-setup-ninja to setup ninja on the CI 2025-04-09 10:46:07 +02:00
Michele Caini 7ecfe45923 meta: rollback factory setup support to get wip in e healthy state (damn MSVC that accepts everything) 2025-04-09 10:30:52 +02:00
Michele Caini 5212f0c44a test: scoped functions 2025-04-09 10:23:31 +02:00
Michele Caini fa58cedd2e meta: avoid shadow-warnings 2025-04-09 10:20:30 +02:00
Michele Caini 8b1b7a0fc9 test: add missing template keywords 2025-04-09 10:11:45 +02:00
Michele Caini 2a37b972d9 meta: meta_factory::setup function 2025-04-09 09:26:00 +02:00
Michele Caini df7ebd244b doc: minor changes 2025-04-08 17:13:17 +02:00
Michele Caini b4b1cf38a6 test: cleanup 2025-04-08 17:12:39 +02:00
Michele Caini 292d57a60b meta: add meta_factory to fwd file 2025-04-08 12:08:27 +02:00
Michele Caini 9d6850636a meta_factory: type -> element_type to avoid collisions 2025-04-08 11:41:38 +02:00
Michele Caini 8879a76e88 meta_factory: expose underlying type 2025-04-07 17:50:56 +02:00
Michele Caini 0fa38bf0e0 testbed: work in progress (if only I had more time these days...) 2025-04-07 17:46:21 +02:00
Michele Caini 36eba38f62 *: updated TODO 2025-04-07 17:45:45 +02:00
Michele Caini fe8d7d78c4 meta: drop unnecessary static keywords 2025-04-04 12:35:12 +02:00
Michele Caini ff32d77eba meta: deprecate fixed_size in favor of extent/meta_dynamic_extent 2025-04-04 12:00:15 +02:00
Michele Caini 84f60ea2be build: use ninja generator for testbed windows workflow 2025-04-03 16:05:38 +02:00
Michele Caini cc6fe33709 build: add ubuntu required packages to testbed workflow 2025-04-03 15:58:47 +02:00
Michele Caini 5b3f04c5ff build: testbed GH workflow (first attempt) 2025-04-03 14:35:47 +02:00
Michele Caini dc0bf7bdd8 build: fix typo in GH workflow 2025-04-03 14:35:27 +02:00
Michele Caini 13f21dd942 build: tools.yml -> analyzer.yml 2025-04-01 14:30:47 +02:00
Michele Caini fbe69ae90b tools: davey trauma :) 2025-04-01 14:23:15 +02:00
Michele Caini dedad6a03e testbed: updated SDL3 version 2025-04-01 11:19:16 +02:00
Michele Caini 86d3d2207a testbed: application skel 2025-03-31 14:41:50 +02:00
Michele Caini 9c39f76774 build: update tests to make them work (again) with cr 2025-03-31 14:31:51 +02:00
Michele Caini 8c04222a40 testbed: app -> application 2025-03-28 11:28:32 +01:00
Michele Caini d84a18e456 testbed: context class 2025-03-28 11:25:29 +01:00
Michele Caini e42231fab0 sparse_set: deprecate type() in favor of info() for consistency 2025-03-27 10:23:26 +01:00
Michele Caini d60efe04fd poly: deprecate type() in favor of info() for consistency 2025-03-26 15:19:15 +01:00
Michele Caini 6e7ca646ec any: deprecate type() in favor of info() for consistency 2025-03-26 15:16:19 +01:00
Michele Caini cac3e4c62b test: minor changes 2025-03-26 15:15:57 +01:00
Michele Caini 0e323954e4 build: testbed initial setup 2025-03-25 15:44:52 +01:00
Michele Caini 385f5a4379 doc: typo 2025-03-25 11:55:36 +01:00
Michele Caini e80d20a740 build: prepare testbed executable 2025-03-25 11:43:56 +01:00
Justin Braben 9d4db9738a build: fix delegate compare test in Release mode (#1242) 2025-03-25 11:40:32 +01:00
Michele Caini f54859bedf build: prepare for tools and testbed 2025-03-21 09:39:53 +01:00
Michele Caini 556ff733d5 meta: drop deprecated utilities 2025-03-21 08:08:45 +01:00
Michele Caini 4027bfff69 meta: drop deprecated accessors on meta_any 2025-03-21 07:51:17 +01:00
Michele Caini dbcc0baa7b meta: drop the meta<Type> function 2025-03-20 19:02:01 +01:00
Michele Caini d45c2aca8a meta: drop multi-setter support for meta data 2025-03-20 09:26:25 +01:00
Michele Caini fd015edb98 meta: drop meta_any_policy 2025-03-20 09:21:38 +01:00
Michele Caini 5ccb46383c storage: drop deprecated functions 2025-03-20 09:20:44 +01:00
Michele Caini fa6fdc4059 now working on version 3.16.0 2025-03-19 17:09:40 +01:00
142 changed files with 11231 additions and 7924 deletions
+2
View File
@@ -18,8 +18,10 @@ Checks: >
performance-*,
portability-*,
readability-*,
-readability-else-after-return,
-readability-function-cognitive-complexity,
-readability-named-parameter,
-readability-redundant-member-init,
-readability-uppercase-literal-suffix,
CheckOptions:
- key: cppcoreguidelines-avoid-magic-numbers.IgnoreAllFloatingPointValues
@@ -1,9 +1,9 @@
name: tools
name: analyzer
on:
push:
branches:
- tools
- analyzer
jobs:
@@ -11,8 +11,8 @@ jobs:
timeout-minutes: 60
env:
IWYU: "0.23"
LLVM: "19"
IWYU: "0.24"
LLVM: "20"
runs-on: ubuntu-latest
continue-on-error: true
@@ -55,7 +55,7 @@ jobs:
-DENTT_BUILD_EXAMPLE=ON \
-DENTT_BUILD_LIB=ON \
-DENTT_BUILD_SNAPSHOT=ON \
-DENTT_BUILD_TOOLS=ON \
-DENTT_BUILD_TESTBED=ON \
-DCMAKE_CXX_INCLUDE_WHAT_YOU_USE="include-what-you-use;-Xiwyu;--mapping_file=${GITHUB_WORKSPACE}/entt.imp;-Xiwyu;--no_fwd_decls;-Xiwyu;--verbose=1" \
..
make -j4
@@ -78,7 +78,7 @@ jobs:
-DENTT_BUILD_EXAMPLE=ON \
-DENTT_BUILD_LIB=ON \
-DENTT_BUILD_SNAPSHOT=ON \
-DENTT_BUILD_TOOLS=ON \
-DENTT_BUILD_TESTBED=ON \
-DENTT_USE_CLANG_TIDY=ON \
..
make -j4
+3 -1
View File
@@ -40,10 +40,12 @@ jobs:
windows:
strategy:
matrix:
toolset: [default, v142, clang-cl]
toolset: [default, v142, v143, clang-cl]
include:
- toolset: v142
toolset_option: -T"v142"
- toolset: v143
toolset_option: -T"v143"
- toolset: clang-cl
toolset_option: -T"ClangCl"
+1 -1
View File
@@ -2,7 +2,7 @@ name: deploy
on:
release:
types: published
types: [published]
jobs:
+79
View File
@@ -0,0 +1,79 @@
name: testbed
on: [push]
jobs:
linux:
timeout-minutes: 15
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install required packages
run: |
sudo apt update
sudo apt install -y \
build-essential \
git \
make \
pkg-config \
cmake \
ninja-build \
gnome-desktop-testing \
libasound2-dev \
libpulse-dev \
libaudio-dev \
libjack-dev \
libsndio-dev \
libx11-dev \
libxext-dev \
libxrandr-dev \
libxcursor-dev \
libxfixes-dev \
libxi-dev \
libxss-dev \
libxtst-dev \
libxkbcommon-dev \
libdrm-dev \
libgbm-dev \
libgl1-mesa-dev \
libgles2-mesa-dev \
libegl1-mesa-dev \
libdbus-1-dev \
libibus-1.0-dev \
libudev-dev \
libpipewire-0.3-dev \
libwayland-dev \
libdecor-0-dev \
liburing-dev
- name: Compile testbed
working-directory: build
run: |
cmake -DENTT_BUILD_TESTBED=ON ..
make -j4
windows:
timeout-minutes: 15
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: seanmiddleditch/gha-setup-ninja@master
- name: Compile testbed
working-directory: build
run: |
cmake -DENTT_BUILD_TESTBED=ON .. -G Ninja
cmake --build . -j 4
macos:
timeout-minutes: 15
runs-on: macOS-latest
steps:
- uses: actions/checkout@v4
- name: Compile testbed
working-directory: build
run: |
cmake -DENTT_BUILD_TESTBED=ON ..
make -j4
+141 -113
View File
@@ -22,7 +22,7 @@ project(
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug)
endif()
message(VERBOSE "*")
message(VERBOSE "* ${PROJECT_NAME} v${PROJECT_VERSION} (${CMAKE_BUILD_TYPE})")
message(VERBOSE "* Copyright (c) 2017-2025 Michele Caini <michele.caini@gmail.com>")
@@ -105,14 +105,110 @@ if(ENTT_HAS_SANITIZER)
endif()
if(ENTT_CLANG_TIDY_EXECUTABLE)
set(CMAKE_CXX_CLANG_TIDY "${ENTT_CLANG_TIDY_EXECUTABLE};--config-file=${EnTT_SOURCE_DIR}/.clang-tidy;--header-filter=${EnTT_SOURCE_DIR}/src/entt/.*")
endif()
set(ENTT_CLANG_TIDY_OPTIONS ";--config-file=${EnTT_SOURCE_DIR}/.clang-tidy;--header-filter=${EnTT_SOURCE_DIR}/src/entt/.*")
if(MSVC AND NOT (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang"))
set(ENTT_CLANG_TIDY_OPTIONS "${ENTT_CLANG_TIDY_OPTIONS};--extra-arg=/EHsc;--extra-arg=/wd4996")
endif()
set(CMAKE_CXX_CLANG_TIDY "${ENTT_CLANG_TIDY_EXECUTABLE}${ENTT_CLANG_TIDY_OPTIONS}")
endif()
# Add EnTT goodies
option(ENTT_INCLUDE_HEADERS "Add all EnTT headers to the EnTT target." OFF)
option(ENTT_INCLUDE_NATVIS "Add EnTT natvis files to the EnTT target." OFF)
if(ENTT_INCLUDE_HEADERS)
set(
HEADERS_FILES
config/config.h
config/macro.h
config/version.h
container/dense_map.hpp
container/dense_set.hpp
container/table.hpp
container/fwd.hpp
core/algorithm.hpp
core/any.hpp
core/bit.hpp
core/compressed_pair.hpp
core/enum.hpp
core/family.hpp
core/fwd.hpp
core/hashed_string.hpp
core/ident.hpp
core/iterator.hpp
core/memory.hpp
core/monostate.hpp
core/ranges.hpp
core/tuple.hpp
core/type_info.hpp
core/type_traits.hpp
core/utility.hpp
entity/component.hpp
entity/entity.hpp
entity/fwd.hpp
entity/group.hpp
entity/handle.hpp
entity/mixin.hpp
entity/helper.hpp
entity/organizer.hpp
entity/ranges.hpp
entity/registry.hpp
entity/runtime_view.hpp
entity/snapshot.hpp
entity/sparse_set.hpp
entity/storage.hpp
entity/view.hpp
graph/adjacency_matrix.hpp
graph/dot.hpp
graph/flow.hpp
graph/fwd.hpp
locator/locator.hpp
meta/adl_pointer.hpp
meta/container.hpp
meta/context.hpp
meta/factory.hpp
meta/fwd.hpp
meta/meta.hpp
meta/node.hpp
meta/pointer.hpp
meta/policy.hpp
meta/range.hpp
meta/resolve.hpp
meta/template.hpp
meta/type_traits.hpp
meta/utility.hpp
poly/fwd.hpp
poly/poly.hpp
process/fwd.hpp
process/process.hpp
process/scheduler.hpp
resource/cache.hpp
resource/fwd.hpp
resource/loader.hpp
resource/resource.hpp
signal/delegate.hpp
signal/dispatcher.hpp
signal/emitter.hpp
signal/fwd.hpp
signal/sigh.hpp
tools/davey.hpp
entt.hpp
fwd.hpp
tools.hpp
)
list(TRANSFORM HEADERS_FILES APPEND ">" OUTPUT_VARIABLE HEADERS_BUILD_INTERFACE)
list(TRANSFORM HEADERS_BUILD_INTERFACE PREPEND "$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/")
list(TRANSFORM HEADERS_FILES APPEND ">" OUTPUT_VARIABLE HEADERS_INSTALL_INTERFACE)
list(TRANSFORM HEADERS_INSTALL_INTERFACE PREPEND "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/entt/")
target_sources(EnTT INTERFACE ${HEADERS_BUILD_INTERFACE} ${HEADERS_INSTALL_INTERFACE})
endif()
if(ENTT_INCLUDE_NATVIS)
if(MSVC)
set(ENTT_HAS_NATVIS TRUE CACHE BOOL "" FORCE)
@@ -124,104 +220,29 @@ if(ENTT_INCLUDE_NATVIS)
endif()
endif()
if(ENTT_INCLUDE_HEADERS)
target_sources(
EnTT
INTERFACE
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/config/config.h>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/config/macro.h>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/config/version.h>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/container/dense_map.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/container/dense_set.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/container/table.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/container/fwd.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/algorithm.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/any.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/attribute.h>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/bit.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/compressed_pair.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/enum.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/family.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/fwd.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/hashed_string.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/ident.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/iterator.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/memory.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/monostate.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/ranges.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/tuple.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/type_info.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/type_traits.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/utility.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/component.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/entity.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/fwd.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/group.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/handle.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/mixin.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/helper.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/organizer.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/ranges.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/registry.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/runtime_view.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/snapshot.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/sparse_set.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/storage.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/view.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/graph/adjacency_matrix.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/graph/dot.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/graph/flow.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/graph/fwd.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/locator/locator.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/adl_pointer.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/container.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/context.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/factory.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/fwd.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/meta.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/node.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/pointer.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/policy.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/range.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/resolve.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/template.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/type_traits.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/utility.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/poly/fwd.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/poly/poly.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/process/fwd.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/process/process.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/process/scheduler.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/resource/cache.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/resource/fwd.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/resource/loader.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/resource/resource.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/delegate.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/dispatcher.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/emitter.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/fwd.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/sigh.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entt.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/fwd.hpp>
)
endif()
if(ENTT_HAS_NATVIS)
target_sources(
EnTT
INTERFACE
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/config.natvis>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/container.natvis>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/core.natvis>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/entity.natvis>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/graph.natvis>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/locator.natvis>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/meta.natvis>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/poly.natvis>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/process.natvis>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/resource.natvis>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/signal.natvis>
set(
NATVIS_FILES
config.natvis
container.natvis
core.natvis
entity.natvis
graph.natvis
locator.natvis
meta.natvis
poly.natvis
process.natvis
resource.natvis
signal.natvis
)
list(TRANSFORM NATVIS_FILES APPEND ">" OUTPUT_VARIABLE NATVIS_BUILD_INTERFACE)
list(TRANSFORM NATVIS_BUILD_INTERFACE PREPEND "$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/natvis/")
list(TRANSFORM NATVIS_FILES APPEND ">" OUTPUT_VARIABLE NATVIS_INSTALL_INTERFACE)
list(TRANSFORM NATVIS_INSTALL_INTERFACE PREPEND "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/entt/natvis/")
target_sources(EnTT INTERFACE ${NATVIS_BUILD_INTERFACE} ${NATVIS_INSTALL_INTERFACE})
endif()
# Install EnTT and all related files
@@ -296,29 +317,36 @@ if(ENTT_INSTALL)
FILES_MATCHING
PATTERN "*.h"
PATTERN "*.hpp"
PATTERN "*.natvis"
)
export(PACKAGE EnTT)
endif()
# Tests
# Tests and testbed
option(ENTT_BUILD_TESTING "Enable building tests." OFF)
option(ENTT_BUILD_TESTBED "Enable building testbed." OFF)
if(ENTT_BUILD_TESTING)
option(ENTT_FIND_GTEST_PACKAGE "Enable finding gtest package." OFF)
if(ENTT_BUILD_TESTING OR ENTT_BUILD_TESTBED)
set(ENTT_ID_TYPE std::uint32_t CACHE STRING "Type of identifiers to use for tests and testbed")
set(ENTT_CXX_STD cxx_std_17 CACHE STRING "C++ standard revision to use for tests and testbed")
option(ENTT_BUILD_BENCHMARK "Build benchmark." OFF)
option(ENTT_BUILD_EXAMPLE "Build examples." OFF)
option(ENTT_BUILD_LIB "Build lib tests." OFF)
option(ENTT_BUILD_SNAPSHOT "Build snapshot test with Cereal." OFF)
set(ENTT_ID_TYPE std::uint32_t CACHE STRING "Type of identifiers to use for the tests")
set(ENTT_CXX_STD cxx_std_17 CACHE STRING "C++ standard revision to use for the tests")
include(CTest)
enable_testing()
add_subdirectory(test)
# Tests and tesetbed do not work together because SDL gets confused with EnTT tests
if(ENTT_BUILD_TESTING)
option(ENTT_FIND_GTEST_PACKAGE "Enable finding gtest package." OFF)
option(ENTT_BUILD_BENCHMARK "Build benchmark." OFF)
option(ENTT_BUILD_EXAMPLE "Build examples." OFF)
option(ENTT_BUILD_LIB "Build lib tests." OFF)
option(ENTT_BUILD_SNAPSHOT "Build snapshot test with Cereal." OFF)
include(CTest)
enable_testing()
add_subdirectory(test)
elseif(ENTT_BUILD_TESTBED)
add_subdirectory(testbed)
endif()
endif()
# Documentation
+8 -2
View File
@@ -232,7 +232,8 @@ build system of the library.
## CMake
To use `EnTT` from a `CMake` project, just link an existing target to the
`EnTT::EnTT` alias.<br/>
`EnTT::EnTT` alias.
The library offers everything you need for locating (as in `find_package`),
embedding (as in `add_subdirectory`), fetching (as in `FetchContent`) or using
it in many of the ways that you can think of and that involve `CMake`.<br/>
@@ -240,12 +241,17 @@ Covering all possible cases would require a treatise and not a simple README
file, but I'm confident that anyone reading this section also knows what it's
about and can use `EnTT` from a `CMake` project without problems.
Note that all `install` calls are guarded by the `ENTT_INSTALL` option to allow
using `EnTT` as a submodule without conflicting with user logic.<br/>
It is therefore necessary to set the option to true to take advantage of the
installation logic provided by this library.
## Natvis support
When using `CMake`, just enable the option `ENTT_INCLUDE_NATVIS` and enjoy
it.<br/>
Otherwise, most of the tools are covered via Natvis and all files can be found
in the `natvis` directory, divided by module.<br/>
in the `natvis` subdirectory, divided by module.<br/>
If you spot errors or have suggestions, any contribution is welcome!
## Packaging Tools
+8 -8
View File
@@ -13,19 +13,13 @@ TODO:
* review all NOLINT
* bring nested groups back in place (see bd34e7f)
* work stealing job system (see #100) + mt scheduler based on const awareness for types
* view: reduce inst due to/improve perf with index-based approach in dispatch_get/pick_and_each/each (single type too, define storage ::at and ::at_as_tuple)
* view: update natvis as needed after the last rework, merge pools/filter in the same array, drop check (?) and turn view into a position
* view: type-only view_iterator (dyn get/excl sizes), type-only basic_common_view (dyn get/excl sizes with pointer to array from derived)
* combine version-mask-vs-version-bits tricks with reserved bits to allow things like enabling/disabling
* self contained entity traits to avoid explicit specializations (ie enum constants)
* auto type info data from types if present
* test: push sharing types further
* storage entity: fast range-push from above
* table: pop back to support swap and pop, single column access, empty type optimization
* review cmake warning about FetchContent_Populate (need .28 and EXCLUDE_FROM_ALL for FetchContent)
* suppress -Wself-move on CI with g++13
* view specializations for multi, single and filtered elements
* don't pass reactive storage by default to callback
* runtime types support for meta for types that aren't backed by C++ types
* built-in no-pagination storage - no_pagination page size as limits::max
* any cdynamic to support const ownership construction
@@ -33,5 +27,11 @@ TODO:
* FetchContent_Populate -> FetchContent_MakeAvailable warnings
* doc: IMPLICIT_DIR_DOCS for dir docs or \dir
* meta non-const allow_cast overloads: (const int &) to (int &) is not allowed, but (const int &) to (double &) is allowed (support only for convertibles)
* improve non-const allow cast with in-place switch
* meta fixed_size could return the size directly if present
* review build process for testbed (i.e. tests first due to SDL)
* use unique_ptr or any for meta_custom_node
* paged vector as a standalone class
* resource: shared_from_this?
* finish the imgui viewer/editor!
* archetype-like a-là EnTT support (see my own notes)
* meta: conversion_helper machinery has lot of room for improvements
* organizer: view/storage only based model, no registry
+3 -2
View File
@@ -45,8 +45,9 @@ also limited to this library only.
In general, `EnTT` does not offer primitives to support multi-threading. Many of
the features can be split over multiple threads without any explicit control and
the user is the one who knows if a synchronization point is required.<br/>
However, some features are not easily accessible to users and are made
thread-safe by means of this definition.
However, some internal static data shared between threads should be atomic when
using `EnTT` from multiple threads, even when dealing with local storage. Define
this macro without assigning any value to it to get the job done.
## ENTT_ID_TYPE
+4 -4
View File
@@ -466,7 +466,7 @@ The `allocate_unique` function follows this proposal, making a virtue out of
necessity:
```cpp
std::unique_ptr<my_type, entt::allocation_deleter<my_type>> ptr = entt::allocate_unique<my_type>(allocator, arguments);
std::unique_ptr<my_type, entt::allocation_deleter<allocator_type>> ptr = entt::allocate_unique<my_type>(allocator, arguments);
```
Although the internal implementation is slightly different from what is proposed
@@ -639,7 +639,7 @@ These are the information made available by `type_info`:
This is also an alias for the following:
```cpp
auto idx = entt::type_index<std::remove_cv_t<std::remove_reference_t<a_type>>>::value();
auto idx = entt::type_index<std::remove_const_t<std::remove_reference_t<a_type>>>::value();
```
* The hash value associated with a given type:
@@ -651,7 +651,7 @@ These are the information made available by `type_info`:
This is also an alias for the following:
```cpp
auto hash = entt::type_hash<std::remove_cv_t<std::remove_reference_t<a_type>>>::value();
auto hash = entt::type_hash<std::remove_const_t<std::remove_reference_t<a_type>>>::value();
```
* The name associated with a given type:
@@ -663,7 +663,7 @@ These are the information made available by `type_info`:
This is also an alias for the following:
```cpp
auto name = entt::type_name<std::remove_cv_t<std::remove_reference_t<a_type>>>::value();
auto name = entt::type_name<std::remove_const_t<std::remove_reference_t<a_type>>>::value();
```
Where all accessed features are available at compile-time, the `type_info` class
+29 -7
View File
@@ -11,6 +11,7 @@
* [Vademecum](#vademecum)
* [The Registry, the Entity and the Component](#the-registry-the-entity-and-the-component)
* [Observe changes](#observe-changes)
* [Auto-binding](#auto-binding)
* [Entity lifecycle](#entity-lifecycle)
* [Listeners disconnection](#listeners-disconnection)
* [They call me reactive storage](#they-call-me-reactive-storage)
@@ -409,6 +410,27 @@ There are many useful but less known functionalities that are not described
here, such as the connection objects or the possibility to attach listeners with
a list of parameters that is shorter than that of the signal itself.
### Auto-binding
Users don't need to create bindings manually each and every time. For managed
types, they can have `EnTT` setup listeners automatically.<br/>
The library searches the types for functions with specific names and signatures,
as in the following example:
```cpp
struct my_type {
static void on_construct(entt::registry &registry, const entt::entity entt);
static void on_update(entt::registry &registry, const entt::entity entt);
static void on_destroy(entt::registry &registry, const entt::entity entt);
// ...
};
```
As soon as a storage is created for such a defined type, these functions are
associated with the respective signals. The function name is self-explanatory of
the target signal.
### Entity lifecycle
Observing entities is also possible. In this case, the user must use the entity
@@ -1548,7 +1570,7 @@ is not known), there is always the possibility of receiving a `type_info` object
for the type of elements associated with the entities (if any):
```cpp
if(entt::type_id<velocity>() == base.type()) {
if(entt::type_id<velocity>() == base.info()) {
// ...
}
```
@@ -2134,13 +2156,13 @@ It means that views and groups generated by a const registry also propagate the
constness to the types involved. As an example:
```cpp
entt::view<const position, const velocity> view = std::as_const(registry).view<const position, const velocity>();
entt::view<entt::get_t<const position, const velocity>> view = std::as_const(registry).view<const position, const velocity>();
```
Consider the following definition for a non-const view instead:
```cpp
entt::view<position, const velocity> view = registry.view<position, const velocity>();
entt::view<entt::get_t<position, const velocity>> view = registry.view<position, const velocity>();
```
In the example above, `view` is used to access either read-only or writable
@@ -2345,10 +2367,10 @@ expedients.
Finally, `EnTT` is configured via a few compile-time definitions to make some of
its parts implicitly thread-safe, roughly speaking only the ones that really
make sense and cannot be turned around.<br/>
In particular, when multiple instances of objects referencing the type index
generator (such as the `registry` class) are used in different threads, then it
might be useful to define `ENTT_USE_ATOMIC`.<br/>
See the relevant documentation for more information.
When using multiple threads with `EnTT`, you should define `ENTT_USE_ATOMIC`
unless you know exactly what you are doing. This is true even if each thread
only uses thread local data. For more information, see
[this section](config.md#entt_use_atomic).
## Iterators
+2 -2
View File
@@ -28,8 +28,8 @@ The section dedicated to `type_info` contains all the details to get around the
issue in a concise and elegant way. Please refer to the specific documentation.
When working with linked libraries, compile definitions `ENTT_API_EXPORT` and
`ENTT_API_IMPORT` are to import or export symbols, so as to make everything work
nicely across boundaries.<br/>
`ENTT_API_IMPORT` are there to import or export symbols, so as to make
everything work nicely across boundaries.<br/>
On the other hand, everything should run smoothly when working with plugins or
shared libraries that do not export any symbols.
+9
View File
@@ -141,6 +141,10 @@ I hope the following lists can grow much more in the future.
small demo game with ships and bullets flying everywhere on the screen.
* [Lichgate](https://buas.itch.io/lichgate): step into the robes of a powerful
mage determined to halt the relentless hordes of undead.
* [You Are Circle](https://store.steampowered.com/app/3578190/You_Are_Circle/):
a roguelite top-down shooter with a high-contrast vector line aesthetic.
* [EnTT Dino](https://github.com/omgitsaheadcrab/entt_dino): a Dinosaur Game
clone in C++ using only `SDL2` and `EnTT`.
## Engines and the like:
@@ -241,6 +245,8 @@ I hope the following lists can grow much more in the future.
* [Darmok](https://github.com/miguelibero/darmok): another C++ game engine.
* [Magique](https://github.com/gk646/magique): 2D game engine for programmers
(or those yet to be).
* [Physecs](https://github.com/thfProjects/Physecs): real-time 3D rigid body
physics simulation built on `EnTT`.
## Articles, videos and blog posts:
@@ -321,6 +327,9 @@ I hope the following lists can grow much more in the future.
[Collector](https://play.google.com/store/apps/details?id=com.esri.arcgis.collector)
and
[Navigator](https://play.google.com/store/apps/details?id=com.esri.navigator).
* [OneArc](https://onearc.com/): [licenses](https://onearc.com/third-party-licensors/)
do not lie. Their products use EnTT in some way, but it is not known _what_
way.
* [FASTSUITE Edition 2](https://www.fastsuite.com/en_EN/fastsuite/fastsuite-edition-2.html)
by [Cenit](http://www.cenit.com/en_EN/about-us/overview.html): they use
`EnTT` to drive their simulation, that is, the communication between robot
+72 -40
View File
@@ -3,10 +3,11 @@
# Table of Contents
* [Introduction](#introduction)
* [Names and identifiers](#names-and-identifiers)
* [Identifiers](#identifiers)
* [Reflection in a nutshell](#reflection-in-a-nutshell)
* [Any to the rescue](#any-to-the-rescue)
* [Enjoy the runtime](#enjoy-the-runtime)
* [Tell me your name](#tell-me-your-name)
* [Container support](#container-support)
* [Pointer-like types](#pointer-like-types)
* [Template information](#template-information)
@@ -33,19 +34,19 @@ reflection system for `EnTT`. Maybe I did not do better than others or maybe
yes, time will tell me, but at least I can model this tool around the library to
which it belongs and not the opposite.
# Names and identifiers
# Identifiers
The meta system does not force users to rely on the tools provided by the
library when it comes to working with names and identifiers. It does this by
offering an API that works with opaque identifiers that may or may not be
generated by means of a hashed string.<br/>
library when it comes to working with identifiers. It does this by offering an
API that works with integral values that may or may not be generated by means of
a hashed string.<br/>
This means that users can assign any type of identifier to the meta objects, as
long as they are numeric. It does not matter if they are generated at runtime,
at compile-time or with custom functions.
That being said, the examples in the following sections are all based on the
`hashed_string` class as provided by this library. Therefore, where an
identifier is required, it is likely that a user defined literal is used as
That being said, some of the examples in the following sections are based on the
`hashed_string` class as provided by this library. Therefore, where an integral
identifier is provided, it is likely that a user defined literal is used as
follows:
```cpp
@@ -82,8 +83,8 @@ However, it is also possible to assign custom identifiers to meta types:
entt::meta_factory<my_type>{}.type("reflected_type"_hs);
```
Identifiers are used to _retrieve_ meta types at runtime by _name_ other than by
type.<br/>
Identifiers are used instead of the type to _retrieve_ meta types at runtime, if
necessary.<br/>
However, users can be interested in adding features to a reflected type so that
the reflection system can use it correctly under the hood, while they do not
want to also make the type _searchable_. In this case, it is sufficient not to
@@ -103,17 +104,6 @@ generally used to create the following:
Meta default constructors are implicitly generated, if possible.
* _Destructors_. Both free functions and member functions are valid destructors:
```cpp
entt::meta_factory<my_type>{}.dtor<&destroy>();
```
The purpose is to offer the possibility to free up resources that require
_special treatment_ before an object is actually destroyed.<br/>
A function should neither delete nor explicitly invoke the destructor of a
given instance.
* _Data members_. Meta data members are actual data members of the underlying
type but also static and global variables or constants of any kind. From the
point of view of the client, all the variables associated with the reflected
@@ -127,7 +117,7 @@ generally used to create the following:
```
The `data` function requires the identifier to use for the meta data member.
Users can then access it by _name_ at runtime.<br/>
This is then used for runtime access.<br/>
Data members are also defined by means of a setter and getter pair. These are
either free functions, class members or a mix of them. This approach is also
convenient to create read-only properties from a non-const data member:
@@ -149,7 +139,7 @@ generally used to create the following:
```
The `func` function requires the identifier to use for the meta data function.
Users can then access it by _name_ at runtime.<br/>
This is then used for runtime access.<br/>
Overloading of meta functions is supported. Overloaded functions are resolved
at runtime by the reflection system according to the types of the arguments.
@@ -240,7 +230,7 @@ In all cases, the returned value is an instance of `meta_type` (possibly with
its id). These objects offer an API to know their _runtime identifiers_, to
iterate all the meta objects associated with them and even to build instances of
the underlying type.<br/>
Meta data members and functions are accessed by name:
Meta data members and functions are accessed by means of their identifiers:
* Meta data members:
@@ -268,6 +258,9 @@ Meta data members and functions are accessed by name:
addition, a meta function object is used to invoke the underlying function and
then get the return value in the form of a `meta_any` object.
Both functions search for the elements throughout the meta type hierarchy.
However, they offer the option of passing a second boolean argument to stop the
search at the top-level meta type.<br/>
All the meta objects thus obtained as well as the meta types explicitly convert
to a boolean value to check for validity:
@@ -292,19 +285,49 @@ type.<br/>
In particular, the `construct` member function accepts a variable number of
arguments and searches for a match. It then returns a `meta_any` object that may
or may not be initialized, depending on whether a suitable constructor was found
or not.
There is no object that wraps the destructor of a meta type nor a `destroy`
member function in its API. Destructors are invoked implicitly by `meta_any`
behind the scenes and users have not to deal with them explicitly. Furthermore,
they have no name, cannot be searched and would not have member functions to
expose anyway.<br/>
Similarly, conversion functions are not directly accessible. They are used
internally by `meta_any` and the meta objects when needed.
or not.<br/>
Conversion functions are not accessible instead. They are used internally by
`meta_any` and the meta objects when needed.
Meta types and meta objects in general contain much more than what was said.
Refer to the inline documentation for further details.
### Tell me your name
For meta types, data and functions, users can also provide custom _names_:
```cpp
entt::meta_factory<my_type>{}
.type("type"_hs, "my_type")
.data<&variable>("data"_hs, "variable")
.func<&function>("func"_hs, "function");
```
The _label_ provided **should** be a string literal. The library does not make
copies. It is up to the user to guarantee the lifetime of the name itself.<br/>
String identifiers are returned from the meta objects via the `name` function:
```cpp
const char *name = entt::resolve<my_type>().name();
```
Since most of the time there is no need to differentiate the _name_ from the
numeric identifier associated with a meta object, `EnTT` also offers a more
compact version of these functions:
```cpp
entt::meta_factory<my_type>{}
.type("my_type")
.data<&variable>("variable")
.func<&function>("function");
```
Again, the name provided **should** be a string literal. The string is then used
to generate a numeric identifier with the `hashed_string` class.<br/>
Despite support for names, there are no string-based lookup functions available.
That is, types (`resolve`) as well as data members (`data`) and function members
(`func`) are only _searchable_ by numeric identifiers.
## Container support
The runtime reflection system also supports containers of all types.<br/>
@@ -767,7 +790,7 @@ other problems.
There are a few alternatives available at the moment:
* The _as-is_ policy, associated with the type `entt::as_is_t`.<br/>
* The _as-value_ policy, associated with the type `entt::as_value_t`.<br/>
This is the default policy. In general, it should never be used explicitly,
since it is implicitly selected if no other policy is specified.<br/>
In this case, the return values of the functions as well as the properties
@@ -805,6 +828,18 @@ There are a few alternatives available at the moment:
`as_ref_t` _adapts_ to the constness of the passed object and to that of the
return type if any.
* The _as-is_ policy, associated with the type `entt::as_is_t`.<br/>
Useful for decoupling meta type creation code from calling code while still
preserving the behavior of data members and member functions as defined:
```cpp
entt::meta_factory<my_type>{}.func<&my_type::any_member, entt::as_is_t>("member"_hs);
```
For data members or member functions that return a reference type, the value
is returned by reference with the same constness. In all other cases, the
value is returned by copy.
Some uses are rather trivial, but it is useful to note that there are some less
obvious corner cases that can in turn be solved with the use of policies.
@@ -867,12 +902,9 @@ entt::meta_factory<my_type>{}.traits(my_traits::required | my_traits::hidden);
In the example above, `EnTT` bitmask enum support is used, but any integral
value is fine, as long as it does not exceed 16 bits.<br/>
It is not possible to assign traits at different times. Therefore, multiple
calls to the `traits` function overwrite previous values. However, traits can be
read from meta objects and used to update existing data with a factory,
effectively extending them as needed.<br/>
Likewise, users can also set traits on meta objects later if needed, as long as
the factory is reset to the meta object of interest:
Traits can be assigned at different times. Subsequent calls to the `traits`
function do not reset previously set values. However, users must reset the
factory to the meta object of interest:
```cpp
entt::meta_factory<my_type>{}
+75 -62
View File
@@ -4,7 +4,8 @@
* [Introduction](#introduction)
* [The process](#the-process)
* [Adaptor](#adaptor)
* [Continuation](#continuation)
* [Shared process](#shared-process)
* [The scheduler](#the-scheduler)
# Introduction
@@ -17,28 +18,20 @@ to define and execute cooperative processes.
# The process
A typical task inherits from the `process` class template that stays true to the
CRTP idiom. Moreover, derived classes specify what the intended type for elapsed
times is.
A typical task inherits from the `process` class template. Derived classes also
specify what the intended type for elapsed times is.
A process should expose publicly the following member functions whether needed
(note that it is not required to define a function unless the derived class
wants to _override_ the default behavior):
A process should implement the following member functions whether needed (note
that it is not required to define a function unless the derived class wants to
_override_ the default behavior):
* `void update(Delta, void *);`
This is invoked once per tick until a process is explicitly aborted or ends
either with or without errors. Technically speaking, this member function is
not strictly required. However, each process should at least define it to work
either with or without errors. Each process should at least define it to work
_properly_. The `void *` parameter is an opaque pointer to user data (if any)
forwarded directly to the process during an update.
* `void init();`
This is invoked when the process joins the running queue of a scheduler. It
happens usually when the process is attached to the scheduler if it is a top
level one, or when it replaces its parent if it is a _continuation_.
* `void succeeded();`
This is invoked in case of success, immediately after an update and during the
@@ -52,22 +45,24 @@ wants to _override_ the default behavior):
* `void aborted();`
This is invoked only if a process is explicitly aborted. There is no guarantee
that it executes in the same tick, it depends solely on whether the process is
that it executes in the same tick. It depends solely on whether the process is
aborted immediately or not.
Derived classes can also change the internal state of a process by invoking
`succeed` and `fail`, as well as `pause` and `unpause` the process itself.<br/>
All these are protected member functions made available to manage the life cycle
of a process from a derived class.
A class can also change the state of a process by invoking `succeed` and `fail`,
as well as `pause` and `unpause` the process itself.<br/>
All these are public member functions made available to manage the life cycle of
a process easily.
Here is a minimal example for the sake of curiosity:
```cpp
struct my_process: entt::process<my_process, std::uint32_t> {
using delta_type = std::uint32_t;
struct my_process: entt::process {
using allocator_type = typename entt::process::allocator_type;
using delta_type = typename entt::process::delta_type;
my_process(delta_type delay)
: remaining{delay}
my_process(const allocator_type &allocator, delta_type delay)
: entt::process{allocator},
remaining{delay}
{}
void update(delta_type delta, void *) {
@@ -85,33 +80,49 @@ private:
};
```
## Adaptor
## Continuation
Lambdas and functors cannot be used directly with a scheduler because they are
not properly defined processes with managed life cycles.<br/>
This class helps in filling the gap and turning lambdas and functors into
full-featured processes usable by a scheduler.
The function call operator has a signature similar to the one of the `update`
function of a process but for the fact that it receives two extra callbacks to
invoke whenever a process terminates with success or with an error:
A process may be followed by other processes upon successful termination.<br/>
This pairing can be set up at creation time, keeping the processes conceptually
separate from each other while still combining them at runtime:
```cpp
void(Delta delta, void *data, auto succeed, auto fail);
my_process process{};
process.then<my_other_process>();
```
Parameters have the following meaning:
This approach allows processes to be developed in isolation and combined to
define complex actions.<br/>
For example, a delayed operation where a parent process (such as a timer)
_schedules_ a child process (the deferred task) once the time is over.
* `delta` is the elapsed time.
* `data` is an opaque pointer to user data if any, `nullptr` otherwise.
* `succeed` is a function to call when a process terminates with success.
* `fail` is a function to call when a process terminates with errors.
The `then` function also accepts lambdas, which are associated with a dedicated
process internally:
Both `succeed` and `fail` accept no parameters at all.
```cpp
process.then([](entt::process &proc, std::uint32_t delta, void *data) {
// ...
})
```
Note that usually users should not worry about creating adaptors at all. A
scheduler creates them internally, each and every time a lambda or a functor is
used as a process.
The lambda function is such that it accepts a reference to the process that
manages it (to be able to terminate it, pause it and so on), plus the usual
values also passed to the `update` function.
## Shared process
All processes inherit from `std::enable_shared_from_this` to allow sharing with
the caller.<br/>
The returned smart pointer was created using the allocator associated with the
scheduler and therefore all its processes. This same allocator is available by
invoking `get_allocator` on the process itself.
As far as possible, sharing a process is not intended to allow the caller to
manage it. This could actually compromise the proper functioning of the
scheduler and the process itself.<br/>
Rather, the purpose is to allow the callers to save a valid reference to the
process, allowing them to intervene in its lifecycle through calls like `pause`
and the like.
# The scheduler
@@ -124,7 +135,7 @@ it is a good candidate to run one more time the next tick.<br/>
A process can also have a _child_. In this case, the parent process is replaced
with its child when it terminates and only if it returns with success. In case
of errors, both the parent process and its child are discarded. This way, it is
easy to create a chain of processes to run sequentially.
easy to create a _chain of processes_ to run sequentially.
Using a scheduler is straightforward. To create it, users must provide only the
type for the elapsed times and no arguments at all:
@@ -137,7 +148,7 @@ Otherwise, the `scheduler` alias is also available for the most common cases. It
uses `std::uint32_t` as a default type:
```cpp
entt::scheduler scheduler;
entt::scheduler scheduler{};
```
The class has member functions to query its internal data structures, like
@@ -154,34 +165,33 @@ entt::scheduler::size_type size = scheduler.size();
scheduler.clear();
```
To attach a process to a scheduler, there are mainly two ways:
To attach a process to a scheduler, invoke the `attach` function with a process
type and the arguments to use to construct it:
* If the process inherits from the `process` class template, it is enough to
indicate its type and submit all the parameters required to construct it to
the `attach` member function:
```cpp
scheduler.attach<my_process>(_1000u);
```
```cpp
scheduler.attach<my_process>(1000u);
```
The scheduler will also provide the process with its allocator as the first
argument.<br>
In case of lambdas or functors, the required signature is the one already seen
for the `then` function of a process:
* Otherwise, in case of a lambda or a functor, it is enough to provide an
instance of the class to the `attach` member function:
```cpp
scheduler.attach([](entt::process &, std::uint32_t, void *){ /* ... */ });
```
```cpp
scheduler.attach([](auto...){ /* ... */ });
```
In both cases, the scheduler is returned and its `then` member function can be
used to create chains of processes to run sequentially.<br/>
In both cases, the newly created process is returned by reference and its `then`
member function is used to create chains of processes to run sequentially.<br/>
As a minimal example of use:
```cpp
// schedules a task in the form of a lambda function
scheduler.attach([](auto delta, void *, auto succeed, auto fail) {
scheduler.attach([](entt::process &, std::uint32_t, void *) {
// ...
})
// appends a child in the form of another lambda function
.then([](auto delta, void *, auto succeed, auto fail) {
.then([](entt::process &, std::uint32_t, void *) {
// ...
})
// appends a child in the form of a process class
@@ -209,3 +219,6 @@ scheduler.abort(true);
// ... or gracefully during the next tick
scheduler.abort();
```
The argument passed to the `abort` function indicates whether execution should
be stopped immediately or processes should be notified on the next tick.
+2 -2
View File
@@ -112,13 +112,13 @@ struct my_loader {
struct from_disk_tag{};
struct from_network_tag{};
template<typename Args>
template<typename... Args>
result_type operator()(from_disk_tag, Args&&... args) {
// ...
return std::make_shared<my_resource>(std::forward<Args>(args)...);
}
template<typename Args>
template<typename... Args>
result_type operator()(from_network_tag, Args&&... args) {
// ...
return std::make_shared<my_resource>(std::forward<Args>(args)...);
-3
View File
@@ -1,3 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
</AutoVisualizer>
+7190 -5250
View File
File diff suppressed because it is too large Load Diff
+26
View File
@@ -95,6 +95,32 @@
# endif
#endif
#ifndef ENTT_EXPORT
# if defined _WIN32 || defined __CYGWIN__ || defined _MSC_VER
# define ENTT_EXPORT __declspec(dllexport)
# define ENTT_IMPORT __declspec(dllimport)
# define ENTT_HIDDEN
# elif defined __GNUC__ && __GNUC__ >= 4
# define ENTT_EXPORT __attribute__((visibility("default")))
# define ENTT_IMPORT __attribute__((visibility("default")))
# define ENTT_HIDDEN __attribute__((visibility("hidden")))
# else /* Unsupported compiler */
# define ENTT_EXPORT
# define ENTT_IMPORT
# define ENTT_HIDDEN
# endif
#endif
#ifndef ENTT_API
# if defined ENTT_API_EXPORT
# define ENTT_API ENTT_EXPORT
# elif defined ENTT_API_IMPORT
# define ENTT_API ENTT_IMPORT
# else /* No API */
# define ENTT_API
# endif
#endif
#if defined _MSC_VER
# pragma detect_mismatch("entt.version", ENTT_VERSION)
# pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY))
+1 -1
View File
@@ -6,7 +6,7 @@
// NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*)
#define ENTT_VERSION_MAJOR 3
#define ENTT_VERSION_MINOR 15
#define ENTT_VERSION_MINOR 16
#define ENTT_VERSION_PATCH 0
#define ENTT_VERSION \
+41 -17
View File
@@ -24,6 +24,8 @@ namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
static constexpr std::size_t dense_map_placeholder_position = (std::numeric_limits<std::size_t>::max)();
template<typename Key, typename Type>
struct dense_map_node final {
using value_type = std::pair<Key, Type>;
@@ -190,9 +192,7 @@ public:
using iterator_category = std::input_iterator_tag;
using iterator_concept = std::forward_iterator_tag;
constexpr dense_map_local_iterator() noexcept
: it{},
offset{} {}
constexpr dense_map_local_iterator() noexcept = default;
constexpr dense_map_local_iterator(It iter, const std::size_t pos) noexcept
: it{iter},
@@ -226,8 +226,8 @@ public:
}
private:
It it;
std::size_t offset;
It it{};
std::size_t offset{dense_map_placeholder_position};
};
template<typename Lhs, typename Rhs>
@@ -260,6 +260,7 @@ template<typename Key, typename Type, typename Hash, typename KeyEqual, typename
class dense_map {
static constexpr float default_threshold = 0.875f;
static constexpr std::size_t minimum_capacity = 8u;
static constexpr std::size_t placeholder_position = internal::dense_map_placeholder_position;
using node_type = internal::dense_map_node<Key, Type>;
using alloc_traits = std::allocator_traits<Allocator>;
@@ -274,10 +275,10 @@ class dense_map {
}
template<typename Other>
[[nodiscard]] auto constrained_find(const Other &key, std::size_t bucket) {
for(auto it = begin(bucket), last = end(bucket); it != last; ++it) {
if(packed.second()(it->first, key)) {
return begin() + static_cast<difference_type>(it.index());
[[nodiscard]] auto constrained_find(const Other &key, const std::size_t bucket) {
for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].next) {
if(packed.second()(packed.first()[offset].element.first, key)) {
return begin() + static_cast<typename iterator::difference_type>(offset);
}
}
@@ -285,10 +286,10 @@ class dense_map {
}
template<typename Other>
[[nodiscard]] auto constrained_find(const Other &key, std::size_t bucket) const {
for(auto it = cbegin(bucket), last = cend(bucket); it != last; ++it) {
if(packed.second()(it->first, key)) {
return cbegin() + static_cast<difference_type>(it.index());
[[nodiscard]] auto constrained_find(const Other &key, const std::size_t bucket) const {
for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].next) {
if(packed.second()(packed.first()[offset].element.first, key)) {
return cbegin() + static_cast<typename const_iterator::difference_type>(offset);
}
}
@@ -695,7 +696,7 @@ public:
* @return Number of elements removed (either 0 or 1).
*/
size_type erase(const key_type &key) {
for(size_type *curr = &sparse.first()[key_to_bucket(key)]; *curr != (std::numeric_limits<size_type>::max)(); curr = &packed.first()[*curr].next) {
for(size_type *curr = &sparse.first()[key_to_bucket(key)]; *curr != placeholder_position; curr = &packed.first()[*curr].next) {
if(packed.second()(packed.first()[*curr].element.first, key)) {
const auto index = *curr;
*curr = packed.first()[*curr].next;
@@ -725,6 +726,29 @@ public:
return it->second;
}
/**
* @brief Accesses a given element with bounds checking.
* @tparam Other Type of the key of an element to find.
* @param key A key of an element to find.
* @return A reference to the mapped value of the requested element.
*/
template<typename Other>
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, mapped_type const &>>
at(const Other &key) const {
auto it = find(key);
ENTT_ASSERT(it != cend(), "Invalid key");
return it->second;
}
/*! @copydoc at */
template<typename Other>
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, mapped_type &>>
at(const Other &key) {
auto it = find(key);
ENTT_ASSERT(it != end(), "Invalid key");
return it->second;
}
/**
* @brief Accesses or inserts a given element.
* @param key A key of an element to find or insert.
@@ -895,7 +919,7 @@ public:
* @return An iterator to the end of the given bucket.
*/
[[nodiscard]] const_local_iterator cend([[maybe_unused]] const size_type index) const {
return {packed.first().begin(), (std::numeric_limits<size_type>::max)()};
return {};
}
/**
@@ -913,7 +937,7 @@ public:
* @return An iterator to the end of the given bucket.
*/
[[nodiscard]] local_iterator end([[maybe_unused]] const size_type index) {
return {packed.first().begin(), (std::numeric_limits<size_type>::max)()};
return {};
}
/**
@@ -990,7 +1014,7 @@ public:
sparse.first().resize(sz);
for(auto &&elem: sparse.first()) {
elem = (std::numeric_limits<size_type>::max)();
elem = placeholder_position;
}
for(size_type pos{}, last = size(); pos < last; ++pos) {
+18 -17
View File
@@ -22,6 +22,8 @@ namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
static constexpr std::size_t dense_set_placeholder_position = (std::numeric_limits<std::size_t>::max)();
template<typename It>
class dense_set_iterator final {
template<typename>
@@ -152,9 +154,7 @@ public:
using difference_type = std::ptrdiff_t;
using iterator_category = std::forward_iterator_tag;
constexpr dense_set_local_iterator() noexcept
: it{},
offset{} {}
constexpr dense_set_local_iterator() noexcept = default;
constexpr dense_set_local_iterator(It iter, const std::size_t pos) noexcept
: it{iter},
@@ -187,8 +187,8 @@ public:
}
private:
It it;
std::size_t offset;
It it{};
std::size_t offset{dense_set_placeholder_position};
};
template<typename Lhs, typename Rhs>
@@ -220,6 +220,7 @@ template<typename Type, typename Hash, typename KeyEqual, typename Allocator>
class dense_set {
static constexpr float default_threshold = 0.875f;
static constexpr std::size_t minimum_capacity = 8u;
static constexpr std::size_t placeholder_position = internal::dense_set_placeholder_position;
using node_type = std::pair<std::size_t, Type>;
using alloc_traits = std::allocator_traits<Allocator>;
@@ -233,10 +234,10 @@ class dense_set {
}
template<typename Other>
[[nodiscard]] auto constrained_find(const Other &value, std::size_t bucket) {
for(auto it = begin(bucket), last = end(bucket); it != last; ++it) {
if(packed.second()(*it, value)) {
return begin() + static_cast<difference_type>(it.index());
[[nodiscard]] auto constrained_find(const Other &value, const std::size_t bucket) {
for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].first) {
if(packed.second()(packed.first()[offset].second, value)) {
return begin() + static_cast<typename iterator::difference_type>(offset);
}
}
@@ -244,10 +245,10 @@ class dense_set {
}
template<typename Other>
[[nodiscard]] auto constrained_find(const Other &value, std::size_t bucket) const {
for(auto it = cbegin(bucket), last = cend(bucket); it != last; ++it) {
if(packed.second()(*it, value)) {
return cbegin() + static_cast<difference_type>(it.index());
[[nodiscard]] auto constrained_find(const Other &value, const std::size_t bucket) const {
for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].first) {
if(packed.second()(packed.first()[offset].second, value)) {
return cbegin() + static_cast<typename const_iterator::difference_type>(offset);
}
}
@@ -624,7 +625,7 @@ public:
* @return Number of elements removed (either 0 or 1).
*/
size_type erase(const value_type &value) {
for(size_type *curr = &sparse.first()[value_to_bucket(value)]; *curr != (std::numeric_limits<size_type>::max)(); curr = &packed.first()[*curr].first) {
for(size_type *curr = &sparse.first()[value_to_bucket(value)]; *curr != placeholder_position; curr = &packed.first()[*curr].first) {
if(packed.second()(packed.first()[*curr].second, value)) {
const auto index = *curr;
*curr = packed.first()[*curr].first;
@@ -787,7 +788,7 @@ public:
* @return An iterator to the end of the given bucket.
*/
[[nodiscard]] const_local_iterator cend([[maybe_unused]] const size_type index) const {
return {packed.first().begin(), (std::numeric_limits<size_type>::max)()};
return {};
}
/**
@@ -805,7 +806,7 @@ public:
* @return An iterator to the end of the given bucket.
*/
[[nodiscard]] local_iterator end([[maybe_unused]] const size_type index) {
return {packed.first().begin(), (std::numeric_limits<size_type>::max)()};
return {};
}
/**
@@ -882,7 +883,7 @@ public:
sparse.first().resize(sz);
for(auto &&elem: sparse.first()) {
elem = (std::numeric_limits<size_type>::max)();
elem = placeholder_position;
}
for(size_type pos{}, last = size(); pos < last; ++pos) {
+225 -144
View File
@@ -6,10 +6,10 @@
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "../core/utility.hpp"
#include "fwd.hpp"
#include "type_info.hpp"
#include "type_traits.hpp"
#include "utility.hpp"
namespace entt {
@@ -17,49 +17,62 @@ namespace entt {
namespace internal {
enum class any_request : std::uint8_t {
info,
transfer,
assign,
destroy,
compare,
copy,
move,
get
move
};
template<std::size_t Len, std::size_t Align>
struct basic_any_storage {
static constexpr bool has_buffer = true;
union {
const void *instance{};
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
alignas(Align) std::byte buffer[Len];
};
};
template<std::size_t Align>
struct basic_any_storage<0u, Align> {
static constexpr bool has_buffer = false;
const void *instance{};
};
template<typename Type, std::size_t Len, std::size_t Align>
// NOLINTNEXTLINE(bugprone-sizeof-expression)
struct in_situ: std::bool_constant<(Len != 0u) && alignof(Type) <= Align && sizeof(Type) <= Len && std::is_nothrow_move_constructible_v<Type>> {};
template<std::size_t Len, std::size_t Align>
struct in_situ<void, Len, Align>: std::false_type {};
} // namespace internal
/*! @endcond */
/**
* @brief A SBO friendly, type-safe container for single values of any type.
* @tparam Len Size of the storage reserved for the small buffer optimization.
* @tparam Len Size of the buffer reserved for the small buffer optimization.
* @tparam Align Optional alignment requirement.
*/
template<std::size_t Len, std::size_t Align>
class basic_any {
class basic_any: private internal::basic_any_storage<Len, Align> {
using request = internal::any_request;
using base_type = internal::basic_any_storage<Len, Align>;
using vtable_type = const void *(const request, const basic_any &, const void *);
struct storage_type {
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
alignas(Align) std::byte data[Len + static_cast<std::size_t>(Len == 0u)];
};
using deleter_type = void(const basic_any &);
template<typename Type>
// NOLINTNEXTLINE(bugprone-sizeof-expression)
static constexpr bool in_situ = (Len != 0u) && alignof(Type) <= Align && sizeof(Type) <= Len && std::is_nothrow_move_constructible_v<Type>;
static constexpr bool in_situ_v = internal::in_situ<Type, Len, Align>::value;
template<typename Type>
static const void *basic_vtable(const request req, const basic_any &value, const void *other) {
static_assert(!std::is_void_v<Type> && std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, Type>, "Invalid type");
const Type *elem = nullptr;
static_assert(std::is_same_v<std::remove_const_t<std::remove_reference_t<Type>>, Type>, "Invalid type");
if constexpr(in_situ<Type>) {
elem = (value.mode == any_policy::embedded) ? reinterpret_cast<const Type *>(&value.storage) : static_cast<const Type *>(value.instance);
} else {
elem = static_cast<const Type *>(value.instance);
}
switch(req) {
switch(const auto *elem = static_cast<const Type *>(value.data()); req) {
case request::info:
return &type_id<Type>();
case request::transfer:
if constexpr(std::is_move_assignable_v<Type>) {
// NOLINTNEXTLINE(bugprone-casting-through-void)
@@ -73,15 +86,6 @@ class basic_any {
return other;
}
break;
case request::destroy:
if constexpr(in_situ<Type>) {
(value.mode == any_policy::embedded) ? elem->~Type() : (delete elem);
} else if constexpr(std::is_array_v<Type>) {
delete[] elem;
} else {
delete elem;
}
break;
case request::compare:
if constexpr(!std::is_function_v<Type> && !std::is_array_v<Type> && is_equality_comparable_v<Type>) {
return (*elem == *static_cast<const Type *>(other)) ? other : nullptr;
@@ -96,67 +100,86 @@ class basic_any {
break;
case request::move:
ENTT_ASSERT(value.mode == any_policy::embedded, "Unexpected policy");
if constexpr(in_situ<Type>) {
if constexpr(in_situ_v<Type>) {
// NOLINTNEXTLINE(bugprone-casting-through-void, bugprone-multi-level-implicit-pointer-conversion)
return ::new(&static_cast<basic_any *>(const_cast<void *>(other))->storage) Type{std::move(*const_cast<Type *>(elem))};
}
[[fallthrough]];
case request::get:
ENTT_ASSERT(value.mode == any_policy::embedded, "Unexpected policy");
if constexpr(in_situ<Type>) {
// NOLINTNEXTLINE(bugprone-multi-level-implicit-pointer-conversion)
return elem;
return ::new(&static_cast<basic_any *>(const_cast<void *>(other))->buffer) Type{std::move(*const_cast<Type *>(elem))};
}
}
return nullptr;
}
template<typename Type>
static void basic_deleter(const basic_any &value) {
static_assert(std::is_same_v<std::remove_const_t<std::remove_reference_t<Type>>, Type>, "Invalid type");
ENTT_ASSERT((value.mode == any_policy::dynamic) || ((value.mode == any_policy::embedded) && !std::is_trivially_destructible_v<Type>), "Unexpected policy");
const auto *elem = static_cast<const Type *>(value.data());
if constexpr(in_situ_v<Type>) {
(value.mode == any_policy::embedded) ? elem->~Type() : (delete elem);
} else if constexpr(std::is_array_v<Type>) {
delete[] elem;
} else {
delete elem;
}
}
template<typename Type, typename... Args>
void initialize([[maybe_unused]] Args &&...args) {
if constexpr(!std::is_void_v<Type>) {
using plain_type = std::remove_cv_t<std::remove_reference_t<Type>>;
using plain_type = std::remove_const_t<std::remove_reference_t<Type>>;
info = &type_id<plain_type>();
vtable = basic_vtable<plain_type>;
vtable = basic_vtable<plain_type>;
underlying_type = type_hash<plain_type>::value();
if constexpr(std::is_lvalue_reference_v<Type>) {
static_assert((std::is_lvalue_reference_v<Args> && ...) && (sizeof...(Args) == 1u), "Invalid arguments");
mode = std::is_const_v<std::remove_reference_t<Type>> ? any_policy::cref : any_policy::ref;
// NOLINTNEXTLINE(bugprone-multi-level-implicit-pointer-conversion)
instance = (std::addressof(args), ...);
} else if constexpr(in_situ<plain_type>) {
mode = any_policy::embedded;
if constexpr(std::is_aggregate_v<plain_type> && (sizeof...(Args) != 0u || !std::is_default_constructible_v<plain_type>)) {
::new(&storage) plain_type{std::forward<Args>(args)...};
} else {
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
::new(&storage) plain_type(std::forward<Args>(args)...);
}
if constexpr(std::is_void_v<Type>) {
deleter = nullptr;
mode = any_policy::empty;
this->instance = nullptr;
} else if constexpr(std::is_lvalue_reference_v<Type>) {
deleter = nullptr;
mode = std::is_const_v<std::remove_reference_t<Type>> ? any_policy::cref : any_policy::ref;
static_assert((std::is_lvalue_reference_v<Args> && ...) && (sizeof...(Args) == 1u), "Invalid arguments");
// NOLINTNEXTLINE(bugprone-multi-level-implicit-pointer-conversion)
this->instance = (std::addressof(args), ...);
} else if constexpr(in_situ_v<plain_type>) {
if constexpr(std::is_trivially_destructible_v<plain_type>) {
deleter = nullptr;
} else {
mode = any_policy::dynamic;
deleter = &basic_deleter<plain_type>;
}
if constexpr(std::is_aggregate_v<plain_type> && (sizeof...(Args) != 0u || !std::is_default_constructible_v<plain_type>)) {
instance = new plain_type{std::forward<Args>(args)...};
} else if constexpr(std::is_array_v<plain_type>) {
static_assert(sizeof...(Args) == 0u, "Invalid arguments");
instance = new plain_type[std::extent_v<plain_type>]();
} else {
instance = new plain_type(std::forward<Args>(args)...);
}
mode = any_policy::embedded;
if constexpr(std::is_aggregate_v<plain_type> && (sizeof...(Args) != 0u || !std::is_default_constructible_v<plain_type>)) {
::new(&this->buffer) plain_type{std::forward<Args>(args)...};
} else {
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
::new(&this->buffer) plain_type(std::forward<Args>(args)...);
}
} else {
deleter = &basic_deleter<plain_type>;
mode = any_policy::dynamic;
if constexpr(std::is_aggregate_v<plain_type> && (sizeof...(Args) != 0u || !std::is_default_constructible_v<plain_type>)) {
this->instance = new plain_type{std::forward<Args>(args)...};
} else if constexpr(std::is_array_v<plain_type>) {
static_assert(sizeof...(Args) == 0u, "Invalid arguments");
this->instance = new plain_type[std::extent_v<plain_type>]();
} else {
this->instance = new plain_type(std::forward<Args>(args)...);
}
}
}
basic_any(const basic_any &other, const any_policy pol) noexcept
: instance{other.data()},
info{other.info},
vtable{other.vtable},
mode{pol} {}
void invoke_deleter_if_exists() {
if(deleter != nullptr) {
deleter(*this);
}
}
public:
/*! @brief Size of the internal storage. */
/*! @brief Size of the internal buffer. */
static constexpr auto length = Len;
/*! @brief Alignment requirement. */
static constexpr auto alignment = Align;
@@ -173,7 +196,7 @@ public:
*/
template<typename Type, typename... Args>
explicit basic_any(std::in_place_type_t<Type>, Args &&...args)
: instance{} {
: base_type{} {
initialize<Type>(std::forward<Args>(args)...);
}
@@ -184,11 +207,14 @@ public:
*/
template<typename Type>
explicit basic_any(std::in_place_t, Type *value)
: instance{} {
: base_type{} {
static_assert(!std::is_const_v<Type> && !std::is_void_v<Type>, "Non-const non-void pointer required");
if(value != nullptr) {
if(value == nullptr) {
initialize<void>();
} else {
initialize<Type &>(*value);
deleter = &basic_deleter<Type>;
mode = any_policy::dynamic;
}
}
@@ -208,9 +234,7 @@ public:
*/
basic_any(const basic_any &other)
: basic_any{} {
if(other.vtable) {
other.vtable(request::copy, other, this);
}
other.vtable(request::copy, other, this);
}
/**
@@ -218,22 +242,21 @@ public:
* @param other The instance to move from.
*/
basic_any(basic_any &&other) noexcept
: instance{},
info{other.info},
: base_type{},
vtable{other.vtable},
deleter{other.deleter},
underlying_type{other.underlying_type},
mode{other.mode} {
if(other.mode == any_policy::embedded) {
other.vtable(request::move, other, this);
} else if(other.mode != any_policy::empty) {
instance = std::exchange(other.instance, nullptr);
this->instance = std::exchange(other.instance, nullptr);
}
}
/*! @brief Frees the internal storage, whatever it means. */
/*! @brief Frees the internal buffer, whatever it means. */
~basic_any() {
if(owner()) {
vtable(request::destroy, *this, nullptr);
}
invoke_deleter_if_exists();
}
/**
@@ -243,10 +266,12 @@ public:
*/
basic_any &operator=(const basic_any &other) {
if(this != &other) {
reset();
invoke_deleter_if_exists();
if(other.vtable) {
if(other) {
other.vtable(request::copy, other, this);
} else {
initialize<void>();
}
}
@@ -255,26 +280,25 @@ public:
/**
* @brief Move assignment operator.
*
* @warning
* Self-moving puts objects in a safe but unspecified state.
*
* @param other The instance to move from.
* @return This any object.
*/
basic_any &operator=(basic_any &&other) noexcept {
reset();
if(this != &other) {
invoke_deleter_if_exists();
if(other.mode == any_policy::embedded) {
other.vtable(request::move, other, this);
} else if(other.mode != any_policy::empty) {
instance = std::exchange(other.instance, nullptr);
if(other.mode == any_policy::embedded) {
other.vtable(request::move, other, this);
} else if(other.mode != any_policy::empty) {
this->instance = std::exchange(other.instance, nullptr);
}
vtable = other.vtable;
deleter = other.deleter;
underlying_type = other.underlying_type;
mode = other.mode;
}
info = other.info;
vtable = other.vtable;
mode = other.mode;
return *this;
}
@@ -291,11 +315,48 @@ public:
}
/**
* @brief Returns the object type if any, `type_id<void>()` otherwise.
* @return The object type if any, `type_id<void>()` otherwise.
* @brief Returns false if a wrapper is empty, true otherwise.
* @return False if the wrapper is empty, true otherwise.
*/
[[nodiscard]] const type_info &type() const noexcept {
return (info == nullptr) ? type_id<void>() : *info;
[[nodiscard]] bool has_value() const noexcept {
return (mode != any_policy::empty);
}
/**
* @brief Returns false if the wrapper does not contain the expected type,
* true otherwise.
* @param req Expected type.
* @return False if the wrapper does not contain the expected type, true
* otherwise.
*/
[[nodiscard]] bool has_value(const type_info &req) const noexcept {
return (underlying_type == req.hash());
}
/**
* @brief Returns false if the wrapper does not contain the expected type,
* true otherwise.
* @tparam Type Expected type.
* @return False if the wrapper does not contain the expected type, true
* otherwise.
*/
template<typename Type>
[[nodiscard]] bool has_value() const noexcept {
static_assert(std::is_same_v<std::remove_const_t<Type>, Type>, "Invalid type");
return (underlying_type == type_hash<Type>::value());
}
/**
* @brief Returns the object type info if any, `type_id<void>()` otherwise.
* @return The object type info if any, `type_id<void>()` otherwise.
*/
[[nodiscard]] const type_info &info() const noexcept {
return *static_cast<const type_info *>(vtable(request::info, *this, nullptr));
}
/*! @copydoc info */
[[deprecated("use ::info instead")]] [[nodiscard]] const type_info &type() const noexcept {
return info();
}
/**
@@ -303,7 +364,11 @@ public:
* @return An opaque pointer the contained instance, if any.
*/
[[nodiscard]] const void *data() const noexcept {
return (mode == any_policy::embedded) ? vtable(request::get, *this, nullptr) : instance;
if constexpr(base_type::has_buffer) {
return (mode == any_policy::embedded) ? &this->buffer : this->instance;
} else {
return this->instance;
}
}
/**
@@ -312,7 +377,17 @@ public:
* @return An opaque pointer the contained instance, if any.
*/
[[nodiscard]] const void *data(const type_info &req) const noexcept {
return (type() == req) ? data() : nullptr;
return has_value(req) ? data() : nullptr;
}
/**
* @brief Returns an opaque pointer to the contained instance.
* @tparam Type Expected type.
* @return An opaque pointer the contained instance, if any.
*/
template<typename Type>
[[nodiscard]] const Type *data() const noexcept {
return has_value<std::remove_const_t<Type>>() ? static_cast<const Type *>(data()) : nullptr;
}
/**
@@ -320,7 +395,7 @@ public:
* @return An opaque pointer the contained instance, if any.
*/
[[nodiscard]] void *data() noexcept {
return mode == any_policy::cref ? nullptr : const_cast<void *>(std::as_const(*this).data());
return (mode == any_policy::cref) ? nullptr : const_cast<void *>(std::as_const(*this).data());
}
/**
@@ -329,7 +404,21 @@ public:
* @return An opaque pointer the contained instance, if any.
*/
[[nodiscard]] void *data(const type_info &req) noexcept {
return mode == any_policy::cref ? nullptr : const_cast<void *>(std::as_const(*this).data(req));
return (mode == any_policy::cref) ? nullptr : const_cast<void *>(std::as_const(*this).data(req));
}
/**
* @brief Returns an opaque pointer to the contained instance.
* @tparam Type Expected type.
* @return An opaque pointer the contained instance, if any.
*/
template<typename Type>
[[nodiscard]] Type *data() noexcept {
if constexpr(std::is_const_v<Type>) {
return std::as_const(*this).template data<std::remove_const_t<Type>>();
} else {
return (mode == any_policy::cref) ? nullptr : const_cast<Type *>(std::as_const(*this).template data<std::remove_const_t<Type>>());
}
}
/**
@@ -340,7 +429,7 @@ public:
*/
template<typename Type, typename... Args>
void emplace(Args &&...args) {
reset();
invoke_deleter_if_exists();
initialize<Type>(std::forward<Args>(args)...);
}
@@ -350,7 +439,7 @@ public:
* @return True in case of success, false otherwise.
*/
bool assign(const basic_any &other) {
if(vtable && mode != any_policy::cref && *info == other.type()) {
if(other && (mode != any_policy::cref) && (underlying_type == other.underlying_type)) {
return (vtable(request::assign, *this, other.data()) != nullptr);
}
@@ -360,12 +449,8 @@ public:
/*! @copydoc assign */
// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
bool assign(basic_any &&other) {
if(vtable && mode != any_policy::cref && *info == other.type()) {
if(auto *val = other.data(); val) {
return (vtable(request::transfer, *this, val) != nullptr);
}
return (vtable(request::assign, *this, std::as_const(other).data()) != nullptr);
if(other && (mode != any_policy::cref) && (underlying_type == other.underlying_type)) {
return (other.mode == any_policy::cref) ? (vtable(request::assign, *this, std::as_const(other).data()) != nullptr) : (vtable(request::transfer, *this, other.data()) != nullptr);
}
return false;
@@ -373,14 +458,8 @@ public:
/*! @brief Destroys contained object */
void reset() {
if(owner()) {
vtable(request::destroy, *this, nullptr);
}
instance = nullptr;
info = nullptr;
vtable = nullptr;
mode = any_policy::empty;
invoke_deleter_if_exists();
initialize<void>();
}
/**
@@ -388,7 +467,7 @@ public:
* @return False if the wrapper is empty, true otherwise.
*/
[[nodiscard]] explicit operator bool() const noexcept {
return vtable != nullptr;
return has_value();
}
/**
@@ -397,11 +476,11 @@ public:
* @return False if the two objects differ in their content, true otherwise.
*/
[[nodiscard]] bool operator==(const basic_any &other) const noexcept {
if(vtable && *info == other.type()) {
if(other && (underlying_type == other.underlying_type)) {
return (vtable(request::compare, *this, other.data()) != nullptr);
}
return (!vtable && !other.vtable);
return (!*this && !other);
}
/**
@@ -418,12 +497,19 @@ public:
* @return A wrapper that shares a reference to an unmanaged object.
*/
[[nodiscard]] basic_any as_ref() noexcept {
return basic_any{*this, (mode == any_policy::cref ? any_policy::cref : any_policy::ref)};
basic_any other = std::as_const(*this).as_ref();
other.mode = (mode == any_policy::cref ? any_policy::cref : any_policy::ref);
return other;
}
/*! @copydoc as_ref */
[[nodiscard]] basic_any as_ref() const noexcept {
return basic_any{*this, any_policy::cref};
basic_any other{};
other.instance = data();
other.vtable = vtable;
other.underlying_type = underlying_type;
other.mode = any_policy::cref;
return other;
}
/**
@@ -443,19 +529,16 @@ public:
}
private:
union {
const void *instance;
storage_type storage;
};
const type_info *info{};
vtable_type *vtable{};
any_policy mode{any_policy::empty};
deleter_type *deleter{};
id_type underlying_type{};
any_policy mode{};
};
/**
* @brief Performs type-safe access to the contained object.
* @tparam Type Type to which conversion is required.
* @tparam Len Size of the storage reserved for the small buffer optimization.
* @tparam Len Size of the buffer reserved for the small buffer optimization.
* @tparam Align Alignment requirement.
* @param data Target any object.
* @return The element converted to the requested type.
@@ -480,7 +563,7 @@ template<typename Type, std::size_t Len, std::size_t Align>
template<typename Type, std::size_t Len, std::size_t Align>
// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
[[nodiscard]] std::remove_const_t<Type> any_cast(basic_any<Len, Align> &&data) noexcept {
if constexpr(std::is_copy_constructible_v<std::remove_cv_t<std::remove_reference_t<Type>>>) {
if constexpr(std::is_copy_constructible_v<std::remove_const_t<std::remove_reference_t<Type>>>) {
if(auto *const instance = any_cast<std::remove_reference_t<Type>>(&data); instance) {
return static_cast<Type>(std::move(*instance));
}
@@ -496,8 +579,7 @@ template<typename Type, std::size_t Len, std::size_t Align>
/*! @copydoc any_cast */
template<typename Type, std::size_t Len, std::size_t Align>
[[nodiscard]] const Type *any_cast(const basic_any<Len, Align> *data) noexcept {
const auto &info = type_id<std::remove_cv_t<Type>>();
return static_cast<const Type *>(data->data(info));
return data->template data<std::remove_const_t<Type>>();
}
/*! @copydoc any_cast */
@@ -507,15 +589,14 @@ template<typename Type, std::size_t Len, std::size_t Align>
// last attempt to make wrappers for const references return their values
return any_cast<Type>(&std::as_const(*data));
} else {
const auto &info = type_id<std::remove_cv_t<Type>>();
return static_cast<Type *>(data->data(info));
return data->template data<Type>();
}
}
/**
* @brief Constructs a wrapper from a given type, passing it all arguments.
* @tparam Type Type of object to use to initialize the wrapper.
* @tparam Len Size of the storage reserved for the small buffer optimization.
* @tparam Len Size of the buffer reserved for the small buffer optimization.
* @tparam Align Optional alignment requirement.
* @tparam Args Types of arguments to use to construct the new instance.
* @param args Parameters to use to construct the instance.
@@ -528,7 +609,7 @@ template<typename Type, std::size_t Len = basic_any<>::length, std::size_t Align
/**
* @brief Forwards its argument and avoids copies for lvalue references.
* @tparam Len Size of the storage reserved for the small buffer optimization.
* @tparam Len Size of the buffer reserved for the small buffer optimization.
* @tparam Align Optional alignment requirement.
* @tparam Type Type of argument to use to construct the new instance.
* @param value Parameter to use to construct the instance.
-30
View File
@@ -1,30 +0,0 @@
#ifndef ENTT_CORE_ATTRIBUTE_H
#define ENTT_CORE_ATTRIBUTE_H
#ifndef ENTT_EXPORT
# if defined _WIN32 || defined __CYGWIN__ || defined _MSC_VER
# define ENTT_EXPORT __declspec(dllexport)
# define ENTT_IMPORT __declspec(dllimport)
# define ENTT_HIDDEN
# elif defined __GNUC__ && __GNUC__ >= 4
# define ENTT_EXPORT __attribute__((visibility("default")))
# define ENTT_IMPORT __attribute__((visibility("default")))
# define ENTT_HIDDEN __attribute__((visibility("hidden")))
# else /* Unsupported compiler */
# define ENTT_EXPORT
# define ENTT_IMPORT
# define ENTT_HIDDEN
# endif
#endif
#ifndef ENTT_API
# if defined ENTT_API_EXPORT
# define ENTT_API ENTT_EXPORT
# elif defined ENTT_API_IMPORT
# define ENTT_API ENTT_IMPORT
# else /* No API */
# define ENTT_API
# endif
#endif
#endif
+2 -2
View File
@@ -22,7 +22,7 @@ struct compressed_pair_element {
// NOLINTNEXTLINE(modernize-use-equals-default)
constexpr compressed_pair_element() noexcept(std::is_nothrow_default_constructible_v<Type>) {}
template<typename Arg, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Arg>>, compressed_pair_element>>>
template<typename Arg, typename = std::enable_if_t<!std::is_same_v<std::remove_const_t<std::remove_reference_t<Arg>>, compressed_pair_element>>>
constexpr compressed_pair_element(Arg &&arg) noexcept(std::is_nothrow_constructible_v<Type, Arg>)
: value{std::forward<Arg>(arg)} {}
@@ -52,7 +52,7 @@ struct compressed_pair_element<Type, Tag, std::enable_if_t<is_ebco_eligible_v<Ty
constexpr compressed_pair_element() noexcept(std::is_nothrow_default_constructible_v<base_type>)
: base_type{} {}
template<typename Arg, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Arg>>, compressed_pair_element>>>
template<typename Arg, typename = std::enable_if_t<!std::is_same_v<std::remove_const_t<std::remove_reference_t<Arg>>, compressed_pair_element>>>
constexpr compressed_pair_element(Arg &&arg) noexcept(std::is_nothrow_constructible_v<base_type, Arg>)
: base_type{std::forward<Arg>(arg)} {}
+5 -3
View File
@@ -15,8 +15,10 @@ namespace entt {
*/
template<typename...>
class family {
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
inline static ENTT_MAYBE_ATOMIC(id_type) identifier{};
static auto identifier() noexcept {
static ENTT_MAYBE_ATOMIC(id_type) value{};
return value++;
}
public:
/*! @brief Unsigned integer type. */
@@ -25,7 +27,7 @@ public:
/*! @brief Statically generated unique identifier for the given type. */
template<typename... Type>
// at the time I'm writing, clang crashes during compilation if auto is used instead of family_type
inline static const value_type value = identifier++;
inline static const value_type value = identifier();
};
} // namespace entt
+5 -5
View File
@@ -9,15 +9,15 @@ namespace entt {
/*! @brief Possible modes of an any object. */
enum class any_policy : std::uint8_t {
/*! @brief Default mode, the object does not own any elements. */
/*! @brief Default mode, no element available. */
empty,
/*! @brief Owning mode, the object owns a dynamically allocated element. */
/*! @brief Owning mode, dynamically allocated element. */
dynamic,
/*! @brief Owning mode, the object owns an embedded element. */
/*! @brief Owning mode, embedded element. */
embedded,
/*! @brief Aliasing mode, the object _points_ to a non-const element. */
/*! @brief Aliasing mode, non-const reference. */
ref,
/*! @brief Const aliasing mode, the object _points_ to a const element. */
/*! @brief Const aliasing mode, const reference. */
cref
};
+28 -22
View File
@@ -3,7 +3,6 @@
#include <cstddef>
#include <cstdint>
#include <string_view>
#include "fwd.hpp"
namespace entt {
@@ -32,9 +31,9 @@ struct basic_hashed_string {
using size_type = std::size_t;
using hash_type = id_type;
const value_type *repr;
size_type length;
hash_type hash;
const value_type *repr{};
hash_type hash{fnv_1a_params<>::offset};
size_type length{};
};
} // namespace internal
@@ -62,23 +61,12 @@ class basic_hashed_string: internal::basic_hashed_string<Char> {
struct const_wrapper {
// non-explicit constructor on purpose
constexpr const_wrapper(const Char *str) noexcept
constexpr const_wrapper(const typename base_type::value_type *str) noexcept
: repr{str} {}
const Char *repr;
const typename base_type::value_type *repr;
};
// Fowler–Noll–Vo hash function v. 1a - the good
[[nodiscard]] static constexpr auto helper(const std::basic_string_view<Char> view) noexcept {
base_type base{view.data(), view.size(), params::offset};
for(auto &&curr: view) {
base.hash = (base.hash ^ static_cast<id_type>(curr)) * params::prime;
}
return base;
}
public:
/*! @brief Character type. */
using value_type = typename base_type::value_type;
@@ -128,7 +116,14 @@ public:
* @param len Length of the string to hash.
*/
constexpr basic_hashed_string(const value_type *str, const size_type len) noexcept
: base_type{helper({str, len})} {}
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
: base_type{str} {
// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic)
for(; base_type::length < len; ++base_type::length) {
base_type::hash = (base_type::hash ^ static_cast<id_type>(str[base_type::length])) * params::prime;
}
// NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
}
/**
* @brief Constructs a hashed string from an array of const characters.
@@ -138,7 +133,12 @@ public:
template<std::size_t N>
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
ENTT_CONSTEVAL basic_hashed_string(const value_type (&str)[N]) noexcept
: base_type{helper({static_cast<const value_type *>(str)})} {}
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
: base_type{str} {
for(; str[base_type::length]; ++base_type::length) {
base_type::hash = (base_type::hash ^ static_cast<id_type>(str[base_type::length])) * params::prime;
}
}
/**
* @brief Explicit constructor on purpose to avoid constructing a hashed
@@ -150,10 +150,16 @@ public:
* @param wrapper Helps achieving the purpose by relying on overloading.
*/
explicit constexpr basic_hashed_string(const_wrapper wrapper) noexcept
: base_type{helper({wrapper.repr})} {}
: base_type{wrapper.repr} {
// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic)
for(; wrapper.repr[base_type::length]; ++base_type::length) {
base_type::hash = (base_type::hash ^ static_cast<id_type>(wrapper.repr[base_type::length])) * params::prime;
}
// NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
}
/**
* @brief Returns the size a hashed string.
* @brief Returns the size of a hashed string.
* @return The size of the hashed string.
*/
[[nodiscard]] constexpr size_type size() const noexcept {
@@ -177,7 +183,7 @@ public:
}
/*! @copydoc data */
[[nodiscard]] constexpr operator const value_type *() const noexcept {
[[nodiscard]] explicit constexpr operator const value_type *() const noexcept {
return data();
}
+1 -1
View File
@@ -83,7 +83,7 @@ struct forward_apply: private Func {
* @tparam Func Type of underlying invocable object.
*/
template<typename Func>
forward_apply(Func) -> forward_apply<std::remove_reference_t<std::remove_cv_t<Func>>>;
forward_apply(Func) -> forward_apply<std::remove_reference_t<std::remove_const_t<Func>>>;
} // namespace entt
+19 -11
View File
@@ -5,7 +5,6 @@
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "../core/attribute.h"
#include "fwd.hpp"
#include "hashed_string.hpp"
@@ -21,15 +20,24 @@ struct ENTT_API type_index final {
}
};
template<typename Type>
[[nodiscard]] constexpr const char *pretty_function() noexcept {
#if defined ENTT_PRETTY_FUNCTION
return static_cast<const char *>(ENTT_PRETTY_FUNCTION);
#else
return "";
#endif
}
template<typename Type>
[[nodiscard]] constexpr auto stripped_type_name() noexcept {
#if defined ENTT_PRETTY_FUNCTION
const std::string_view pretty_function{static_cast<const char *>(ENTT_PRETTY_FUNCTION)};
auto first = pretty_function.find_first_not_of(' ', pretty_function.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX) + 1);
auto value = pretty_function.substr(first, pretty_function.find_last_of(ENTT_PRETTY_FUNCTION_SUFFIX) - first);
const std::string_view full_name{pretty_function<Type>()};
auto first = full_name.find_first_not_of(' ', full_name.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX) + 1);
auto value = full_name.substr(first, full_name.find_last_of(ENTT_PRETTY_FUNCTION_SUFFIX) - first);
return value;
#else
return std::string_view{""};
return std::string_view{};
#endif
}
@@ -138,9 +146,9 @@ struct type_info final {
template<typename Type>
// NOLINTBEGIN(modernize-use-transparent-functors)
constexpr type_info(std::in_place_type_t<Type>) noexcept
: seq{type_index<std::remove_cv_t<std::remove_reference_t<Type>>>::value()},
identifier{type_hash<std::remove_cv_t<std::remove_reference_t<Type>>>::value()},
alias{type_name<std::remove_cv_t<std::remove_reference_t<Type>>>::value()} {}
: seq{type_index<std::remove_const_t<std::remove_reference_t<Type>>>::value()},
identifier{type_hash<std::remove_const_t<std::remove_reference_t<Type>>>::value()},
alias{type_name<std::remove_const_t<std::remove_reference_t<Type>>>::value()} {}
// NOLINTEND(modernize-use-transparent-functors)
/**
@@ -249,11 +257,11 @@ private:
*/
template<typename Type>
[[nodiscard]] const type_info &type_id() noexcept {
if constexpr(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>) {
if constexpr(std::is_same_v<Type, std::remove_const_t<std::remove_reference_t<Type>>>) {
static const type_info instance{std::in_place_type<Type>};
return instance;
} else {
return type_id<std::remove_cv_t<std::remove_reference_t<Type>>>();
return type_id<std::remove_const_t<std::remove_reference_t<Type>>>();
}
}
@@ -261,7 +269,7 @@ template<typename Type>
template<typename Type>
// NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward)
[[nodiscard]] const type_info &type_id(Type &&) noexcept {
return type_id<std::remove_cv_t<std::remove_reference_t<Type>>>();
return type_id<std::remove_const_t<std::remove_reference_t<Type>>>();
}
} // namespace entt
+2 -2
View File
@@ -691,7 +691,7 @@ struct has_iterator_category<Type, std::void_t<typename std::iterator_traits<Typ
/*! @copydoc is_iterator */
template<typename Type>
struct is_iterator<Type, std::enable_if_t<!std::is_void_v<std::remove_cv_t<std::remove_pointer_t<Type>>>>>
struct is_iterator<Type, std::enable_if_t<!std::is_void_v<std::remove_const_t<std::remove_pointer_t<Type>>>>>
: internal::has_iterator_category<Type> {};
/**
@@ -774,7 +774,7 @@ template<typename Type>
// NOLINTBEGIN(modernize-use-transparent-functors)
if constexpr(std::is_array_v<Type>) {
return false;
} else if constexpr(is_complete_v<std::tuple_size<std::remove_cv_t<Type>>>) {
} else if constexpr(is_complete_v<std::tuple_size<std::remove_const_t<Type>>>) {
if constexpr(has_tuple_size_value<Type>::value) {
return maybe_equality_comparable<Type>(0) && unpack_maybe_equality_comparable<Type>(std::make_index_sequence<std::tuple_size<Type>::value>{});
} else {
+1 -1
View File
@@ -151,7 +151,7 @@ public:
[[nodiscard]] bool owned(const id_type hash) const noexcept override {
for(size_type pos{}; pos < Owned; ++pos) {
if(pools[pos]->type().hash() == hash) {
if(pools[pos]->info().hash() == hash) {
return true;
}
}
+9 -17
View File
@@ -150,15 +150,15 @@ public:
destruction{allocator},
update{allocator} {
if constexpr(internal::has_on_construct<typename underlying_type::element_type, Registry>::value) {
entt::sink{construction}.template connect<&underlying_type::element_type::on_construct>();
sink{construction}.template connect<&underlying_type::element_type::on_construct>();
}
if constexpr(internal::has_on_update<typename underlying_type::element_type, Registry>::value) {
entt::sink{update}.template connect<&underlying_type::element_type::on_update>();
sink{update}.template connect<&underlying_type::element_type::on_update>();
}
if constexpr(internal::has_on_destroy<typename underlying_type::element_type, Registry>::value) {
entt::sink{destruction}.template connect<&underlying_type::element_type::on_destroy>();
sink{destruction}.template connect<&underlying_type::element_type::on_destroy>();
}
}
@@ -169,28 +169,24 @@ public:
* @brief Move constructor.
* @param other The instance to move from.
*/
// NOLINTBEGIN(bugprone-use-after-move)
basic_sigh_mixin(basic_sigh_mixin &&other) noexcept
: underlying_type{std::move(other)},
: underlying_type{static_cast<underlying_type &&>(other)},
owner{other.owner},
construction{std::move(other.construction)},
destruction{std::move(other.destruction)},
update{std::move(other.update)} {}
// NOLINTEND(bugprone-use-after-move)
/**
* @brief Allocator-extended move constructor.
* @param other The instance to move from.
* @param allocator The allocator to use.
*/
// NOLINTBEGIN(bugprone-use-after-move)
basic_sigh_mixin(basic_sigh_mixin &&other, const allocator_type &allocator)
: underlying_type{std::move(other), allocator},
: underlying_type{static_cast<underlying_type &&>(other), allocator},
owner{other.owner},
construction{std::move(other.construction), allocator},
destruction{std::move(other.destruction), allocator},
update{std::move(other.update), allocator} {}
// NOLINTEND(bugprone-use-after-move)
/*! @brief Default destructor. */
~basic_sigh_mixin() override = default;
@@ -454,26 +450,22 @@ public:
* @brief Move constructor.
* @param other The instance to move from.
*/
// NOLINTBEGIN(bugprone-use-after-move)
basic_reactive_mixin(basic_reactive_mixin &&other) noexcept
: underlying_type{std::move(other)},
: underlying_type{static_cast<underlying_type &&>(other)},
owner{other.owner},
conn{} {
conn{std::move(other.conn)} {
}
// NOLINTEND(bugprone-use-after-move)
/**
* @brief Allocator-extended move constructor.
* @param other The instance to move from.
* @param allocator The allocator to use.
*/
// NOLINTBEGIN(bugprone-use-after-move)
basic_reactive_mixin(basic_reactive_mixin &&other, const allocator_type &allocator)
: underlying_type{std::move(other), allocator},
: underlying_type{static_cast<underlying_type &&>(other), allocator},
owner{other.owner},
conn{allocator} {
conn{std::move(other.conn), allocator} {
}
// NOLINTEND(bugprone-use-after-move)
/*! @brief Default destructor. */
~basic_reactive_mixin() override = default;
+20 -21
View File
@@ -79,27 +79,28 @@ template<typename... Owned, typename... Get, typename... Exclude, typename... Ov
struct unpack_type<const basic_group<owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>>, type_list<Override...>>
: unpack_type<basic_group<owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>>, type_list<Override...>> {};
template<typename, typename>
template<typename, typename, typename>
struct resource_traits;
template<typename... Args, typename... Req>
struct resource_traits<type_list<Args...>, type_list<Req...>> {
template<typename Registry, typename... Args, typename... Req>
struct resource_traits<Registry, type_list<Args...>, type_list<Req...>> {
using args = type_list<std::remove_const_t<Args>...>;
using ro = type_list_cat_t<typename unpack_type<Args, type_list<Req...>>::ro..., typename unpack_type<Req, type_list<>>::ro...>;
using rw = type_list_cat_t<typename unpack_type<Args, type_list<Req...>>::rw..., typename unpack_type<Req, type_list<>>::rw...>;
static constexpr auto sync_point = (std::is_same_v<Args, Registry> || ...);
};
template<typename... Req, typename Ret, typename... Args>
resource_traits<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> free_function_to_resource_traits(Ret (*)(Args...));
template<typename Registry, typename... Req, typename Ret, typename... Args>
resource_traits<Registry, type_list<std::remove_reference_t<Args>...>, type_list<Req...>> free_function_to_resource_traits(Ret (*)(Args...));
template<typename... Req, typename Ret, typename Type, typename... Args>
resource_traits<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource_traits(Ret (*)(Type &, Args...));
template<typename Registry, typename... Req, typename Ret, typename Type, typename... Args>
resource_traits<Registry, type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource_traits(Ret (*)(Type &, Args...));
template<typename... Req, typename Ret, typename Class, typename... Args>
resource_traits<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource_traits(Ret (Class::*)(Args...));
template<typename Registry, typename... Req, typename Ret, typename Class, typename... Args>
resource_traits<Registry, type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource_traits(Ret (Class::*)(Args...));
template<typename... Req, typename Ret, typename Class, typename... Args>
resource_traits<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource_traits(Ret (Class::*)(Args...) const);
template<typename Registry, typename... Req, typename Ret, typename Class, typename... Args>
resource_traits<Registry, type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource_traits(Ret (Class::*)(Args...) const);
} // namespace internal
/*! @endcond */
@@ -169,9 +170,9 @@ class basic_organizer final {
}
template<typename... RO, typename... RW>
void track_dependencies(std::size_t index, const bool requires_registry, type_list<RO...>, type_list<RW...>) {
void track_dependencies(std::size_t index, const bool sync_point, type_list<RO...>, type_list<RW...>) {
builder.bind(static_cast<id_type>(index));
builder.set(type_hash<Registry>::value(), requires_registry || (sizeof...(RO) + sizeof...(RW) == 0u));
builder.set(type_hash<Registry>::value(), sync_point || (sizeof...(RO) + sizeof...(RW) == 0u));
(builder.ro(type_hash<RO>::value()), ...);
(builder.rw(type_hash<RW>::value()), ...);
}
@@ -316,8 +317,7 @@ public:
*/
template<auto Candidate, typename... Req>
void emplace(const char *name = nullptr) {
using resource_type = decltype(internal::free_function_to_resource_traits<Req...>(Candidate));
constexpr auto requires_registry = type_list_contains_v<typename resource_type::args, registry_type>;
using resource_type = decltype(internal::free_function_to_resource_traits<registry_type, Req...>(Candidate));
callback_type *callback = +[](const void *, registry_type &reg) {
std::apply(Candidate, to_args(reg, typename resource_type::args{}));
@@ -333,7 +333,7 @@ public:
+[](registry_type &reg) { void(to_args(reg, typename resource_type::args{})); },
&type_id<std::integral_constant<decltype(Candidate), Candidate>>()};
track_dependencies(vertices.size(), requires_registry, typename resource_type::ro{}, typename resource_type::rw{});
track_dependencies(vertices.size(), resource_type::sync_point, typename resource_type::ro{}, typename resource_type::rw{});
vertices.push_back(std::move(vdata));
}
@@ -348,8 +348,7 @@ public:
*/
template<auto Candidate, typename... Req, typename Type>
void emplace(Type &value_or_instance, const char *name = nullptr) {
using resource_type = decltype(internal::constrained_function_to_resource_traits<Req...>(Candidate));
constexpr auto requires_registry = type_list_contains_v<typename resource_type::args, registry_type>;
using resource_type = decltype(internal::constrained_function_to_resource_traits<registry_type, Req...>(Candidate));
callback_type *callback = +[](const void *payload, registry_type &reg) {
Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
@@ -366,7 +365,7 @@ public:
+[](registry_type &reg) { void(to_args(reg, typename resource_type::args{})); },
&type_id<std::integral_constant<decltype(Candidate), Candidate>>()};
track_dependencies(vertices.size(), requires_registry, typename resource_type::ro{}, typename resource_type::rw{});
track_dependencies(vertices.size(), resource_type::sync_point, typename resource_type::ro{}, typename resource_type::rw{});
vertices.push_back(std::move(vdata));
}
@@ -380,7 +379,7 @@ public:
*/
template<typename... Req>
void emplace(function_type *func, const void *payload = nullptr, const char *name = nullptr) {
using resource_type = internal::resource_traits<type_list<>, type_list<Req...>>;
using resource_type = internal::resource_traits<registry_type, type_list<>, type_list<Req...>>;
track_dependencies(vertices.size(), true, typename resource_type::ro{}, typename resource_type::rw{});
vertex_data vdata{
@@ -400,7 +399,7 @@ public:
* @brief Generates a task graph for the current content.
* @return The adjacency list of the task graph.
*/
[[nodiscard]] std::vector<vertex> graph() {
[[nodiscard]] std::vector<vertex> graph() const {
std::vector<vertex> adjacency_list{};
adjacency_list.reserve(vertices.size());
auto adjacency_matrix = builder.graph();
+26 -6
View File
@@ -164,6 +164,10 @@ public:
explicit registry_context(const allocator_type &allocator)
: ctx{allocator} {}
void clear() noexcept {
ctx.clear();
}
template<typename Type, typename... Args>
Type &emplace_as(const id_type id, Args &&...args) {
return any_cast<Type &>(ctx.try_emplace(id, std::in_place_type<Type>, std::forward<Args>(args)...).first->second);
@@ -176,7 +180,7 @@ public:
template<typename Type>
Type &insert_or_assign(const id_type id, Type &&value) {
return any_cast<std::remove_cv_t<std::remove_reference_t<Type>> &>(ctx.insert_or_assign(id, std::forward<Type>(value)).first->second);
return any_cast<std::remove_const_t<std::remove_reference_t<Type>> &>(ctx.insert_or_assign(id, std::forward<Type>(value)).first->second);
}
template<typename Type>
@@ -187,7 +191,7 @@ public:
template<typename Type>
bool erase(const id_type id = type_id<Type>().hash()) {
const auto it = ctx.find(id);
return it != ctx.end() && it->second.type() == type_id<Type>() ? (ctx.erase(it), true) : false;
return it != ctx.end() && it->second.info() == type_id<Type>() ? (ctx.erase(it), true) : false;
}
template<typename Type>
@@ -215,7 +219,7 @@ public:
template<typename Type>
[[nodiscard]] bool contains(const id_type id = type_id<Type>().hash()) const {
const auto it = ctx.find(id);
return it != ctx.cend() && it->second.type() == type_id<Type>();
return it != ctx.cend() && it->second.info() == type_id<Type>();
}
private:
@@ -251,7 +255,7 @@ class basic_registry {
using storage_type = storage_for_type<Type>;
if(auto it = pools.find(id); it != pools.cend()) {
ENTT_ASSERT(it->second->type() == type_id<Type>(), "Unexpected type");
ENTT_ASSERT(it->second->info() == type_id<Type>(), "Unexpected type");
return static_cast<storage_type &>(*it->second);
}
@@ -281,7 +285,7 @@ class basic_registry {
return &entities;
} else {
if(const auto it = pools.find(id); it != pools.cend()) {
ENTT_ASSERT(it->second->type() == type_id<Type>(), "Unexpected type");
ENTT_ASSERT(it->second->info() == type_id<Type>(), "Unexpected type");
return static_cast<const storage_for_type<Type> *>(it->second.get());
}
@@ -606,6 +610,22 @@ public:
return assure<Type>().emplace(entt, std::forward<Args>(args)...);
}
/**
* @brief Assigns each entity in a range the given element.
*
* @sa emplace
*
* @tparam Type Type of element to create.
* @tparam It Type of input iterator.
* @param first An iterator to the first element of the range of entities.
* @param last An iterator past the last element of the range of entities.
*/
template<typename Type, typename It>
void insert(It first, It last) {
ENTT_ASSERT(std::all_of(first, last, [this](const auto entt) { return valid(entt); }), "Invalid entity");
assure<Type>().insert(std::move(first), std::move(last));
}
/**
* @brief Assigns each entity in a range the given element.
*
@@ -618,7 +638,7 @@ public:
* @param value An instance of the element to assign.
*/
template<typename Type, typename It>
void insert(It first, It last, const Type &value = {}) {
void insert(It first, It last, const Type &value) {
ENTT_ASSERT(std::all_of(first, last, [this](const auto entt) { return valid(entt); }), "Invalid entity");
assure<Type>().insert(std::move(first), std::move(last), value);
}
+16 -8
View File
@@ -38,8 +38,7 @@ public:
it{},
tombstone_check{} {}
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
runtime_view_iterator(const std::vector<Set *> &cpools, const std::vector<Set *> &ignore, iterator_type curr) noexcept
runtime_view_iterator(const std::vector<Set *> &cpools, iterator_type curr, const std::vector<Set *> &ignore) noexcept
: pools{&cpools},
filter{&ignore},
it{curr},
@@ -126,6 +125,12 @@ class basic_runtime_view {
static_assert(std::is_same_v<typename alloc_traits::value_type, Type *>, "Invalid value type");
using container_type = std::vector<Type *, Allocator>;
[[nodiscard]] auto offset() const noexcept {
ENTT_ASSERT(!pools.empty(), "Invalid view");
const auto &leading = *pools.front();
return (leading.policy() == deletion_policy::swap_only) ? leading.free_list() : leading.size();
}
public:
/*! @brief Allocator type. */
using allocator_type = Allocator;
@@ -133,6 +138,8 @@ public:
using entity_type = typename Type::entity_type;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
/*! @brief Signed integer type. */
using difference_type = std::ptrdiff_t;
/*! @brief Common type among all storage types. */
using common_type = Type;
/*! @brief Bidirectional iterator type. */
@@ -219,10 +226,10 @@ public:
* @return This runtime view.
*/
basic_runtime_view &iterate(common_type &base) {
if(pools.empty() || !(base.size() < pools[0u]->size())) {
if(pools.empty() || !(base.size() < pools.front()->size())) {
pools.push_back(&base);
} else {
pools.push_back(std::exchange(pools[0u], &base));
pools.push_back(std::exchange(pools.front(), &base));
}
return *this;
@@ -243,7 +250,7 @@ public:
* @return Estimated number of entities iterated by the view.
*/
[[nodiscard]] size_type size_hint() const {
return pools.empty() ? size_type{} : pools.front()->size();
return pools.empty() ? size_type{} : offset();
}
/**
@@ -255,7 +262,7 @@ public:
* @return An iterator to the first entity that has the given elements.
*/
[[nodiscard]] iterator begin() const {
return pools.empty() ? iterator{} : iterator{pools, filter, pools[0]->begin()};
return pools.empty() ? iterator{} : iterator{pools, pools.front()->end() - static_cast<difference_type>(offset()), filter};
}
/**
@@ -265,7 +272,7 @@ public:
* given elements.
*/
[[nodiscard]] iterator end() const {
return pools.empty() ? iterator{} : iterator{pools, filter, pools[0]->end()};
return pools.empty() ? iterator{} : iterator{pools, pools.front()->end(), filter};
}
/**
@@ -284,7 +291,8 @@ public:
[[nodiscard]] bool contains(const entity_type entt) const {
return !pools.empty()
&& std::all_of(pools.cbegin(), pools.cend(), [entt](const auto *curr) { return curr->contains(entt); })
&& std::none_of(filter.cbegin(), filter.cend(), [entt](const auto *curr) { return curr && curr->contains(entt); });
&& std::none_of(filter.cbegin(), filter.cend(), [entt](const auto *curr) { return curr && curr->contains(entt); })
&& pools.front()->index(entt) < offset();
}
/**
+15 -10
View File
@@ -375,7 +375,7 @@ protected:
break;
}
return --(end() - static_cast<difference_type>(pos));
return iterator{packed, static_cast<difference_type>(++pos)};
}
/*! @brief Forwards variables to derived classes, if any. */
@@ -433,7 +433,7 @@ public:
explicit basic_sparse_set(const type_info &elem, deletion_policy pol = deletion_policy::swap_and_pop, const allocator_type &allocator = {})
: sparse{allocator},
packed{allocator},
info{&elem},
descriptor{&elem},
mode{pol},
head{policy_to_head()} {
ENTT_ASSERT(traits_type::version_mask || mode != deletion_policy::in_place, "Policy does not support zero-sized versions");
@@ -449,7 +449,7 @@ public:
basic_sparse_set(basic_sparse_set &&other) noexcept
: sparse{std::move(other.sparse)},
packed{std::move(other.packed)},
info{other.info},
descriptor{other.descriptor},
mode{other.mode},
head{std::exchange(other.head, policy_to_head())} {}
@@ -461,7 +461,7 @@ public:
basic_sparse_set(basic_sparse_set &&other, const allocator_type &allocator)
: sparse{std::move(other.sparse), allocator},
packed{std::move(other.packed), allocator},
info{other.info},
descriptor{other.descriptor},
mode{other.mode},
head{std::exchange(other.head, policy_to_head())} {
ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a sparse set is not allowed");
@@ -497,7 +497,7 @@ public:
using std::swap;
swap(sparse, other.sparse);
swap(packed, other.packed);
swap(info, other.info);
swap(descriptor, other.descriptor);
swap(mode, other.mode);
swap(head, other.head);
}
@@ -1079,11 +1079,16 @@ public:
}
/**
* @brief Returned value type, if any.
* @return Returned value type, if any.
* @brief Returns a type info object for the value type, if any.
* @return A type info object for the value type, if any.
*/
[[nodiscard]] const type_info &type() const noexcept {
return *info;
[[nodiscard]] const type_info &info() const noexcept {
return *descriptor;
}
/*! @copydoc info */
[[deprecated("use ::info instead")]] [[nodiscard]] const type_info &type() const noexcept {
return info();
}
/**
@@ -1099,7 +1104,7 @@ public:
private:
sparse_container_type sparse;
packed_container_type packed;
const type_info *info;
const type_info *descriptor;
deletion_policy mode;
size_type head;
};
+19 -52
View File
@@ -450,24 +450,20 @@ public:
* @brief Move constructor.
* @param other The instance to move from.
*/
// NOLINTBEGIN(bugprone-use-after-move)
basic_storage(basic_storage &&other) noexcept
: base_type{std::move(other)},
: base_type{static_cast<base_type &&>(other)},
payload{std::move(other.payload)} {}
// NOLINTEND(bugprone-use-after-move)
/**
* @brief Allocator-extended move constructor.
* @param other The instance to move from.
* @param allocator The allocator to use.
*/
// NOLINTBEGIN(bugprone-use-after-move)
basic_storage(basic_storage &&other, const allocator_type &allocator)
: base_type{std::move(other), allocator},
: base_type{static_cast<base_type &&>(other), allocator},
payload{std::move(other.payload), allocator} {
ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a storage is not allowed");
}
// NOLINTEND(bugprone-use-after-move)
/*! @brief Default destructor. */
// NOLINTNEXTLINE(bugprone-exception-escape)
@@ -909,12 +905,9 @@ public:
* Attempting to use an entity that already belongs to the storage results
* in undefined behavior.
*
* @tparam Args Types of arguments to use to construct the object.
* @param entt A valid identifier.
*/
template<typename... Args>
// NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward)
void emplace(const entity_type entt, Args &&...) {
void emplace(const entity_type entt) {
base_type::try_emplace(entt, false);
}
@@ -933,13 +926,11 @@ public:
/**
* @brief Assigns entities to a storage.
* @tparam It Type of input iterator.
* @tparam Args Types of optional arguments.
* @param first An iterator to the first element of the range of entities.
* @param last An iterator past the last element of the range of entities.
*/
template<typename It, typename... Args>
// NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward)
void insert(It first, It last, Args &&...) {
template<typename It>
void insert(It first, It last) {
for(; first != last; ++first) {
base_type::try_emplace(*first, true);
}
@@ -1069,22 +1060,20 @@ public:
* @brief Move constructor.
* @param other The instance to move from.
*/
// NOLINTBEGIN(bugprone-use-after-move)
// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
basic_storage(basic_storage &&other) noexcept
: base_type{std::move(other)},
: base_type{static_cast<base_type &&>(other)},
placeholder{other.placeholder} {}
// NOLINTEND(bugprone-use-after-move)
/**
* @brief Allocator-extended move constructor.
* @param other The instance to move from.
* @param allocator The allocator to use.
*/
// NOLINTBEGIN(bugprone-use-after-move)
// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
basic_storage(basic_storage &&other, const allocator_type &allocator)
: base_type{std::move(other), allocator},
: base_type{static_cast<base_type &&>(other), allocator},
placeholder{other.placeholder} {}
// NOLINTEND(bugprone-use-after-move)
/*! @brief Default destructor. */
~basic_storage() override = default;
@@ -1106,6 +1095,16 @@ public:
return *this;
}
/**
* @brief Exchanges the contents with those of a given storage.
* @param other Storage to exchange the content with.
*/
void swap(basic_storage &other) noexcept {
using std::swap;
swap(placeholder, other.placeholder);
base_type::swap(other);
}
/**
* @brief Returns the object assigned to an entity, that is `void`.
*
@@ -1175,27 +1174,6 @@ public:
}
}
/**
* @brief Creates a new identifier or recycles a destroyed one.
* @return A valid identifier.
*/
[[deprecated("use ::generate() instead")]] entity_type emplace() {
return generate();
}
/**
* @brief Creates a new identifier or recycles a destroyed one.
*
* If the requested identifier isn't in use, the suggested one is used.
* Otherwise, a new identifier is returned.
*
* @param hint Required identifier.
* @return A valid identifier.
*/
[[deprecated("use ::generate(hint) instead")]] entity_type emplace(const entity_type hint) {
return generate(hint);
}
/**
* @brief Updates a given identifier.
* @tparam Func Types of the function objects to invoke.
@@ -1208,17 +1186,6 @@ public:
(std::forward<Func>(func)(), ...);
}
/**
* @brief Assigns each element in a range an identifier.
* @tparam It Type of mutable forward iterator.
* @param first An iterator to the first element of the range to generate.
* @param last An iterator past the last element of the range to generate.
*/
template<typename It>
[[deprecated("use ::generate(first, last) instead")]] void insert(It first, It last) {
generate(std::move(first), std::move(last));
}
/**
* @brief Returns an iterable object to use to _visit_ a storage.
*
-1
View File
@@ -10,7 +10,6 @@ namespace entt {}
#include "container/table.hpp"
#include "core/algorithm.hpp"
#include "core/any.hpp"
#include "core/attribute.h"
#include "core/bit.hpp"
#include "core/compressed_pair.hpp"
#include "core/enum.hpp"
+41 -54
View File
@@ -4,6 +4,7 @@
#define ENTT_META_CONTAINER_HPP
#include <array>
#include <cstddef>
#include <deque>
#include <iterator>
#include <list>
@@ -15,7 +16,9 @@
#include <vector>
#include "../container/dense_map.hpp"
#include "../container/dense_set.hpp"
#include "../core/type_traits.hpp"
#include "context.hpp"
#include "fwd.hpp"
#include "meta.hpp"
#include "type_traits.hpp"
@@ -24,14 +27,14 @@ namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename, typename = void>
struct fixed_size_sequence_container: std::true_type {};
template<typename Type, typename = void>
struct sequence_container_extent: integral_constant<meta_dynamic_extent> {};
template<typename Type>
struct fixed_size_sequence_container<Type, std::void_t<decltype(&Type::clear)>>: std::false_type {};
struct sequence_container_extent<Type, std::enable_if_t<is_complete_v<std::tuple_size<Type>>>>: integral_constant<std::tuple_size_v<Type>> {};
template<typename Type>
inline constexpr bool fixed_size_sequence_container_v = fixed_size_sequence_container<Type>::value;
inline constexpr std::size_t sequence_container_extent_v = sequence_container_extent<Type>::value;
template<typename, typename = void>
struct key_only_associative_container: std::true_type {};
@@ -60,15 +63,17 @@ inline constexpr bool reserve_aware_container_v = reserve_aware_container<Type>:
*/
template<typename Type>
struct basic_meta_sequence_container_traits {
static_assert(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>, "Unexpected type");
static_assert(std::is_same_v<Type, std::remove_const_t<std::remove_reference_t<Type>>>, "Unexpected type");
/*! @brief Unsigned integer type. */
using size_type = typename meta_sequence_container::size_type;
/*! @brief Meta iterator type. */
using iterator = typename meta_sequence_container::iterator;
/*! @brief True in case of key-only containers, false otherwise. */
static constexpr bool fixed_size = internal::fixed_size_sequence_container_v<Type>;
/*! @brief Number of elements, or `meta_dynamic_extent` if dynamic. */
static constexpr std::size_t extent = internal::sequence_container_extent_v<Type>;
/*! @brief True in case of fixed size containers, false otherwise. */
[[deprecated("use ::extent instead")]] static constexpr bool fixed_size = (extent != meta_dynamic_extent);
/**
* @brief Returns the number of elements in a container.
@@ -85,11 +90,11 @@ struct basic_meta_sequence_container_traits {
* @return True in case of success, false otherwise.
*/
[[nodiscard]] static bool clear([[maybe_unused]] void *container) {
if constexpr(fixed_size) {
return false;
} else {
if constexpr(extent == meta_dynamic_extent) {
static_cast<Type *>(container)->clear();
return true;
} else {
return false;
}
}
@@ -115,36 +120,27 @@ struct basic_meta_sequence_container_traits {
* @return True in case of success, false otherwise.
*/
[[nodiscard]] static bool resize([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) {
if constexpr(fixed_size || !std::is_default_constructible_v<typename Type::value_type>) {
return false;
} else {
if constexpr((extent == meta_dynamic_extent) && std::is_default_constructible_v<typename Type::value_type>) {
static_cast<Type *>(container)->resize(sz);
return true;
} else {
return false;
}
}
/**
* @brief Returns a possibly const iterator to the beginning.
* @brief Returns a possibly const iterator to the beginning or the end.
* @param area The context to pass to the newly created iterator.
* @param container Opaque pointer to a container of the given type.
* @param as_const Const opaque pointer fallback.
* @return An iterator to the first element of the container.
* @param end False to get a pointer that is past the last element.
* @return An iterator to the first or past the last element of the
* container.
*/
static iterator begin(const meta_ctx &area, void *container, const void *as_const) {
return (container != nullptr) ? iterator{area, static_cast<Type *>(container)->begin()}
: iterator{area, static_cast<const Type *>(as_const)->begin()};
}
/**
* @brief Returns a possibly const iterator to the end.
* @param area The context to pass to the newly created iterator.
* @param container Opaque pointer to a container of the given type.
* @param as_const Const opaque pointer fallback.
* @return An iterator that is past the last element of the container.
*/
static iterator end(const meta_ctx &area, void *container, const void *as_const) {
return (container != nullptr) ? iterator{area, static_cast<Type *>(container)->end()}
: iterator{area, static_cast<const Type *>(as_const)->end()};
static iterator iter(const meta_ctx &area, void *container, const void *as_const, const bool end) {
return (container == nullptr)
? iterator{area, end ? static_cast<const Type *>(as_const)->cend() : static_cast<const Type *>(as_const)->cbegin()}
: iterator{area, end ? static_cast<Type *>(container)->end() : static_cast<Type *>(container)->begin()};
}
/**
@@ -160,13 +156,13 @@ struct basic_meta_sequence_container_traits {
* @return A possibly invalid iterator to the inserted element.
*/
[[nodiscard]] static iterator insert([[maybe_unused]] const meta_ctx &area, [[maybe_unused]] void *container, [[maybe_unused]] const void *value, [[maybe_unused]] const void *cref, [[maybe_unused]] const iterator &it) {
if constexpr(fixed_size) {
return iterator{};
} else {
if constexpr(extent == meta_dynamic_extent) {
auto *const non_const = any_cast<typename Type::iterator>(&it.base());
return {area, static_cast<Type *>(container)->insert(
non_const ? *non_const : any_cast<const typename Type::const_iterator &>(it.base()),
(value != nullptr) ? *static_cast<const typename Type::value_type *>(value) : *static_cast<const std::remove_reference_t<typename Type::const_reference> *>(cref))};
} else {
return iterator{};
}
}
@@ -178,11 +174,11 @@ struct basic_meta_sequence_container_traits {
* @return A possibly invalid iterator following the last removed element.
*/
[[nodiscard]] static iterator erase([[maybe_unused]] const meta_ctx &area, [[maybe_unused]] void *container, [[maybe_unused]] const iterator &it) {
if constexpr(fixed_size) {
return iterator{};
} else {
if constexpr(extent == meta_dynamic_extent) {
auto *const non_const = any_cast<typename Type::iterator>(&it.base());
return {area, static_cast<Type *>(container)->erase(non_const ? *non_const : any_cast<const typename Type::const_iterator &>(it.base()))};
} else {
return iterator{};
}
}
};
@@ -193,7 +189,7 @@ struct basic_meta_sequence_container_traits {
*/
template<typename Type>
struct basic_meta_associative_container_traits {
static_assert(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>, "Unexpected type");
static_assert(std::is_same_v<Type, std::remove_const_t<std::remove_reference_t<Type>>>, "Unexpected type");
/*! @brief Unsigned integer type. */
using size_type = typename meta_associative_container::size_type;
@@ -238,27 +234,18 @@ struct basic_meta_associative_container_traits {
}
/**
* @brief Returns a possibly const iterator to the beginning.
* @brief Returns a possibly const iterator to the beginning or the end.
* @param area The context to pass to the newly created iterator.
* @param container Opaque pointer to a container of the given type.
* @param as_const Const opaque pointer fallback.
* @return An iterator to the first element of the container.
* @param end False to get a pointer that is past the last element.
* @return An iterator to the first or past the last element of the
* container.
*/
static iterator begin(const meta_ctx &area, void *container, const void *as_const) {
return (container != nullptr) ? iterator{area, std::bool_constant<key_only>{}, static_cast<Type *>(container)->begin()}
: iterator{area, std::bool_constant<key_only>{}, static_cast<const Type *>(as_const)->begin()};
}
/**
* @brief Returns a possibly const iterator to the end.
* @param area The context to pass to the newly created iterator.
* @param container Opaque pointer to a container of the given type.
* @param as_const Const opaque pointer fallback.
* @return An iterator that is past the last element of the container.
*/
static iterator end(const meta_ctx &area, void *container, const void *as_const) {
return (container != nullptr) ? iterator{area, std::bool_constant<key_only>{}, static_cast<Type *>(container)->end()}
: iterator{area, std::bool_constant<key_only>{}, static_cast<const Type *>(as_const)->end()};
static iterator iter(const meta_ctx &area, void *container, const void *as_const, const bool end) {
return (container == nullptr)
? iterator{area, std::bool_constant<key_only>{}, end ? static_cast<const Type *>(as_const)->cend() : static_cast<const Type *>(as_const)->cbegin()}
: iterator{area, std::bool_constant<key_only>{}, end ? static_cast<Type *>(container)->end() : static_cast<Type *>(container)->begin()};
}
/**
+5 -5
View File
@@ -1,24 +1,24 @@
#ifndef ENTT_META_CTX_HPP
#define ENTT_META_CTX_HPP
#include <memory>
#include "../container/dense_map.hpp"
#include "../core/fwd.hpp"
#include "../core/utility.hpp"
#include "fwd.hpp"
namespace entt {
class meta_ctx;
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
struct meta_type_node;
struct meta_context {
dense_map<id_type, meta_type_node, identity> value;
dense_map<id_type, std::unique_ptr<meta_type_node>, identity> value;
[[nodiscard]] inline static meta_context &from(meta_ctx &ctx);
[[nodiscard]] inline static const meta_context &from(const meta_ctx &ctx);
[[nodiscard]] inline static meta_context &from(meta_ctx &);
[[nodiscard]] inline static const meta_context &from(const meta_ctx &);
};
} // namespace internal
+118 -152
View File
@@ -11,10 +11,12 @@
#include "../config/config.h"
#include "../core/bit.hpp"
#include "../core/fwd.hpp"
#include "../core/hashed_string.hpp"
#include "../core/type_info.hpp"
#include "../core/type_traits.hpp"
#include "../locator/locator.hpp"
#include "context.hpp"
#include "fwd.hpp"
#include "meta.hpp"
#include "node.hpp"
#include "policy.hpp"
@@ -30,14 +32,18 @@ namespace internal {
class basic_meta_factory {
using invoke_type = std::remove_pointer_t<decltype(meta_func_node::invoke)>;
auto *find_member_or_assert() {
auto *member = find_member<&meta_data_node::id>(details->data, bucket);
[[nodiscard]] auto &fetch_node() noexcept {
return *meta_context::from(*ctx).value[parent];
}
[[nodiscard]] auto *find_member_or_assert() {
auto *member = find_member<&meta_data_node::id>(fetch_node().details->data, bucket);
ENTT_ASSERT(member != nullptr, "Cannot find member");
return member;
}
auto *find_overload_or_assert() {
auto *overload = find_overload(find_member<&meta_func_node::id>(details->func, bucket), invoke);
[[nodiscard]] auto *find_overload_or_assert() {
auto *overload = find_overload(find_member<&meta_func_node::id>(fetch_node().details->func, bucket), invoke);
ENTT_ASSERT(overload != nullptr, "Cannot find overload");
return overload;
}
@@ -48,69 +54,75 @@ class basic_meta_factory {
}
protected:
void type(const id_type id) noexcept {
void type(const id_type id, const char *name) noexcept {
reset_bucket(parent);
auto &&elem = meta_context::from(*ctx).value[parent];
auto &elem = fetch_node();
ENTT_ASSERT(elem.id == id || !resolve(*ctx, id), "Duplicate identifier");
elem.name = name;
elem.id = id;
}
template<typename Type>
void insert_or_assign(Type node) {
auto &elem = fetch_node();
reset_bucket(parent);
if constexpr(std::is_same_v<Type, meta_base_node>) {
auto *member = find_member<&meta_base_node::type>(details->base, node.type);
member ? (*member = node) : details->base.emplace_back(node);
auto *member = find_member<&meta_base_node::type>(elem.details->base, node.type);
member ? (*member = node) : elem.details->base.emplace_back(node);
} else if constexpr(std::is_same_v<Type, meta_conv_node>) {
auto *member = find_member<&meta_conv_node::type>(details->conv, node.type);
member ? (*member = node) : details->conv.emplace_back(node);
auto *member = find_member<&meta_conv_node::type>(elem.details->conv, node.type);
member ? (*member = node) : elem.details->conv.emplace_back(node);
} else {
static_assert(std::is_same_v<Type, meta_ctor_node>, "Unexpected type");
auto *member = find_member<&meta_ctor_node::id>(details->ctor, node.id);
member ? (*member = node) : details->ctor.emplace_back(node);
auto *member = find_member<&meta_ctor_node::id>(elem.details->ctor, node.id);
member ? (*member = node) : elem.details->ctor.emplace_back(node);
}
}
void dtor(meta_dtor_node node) {
reset_bucket(parent);
meta_context::from(*ctx).value[parent].dtor = node;
}
void data(meta_data_node node) {
auto &elem = fetch_node();
reset_bucket(node.id);
if(auto *member = find_member<&meta_data_node::id>(details->data, node.id); member == nullptr) {
details->data.emplace_back(std::move(node));
if(auto *member = find_member<&meta_data_node::id>(elem.details->data, node.id); member == nullptr) {
elem.details->data.emplace_back(std::move(node));
} else if(member->set != node.set || member->get != node.get) {
*member = std::move(node);
}
}
void func(meta_func_node node) {
auto &elem = fetch_node();
reset_bucket(node.id, node.invoke);
if(auto *member = find_member<&meta_func_node::id>(details->func, node.id); member == nullptr) {
details->func.emplace_back(std::move(node));
if(auto *member = find_member<&meta_func_node::id>(elem.details->func, node.id); member == nullptr) {
elem.details->func.emplace_back(std::move(node));
} else if(auto *overload = find_overload(member, node.invoke); overload == nullptr) {
while(member->next != nullptr) { member = member->next.get(); }
member->next = std::make_shared<meta_func_node>(std::move(node));
member->next = std::make_unique<meta_func_node>(std::move(node));
}
}
void traits(const meta_traits value) {
void traits(const meta_traits value, const bool unset) {
auto set_or_unset_on = [=](auto &node) {
node.traits = (unset ? (node.traits & ~value) : (node.traits | value));
};
if(bucket == parent) {
meta_context::from(*ctx).value[bucket].traits |= value;
set_or_unset_on(fetch_node());
} else if(invoke == nullptr) {
find_member_or_assert()->traits |= value;
set_or_unset_on(*find_member_or_assert());
} else {
find_overload_or_assert()->traits |= value;
set_or_unset_on(*find_overload_or_assert());
}
}
void custom(meta_custom_node node) {
if(bucket == parent) {
meta_context::from(*ctx).value[bucket].custom = std::move(node);
fetch_node().custom = std::move(node);
} else if(invoke == nullptr) {
find_member_or_assert()->custom = std::move(node);
} else {
@@ -122,12 +134,9 @@ public:
basic_meta_factory(meta_ctx &area, meta_type_node node)
: ctx{&area},
parent{node.info->hash()},
bucket{parent},
details{node.details.get()} {
if(details == nullptr) {
node.details = std::make_shared<meta_type_descriptor>();
meta_context::from(*ctx).value[parent] = node;
details = node.details.get();
bucket{parent} {
if(auto *curr = meta_context::from(*ctx).value.try_emplace(parent, std::make_unique<meta_type_node>(std::move(node))).first->second.get(); curr->details == nullptr) {
curr->details = std::make_unique<meta_type_descriptor>();
}
}
@@ -136,7 +145,6 @@ private:
id_type parent{};
id_type bucket{};
invoke_type *invoke{};
meta_type_descriptor *details{};
};
} // namespace internal
@@ -144,32 +152,16 @@ private:
/**
* @brief Meta factory to be used for reflection purposes.
* @tparam Type Reflected type for which the factory was created.
* @tparam Type Type for which the factory was created.
*/
template<typename Type>
class meta_factory: private internal::basic_meta_factory {
using base_type = internal::basic_meta_factory;
template<typename Setter, auto Getter, typename Policy, std::size_t... Index>
[[deprecated("use variant types or conversion support")]]
void data(const id_type id, std::index_sequence<Index...>) noexcept {
using data_type = std::invoke_result_t<decltype(Getter), Type &>;
using args_type = type_list<typename meta_function_helper_t<Type, decltype(value_list_element_v<Index, Setter>)>::args_type...>;
static_assert(Policy::template value<data_type>, "Invalid return type for the given policy");
base_type::data(
internal::meta_data_node{
id,
/* this is never static */
(std::is_member_object_pointer_v<decltype(value_list_element_v<Index, Setter>)> && ... && std::is_const_v<std::remove_reference_t<data_type>>) ? internal::meta_traits::is_const : internal::meta_traits::is_none,
Setter::size,
&internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
&meta_arg<type_list<type_list_element_t<static_cast<std::size_t>(type_list_element_t<Index, args_type>::size != 1u), type_list_element_t<Index, args_type>>...>>,
+[](meta_handle instance, meta_any value) { return (meta_setter<Type, value_list_element_v<Index, Setter>>(*instance.operator->(), value.as_ref()) || ...); },
&meta_getter<Type, Getter, Policy>});
}
public:
/*! @brief Type of object for which this factory builds a meta type. */
using element_type = Type;
/*! @brief Default constructor. */
meta_factory() noexcept
: meta_factory{locator<meta_ctx>::value_or()} {}
@@ -179,15 +171,25 @@ public:
* @param area The context into which to construct meta types.
*/
meta_factory(meta_ctx &area) noexcept
: internal::basic_meta_factory{area, internal::resolve<Type>(internal::meta_context::from(area))} {}
: internal::basic_meta_factory{area, internal::setup_node_for<Type>()} {}
/**
* @brief Assigns a custom unique identifier to a meta type.
* @param name A custom unique identifier as a **string literal**.
* @return A meta factory for the given type.
*/
meta_factory type(const char *name) noexcept {
return type(hashed_string::value(name), name);
}
/**
* @brief Assigns a custom unique identifier to a meta type.
* @param id A custom unique identifier.
* @param name An optional name for the type as a **string literal**.
* @return A meta factory for the given type.
*/
meta_factory type(const id_type id) noexcept {
base_type::type(id);
meta_factory type(const id_type id, const char *name = nullptr) noexcept {
base_type::type(id, name);
return *this;
}
@@ -221,7 +223,7 @@ public:
*/
template<auto Candidate>
auto conv() noexcept {
using conv_type = std::remove_cv_t<std::remove_reference_t<std::invoke_result_t<decltype(Candidate), Type &>>>;
using conv_type = std::remove_const_t<std::remove_reference_t<std::invoke_result_t<decltype(Candidate), Type &>>>;
auto *const op = +[](const meta_ctx &area, const void *instance) { return forward_as_meta(area, std::invoke(Candidate, *static_cast<const Type *>(instance))); };
base_type::insert_or_assign(internal::meta_conv_node{type_id<conv_type>().hash(), op});
return *this;
@@ -238,7 +240,7 @@ public:
*/
template<typename To>
meta_factory conv() noexcept {
using conv_type = std::remove_cv_t<std::remove_reference_t<To>>;
using conv_type = std::remove_const_t<std::remove_reference_t<To>>;
auto *const op = +[](const meta_ctx &area, const void *instance) { return forward_as_meta(area, static_cast<To>(*static_cast<const Type *>(instance))); };
base_type::insert_or_assign(internal::meta_conv_node{type_id<conv_type>().hash(), op});
return *this;
@@ -257,11 +259,11 @@ public:
* @tparam Policy Optional policy (no policy set by default).
* @return A meta factory for the parent type.
*/
template<auto Candidate, typename Policy = as_is_t>
template<auto Candidate, typename Policy = as_value_t>
meta_factory ctor() noexcept {
using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
static_assert(Policy::template value<typename descriptor::return_type>, "Invalid return type for the given policy");
static_assert(std::is_same_v<std::remove_cv_t<std::remove_reference_t<typename descriptor::return_type>>, Type>, "The function doesn't return an object of the required type");
static_assert(std::is_same_v<std::remove_const_t<std::remove_reference_t<typename descriptor::return_type>>, Type>, "The function doesn't return an object of the required type");
base_type::insert_or_assign(internal::meta_ctor_node{type_id<typename descriptor::args_type>().hash(), descriptor::args_type::size, &meta_arg<typename descriptor::args_type>, &meta_construct<Type, Candidate, Policy>});
return *this;
}
@@ -288,29 +290,15 @@ public:
}
/**
* @brief Assigns a meta destructor to a meta type.
*
* Both free functions and member functions can be assigned to meta types in
* the role of destructors.<br/>
* The signature of a free function should be identical to the following:
*
* @code{.cpp}
* void(Type &);
* @endcode
*
* Member functions should not take arguments instead.<br/>
* The purpose is to give users the ability to free up resources that
* require special treatment before an object is actually destroyed.
*
* @tparam Func The actual function to use as a destructor.
* @return A meta factory for the parent type.
* @brief Assigns a meta data to a meta type.
* @tparam Data The actual variable to attach to the meta type.
* @tparam Policy Optional policy (no policy set by default).
* @param name A custom unique identifier as a **string literal**.
* @return A meta factory for the given type.
*/
template<auto Func>
meta_factory dtor() noexcept {
static_assert(std::is_invocable_v<decltype(Func), Type &>, "The function doesn't accept an object of the type provided");
auto *const op = +[](void *instance) { std::invoke(Func, *static_cast<Type *>(instance)); };
base_type::dtor(internal::meta_dtor_node{op});
return *this;
template<auto Data, typename Policy = as_value_t>
meta_factory data(const char *name) noexcept {
return data<Data, Policy>(hashed_string::value(name), name);
}
/**
@@ -324,10 +312,11 @@ public:
* @tparam Data The actual variable to attach to the meta type.
* @tparam Policy Optional policy (no policy set by default).
* @param id Unique identifier.
* @param name An optional name for the meta data as a **string literal**.
* @return A meta factory for the parent type.
*/
template<auto Data, typename Policy = as_is_t>
meta_factory data(const id_type id) noexcept {
template<auto Data, typename Policy = as_value_t>
meta_factory data(const id_type id, const char *name = nullptr) noexcept {
if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
using data_type = std::invoke_result_t<decltype(Data), Type &>;
static_assert(Policy::template value<data_type>, "Invalid return type for the given policy");
@@ -335,11 +324,12 @@ public:
base_type::data(
internal::meta_data_node{
id,
name,
/* this is never static */
std::is_const_v<std::remove_reference_t<data_type>> ? internal::meta_traits::is_const : internal::meta_traits::is_none,
1u,
&internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
&meta_arg<type_list<std::remove_cv_t<std::remove_reference_t<data_type>>>>,
&internal::resolve<std::remove_const_t<std::remove_reference_t<data_type>>>,
&meta_arg<type_list<std::remove_const_t<std::remove_reference_t<data_type>>>>,
&meta_setter<Type, Data>,
&meta_getter<Type, Data, Policy>});
} else {
@@ -354,10 +344,11 @@ public:
base_type::data(
internal::meta_data_node{
id,
name,
((!std::is_pointer_v<decltype(Data)> || std::is_const_v<data_type>) ? internal::meta_traits::is_const : internal::meta_traits::is_none) | internal::meta_traits::is_static,
1u,
&internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
&meta_arg<type_list<std::remove_cv_t<std::remove_reference_t<data_type>>>>,
&internal::resolve<std::remove_const_t<std::remove_reference_t<data_type>>>,
&meta_arg<type_list<std::remove_const_t<std::remove_reference_t<data_type>>>>,
&meta_setter<Type, Data>,
&meta_getter<Type, Data, Policy>});
}
@@ -365,6 +356,20 @@ public:
return *this;
}
/**
* @brief Assigns a meta data to a meta type by means of its setter and
* getter.
* @tparam Setter The actual function to use as a setter.
* @tparam Getter The actual function to use as a getter.
* @tparam Policy Optional policy (no policy set by default).
* @param name A custom unique identifier as a **string literal**.
* @return A meta factory for the given type.
*/
template<auto Setter, auto Getter, typename Policy = as_value_t>
meta_factory data(const char *name) noexcept {
return data<Setter, Getter, Policy>(hashed_string::value(name), name);
}
/**
* @brief Assigns a meta data to a meta type by means of its setter and
* getter.
@@ -383,10 +388,11 @@ public:
* @tparam Getter The actual function to use as a getter.
* @tparam Policy Optional policy (no policy set by default).
* @param id Unique identifier.
* @param name An optional name for the meta data as a **string literal**.
* @return A meta factory for the parent type.
*/
template<auto Setter, auto Getter, typename Policy = as_is_t>
meta_factory data(const id_type id) noexcept {
template<auto Setter, auto Getter, typename Policy = as_value_t>
meta_factory data(const id_type id, const char *name = nullptr) noexcept {
using descriptor = meta_function_helper_t<Type, decltype(Getter)>;
static_assert(Policy::template value<typename descriptor::return_type>, "Invalid return type for the given policy");
@@ -394,10 +400,11 @@ public:
base_type::data(
internal::meta_data_node{
id,
name,
/* this is never static */
internal::meta_traits::is_const,
0u,
&internal::resolve<std::remove_cv_t<std::remove_reference_t<typename descriptor::return_type>>>,
&internal::resolve<std::remove_const_t<std::remove_reference_t<typename descriptor::return_type>>>,
&meta_arg<type_list<>>,
&meta_setter<Type, Setter>,
&meta_getter<Type, Getter, Policy>});
@@ -407,10 +414,11 @@ public:
base_type::data(
internal::meta_data_node{
id,
name,
/* this is never static nor const */
internal::meta_traits::is_none,
1u,
&internal::resolve<std::remove_cv_t<std::remove_reference_t<typename descriptor::return_type>>>,
&internal::resolve<std::remove_const_t<std::remove_reference_t<typename descriptor::return_type>>>,
&meta_arg<type_list<type_list_element_t<static_cast<std::size_t>(args_type::size != 1u), args_type>>>,
&meta_setter<Type, Setter>,
&meta_getter<Type, Getter, Policy>});
@@ -420,27 +428,15 @@ public:
}
/**
* @brief Assigns a meta data to a meta type by means of its setters and
* getter.
*
* Multi-setter support for meta data members. All setters are tried in the
* order of definition before returning to the caller.<br/>
* Setters can be either free functions, member functions or a mix of them
* and are provided via a `value_list` type.
*
* @sa data
*
* @tparam Setter The actual functions to use as setters.
* @tparam Getter The actual getter function.
* @brief Assigns a meta function to a meta type.
* @tparam Candidate The actual function to attach to the meta function.
* @tparam Policy Optional policy (no policy set by default).
* @param id Unique identifier.
* @return A meta factory for the parent type.
* @param name A custom unique identifier as a **string literal**.
* @return A meta factory for the given type.
*/
template<typename Setter, auto Getter, typename Policy = as_is_t>
[[deprecated("use variant types or conversion support")]]
meta_factory data(const id_type id) noexcept {
data<Setter, Getter, Policy>(id, std::make_index_sequence<Setter::size>{});
return *this;
template<auto Candidate, typename Policy = as_value_t>
meta_factory func(const char *name) noexcept {
return func<Candidate, Policy>(hashed_string::value(name), name);
}
/**
@@ -454,19 +450,21 @@ public:
* @tparam Candidate The actual function to attach to the meta type.
* @tparam Policy Optional policy (no policy set by default).
* @param id Unique identifier.
* @param name An optional name for the function as a **string literal**.
* @return A meta factory for the parent type.
*/
template<auto Candidate, typename Policy = as_is_t>
meta_factory func(const id_type id) noexcept {
template<auto Candidate, typename Policy = as_value_t>
meta_factory func(const id_type id, const char *name = nullptr) noexcept {
using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
static_assert(Policy::template value<typename descriptor::return_type>, "Invalid return type for the given policy");
base_type::func(
internal::meta_func_node{
id,
name,
(descriptor::is_const ? internal::meta_traits::is_const : internal::meta_traits::is_none) | (descriptor::is_static ? internal::meta_traits::is_static : internal::meta_traits::is_none),
descriptor::args_type::size,
&internal::resolve<std::conditional_t<std::is_same_v<Policy, as_void_t>, void, std::remove_cv_t<std::remove_reference_t<typename descriptor::return_type>>>>,
&internal::resolve<std::conditional_t<std::is_same_v<Policy, as_void_t>, void, std::remove_const_t<std::remove_reference_t<typename descriptor::return_type>>>>,
&meta_arg<typename descriptor::args_type>,
&meta_invoke<Type, Candidate, Policy>});
@@ -480,12 +478,13 @@ public:
*
* @tparam Value Type of the traits value.
* @param value Traits value.
* @param unset True to unset the given traits, false otherwise.
* @return A meta factory for the parent type.
*/
template<typename Value>
meta_factory traits(const Value value) {
meta_factory traits(const Value value, const bool unset = false) {
static_assert(std::is_enum_v<Value>, "Invalid enum type");
base_type::traits(internal::user_to_meta_traits(value));
base_type::traits(internal::user_to_meta_traits(value), unset);
return *this;
}
@@ -503,39 +502,6 @@ public:
}
};
/**
* @brief Utility function to use for reflection.
*
* This is the point from which everything starts.<br/>
* By invoking this function with a type that is not yet reflected, a meta type
* is created to which it will be possible to attach meta objects through a
* dedicated factory.
*
* @tparam Type Type to reflect.
* @param ctx The context into which to construct meta types.
* @return A meta factory for the given type.
*/
template<typename Type>
[[nodiscard]] [[deprecated("use meta_factory directly instead")]] auto meta(meta_ctx &ctx) noexcept {
return meta_factory<Type>{ctx};
}
/**
* @brief Utility function to use for reflection.
*
* This is the point from which everything starts.<br/>
* By invoking this function with a type that is not yet reflected, a meta type
* is created to which it will be possible to attach meta objects through a
* dedicated factory.
*
* @tparam Type Type to reflect.
* @return A meta factory for the given type.
*/
template<typename Type>
[[nodiscard]] [[deprecated("use meta_factory directly instead")]] auto meta() noexcept {
return meta<Type>(locator<meta_ctx>::value_or());
}
/**
* @brief Resets a type and all its parts.
*
@@ -549,10 +515,10 @@ template<typename Type>
* @param ctx The context from which to reset meta types.
*/
inline void meta_reset(meta_ctx &ctx, const id_type id) noexcept {
auto &&context = internal::meta_context::from(ctx);
auto &context = internal::meta_context::from(ctx);
for(auto it = context.value.begin(); it != context.value.end();) {
if(it->second.id == id) {
if(it->second->id == id) {
it = context.value.erase(it);
} else {
++it;
+14 -3
View File
@@ -1,24 +1,35 @@
#ifndef ENTT_META_FWD_HPP
#define ENTT_META_FWD_HPP
#include <cstddef>
#include <limits>
namespace entt {
class meta_ctx;
class meta_sequence_container;
class meta_associative_container;
class meta_any;
struct meta_handle;
class meta_handle;
struct meta_custom;
struct meta_data;
class meta_data;
struct meta_func;
class meta_func;
class meta_type;
template<typename>
class meta_factory;
/*! @brief Used to identicate that a sequence container has not a fixed size. */
inline constexpr std::size_t meta_dynamic_extent = (std::numeric_limits<std::size_t>::max)();
} // namespace entt
#endif
+377 -360
View File
File diff suppressed because it is too large Load Diff
+52 -85
View File
@@ -1,13 +1,13 @@
#ifndef ENTT_META_NODE_HPP
#define ENTT_META_NODE_HPP
#include <array>
#include <cstddef>
#include <memory>
#include <type_traits>
#include <utility>
#include <vector>
#include "../config/config.h"
#include "../core/attribute.h"
#include "../core/bit.hpp"
#include "../core/enum.hpp"
#include "../core/fwd.hpp"
@@ -21,7 +21,7 @@ namespace entt {
class meta_any;
class meta_type;
struct meta_handle;
class meta_handle;
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
@@ -64,12 +64,12 @@ struct meta_type_node;
struct meta_custom_node {
id_type type{};
std::shared_ptr<void> value;
std::shared_ptr<void> value{};
};
struct meta_base_node {
id_type type{};
meta_type_node (*resolve)(const meta_context &) noexcept {};
const meta_type_node &(*resolve)(const meta_context &) noexcept {};
const void *(*cast)(const void *) noexcept {};
};
@@ -87,17 +87,14 @@ struct meta_ctor_node {
meta_any (*invoke)(const meta_ctx &, meta_any *const){};
};
struct meta_dtor_node {
void (*dtor)(void *){};
};
struct meta_data_node {
using size_type = std::size_t;
id_type id{};
const char *name{};
meta_traits traits{meta_traits::is_none};
size_type arity{0u};
meta_type_node (*type)(const meta_context &) noexcept {};
const meta_type_node &(*type)(const meta_context &) noexcept {};
meta_type (*arg)(const meta_ctx &, const size_type) noexcept {};
bool (*set)(meta_handle, meta_any){};
meta_any (*get)(meta_handle){};
@@ -108,12 +105,13 @@ struct meta_func_node {
using size_type = std::size_t;
id_type id{};
const char *name{};
meta_traits traits{meta_traits::is_none};
size_type arity{0u};
meta_type_node (*ret)(const meta_context &) noexcept {};
const meta_type_node &(*ret)(const meta_context &) noexcept {};
meta_type (*arg)(const meta_ctx &, const size_type) noexcept {};
meta_any (*invoke)(meta_handle, meta_any *const){};
std::shared_ptr<meta_func_node> next;
std::unique_ptr<meta_func_node> next;
meta_custom_node custom{};
};
@@ -121,16 +119,16 @@ struct meta_template_node {
using size_type = std::size_t;
size_type arity{0u};
meta_type_node (*resolve)(const meta_context &) noexcept {};
meta_type_node (*arg)(const meta_context &, const size_type) noexcept {};
const meta_type_node &(*resolve)(const meta_context &) noexcept {};
const meta_type_node &(*arg)(const meta_context &, const size_type) noexcept {};
};
struct meta_type_descriptor {
std::vector<meta_ctor_node> ctor;
std::vector<meta_base_node> base;
std::vector<meta_conv_node> conv;
std::vector<meta_data_node> data;
std::vector<meta_func_node> func;
std::vector<meta_ctor_node> ctor{};
std::vector<meta_base_node> base{};
std::vector<meta_conv_node> conv{};
std::vector<meta_data_node> data{};
std::vector<meta_func_node> func{};
};
struct meta_type_node {
@@ -138,17 +136,16 @@ struct meta_type_node {
const type_info *info{};
id_type id{};
const char *name{};
meta_traits traits{meta_traits::is_none};
size_type size_of{0u};
meta_type_node (*resolve)(const meta_context &) noexcept {};
meta_type_node (*remove_pointer)(const meta_context &) noexcept {};
const meta_type_node &(*remove_pointer)(const meta_context &) noexcept {};
meta_any (*default_constructor)(const meta_ctx &){};
double (*conversion_helper)(void *, const void *){};
meta_any (*from_void)(const meta_ctx &, void *, const void *){};
meta_template_node templ{};
meta_dtor_node dtor{};
meta_custom_node custom{};
std::shared_ptr<meta_type_descriptor> details;
std::unique_ptr<meta_type_descriptor> details{};
};
template<auto Member, typename Type, typename Value>
@@ -168,7 +165,7 @@ template<auto Member, typename Type, typename Value>
}
template<auto Member>
[[nodiscard]] auto *look_for(const meta_context &context, const meta_type_node &node, const id_type id) {
[[nodiscard]] auto *look_for(const meta_context &context, const meta_type_node &node, const id_type id, bool recursive) {
using value_type = typename std::remove_reference_t<decltype((node.details.get()->*Member))>::value_type;
if(node.details) {
@@ -176,9 +173,11 @@ template<auto Member>
return member;
}
for(auto &&curr: node.details->base) {
if(auto *elem = look_for<Member>(context, curr.resolve(context), id); elem) {
return elem;
if(recursive) {
for(auto &&curr: node.details->base) {
if(auto *elem = look_for<Member>(context, curr.resolve(context), id, recursive); elem) {
return elem;
}
}
}
}
@@ -187,29 +186,22 @@ template<auto Member>
}
template<typename Type>
meta_type_node resolve(const meta_context &) noexcept;
const meta_type_node &resolve(const meta_context &) noexcept;
template<typename... Args>
[[nodiscard]] auto meta_arg_node(const meta_context &context, type_list<Args...>, [[maybe_unused]] const std::size_t index) noexcept {
meta_type_node (*value)(const meta_context &) noexcept = nullptr;
if constexpr(sizeof...(Args) != 0u) {
std::size_t pos{};
((value = (pos++ == index ? &resolve<std::remove_cv_t<std::remove_reference_t<Args>>> : value)), ...);
}
ENTT_ASSERT(value != nullptr, "Out of bounds");
return value(context);
[[nodiscard]] const meta_type_node &meta_arg_node(const meta_context &context, type_list<Args...>, const std::size_t index) noexcept {
using resolve_type = const meta_type_node &(*)(const meta_context &) noexcept;
constexpr std::array<resolve_type, sizeof...(Args)> list{&resolve<std::remove_const_t<std::remove_reference_t<Args>>>...};
ENTT_ASSERT(index < sizeof...(Args), "Out of bounds");
return list[index](context);
}
[[nodiscard]] inline const void *try_cast(const meta_context &context, const meta_type_node &from, const type_info &to, const void *instance) noexcept {
if((from.info != nullptr) && *from.info == to) {
return instance;
}
[[nodiscard]] inline const void *try_cast(const meta_context &context, const meta_type_node &from, const id_type to, const void *instance) noexcept {
if(from.details) {
for(auto &&curr: from.details->base) {
if(const void *elem = try_cast(context, curr.resolve(context), to, curr.cast(instance)); elem) {
if(const void *other = curr.cast(instance); curr.type == to) {
return other;
} else if(const void *elem = try_cast(context, curr.resolve(context), to, other); elem) {
return elem;
}
}
@@ -218,49 +210,12 @@ template<typename... Args>
return nullptr;
}
template<typename Func>
[[nodiscard]] inline auto try_convert(const meta_context &context, const meta_type_node &from, const type_info &to, const bool arithmetic_or_enum, const void *instance, Func func) {
if(from.info && *from.info == to) {
return func(instance, from);
}
if(from.details) {
for(auto &&elem: from.details->conv) {
if(elem.type == to.hash()) {
return func(instance, elem);
}
}
for(auto &&curr: from.details->base) {
if(auto other = try_convert(context, curr.resolve(context), to, arithmetic_or_enum, curr.cast(instance), func); other) {
return other;
}
}
}
if(from.conversion_helper && arithmetic_or_enum) {
return func(instance, from.conversion_helper);
}
return func(instance);
}
[[nodiscard]] inline const meta_type_node *try_resolve(const meta_context &context, const type_info &info) noexcept {
const auto it = context.value.find(info.hash());
return it != context.value.end() ? &it->second : nullptr;
}
template<typename Type>
[[nodiscard]] meta_type_node resolve(const meta_context &context) noexcept {
static_assert(std::is_same_v<Type, std::remove_const_t<std::remove_reference_t<Type>>>, "Invalid type");
if(auto *elem = try_resolve(context, type_id<Type>()); elem) {
return *elem;
}
auto setup_node_for() noexcept {
meta_type_node node{
&type_id<Type>(),
type_id<Type>().hash(),
nullptr,
(std::is_arithmetic_v<Type> ? meta_traits::is_arithmetic : meta_traits::is_none)
| (std::is_integral_v<Type> ? meta_traits::is_integral : meta_traits::is_none)
| (std::is_signed_v<Type> ? meta_traits::is_signed : meta_traits::is_none)
@@ -272,8 +227,7 @@ template<typename Type>
| (is_complete_v<meta_sequence_container_traits<Type>> ? meta_traits::is_sequence_container : meta_traits::is_none)
| (is_complete_v<meta_associative_container_traits<Type>> ? meta_traits::is_associative_container : meta_traits::is_none),
size_of_v<Type>,
&resolve<Type>,
&resolve<std::remove_cv_t<std::remove_pointer_t<Type>>>};
&resolve<std::remove_const_t<std::remove_pointer_t<Type>>>};
if constexpr(std::is_default_constructible_v<Type>) {
node.default_constructor = +[](const meta_ctx &ctx) {
@@ -310,12 +264,25 @@ template<typename Type>
node.templ = meta_template_node{
meta_template_traits<Type>::args_type::size,
&resolve<typename meta_template_traits<Type>::class_type>,
+[](const meta_context &area, const std::size_t index) noexcept { return meta_arg_node(area, typename meta_template_traits<Type>::args_type{}, index); }};
+[](const meta_context &area, const std::size_t index) noexcept -> decltype(auto) { return meta_arg_node(area, typename meta_template_traits<Type>::args_type{}, index); }};
}
return node;
}
[[nodiscard]] inline const meta_type_node *try_resolve(const meta_context &context, const type_info &info) noexcept {
const auto it = context.value.find(info.hash());
return (it != context.value.end()) ? it->second.get() : nullptr;
}
template<typename Type>
[[nodiscard]] const meta_type_node &resolve(const meta_context &context) noexcept {
static_assert(std::is_same_v<Type, std::remove_const_t<std::remove_reference_t<Type>>>, "Invalid type");
static const meta_type_node node = setup_node_for<Type>();
const auto *elem = try_resolve(context, *node.info);
return (elem == nullptr) ? node : *elem;
}
} // namespace internal
/*! @endcond */
+33 -17
View File
@@ -5,24 +5,16 @@
namespace entt {
/*! @brief Empty class type used to request the _as ref_ policy. */
struct as_ref_t final {
/*! @cond TURN_OFF_DOXYGEN */
template<typename Type>
static constexpr bool value = std::is_reference_v<Type> && !std::is_const_v<std::remove_reference_t<Type>>;
/*! @endcond */
};
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
/*! @brief Empty class type used to request the _as cref_ policy. */
struct as_cref_t final {
/*! @cond TURN_OFF_DOXYGEN */
template<typename Type>
static constexpr bool value = std::is_reference_v<Type>;
/*! @endcond */
};
struct meta_policy {};
} // namespace internal
/*! @endcond */
/*! @brief Empty class type used to request the _as-is_ policy. */
struct as_is_t final {
struct as_value_t final: private internal::meta_policy {
/*! @cond TURN_OFF_DOXYGEN */
template<typename>
static constexpr bool value = true;
@@ -30,7 +22,31 @@ struct as_is_t final {
};
/*! @brief Empty class type used to request the _as void_ policy. */
struct as_void_t final {
struct as_void_t final: private internal::meta_policy {
/*! @cond TURN_OFF_DOXYGEN */
template<typename>
static constexpr bool value = true;
/*! @endcond */
};
/*! @brief Empty class type used to request the _as ref_ policy. */
struct as_ref_t final: private internal::meta_policy {
/*! @cond TURN_OFF_DOXYGEN */
template<typename Type>
static constexpr bool value = std::is_reference_v<Type> && !std::is_const_v<std::remove_reference_t<Type>>;
/*! @endcond */
};
/*! @brief Empty class type used to request the _as cref_ policy. */
struct as_cref_t final: private internal::meta_policy {
/*! @cond TURN_OFF_DOXYGEN */
template<typename Type>
static constexpr bool value = std::is_reference_v<Type>;
/*! @endcond */
};
/*! @brief Empty class type used to request the _as auto_ policy. */
struct as_is_t final: private internal::meta_policy {
/*! @cond TURN_OFF_DOXYGEN */
template<typename>
static constexpr bool value = true;
@@ -44,7 +60,7 @@ struct as_void_t final {
*/
template<typename Type>
struct is_meta_policy
: std::bool_constant<std::is_same_v<Type, as_ref_t> || std::is_same_v<Type, as_cref_t> || std::is_same_v<Type, as_is_t> || std::is_same_v<Type, as_void_t>> {};
: std::bool_constant<std::is_base_of_v<internal::meta_policy, Type>> {};
/**
* @brief Helper variable template.
+1 -1
View File
@@ -70,7 +70,7 @@ struct meta_range_iterator final {
[[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept {
if constexpr(std::is_same_v<It, typename decltype(meta_context::value)::const_iterator>) {
return {it[value].first, Type{*ctx, it[value].second}};
return {it[value].first, Type{*ctx, *it[value].second}};
} else if constexpr(std::is_same_v<typename std::iterator_traits<It>::value_type, meta_base_node>) {
return {it[value].type, Type{*ctx, it[value]}};
} else {
+4 -4
View File
@@ -19,8 +19,8 @@ namespace entt {
*/
template<typename Type>
[[nodiscard]] meta_type resolve(const meta_ctx &ctx) noexcept {
auto &&context = internal::meta_context::from(ctx);
return {ctx, internal::resolve<std::remove_cv_t<std::remove_reference_t<Type>>>(context)};
const auto &context = internal::meta_context::from(ctx);
return {ctx, internal::resolve<std::remove_const_t<std::remove_reference_t<Type>>>(context)};
}
/**
@@ -39,7 +39,7 @@ template<typename Type>
* @return An iterable range to use to visit all meta types.
*/
[[nodiscard]] inline meta_range<meta_type, typename decltype(internal::meta_context::value)::const_iterator> resolve(const meta_ctx &ctx) noexcept {
auto &&context = internal::meta_context::from(ctx);
const auto &context = internal::meta_context::from(ctx);
return {{ctx, context.value.cbegin()}, {ctx, context.value.cend()}};
}
@@ -83,7 +83,7 @@ template<typename Type>
* @return The meta type associated with the given type info object, if any.
*/
[[nodiscard]] inline meta_type resolve(const meta_ctx &ctx, const type_info &info) noexcept {
auto &&context = internal::meta_context::from(ctx);
const auto &context = internal::meta_context::from(ctx);
const auto *elem = internal::try_resolve(context, info);
return (elem != nullptr) ? meta_type{ctx, *elem} : meta_type{};
}
+34 -79
View File
@@ -93,11 +93,11 @@ struct meta_function_descriptor<Type, Ret (*)(MaybeType, Args...)>
: meta_function_descriptor_traits<
Ret,
std::conditional_t<
std::is_same_v<std::remove_cv_t<std::remove_reference_t<MaybeType>>, Type> || std::is_base_of_v<std::remove_cv_t<std::remove_reference_t<MaybeType>>, Type>,
std::is_same_v<std::remove_const_t<std::remove_reference_t<MaybeType>>, Type> || std::is_base_of_v<std::remove_const_t<std::remove_reference_t<MaybeType>>, Type>,
type_list<Args...>,
type_list<MaybeType, Args...>>,
!(std::is_same_v<std::remove_cv_t<std::remove_reference_t<MaybeType>>, Type> || std::is_base_of_v<std::remove_cv_t<std::remove_reference_t<MaybeType>>, Type>),
std::is_const_v<std::remove_reference_t<MaybeType>> && (std::is_same_v<std::remove_cv_t<std::remove_reference_t<MaybeType>>, Type> || std::is_base_of_v<std::remove_cv_t<std::remove_reference_t<MaybeType>>, Type>)> {};
!(std::is_same_v<std::remove_const_t<std::remove_reference_t<MaybeType>>, Type> || std::is_base_of_v<std::remove_const_t<std::remove_reference_t<MaybeType>>, Type>),
std::is_const_v<std::remove_reference_t<MaybeType>> && (std::is_same_v<std::remove_const_t<std::remove_reference_t<MaybeType>>, Type> || std::is_base_of_v<std::remove_const_t<std::remove_reference_t<MaybeType>>, Type>)> {};
/**
* @brief Meta function descriptor.
@@ -164,15 +164,15 @@ using meta_function_helper_t = typename meta_function_helper<Type, Candidate>::t
* @param value Value to wrap.
* @return A meta any containing the returned value, if any.
*/
template<typename Policy = as_is_t, typename Type>
template<typename Policy = as_value_t, typename Type>
[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_dispatch(const meta_ctx &ctx, [[maybe_unused]] Type &&value) {
if constexpr(std::is_same_v<Policy, as_void_t>) {
return meta_any{ctx, std::in_place_type<void>};
} else if constexpr(std::is_same_v<Policy, as_ref_t>) {
return meta_any{ctx, std::in_place_type<Type>, value};
} else if constexpr(std::is_same_v<Policy, as_cref_t>) {
if constexpr(std::is_same_v<Policy, as_cref_t>) {
static_assert(std::is_lvalue_reference_v<Type>, "Invalid type");
return meta_any{ctx, std::in_place_type<const std::remove_reference_t<Type> &>, std::as_const(value)};
} else if constexpr(std::is_same_v<Policy, as_ref_t> || (std::is_same_v<Policy, as_is_t> && std::is_lvalue_reference_v<Type>)) {
return meta_any{ctx, std::in_place_type<Type>, value};
} else if constexpr(std::is_same_v<Policy, as_void_t>) {
return meta_any{ctx, std::in_place_type<void>};
} else {
return meta_any{ctx, std::forward<Type>(value)};
}
@@ -185,7 +185,7 @@ template<typename Policy = as_is_t, typename Type>
* @param value Value to wrap.
* @return A meta any containing the returned value, if any.
*/
template<typename Policy = as_is_t, typename Type>
template<typename Policy = as_value_t, typename Type>
[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_dispatch(Type &&value) {
return meta_dispatch<Policy, Type>(locator<meta_ctx>::value_or(), std::forward<Type>(value));
}
@@ -204,26 +204,26 @@ template<typename Policy, typename Candidate, typename... Args>
}
template<typename Type, typename Policy, typename Candidate, std::size_t... Index>
[[nodiscard]] meta_any meta_invoke(meta_handle instance, Candidate &&candidate, [[maybe_unused]] meta_any *const args, std::index_sequence<Index...>) {
[[nodiscard]] meta_any meta_invoke(meta_any &instance, Candidate &&candidate, [[maybe_unused]] meta_any *const args, std::index_sequence<Index...>) {
using descriptor = meta_function_helper_t<Type, std::remove_reference_t<Candidate>>;
// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and std::span)
if constexpr(std::is_invocable_v<std::remove_reference_t<Candidate>, const Type &, type_list_element_t<Index, typename descriptor::args_type>...>) {
if(const auto *const clazz = instance->try_cast<const Type>(); clazz && ((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
return meta_invoke_with_args<Policy>(instance->context(), std::forward<Candidate>(candidate), *clazz, (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
if(const auto *const clazz = instance.try_cast<const Type>(); clazz && ((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
return meta_invoke_with_args<Policy>(instance.context(), std::forward<Candidate>(candidate), *clazz, (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
}
} else if constexpr(std::is_invocable_v<std::remove_reference_t<Candidate>, Type &, type_list_element_t<Index, typename descriptor::args_type>...>) {
if(auto *const clazz = instance->try_cast<Type>(); clazz && ((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
return meta_invoke_with_args<Policy>(instance->context(), std::forward<Candidate>(candidate), *clazz, (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
if(auto *const clazz = instance.try_cast<Type>(); clazz && ((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
return meta_invoke_with_args<Policy>(instance.context(), std::forward<Candidate>(candidate), *clazz, (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
}
} else {
if(((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
return meta_invoke_with_args<Policy>(instance->context(), std::forward<Candidate>(candidate), (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
return meta_invoke_with_args<Policy>(instance.context(), std::forward<Candidate>(candidate), (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
}
}
// NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
return meta_any{meta_ctx_arg, instance->context()};
return meta_any{meta_ctx_arg, instance.context()};
}
template<typename Type, typename... Args, std::size_t... Index>
@@ -248,8 +248,8 @@ template<typename Type, typename... Args, std::size_t... Index>
* @return The meta type of the i-th element of the list of arguments.
*/
template<typename Type>
[[nodiscard]] static meta_type meta_arg(const meta_ctx &ctx, const std::size_t index) noexcept {
auto &&context = internal::meta_context::from(ctx);
[[nodiscard]] meta_type meta_arg(const meta_ctx &ctx, const std::size_t index) noexcept {
const auto &context = internal::meta_context::from(ctx);
return {ctx, internal::meta_arg_node(context, Type{}, index)};
}
@@ -260,7 +260,7 @@ template<typename Type>
* @return The meta type of the i-th element of the list of arguments.
*/
template<typename Type>
[[nodiscard]] static meta_type meta_arg(const std::size_t index) noexcept {
[[nodiscard]] meta_type meta_arg(const std::size_t index) noexcept {
return meta_arg<Type>(locator<meta_ctx>::value_or(), index);
}
@@ -313,10 +313,10 @@ template<typename Type, auto Data>
* @param instance An opaque instance of the underlying type, if required.
* @return A meta any containing the value of the underlying variable.
*/
template<typename Type, auto Data, typename Policy = as_is_t>
template<typename Type, auto Data, typename Policy = as_value_t>
[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_getter(meta_handle instance) {
if constexpr(std::is_member_pointer_v<decltype(Data)> || std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>>) {
if constexpr(!std::is_array_v<std::remove_cv_t<std::remove_reference_t<std::invoke_result_t<decltype(Data), Type &>>>>) {
if constexpr(!std::is_array_v<std::remove_const_t<std::remove_reference_t<std::invoke_result_t<decltype(Data), Type &>>>>) {
if constexpr(std::is_invocable_v<decltype(Data), Type &>) {
if(auto *clazz = instance->try_cast<Type>(); clazz) {
return meta_dispatch<Policy>(instance->context(), std::invoke(Data, *clazz));
@@ -342,20 +342,6 @@ template<typename Type, auto Data, typename Policy = as_is_t>
}
}
/**
* @brief Gets the value of a given variable.
* @tparam Type Reflected type to which the variable is associated.
* @tparam Data The actual variable to get.
* @tparam Policy Optional policy (no policy set by default).
* @param ctx The context from which to search for meta types.
* @param instance An opaque instance of the underlying type, if required.
* @return A meta any containing the value of the underlying variable.
*/
template<typename Type, auto Data, typename Policy = as_is_t>
[[deprecated("a context is no longer required, it is inferred from the meta_handle")]] [[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_getter(const meta_ctx &ctx, meta_handle instance) {
return meta_getter<Type, Data, Policy>(meta_handle{ctx, std::move(instance)});
}
/**
* @brief Tries to _invoke_ an object given a list of erased parameters.
* @tparam Type Reflected type to which the object to _invoke_ is associated.
@@ -366,25 +352,9 @@ template<typename Type, auto Data, typename Policy = as_is_t>
* @param args Parameters to use to _invoke_ the object.
* @return A meta any containing the returned value, if any.
*/
template<typename Type, typename Policy = as_is_t, typename Candidate>
template<typename Type, typename Policy = as_value_t, typename Candidate>
[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_invoke(meta_handle instance, Candidate &&candidate, meta_any *const args) {
return internal::meta_invoke<Type, Policy>(std::move(instance), std::forward<Candidate>(candidate), args, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<Candidate>>::args_type::size>{});
}
/**
* @brief Tries to _invoke_ an object given a list of erased parameters.
* @tparam Type Reflected type to which the object to _invoke_ is associated.
* @tparam Policy Optional policy (no policy set by default).
* @param ctx The context from which to search for meta types.
* @tparam Candidate The type of the actual object to _invoke_.
* @param instance An opaque instance of the underlying type, if required.
* @param candidate The actual object to _invoke_.
* @param args Parameters to use to _invoke_ the object.
* @return A meta any containing the returned value, if any.
*/
template<typename Type, typename Policy = as_is_t, typename Candidate>
[[deprecated("a context is no longer required, it is inferred from the meta_handle")]] [[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_invoke(const meta_ctx &ctx, meta_handle instance, Candidate &&candidate, meta_any *const args) {
return meta_invoke<Type, Policy>(meta_handle{ctx, std::move(instance)}, std::forward<Candidate>(candidate), args);
return internal::meta_invoke<Type, Policy>(*instance.operator->(), std::forward<Candidate>(candidate), args, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<Candidate>>::args_type::size>{});
}
/**
@@ -396,24 +366,9 @@ template<typename Type, typename Policy = as_is_t, typename Candidate>
* @param args Parameters to use to invoke the function.
* @return A meta any containing the returned value, if any.
*/
template<typename Type, auto Candidate, typename Policy = as_is_t>
template<typename Type, auto Candidate, typename Policy = as_value_t>
[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_invoke(meta_handle instance, meta_any *const args) {
return internal::meta_invoke<Type, Policy>(std::move(instance), Candidate, args, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<decltype(Candidate)>>::args_type::size>{});
}
/**
* @brief Tries to invoke a function given a list of erased parameters.
* @tparam Type Reflected type to which the function is associated.
* @tparam Candidate The actual function to invoke.
* @tparam Policy Optional policy (no policy set by default).
* @param ctx The context from which to search for meta types.
* @param instance An opaque instance of the underlying type, if required.
* @param args Parameters to use to invoke the function.
* @return A meta any containing the returned value, if any.
*/
template<typename Type, auto Candidate, typename Policy = as_is_t>
[[deprecated("a context is no longer required, it is inferred from the meta_handle")]] [[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_invoke(const meta_ctx &ctx, meta_handle instance, meta_any *const args) {
return meta_invoke<Type, Candidate, Policy>(meta_handle{ctx, std::move(instance)}, args);
return internal::meta_invoke<Type, Policy>(*instance.operator->(), Candidate, args, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<decltype(Candidate)>>::args_type::size>{});
}
/**
@@ -461,14 +416,14 @@ template<typename Type, typename... Args>
* @param args Parameters to use to _invoke_ the object.
* @return A meta any containing the returned value, if any.
*/
template<typename Type, typename Policy = as_is_t, typename Candidate>
template<typename Type, typename Policy = as_value_t, typename Candidate>
[[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, Candidate &&candidate, meta_any *const args) {
if constexpr(meta_function_helper_t<Type, Candidate>::is_static || std::is_class_v<std::remove_cv_t<std::remove_reference_t<Candidate>>>) {
return internal::meta_invoke<Type, Policy>(meta_handle{meta_ctx_arg, ctx}, std::forward<Candidate>(candidate), args, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<Candidate>>::args_type::size>{});
if constexpr(meta_function_helper_t<Type, Candidate>::is_static || std::is_class_v<std::remove_const_t<std::remove_reference_t<Candidate>>>) {
meta_any placeholder{meta_ctx_arg, ctx};
return internal::meta_invoke<Type, Policy>(placeholder, std::forward<Candidate>(candidate), args, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<Candidate>>::args_type::size>{});
} else {
meta_any handle{ctx, args->as_ref()};
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and std::span)
return internal::meta_invoke<Type, Policy>(handle, std::forward<Candidate>(candidate), args + 1u, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<Candidate>>::args_type::size>{});
return internal::meta_invoke<Type, Policy>(*args, std::forward<Candidate>(candidate), args + 1u, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<Candidate>>::args_type::size>{});
}
}
@@ -481,7 +436,7 @@ template<typename Type, typename Policy = as_is_t, typename Candidate>
* @param args Parameters to use to _invoke_ the object.
* @return A meta any containing the returned value, if any.
*/
template<typename Type, typename Policy = as_is_t, typename Candidate>
template<typename Type, typename Policy = as_value_t, typename Candidate>
[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_construct(Candidate &&candidate, meta_any *const args) {
return meta_construct<Type, Policy>(locator<meta_ctx>::value_or(), std::forward<Candidate>(candidate), args);
}
@@ -500,7 +455,7 @@ template<typename Type, typename Policy = as_is_t, typename Candidate>
* @param args Parameters to use to invoke the function.
* @return A meta any containing the returned value, if any.
*/
template<typename Type, auto Candidate, typename Policy = as_is_t>
template<typename Type, auto Candidate, typename Policy = as_value_t>
[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_construct(const meta_ctx &ctx, meta_any *const args) {
return meta_construct<Type, Policy>(ctx, Candidate, args);
}
@@ -513,7 +468,7 @@ template<typename Type, auto Candidate, typename Policy = as_is_t>
* @param args Parameters to use to invoke the function.
* @return A meta any containing the returned value, if any.
*/
template<typename Type, auto Candidate, typename Policy = as_is_t>
template<typename Type, auto Candidate, typename Policy = as_value_t>
[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_construct(meta_any *const args) {
return meta_construct<Type, Candidate, Policy>(locator<meta_ctx>::value_or(), args);
}
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="entt::basic_any&lt;*&gt;">
<DisplayString>{{ type={ info->alias,na }, policy={ mode,en } }}</DisplayString>
<DisplayString>{{ policy={ mode,en } }}</DisplayString>
</Type>
<Type Name="entt::compressed_pair&lt;*&gt;">
<Intrinsic Name="first" Optional="true" Expression="((first_base*)this)->value"/>
@@ -47,7 +47,7 @@
<Intrinsic Name="is_valid_entity" Expression="!traits_type::version_mask || (*((traits_type::entity_type *)&amp;entity) &lt; (traits_type::version_mask &lt;&lt; traits_type::length))">
<Parameter Name="entity" Type="const traits_type::value_type &amp;"/>
</Intrinsic>
<DisplayString>{{ size={ packed.size() }, type={ info->alias,na } }}</DisplayString>
<DisplayString>{{ size={ packed.size() }, type={ descriptor->alias,na } }}</DisplayString>
<Expand>
<Item Name="[capacity]" ExcludeView="simple">packed.capacity()</Item>
<Item Name="[policy]" ExcludeView="simple">mode,en</Item>
@@ -94,7 +94,7 @@
<Intrinsic Name="is_valid_entity" Expression="!base_type::traits_type::version_mask || (*((base_type::traits_type::entity_type *)&amp;entity) &lt; (base_type::traits_type::version_mask &lt;&lt; base_type::traits_type::length))">
<Parameter Name="entity" Type="const base_type::traits_type::value_type &amp;"/>
</Intrinsic>
<DisplayString>{{ size={ base_type::packed.size() }, type={ base_type::info->alias,na } }}</DisplayString>
<DisplayString>{{ size={ base_type::packed.size() }, type={ base_type::descriptor->alias,na } }}</DisplayString>
<Expand>
<Item Name="[capacity]" Optional="true" ExcludeView="simple">payload.capacity() * traits_type::page_size</Item>
<Item Name="[page size]" Optional="true" ExcludeView="simple">traits_type::page_size</Item>
@@ -163,7 +163,7 @@
<Loop>
<Break Condition="pos == last"/>
<If Condition="pool_at(pos)->sparse.size() &gt; page &amp;&amp; pool_at(pos)->sparse[page] != nullptr &amp;&amp; ((*((traits_type::entity_type *)&amp;pool_at(pos)->sparse[page][offset])) &amp; entity_mask) != entity_mask">
<Item Name="[{ pool_at(pos)->info->alias,na }:{ ((*((traits_type::entity_type *)&amp;pool_at(pos)->sparse[page][offset])) &amp; entity_mask) != entity_mask }]">pool_at(pos),view(simple)nanr</Item>
<Item Name="[{ pool_at(pos)->descriptor->alias,na }:{ ((*((traits_type::entity_type *)&amp;pool_at(pos)->sparse[page][offset])) &amp; entity_mask) != entity_mask }]">pool_at(pos),view(simple)nanr</Item>
</If>
<Exec>++pos</Exec>
</Loop>
@@ -34,33 +34,33 @@
<Intrinsic Name="has_trait" Expression="!!(traits &amp; property)">
<Parameter Name="property" Type="int"/>
</Intrinsic>
<DisplayString Condition="name != nullptr">{{ id={ name,na } }}</DisplayString>
<DisplayString Condition="get != nullptr">{{ id={ id } }}</DisplayString>
<DisplayString>{{}}</DisplayString>
<Expand>
<Item Name="[id]">id</Item>
<Item Name="[name]" Condition="name != nullptr">name,na</Item>
<Item Name="[arity]">arity</Item>
<Item Name="[is_const]">has_trait(entt::internal::meta_traits::is_const)</Item>
<Item Name="[is_static]">has_trait(entt::internal::meta_traits::is_static)</Item>
<Item Name="[custom]">custom</Item>
<Item Name="[custom]" Condition="custom.value != nullptr">custom</Item>
</Expand>
</Type>
<Type Name="entt::internal::meta_dtor_node">
<DisplayString>{{}}</DisplayString>
<Expand/>
</Type>
<Type Name="entt::internal::meta_func_node" >
<Intrinsic Name="has_trait" Expression="!!(traits &amp; property)">
<Parameter Name="property" Type="int"/>
</Intrinsic>
<DisplayString Condition="name != nullptr">{{ id={ name,na } }}</DisplayString>
<DisplayString Condition="invoke != nullptr">{{ id={ id } }}</DisplayString>
<DisplayString>{{}}</DisplayString>
<Expand>
<Item Name="[id]">id</Item>
<Item Name="[name]" Condition="name != nullptr">name,na</Item>
<Item Name="[arity]">arity</Item>
<Item Name="[is_const]">has_trait(entt::internal::meta_traits::is_const)</Item>
<Item Name="[is_static]">has_trait(entt::internal::meta_traits::is_static)</Item>
<Item Name="[next]" Condition="next != nullptr">*next</Item>
<Item Name="[custom]">custom</Item>
<Item Name="[custom]" Condition="custom.value != nullptr">custom</Item>
</Expand>
</Type>
<Type Name="entt::internal::meta_template_node">
@@ -84,10 +84,12 @@
<Intrinsic Name="has_trait" Expression="!!(traits &amp; property)">
<Parameter Name="property" Type="int"/>
</Intrinsic>
<DisplayString Condition="name != nullptr">{{ type={ name,na } }}</DisplayString>
<DisplayString Condition="info != nullptr">{{ type={ info->alias,na } }}</DisplayString>
<DisplayString>{{}}</DisplayString>
<Expand>
<Item Name="[id]">id</Item>
<Item Name="[name]" Condition="name != nullptr">name,na</Item>
<Item Name="[sizeof]">size_of</Item>
<Item Name="[is_arithmetic]">has_trait(entt::internal::meta_traits::is_arithmetic)</Item>
<Item Name="[is_integral]">has_trait(entt::internal::meta_traits::is_integral)</Item>
@@ -102,17 +104,17 @@
<Item Name="[default_constructor]">default_constructor != nullptr</Item>
<Item Name="[conversion_helper]">conversion_helper != nullptr</Item>
<Item Name="[from_void]">from_void != nullptr</Item>
<Item Name="[template_info]">templ</Item>
<Item Name="[custom]">custom</Item>
<Item Name="[details]" Condition="!(details == nullptr)">*details</Item>
<Item Name="[template_info]" Condition="templ.arity != 0u">templ</Item>
<Item Name="[custom]" Condition="custom.value != nullptr">custom</Item>
<Item Name="[details]" Condition="details != nullptr">*details</Item>
</Expand>
</Type>
<Type Name="entt::meta_any">
<DisplayString Condition="node.info != nullptr">{{ type={ node.info->alias,na }, policy={ storage.mode,en } }}</DisplayString>
<DisplayString>{ storage }</DisplayString>
<DisplayString>{{}}</DisplayString>
<Expand>
<ExpandedItem>node</ExpandedItem>
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
<ExpandedItem Condition="node != nullptr">node,na</ExpandedItem>
<Item Name="[context]" Condition="ctx != nullptr">ctx,na</Item>
</Expand>
</Type>
<Type Name="entt::meta_handle">
@@ -125,7 +127,7 @@
<DisplayString Condition="data != nullptr">{{ const={ const_only } }}</DisplayString>
<DisplayString>{{}}</DisplayString>
<Expand>
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
<Item Name="[context]" Condition="ctx != nullptr">ctx,na</Item>
<Item Name="[const]">const_only</Item>
<Item Name="[data]">data</Item>
</Expand>
@@ -134,38 +136,40 @@
<DisplayString Condition="data != nullptr">{{ const={ const_only } }}</DisplayString>
<DisplayString>{{}}</DisplayString>
<Expand>
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
<Item Name="[context]" Condition="ctx != nullptr">ctx,na</Item>
<Item Name="[const]">const_only</Item>
<Item Name="[data]">data</Item>
</Expand>
</Type>
<Type Name="entt::meta_custom">
<DisplayString>{ node }</DisplayString>
<DisplayString Condition="node != nullptr">{ node }</DisplayString>
<DisplayString>{{}}</DisplayString>
<Expand>
<ExpandedItem>node</ExpandedItem>
<ExpandedItem Condition="node != nullptr">node</ExpandedItem>
</Expand>
</Type>
<Type Name="entt::meta_data">
<DisplayString Condition="node.get != nullptr">{ node }</DisplayString>
<DisplayString Condition="node != nullptr">{ node }</DisplayString>
<DisplayString>{{}}</DisplayString>
<Expand>
<ExpandedItem Condition="node.get != nullptr">node</ExpandedItem>
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
<ExpandedItem Condition="node != nullptr">node</ExpandedItem>
<Item Name="[context]" Condition="ctx != nullptr">ctx,na</Item>
</Expand>
</Type>
<Type Name="entt::meta_func">
<DisplayString Condition="node.invoke != nullptr">{ node }</DisplayString>
<DisplayString Condition="node != nullptr">{ node }</DisplayString>
<DisplayString>{{}}</DisplayString>
<Expand>
<ExpandedItem Condition="node.invoke != nullptr">node</ExpandedItem>
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
<ExpandedItem Condition="node != nullptr">node</ExpandedItem>
<Item Name="[context]" Condition="ctx != nullptr">ctx,na</Item>
</Expand>
</Type>
<Type Name="entt::meta_type">
<DisplayString>{ node }</DisplayString>
<DisplayString Condition="node != nullptr">{ node }</DisplayString>
<DisplayString>{{}}</DisplayString>
<Expand>
<ExpandedItem>node</ExpandedItem>
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
<ExpandedItem Condition="node != nullptr">node</ExpandedItem>
<Item Name="[context]" Condition="ctx != nullptr">ctx,na</Item>
</Expand>
</Type>
<Type Name="entt::meta_ctx">
+21
View File
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="entt::basic_process&lt;*&gt;">
<DisplayString>{{ state={ current,en } }}</DisplayString>
<Expand>
<Item Name="[state]">current,en</Item>
<Item Name="[child]" Condition="next.first_base::value != nullptr">*next.first_base::value</Item>
</Expand>
</Type>
<Type Name="entt::basic_scheduler&lt;*&gt;">
<Intrinsic Name="size" Expression="handlers.first_base::value.size()"/>
<DisplayString>{{ size={ size() } }}</DisplayString>
<Expand>
<Item Name="[capacity]" ExcludeView="simple">handlers.first_base::value.capacity()</Item>
<IndexListItems>
<Size>size()</Size>
<ValueNode>*handlers.first_base::value[$i]</ValueNode>
</IndexListItems>
</Expand>
</Type>
</AutoVisualizer>
+13 -8
View File
@@ -211,23 +211,28 @@ public:
template<typename Type, typename... Args>
explicit basic_poly(std::in_place_type_t<Type>, Args &&...args)
: storage{std::in_place_type<Type>, std::forward<Args>(args)...},
vtable{poly_vtable<Concept, Len, Align>::template instance<std::remove_cv_t<std::remove_reference_t<Type>>>()} {}
vtable{poly_vtable<Concept, Len, Align>::template instance<std::remove_const_t<std::remove_reference_t<Type>>>()} {}
/**
* @brief Constructs a poly from a given value.
* @tparam Type Type of object to use to initialize the poly.
* @param value An instance of an object to use to initialize the poly.
*/
template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, basic_poly>>>
template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::remove_const_t<std::remove_reference_t<Type>>, basic_poly>>>
basic_poly(Type &&value) noexcept
: basic_poly{std::in_place_type<std::remove_cv_t<std::remove_reference_t<Type>>>, std::forward<Type>(value)} {}
: basic_poly{std::in_place_type<std::remove_const_t<std::remove_reference_t<Type>>>, std::forward<Type>(value)} {}
/**
* @brief Returns the object type if any, `type_id<void>()` otherwise.
* @return The object type if any, `type_id<void>()` otherwise.
* @brief Returns the object type info if any, `type_id<void>()` otherwise.
* @return The object type info if any, `type_id<void>()` otherwise.
*/
[[nodiscard]] const type_info &type() const noexcept {
return storage.type();
[[nodiscard]] const type_info &info() const noexcept {
return storage.info();
}
/*! @copydoc info */
[[deprecated("use ::info instead")]] [[nodiscard]] const type_info &type() const noexcept {
return info();
}
/**
@@ -252,7 +257,7 @@ public:
template<typename Type, typename... Args>
void emplace(Args &&...args) {
storage.template emplace<Type>(std::forward<Args>(args)...);
vtable = poly_vtable<Concept, Len, Align>::template instance<std::remove_cv_t<std::remove_reference_t<Type>>>();
vtable = poly_vtable<Concept, Len, Align>::template instance<std::remove_const_t<std::remove_reference_t<Type>>>();
}
/*! @brief Destroys contained object */
+7 -4
View File
@@ -6,14 +6,17 @@
namespace entt {
template<typename, typename>
class process;
template<typename, typename = std::allocator<void>>
class basic_process;
template<typename = std::uint32_t, typename = std::allocator<void>>
/*! @brief Alias declaration for the most common use case. */
using process = basic_process<std::uint32_t>;
template<typename, typename = std::allocator<void>>
class basic_scheduler;
/*! @brief Alias declaration for the most common use case. */
using scheduler = basic_scheduler<>;
using scheduler = basic_scheduler<std::uint32_t>;
} // namespace entt
+154 -192
View File
@@ -2,22 +2,32 @@
#define ENTT_PROCESS_PROCESS_HPP
#include <cstdint>
#include <memory>
#include <type_traits>
#include <utility>
#include "../core/compressed_pair.hpp"
#include "../core/type_traits.hpp"
#include "fwd.hpp"
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename, typename, typename>
struct process_adaptor;
} // namespace internal
/*! @endcond */
/**
* @brief Base class for processes.
*
* This class stays true to the CRTP idiom. Derived classes must specify what's
* the intended type for elapsed times.<br/>
* A process should expose publicly the following member functions whether
* required:
* Derived classes must specify what's the intended type for elapsed times.<br/>
* A process can implement the following member functions whether required:
*
* * @code{.cpp}
* void update(Delta, void *);
* void update(Delta, void *) override;
* @endcode
*
* It's invoked once per tick until a process is explicitly aborted or it
@@ -28,30 +38,21 @@ namespace entt {
* update.
*
* * @code{.cpp}
* void init();
* @endcode
*
* It's invoked when the process joins the running queue of a scheduler. This
* happens as soon as it's attached to the scheduler if the process is a top
* level one, otherwise when it replaces its parent if the process is a
* continuation.
*
* * @code{.cpp}
* void succeeded();
* void succeeded() override;
* @endcode
*
* It's invoked in case of success, immediately after an update and during the
* same tick.
*
* * @code{.cpp}
* void failed();
* void failed() override;
* @endcode
*
* It's invoked in case of errors, immediately after an update and during the
* same tick.
*
* * @code{.cpp}
* void aborted();
* void aborted() override;
* @endcode
*
* It's invoked only if a process is explicitly aborted. There is no guarantee
@@ -59,18 +60,18 @@ namespace entt {
* process is aborted immediately or not.
*
* Derived classes can change the internal state of a process by invoking the
* `succeed` and `fail` protected member functions and even pause or unpause the
* process itself.
* `succeed` and `fail` member functions and even pause or unpause the process
* itself.
*
* @sa scheduler
*
* @tparam Derived Actual type of process that extends the class template.
* @tparam Delta Type to use to provide elapsed time.
* @tparam Allocator Type of allocator used to manage memory and elements.
*/
template<typename Derived, typename Delta>
class process {
template<typename Delta, typename Allocator>
class basic_process: public std::enable_shared_from_this<basic_process<Delta, Allocator>> {
enum class state : std::uint8_t {
uninitialized = 0,
idle = 0,
running,
paused,
succeeded,
@@ -80,45 +81,73 @@ class process {
rejected
};
template<typename Target = Derived>
auto next(std::integral_constant<state, state::uninitialized>)
-> decltype(std::declval<Target>().init(), void()) {
static_cast<Target *>(this)->init();
virtual void update(const Delta, void *) {
abort();
}
template<typename Target = Derived>
auto next(std::integral_constant<state, state::running>, Delta delta, void *data)
-> decltype(std::declval<Target>().update(delta, data), void()) {
static_cast<Target *>(this)->update(delta, data);
}
virtual void succeeded() {}
virtual void failed() {}
virtual void aborted() {}
template<typename Target = Derived>
auto next(std::integral_constant<state, state::succeeded>)
-> decltype(std::declval<Target>().succeeded(), void()) {
static_cast<Target *>(this)->succeeded();
}
public:
/*! @brief Allocator type. */
using allocator_type = Allocator;
/*! @brief Type used to provide elapsed time. */
using delta_type = Delta;
/*! @brief Handle type. */
using handle_type = std::shared_ptr<basic_process>;
template<typename Target = Derived>
auto next(std::integral_constant<state, state::failed>)
-> decltype(std::declval<Target>().failed(), void()) {
static_cast<Target *>(this)->failed();
}
/*! @brief Default constructor. */
basic_process()
: basic_process{allocator_type{}} {}
template<typename Target = Derived>
auto next(std::integral_constant<state, state::aborted>)
-> decltype(std::declval<Target>().aborted(), void()) {
static_cast<Target *>(this)->aborted();
}
template<typename... Args>
void next(Args...) const noexcept {}
protected:
/**
* @brief Terminates a process with success if it's still alive.
*
* The function is idempotent and it does nothing if the process isn't
* alive.
* @brief Constructs a scheduler with a given allocator.
* @param allocator The allocator to use.
*/
explicit basic_process(const allocator_type &allocator)
: next{nullptr, allocator},
current{state::idle} {}
/*! @brief Default copy constructor, deleted on purpose. */
basic_process(const basic_process &) = delete;
/*! @brief Default move constructor, deleted on purpose. */
basic_process(basic_process &&) = delete;
/*! @brief Default destructor. */
virtual ~basic_process() = default;
/**
* @brief Default copy assignment operator, deleted on purpose.
* @return This process scheduler.
*/
basic_process &operator=(const basic_process &) = delete;
/**
* @brief Default move assignment operator, deleted on purpose.
* @return This process scheduler.
*/
basic_process &operator=(basic_process &&) = delete;
/**
* @brief Returns the associated allocator.
* @return The associated allocator.
*/
[[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
return next.second();
}
/*! @brief Aborts a process if it's still alive, otherwise does nothing. */
void abort() {
if(alive()) {
current = state::aborted;
}
}
/**
* @brief Terminates a process with success if it's still alive, otherwise
* does nothing.
*/
void succeed() noexcept {
if(alive()) {
@@ -127,10 +156,8 @@ protected:
}
/**
* @brief Terminates a process with errors if it's still alive.
*
* The function is idempotent and it does nothing if the process isn't
* alive.
* @brief Terminates a process with errors if it's still alive, otherwise
* does nothing.
*/
void fail() noexcept {
if(alive()) {
@@ -138,75 +165,17 @@ protected:
}
}
/**
* @brief Stops a process if it's in a running state.
*
* The function is idempotent and it does nothing if the process isn't
* running.
*/
/*! @brief Stops a process if it's running, otherwise does nothing. */
void pause() noexcept {
if(current == state::running) {
if(alive()) {
current = state::paused;
}
}
/**
* @brief Restarts a process if it's paused.
*
* The function is idempotent and it does nothing if the process isn't
* paused.
*/
/*! @brief Restarts a process if it's paused, otherwise does nothing. */
void unpause() noexcept {
if(current == state::paused) {
current = state::running;
}
}
public:
/*! @brief Type used to provide elapsed time. */
using delta_type = Delta;
/*! @brief Default constructor. */
constexpr process() = default;
/*! @brief Default copy constructor. */
process(const process &) = default;
/*! @brief Default move constructor. */
process(process &&) noexcept = default;
/**
* @brief Default copy assignment operator.
* @return This process.
*/
process &operator=(const process &) = default;
/**
* @brief Default move assignment operator.
* @return This process.
*/
process &operator=(process &&) noexcept = default;
/*! @brief Default destructor. */
virtual ~process() {
static_assert(std::is_base_of_v<process, Derived>, "Incorrect use of the class template");
}
/**
* @brief Aborts a process if it's still alive.
*
* The function is idempotent and it does nothing if the process isn't
* alive.
*
* @param immediate Requests an immediate operation.
*/
void abort(const bool immediate = false) {
if(alive()) {
current = state::aborted;
if(immediate) {
tick({});
}
current = state::running;
}
}
@@ -243,18 +212,50 @@ public:
}
/**
* @brief Updates a process and its internal state if required.
* @brief Assigns a child process to run in case of success.
* @tparam Type Type of child process to create.
* @tparam Args Types of arguments to use to initialize the child process.
* @param args Parameters to use to initialize the child process.
* @return A reference to the newly created child process.
*/
template<typename Type, typename... Args>
basic_process &then(Args &&...args) {
const auto &allocator = next.second();
return *(next.first() = std::allocate_shared<Type>(allocator, allocator, std::forward<Args>(args)...));
}
/**
* @brief Assigns a child process to run in case of success.
* @tparam Func Type of child process to create.
* @param func Either a lambda or a functor to use as a child process.
* @return A reference to the newly created child process.
*/
template<typename Func>
basic_process &then(Func func) {
const auto &allocator = next.second();
using process_type = internal::process_adaptor<delta_type, Func, allocator_type>;
return *(next.first() = std::allocate_shared<process_type>(allocator, allocator, std::move(func)));
}
/**
* @brief Returns the child process without releasing ownership, if any.
* @return The child process attached to the object, if any.
*/
handle_type peek() {
return next.first();
}
/**
* @brief Updates a process and its internal state, if required.
* @param delta Elapsed time.
* @param data Optional data.
*/
void tick(const Delta delta, void *data = nullptr) {
switch(current) {
case state::uninitialized:
next(std::integral_constant<state, state::uninitialized>{});
current = state::running;
break;
case state::idle:
case state::running:
next(std::integral_constant<state, state::running>{}, delta, data);
current = state::running;
update(delta, data);
break;
default:
// suppress warnings
@@ -264,15 +265,15 @@ public:
// if it's dead, it must be notified and removed immediately
switch(current) {
case state::succeeded:
next(std::integral_constant<state, state::succeeded>{});
succeeded();
current = state::finished;
break;
case state::failed:
next(std::integral_constant<state, state::failed>{});
failed();
current = state::rejected;
break;
case state::aborted:
next(std::integral_constant<state, state::aborted>{});
aborted();
current = state::rejected;
break;
default:
@@ -282,73 +283,34 @@ public:
}
private:
state current{state::uninitialized};
compressed_pair<handle_type, allocator_type> next;
state current;
};
/**
* @brief Adaptor for lambdas and functors to turn them into processes.
*
* Lambdas and functors can't be used directly with a scheduler for they are not
* properly defined processes with managed life cycles.<br/>
* This class helps in filling the gap and turning lambdas and functors into
* full featured processes usable by a scheduler.
*
* The signature of the function call operator should be equivalent to the
* following:
*
* @code{.cpp}
* void(Delta delta, void *data, auto succeed, auto fail);
* @endcode
*
* Where:
*
* * `delta` is the elapsed time.
* * `data` is an opaque pointer to user data if any, `nullptr` otherwise.
* * `succeed` is a function to call when a process terminates with success.
* * `fail` is a function to call when a process terminates with errors.
*
* The signature of the function call operator of both `succeed` and `fail`
* is equivalent to the following:
*
* @code{.cpp}
* void();
* @endcode
*
* Usually users shouldn't worry about creating adaptors. A scheduler will
* create them internally each and avery time a lambda or a functor is used as
* a process.
*
* @sa process
* @sa scheduler
*
* @tparam Func Actual type of process.
* @tparam Delta Type to use to provide elapsed time.
*/
template<typename Func, typename Delta>
struct process_adaptor: process<process_adaptor<Func, Delta>, Delta>, private Func {
/**
* @brief Constructs a process adaptor from a lambda or a functor.
* @tparam Args Types of arguments to use to initialize the actual process.
* @param args Parameters to use to initialize the actual process.
*/
template<typename... Args>
process_adaptor(Args &&...args)
: Func{std::forward<Args>(args)...} {}
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
/**
* @brief Updates a process and its internal state if required.
* @param delta Elapsed time.
* @param data Optional data.
*/
void update(const Delta delta, void *data) {
Func::operator()(
delta,
data,
[this]() { this->succeed(); },
[this]() { this->fail(); });
template<typename Delta, typename Func, typename Allocator>
struct process_adaptor: public basic_process<Delta, Allocator> {
using allocator_type = Allocator;
using base_type = basic_process<Delta, Allocator>;
using delta_type = typename base_type::delta_type;
process_adaptor(const allocator_type &allocator, Func proc)
: base_type{allocator},
func{std::move(proc)} {}
void update(const delta_type delta, void *data) override {
func(*this, delta, data);
}
private:
Func func;
};
} // namespace internal
/*! @endcond */
} // namespace entt
#endif
+34 -171
View File
@@ -13,44 +13,6 @@
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename Delta>
struct basic_process_handler {
virtual ~basic_process_handler() = default;
virtual bool update(Delta, void *) = 0;
virtual void abort(bool) = 0;
// std::shared_ptr because of its type erased allocator which is useful here
std::shared_ptr<basic_process_handler> next;
};
template<typename Delta, typename Type>
struct process_handler final: basic_process_handler<Delta> {
template<typename... Args>
process_handler(Args &&...args)
: process{std::forward<Args>(args)...} {}
bool update(const Delta delta, void *data) override {
if(process.tick(delta, data); process.rejected()) {
this->next.reset();
}
return (process.rejected() || process.finished());
}
void abort(const bool immediate) override {
process.abort(immediate);
}
Type process;
};
} // namespace internal
/*! @endcond */
/**
* @brief Cooperative scheduler for processes.
*
@@ -62,14 +24,6 @@ struct process_handler final: basic_process_handler<Delta> {
* its child when it terminates if it returns with success. In case of errors,
* both the process and its child are discarded.
*
* Example of use (pseudocode):
*
* @code{.cpp}
* scheduler.attach([](auto delta, void *, auto succeed, auto fail) {
* // code
* }).then<my_process>(arguments...);
* @endcode
*
* In order to invoke all scheduled processes, call the `update` member function
* passing it the elapsed time to forward to the tasks.
*
@@ -80,17 +34,14 @@ struct process_handler final: basic_process_handler<Delta> {
*/
template<typename Delta, typename Allocator>
class basic_scheduler {
template<typename Type>
using handler_type = internal::process_handler<Delta, Type>;
// std::shared_ptr because of its type erased allocator which is useful here
using process_type = std::shared_ptr<internal::basic_process_handler<Delta>>;
using base_type = basic_process<Delta, Allocator>;
using alloc_traits = std::allocator_traits<Allocator>;
using container_allocator = typename alloc_traits::template rebind_alloc<process_type>;
using container_type = std::vector<process_type, container_allocator>;
using container_allocator = typename alloc_traits::template rebind_alloc<std::shared_ptr<base_type>>;
using container_type = std::vector<std::shared_ptr<base_type>, container_allocator>;
public:
/*! @brief Process type. */
using type = base_type;
/*! @brief Allocator type. */
using allocator_type = Allocator;
/*! @brief Unsigned integer type. */
@@ -194,122 +145,28 @@ public:
/**
* @brief Schedules a process for the next tick.
*
* Returned value can be used to attach a continuation for the last process.
* The continutation is scheduled automatically when the process terminates
* and only if the process returns with success.
*
* Example of use (pseudocode):
*
* @code{.cpp}
* // schedules a task in the form of a process class
* scheduler.attach<my_process>(arguments...)
* // appends a child in the form of a lambda function
* .then([](auto delta, void *, auto succeed, auto fail) {
* // code
* })
* // appends a child in the form of another process class
* .then<my_other_process>();
* @endcode
*
* @tparam Proc Type of process to schedule.
* @tparam Type Type of process to create.
* @tparam Args Types of arguments to use to initialize the process.
* @param args Parameters to use to initialize the process.
* @return This process scheduler.
* @return A reference to the newly created process.
*/
template<typename Proc, typename... Args>
basic_scheduler &attach(Args &&...args) {
static_assert(std::is_base_of_v<process<Proc, Delta>, Proc>, "Invalid process type");
auto &ref = handlers.first().emplace_back(std::allocate_shared<handler_type<Proc>>(handlers.second(), std::forward<Args>(args)...));
// forces the process to exit the uninitialized state
ref->update({}, nullptr);
return *this;
template<typename Type, typename... Args>
type &attach(Args &&...args) {
const auto &allocator = handlers.second();
return *handlers.first().emplace_back(std::allocate_shared<Type>(allocator, allocator, std::forward<Args>(args)...));
}
/**
* @brief Schedules a process for the next tick.
*
* A process can be either a lambda or a functor. The scheduler wraps both
* of them in a process adaptor internally.<br/>
* The signature of the function call operator should be equivalent to the
* following:
*
* @code{.cpp}
* void(Delta delta, void *data, auto succeed, auto fail);
* @endcode
*
* Where:
*
* * `delta` is the elapsed time.
* * `data` is an opaque pointer to user data if any, `nullptr` otherwise.
* * `succeed` is a function to call when a process terminates with success.
* * `fail` is a function to call when a process terminates with errors.
*
* The signature of the function call operator of both `succeed` and `fail`
* is equivalent to the following:
*
* @code{.cpp}
* void();
* @endcode
*
* Returned value can be used to attach a continuation for the last process.
* The continutation is scheduled automatically when the process terminates
* and only if the process returns with success.
*
* Example of use (pseudocode):
*
* @code{.cpp}
* // schedules a task in the form of a lambda function
* scheduler.attach([](auto delta, void *, auto succeed, auto fail) {
* // code
* })
* // appends a child in the form of another lambda function
* .then([](auto delta, void *, auto succeed, auto fail) {
* // code
* })
* // appends a child in the form of a process class
* .then<my_process>(arguments...);
* @endcode
*
* @sa process_adaptor
*
* @tparam Func Type of process to schedule.
* @tparam Func Type of process to create.
* @param func Either a lambda or a functor to use as a process.
* @return This process scheduler.
* @return A reference to the newly created process.
*/
template<typename Func>
basic_scheduler &attach(Func &&func) {
using Proc = process_adaptor<std::decay_t<Func>, Delta>;
return attach<Proc>(std::forward<Func>(func));
}
/**
* @brief Sets a process as a continuation of the last scheduled process.
* @tparam Proc Type of process to use as a continuation.
* @tparam Args Types of arguments to use to initialize the process.
* @param args Parameters to use to initialize the process.
* @return This process scheduler.
*/
template<typename Proc, typename... Args>
basic_scheduler &then(Args &&...args) {
static_assert(std::is_base_of_v<process<Proc, Delta>, Proc>, "Invalid process type");
ENTT_ASSERT(!handlers.first().empty(), "Process not available");
auto *curr = handlers.first().back().get();
for(; curr->next; curr = curr->next.get()) {}
curr->next = std::allocate_shared<handler_type<Proc>>(handlers.second(), std::forward<Args>(args)...);
return *this;
}
/**
* @brief Sets a process as a continuation of the last scheduled process.
* @tparam Func Type of process to use as a continuation.
* @param func Either a lambda or a functor to use as a process.
* @return This process scheduler.
*/
template<typename Func>
basic_scheduler &then(Func &&func) {
using Proc = process_adaptor<std::decay_t<Func>, Delta>;
return then<Proc>(std::forward<Func>(func));
type &attach(Func func) {
const auto &allocator = handlers.second();
using process_type = internal::process_adaptor<delta_type, Func, allocator_type>;
return *handlers.first().emplace_back(std::allocate_shared<process_type>(allocator, allocator, std::move(func)));
}
/**
@@ -325,16 +182,18 @@ public:
*/
void update(const delta_type delta, void *data = nullptr) {
for(auto next = handlers.first().size(); next; --next) {
if(const auto pos = next - 1u; handlers.first()[pos]->update(delta, data)) {
// updating might spawn/reallocate, cannot hold refs until here
if(auto &curr = handlers.first()[pos]; curr->next) {
curr = std::move(curr->next);
// forces the process to exit the uninitialized state
curr->update({}, nullptr);
} else {
curr = std::move(handlers.first().back());
handlers.first().pop_back();
}
const auto pos = next - 1u;
handlers.first()[pos]->tick(delta, data);
// updating might spawn/reallocate, cannot hold refs until here
auto &elem = handlers.first()[pos];
if(elem->finished()) {
elem = elem->peek();
}
if(!elem || elem->rejected()) {
elem = std::move(handlers.first().back());
handlers.first().pop_back();
}
}
}
@@ -351,7 +210,11 @@ public:
*/
void abort(const bool immediate = false) {
for(auto &&curr: handlers.first()) {
curr->abort(immediate);
curr->abort();
if(immediate) {
curr->tick({});
}
}
}
+1 -1
View File
@@ -175,7 +175,7 @@ public:
* @brief Returns the underlying resource handle.
* @return The underlying resource handle.
*/
[[nodiscard]] const handle_type &handle() const noexcept {
[[nodiscard]] handle_type handle() const noexcept {
return value;
}
+2 -2
View File
@@ -147,7 +147,7 @@ public:
*/
template<typename Type>
void erase() {
handlers.first().erase(type_hash<std::remove_cv_t<std::remove_reference_t<Type>>>::value());
handlers.first().erase(type_hash<std::remove_const_t<std::remove_reference_t<Type>>>::value());
}
/*! @brief Disconnects all the listeners. */
@@ -162,7 +162,7 @@ public:
*/
template<typename Type>
[[nodiscard]] bool contains() const {
return handlers.first().contains(type_hash<std::remove_cv_t<std::remove_reference_t<Type>>>::value());
return handlers.first().contains(type_hash<std::remove_const_t<std::remove_reference_t<Type>>>::value());
}
/**
+3
View File
@@ -0,0 +1,3 @@
// IWYU pragma: begin_exports
#include "tools/davey.hpp"
// IWYU pragma: end_exports
+331
View File
@@ -0,0 +1,331 @@
#ifndef ENTT_TOOLS_DAVEY_HPP
#define ENTT_TOOLS_DAVEY_HPP
#include <cstdint>
#include <ios>
#include <sstream>
#include <string>
#include <imgui.h>
#include "../entity/mixin.hpp"
#include "../entity/registry.hpp"
#include "../entity/sparse_set.hpp"
#include "../entity/storage.hpp"
#include "../locator/locator.hpp"
#include "../meta/container.hpp"
#include "../meta/context.hpp"
#include "../meta/meta.hpp"
#include "../meta/pointer.hpp"
#include "../meta/resolve.hpp"
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename Entity, typename OnEntity>
static void present_element(const meta_any &obj, OnEntity on_entity) {
for([[maybe_unused]] const auto [id, data]: obj.type().data()) {
const auto elem = data.get(obj);
const char *label = data.name() ? data.name() : std::string{data.type().info().name()}.data();
if(auto type = data.type(); type.info() == type_id<const char *>()) {
ImGui::Text("%s: %s", label, elem.template cast<const char *>());
} else if(type.info() == type_id<std::string>()) {
ImGui::Text("%s: %s", label, elem.template cast<const std::string &>().data());
} else if(type.info() == type_id<Entity>()) {
if(const auto entt = elem.template cast<Entity>(); entt == null) {
ImGui::Text("%s: %s", label, "null");
} else {
on_entity(label, entt);
}
} else if(type.is_enum()) {
const char *as_string = nullptr;
for(auto [id, curr]: type.data()) {
if(curr.get({}) == elem) {
as_string = curr.name();
break;
}
}
if(as_string) {
ImGui::Text("%s: %s", label, as_string);
} else {
ImGui::Text("%s: %zu", label, elem.template allow_cast<std::uint64_t>().template cast<std::uint64_t>());
}
} else if(type.is_arithmetic()) {
if(type.info() == type_id<bool>()) {
std::stringstream buffer{};
buffer << std::boolalpha << elem.template cast<bool>();
ImGui::Text("%s: %s", label, buffer.str().data());
} else if(type.info() == type_id<char>()) {
ImGui::Text("%s: %c", label, elem.template cast<char>());
} else if(type.is_integral()) {
ImGui::Text("%s: %zu", label, elem.template allow_cast<std::uint64_t>().template cast<std::uint64_t>());
} else {
ImGui::Text("%s: %f", label, elem.template allow_cast<double>().template cast<double>());
}
} else if(type.is_pointer_like()) {
if(auto deref = *obj; deref) {
if(ImGui::TreeNode(label)) {
present_element<Entity>(*obj, on_entity);
ImGui::TreePop();
}
} else {
ImGui::Text("%s: %s", label, "null");
}
} else if(type.is_sequence_container()) {
if(ImGui::TreeNode(label)) {
meta_sequence_container view = elem.as_sequence_container();
for(std::size_t pos{}, last = view.size(); pos < last; ++pos) {
ImGui::PushID(static_cast<int>(pos));
if(ImGui::TreeNode(label, "%zu", pos)) {
present_element<Entity>(view[pos], on_entity);
ImGui::TreePop();
}
ImGui::PopID();
}
ImGui::TreePop();
}
} else if(type.is_associative_container()) {
if(ImGui::TreeNode(label)) {
meta_associative_container view = elem.as_associative_container();
auto it = view.begin();
for(std::size_t pos{}, last = view.size(); pos < last; ++pos, ++it) {
ImGui::PushID(static_cast<int>(pos));
if(ImGui::TreeNode(label, "%zu", pos)) {
const auto [key, value] = *it;
if(ImGui::TreeNode("key")) {
present_element<Entity>(key, on_entity);
ImGui::TreePop();
}
if(ImGui::TreeNode("value")) {
present_element<Entity>(value, on_entity);
ImGui::TreePop();
}
ImGui::TreePop();
}
ImGui::PopID();
}
ImGui::TreePop();
}
} else if(type.is_class()) {
if(ImGui::TreeNode(label)) {
present_element<Entity>(elem, on_entity);
ImGui::TreePop();
}
} else {
const std::string underlying_type{data.type().info().name()};
ImGui::Text("%s: %s", label, underlying_type.data());
}
}
}
template<typename Entity, typename Allocator>
static void present_storage(const meta_ctx &ctx, const basic_sparse_set<Entity, Allocator> &storage) {
if(auto type = resolve(ctx, storage.info()); type) {
for(auto entt: storage) {
ImGui::PushID(static_cast<int>(to_entity(entt)));
if(ImGui::TreeNode(&storage.info(), "%d [%d/%d]", to_integral(entt), to_entity(entt), to_version(entt))) {
if(const auto obj = type.from_void(storage.value(entt)); obj) {
present_element<typename std::decay_t<decltype(storage)>::entity_type>(obj, [](const char *name, const Entity entt) {
ImGui::Text("%s: %d [%d/%d]", name, to_integral(entt), to_entity(entt), to_version(entt));
});
}
ImGui::TreePop();
}
ImGui::PopID();
}
} else {
for(auto entt: storage) {
ImGui::Text("%d [%d/%d]", to_integral(entt), to_entity(entt), to_version(entt));
}
}
}
template<typename Entity, typename It>
static void present_entity(const meta_ctx &ctx, const Entity entt, const It from, const It to) {
for(auto it = from; it != to; ++it) {
if(const auto &storage = it->second; storage.contains(entt)) {
if(auto type = resolve(ctx, storage.info()); type) {
const char *label = type.name() ? type.name() : std::string{storage.info().name()}.data();
if(ImGui::TreeNode(&storage.info(), "%s", label)) {
if(const auto obj = type.from_void(storage.value(entt)); obj) {
present_element<Entity>(obj, [&ctx, from, to](const char *name, const Entity other) {
if(ImGui::TreeNode(name, "%s: %d [%d/%d]", name, to_integral(other), to_entity(other), to_version(other))) {
present_entity<Entity>(ctx, other, from, to);
ImGui::TreePop();
}
});
}
ImGui::TreePop();
}
} else {
const std::string name{storage.info().name()};
ImGui::Text("%s", name.data());
}
}
}
}
template<typename... Get, typename... Exclude, std::size_t... Index>
static void present_view(const meta_ctx &ctx, const basic_view<get_t<Get...>, exclude_t<Exclude...>> &view, std::index_sequence<Index...>) {
using view_type = basic_view<get_t<Get...>, exclude_t<Exclude...>>;
const std::array<const typename view_type::common_type *, sizeof...(Index)> range{view.template storage<Index>()...};
for(auto tup: view.each()) {
const auto entt = std::get<0>(tup);
ImGui::PushID(static_cast<int>(to_entity(entt)));
if(ImGui::TreeNode(&type_id<typename view_type::entity_type>(), "%d [%d/%d]", to_integral(entt), to_entity(entt), to_version(entt))) {
for(const auto *storage: range) {
if(auto type = resolve(ctx, storage->info()); type) {
const char *label = type.name() ? type.name() : std::string{storage->info().name()}.data();
if(ImGui::TreeNode(&storage->info(), "%s", label)) {
if(const auto obj = type.from_void(storage->value(entt)); obj) {
present_element<typename view_type::entity_type>(obj, [](const char *name, const typename view_type::entity_type entt) {
ImGui::Text("%s: %d [%d/%d]", name, to_integral(entt), to_entity(entt), to_version(entt));
});
}
ImGui::TreePop();
}
} else {
const std::string name{storage->info().name()};
ImGui::Text("%s", name.data());
}
}
ImGui::TreePop();
}
ImGui::PopID();
}
}
} // namespace internal
/*! @endcond */
/**
* @brief ImGui-based introspection tool for storage types.
* @tparam Type Storage element type.
* @tparam Entity Storage entity type.
* @tparam Allocator Storage allocator type.
* @param ctx The context from which to search for meta types.
* @param storage An instance of the storage type.
*/
template<typename Type, typename Entity, typename Allocator>
void davey(const meta_ctx &ctx, const basic_storage<Type, Entity, Allocator> &storage) {
internal::present_storage(ctx, storage);
}
/**
* @brief ImGui-based introspection tool for storage types.
* @tparam Type Storage element type.
* @tparam Entity Storage entity type.
* @tparam Allocator Storage allocator type.
* @param storage An instance of the storage type.
*/
template<typename Type, typename Entity, typename Allocator>
void davey(const basic_storage<Type, Entity, Allocator> &storage) {
davey(locator<meta_ctx>::value_or(), storage);
}
/**
* @brief ImGui-based introspection tool for view types.
* @tparam Get Types of storage iterated by the view.
* @tparam Exclude Types of storage used to filter the view.
* @param ctx The context from which to search for meta types.
* @param view An instance of the view type.
*/
template<typename... Get, typename... Exclude>
void davey(const meta_ctx &ctx, const basic_view<get_t<Get...>, exclude_t<Exclude...>> &view) {
internal::present_view(ctx, view, std::index_sequence_for<Get...>{});
}
/**
* @brief ImGui-based introspection tool for view types.
* @tparam Get Types of storage iterated by the view.
* @tparam Exclude Types of storage used to filter the view.
* @param view An instance of the view type.
*/
template<typename... Get, typename... Exclude>
void davey(const basic_view<get_t<Get...>, exclude_t<Exclude...>> &view) {
davey(locator<meta_ctx>::value_or(), view);
}
/**
* @brief ImGui-based introspection tool for registry types.
* @tparam Entity Registry entity type.
* @tparam Allocator Registry allocator type.
* @param ctx The context from which to search for meta types.
* @param registry An instance of the registry type.
*/
template<typename Entity, typename Allocator>
void davey(const meta_ctx &ctx, const basic_registry<Entity, Allocator> &registry) {
ImGui::BeginTabBar("#tabs");
if(ImGui::BeginTabItem("Entity")) {
for(const auto [entt]: registry.template storage<Entity>()->each()) {
ImGui::PushID(static_cast<int>(to_entity(entt)));
if(ImGui::TreeNode(&type_id<Entity>(), "%d [%d/%d]", to_integral(entt), to_entity(entt), to_version(entt))) {
const auto range = registry.storage();
internal::present_entity(ctx, entt, range.begin(), range.end());
ImGui::TreePop();
}
ImGui::PopID();
}
ImGui::EndTabItem();
}
if(ImGui::BeginTabItem("Storage")) {
for([[maybe_unused]] auto [id, storage]: registry.storage()) {
const auto type = resolve(ctx, storage.info());
const char *label = type.name() ? type.name() : std::string{storage.info().name()}.data();
if(ImGui::TreeNode(&storage.info(), "%s (%zu)", label, storage.size())) {
internal::present_storage(ctx, storage);
ImGui::TreePop();
}
}
ImGui::EndTabItem();
}
ImGui::EndTabBar();
}
/**
* @brief ImGui-based introspection tool for registry types.
* @tparam Entity Registry entity type.
* @tparam Allocator Registry allocator type.
* @param registry An instance of the registry type.
*/
template<typename Entity, typename Allocator>
void davey(const basic_registry<Entity, Allocator> &registry) {
davey(locator<meta_ctx>::value_or(), registry);
}
} // namespace entt
#endif
+7 -9
View File
@@ -43,6 +43,8 @@ function(SETUP_TARGET TARGET_NAME)
target_link_libraries(${TARGET_NAME} PRIVATE EnTT)
if(MSVC)
set_target_properties(${TARGET_NAME} PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/PROFILE")
target_compile_options(
${TARGET_NAME}
PRIVATE
@@ -63,6 +65,7 @@ function(SETUP_TARGET TARGET_NAME)
PRIVATE
# disabling INCREMENTAL is required by SizeBench
$<$<CONFIG:Debug>:/INCREMENTAL:NO>
$<$<CONFIG:Release>:/OPT:NOICF>
)
else()
target_compile_options(
@@ -115,13 +118,12 @@ function(SETUP_LIB_PLUGIN_TEST TEST_NAME SUB_PATH)
add_library(_${TARGET_NAME} MODULE $<TARGET_OBJECTS:odr> lib/${TEST_NAME}/${SUB_PATH}/plugin.cpp)
SETUP_TARGET(_${TARGET_NAME} ${ARGVN})
SETUP_BASIC_TEST(lib_${TARGET_NAME} lib/${TEST_NAME}/${SUB_PATH}/main.cpp PLUGIN="$<TARGET_FILE:_${TARGET_NAME}>" ${ARGVN})
target_link_libraries(_${TARGET_NAME} PRIVATE cr::cr)
target_link_libraries(lib_${TARGET_NAME} PRIVATE cr::cr ${CMAKE_DL_LIBS})
set_target_properties(_${TARGET_NAME} PROPERTIES CXX_CLANG_TIDY "")
set_target_properties(lib_${TARGET_NAME} PROPERTIES CXX_CLANG_TIDY "")
target_include_directories(_${TARGET_NAME} PRIVATE ${cr_INCLUDE_DIR})
target_include_directories(lib_${TARGET_NAME} PRIVATE ${cr_INCLUDE_DIR})
target_compile_options(_${TARGET_NAME} PRIVATE $<$<NOT:$<STREQUAL:"${CMAKE_CXX_COMPILER_ID}","MSVC">>:-Wno-conversion>)
target_compile_options(lib_${TARGET_NAME} PRIVATE $<$<NOT:$<STREQUAL:"${CMAKE_CXX_COMPILER_ID}","MSVC">>:-Wno-conversion>)
target_link_libraries(lib_${TARGET_NAME} PRIVATE ${CMAKE_DL_LIBS})
add_dependencies(lib_${TARGET_NAME} _${TARGET_NAME})
endfunction()
@@ -151,12 +153,9 @@ if(ENTT_BUILD_LIB)
GIT_SHALLOW 1
)
FetchContent_GetProperties(cr)
FetchContent_MakeAvailable(cr)
if(NOT cr_POPULATED)
FetchContent_Populate(cr)
set(cr_INCLUDE_DIR ${cr_SOURCE_DIR})
endif()
add_library(cr::cr ALIAS cr)
SETUP_LIB_SHARED_TEST(dispatcher shared)
SETUP_LIB_PLUGIN_TEST(dispatcher plugin)
@@ -271,7 +270,6 @@ SETUP_BASIC_TEST(meta_conv entt/meta/meta_conv.cpp)
SETUP_BASIC_TEST(meta_ctor entt/meta/meta_ctor.cpp)
SETUP_BASIC_TEST(meta_custom entt/meta/meta_custom.cpp)
SETUP_BASIC_TEST(meta_data entt/meta/meta_data.cpp)
SETUP_BASIC_TEST(meta_dtor entt/meta/meta_dtor.cpp)
SETUP_BASIC_TEST(meta_factory entt/meta/meta_factory.cpp)
SETUP_BASIC_TEST(meta_func entt/meta/meta_func.cpp)
SETUP_BASIC_TEST(meta_handle entt/meta/meta_handle.cpp)
+7 -6
View File
@@ -5,12 +5,13 @@
namespace test {
enum class meta_traits {
none = 0x0000,
one = 0x0001,
two = 0x0002,
three = 0x0100,
_entt_enum_as_bitmask
enum class meta_traits : std::uint8_t {
none = 0x00,
one = 0x01,
two = 0x02,
three = 0x04,
all = 0xFF,
_entt_enum_as_bitmask = all
};
} // namespace test
+29 -21
View File
@@ -1,6 +1,7 @@
#include <array>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <iterator>
#include <memory>
@@ -818,8 +819,8 @@ TEST(DenseMap, EraseFromBucket) {
for(std::size_t next{}; next < 4u; ++next) {
ASSERT_TRUE(map.emplace(2u * minimum_bucket_count * next, 2u * minimum_bucket_count * next).second);
ASSERT_TRUE(map.emplace(2u * minimum_bucket_count * next + 2u, 2u * minimum_bucket_count * next + 2u).second);
ASSERT_TRUE(map.emplace(2u * minimum_bucket_count * next + 3u, 2u * minimum_bucket_count * next + 3u).second);
ASSERT_TRUE(map.emplace((2u * minimum_bucket_count * next) + 2u, (2u * minimum_bucket_count * next) + 2u).second);
ASSERT_TRUE(map.emplace((2u * minimum_bucket_count * next) + 3u, (2u * minimum_bucket_count * next) + 3u).second);
}
ASSERT_EQ(map.bucket_count(), 2u * minimum_bucket_count);
@@ -842,16 +843,16 @@ TEST(DenseMap, EraseFromBucket) {
ASSERT_TRUE(map.contains(2u * minimum_bucket_count * next));
ASSERT_EQ(map.bucket(2u * minimum_bucket_count * next), 0u);
ASSERT_TRUE(map.contains(2u * minimum_bucket_count * next + 2u));
ASSERT_EQ(map.bucket(2u * minimum_bucket_count * next + 2u), 2u);
ASSERT_TRUE(map.contains((2u * minimum_bucket_count * next) + 2u));
ASSERT_EQ(map.bucket((2u * minimum_bucket_count * next) + 2u), 2u);
ASSERT_TRUE(map.contains(2u * minimum_bucket_count * next + 3u));
ASSERT_EQ(map.bucket(2u * minimum_bucket_count * next + 3u), 3u);
ASSERT_TRUE(map.contains((2u * minimum_bucket_count * next) + 3u));
ASSERT_EQ(map.bucket((2u * minimum_bucket_count * next) + 3u), 3u);
}
ASSERT_FALSE(map.contains(2u * minimum_bucket_count * 3u));
ASSERT_FALSE(map.contains(2u * minimum_bucket_count * 3u + 2u));
ASSERT_FALSE(map.contains(2u * minimum_bucket_count * 3u + 3u));
ASSERT_FALSE(map.contains((2u * minimum_bucket_count * 3u) + 2u));
ASSERT_FALSE(map.contains((2u * minimum_bucket_count * 3u) + 3u));
map.erase((++map.begin(0u))->first);
map.erase((++map.begin(2u))->first);
@@ -865,8 +866,8 @@ TEST(DenseMap, EraseFromBucket) {
ASSERT_EQ(map.bucket_size(3u), 2u);
ASSERT_FALSE(map.contains(2u * minimum_bucket_count * 1u));
ASSERT_FALSE(map.contains(2u * minimum_bucket_count * 1u + 2u));
ASSERT_FALSE(map.contains(2u * minimum_bucket_count * 1u + 3u));
ASSERT_FALSE(map.contains((2u * minimum_bucket_count * 1u) + 2u));
ASSERT_FALSE(map.contains((2u * minimum_bucket_count * 1u) + 3u));
while(map.begin(3) != map.end(3u)) {
map.erase(map.begin(3)->first);
@@ -880,11 +881,11 @@ TEST(DenseMap, EraseFromBucket) {
ASSERT_EQ(map.bucket_size(3u), 0u);
ASSERT_TRUE(map.contains(0u * minimum_bucket_count));
ASSERT_TRUE(map.contains(0u * minimum_bucket_count + 2u));
ASSERT_TRUE(map.contains((0u * minimum_bucket_count) + 2u));
ASSERT_TRUE(map.contains(4u * minimum_bucket_count));
ASSERT_TRUE(map.contains(4u * minimum_bucket_count + 2u));
ASSERT_TRUE(map.contains((4u * minimum_bucket_count) + 2u));
map.erase(4u * minimum_bucket_count + 2u);
map.erase((4u * minimum_bucket_count) + 2u);
map.erase(0u * minimum_bucket_count);
ASSERT_EQ(map.bucket_count(), 2u * minimum_bucket_count);
@@ -895,9 +896,9 @@ TEST(DenseMap, EraseFromBucket) {
ASSERT_EQ(map.bucket_size(3u), 0u);
ASSERT_FALSE(map.contains(0u * minimum_bucket_count));
ASSERT_TRUE(map.contains(0u * minimum_bucket_count + 2u));
ASSERT_TRUE(map.contains((0u * minimum_bucket_count) + 2u));
ASSERT_TRUE(map.contains(4u * minimum_bucket_count));
ASSERT_FALSE(map.contains(4u * minimum_bucket_count + 2u));
ASSERT_FALSE(map.contains((4u * minimum_bucket_count) + 2u));
}
TEST(DenseMap, Swap) {
@@ -959,7 +960,7 @@ TEST(DenseMap, EqualRange) {
}
TEST(DenseMap, Indexing) {
entt::dense_map<int, int> map;
entt::dense_map<int, int, entt::identity, test::transparent_equal_to> map;
const auto &cmap = map;
const auto key = 1;
@@ -969,16 +970,23 @@ TEST(DenseMap, Indexing) {
ASSERT_TRUE(map.contains(key));
ASSERT_EQ(map[int{key}], 3);
ASSERT_EQ(cmap.at(key), 3);
ASSERT_EQ(map.at(key), 3);
ASSERT_EQ(cmap.at(key), 3);
ASSERT_EQ(map.at(static_cast<double>(key)), 3);
ASSERT_EQ(cmap.at(static_cast<double>(key)), 3);
}
ENTT_DEBUG_TEST(DenseMapDeathTest, Indexing) {
entt::dense_map<int, int> map;
entt::dense_map<int, int, entt::identity, test::transparent_equal_to> map;
const auto &cmap = map;
ASSERT_DEATH([[maybe_unused]] auto value = cmap.at(0), "");
ASSERT_DEATH([[maybe_unused]] auto value = map.at(3), "");
ASSERT_DEATH([[maybe_unused]] auto value = cmap.at(0), "");
ASSERT_DEATH([[maybe_unused]] auto value = map.at(3.), "");
ASSERT_DEATH([[maybe_unused]] auto value = cmap.at(0.), "");
}
TEST(DenseMap, LocalIterator) {
@@ -1073,7 +1081,7 @@ TEST(DenseMap, Rehash) {
ASSERT_EQ(map.bucket(32u), 0u);
ASSERT_EQ(map[32u], 2u);
map.rehash(4u * minimum_bucket_count + 1u);
map.rehash((4u * minimum_bucket_count) + 1u);
ASSERT_EQ(map.bucket_count(), 8u * minimum_bucket_count);
ASSERT_TRUE(map.contains(32u));
@@ -1099,7 +1107,7 @@ TEST(DenseMap, Rehash) {
ASSERT_EQ(map.bucket_count(), 2u * minimum_bucket_count);
ASSERT_TRUE(map.contains(32u));
map.rehash(4u * minimum_bucket_count + 4u);
map.rehash((4u * minimum_bucket_count) + 4u);
ASSERT_EQ(map.bucket_count(), 8u * minimum_bucket_count);
ASSERT_TRUE(map.contains(32u));
+17 -17
View File
@@ -676,8 +676,8 @@ TEST(DenseSet, EraseFromBucket) {
for(std::size_t next{}; next < 4u; ++next) {
ASSERT_TRUE(set.emplace(2u * minimum_bucket_count * next).second);
ASSERT_TRUE(set.emplace(2u * minimum_bucket_count * next + 2u).second);
ASSERT_TRUE(set.emplace(2u * minimum_bucket_count * next + 3u).second);
ASSERT_TRUE(set.emplace((2u * minimum_bucket_count * next) + 2u).second);
ASSERT_TRUE(set.emplace((2u * minimum_bucket_count * next) + 3u).second);
}
ASSERT_EQ(set.bucket_count(), 2u * minimum_bucket_count);
@@ -700,16 +700,16 @@ TEST(DenseSet, EraseFromBucket) {
ASSERT_TRUE(set.contains(2u * minimum_bucket_count * next));
ASSERT_EQ(set.bucket(2u * minimum_bucket_count * next), 0u);
ASSERT_TRUE(set.contains(2u * minimum_bucket_count * next + 2u));
ASSERT_EQ(set.bucket(2u * minimum_bucket_count * next + 2u), 2u);
ASSERT_TRUE(set.contains((2u * minimum_bucket_count * next) + 2u));
ASSERT_EQ(set.bucket((2u * minimum_bucket_count * next) + 2u), 2u);
ASSERT_TRUE(set.contains(2u * minimum_bucket_count * next + 3u));
ASSERT_EQ(set.bucket(2u * minimum_bucket_count * next + 3u), 3u);
ASSERT_TRUE(set.contains((2u * minimum_bucket_count * next) + 3u));
ASSERT_EQ(set.bucket((2u * minimum_bucket_count * next) + 3u), 3u);
}
ASSERT_FALSE(set.contains(2u * minimum_bucket_count * 3u));
ASSERT_FALSE(set.contains(2u * minimum_bucket_count * 3u + 2u));
ASSERT_FALSE(set.contains(2u * minimum_bucket_count * 3u + 3u));
ASSERT_FALSE(set.contains((2u * minimum_bucket_count * 3u) + 2u));
ASSERT_FALSE(set.contains((2u * minimum_bucket_count * 3u) + 3u));
set.erase(*++set.begin(0u));
set.erase(*++set.begin(2u));
@@ -723,8 +723,8 @@ TEST(DenseSet, EraseFromBucket) {
ASSERT_EQ(set.bucket_size(3u), 2u);
ASSERT_FALSE(set.contains(2u * minimum_bucket_count * 1u));
ASSERT_FALSE(set.contains(2u * minimum_bucket_count * 1u + 2u));
ASSERT_FALSE(set.contains(2u * minimum_bucket_count * 1u + 3u));
ASSERT_FALSE(set.contains((2u * minimum_bucket_count * 1u) + 2u));
ASSERT_FALSE(set.contains((2u * minimum_bucket_count * 1u) + 3u));
while(set.begin(3) != set.end(3u)) {
set.erase(*set.begin(3));
@@ -738,11 +738,11 @@ TEST(DenseSet, EraseFromBucket) {
ASSERT_EQ(set.bucket_size(3u), 0u);
ASSERT_TRUE(set.contains(0u * minimum_bucket_count));
ASSERT_TRUE(set.contains(0u * minimum_bucket_count + 2u));
ASSERT_TRUE(set.contains((0u * minimum_bucket_count) + 2u));
ASSERT_TRUE(set.contains(4u * minimum_bucket_count));
ASSERT_TRUE(set.contains(4u * minimum_bucket_count + 2u));
ASSERT_TRUE(set.contains((4u * minimum_bucket_count) + 2u));
set.erase(4u * minimum_bucket_count + 2u);
set.erase((4u * minimum_bucket_count) + 2u);
set.erase(0u * minimum_bucket_count);
ASSERT_EQ(set.bucket_count(), 2u * minimum_bucket_count);
@@ -753,9 +753,9 @@ TEST(DenseSet, EraseFromBucket) {
ASSERT_EQ(set.bucket_size(3u), 0u);
ASSERT_FALSE(set.contains(0u * minimum_bucket_count));
ASSERT_TRUE(set.contains(0u * minimum_bucket_count + 2u));
ASSERT_TRUE(set.contains((0u * minimum_bucket_count) + 2u));
ASSERT_TRUE(set.contains(4u * minimum_bucket_count));
ASSERT_FALSE(set.contains(4u * minimum_bucket_count + 2u));
ASSERT_FALSE(set.contains((4u * minimum_bucket_count) + 2u));
}
TEST(DenseSet, Swap) {
@@ -902,7 +902,7 @@ TEST(DenseSet, Rehash) {
ASSERT_TRUE(set.contains(32u));
ASSERT_EQ(set.bucket(32u), 0u);
set.rehash(4u * minimum_bucket_count + 1u);
set.rehash((4u * minimum_bucket_count) + 1u);
ASSERT_EQ(set.bucket_count(), 8u * minimum_bucket_count);
ASSERT_TRUE(set.contains(32u));
@@ -926,7 +926,7 @@ TEST(DenseSet, Rehash) {
ASSERT_EQ(set.bucket_count(), 2u * minimum_bucket_count);
ASSERT_TRUE(set.contains(32u));
set.rehash(4u * minimum_bucket_count + 4u);
set.rehash((4u * minimum_bucket_count) + 4u);
ASSERT_EQ(set.bucket_count(), 8u * minimum_bucket_count);
ASSERT_TRUE(set.contains(32u));
+157 -100
View File
@@ -57,6 +57,24 @@ TEST(Any, Empty) {
ASSERT_EQ(any.data(), nullptr);
}
TEST(Any, HasValue) {
entt::any any{};
ASSERT_FALSE(any.has_value());
ASSERT_FALSE(any.has_value(entt::type_id<char>()));
ASSERT_FALSE(any.has_value(entt::type_id<int>()));
ASSERT_FALSE(any.has_value<char>());
ASSERT_FALSE(any.has_value<int>());
any = 2;
ASSERT_TRUE(any.has_value());
ASSERT_FALSE(any.has_value(entt::type_id<char>()));
ASSERT_TRUE(any.has_value(entt::type_id<int>()));
ASSERT_FALSE(any.has_value<char>());
ASSERT_TRUE(any.has_value<int>());
}
TEST(Any, SBO) {
entt::any any{'c'};
@@ -88,7 +106,7 @@ TEST(Any, SBOInPlaceConstruction) {
ASSERT_TRUE(any);
ASSERT_TRUE(any.owner());
ASSERT_EQ(any.policy(), entt::any_policy::dynamic);
ASSERT_EQ(any.type(), entt::type_id<int>());
ASSERT_EQ(any.info(), entt::type_id<int>());
ASSERT_EQ(entt::any_cast<double>(&any), nullptr);
ASSERT_EQ(entt::any_cast<int>(any), 2);
@@ -97,7 +115,7 @@ TEST(Any, SBOInPlaceConstruction) {
ASSERT_TRUE(other);
ASSERT_FALSE(other.owner());
ASSERT_EQ(other.policy(), entt::any_policy::ref);
ASSERT_EQ(other.type(), entt::type_id<int>());
ASSERT_EQ(other.info(), entt::type_id<int>());
ASSERT_EQ(entt::any_cast<int>(other), 2);
ASSERT_EQ(other.data(), any.data());
}
@@ -109,7 +127,7 @@ TEST(Any, SBOInPlaceNullptrConstruction) {
ASSERT_FALSE(any);
ASSERT_FALSE(any.owner());
ASSERT_EQ(any.policy(), entt::any_policy::empty);
ASSERT_EQ(any.type(), entt::type_id<void>());
ASSERT_EQ(any.info(), entt::type_id<void>());
}
TEST(Any, SBOInPlaceTypeConstruction) {
@@ -118,7 +136,7 @@ TEST(Any, SBOInPlaceTypeConstruction) {
ASSERT_TRUE(any);
ASSERT_TRUE(any.owner());
ASSERT_EQ(any.policy(), entt::any_policy::embedded);
ASSERT_EQ(any.type(), entt::type_id<int>());
ASSERT_EQ(any.info(), entt::type_id<int>());
ASSERT_EQ(entt::any_cast<double>(&any), nullptr);
ASSERT_EQ(entt::any_cast<int>(any), 2);
@@ -127,7 +145,7 @@ TEST(Any, SBOInPlaceTypeConstruction) {
ASSERT_TRUE(other);
ASSERT_FALSE(other.owner());
ASSERT_EQ(other.policy(), entt::any_policy::ref);
ASSERT_EQ(other.type(), entt::type_id<int>());
ASSERT_EQ(other.info(), entt::type_id<int>());
ASSERT_EQ(entt::any_cast<int>(other), 2);
ASSERT_EQ(other.data(), any.data());
}
@@ -139,7 +157,7 @@ TEST(Any, SBOAsRefConstruction) {
ASSERT_TRUE(any);
ASSERT_FALSE(any.owner());
ASSERT_EQ(any.policy(), entt::any_policy::ref);
ASSERT_EQ(any.type(), entt::type_id<int>());
ASSERT_EQ(any.info(), entt::type_id<int>());
ASSERT_EQ(entt::any_cast<double>(&any), nullptr);
ASSERT_EQ(entt::any_cast<const int>(&any), &value);
@@ -158,7 +176,7 @@ TEST(Any, SBOAsRefConstruction) {
ASSERT_TRUE(any);
ASSERT_FALSE(any.owner());
ASSERT_EQ(any.policy(), entt::any_policy::ref);
ASSERT_EQ(any.type(), entt::type_id<int>());
ASSERT_EQ(any.info(), entt::type_id<int>());
ASSERT_EQ(entt::any_cast<int>(&any), &value);
auto other = any.as_ref();
@@ -166,7 +184,7 @@ TEST(Any, SBOAsRefConstruction) {
ASSERT_TRUE(other);
ASSERT_FALSE(other.owner());
ASSERT_EQ(other.policy(), entt::any_policy::ref);
ASSERT_EQ(other.type(), entt::type_id<int>());
ASSERT_EQ(other.info(), entt::type_id<int>());
ASSERT_EQ(entt::any_cast<int>(other), 2);
ASSERT_EQ(other.data(), any.data());
}
@@ -178,7 +196,7 @@ TEST(Any, SBOAsConstRefConstruction) {
ASSERT_TRUE(any);
ASSERT_FALSE(any.owner());
ASSERT_EQ(any.policy(), entt::any_policy::cref);
ASSERT_EQ(any.type(), entt::type_id<int>());
ASSERT_EQ(any.info(), entt::type_id<int>());
ASSERT_EQ(entt::any_cast<double>(&any), nullptr);
ASSERT_EQ(entt::any_cast<const int>(&any), &value);
@@ -197,7 +215,7 @@ TEST(Any, SBOAsConstRefConstruction) {
ASSERT_TRUE(any);
ASSERT_FALSE(any.owner());
ASSERT_EQ(any.policy(), entt::any_policy::cref);
ASSERT_EQ(any.type(), entt::type_id<int>());
ASSERT_EQ(any.info(), entt::type_id<int>());
ASSERT_EQ(entt::any_cast<const int>(&any), &value);
auto other = any.as_ref();
@@ -205,7 +223,7 @@ TEST(Any, SBOAsConstRefConstruction) {
ASSERT_TRUE(other);
ASSERT_FALSE(other.owner());
ASSERT_EQ(other.policy(), entt::any_policy::cref);
ASSERT_EQ(other.type(), entt::type_id<int>());
ASSERT_EQ(other.info(), entt::type_id<int>());
ASSERT_EQ(entt::any_cast<int>(other), 2);
ASSERT_EQ(other.data(), any.data());
}
@@ -218,7 +236,7 @@ TEST(Any, SBOCopyConstruction) {
ASSERT_TRUE(other);
ASSERT_TRUE(other.owner());
ASSERT_EQ(other.policy(), entt::any_policy::embedded);
ASSERT_EQ(other.type(), entt::type_id<int>());
ASSERT_EQ(other.info(), entt::type_id<int>());
ASSERT_EQ(entt::any_cast<double>(&other), nullptr);
ASSERT_EQ(entt::any_cast<int>(other), 2);
}
@@ -233,7 +251,7 @@ TEST(Any, SBOCopyAssignment) {
ASSERT_TRUE(other);
ASSERT_TRUE(other.owner());
ASSERT_EQ(other.policy(), entt::any_policy::embedded);
ASSERT_EQ(other.type(), entt::type_id<int>());
ASSERT_EQ(other.info(), entt::type_id<int>());
ASSERT_EQ(entt::any_cast<double>(&other), nullptr);
ASSERT_EQ(entt::any_cast<int>(other), 2);
}
@@ -247,7 +265,7 @@ TEST(Any, SBOSelfCopyAssignment) {
ASSERT_TRUE(any);
ASSERT_TRUE(any.owner());
ASSERT_EQ(any.policy(), entt::any_policy::embedded);
ASSERT_EQ(any.type(), entt::type_id<int>());
ASSERT_EQ(any.info(), entt::type_id<int>());
ASSERT_EQ(entt::any_cast<double>(&any), nullptr);
ASSERT_EQ(entt::any_cast<int>(any), 2);
}
@@ -262,7 +280,7 @@ TEST(Any, SBOMoveConstruction) {
ASSERT_TRUE(other);
ASSERT_TRUE(other.owner());
ASSERT_EQ(other.policy(), entt::any_policy::embedded);
ASSERT_EQ(other.type(), entt::type_id<int>());
ASSERT_EQ(other.info(), entt::type_id<int>());
ASSERT_EQ(entt::any_cast<double>(&other), nullptr);
ASSERT_EQ(entt::any_cast<int>(other), 2);
}
@@ -278,22 +296,22 @@ TEST(Any, SBOMoveAssignment) {
ASSERT_TRUE(other);
ASSERT_TRUE(other.owner());
ASSERT_EQ(other.policy(), entt::any_policy::embedded);
ASSERT_EQ(other.type(), entt::type_id<int>());
ASSERT_EQ(other.info(), entt::type_id<int>());
ASSERT_EQ(entt::any_cast<double>(&other), nullptr);
ASSERT_EQ(entt::any_cast<int>(other), 2);
}
TEST(AnyDeathTest, SBOSelfMoveAssignment) {
TEST(Any, SBOSelfMoveAssignment) {
entt::any any{2};
// avoid warnings due to self-assignment
any = std::move(*&any);
ASSERT_FALSE(any);
ASSERT_FALSE(any.owner());
ASSERT_EQ(any.policy(), entt::any_policy::empty);
ASSERT_EQ(any.type(), entt::type_id<void>());
ASSERT_EQ(any.data(), nullptr);
ASSERT_TRUE(any);
ASSERT_TRUE(any.owner());
ASSERT_EQ(any.policy(), entt::any_policy::embedded);
ASSERT_EQ(any.info(), entt::type_id<int>());
ASSERT_EQ(entt::any_cast<int>(any), 2);
}
TEST(Any, SBODirectAssignment) {
@@ -303,7 +321,7 @@ TEST(Any, SBODirectAssignment) {
ASSERT_TRUE(any);
ASSERT_TRUE(any.owner());
ASSERT_EQ(any.policy(), entt::any_policy::embedded);
ASSERT_EQ(any.type(), entt::type_id<int>());
ASSERT_EQ(any.info(), entt::type_id<int>());
ASSERT_EQ(entt::any_cast<double>(&any), nullptr);
ASSERT_EQ(entt::any_cast<int>(any), 2);
}
@@ -407,7 +425,7 @@ TEST(Any, NoSBOInPlaceConstruction) {
ASSERT_TRUE(any);
ASSERT_TRUE(any.owner());
ASSERT_EQ(any.policy(), entt::any_policy::dynamic);
ASSERT_EQ(any.type(), entt::type_id<fat>());
ASSERT_EQ(any.info(), entt::type_id<fat>());
ASSERT_EQ(entt::any_cast<double>(&any), nullptr);
ASSERT_EQ(entt::any_cast<fat>(any), (fat{.1, .2, .3, .4}));
@@ -416,7 +434,7 @@ TEST(Any, NoSBOInPlaceConstruction) {
ASSERT_TRUE(other);
ASSERT_FALSE(other.owner());
ASSERT_EQ(other.policy(), entt::any_policy::ref);
ASSERT_EQ(other.type(), entt::type_id<fat>());
ASSERT_EQ(other.info(), entt::type_id<fat>());
ASSERT_EQ(entt::any_cast<fat>(other), (fat{.1, .2, .3, .4}));
ASSERT_EQ(other.data(), any.data());
}
@@ -428,7 +446,7 @@ TEST(Any, NoSBOInPlaceNullptrConstruction) {
ASSERT_FALSE(any);
ASSERT_FALSE(any.owner());
ASSERT_EQ(any.policy(), entt::any_policy::empty);
ASSERT_EQ(any.type(), entt::type_id<void>());
ASSERT_EQ(any.info(), entt::type_id<void>());
}
TEST(Any, NoSBOInPlaceTypeConstruction) {
@@ -438,7 +456,7 @@ TEST(Any, NoSBOInPlaceTypeConstruction) {
ASSERT_TRUE(any);
ASSERT_TRUE(any.owner());
ASSERT_EQ(any.policy(), entt::any_policy::dynamic);
ASSERT_EQ(any.type(), entt::type_id<fat>());
ASSERT_EQ(any.info(), entt::type_id<fat>());
ASSERT_EQ(entt::any_cast<double>(&any), nullptr);
ASSERT_EQ(entt::any_cast<fat>(any), instance);
@@ -447,7 +465,7 @@ TEST(Any, NoSBOInPlaceTypeConstruction) {
ASSERT_TRUE(other);
ASSERT_FALSE(other.owner());
ASSERT_EQ(other.policy(), entt::any_policy::ref);
ASSERT_EQ(other.type(), entt::type_id<fat>());
ASSERT_EQ(other.info(), entt::type_id<fat>());
ASSERT_EQ(entt::any_cast<fat>(other), (fat{.1, .2, .3, .4}));
ASSERT_EQ(other.data(), any.data());
}
@@ -459,7 +477,7 @@ TEST(Any, NoSBOAsRefConstruction) {
ASSERT_TRUE(any);
ASSERT_FALSE(any.owner());
ASSERT_EQ(any.policy(), entt::any_policy::ref);
ASSERT_EQ(any.type(), entt::type_id<fat>());
ASSERT_EQ(any.info(), entt::type_id<fat>());
ASSERT_EQ(entt::any_cast<double>(&any), nullptr);
ASSERT_EQ(entt::any_cast<const fat>(&any), &instance);
@@ -478,7 +496,7 @@ TEST(Any, NoSBOAsRefConstruction) {
ASSERT_TRUE(any);
ASSERT_FALSE(any.owner());
ASSERT_EQ(any.policy(), entt::any_policy::ref);
ASSERT_EQ(any.type(), entt::type_id<fat>());
ASSERT_EQ(any.info(), entt::type_id<fat>());
ASSERT_EQ(entt::any_cast<fat>(&any), &instance);
auto other = any.as_ref();
@@ -486,7 +504,7 @@ TEST(Any, NoSBOAsRefConstruction) {
ASSERT_TRUE(other);
ASSERT_FALSE(other.owner());
ASSERT_EQ(other.policy(), entt::any_policy::ref);
ASSERT_EQ(other.type(), entt::type_id<fat>());
ASSERT_EQ(other.info(), entt::type_id<fat>());
ASSERT_EQ(entt::any_cast<fat>(other), (fat{.1, .2, .3, .4}));
ASSERT_EQ(other.data(), any.data());
}
@@ -498,7 +516,7 @@ TEST(Any, NoSBOAsConstRefConstruction) {
ASSERT_TRUE(any);
ASSERT_FALSE(any.owner());
ASSERT_EQ(any.policy(), entt::any_policy::cref);
ASSERT_EQ(any.type(), entt::type_id<fat>());
ASSERT_EQ(any.info(), entt::type_id<fat>());
ASSERT_EQ(entt::any_cast<double>(&any), nullptr);
ASSERT_EQ(entt::any_cast<const fat>(&any), &instance);
@@ -517,7 +535,7 @@ TEST(Any, NoSBOAsConstRefConstruction) {
ASSERT_TRUE(any);
ASSERT_FALSE(any.owner());
ASSERT_EQ(any.policy(), entt::any_policy::cref);
ASSERT_EQ(any.type(), entt::type_id<fat>());
ASSERT_EQ(any.info(), entt::type_id<fat>());
ASSERT_EQ(entt::any_cast<const fat>(&any), &instance);
auto other = any.as_ref();
@@ -525,7 +543,7 @@ TEST(Any, NoSBOAsConstRefConstruction) {
ASSERT_TRUE(other);
ASSERT_FALSE(other.owner());
ASSERT_EQ(other.policy(), entt::any_policy::cref);
ASSERT_EQ(other.type(), entt::type_id<fat>());
ASSERT_EQ(other.info(), entt::type_id<fat>());
ASSERT_EQ(entt::any_cast<fat>(other), (fat{.1, .2, .3, .4}));
ASSERT_EQ(other.data(), any.data());
}
@@ -539,7 +557,7 @@ TEST(Any, NoSBOCopyConstruction) {
ASSERT_TRUE(other);
ASSERT_TRUE(other.owner());
ASSERT_EQ(other.policy(), entt::any_policy::dynamic);
ASSERT_EQ(other.type(), entt::type_id<fat>());
ASSERT_EQ(other.info(), entt::type_id<fat>());
ASSERT_EQ(entt::any_cast<double>(&other), nullptr);
ASSERT_EQ(entt::any_cast<fat>(other), instance);
}
@@ -555,7 +573,7 @@ TEST(Any, NoSBOCopyAssignment) {
ASSERT_TRUE(other);
ASSERT_TRUE(other.owner());
ASSERT_EQ(other.policy(), entt::any_policy::dynamic);
ASSERT_EQ(other.type(), entt::type_id<fat>());
ASSERT_EQ(other.info(), entt::type_id<fat>());
ASSERT_EQ(entt::any_cast<double>(&other), nullptr);
ASSERT_EQ(entt::any_cast<fat>(other), instance);
}
@@ -570,7 +588,7 @@ TEST(Any, NoSBOSelfCopyAssignment) {
ASSERT_TRUE(any);
ASSERT_TRUE(any.owner());
ASSERT_EQ(any.policy(), entt::any_policy::dynamic);
ASSERT_EQ(any.type(), entt::type_id<fat>());
ASSERT_EQ(any.info(), entt::type_id<fat>());
ASSERT_EQ(entt::any_cast<double>(&any), nullptr);
ASSERT_EQ(entt::any_cast<fat>(any), instance);
}
@@ -586,7 +604,7 @@ TEST(Any, NoSBOMoveConstruction) {
ASSERT_TRUE(other);
ASSERT_TRUE(other.owner());
ASSERT_EQ(other.policy(), entt::any_policy::dynamic);
ASSERT_EQ(other.type(), entt::type_id<fat>());
ASSERT_EQ(other.info(), entt::type_id<fat>());
ASSERT_EQ(entt::any_cast<double>(&other), nullptr);
ASSERT_EQ(entt::any_cast<fat>(other), instance);
}
@@ -603,23 +621,23 @@ TEST(Any, NoSBOMoveAssignment) {
ASSERT_TRUE(other);
ASSERT_TRUE(other.owner());
ASSERT_EQ(other.policy(), entt::any_policy::dynamic);
ASSERT_EQ(other.type(), entt::type_id<fat>());
ASSERT_EQ(other.info(), entt::type_id<fat>());
ASSERT_EQ(entt::any_cast<double>(&other), nullptr);
ASSERT_EQ(entt::any_cast<fat>(other), instance);
}
TEST(AnyDeathTest, NoSBOSelfMoveAssignment) {
TEST(Any, NoSBOSelfMoveAssignment) {
const fat instance{.1, .2, .3, .4};
entt::any any{instance};
// avoid warnings due to self-assignment
any = std::move(*&any);
ASSERT_FALSE(any);
ASSERT_FALSE(any.owner());
ASSERT_EQ(any.policy(), entt::any_policy::empty);
ASSERT_EQ(any.type(), entt::type_id<void>());
ASSERT_EQ(any.data(), nullptr);
ASSERT_TRUE(any);
ASSERT_TRUE(any.owner());
ASSERT_EQ(any.policy(), entt::any_policy::dynamic);
ASSERT_EQ(any.info(), entt::type_id<fat>());
ASSERT_EQ(entt::any_cast<fat>(any), instance);
}
TEST(Any, NoSBODirectAssignment) {
@@ -630,7 +648,7 @@ TEST(Any, NoSBODirectAssignment) {
ASSERT_TRUE(any);
ASSERT_TRUE(any.owner());
ASSERT_EQ(any.policy(), entt::any_policy::dynamic);
ASSERT_EQ(any.type(), entt::type_id<fat>());
ASSERT_EQ(any.info(), entt::type_id<fat>());
ASSERT_EQ(entt::any_cast<double>(&any), nullptr);
ASSERT_EQ(entt::any_cast<fat>(any), instance);
}
@@ -747,7 +765,7 @@ TEST(Any, VoidInPlaceTypeConstruction) {
ASSERT_FALSE(any);
ASSERT_FALSE(any.owner());
ASSERT_EQ(any.policy(), entt::any_policy::empty);
ASSERT_EQ(any.type(), entt::type_id<void>());
ASSERT_EQ(any.info(), entt::type_id<void>());
ASSERT_EQ(entt::any_cast<int>(&any), nullptr);
}
@@ -759,7 +777,7 @@ TEST(Any, VoidCopyConstruction) {
ASSERT_FALSE(other);
ASSERT_FALSE(other.owner());
ASSERT_EQ(other.policy(), entt::any_policy::empty);
ASSERT_EQ(other.type(), entt::type_id<void>());
ASSERT_EQ(other.info(), entt::type_id<void>());
ASSERT_EQ(entt::any_cast<int>(&any), nullptr);
ASSERT_EQ(entt::any_cast<double>(&other), nullptr);
}
@@ -774,7 +792,7 @@ TEST(Any, VoidCopyAssignment) {
ASSERT_FALSE(other);
ASSERT_FALSE(other.owner());
ASSERT_EQ(other.policy(), entt::any_policy::empty);
ASSERT_EQ(other.type(), entt::type_id<void>());
ASSERT_EQ(other.info(), entt::type_id<void>());
ASSERT_EQ(entt::any_cast<int>(&any), nullptr);
ASSERT_EQ(entt::any_cast<double>(&other), nullptr);
}
@@ -788,7 +806,7 @@ TEST(Any, VoidSelfCopyAssignment) {
ASSERT_FALSE(any);
ASSERT_FALSE(any.owner());
ASSERT_EQ(any.policy(), entt::any_policy::empty);
ASSERT_EQ(any.type(), entt::type_id<void>());
ASSERT_EQ(any.info(), entt::type_id<void>());
ASSERT_EQ(entt::any_cast<int>(&any), nullptr);
ASSERT_EQ(entt::any_cast<double>(&any), nullptr);
}
@@ -803,7 +821,7 @@ TEST(Any, VoidMoveConstruction) {
ASSERT_FALSE(other);
ASSERT_FALSE(other.owner());
ASSERT_EQ(other.policy(), entt::any_policy::empty);
ASSERT_EQ(other.type(), entt::type_id<void>());
ASSERT_EQ(other.info(), entt::type_id<void>());
ASSERT_EQ(entt::any_cast<double>(&other), nullptr);
}
@@ -818,11 +836,11 @@ TEST(Any, VoidMoveAssignment) {
ASSERT_FALSE(other);
ASSERT_FALSE(other.owner());
ASSERT_EQ(other.policy(), entt::any_policy::empty);
ASSERT_EQ(other.type(), entt::type_id<void>());
ASSERT_EQ(other.info(), entt::type_id<void>());
ASSERT_EQ(entt::any_cast<double>(&other), nullptr);
}
TEST(AnyDeathTest, VoidSelfMoveAssignment) {
TEST(Any, VoidSelfMoveAssignment) {
entt::any any{std::in_place_type<void>};
// avoid warnings due to self-assignment
@@ -831,7 +849,7 @@ TEST(AnyDeathTest, VoidSelfMoveAssignment) {
ASSERT_FALSE(any);
ASSERT_FALSE(any.owner());
ASSERT_EQ(any.policy(), entt::any_policy::empty);
ASSERT_EQ(any.type(), entt::type_id<void>());
ASSERT_EQ(any.info(), entt::type_id<void>());
ASSERT_EQ(any.data(), nullptr);
}
@@ -919,7 +937,7 @@ TEST(Any, Emplace) {
ASSERT_TRUE(any);
ASSERT_TRUE(any.owner());
ASSERT_EQ(any.policy(), entt::any_policy::embedded);
ASSERT_EQ(any.type(), entt::type_id<int>());
ASSERT_EQ(any.info(), entt::type_id<int>());
ASSERT_EQ(entt::any_cast<double>(&any), nullptr);
ASSERT_EQ(entt::any_cast<int>(any), 2);
}
@@ -931,7 +949,7 @@ TEST(Any, EmplaceVoid) {
ASSERT_FALSE(any);
ASSERT_FALSE(any.owner());
ASSERT_EQ(any.policy(), entt::any_policy::empty);
ASSERT_EQ(any.type(), entt::type_id<void>());
ASSERT_EQ(any.info(), entt::type_id<void>());
}
TEST(Any, Reset) {
@@ -940,14 +958,14 @@ TEST(Any, Reset) {
ASSERT_TRUE(any);
ASSERT_TRUE(any.owner());
ASSERT_EQ(any.policy(), entt::any_policy::embedded);
ASSERT_EQ(any.type(), entt::type_id<int>());
ASSERT_EQ(any.info(), entt::type_id<int>());
any.reset();
ASSERT_FALSE(any);
ASSERT_FALSE(any.owner());
ASSERT_EQ(any.policy(), entt::any_policy::empty);
ASSERT_EQ(any.type(), entt::type_id<void>());
ASSERT_EQ(any.info(), entt::type_id<void>());
int value = 2;
any.emplace<int &>(value);
@@ -955,14 +973,14 @@ TEST(Any, Reset) {
ASSERT_TRUE(any);
ASSERT_FALSE(any.owner());
ASSERT_EQ(any.policy(), entt::any_policy::ref);
ASSERT_EQ(any.type(), entt::type_id<int>());
ASSERT_EQ(any.info(), entt::type_id<int>());
any.reset();
ASSERT_FALSE(any);
ASSERT_FALSE(any.owner());
ASSERT_EQ(any.policy(), entt::any_policy::empty);
ASSERT_EQ(any.type(), entt::type_id<void>());
ASSERT_EQ(any.info(), entt::type_id<void>());
}
TEST(Any, SBOSwap) {
@@ -977,8 +995,8 @@ TEST(Any, SBOSwap) {
ASSERT_EQ(lhs.policy(), entt::any_policy::embedded);
ASSERT_EQ(rhs.policy(), entt::any_policy::embedded);
ASSERT_EQ(lhs.type(), entt::type_id<int>());
ASSERT_EQ(rhs.type(), entt::type_id<char>());
ASSERT_EQ(lhs.info(), entt::type_id<int>());
ASSERT_EQ(rhs.info(), entt::type_id<char>());
ASSERT_EQ(entt::any_cast<char>(&lhs), nullptr);
ASSERT_EQ(entt::any_cast<int>(&rhs), nullptr);
ASSERT_EQ(entt::any_cast<int>(lhs), 2);
@@ -1029,8 +1047,8 @@ TEST(Any, SBOWithNoSBOSwap) {
ASSERT_EQ(lhs.policy(), entt::any_policy::embedded);
ASSERT_EQ(rhs.policy(), entt::any_policy::dynamic);
ASSERT_EQ(lhs.type(), entt::type_id<char>());
ASSERT_EQ(rhs.type(), entt::type_id<fat>());
ASSERT_EQ(lhs.info(), entt::type_id<char>());
ASSERT_EQ(rhs.info(), entt::type_id<fat>());
ASSERT_EQ(entt::any_cast<fat>(&lhs), nullptr);
ASSERT_EQ(entt::any_cast<char>(&rhs), nullptr);
ASSERT_EQ(entt::any_cast<char>(lhs), 'c');
@@ -1050,8 +1068,8 @@ TEST(Any, SBOWithRefSwap) {
ASSERT_EQ(lhs.policy(), entt::any_policy::embedded);
ASSERT_EQ(rhs.policy(), entt::any_policy::ref);
ASSERT_EQ(lhs.type(), entt::type_id<char>());
ASSERT_EQ(rhs.type(), entt::type_id<int>());
ASSERT_EQ(lhs.info(), entt::type_id<char>());
ASSERT_EQ(rhs.info(), entt::type_id<int>());
ASSERT_EQ(entt::any_cast<int>(&lhs), nullptr);
ASSERT_EQ(entt::any_cast<char>(&rhs), nullptr);
ASSERT_EQ(entt::any_cast<char>(lhs), 'c');
@@ -1072,8 +1090,8 @@ TEST(Any, SBOWithConstRefSwap) {
ASSERT_EQ(lhs.policy(), entt::any_policy::embedded);
ASSERT_EQ(rhs.policy(), entt::any_policy::cref);
ASSERT_EQ(lhs.type(), entt::type_id<char>());
ASSERT_EQ(rhs.type(), entt::type_id<int>());
ASSERT_EQ(lhs.info(), entt::type_id<char>());
ASSERT_EQ(rhs.info(), entt::type_id<int>());
ASSERT_EQ(entt::any_cast<int>(&lhs), nullptr);
ASSERT_EQ(entt::any_cast<char>(&rhs), nullptr);
ASSERT_EQ(entt::any_cast<char>(lhs), 'c');
@@ -1091,7 +1109,7 @@ TEST(Any, SBOWithEmptySwap) {
ASSERT_FALSE(lhs);
ASSERT_FALSE(lhs.owner());
ASSERT_EQ(lhs.policy(), entt::any_policy::empty);
ASSERT_EQ(rhs.type(), entt::type_id<char>());
ASSERT_EQ(rhs.info(), entt::type_id<char>());
ASSERT_EQ(entt::any_cast<char>(&lhs), nullptr);
ASSERT_EQ(entt::any_cast<double>(&rhs), nullptr);
ASSERT_EQ(entt::any_cast<char>(rhs), 'c');
@@ -1101,7 +1119,7 @@ TEST(Any, SBOWithEmptySwap) {
ASSERT_FALSE(rhs);
ASSERT_TRUE(lhs.owner());
ASSERT_EQ(lhs.policy(), entt::any_policy::embedded);
ASSERT_EQ(lhs.type(), entt::type_id<char>());
ASSERT_EQ(lhs.info(), entt::type_id<char>());
ASSERT_EQ(entt::any_cast<double>(&lhs), nullptr);
ASSERT_EQ(entt::any_cast<char>(&rhs), nullptr);
ASSERT_EQ(entt::any_cast<char>(lhs), 'c');
@@ -1116,7 +1134,7 @@ TEST(Any, SBOWithVoidSwap) {
ASSERT_FALSE(lhs);
ASSERT_FALSE(lhs.owner());
ASSERT_EQ(lhs.policy(), entt::any_policy::empty);
ASSERT_EQ(rhs.type(), entt::type_id<char>());
ASSERT_EQ(rhs.info(), entt::type_id<char>());
ASSERT_EQ(entt::any_cast<char>(&lhs), nullptr);
ASSERT_EQ(entt::any_cast<double>(&rhs), nullptr);
ASSERT_EQ(entt::any_cast<char>(rhs), 'c');
@@ -1126,7 +1144,7 @@ TEST(Any, SBOWithVoidSwap) {
ASSERT_FALSE(rhs);
ASSERT_TRUE(lhs.owner());
ASSERT_EQ(lhs.policy(), entt::any_policy::embedded);
ASSERT_EQ(lhs.type(), entt::type_id<char>());
ASSERT_EQ(lhs.info(), entt::type_id<char>());
ASSERT_EQ(entt::any_cast<double>(&lhs), nullptr);
ASSERT_EQ(entt::any_cast<char>(&rhs), nullptr);
ASSERT_EQ(entt::any_cast<char>(lhs), 'c');
@@ -1145,8 +1163,8 @@ TEST(Any, NoSBOWithRefSwap) {
ASSERT_EQ(lhs.policy(), entt::any_policy::dynamic);
ASSERT_EQ(rhs.policy(), entt::any_policy::ref);
ASSERT_EQ(lhs.type(), entt::type_id<fat>());
ASSERT_EQ(rhs.type(), entt::type_id<int>());
ASSERT_EQ(lhs.info(), entt::type_id<fat>());
ASSERT_EQ(rhs.info(), entt::type_id<int>());
ASSERT_EQ(entt::any_cast<int>(&lhs), nullptr);
ASSERT_EQ(entt::any_cast<fat>(&rhs), nullptr);
ASSERT_EQ(entt::any_cast<fat>(lhs), (fat{.1, .2, .3, .4}));
@@ -1167,8 +1185,8 @@ TEST(Any, NoSBOWithConstRefSwap) {
ASSERT_EQ(lhs.policy(), entt::any_policy::dynamic);
ASSERT_EQ(rhs.policy(), entt::any_policy::cref);
ASSERT_EQ(lhs.type(), entt::type_id<fat>());
ASSERT_EQ(rhs.type(), entt::type_id<int>());
ASSERT_EQ(lhs.info(), entt::type_id<fat>());
ASSERT_EQ(rhs.info(), entt::type_id<int>());
ASSERT_EQ(entt::any_cast<int>(&lhs), nullptr);
ASSERT_EQ(entt::any_cast<fat>(&rhs), nullptr);
ASSERT_EQ(entt::any_cast<fat>(lhs), (fat{.1, .2, .3, .4}));
@@ -1186,7 +1204,7 @@ TEST(Any, NoSBOWithEmptySwap) {
ASSERT_FALSE(lhs);
ASSERT_FALSE(lhs.owner());
ASSERT_EQ(lhs.policy(), entt::any_policy::empty);
ASSERT_EQ(rhs.type(), entt::type_id<fat>());
ASSERT_EQ(rhs.info(), entt::type_id<fat>());
ASSERT_EQ(entt::any_cast<fat>(&lhs), nullptr);
ASSERT_EQ(entt::any_cast<double>(&rhs), nullptr);
ASSERT_EQ(entt::any_cast<fat>(rhs), (fat{.1, .2, .3, .4}));
@@ -1196,7 +1214,7 @@ TEST(Any, NoSBOWithEmptySwap) {
ASSERT_FALSE(rhs);
ASSERT_TRUE(lhs.owner());
ASSERT_EQ(lhs.policy(), entt::any_policy::dynamic);
ASSERT_EQ(lhs.type(), entt::type_id<fat>());
ASSERT_EQ(lhs.info(), entt::type_id<fat>());
ASSERT_EQ(entt::any_cast<double>(&lhs), nullptr);
ASSERT_EQ(entt::any_cast<fat>(&rhs), nullptr);
ASSERT_EQ(entt::any_cast<fat>(lhs), (fat{.1, .2, .3, .4}));
@@ -1211,7 +1229,7 @@ TEST(Any, NoSBOWithVoidSwap) {
ASSERT_FALSE(lhs);
ASSERT_FALSE(lhs.owner());
ASSERT_EQ(lhs.policy(), entt::any_policy::empty);
ASSERT_EQ(rhs.type(), entt::type_id<fat>());
ASSERT_EQ(rhs.info(), entt::type_id<fat>());
ASSERT_EQ(entt::any_cast<fat>(&lhs), nullptr);
ASSERT_EQ(entt::any_cast<double>(&rhs), nullptr);
ASSERT_EQ(entt::any_cast<fat>(rhs), (fat{.1, .2, .3, .4}));
@@ -1221,7 +1239,7 @@ TEST(Any, NoSBOWithVoidSwap) {
ASSERT_FALSE(rhs);
ASSERT_TRUE(lhs.owner());
ASSERT_EQ(lhs.policy(), entt::any_policy::dynamic);
ASSERT_EQ(lhs.type(), entt::type_id<fat>());
ASSERT_EQ(lhs.info(), entt::type_id<fat>());
ASSERT_EQ(entt::any_cast<double>(&lhs), nullptr);
ASSERT_EQ(entt::any_cast<fat>(&rhs), nullptr);
ASSERT_EQ(entt::any_cast<fat>(lhs), (fat{.1, .2, .3, .4}));
@@ -1443,6 +1461,53 @@ TEST(Any, CompareVoid) {
ASSERT_FALSE(entt::any{} != any);
}
TEST(Any, Data) {
entt::any any{2};
const auto &cany = any;
entt::any empty{};
ASSERT_EQ(empty.data(), nullptr);
ASSERT_NE(any.data(), nullptr);
ASSERT_NE(cany.data(), nullptr);
ASSERT_NE(any.as_ref().data(), nullptr);
ASSERT_EQ(cany.as_ref().data(), nullptr);
ASSERT_EQ(empty.data<char>(), nullptr);
ASSERT_EQ(any.data<char>(), nullptr);
ASSERT_EQ(cany.data<char>(), nullptr);
ASSERT_EQ(any.data<const char>(), nullptr);
ASSERT_EQ(cany.data<const char>(), nullptr);
ASSERT_EQ(any.as_ref().data<char>(), nullptr);
ASSERT_EQ(cany.as_ref().data<char>(), nullptr);
ASSERT_EQ(any.as_ref().data<const char>(), nullptr);
ASSERT_EQ(cany.as_ref().data<const char>(), nullptr);
ASSERT_EQ(empty.data<int>(), nullptr);
ASSERT_NE(any.data<int>(), nullptr);
ASSERT_NE(cany.data<int>(), nullptr);
ASSERT_NE(any.data<const int>(), nullptr);
ASSERT_NE(cany.data<const int>(), nullptr);
ASSERT_NE(any.as_ref().data<int>(), nullptr);
ASSERT_EQ(cany.as_ref().data<int>(), nullptr);
ASSERT_NE(any.as_ref().data<const int>(), nullptr);
ASSERT_NE(cany.as_ref().data<const int>(), nullptr);
const auto &char_info = entt::type_id<char>();
const auto &int_info = entt::type_id<int>();
ASSERT_EQ(empty.data(char_info), nullptr);
ASSERT_EQ(any.data(char_info), nullptr);
ASSERT_EQ(cany.data(char_info), nullptr);
ASSERT_EQ(any.as_ref().data(char_info), nullptr);
ASSERT_EQ(cany.as_ref().data(char_info), nullptr);
ASSERT_EQ(empty.data(int_info), nullptr);
ASSERT_NE(any.data(int_info), nullptr);
ASSERT_NE(cany.data(int_info), nullptr);
ASSERT_NE(any.as_ref().data(int_info), nullptr);
ASSERT_EQ(cany.as_ref().data(int_info), nullptr);
}
TEST(Any, AnyCast) {
entt::any any{2};
const auto &cany = any;
@@ -1552,7 +1617,7 @@ TEST(Any, NonCopyableType) {
ASSERT_EQ(any.policy(), entt::any_policy::embedded);
ASSERT_EQ(other.policy(), entt::any_policy::cref);
ASSERT_EQ(any.type(), other.type());
ASSERT_EQ(any.info(), other.info());
ASSERT_FALSE(any.assign(other));
ASSERT_FALSE(any.assign(std::move(other)));
@@ -1609,7 +1674,7 @@ TEST(Any, NonMovableType) {
ASSERT_EQ(any.policy(), entt::any_policy::dynamic);
ASSERT_EQ(other.policy(), entt::any_policy::dynamic);
ASSERT_EQ(any.type(), other.type());
ASSERT_EQ(any.info(), other.info());
ASSERT_TRUE(any.assign(other));
ASSERT_TRUE(any.assign(std::move(other)));
@@ -1646,17 +1711,17 @@ TEST(Any, Array) {
ASSERT_FALSE(copy);
// NOLINTBEGIN(*-avoid-c-arrays)
ASSERT_EQ(any.type(), entt::type_id<int[1]>());
ASSERT_EQ(any.info(), entt::type_id<int[1]>());
ASSERT_NE(entt::any_cast<int[1]>(&any), nullptr);
ASSERT_EQ(entt::any_cast<int[2]>(&any), nullptr);
// NOLINTEND(*-avoid-c-arrays)
ASSERT_EQ(entt::any_cast<int *>(&any), nullptr);
// NOLINTNEXTLINE(*-avoid-c-arrays)
entt::any_cast<int(&)[1]>(any)[0] = 2;
entt::any_cast<int (&)[1]>(any)[0] = 2;
// NOLINTNEXTLINE(*-avoid-c-arrays)
ASSERT_EQ(entt::any_cast<const int(&)[1]>(std::as_const(any))[0], 2);
ASSERT_EQ(entt::any_cast<const int (&)[1]>(std::as_const(any))[0], 2);
}
TEST(Any, CopyMoveReference) {
@@ -1677,8 +1742,8 @@ TEST(Any, CopyMoveReference) {
ASSERT_EQ(move.policy(), entt::any_policy::ref);
ASSERT_EQ(copy.policy(), entt::any_policy::embedded);
ASSERT_EQ(move.type(), entt::type_id<int>());
ASSERT_EQ(copy.type(), entt::type_id<int>());
ASSERT_EQ(move.info(), entt::type_id<int>());
ASSERT_EQ(copy.info(), entt::type_id<int>());
ASSERT_EQ(std::as_const(move).data(), &value);
ASSERT_NE(std::as_const(copy).data(), &value);
@@ -1710,8 +1775,8 @@ TEST(Any, CopyMoveConstReference) {
ASSERT_EQ(move.policy(), entt::any_policy::cref);
ASSERT_EQ(copy.policy(), entt::any_policy::embedded);
ASSERT_EQ(move.type(), entt::type_id<int>());
ASSERT_EQ(copy.type(), entt::type_id<int>());
ASSERT_EQ(move.info(), entt::type_id<int>());
ASSERT_EQ(copy.info(), entt::type_id<int>());
ASSERT_EQ(std::as_const(move).data(), &value);
ASSERT_NE(std::as_const(copy).data(), &value);
@@ -1746,17 +1811,13 @@ TEST(Any, SboAlignment) {
std::array<any_type, 2u> sbo = {over_aligned{}, over_aligned{}};
const auto *data = sbo[0].data();
// NOLINTBEGIN(*-reinterpret-cast)
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(sbo[0u].data()) % alignment) == 0u);
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(sbo[1u].data()) % alignment) == 0u);
// NOLINTEND(*-reinterpret-cast)
std::swap(sbo[0], sbo[1]);
// NOLINTBEGIN(*-reinterpret-cast)
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(sbo[0u].data()) % alignment) == 0u);
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(sbo[1u].data()) % alignment) == 0u);
// NOLINTEND(*-reinterpret-cast)
ASSERT_NE(data, sbo[1].data());
}
@@ -1768,17 +1829,13 @@ TEST(Any, NoSboAlignment) {
std::array<any_type, 2u> nosbo = {over_aligned{}, over_aligned{}};
const auto *data = nosbo[0].data();
// NOLINTBEGIN(*-reinterpret-cast)
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(nosbo[0u].data()) % alignment) == 0u);
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(nosbo[1u].data()) % alignment) == 0u);
// NOLINTEND(*-reinterpret-cast)
std::swap(nosbo[0], nosbo[1]);
// NOLINTBEGIN(*-reinterpret-cast)
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(nosbo[0u].data()) % alignment) == 0u);
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(nosbo[1u].data()) % alignment) == 0u);
// NOLINTEND(*-reinterpret-cast)
ASSERT_EQ(data, nosbo[1].data());
}
@@ -1792,13 +1849,13 @@ TEST(Any, DeducedArrayType) {
entt::any any{"array of char"};
ASSERT_TRUE(any);
ASSERT_EQ(any.type(), entt::type_id<const char *>());
ASSERT_EQ(any.info(), entt::type_id<const char *>());
ASSERT_EQ((std::strcmp("array of char", entt::any_cast<const char *>(any))), 0);
any = "another array of char";
ASSERT_TRUE(any);
ASSERT_EQ(any.type(), entt::type_id<const char *>());
ASSERT_EQ(any.info(), entt::type_id<const char *>());
ASSERT_EQ((std::strcmp("another array of char", entt::any_cast<const char *>(any))), 0);
}
@@ -1807,6 +1864,6 @@ TEST(Any, ClassLevelNewDelete) {
entt::any any{std::in_place_type<test::new_delete>, *std::make_unique<test::new_delete>(test::new_delete{3})};
ASSERT_TRUE(any);
ASSERT_EQ(any.type(), entt::type_id<test::new_delete>());
ASSERT_EQ(any.info(), entt::type_id<test::new_delete>());
ASSERT_EQ(entt::any_cast<const test::new_delete &>(any).value, 3);
}
-2
View File
@@ -177,7 +177,6 @@ TEST(UninitializedConstructUsingAllocator, NoUsesAllocatorConstruction) {
alignas(int) std::array<std::byte, sizeof(int)> storage{};
const std::allocator<int> allocator{};
// NOLINTNEXTLINE(*-reinterpret-cast)
int *value = entt::uninitialized_construct_using_allocator(reinterpret_cast<int *>(storage.data()), allocator, 1);
ASSERT_EQ(*value, 1);
@@ -193,7 +192,6 @@ TEST(UninitializedConstructUsingAllocator, UsesAllocatorConstruction) {
const std::pmr::polymorphic_allocator<string_type> allocator{&memory_resource};
alignas(string_type) std::array<std::byte, sizeof(string_type)> storage{};
// NOLINTNEXTLINE(*-reinterpret-cast)
string_type *value = entt::uninitialized_construct_using_allocator(reinterpret_cast<string_type *>(storage.data()), allocator, test::tracked_memory_resource::default_value);
ASSERT_GT(memory_resource.do_allocate_counter(), 0u);
+8 -14
View File
@@ -51,53 +51,47 @@ using EntityTypes = ::testing::Types<entt::entity, test::entity, test::other_ent
TYPED_TEST_SUITE(Component, EntityTypes, );
TYPED_TEST(Component, VoidType) {
using entity_type = typename TestFixture::entity_type;
using traits_type = entt::component_traits<void, entity_type>;
using traits_type = entt::component_traits<void, typename TestFixture::entity_type>;
ASSERT_FALSE(traits_type::in_place_delete);
ASSERT_EQ(traits_type::page_size, 0u);
}
TYPED_TEST(Component, Empty) {
using entity_type = typename TestFixture::entity_type;
using traits_type = entt::component_traits<test::empty, entity_type>;
using traits_type = entt::component_traits<test::empty, typename TestFixture::entity_type>;
ASSERT_FALSE(traits_type::in_place_delete);
ASSERT_EQ(traits_type::page_size, 0u);
}
TYPED_TEST(Component, NonEmpty) {
using entity_type = typename TestFixture::entity_type;
using traits_type = entt::component_traits<test::boxed_int, entity_type>;
using traits_type = entt::component_traits<test::boxed_int, typename TestFixture::entity_type>;
ASSERT_FALSE(traits_type::in_place_delete);
ASSERT_EQ(traits_type::page_size, ENTT_PACKED_PAGE);
}
TYPED_TEST(Component, NonMovable) {
using entity_type = typename TestFixture::entity_type;
using traits_type = entt::component_traits<test::non_movable, entity_type>;
using traits_type = entt::component_traits<test::non_movable, typename TestFixture::entity_type>;
ASSERT_TRUE(traits_type::in_place_delete);
ASSERT_EQ(traits_type::page_size, ENTT_PACKED_PAGE);
}
TYPED_TEST(Component, SelfContained) {
using entity_type = typename TestFixture::entity_type;
using traits_type = entt::component_traits<self_contained, entity_type>;
using traits_type = entt::component_traits<self_contained, typename TestFixture::entity_type>;
ASSERT_TRUE(traits_type::in_place_delete);
ASSERT_EQ(traits_type::page_size, 4u);
}
TYPED_TEST(Component, TraitsBased) {
using entity_type = typename TestFixture::entity_type;
using traits_type = entt::component_traits<traits_based, entity_type>;
using traits_type = entt::component_traits<traits_based, typename TestFixture::entity_type>;
if constexpr(std::is_same_v<entity_type, entt::entity>) {
if constexpr(std::is_same_v<typename traits_type::entity_type, entt::entity>) {
ASSERT_TRUE(traits_type::in_place_delete);
ASSERT_EQ(traits_type::page_size, 8u);
} else if constexpr(std::is_same_v<entity_type, test::entity>) {
} else if constexpr(std::is_same_v<typename traits_type::entity_type, test::entity>) {
ASSERT_FALSE(traits_type::in_place_delete);
ASSERT_EQ(traits_type::page_size, 16u);
} else {
+9 -9
View File
@@ -93,7 +93,7 @@ TYPED_TEST(BasicHandle, Storage) {
ASSERT_NE(handle.storage().begin(), handle.storage().end());
ASSERT_EQ(++handle.storage().begin(), handle.storage().end());
ASSERT_EQ(handle.storage().begin()->second.type(), entt::type_id<int>());
ASSERT_EQ(handle.storage().begin()->second.info(), entt::type_id<int>());
}
ENTT_DEBUG_TYPED_TEST(BasicHandleDeathTest, Storage) {
@@ -187,8 +187,8 @@ TEST(BasicHandle, Destruction) {
ENTT_DEBUG_TEST(BasicHandleDeathTest, Destruction) {
entt::handle handle{};
ASSERT_DEATH(handle.destroy(0u);, "");
ASSERT_DEATH(handle.destroy();, "");
ASSERT_DEATH(handle.destroy(0u), "");
ASSERT_DEATH(handle.destroy(), "");
}
TEST(BasicHandle, Emplace) {
@@ -207,7 +207,7 @@ TEST(BasicHandle, Emplace) {
ENTT_DEBUG_TEST(BasicHandleDeathTest, Emplace) {
const entt::handle handle{};
ASSERT_DEATH(handle.emplace<int>(3);, "");
ASSERT_DEATH(handle.emplace<int>(3), "");
}
TEST(BasicHandle, EmplaceOrReplace) {
@@ -230,7 +230,7 @@ TEST(BasicHandle, EmplaceOrReplace) {
ENTT_DEBUG_TEST(BasicHandleDeathTest, EmplaceOrReplace) {
const entt::handle handle{};
ASSERT_DEATH(handle.emplace_or_replace<int>(3);, "");
ASSERT_DEATH(handle.emplace_or_replace<int>(3), "");
}
TEST(BasicHandle, Patch) {
@@ -249,7 +249,7 @@ TEST(BasicHandle, Patch) {
ENTT_DEBUG_TEST(BasicHandleDeathTest, Patch) {
const entt::handle handle{};
ASSERT_DEATH(handle.patch<int>([](auto &comp) { comp = 1; });, "");
ASSERT_DEATH(handle.patch<int>([](auto &comp) { comp = 1; }), "");
}
TEST(BasicHandle, Replace) {
@@ -268,7 +268,7 @@ TEST(BasicHandle, Replace) {
ENTT_DEBUG_TEST(BasicHandleDeathTest, Replace) {
const entt::handle handle{};
ASSERT_DEATH(handle.replace<int>(3);, "");
ASSERT_DEATH(handle.replace<int>(3), "");
}
TEST(BasicHandle, Remove) {
@@ -291,7 +291,7 @@ TEST(BasicHandle, Remove) {
ENTT_DEBUG_TEST(BasicHandleDeathTest, Remove) {
const entt::handle handle{};
ASSERT_DEATH(handle.remove<int>();, "");
ASSERT_DEATH(handle.remove<int>(), "");
}
TEST(BasicHandle, Erase) {
@@ -311,7 +311,7 @@ TEST(BasicHandle, Erase) {
ENTT_DEBUG_TEST(BasicHandleDeathTest, Erase) {
const entt::handle handle{};
ASSERT_DEATH(handle.erase<int>();, "");
ASSERT_DEATH(handle.erase<int>(), "");
}
TYPED_TEST(BasicHandle, AllAnyOf) {
+1
View File
@@ -2,6 +2,7 @@
#include <entt/core/hashed_string.hpp>
#include <entt/entity/component.hpp>
#include <entt/entity/entity.hpp>
#include <entt/entity/group.hpp>
#include <entt/entity/helper.hpp>
#include <entt/entity/mixin.hpp>
#include <entt/entity/registry.hpp>
+33
View File
@@ -1,6 +1,7 @@
#include <array>
#include <cstddef>
#include <utility>
#include <vector>
#include <gtest/gtest.h>
#include <entt/core/type_info.hpp>
#include <entt/entity/group.hpp>
@@ -24,6 +25,9 @@ struct clazz {
static void ro_int_with_payload(const clazz &, entt::view<entt::get_t<const int>>) {}
static void ro_char_with_payload(const clazz &, entt::group<entt::owned_t<const char>>) {}
static void ro_int_char_with_payload(clazz &, entt::view<entt::get_t<const int, const char>>) {}
static void const_registry_first(const entt::registry &, entt::view<entt::get_t<int>>) {}
static void const_registry_second(const entt::registry &, entt::view<entt::get_t<double>>) {}
};
void to_args_integrity(entt::view<entt::get_t<int>> view, std::size_t &value, entt::registry &) {
@@ -381,6 +385,35 @@ TEST(Organizer, SyncPoint) {
}
}
TEST(Organizer, ConstRegistry) {
entt::organizer organizer;
entt::registry registry;
organizer.emplace<&clazz::const_registry_first>("first");
organizer.emplace<&clazz::const_registry_second>("second");
const auto graph = organizer.graph();
ASSERT_EQ(graph.size(), 2u);
ASSERT_STREQ(graph[0u].name(), "first");
ASSERT_STREQ(graph[1u].name(), "second");
ASSERT_TRUE(graph[0u].top_level());
ASSERT_TRUE(graph[1u].top_level());
ASSERT_EQ(graph[0u].in_edges().size(), 0u);
ASSERT_EQ(graph[1u].in_edges().size(), 0u);
ASSERT_EQ(graph[0u].out_edges().size(), 0u);
ASSERT_EQ(graph[1u].out_edges().size(), 0u);
for(auto &&vertex: graph) {
typename entt::organizer::function_type *cb = vertex.callback();
ASSERT_NO_THROW(cb(vertex.data(), registry));
}
}
TEST(Organizer, Override) {
entt::organizer organizer;
+6 -6
View File
@@ -56,13 +56,13 @@ TYPED_TEST(ReactiveMixin, Constructors) {
ASSERT_EQ(pool.policy(), entt::deletion_policy{traits_type::in_place_delete});
ASSERT_NO_THROW([[maybe_unused]] auto alloc = pool.get_allocator());
ASSERT_EQ(pool.type(), entt::type_id<value_type>());
ASSERT_EQ(pool.info(), entt::type_id<value_type>());
pool = entt::reactive_mixin<entt::storage<value_type>>{std::allocator<value_type>{}};
ASSERT_EQ(pool.policy(), entt::deletion_policy{traits_type::in_place_delete});
ASSERT_NO_THROW([[maybe_unused]] auto alloc = pool.get_allocator());
ASSERT_EQ(pool.type(), entt::type_id<value_type>());
ASSERT_EQ(pool.info(), entt::type_id<value_type>());
}
TYPED_TEST(ReactiveMixin, Move) {
@@ -80,7 +80,7 @@ TYPED_TEST(ReactiveMixin, Move) {
static_assert(std::is_move_assignable_v<decltype(pool)>, "Move assignable type required");
ASSERT_TRUE(pool.contains(entity[0u]));
ASSERT_EQ(pool.type(), entt::type_id<value_type>());
ASSERT_EQ(pool.info(), entt::type_id<value_type>());
entt::reactive_mixin<entt::storage<value_type>> other{std::move(pool)};
@@ -89,7 +89,7 @@ TYPED_TEST(ReactiveMixin, Move) {
ASSERT_TRUE(pool.empty());
ASSERT_FALSE(other.empty());
ASSERT_EQ(other.type(), entt::type_id<value_type>());
ASSERT_EQ(other.info(), entt::type_id<value_type>());
ASSERT_EQ(other.index(entity[0u]), 0u);
ASSERT_EQ(&other.registry(), &registry);
@@ -149,8 +149,8 @@ TYPED_TEST(ReactiveMixin, Swap) {
pool.swap(other);
ASSERT_EQ(pool.type(), entt::type_id<value_type>());
ASSERT_EQ(other.type(), entt::type_id<value_type>());
ASSERT_EQ(pool.info(), entt::type_id<value_type>());
ASSERT_EQ(other.info(), entt::type_id<value_type>());
ASSERT_EQ(pool.size(), 1u);
ASSERT_EQ(other.size(), 1u);
+19 -9
View File
@@ -309,13 +309,15 @@ TEST(Registry, Swap) {
other.erase<int>(entity);
registry = {};
registry.emplace<int>(registry.create(entity));
const auto reboot = registry.create();
registry.emplace<int>(reboot);
ASSERT_EQ(entity, reboot);
ASSERT_EQ(test.parent, &other);
registry.swap(other);
registry.emplace<int>(entity);
registry.emplace<int>(registry.create(entity));
registry.emplace<int>(reboot);
registry.emplace<int>(registry.create(reboot));
ASSERT_EQ(test.parent, &registry);
}
@@ -466,9 +468,9 @@ TEST(Registry, RegistryStorageIteratorConversion) {
testing::StaticAssertTypeEq<decltype(*cit), std::pair<entt::id_type, const entt::sparse_set &>>();
ASSERT_EQ(it->first, entt::type_id<int>().hash());
ASSERT_EQ((*it).second.type(), entt::type_id<int>());
ASSERT_EQ((*it).second.info(), entt::type_id<int>());
ASSERT_EQ(it->first, cit->first);
ASSERT_EQ((*it).second.type(), (*cit).second.type());
ASSERT_EQ((*it).second.info(), (*cit).second.info());
ASSERT_EQ(it - cit, 0);
ASSERT_EQ(cit - it, 0);
@@ -973,7 +975,7 @@ TEST(Registry, EmplaceEmpty) {
ASSERT_FALSE(registry.all_of<test::empty>(entity));
registry.emplace<test::empty>(entity, 4);
registry.emplace<test::empty>(entity);
ASSERT_TRUE(registry.all_of<test::empty>(entity));
}
@@ -1442,7 +1444,7 @@ TEST(Registry, EraseIf) {
ASSERT_FALSE(registry.storage<int>("other"_hs).contains(entity));
ASSERT_TRUE(registry.storage<char>().contains(entity));
registry.erase_if(entity, [](auto, const auto &storage) { return storage.type() == entt::type_id<char>(); });
registry.erase_if(entity, [](auto, const auto &storage) { return storage.info() == entt::type_id<char>(); });
ASSERT_TRUE(registry.storage<int>().contains(entity));
ASSERT_FALSE(registry.storage<int>("other"_hs).contains(entity));
@@ -2353,6 +2355,14 @@ TEST(Registry, Context) {
ASSERT_EQ(ctx.find<const int>(), cctx.find<int>());
ASSERT_EQ(ctx.get<int>(), cctx.get<const int>());
ASSERT_EQ(ctx.get<int>(), 0);
ASSERT_TRUE(ctx.contains<char>());
ASSERT_TRUE(ctx.contains<int>());
ctx.clear();
ASSERT_FALSE(ctx.contains<char>());
ASSERT_FALSE(ctx.contains<int>());
}
TEST(Registry, ContextHint) {
@@ -2546,8 +2556,8 @@ TEST(Registry, VoidType) {
ASSERT_FALSE(registry.storage<void>("custom"_hs).empty());
ASSERT_TRUE(registry.storage<void>("custom"_hs).contains(entity));
ASSERT_EQ(registry.storage<void>().type(), entt::type_id<void>());
ASSERT_EQ(registry.storage<void>("custom"_hs).type(), entt::type_id<void>());
ASSERT_EQ(registry.storage<void>().info(), entt::type_id<void>());
ASSERT_EQ(registry.storage<void>("custom"_hs).info(), entt::type_id<void>());
}
TEST(Registry, NoEtoType) {
+157 -2
View File
@@ -1,5 +1,6 @@
#include <algorithm>
#include <array>
#include <iterator>
#include <memory>
#include <tuple>
#include <utility>
@@ -73,6 +74,29 @@ TYPED_TEST(RuntimeView, Functionalities) {
ASSERT_EQ(view.begin(), view.end());
}
TYPED_TEST(RuntimeView, InvalidView) {
using runtime_view_type = typename TestFixture::type;
runtime_view_type view{};
ASSERT_FALSE(view);
ASSERT_EQ(view.size_hint(), 0u);
ASSERT_FALSE(view.contains(entt::null));
ASSERT_EQ(view.begin(), typename decltype(view)::iterator{});
ASSERT_EQ(view.begin(), view.end());
view.each([](const entt::entity) { FAIL(); });
entt::storage<int> storage;
storage.emplace(entt::entity{});
view.iterate(storage);
ASSERT_TRUE(view);
}
TYPED_TEST(RuntimeView, Constructors) {
using runtime_view_type = typename TestFixture::type;
@@ -322,7 +346,7 @@ TYPED_TEST(RuntimeView, EachWithHoles) {
});
}
TYPED_TEST(RuntimeView, ExcludedComponents) {
TYPED_TEST(RuntimeView, Exclude) {
using runtime_view_type = typename TestFixture::type;
std::tuple<entt::storage<int>, entt::storage<char>> storage{};
@@ -383,7 +407,7 @@ TYPED_TEST(RuntimeView, StableType) {
ASSERT_EQ(view.size_hint(), 1u);
}
TYPED_TEST(RuntimeView, StableTypeWithExcludedComponent) {
TYPED_TEST(RuntimeView, StableTypeWithExclude) {
using runtime_view_type = typename TestFixture::type;
constexpr entt::entity tombstone = entt::tombstone;
@@ -418,3 +442,134 @@ TYPED_TEST(RuntimeView, StableTypeWithExcludedComponent) {
ASSERT_EQ(entt, entity[1u]);
});
}
TYPED_TEST(RuntimeView, SameStorageTypes) {
using runtime_view_type = typename TestFixture::type;
std::tuple<entt::storage<int>, entt::storage<int>> storage{};
const std::array entity{entt::entity{1}, entt::entity{3}};
runtime_view_type view{};
std::get<0>(storage).emplace(entity[0u], 2);
std::get<1>(storage).emplace(entity[0u], 3);
std::get<1>(storage).emplace(entity[1u], 1);
view.iterate(std::get<0>(storage)).iterate(std::get<1>(storage));
ASSERT_TRUE(view.contains(entity[0u]));
ASSERT_FALSE(view.contains(entity[1u]));
for(auto entt: view) {
ASSERT_EQ(entt, entity[0u]);
}
view.each([&](auto entt) {
ASSERT_EQ(entt, entity[0u]);
});
}
TYPED_TEST(RuntimeView, StorageEntity) {
using runtime_view_type = typename TestFixture::type;
std::tuple<entt::storage<entt::entity>, entt::storage<char>> storage{};
const std::array entity{std::get<0>(storage).generate(), std::get<0>(storage).generate()};
runtime_view_type view{};
std::get<1>(storage).emplace(entity[0u]);
std::get<1>(storage).emplace(entity[1u]);
std::get<1>(storage).erase(entity[0u]);
std::get<0>(storage).erase(entity[0u]);
std::get<0>(storage).bump(entity[0u]);
view.iterate(std::get<0>(storage)).iterate(std::get<1>(storage));
ASSERT_FALSE(view.contains(entity[0u]));
ASSERT_TRUE(view.contains(entity[1u]));
ASSERT_EQ(view.size_hint(), 1u);
ASSERT_NE(view.begin(), view.end());
ASSERT_EQ(std::distance(view.begin(), view.end()), 1);
ASSERT_EQ(*view.begin(), entity[1u]);
for(auto entt: view) {
ASSERT_EQ(entt, entity[1u]);
}
view.each([&entity](auto entt) {
ASSERT_EQ(entt, entity[1u]);
});
}
TYPED_TEST(RuntimeView, StorageEntityWithExclude) {
using runtime_view_type = typename TestFixture::type;
std::tuple<entt::storage<entt::entity>, entt::storage<int>, entt::storage<char>> storage{};
const std::array entity{std::get<0>(storage).generate(), std::get<0>(storage).generate(), std::get<0>(storage).generate()};
runtime_view_type view{};
std::get<1>(storage).emplace(entity[0u]);
std::get<1>(storage).emplace(entity[1u]);
std::get<1>(storage).emplace(entity[2u]);
std::get<2>(storage).emplace(entity[2u]);
std::get<1>(storage).erase(entity[0u]);
std::get<0>(storage).erase(entity[0u]);
std::get<0>(storage).bump(entity[0u]);
view.iterate(std::get<0>(storage)).iterate(std::get<1>(storage)).exclude(std::get<2>(storage));
ASSERT_FALSE(view.contains(entity[0u]));
ASSERT_TRUE(view.contains(entity[1u]));
ASSERT_FALSE(view.contains(entity[2u]));
ASSERT_EQ(view.size_hint(), 2u);
ASSERT_NE(view.begin(), view.end());
ASSERT_EQ(std::distance(view.begin(), view.end()), 1);
ASSERT_EQ(*view.begin(), entity[1u]);
for(auto entt: view) {
ASSERT_EQ(entt, entity[1u]);
}
view.each([&entity](auto entt, auto &&...) {
ASSERT_EQ(entt, entity[1u]);
});
}
TYPED_TEST(RuntimeView, StorageEntityExcludeOnly) {
using runtime_view_type = typename TestFixture::type;
std::tuple<entt::storage<entt::entity>, entt::storage<int>> storage{};
const std::array entity{std::get<0>(storage).generate(), std::get<0>(storage).generate(), std::get<0>(storage).generate()};
runtime_view_type view{};
std::get<1>(storage).emplace(entity[2u]);
std::get<0>(storage).erase(entity[0u]);
std::get<0>(storage).bump(entity[0u]);
view.iterate(std::get<0>(storage)).exclude(std::get<1>(storage));
ASSERT_FALSE(view.contains(entity[0u]));
ASSERT_TRUE(view.contains(entity[1u]));
ASSERT_FALSE(view.contains(entity[2u]));
ASSERT_EQ(view.size_hint(), 2u);
ASSERT_NE(view.begin(), view.end());
ASSERT_EQ(std::distance(view.begin(), view.end()), 1);
ASSERT_EQ(*view.begin(), entity[1u]);
for(auto entt: view) {
ASSERT_EQ(entt, entity[1u]);
}
view.each([&entity](auto entt) {
ASSERT_EQ(entt, entity[1u]);
});
}
+5 -5
View File
@@ -231,7 +231,7 @@ TEST(SighMixin, VoidType) {
pool.emplace(entity);
ASSERT_EQ(pool.type(), entt::type_id<void>());
ASSERT_EQ(pool.info(), entt::type_id<void>());
ASSERT_TRUE(pool.contains(entity));
entt::sigh_mixin<entt::storage<void>> other{std::move(pool)};
@@ -336,7 +336,7 @@ TYPED_TEST(SighMixin, Move) {
static_assert(std::is_move_constructible_v<decltype(pool)>, "Move constructible type required");
static_assert(std::is_move_assignable_v<decltype(pool)>, "Move assignable type required");
ASSERT_EQ(pool.type(), entt::type_id<value_type>());
ASSERT_EQ(pool.info(), entt::type_id<value_type>());
entt::sigh_mixin<entt::storage<value_type>> other{std::move(pool)};
@@ -345,7 +345,7 @@ TYPED_TEST(SighMixin, Move) {
ASSERT_TRUE(pool.empty());
ASSERT_FALSE(other.empty());
ASSERT_EQ(other.type(), entt::type_id<value_type>());
ASSERT_EQ(other.info(), entt::type_id<value_type>());
ASSERT_EQ(other.index(entt::entity{3}), 0u);
ASSERT_EQ(other.get(entt::entity{3}), value_type{3});
@@ -408,8 +408,8 @@ TYPED_TEST(SighMixin, Swap) {
pool.swap(other);
ASSERT_EQ(pool.type(), entt::type_id<value_type>());
ASSERT_EQ(other.type(), entt::type_id<value_type>());
ASSERT_EQ(pool.info(), entt::type_id<value_type>());
ASSERT_EQ(other.info(), entt::type_id<value_type>());
ASSERT_EQ(pool.size(), 1u + traits_type::in_place_delete);
ASSERT_EQ(other.size(), 1u);
+2 -2
View File
@@ -58,7 +58,7 @@ TYPED_TEST(SparseSet, Constructors) {
ASSERT_EQ(set.policy(), entt::deletion_policy::swap_and_pop);
ASSERT_NO_THROW([[maybe_unused]] auto alloc = set.get_allocator());
ASSERT_EQ(set.type(), entt::type_id<void>());
ASSERT_EQ(set.info(), entt::type_id<void>());
set = sparse_set_type{allocator_type{}};
@@ -70,7 +70,7 @@ TYPED_TEST(SparseSet, Constructors) {
ASSERT_EQ(set.policy(), policy);
ASSERT_NO_THROW([[maybe_unused]] auto alloc = set.get_allocator());
ASSERT_EQ(set.type(), entt::type_id<void>());
ASSERT_EQ(set.info(), entt::type_id<void>());
set = sparse_set_type{entt::type_id<int>(), policy, allocator_type{}};
+14 -14
View File
@@ -96,13 +96,13 @@ TYPED_TEST(Storage, Constructors) {
ASSERT_EQ(pool.policy(), entt::deletion_policy{traits_type::in_place_delete});
ASSERT_NO_THROW([[maybe_unused]] auto alloc = pool.get_allocator());
ASSERT_EQ(pool.type(), entt::type_id<value_type>());
ASSERT_EQ(pool.info(), entt::type_id<value_type>());
pool = entt::storage<value_type>{std::allocator<value_type>{}};
ASSERT_EQ(pool.policy(), entt::deletion_policy{traits_type::in_place_delete});
ASSERT_NO_THROW([[maybe_unused]] auto alloc = pool.get_allocator());
ASSERT_EQ(pool.type(), entt::type_id<value_type>());
ASSERT_EQ(pool.info(), entt::type_id<value_type>());
}
TYPED_TEST(Storage, Move) {
@@ -123,7 +123,7 @@ TYPED_TEST(Storage, Move) {
ASSERT_TRUE(pool.empty());
ASSERT_FALSE(other.empty());
ASSERT_EQ(other.type(), entt::type_id<value_type>());
ASSERT_EQ(other.info(), entt::type_id<value_type>());
ASSERT_EQ(other.index(entity[0u]), 0u);
ASSERT_EQ(other.get(entity[0u]), value_type{3});
@@ -134,7 +134,7 @@ TYPED_TEST(Storage, Move) {
ASSERT_TRUE(other.empty());
ASSERT_FALSE(extended.empty());
ASSERT_EQ(extended.type(), entt::type_id<value_type>());
ASSERT_EQ(extended.info(), entt::type_id<value_type>());
ASSERT_EQ(extended.index(entity[0u]), 0u);
ASSERT_EQ(extended.get(entity[0u]), value_type{3});
@@ -145,7 +145,7 @@ TYPED_TEST(Storage, Move) {
ASSERT_TRUE(other.empty());
ASSERT_TRUE(extended.empty());
ASSERT_EQ(pool.type(), entt::type_id<value_type>());
ASSERT_EQ(pool.info(), entt::type_id<value_type>());
ASSERT_EQ(pool.index(entity[0u]), 0u);
ASSERT_EQ(pool.get(entity[0u]), value_type{3});
@@ -157,7 +157,7 @@ TYPED_TEST(Storage, Move) {
ASSERT_FALSE(pool.empty());
ASSERT_FALSE(other.empty());
ASSERT_EQ(other.type(), entt::type_id<value_type>());
ASSERT_EQ(other.info(), entt::type_id<value_type>());
ASSERT_EQ(other.index(entity[0u]), 0u);
ASSERT_EQ(other.get(entity[0u]), value_type{3});
}
@@ -169,8 +169,8 @@ TYPED_TEST(Storage, Swap) {
entt::storage<value_type> pool;
entt::storage<value_type> other;
ASSERT_EQ(pool.type(), entt::type_id<value_type>());
ASSERT_EQ(other.type(), entt::type_id<value_type>());
ASSERT_EQ(pool.info(), entt::type_id<value_type>());
ASSERT_EQ(other.info(), entt::type_id<value_type>());
pool.emplace(entt::entity{4}, 1);
@@ -183,8 +183,8 @@ TYPED_TEST(Storage, Swap) {
pool.swap(other);
ASSERT_EQ(pool.type(), entt::type_id<value_type>());
ASSERT_EQ(other.type(), entt::type_id<value_type>());
ASSERT_EQ(pool.info(), entt::type_id<value_type>());
ASSERT_EQ(other.info(), entt::type_id<value_type>());
ASSERT_EQ(pool.size(), 1u + traits_type::in_place_delete);
ASSERT_EQ(other.size(), 1u);
@@ -721,8 +721,8 @@ TEST(Storage, TryEmplaceNonDefaultConstructible) {
entt::sparse_set &base = pool;
const std::array entity{entt::entity{1}, entt::entity{3}};
ASSERT_EQ(pool.type(), entt::type_id<value_type>());
ASSERT_EQ(pool.type(), base.type());
ASSERT_EQ(pool.info(), entt::type_id<value_type>());
ASSERT_EQ(pool.info(), base.info());
ASSERT_FALSE(pool.contains(entity[0u]));
ASSERT_FALSE(pool.contains(entity[1u]));
@@ -764,8 +764,8 @@ TEST(Storage, TryEmplaceNonCopyConstructible) {
entt::sparse_set &base = pool;
const std::array entity{entt::entity{1}, entt::entity{3}};
ASSERT_EQ(pool.type(), entt::type_id<value_type>());
ASSERT_EQ(pool.type(), base.type());
ASSERT_EQ(pool.info(), entt::type_id<value_type>());
ASSERT_EQ(pool.info(), base.info());
ASSERT_FALSE(pool.contains(entity[0u]));
ASSERT_FALSE(pool.contains(entity[1u]));
+55 -46
View File
@@ -19,13 +19,13 @@ TEST(StorageEntity, Constructors) {
ASSERT_EQ(pool.policy(), entt::deletion_policy::swap_only);
ASSERT_NO_THROW([[maybe_unused]] auto alloc = pool.get_allocator());
ASSERT_EQ(pool.type(), entt::type_id<void>());
ASSERT_EQ(pool.info(), entt::type_id<void>());
pool = entt::storage<entt::entity>{std::allocator<entt::entity>{}};
ASSERT_EQ(pool.policy(), entt::deletion_policy::swap_only);
ASSERT_NO_THROW([[maybe_unused]] auto alloc = pool.get_allocator());
ASSERT_EQ(pool.type(), entt::type_id<void>());
ASSERT_EQ(pool.info(), entt::type_id<void>());
}
TEST(StorageEntity, Move) {
@@ -44,7 +44,7 @@ TEST(StorageEntity, Move) {
ASSERT_TRUE(pool.empty());
ASSERT_FALSE(other.empty());
ASSERT_EQ(other.type(), entt::type_id<void>());
ASSERT_EQ(other.info(), entt::type_id<void>());
ASSERT_EQ(other.index(entity[0u]), 0u);
entt::storage<entt::entity> extended{std::move(other), std::allocator<entt::entity>{}};
@@ -54,7 +54,7 @@ TEST(StorageEntity, Move) {
ASSERT_TRUE(other.empty());
ASSERT_FALSE(extended.empty());
ASSERT_EQ(extended.type(), entt::type_id<void>());
ASSERT_EQ(extended.info(), entt::type_id<void>());
ASSERT_EQ(extended.index(entity[0u]), 0u);
pool = std::move(extended);
@@ -64,7 +64,7 @@ TEST(StorageEntity, Move) {
ASSERT_TRUE(other.empty());
ASSERT_TRUE(extended.empty());
ASSERT_EQ(pool.type(), entt::type_id<void>());
ASSERT_EQ(pool.info(), entt::type_id<void>());
ASSERT_EQ(pool.index(entity[0u]), 0u);
other = entt::storage<entt::entity>{};
@@ -75,36 +75,45 @@ TEST(StorageEntity, Move) {
ASSERT_FALSE(pool.empty());
ASSERT_FALSE(other.empty());
ASSERT_EQ(other.type(), entt::type_id<void>());
ASSERT_EQ(other.info(), entt::type_id<void>());
ASSERT_EQ(other.index(entity[0u]), 0u);
}
TEST(StorageEntity, Swap) {
using traits_type = entt::entt_traits<entt::entity>;
entt::storage<entt::entity> pool;
entt::storage<entt::entity> other;
ASSERT_EQ(pool.type(), entt::type_id<void>());
ASSERT_EQ(other.type(), entt::type_id<void>());
ASSERT_EQ(pool.info(), entt::type_id<void>());
ASSERT_EQ(other.info(), entt::type_id<void>());
pool.generate(entt::entity{4});
pool.generate(entt::entity{2});
other.generate(entt::entity{2});
other.generate(entt::entity{1});
other.erase(entt::entity{2});
other.generate(entt::entity{0});
other.erase(entt::entity{1});
ASSERT_EQ(pool.size(), 1u);
ASSERT_EQ(other.size(), 2u);
pool.start_from(entt::entity{3});
other.start_from(entt::entity{2});
pool.swap(other);
ASSERT_EQ(pool.type(), entt::type_id<void>());
ASSERT_EQ(other.type(), entt::type_id<void>());
ASSERT_EQ(pool.info(), entt::type_id<void>());
ASSERT_EQ(other.info(), entt::type_id<void>());
ASSERT_EQ(pool.size(), 2u);
ASSERT_EQ(other.size(), 1u);
ASSERT_EQ(pool.index(entt::entity{1}), 0u);
ASSERT_EQ(other.index(entt::entity{4}), 0u);
ASSERT_EQ(pool.generate(), traits_type::construct(1, 1));
ASSERT_EQ(pool.generate(), entt::entity{2});
ASSERT_EQ(other.generate(), entt::entity{3});
ASSERT_EQ(pool.index(entt::entity{0}), 0u);
ASSERT_EQ(other.index(entt::entity{2}), 0u);
}
TEST(StorageEntity, Getters) {
@@ -143,10 +152,10 @@ TEST(StorageEntity, Generate) {
entt::storage<entt::entity> pool;
std::array<entt::entity, 2u> entity{};
ASSERT_EQ(pool.emplace(), entt::entity{0});
ASSERT_EQ(pool.generate(), entt::entity{0});
ASSERT_EQ(pool.generate(entt::null), entt::entity{1});
ASSERT_EQ(pool.generate(entt::tombstone), entt::entity{2});
ASSERT_EQ(pool.emplace(entt::entity{0}), entt::entity{3});
ASSERT_EQ(pool.generate(entt::entity{0}), entt::entity{3});
ASSERT_EQ(pool.generate(traits_type::construct(1, 1)), entt::entity{4});
ASSERT_EQ(pool.generate(traits_type::construct(6, 3)), traits_type::construct(6, 3));
@@ -172,6 +181,35 @@ TEST(StorageEntity, Generate) {
ASSERT_EQ(entity[1u], entt::entity{8});
}
TEST(StorageEntity, GenerateRange) {
entt::storage<entt::entity> pool;
std::array<entt::entity, 2u> entity{};
pool.generate(entity.begin(), entity.end());
ASSERT_TRUE(pool.contains(entity[0u]));
ASSERT_TRUE(pool.contains(entity[1u]));
ASSERT_FALSE(pool.empty());
ASSERT_EQ(pool.size(), 2u);
ASSERT_EQ(pool.free_list(), 2u);
pool.erase(entity.begin(), entity.end());
ASSERT_FALSE(pool.empty());
ASSERT_EQ(pool.size(), 2u);
ASSERT_EQ(pool.free_list(), 0u);
pool.generate(entity.begin(), entity.begin() + 1u);
ASSERT_TRUE(pool.contains(entity[0u]));
ASSERT_FALSE(pool.contains(entity[1u]));
ASSERT_FALSE(pool.empty());
ASSERT_EQ(pool.size(), 2u);
ASSERT_EQ(pool.free_list(), 1u);
}
TEST(StorageEntity, GenerateFrom) {
entt::storage<entt::entity> pool;
std::array entity{entt::entity{0}, entt::entity{1}, entt::entity{2}};
@@ -287,35 +325,6 @@ ENTT_DEBUG_TEST(StorageEntityDeathTest, Patch) {
ASSERT_DEATH(pool.patch(entt::null), "");
}
TEST(StorageEntity, Insert) {
entt::storage<entt::entity> pool;
std::array<entt::entity, 2u> entity{};
pool.insert(entity.begin(), entity.end());
ASSERT_TRUE(pool.contains(entity[0u]));
ASSERT_TRUE(pool.contains(entity[1u]));
ASSERT_FALSE(pool.empty());
ASSERT_EQ(pool.size(), 2u);
ASSERT_EQ(pool.free_list(), 2u);
pool.erase(entity.begin(), entity.end());
ASSERT_FALSE(pool.empty());
ASSERT_EQ(pool.size(), 2u);
ASSERT_EQ(pool.free_list(), 0u);
pool.generate(entity.begin(), entity.begin() + 1u);
ASSERT_TRUE(pool.contains(entity[0u]));
ASSERT_FALSE(pool.contains(entity[1u]));
ASSERT_FALSE(pool.empty());
ASSERT_EQ(pool.size(), 2u);
ASSERT_EQ(pool.free_list(), 1u);
}
TEST(StorageEntity, Pack) {
entt::storage<entt::entity> pool;
std::array entity{entt::entity{1}, entt::entity{3}, entt::entity{4}, entt::entity{2}};
+14 -23
View File
@@ -22,21 +22,12 @@ struct StorageNoInstance: testing::Test {
using type = Type;
static auto emplace_instance(entt::storage<type> &pool, const entt::entity entt) {
if constexpr(std::is_void_v<type>) {
return pool.emplace(entt);
} else {
return pool.emplace(entt, type{});
}
return pool.emplace(entt);
}
template<typename It>
static auto insert_instance(entt::storage<type> &pool, const It from, const It to) {
if constexpr(std::is_void_v<type>) {
return pool.insert(from, to);
} else {
const std::array<type, 2u> value{};
return pool.insert(from, to, value.begin());
}
return pool.insert(from, to);
}
static auto push_instance(entt::storage<type> &pool, const entt::entity entt) {
@@ -64,13 +55,13 @@ TYPED_TEST(StorageNoInstance, Constructors) {
ASSERT_EQ(pool.policy(), entt::deletion_policy::swap_and_pop);
ASSERT_NO_THROW([[maybe_unused]] auto alloc = pool.get_allocator());
ASSERT_EQ(pool.type(), entt::type_id<value_type>());
ASSERT_EQ(pool.info(), entt::type_id<value_type>());
pool = entt::storage<value_type>{std::allocator<value_type>{}};
ASSERT_EQ(pool.policy(), entt::deletion_policy::swap_and_pop);
ASSERT_NO_THROW([[maybe_unused]] auto alloc = pool.get_allocator());
ASSERT_EQ(pool.type(), entt::type_id<value_type>());
ASSERT_EQ(pool.info(), entt::type_id<value_type>());
}
TYPED_TEST(StorageNoInstance, Move) {
@@ -91,7 +82,7 @@ TYPED_TEST(StorageNoInstance, Move) {
ASSERT_TRUE(pool.empty());
ASSERT_FALSE(other.empty());
ASSERT_EQ(other.type(), entt::type_id<value_type>());
ASSERT_EQ(other.info(), entt::type_id<value_type>());
ASSERT_EQ(other.index(entity[0u]), 0u);
entt::storage<value_type> extended{std::move(other), std::allocator<value_type>{}};
@@ -101,7 +92,7 @@ TYPED_TEST(StorageNoInstance, Move) {
ASSERT_TRUE(other.empty());
ASSERT_FALSE(extended.empty());
ASSERT_EQ(extended.type(), entt::type_id<value_type>());
ASSERT_EQ(extended.info(), entt::type_id<value_type>());
ASSERT_EQ(extended.index(entity[0u]), 0u);
pool = std::move(extended);
@@ -111,18 +102,18 @@ TYPED_TEST(StorageNoInstance, Move) {
ASSERT_TRUE(other.empty());
ASSERT_TRUE(extended.empty());
ASSERT_EQ(pool.type(), entt::type_id<value_type>());
ASSERT_EQ(pool.info(), entt::type_id<value_type>());
ASSERT_EQ(pool.index(entity[0u]), 0u);
other = entt::storage<value_type>{};
other.emplace(entity[1u], 2);
other.emplace(entity[1u]);
other = std::move(pool);
test::is_initialized(pool);
ASSERT_FALSE(pool.empty());
ASSERT_FALSE(other.empty());
ASSERT_EQ(other.type(), entt::type_id<value_type>());
ASSERT_EQ(other.info(), entt::type_id<value_type>());
ASSERT_EQ(other.index(entity[0u]), 0u);
}
@@ -132,8 +123,8 @@ TYPED_TEST(StorageNoInstance, Swap) {
entt::storage<value_type> pool;
entt::storage<value_type> other;
ASSERT_EQ(pool.type(), entt::type_id<value_type>());
ASSERT_EQ(other.type(), entt::type_id<value_type>());
ASSERT_EQ(pool.info(), entt::type_id<value_type>());
ASSERT_EQ(other.info(), entt::type_id<value_type>());
pool.emplace(entt::entity{4});
@@ -146,8 +137,8 @@ TYPED_TEST(StorageNoInstance, Swap) {
pool.swap(other);
ASSERT_EQ(pool.type(), entt::type_id<value_type>());
ASSERT_EQ(other.type(), entt::type_id<value_type>());
ASSERT_EQ(pool.info(), entt::type_id<value_type>());
ASSERT_EQ(other.info(), entt::type_id<value_type>());
ASSERT_EQ(pool.size(), 1u);
ASSERT_EQ(other.size(), 1u);
@@ -162,7 +153,7 @@ TYPED_TEST(StorageNoInstance, Getters) {
entt::storage<value_type> pool;
const entt::entity entity{4};
pool.emplace(entity, 3);
pool.emplace(entity);
testing::StaticAssertTypeEq<decltype(pool.get({})), void>();
testing::StaticAssertTypeEq<decltype(std::as_const(pool).get({})), void>();
+3 -3
View File
@@ -855,19 +855,19 @@ TEST(MultiStorageView, UseAndRefresh) {
view.use<int>();
ASSERT_EQ(view.handle()->type(), entt::type_id<int>());
ASSERT_EQ(view.handle()->info(), entt::type_id<int>());
ASSERT_EQ(view.front(), entity[1u]);
ASSERT_EQ(view.back(), entity[0u]);
view.use<char>();
ASSERT_EQ(view.handle()->type(), entt::type_id<char>());
ASSERT_EQ(view.handle()->info(), entt::type_id<char>());
ASSERT_EQ(view.front(), entity[0u]);
ASSERT_EQ(view.back(), entity[1u]);
view.refresh();
ASSERT_EQ(view.handle()->type(), entt::type_id<int>());
ASSERT_EQ(view.handle()->info(), entt::type_id<int>());
}
TEST(MultiStorageView, Each) {
-1
View File
@@ -11,7 +11,6 @@ _TESTS = [
"meta_ctor",
"meta_custom",
"meta_data",
"meta_dtor",
"meta_factory",
"meta_func",
"meta_handle",
+42 -35
View File
@@ -5,7 +5,10 @@
#include <memory>
#include <utility>
#include <gtest/gtest.h>
#include <entt/core/any.hpp>
#include <entt/core/hashed_string.hpp>
#include <entt/locator/locator.hpp>
#include <entt/meta/context.hpp>
#include <entt/meta/factory.hpp>
#include <entt/meta/meta.hpp>
#include <entt/meta/resolve.hpp>
@@ -36,15 +39,10 @@ struct empty {
empty &operator=(const empty &) = default;
virtual ~empty() {
++destructor_counter;
++counter;
}
static void destroy(empty &) {
++destroy_counter;
}
inline static int destroy_counter = 0; // NOLINT
inline static int destructor_counter = 0; // NOLINT
inline static int counter = 0; // NOLINT
};
struct fat: empty {
@@ -91,13 +89,11 @@ struct MetaAny: ::testing::Test {
using namespace entt::literals;
entt::meta_factory<empty>{}
.type("empty"_hs)
.dtor<empty::destroy>();
.type("empty"_hs);
entt::meta_factory<fat>{}
.type("fat"_hs)
.base<empty>()
.dtor<fat::destroy>();
.base<empty>();
entt::meta_factory<clazz>{}
.type("clazz"_hs)
@@ -106,8 +102,7 @@ struct MetaAny: ::testing::Test {
.func<clazz::func>("func"_hs)
.conv<int>();
empty::destroy_counter = 0;
empty::destructor_counter = 0;
empty::counter = 0;
}
void TearDown() override {
@@ -154,10 +149,10 @@ TEST_F(MetaAny, SBO) {
ASSERT_TRUE(any);
ASSERT_TRUE(any.base().owner());
ASSERT_EQ(any.policy(), entt::meta_any_policy::embedded);
ASSERT_EQ(any.base().policy(), entt::any_policy::embedded);
ASSERT_FALSE(any.try_cast<std::size_t>());
ASSERT_EQ(any.cast<char>(), 'c');
ASSERT_NE(any.data(), nullptr);
ASSERT_NE(any.base().data(), nullptr);
ASSERT_EQ(any, entt::meta_any{'c'});
ASSERT_NE(entt::meta_any{'h'}, any);
}
@@ -168,10 +163,10 @@ TEST_F(MetaAny, NoSBO) {
ASSERT_TRUE(any);
ASSERT_TRUE(any.base().owner());
ASSERT_EQ(any.policy(), entt::meta_any_policy::dynamic);
ASSERT_EQ(any.base().policy(), entt::any_policy::dynamic);
ASSERT_FALSE(any.try_cast<std::size_t>());
ASSERT_EQ(any.cast<fat>(), instance);
ASSERT_NE(any.data(), nullptr);
ASSERT_NE(any.base().data(), nullptr);
ASSERT_EQ(any, entt::meta_any{instance});
ASSERT_NE(any, fat{});
}
@@ -194,7 +189,7 @@ TEST_F(MetaAny, SBOInPlaceConstruction) {
ASSERT_TRUE(other);
ASSERT_FALSE(other.base().owner());
ASSERT_EQ(other.policy(), entt::any_policy::ref);
ASSERT_EQ(other.base().policy(), entt::any_policy::ref);
ASSERT_FALSE(other.try_cast<std::size_t>());
ASSERT_EQ(other.cast<int>(), 2);
ASSERT_NE(other.base().data(), nullptr);
@@ -371,15 +366,17 @@ TEST_F(MetaAny, SBOMoveAssignment) {
ASSERT_NE(other, entt::meta_any{0});
}
TEST_F(MetaAnyDeathTest, SBOSelfMoveAssignment) {
TEST_F(MetaAny, SBOSelfMoveAssignment) {
entt::meta_any any{3};
// avoid warnings due to self-assignment
any = std::move(*&any);
ASSERT_FALSE(any);
ASSERT_FALSE(any.type());
ASSERT_EQ(any.base().data(), nullptr);
ASSERT_TRUE(any);
ASSERT_FALSE(any.try_cast<std::size_t>());
ASSERT_EQ(any.cast<int>(), 3);
ASSERT_EQ(any, entt::meta_any{3});
ASSERT_NE(any, entt::meta_any{0});
}
TEST_F(MetaAny, SBODirectAssignment) {
@@ -526,7 +523,7 @@ TEST_F(MetaAny, NoSBOInPlaceConstruction) {
ASSERT_TRUE(other);
ASSERT_FALSE(other.base().owner());
ASSERT_EQ(other.policy(), entt::any_policy::ref);
ASSERT_EQ(other.base().policy(), entt::any_policy::ref);
ASSERT_FALSE(other.try_cast<std::size_t>());
ASSERT_EQ(other.cast<fat>(), instance);
ASSERT_NE(other.base().data(), nullptr);
@@ -705,16 +702,18 @@ TEST_F(MetaAny, NoSBOMoveAssignment) {
ASSERT_NE(other, fat{});
}
TEST_F(MetaAnyDeathTest, NoSBOSelfMoveAssignment) {
TEST_F(MetaAny, NoSBOSelfMoveAssignment) {
const fat instance{.1, .2, .3, .4};
entt::meta_any any{instance};
// avoid warnings due to self-assignment
any = std::move(*&any);
ASSERT_FALSE(any);
ASSERT_FALSE(any.type());
ASSERT_EQ(any.base().data(), nullptr);
ASSERT_TRUE(any);
ASSERT_FALSE(any.try_cast<std::size_t>());
ASSERT_EQ(any.cast<fat>(), instance);
ASSERT_EQ(any, entt::meta_any{instance});
ASSERT_NE(any, fat{});
}
TEST_F(MetaAny, NoSBODirectAssignment) {
@@ -961,15 +960,16 @@ TEST_F(MetaAny, VoidMoveAssignment) {
ASSERT_EQ(other, entt::meta_any{std::in_place_type<void>});
}
TEST_F(MetaAnyDeathTest, VoidSelfMoveAssignment) {
TEST_F(MetaAny, VoidSelfMoveAssignment) {
entt::meta_any any{std::in_place_type<void>};
// avoid warnings due to self-assignment
any = std::move(*&any);
ASSERT_FALSE(any);
ASSERT_FALSE(any.type());
ASSERT_EQ(any.base().data(), nullptr);
ASSERT_TRUE(any);
ASSERT_FALSE(any.try_cast<std::size_t>());
ASSERT_EQ(any.type(), entt::resolve<void>());
ASSERT_EQ(any, entt::meta_any{std::in_place_type<void>});
}
TEST_F(MetaAny, SBOMoveInvalidate) {
@@ -1021,8 +1021,7 @@ TEST_F(MetaAny, SBODestruction) {
any = std::move(other);
}
ASSERT_EQ(empty::destroy_counter, 3);
ASSERT_EQ(empty::destructor_counter, 6);
ASSERT_EQ(empty::counter, 6);
}
TEST_F(MetaAny, NoSBODestruction) {
@@ -1034,8 +1033,7 @@ TEST_F(MetaAny, NoSBODestruction) {
any = std::move(other);
}
ASSERT_EQ(fat::destroy_counter, 3);
ASSERT_EQ(empty::destructor_counter, 4);
ASSERT_EQ(empty::counter, 4);
}
TEST_F(MetaAny, VoidDestruction) {
@@ -1328,16 +1326,21 @@ TEST_F(MetaAny, Cast) {
}
TEST_F(MetaAny, AllowCast) {
entt::meta_any any{};
entt::meta_any instance{clazz{}};
entt::meta_any other{fat{}};
entt::meta_any arithmetic{3};
auto as_cref = entt::forward_as_meta(arithmetic.cast<const int &>());
ASSERT_FALSE(any);
ASSERT_TRUE(instance);
ASSERT_TRUE(other);
ASSERT_TRUE(arithmetic);
ASSERT_TRUE(as_cref);
ASSERT_FALSE(any.allow_cast<clazz>());
ASSERT_FALSE(std::as_const(any).allow_cast<clazz>());
ASSERT_TRUE(instance.allow_cast<clazz>());
ASSERT_TRUE(instance.allow_cast<clazz &>());
ASSERT_TRUE(instance.allow_cast<const clazz &>());
@@ -1386,16 +1389,20 @@ TEST_F(MetaAny, AllowCast) {
}
TEST_F(MetaAny, OpaqueAllowCast) {
entt::meta_any any{};
entt::meta_any instance{clazz{}};
entt::meta_any other{fat{}};
entt::meta_any arithmetic{3};
auto as_cref = entt::forward_as_meta(arithmetic.cast<const int &>());
ASSERT_FALSE(any);
ASSERT_TRUE(instance);
ASSERT_TRUE(other);
ASSERT_TRUE(arithmetic);
ASSERT_TRUE(as_cref);
ASSERT_FALSE(any.allow_cast(entt::resolve<clazz>()));
ASSERT_TRUE(instance.allow_cast(entt::resolve<clazz>()));
ASSERT_EQ(instance.type(), entt::resolve<clazz>());
-23
View File
@@ -117,7 +117,6 @@ class MetaContext: public ::testing::Test {
.custom<char>('c')
.base<base>()
.ctor<char, int>()
.dtor<&clazz::move_to_bucket>()
.data<nullptr, &clazz::value>("value"_hs)
.data<&clazz::value>("rw"_hs)
.func<&clazz::cfunc>("func"_hs);
@@ -336,21 +335,6 @@ TEST_F(MetaContext, MetaConv) {
ASSERT_EQ(local.cast<int>(), value.get_mul());
}
TEST_F(MetaContext, MetaDtor) {
auto global = entt::resolve<clazz>().construct();
auto local = entt::resolve<clazz>(ctx()).construct();
ASSERT_EQ(clazz::bucket, bucket_value);
global.reset();
ASSERT_EQ(clazz::bucket, bucket_value);
local.reset();
ASSERT_NE(clazz::bucket, bucket_value);
}
TEST_F(MetaContext, MetaCustom) {
using namespace entt::literals;
@@ -480,19 +464,12 @@ TEST_F(MetaContext, MetaHandle) {
entt::meta_handle global{value};
entt::meta_handle ctx_value{ctx(), value};
entt::meta_handle two_step_local{entt::meta_ctx_arg, ctx()};
ASSERT_TRUE(global);
ASSERT_TRUE(ctx_value);
ASSERT_FALSE(two_step_local);
two_step_local->emplace<int &>(value);
ASSERT_TRUE(two_step_local);
ASSERT_EQ(global->type().data("marker"_hs).get({}).cast<int>(), global_marker);
ASSERT_EQ(ctx_value->type().data("marker"_hs).get({}).cast<int>(), local_marker);
ASSERT_EQ(two_step_local->type().data("marker"_hs).get({}).cast<int>(), local_marker);
}
TEST_F(MetaContext, ForwardAsMeta) {
+71 -76
View File
@@ -17,18 +17,10 @@
struct base {
virtual ~base() = default;
static void destroy(base &) {
++counter;
}
inline static int counter = 0; // NOLINT
int value{3};
};
struct derived: base {
derived() = default;
};
struct derived: base {};
struct clazz {
operator int() const {
@@ -70,18 +62,6 @@ struct setter_getter {
int value{0};
};
struct multi_setter {
void from_double(double val) {
value = static_cast<int>(val);
}
void from_string(const char *val) {
value = std::atoi(val);
}
int value{0};
};
struct array {
inline static int global[2]; // NOLINT
int local[4]; // NOLINT
@@ -93,13 +73,11 @@ struct MetaData: ::testing::Test {
entt::meta_factory<base>{}
.type("base"_hs)
.dtor<base::destroy>()
.data<&base::value>("value"_hs);
entt::meta_factory<derived>{}
.type("derived"_hs)
.base<base>()
.dtor<derived::destroy>()
.data<&base::value>("value_from_base"_hs);
entt::meta_factory<clazz>{}
@@ -108,9 +86,9 @@ struct MetaData: ::testing::Test {
.custom<char>('c')
.traits(test::meta_traits::one | test::meta_traits::two | test::meta_traits::three)
.data<&clazz::i, entt::as_cref_t>("ci"_hs)
.data<&clazz::j>("j"_hs)
.data<&clazz::j>("j")
.traits(test::meta_traits::one)
.data<&clazz::h>("h"_hs)
.data<&clazz::h>("h"_hs, "hhh")
.traits(test::meta_traits::two)
.data<&clazz::k>("k"_hs)
.traits(test::meta_traits::three)
@@ -119,25 +97,26 @@ struct MetaData: ::testing::Test {
.data<&clazz::i, entt::as_void_t>("void"_hs)
.conv<int>();
entt::meta_factory<clazz>{}
.data<&clazz::i, entt::as_is_t>("ir"_hs)
.data<&clazz::j, entt::as_is_t>("jc"_hs)
.data<&clazz::h, entt::as_is_t>("hr"_hs)
.data<&clazz::k, entt::as_is_t>("kc"_hs)
.data<nullptr, &clazz::operator int, entt::as_is_t>("ov"_hs);
entt::meta_factory<setter_getter>{}
.type("setter_getter"_hs)
.data<&setter_getter::static_setter, &setter_getter::static_getter>("x"_hs)
.data<&setter_getter::setter, &setter_getter::getter>("y"_hs)
.data<&setter_getter::static_setter, &setter_getter::getter>("z"_hs)
.data<&setter_getter::setter_with_ref, &setter_getter::getter_with_ref>("w"_hs)
.data<nullptr, &setter_getter::getter>("z_ro"_hs)
.data<&setter_getter::setter_with_ref, &setter_getter::getter_with_ref>("w")
.data<nullptr, &setter_getter::getter>("z_ro"_hs, "readonly")
.data<nullptr, &setter_getter::value>("value"_hs);
entt::meta_factory<multi_setter>{}
.type("multi_setter"_hs)
.data<entt::value_list<&multi_setter::from_double, &multi_setter::from_string>, &multi_setter::value>("value"_hs);
entt::meta_factory<array>{}
.type("array"_hs)
.data<&array::global>("global"_hs)
.data<&array::local>("local"_hs);
base::counter = 0;
}
void TearDown() override {
@@ -147,22 +126,6 @@ struct MetaData: ::testing::Test {
using MetaDataDeathTest = MetaData;
TEST_F(MetaData, SafeWhenEmpty) {
const entt::meta_data data{};
ASSERT_FALSE(data);
ASSERT_EQ(data, entt::meta_data{});
ASSERT_EQ(data.arity(), 0u);
ASSERT_FALSE(data.is_const());
ASSERT_FALSE(data.is_static());
ASSERT_EQ(data.type(), entt::meta_type{});
ASSERT_FALSE(data.set({}, 0));
ASSERT_FALSE(data.get({}));
ASSERT_EQ(data.arg(0u), entt::meta_type{});
ASSERT_EQ(data.traits<test::meta_traits>(), test::meta_traits::none);
ASSERT_EQ(static_cast<const char *>(data.custom()), nullptr);
}
TEST_F(MetaData, UserTraits) {
using namespace entt::literals;
@@ -200,6 +163,21 @@ ENTT_DEBUG_TEST_F(MetaDataDeathTest, Custom) {
ASSERT_DEATH([[maybe_unused]] const char value = entt::resolve<clazz>().data("j"_hs).custom(), "");
}
TEST_F(MetaData, Name) {
using namespace entt::literals;
const entt::meta_type type = entt::resolve<clazz>();
const entt::meta_type other = entt::resolve<setter_getter>();
ASSERT_EQ(type.data("i"_hs).name(), nullptr);
ASSERT_STREQ(type.data("j"_hs).name(), "j");
ASSERT_STREQ(type.data("h"_hs).name(), "hhh");
ASSERT_EQ(other.data("z"_hs).name(), nullptr);
ASSERT_STREQ(other.data("w"_hs).name(), "w");
ASSERT_STREQ(other.data("z_ro"_hs).name(), "readonly");
}
TEST_F(MetaData, Comparison) {
using namespace entt::literals;
@@ -335,10 +313,13 @@ TEST_F(MetaData, SetCast) {
using namespace entt::literals;
clazz instance{};
derived other{};
ASSERT_EQ(base::counter, 0);
ASSERT_TRUE(entt::resolve<clazz>().data("base"_hs).set(instance, derived{}));
ASSERT_EQ(base::counter, 1);
other.value = 1;
ASSERT_EQ(instance.instance.value, 3);
ASSERT_TRUE(entt::resolve<clazz>().data("base"_hs).set(instance, other));
ASSERT_EQ(instance.instance.value, 1);
}
TEST_F(MetaData, SetConvert) {
@@ -490,30 +471,6 @@ TEST_F(MetaData, SetterGetterReadOnlyDataMember) {
ASSERT_EQ(data.get(instance).cast<int>(), 0);
}
TEST_F(MetaData, MultiSetter) {
using namespace entt::literals;
auto data = entt::resolve<multi_setter>().data("value"_hs);
multi_setter instance{};
ASSERT_TRUE(data);
ASSERT_EQ(data.arity(), 2u);
ASSERT_EQ(data.type(), entt::resolve<int>());
ASSERT_EQ(data.arg(0u), entt::resolve<double>());
ASSERT_EQ(data.arg(1u), entt::resolve<const char *>());
ASSERT_EQ(data.arg(2u), entt::meta_type{});
ASSERT_FALSE(data.is_const());
ASSERT_FALSE(data.is_static());
ASSERT_EQ(data.get(instance).cast<int>(), 0);
ASSERT_TRUE(data.set(instance, 1));
ASSERT_EQ(data.get(instance).cast<int>(), 1);
ASSERT_TRUE(data.set(instance, 2.));
ASSERT_EQ(data.get(instance).cast<int>(), 2);
ASSERT_FALSE(data.set(instance, std::string{"3"}));
ASSERT_TRUE(data.set(instance, std::string{"3"}.c_str()));
ASSERT_EQ(data.get(instance).cast<int>(), 3);
}
TEST_F(MetaData, ConstInstance) {
using namespace entt::literals;
@@ -591,6 +548,44 @@ TEST_F(MetaData, AsVoid) {
ASSERT_EQ(data.get(instance), entt::meta_any{std::in_place_type<void>});
}
TEST_F(MetaData, AsIs) {
using namespace entt::literals;
auto type = entt::resolve<clazz>();
entt::meta_data data{};
clazz instance{};
data = type.data("ir"_hs);
ASSERT_TRUE(data);
ASSERT_EQ(data.type(), entt::resolve<int>());
ASSERT_EQ(data.get(instance).base().policy(), entt::any_policy::ref);
data = type.data("jc"_hs);
ASSERT_TRUE(data);
ASSERT_EQ(data.type(), entt::resolve<int>());
ASSERT_EQ(data.get(instance).base().policy(), entt::any_policy::cref);
data = type.data("hr"_hs);
ASSERT_TRUE(data);
ASSERT_EQ(data.type(), entt::resolve<int>());
ASSERT_EQ(data.get(instance).base().policy(), entt::any_policy::ref);
data = type.data("kc"_hs);
ASSERT_TRUE(data);
ASSERT_EQ(data.type(), entt::resolve<int>());
ASSERT_EQ(data.get(instance).base().policy(), entt::any_policy::cref);
data = type.data("ov"_hs);
ASSERT_TRUE(data);
ASSERT_EQ(data.type(), entt::resolve<int>());
ASSERT_EQ(data.get(instance).base().policy(), entt::any_policy::embedded);
}
TEST_F(MetaData, AsRef) {
using namespace entt::literals;
-115
View File
@@ -1,115 +0,0 @@
#include <utility>
#include <gtest/gtest.h>
#include <entt/core/hashed_string.hpp>
#include <entt/locator/locator.hpp>
#include <entt/meta/context.hpp>
#include <entt/meta/factory.hpp>
#include <entt/meta/meta.hpp>
#include <entt/meta/node.hpp>
#include <entt/meta/resolve.hpp>
struct clazz {
clazz(int &cnt)
: counter{&cnt} {
++(*counter);
}
static void destroy_decr(clazz &instance) {
--(*instance.counter);
}
void destroy_incr() const {
++(*counter);
}
int *counter;
};
struct MetaDtor: ::testing::Test {
void SetUp() override {
using namespace entt::literals;
entt::meta_factory<clazz>{}
.type("clazz"_hs)
.ctor<int &>()
.dtor<clazz::destroy_decr>();
}
void TearDown() override {
entt::meta_reset();
}
};
TEST_F(MetaDtor, Dtor) {
int counter{};
auto any = entt::resolve<clazz>().construct(entt::forward_as_meta(counter));
auto cref = std::as_const(any).as_ref();
auto ref = any.as_ref();
ASSERT_TRUE(any);
ASSERT_TRUE(cref);
ASSERT_TRUE(ref);
ASSERT_EQ(counter, 1);
cref.reset();
ref.reset();
ASSERT_TRUE(any);
ASSERT_FALSE(cref);
ASSERT_FALSE(ref);
ASSERT_EQ(counter, 1);
any.reset();
ASSERT_FALSE(any);
ASSERT_FALSE(cref);
ASSERT_FALSE(ref);
ASSERT_EQ(counter, 0);
}
TEST_F(MetaDtor, AsRefConstruction) {
int counter{};
clazz instance{counter};
auto any = entt::forward_as_meta(instance);
auto cany = entt::forward_as_meta(std::as_const(instance));
auto cref = cany.as_ref();
auto ref = any.as_ref();
ASSERT_TRUE(any);
ASSERT_TRUE(cany);
ASSERT_TRUE(cref);
ASSERT_TRUE(ref);
ASSERT_EQ(counter, 1);
any.reset();
cany.reset();
cref.reset();
ref.reset();
ASSERT_FALSE(any);
ASSERT_FALSE(cany);
ASSERT_FALSE(cref);
ASSERT_FALSE(ref);
ASSERT_EQ(counter, 1);
}
TEST_F(MetaDtor, ReRegistration) {
SetUp();
int counter{};
auto &&node = entt::internal::resolve<clazz>(entt::internal::meta_context::from(entt::locator<entt::meta_ctx>::value_or()));
ASSERT_NE(node.dtor.dtor, nullptr);
entt::meta_factory<clazz>{}.dtor<&clazz::destroy_incr>();
entt::resolve<clazz>().construct(entt::forward_as_meta(counter)).reset();
ASSERT_EQ(counter, 2);
}
+18 -69
View File
@@ -49,18 +49,6 @@ private:
int value{};
};
struct dtor_callback {
dtor_callback(bool &ref)
: cb{&ref} {}
static void on_destroy(dtor_callback &instance) {
*instance.cb = !*instance.cb;
}
private:
bool *cb;
};
struct MetaFactory: ::testing::Test {
void TearDown() override {
entt::meta_reset();
@@ -115,7 +103,7 @@ ENTT_DEBUG_TEST_F(MetaFactoryDeathTest, Type) {
factory.type("foo"_hs);
ASSERT_DEATH(other.type("foo"_hs);, "");
ASSERT_DEATH(other.type("foo"_hs), "");
}
TEST_F(MetaFactory, Base) {
@@ -175,22 +163,6 @@ TEST_F(MetaFactory, Ctor) {
ASSERT_EQ(other.cast<const clazz &>().get_int(), values[1u]);
}
TEST_F(MetaFactory, Dtor) {
bool check = false;
entt::meta_factory<dtor_callback> factory{};
entt::meta_any any{std::in_place_type<dtor_callback>, check};
any.reset();
ASSERT_FALSE(check);
factory.dtor<&dtor_callback::on_destroy>();
any.emplace<dtor_callback>(check);
any.reset();
ASSERT_TRUE(check);
}
TEST_F(MetaFactory, DataMemberObject) {
using namespace entt::literals;
@@ -282,27 +254,6 @@ TEST_F(MetaFactory, DataSetterGetter) {
ASSERT_TRUE(type.set("value"_hs, instance, instance.get_int()));
}
TEST_F(MetaFactory, DataMultiSetterGetter) {
using namespace entt::literals;
clazz instance{1};
entt::meta_factory<clazz> factory{};
entt::meta_type type = entt::resolve<clazz>();
ASSERT_FALSE(type.data("value"_hs));
factory.data<entt::value_list<&clazz::set_int, &clazz::set_boxed_int>, &clazz::get_int>("value"_hs);
type = entt::resolve<clazz>();
ASSERT_TRUE(type.data("value"_hs));
ASSERT_EQ(type.get("value"_hs, std::as_const(instance)), instance.get_int());
ASSERT_EQ(type.get("value"_hs, instance), instance.get_int());
ASSERT_FALSE(type.set("value"_hs, std::as_const(instance), instance.get_int()));
ASSERT_TRUE(type.set("value"_hs, instance, instance.get_int()));
ASSERT_FALSE(type.set("value"_hs, std::as_const(instance), test::boxed_int{instance.get_int()}));
ASSERT_TRUE(type.set("value"_hs, instance, test::boxed_int{instance.get_int()}));
}
TEST_F(MetaFactory, DataOverwrite) {
using namespace entt::literals;
@@ -400,6 +351,23 @@ TEST_F(MetaFactory, Traits) {
ASSERT_EQ(type.data("member"_hs).traits<test::meta_traits>(), test::meta_traits::one);
ASSERT_EQ(type.func("func"_hs).traits<test::meta_traits>(), test::meta_traits::two);
ASSERT_EQ(type.func("func"_hs).next().traits<test::meta_traits>(), test::meta_traits::three);
entt::meta_factory<clazz>{}
.traits(test::meta_traits::one, true)
.data<&base::member>("member"_hs)
.traits(test::meta_traits::one | test::meta_traits::three, true)
.func<&clazz::set_int>("func"_hs)
.traits(test::meta_traits::one | test::meta_traits::three, true)
.func<&clazz::set_boxed_int>("func"_hs)
.traits(test::meta_traits::all, true);
// traits are copied and never refreshed
type = entt::resolve<clazz>();
ASSERT_EQ(type.traits<test::meta_traits>(), test::meta_traits::three);
ASSERT_EQ(type.data("member"_hs).traits<test::meta_traits>(), test::meta_traits::none);
ASSERT_EQ(type.func("func"_hs).traits<test::meta_traits>(), test::meta_traits::two);
ASSERT_EQ(type.func("func"_hs).next().traits<test::meta_traits>(), test::meta_traits::none);
}
TEST_F(MetaFactory, Custom) {
@@ -435,25 +403,6 @@ TEST_F(MetaFactory, Custom) {
ASSERT_EQ(static_cast<int>(type.func("func"_hs).next().custom()), 3);
}
TEST_F(MetaFactory, Meta) {
entt::meta_ctx ctx{};
ASSERT_EQ(entt::resolve(entt::type_id<int>()), entt::meta_type{});
ASSERT_EQ(entt::resolve(ctx, entt::type_id<int>()), entt::meta_type{});
auto factory = entt::meta<int>();
ASSERT_NE(entt::resolve(entt::type_id<int>()), entt::meta_type{});
ASSERT_EQ(entt::resolve(ctx, entt::type_id<int>()), entt::meta_type{});
ASSERT_TRUE(entt::resolve(entt::type_id<int>()).is_integral());
factory = entt::meta<int>(ctx);
ASSERT_NE(entt::resolve(entt::type_id<int>()), entt::meta_type{});
ASSERT_NE(entt::resolve(ctx, entt::type_id<int>()), entt::meta_type{});
ASSERT_TRUE(entt::resolve(ctx, entt::type_id<int>()).is_integral());
}
TEST_F(MetaFactory, MetaReset) {
using namespace entt::literals;
+123 -24
View File
@@ -58,6 +58,10 @@ struct function {
return value * iv;
}
[[nodiscard]] int f(int iv) {
return (value += iv);
}
void g(int iv) {
value = iv * iv;
}
@@ -70,7 +74,7 @@ struct function {
instance.value = iv;
}
[[nodiscard]] int v(int &iv) const {
[[nodiscard]] const int &v(int &iv) const {
return (iv = value);
}
@@ -107,8 +111,8 @@ struct MetaFunc: ::testing::Test {
.type("derived"_hs)
.base<base>()
.func<&base::setter>("setter_from_base"_hs)
.func<&base::getter>("getter_from_base"_hs)
.func<&base::static_setter>("static_setter_from_base"_hs);
.func<&base::getter>("getter_from_base")
.func<&base::static_setter>("static_setter_from_base"_hs, "static setter");
entt::meta_factory<function>{}
.type("func"_hs)
@@ -121,6 +125,10 @@ struct MetaFunc: ::testing::Test {
.custom<int>(2)
.func<entt::overload<int(int) const>(&function::f)>("f1"_hs)
.traits(test::meta_traits::one)
.func<entt::overload<int(int) const>(&function::f)>("cf"_hs)
.func<entt::overload<int(int)>(&function::f)>("cf"_hs)
.func<entt::overload<int(int)>(&function::f)>("ncf"_hs)
.func<entt::overload<int(int) const>(&function::f)>("ncf"_hs)
.func<&function::g>("g"_hs)
.custom<char>('c')
.func<function::h>("h"_hs)
@@ -129,6 +137,12 @@ struct MetaFunc: ::testing::Test {
.func<&function::a, entt::as_ref_t>("a"_hs)
.func<&function::a, entt::as_cref_t>("ca"_hs)
.conv<int>();
entt::meta_factory<function>{}
.func<&function::a, entt::as_is_t>("ar"_hs)
.func<&function::v, entt::as_is_t>("vc"_hs)
.func<&function::operator int, entt::as_is_t>("ov"_hs)
.func<&function::g, entt::as_is_t>("ge"_hs);
}
void TearDown() override {
@@ -158,27 +172,6 @@ struct MetaFunc: ::testing::Test {
using MetaFuncDeathTest = MetaFunc;
TEST_F(MetaFunc, SafeWhenEmpty) {
const entt::meta_func func{};
entt::meta_any *args = nullptr;
ASSERT_FALSE(func);
ASSERT_EQ(func, entt::meta_func{});
ASSERT_EQ(func.arity(), 0u);
ASSERT_FALSE(func.is_const());
ASSERT_FALSE(func.is_static());
ASSERT_EQ(func.ret(), entt::meta_type{});
ASSERT_EQ(func.arg(0u), entt::meta_type{});
ASSERT_EQ(func.arg(1u), entt::meta_type{});
ASSERT_FALSE(func.invoke({}, args, 0u));
ASSERT_FALSE(func.invoke({}, args, 1u));
ASSERT_FALSE(func.invoke({}));
ASSERT_FALSE(func.invoke({}, 'c'));
ASSERT_EQ(func.traits<test::meta_traits>(), test::meta_traits::none);
ASSERT_EQ(static_cast<const char *>(func.custom()), nullptr);
ASSERT_EQ(func.next(), func);
}
TEST_F(MetaFunc, UserTraits) {
using namespace entt::literals;
@@ -216,6 +209,16 @@ ENTT_DEBUG_TEST_F(MetaFuncDeathTest, Custom) {
ASSERT_DEATH([[maybe_unused]] const char value = entt::resolve<function>().func("h"_hs).custom(), "");
}
TEST_F(MetaFunc, Name) {
using namespace entt::literals;
const entt::meta_type type = entt::resolve<derived>();
ASSERT_EQ(type.func("setter_from_base"_hs).name(), nullptr);
ASSERT_STREQ(type.func("getter_from_base"_hs).name(), "getter_from_base");
ASSERT_STREQ(type.func("static_setter_from_base"_hs).name(), "static setter");
}
TEST_F(MetaFunc, Comparison) {
using namespace entt::literals;
@@ -506,6 +509,38 @@ TEST_F(MetaFunc, AsVoid) {
ASSERT_EQ(value, instance.value);
}
TEST_F(MetaFunc, AsIs) {
using namespace entt::literals;
auto type = entt::resolve<function>();
entt::meta_func func{};
function instance{3};
func = type.func("ar"_hs);
ASSERT_TRUE(func);
ASSERT_EQ(func.ret(), entt::resolve<int>());
ASSERT_EQ(func.invoke(instance).base().policy(), entt::any_policy::ref);
func = type.func("vc"_hs);
ASSERT_TRUE(func);
ASSERT_EQ(func.ret(), entt::resolve<int>());
ASSERT_EQ(func.invoke(instance, 3).base().policy(), entt::any_policy::cref);
func = type.func("ov"_hs);
ASSERT_TRUE(func);
ASSERT_EQ(func.ret(), entt::resolve<int>());
ASSERT_EQ(func.invoke(instance).base().policy(), entt::any_policy::embedded);
func = type.func("ge"_hs);
ASSERT_TRUE(func);
ASSERT_EQ(func.ret(), entt::resolve<void>());
ASSERT_EQ(func.invoke(instance).base().policy(), entt::any_policy::empty);
}
TEST_F(MetaFunc, AsRef) {
using namespace entt::literals;
@@ -633,6 +668,70 @@ TEST_F(MetaFunc, Overloaded) {
ASSERT_EQ(static_cast<const int &>(type.func("f2"_hs).next().custom()), 3);
}
TEST_F(MetaFunc, OverloadedConstFirst) {
using namespace entt::literals;
auto func = entt::resolve<function>().func("cf"_hs);
auto next = func.next();
function instance{2};
ASSERT_TRUE(func);
ASSERT_EQ(func.arity(), 1u);
ASSERT_TRUE(func.is_const());
ASSERT_EQ(func.ret(), entt::resolve<int>());
ASSERT_EQ(func.arg(0u), entt::resolve<int>());
ASSERT_TRUE(next);
ASSERT_EQ(next.arity(), 1u);
ASSERT_FALSE(next.is_const());
ASSERT_EQ(next.ret(), entt::resolve<int>());
ASSERT_EQ(next.arg(0u), entt::resolve<int>());
ASSERT_EQ(func.invoke(instance, 1).cast<int>(), 2);
ASSERT_EQ(next.invoke(instance, 1).cast<int>(), 3);
ASSERT_EQ(func.invoke(std::as_const(instance), 1).cast<int>(), 3);
ASSERT_FALSE(next.invoke(std::as_const(instance), 1));
ASSERT_EQ(func.invoke(entt::meta_handle{instance}, entt::meta_any{1}).cast<int>(), 3);
ASSERT_EQ(next.invoke(entt::meta_handle{instance}, entt::meta_any{1}).cast<int>(), 4);
ASSERT_EQ(func.invoke(entt::meta_handle{std::as_const(instance)}, entt::meta_any{1}).cast<int>(), 4);
ASSERT_FALSE(next.invoke(entt::meta_handle{std::as_const(instance)}, entt::meta_any{1}));
}
TEST_F(MetaFunc, OverloadedNonConstFirst) {
using namespace entt::literals;
auto func = entt::resolve<function>().func("ncf"_hs);
auto next = func.next();
function instance{2};
ASSERT_TRUE(func);
ASSERT_EQ(func.arity(), 1u);
ASSERT_FALSE(func.is_const());
ASSERT_EQ(func.ret(), entt::resolve<int>());
ASSERT_EQ(func.arg(0u), entt::resolve<int>());
ASSERT_TRUE(next);
ASSERT_EQ(next.arity(), 1u);
ASSERT_TRUE(next.is_const());
ASSERT_EQ(next.ret(), entt::resolve<int>());
ASSERT_EQ(next.arg(0u), entt::resolve<int>());
ASSERT_EQ(func.invoke(instance, 1).cast<int>(), 3);
ASSERT_EQ(next.invoke(instance, 1).cast<int>(), 3);
ASSERT_FALSE(func.invoke(std::as_const(instance), 1));
ASSERT_EQ(next.invoke(std::as_const(instance), 1).cast<int>(), 3);
ASSERT_EQ(func.invoke(entt::meta_handle{instance}, entt::meta_any{1}).cast<int>(), 4);
ASSERT_EQ(next.invoke(entt::meta_handle{instance}, entt::meta_any{1}).cast<int>(), 4);
ASSERT_FALSE(func.invoke(entt::meta_handle{std::as_const(instance)}, entt::meta_any{1}));
ASSERT_EQ(next.invoke(entt::meta_handle{std::as_const(instance)}, entt::meta_any{1}).cast<int>(), 4);
}
TEST_F(MetaFunc, OverloadedOrder) {
using namespace entt::literals;
+45 -10
View File
@@ -1,6 +1,8 @@
#include <utility>
#include <gtest/gtest.h>
#include <entt/core/hashed_string.hpp>
#include <entt/locator/locator.hpp>
#include <entt/meta/context.hpp>
#include <entt/meta/factory.hpp>
#include <entt/meta/meta.hpp>
@@ -41,22 +43,12 @@ TEST_F(MetaHandle, Handle) {
ASSERT_FALSE(handle);
ASSERT_FALSE(chandle);
ASSERT_EQ(handle, chandle);
ASSERT_EQ(handle, entt::meta_handle{});
ASSERT_FALSE(handle != handle);
ASSERT_TRUE(handle == handle);
handle = entt::meta_handle{instance};
chandle = entt::meta_handle{std::as_const(instance)};
ASSERT_TRUE(handle);
ASSERT_TRUE(chandle);
ASSERT_EQ(handle, chandle);
ASSERT_NE(handle, entt::meta_handle{});
ASSERT_FALSE(handle != handle);
ASSERT_TRUE(handle == handle);
ASSERT_TRUE(handle->invoke("incr"_hs));
ASSERT_FALSE(chandle->invoke("incr"_hs));
ASSERT_FALSE(std::as_const(handle)->invoke("incr"_hs));
@@ -71,3 +63,46 @@ TEST_F(MetaHandle, Handle) {
ASSERT_FALSE(std::as_const(handle)->invoke("decr"_hs));
ASSERT_EQ(instance.value, 0);
}
TEST_F(MetaHandle, Value) {
int value{2};
entt::meta_handle handle{value};
entt::meta_handle chandle{std::as_const(value)};
ASSERT_NE(handle->try_cast<int>(), nullptr);
ASSERT_NE(handle->try_cast<const int>(), nullptr);
ASSERT_EQ(chandle->try_cast<int>(), nullptr);
ASSERT_NE(chandle->try_cast<const int>(), nullptr);
ASSERT_EQ(&handle->context(), &entt::locator<entt::meta_ctx>::value_or());
ASSERT_EQ(&chandle->context(), &entt::locator<entt::meta_ctx>::value_or());
}
TEST_F(MetaHandle, MetaAny) {
entt::meta_any value{2};
entt::meta_handle handle{value};
entt::meta_handle chandle{std::as_const(value)};
ASSERT_NE(handle->try_cast<int>(), nullptr);
ASSERT_NE(handle->try_cast<const int>(), nullptr);
ASSERT_EQ(chandle->try_cast<int>(), nullptr);
ASSERT_NE(chandle->try_cast<const int>(), nullptr);
ASSERT_EQ(&handle->context(), &entt::locator<entt::meta_ctx>::value_or());
ASSERT_EQ(&chandle->context(), &entt::locator<entt::meta_ctx>::value_or());
}
TEST_F(MetaHandle, ScopedMetaAny) {
const entt::meta_ctx ctx{};
entt::meta_any value{ctx, 2};
entt::meta_handle handle{value};
entt::meta_handle chandle{std::as_const(value)};
ASSERT_NE(handle->try_cast<int>(), nullptr);
ASSERT_NE(handle->try_cast<const int>(), nullptr);
ASSERT_EQ(chandle->try_cast<int>(), nullptr);
ASSERT_NE(chandle->try_cast<const int>(), nullptr);
ASSERT_EQ(&handle->context(), &ctx);
ASSERT_EQ(&chandle->context(), &ctx);
}
+108 -8
View File
@@ -32,6 +32,10 @@ Type get(Type &elem) {
struct base {
char value{'c'};
static int f() {
return 0;
}
};
struct derived: base {
@@ -127,17 +131,18 @@ struct MetaType: ::testing::Test {
.data<set<double>, get<double>>("var"_hs);
entt::meta_factory<unsigned int>{}
.type("unsigned int"_hs)
.type("unsigned int"_hs, "uint")
.traits(test::meta_traits::two)
.data<0u>("min"_hs)
.data<128u>("max"_hs);
entt::meta_factory<base>{}
.type("base"_hs)
.data<&base::value>("value"_hs);
.data<&base::value>("value"_hs)
.func<&base::f>("func"_hs);
entt::meta_factory<derived>{}
.type("derived"_hs)
.type("derived")
.traits(test::meta_traits::one | test::meta_traits::three)
.base<base>();
@@ -157,7 +162,11 @@ struct MetaType: ::testing::Test {
.func<entt::overload<int(int, int)>(&overloaded_func::f)>("f"_hs)
.func<entt::overload<int(int)>(&overloaded_func::f)>("f"_hs)
.func<entt::overload<int(int) const>(&overloaded_func::f)>("f"_hs)
.func<entt::overload<float(int, float)>(&overloaded_func::f)>("f"_hs);
.func<entt::overload<float(int, float)>(&overloaded_func::f)>("f"_hs)
.func<entt::overload<int(int) const>(&overloaded_func::f)>("cf"_hs)
.func<entt::overload<int(int)>(&overloaded_func::f)>("cf"_hs)
.func<entt::overload<int(int)>(&overloaded_func::f)>("ncf"_hs)
.func<entt::overload<int(int) const>(&overloaded_func::f)>("ncf"_hs);
entt::meta_factory<property_type>{}
.type("property"_hs)
@@ -214,7 +223,7 @@ TEST_F(MetaType, SafeWhenEmpty) {
ASSERT_FALSE(type);
ASSERT_EQ(type, entt::meta_type{});
ASSERT_EQ(type.info(), entt::type_id<void>());
ASSERT_EQ(type.id(), entt::id_type{});
ASSERT_EQ(type.id(), entt::type_id<void>().hash());
ASSERT_EQ(type.size_of(), 0u);
ASSERT_FALSE(type.is_arithmetic());
ASSERT_FALSE(type.is_integral());
@@ -233,9 +242,9 @@ TEST_F(MetaType, SafeWhenEmpty) {
ASSERT_EQ(type.template_arg(0u), type);
ASSERT_EQ(type.template_arg(1u), type);
ASSERT_FALSE(type.can_cast(type));
ASSERT_FALSE(type.can_cast(entt::resolve<void>()));
ASSERT_FALSE(type.can_convert(type));
ASSERT_FALSE(type.can_convert(entt::resolve<void>()));
ASSERT_TRUE(type.can_cast(entt::resolve<void>()));
ASSERT_TRUE(type.can_convert(type));
ASSERT_TRUE(type.can_convert(entt::resolve<void>()));
ASSERT_EQ(type.base().begin(), type.base().end());
ASSERT_EQ(type.data().begin(), type.data().end());
ASSERT_EQ(type.data("data"_hs), entt::meta_data{});
@@ -301,6 +310,15 @@ TEST_F(MetaType, IdAndInfo) {
ASSERT_EQ(type.info(), entt::type_id<clazz>());
}
TEST_F(MetaType, Name) {
using namespace entt::literals;
ASSERT_EQ(entt::resolve<base>().name(), nullptr);
ASSERT_STREQ(entt::resolve<derived>().name(), "derived");
ASSERT_STREQ(entt::resolve<unsigned int>().name(), "uint");
ASSERT_EQ(entt::resolve<void>().name(), nullptr);
}
TEST_F(MetaType, SizeOf) {
ASSERT_EQ(entt::resolve<void>().size_of(), 0u);
ASSERT_EQ(entt::resolve<int>().size_of(), sizeof(int));
@@ -442,6 +460,17 @@ TEST_F(MetaType, Data) {
ASSERT_EQ(type.data().cbegin(), type.data().cend());
}
TEST_F(MetaType, DataRecursive) {
using namespace entt::literals;
auto type = entt::resolve<derived>();
const derived instance{};
ASSERT_TRUE(type.data("value"_hs));
ASSERT_EQ('c', type.data("value"_hs).get(instance).cast<char>());
ASSERT_FALSE(type.data("value"_hs, false));
}
TEST_F(MetaType, Func) {
using namespace entt::literals;
@@ -465,6 +494,17 @@ TEST_F(MetaType, Func) {
ASSERT_EQ(type.func().cbegin(), type.func().cend());
}
TEST_F(MetaType, FuncRecursive) {
using namespace entt::literals;
auto type = entt::resolve<derived>();
const derived instance{};
ASSERT_TRUE(type.func("func"_hs));
ASSERT_EQ(0, type.func("func"_hs).invoke(instance).cast<int>());
ASSERT_FALSE(type.func("func"_hs, false));
}
TEST_F(MetaType, Invoke) {
using namespace entt::literals;
@@ -543,6 +583,66 @@ TEST_F(MetaType, OverloadedFunc) {
ASSERT_FALSE(type.invoke("f"_hs, instance, 4, 8.));
}
TEST_F(MetaType, OverloadedFuncConstFirst) {
using namespace entt::literals;
const auto type = entt::resolve<overloaded_func>();
overloaded_func instance{2};
entt::meta_any res{};
ASSERT_TRUE(type.func("cf"_hs));
res = type.invoke("cf"_hs, instance, 1);
ASSERT_TRUE(res);
ASSERT_EQ(res.cast<int>(), 4);
res = type.invoke("cf"_hs, std::as_const(instance), 1);
ASSERT_TRUE(res);
ASSERT_EQ(res.cast<int>(), 2);
res = type.invoke("cf"_hs, entt::meta_handle{instance}, entt::meta_any{1});
ASSERT_TRUE(res);
ASSERT_EQ(res.cast<int>(), 4);
res = type.invoke("cf"_hs, entt::meta_handle{std::as_const(instance)}, entt::meta_any{1});
ASSERT_TRUE(res);
ASSERT_EQ(res.cast<int>(), 2);
}
TEST_F(MetaType, OverloadedFuncNonConstFirst) {
using namespace entt::literals;
const auto type = entt::resolve<overloaded_func>();
overloaded_func instance{2};
entt::meta_any res{};
ASSERT_TRUE(type.func("ncf"_hs));
res = type.invoke("ncf"_hs, instance, 1);
ASSERT_TRUE(res);
ASSERT_EQ(res.cast<int>(), 4);
res = type.invoke("ncf"_hs, std::as_const(instance), 1);
ASSERT_TRUE(res);
ASSERT_EQ(res.cast<int>(), 2);
res = type.invoke("ncf"_hs, entt::meta_handle{instance}, entt::meta_any{1});
ASSERT_TRUE(res);
ASSERT_EQ(res.cast<int>(), 4);
res = type.invoke("ncf"_hs, entt::meta_handle{std::as_const(instance)}, entt::meta_any{1});
ASSERT_TRUE(res);
ASSERT_EQ(res.cast<int>(), 2);
}
TEST_F(MetaType, OverloadedFuncOrder) {
using namespace entt::literals;
+47 -27
View File
@@ -59,24 +59,44 @@ using MetaUtilityDeathTest = MetaUtility;
TEST_F(MetaUtility, MetaDispatch) {
int value = 2;
auto as_void = entt::meta_dispatch<entt::as_void_t>(value);
auto as_ref = entt::meta_dispatch<entt::as_ref_t>(value);
auto as_cref = entt::meta_dispatch<entt::as_cref_t>(value);
auto as_is = entt::meta_dispatch(value);
auto as_ref = entt::meta_dispatch<entt::as_ref_t>(value);
auto as_void = entt::meta_dispatch<entt::as_void_t>(value);
auto as_is_copy = entt::meta_dispatch<entt::as_is_t>(static_cast<int &&>(value));
auto as_is_cref = entt::meta_dispatch<entt::as_is_t>(std::as_const(value));
auto as_is_ref = entt::meta_dispatch<entt::as_is_t>(value);
auto as_value = entt::meta_dispatch(value);
ASSERT_EQ(as_void.type(), entt::resolve<void>());
ASSERT_EQ(as_ref.type(), entt::resolve<int>());
ASSERT_EQ(as_cref.type(), entt::resolve<int>());
ASSERT_EQ(as_is.type(), entt::resolve<int>());
ASSERT_EQ(as_ref.type(), entt::resolve<int>());
ASSERT_EQ(as_void.type(), entt::resolve<void>());
ASSERT_EQ(as_is_copy.type(), entt::resolve<int>());
ASSERT_EQ(as_is_cref.type(), entt::resolve<int>());
ASSERT_EQ(as_is_ref.type(), entt::resolve<int>());
ASSERT_EQ(as_value.type(), entt::resolve<int>());
ASSERT_EQ(as_cref.base().policy(), entt::any_policy::cref);
ASSERT_EQ(as_ref.base().policy(), entt::any_policy::ref);
ASSERT_EQ(as_void.base().policy(), entt::any_policy::empty);
ASSERT_EQ(as_is_copy.base().policy(), entt::any_policy::embedded);
ASSERT_EQ(as_is_cref.base().policy(), entt::any_policy::cref);
ASSERT_EQ(as_is_ref.base().policy(), entt::any_policy::ref);
ASSERT_EQ(as_value.base().policy(), entt::any_policy::embedded);
ASSERT_NE(as_is.try_cast<int>(), nullptr);
ASSERT_NE(as_ref.try_cast<int>(), nullptr);
ASSERT_EQ(as_cref.try_cast<int>(), nullptr);
ASSERT_NE(as_cref.try_cast<const int>(), nullptr);
ASSERT_NE(as_ref.try_cast<int>(), nullptr);
ASSERT_NE(as_is_copy.try_cast<int>(), nullptr);
ASSERT_EQ(as_is_cref.try_cast<int>(), nullptr);
ASSERT_NE(as_is_ref.try_cast<int>(), nullptr);
ASSERT_NE(as_value.try_cast<int>(), nullptr);
ASSERT_EQ(as_is.cast<int>(), 2);
ASSERT_EQ(as_ref.cast<int>(), 2);
ASSERT_EQ(as_cref.cast<int>(), 2);
ASSERT_EQ(as_ref.cast<int>(), 2);
ASSERT_EQ(as_is_copy.cast<int>(), 2);
ASSERT_EQ(as_is_cref.cast<int>(), 2);
ASSERT_EQ(as_is_ref.cast<int>(), 2);
ASSERT_EQ(as_value.cast<int>(), 2);
}
TEST_F(MetaUtility, MetaDispatchMetaAny) {
@@ -162,30 +182,30 @@ TEST_F(MetaUtility, MetaGetter) {
clazz instance{};
ASSERT_FALSE((entt::meta_getter<clazz, &clazz::static_getter>(invalid)));
ASSERT_EQ((entt::meta_getter<clazz, &clazz::static_getter>(entt::meta_any{}.context(), instance)).cast<int>(), 0);
ASSERT_EQ((entt::meta_getter<clazz, &clazz::static_getter>(instance)).cast<int>(), 0);
ASSERT_FALSE((entt::meta_getter<clazz, &clazz::getter>(invalid)));
ASSERT_EQ((entt::meta_getter<clazz, &clazz::getter>(entt::meta_any{}.context(), instance)).cast<int>(), 0);
ASSERT_EQ((entt::meta_getter<clazz, &clazz::getter>(instance)).cast<int>(), 0);
ASSERT_FALSE((entt::meta_getter<clazz, &clazz::member>(invalid)));
ASSERT_EQ((entt::meta_getter<clazz, &clazz::member>(entt::meta_any{}.context(), instance)).cast<int>(), 0);
ASSERT_EQ((entt::meta_getter<clazz, &clazz::member>(instance)).cast<int>(), 0);
ASSERT_EQ((entt::meta_getter<clazz, &clazz::member>(std::as_const(instance))).cast<int>(), 0);
ASSERT_FALSE((entt::meta_getter<clazz, &clazz::cmember>(invalid)));
ASSERT_EQ((entt::meta_getter<clazz, &clazz::cmember>(entt::meta_any{}.context(), instance)).cast<int>(), 0);
ASSERT_EQ((entt::meta_getter<clazz, &clazz::cmember>(instance)).cast<int>(), 0);
ASSERT_EQ((entt::meta_getter<clazz, &clazz::cmember>(std::as_const(instance))).cast<int>(), 0);
ASSERT_FALSE((entt::meta_getter<clazz, &clazz::arr>(invalid)));
ASSERT_FALSE((entt::meta_getter<clazz, &clazz::arr>(entt::meta_any{}.context(), instance)));
ASSERT_FALSE((entt::meta_getter<clazz, &clazz::arr>(instance)));
ASSERT_EQ((entt::meta_getter<clazz, &clazz::value>(invalid)).cast<int>(), 0);
ASSERT_EQ((entt::meta_getter<clazz, &clazz::value>(entt::meta_any{}.context(), instance)).cast<int>(), 0);
ASSERT_EQ((entt::meta_getter<clazz, &clazz::value>(instance)).cast<int>(), 0);
ASSERT_EQ((entt::meta_getter<clazz, &clazz::cvalue>(invalid)).cast<int>(), 0);
ASSERT_EQ((entt::meta_getter<clazz, &clazz::cvalue>(entt::meta_any{}.context(), instance)).cast<int>(), 0);
ASSERT_EQ((entt::meta_getter<clazz, &clazz::cvalue>(instance)).cast<int>(), 0);
ASSERT_EQ((entt::meta_getter<clazz, 1>(invalid)).cast<int>(), 1);
ASSERT_EQ((entt::meta_getter<clazz, 1>(entt::meta_any{}.context(), instance)).cast<int>(), 1);
ASSERT_EQ((entt::meta_getter<clazz, 1>(instance)).cast<int>(), 1);
}
TEST_F(MetaUtility, MetaInvokeWithCandidate) {
@@ -194,22 +214,22 @@ TEST_F(MetaUtility, MetaInvokeWithCandidate) {
clazz::value = 3;
ASSERT_FALSE((entt::meta_invoke<clazz>({}, &clazz::setter, std::next(args.data()))));
ASSERT_FALSE((entt::meta_invoke<clazz>(entt::meta_any{}.context(), {}, &clazz::getter, nullptr)));
ASSERT_FALSE((entt::meta_invoke<clazz>({}, &clazz::getter, nullptr)));
ASSERT_TRUE((entt::meta_invoke<clazz>(args[0u], &clazz::setter, std::next(args.data()))));
ASSERT_FALSE((entt::meta_invoke<clazz>(entt::meta_any{}.context(), args[0u], &clazz::setter, args.data())));
ASSERT_FALSE((entt::meta_invoke<clazz>(args[0u], &clazz::setter, args.data())));
ASSERT_EQ((entt::meta_invoke<clazz>(args[0u], &clazz::getter, nullptr)).cast<int>(), 4);
ASSERT_FALSE((entt::meta_invoke<clazz>(entt::meta_any{}.context(), args[1u], &clazz::getter, nullptr)));
ASSERT_FALSE((entt::meta_invoke<clazz>(args[1u], &clazz::getter, nullptr)));
ASSERT_EQ((entt::meta_invoke<clazz>({}, &clazz::get_value, nullptr)).cast<int>(), 3);
ASSERT_TRUE((entt::meta_invoke<clazz>(entt::meta_any{}.context(), {}, &clazz::reset_value, nullptr)));
ASSERT_TRUE((entt::meta_invoke<clazz>({}, &clazz::reset_value, nullptr)));
ASSERT_EQ(args[0u].cast<clazz &>().value, 0);
const auto setter = [](int &value) { value = 3; };
const auto getter = [](int value) { return value * 2; };
ASSERT_TRUE(entt::meta_invoke<test::empty>({}, setter, std::next(args.data())));
ASSERT_EQ(entt::meta_invoke<test::empty>(entt::meta_any{}.context(), {}, getter, std::next(args.data())).cast<int>(), 6);
ASSERT_EQ(entt::meta_invoke<test::empty>({}, getter, std::next(args.data())).cast<int>(), 6);
}
TEST_F(MetaUtility, MetaInvoke) {
@@ -218,15 +238,15 @@ TEST_F(MetaUtility, MetaInvoke) {
clazz::value = 3;
ASSERT_FALSE((entt::meta_invoke<clazz, &clazz::setter>({}, std::next(args.data()))));
ASSERT_FALSE((entt::meta_invoke<clazz, &clazz::getter>(entt::meta_any{}.context(), {}, nullptr)));
ASSERT_FALSE((entt::meta_invoke<clazz, &clazz::getter>({}, nullptr)));
ASSERT_TRUE((entt::meta_invoke<clazz, &clazz::setter>(args[0u], std::next(args.data()))));
ASSERT_FALSE((entt::meta_invoke<clazz, &clazz::setter>(entt::meta_any{}.context(), args[0u], args.data())));
ASSERT_FALSE((entt::meta_invoke<clazz, &clazz::setter>(args[0u], args.data())));
ASSERT_EQ((entt::meta_invoke<clazz, &clazz::getter>(args[0u], nullptr)).cast<int>(), 4);
ASSERT_FALSE((entt::meta_invoke<clazz, &clazz::getter>(entt::meta_any{}.context(), args[1u], nullptr)));
ASSERT_FALSE((entt::meta_invoke<clazz, &clazz::getter>(args[1u], nullptr)));
ASSERT_EQ((entt::meta_invoke<clazz, &clazz::get_value>({}, nullptr)).cast<int>(), 3);
ASSERT_TRUE((entt::meta_invoke<clazz, &clazz::reset_value>(entt::meta_any{}.context(), {}, nullptr)));
ASSERT_TRUE((entt::meta_invoke<clazz, &clazz::reset_value>({}, nullptr)));
ASSERT_EQ(args[0u].cast<clazz &>().value, 0);
}
+5 -13
View File
@@ -236,9 +236,9 @@ TYPED_TEST(Poly, Functionalities) {
ASSERT_TRUE(alias);
ASSERT_TRUE(value);
ASSERT_EQ(empty.type(), entt::type_id<void>());
ASSERT_EQ(empty.info(), entt::type_id<void>());
ASSERT_EQ(in_place.type(), entt::type_id<impl>());
ASSERT_EQ(alias.type(), entt::type_id<impl>());
ASSERT_EQ(alias.info(), entt::type_id<impl>());
ASSERT_EQ(value.type(), entt::type_id<impl>());
ASSERT_EQ(alias.data(), &instance);
@@ -251,7 +251,7 @@ TYPED_TEST(Poly, Functionalities) {
ASSERT_TRUE(empty);
ASSERT_NE(empty.data(), nullptr);
ASSERT_NE(std::as_const(empty).data(), nullptr);
ASSERT_EQ(empty.type(), entt::type_id<impl>());
ASSERT_EQ(empty.info(), entt::type_id<impl>());
ASSERT_EQ(empty->get(), 0);
empty.template emplace<impl>(3);
@@ -265,7 +265,7 @@ TYPED_TEST(Poly, Functionalities) {
ASSERT_NE(ref.data(), nullptr);
ASSERT_EQ(ref.data(), in_place.data());
ASSERT_EQ(std::as_const(ref).data(), std::as_const(in_place).data());
ASSERT_EQ(ref.type(), entt::type_id<impl>());
ASSERT_EQ(ref.info(), entt::type_id<impl>());
ASSERT_EQ(ref->get(), 3);
poly_type null{};
@@ -288,7 +288,7 @@ TYPED_TEST(Poly, Functionalities) {
move.reset();
ASSERT_FALSE(move);
ASSERT_EQ(move.type(), entt::type_id<void>());
ASSERT_EQ(move.info(), entt::type_id<void>());
}
TYPED_TEST(Poly, Owned) {
@@ -436,17 +436,13 @@ TYPED_TEST(Poly, SboAlignment) {
std::array<poly_type, 2u> sbo = {over_aligned{}, over_aligned{}};
const auto *data = sbo[0].data();
// NOLINTBEGIN(*-reinterpret-cast)
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(sbo[0u].data()) % alignment) == 0u);
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(sbo[1u].data()) % alignment) == 0u);
// NOLINTEND(*-reinterpret-cast)
std::swap(sbo[0], sbo[1]);
// NOLINTBEGIN(*-reinterpret-cast)
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(sbo[0u].data()) % alignment) == 0u);
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(sbo[1u].data()) % alignment) == 0u);
// NOLINTEND(*-reinterpret-cast)
ASSERT_NE(data, sbo[1].data());
}
@@ -458,17 +454,13 @@ TYPED_TEST(Poly, NoSboAlignment) {
std::array<poly_type, 2u> nosbo = {over_aligned{}, over_aligned{}};
const auto *data = nosbo[0].data();
// NOLINTBEGIN(*-reinterpret-cast)
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(nosbo[0u].data()) % alignment) == 0u);
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(nosbo[1u].data()) % alignment) == 0u);
// NOLINTEND(*-reinterpret-cast)
std::swap(nosbo[0], nosbo[1]);
// NOLINTBEGIN(*-reinterpret-cast)
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(nosbo[0u].data()) % alignment) == 0u);
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(nosbo[1u].data()) % alignment) == 0u);
// NOLINTEND(*-reinterpret-cast)
ASSERT_EQ(data, nosbo[1].data());
}
+172 -111
View File
@@ -1,46 +1,26 @@
#include <cstdint>
#include <memory>
#include <gtest/gtest.h>
#include <entt/process/process.hpp>
#include "../../common/empty.h"
template<typename Delta>
struct fake_process: entt::process<fake_process<Delta>, Delta> {
using process_type = entt::process<fake_process<Delta>, Delta>;
using delta_type = typename process_type::delta_type;
class test_process: public entt::basic_process<Delta> {
using entt::basic_process<Delta>::basic_process;
void succeed() noexcept {
process_type::succeed();
}
void fail() noexcept {
process_type::fail();
}
void pause() noexcept {
process_type::pause();
}
void unpause() noexcept {
process_type::unpause();
}
void init() {
init_invoked = true;
}
void succeeded() {
void succeeded() override {
succeeded_invoked = true;
}
void failed() {
void failed() override {
failed_invoked = true;
}
void aborted() {
void aborted() override {
aborted_invoked = true;
}
void update(typename entt::process<fake_process<Delta>, Delta>::delta_type, void *data) {
void update(const Delta, void *data) override {
if(data != nullptr) {
(*static_cast<int *>(data))++;
}
@@ -48,15 +28,29 @@ struct fake_process: entt::process<fake_process<Delta>, Delta> {
update_invoked = true;
}
bool init_invoked{};
public:
bool update_invoked{};
bool succeeded_invoked{};
bool failed_invoked{};
bool aborted_invoked{};
};
class test_no_update_process: public entt::process {
void aborted() override {
aborted_invoked = true;
}
public:
bool aborted_invoked{};
};
class test_plain_process: public entt::process {
using delta_type = typename entt::process::delta_type;
void update(const delta_type, void *) override {}
};
TEST(Process, Basics) {
fake_process<int> process{};
test_process<int> process{};
ASSERT_FALSE(process.alive());
ASSERT_FALSE(process.finished());
@@ -110,8 +104,32 @@ TEST(Process, Basics) {
ASSERT_TRUE(process.rejected());
}
TEST(Process, Succeeded) {
fake_process<test::empty> process{};
TEST(Process, SucceedNoOverride) {
test_plain_process process{};
ASSERT_FALSE(process.alive());
process.tick(0u);
ASSERT_TRUE(process.alive());
ASSERT_FALSE(process.finished());
ASSERT_FALSE(process.rejected());
process.succeed();
ASSERT_FALSE(process.alive());
ASSERT_FALSE(process.finished());
ASSERT_FALSE(process.rejected());
process.tick(0u);
ASSERT_FALSE(process.alive());
ASSERT_TRUE(process.finished());
ASSERT_FALSE(process.rejected());
}
TEST(Process, Succeed) {
test_process<test::empty> process{};
process.tick({});
process.tick({});
@@ -123,15 +141,38 @@ TEST(Process, Succeeded) {
ASSERT_FALSE(process.paused());
ASSERT_FALSE(process.rejected());
ASSERT_TRUE(process.init_invoked);
ASSERT_TRUE(process.update_invoked);
ASSERT_TRUE(process.succeeded_invoked);
ASSERT_FALSE(process.failed_invoked);
ASSERT_FALSE(process.aborted_invoked);
}
TEST(Process, FailNoOverride) {
test_plain_process process{};
ASSERT_FALSE(process.alive());
process.tick(0u);
ASSERT_TRUE(process.alive());
ASSERT_FALSE(process.finished());
ASSERT_FALSE(process.rejected());
process.fail();
ASSERT_FALSE(process.alive());
ASSERT_FALSE(process.finished());
ASSERT_FALSE(process.rejected());
process.tick(0u);
ASSERT_FALSE(process.alive());
ASSERT_FALSE(process.finished());
ASSERT_TRUE(process.rejected());
}
TEST(Process, Fail) {
fake_process<int> process{};
test_process<int> process{};
process.tick(0);
process.tick(0);
@@ -143,15 +184,88 @@ TEST(Process, Fail) {
ASSERT_FALSE(process.paused());
ASSERT_TRUE(process.rejected());
ASSERT_TRUE(process.init_invoked);
ASSERT_TRUE(process.update_invoked);
ASSERT_FALSE(process.succeeded_invoked);
ASSERT_TRUE(process.failed_invoked);
ASSERT_FALSE(process.aborted_invoked);
}
TEST(Process, AbortNoOverride) {
test_plain_process process{};
ASSERT_FALSE(process.alive());
process.tick(0u);
ASSERT_TRUE(process.alive());
ASSERT_FALSE(process.finished());
ASSERT_FALSE(process.rejected());
process.abort();
ASSERT_FALSE(process.alive());
ASSERT_FALSE(process.finished());
ASSERT_FALSE(process.rejected());
process.tick(0u);
ASSERT_FALSE(process.alive());
ASSERT_FALSE(process.finished());
ASSERT_TRUE(process.rejected());
}
TEST(Process, NoUpdateAbort) {
test_no_update_process process{};
ASSERT_FALSE(process.alive());
ASSERT_FALSE(process.rejected());
ASSERT_FALSE(process.aborted_invoked);
process.tick(0u);
ASSERT_FALSE(process.alive());
ASSERT_TRUE(process.rejected());
ASSERT_TRUE(process.aborted_invoked);
}
TEST(Process, AbortNextTick) {
test_process<int> process{};
process.tick(0);
process.abort();
process.tick(0);
ASSERT_FALSE(process.alive());
ASSERT_FALSE(process.finished());
ASSERT_FALSE(process.paused());
ASSERT_TRUE(process.rejected());
ASSERT_TRUE(process.update_invoked);
ASSERT_FALSE(process.succeeded_invoked);
ASSERT_FALSE(process.failed_invoked);
ASSERT_TRUE(process.aborted_invoked);
}
TEST(Process, AbortImmediately) {
test_process<test::empty> process{};
process.tick({});
process.abort();
process.tick({});
ASSERT_FALSE(process.alive());
ASSERT_FALSE(process.finished());
ASSERT_FALSE(process.paused());
ASSERT_TRUE(process.rejected());
ASSERT_TRUE(process.update_invoked);
ASSERT_FALSE(process.succeeded_invoked);
ASSERT_FALSE(process.failed_invoked);
ASSERT_TRUE(process.aborted_invoked);
}
TEST(Process, Data) {
fake_process<test::empty> process{};
test_process<test::empty> process{};
int value = 0;
process.tick({});
@@ -165,97 +279,44 @@ TEST(Process, Data) {
ASSERT_FALSE(process.rejected());
ASSERT_EQ(value, 1);
ASSERT_TRUE(process.init_invoked);
ASSERT_TRUE(process.update_invoked);
ASSERT_TRUE(process.succeeded_invoked);
ASSERT_FALSE(process.failed_invoked);
ASSERT_FALSE(process.aborted_invoked);
}
TEST(Process, AbortNextTick) {
fake_process<int> process{};
TEST(Process, ThenPeek) {
test_process<int> process{};
process.tick(0);
process.abort();
process.tick(0);
ASSERT_FALSE(process.peek());
ASSERT_FALSE(process.alive());
ASSERT_FALSE(process.finished());
ASSERT_FALSE(process.paused());
ASSERT_TRUE(process.rejected());
process.then<test_process<int>>().then<test_process<int>>();
ASSERT_TRUE(process.init_invoked);
ASSERT_FALSE(process.update_invoked);
ASSERT_FALSE(process.succeeded_invoked);
ASSERT_FALSE(process.failed_invoked);
ASSERT_TRUE(process.aborted_invoked);
ASSERT_TRUE(process.peek());
ASSERT_TRUE(process.peek()->peek());
ASSERT_FALSE(process.peek()->peek()->peek());
// peek does not release ownership
ASSERT_TRUE(process.peek());
}
TEST(Process, AbortImmediately) {
fake_process<test::empty> process{};
TEST(Process, Handle) {
auto process = std::make_shared<test_process<int>>();
auto handle = process->shared_from_this();
process.tick({});
process.abort(true);
ASSERT_FALSE(process.alive());
ASSERT_FALSE(process.finished());
ASSERT_FALSE(process.paused());
ASSERT_TRUE(process.rejected());
ASSERT_TRUE(process.init_invoked);
ASSERT_FALSE(process.update_invoked);
ASSERT_FALSE(process.succeeded_invoked);
ASSERT_FALSE(process.failed_invoked);
ASSERT_TRUE(process.aborted_invoked);
ASSERT_TRUE(handle);
ASSERT_EQ(process.get(), handle.get());
}
TEST(ProcessAdaptor, Resolved) {
bool updated = false;
auto lambda = [&updated](std::uint64_t, void *, auto resolve, auto) {
ASSERT_FALSE(updated);
updated = true;
resolve();
};
TEST(Process, CustomAllocator) {
const std::allocator<void> allocator{};
entt::process process{allocator};
auto process = entt::process_adaptor<decltype(lambda), std::uint64_t>{lambda};
ASSERT_EQ(process.get_allocator(), allocator);
ASSERT_FALSE(process.get_allocator() != allocator);
process.tick(0);
process.tick(0);
const entt::process &other = process.then([](entt::process &, std::uint32_t, void *) {});
ASSERT_TRUE(process.finished());
ASSERT_TRUE(updated);
}
TEST(ProcessAdaptor, Rejected) {
bool updated = false;
auto lambda = [&updated](std::uint64_t, void *, auto, auto rejected) {
ASSERT_FALSE(updated);
updated = true;
rejected();
};
auto process = entt::process_adaptor<decltype(lambda), std::uint64_t>{lambda};
process.tick(0);
process.tick(0);
ASSERT_TRUE(process.rejected());
ASSERT_TRUE(updated);
}
TEST(ProcessAdaptor, Data) {
int value = 0;
auto lambda = [](std::uint64_t, void *data, auto resolve, auto) {
*static_cast<int *>(data) = 2;
resolve();
};
auto process = entt::process_adaptor<decltype(lambda), std::uint64_t>{lambda};
process.tick(0);
process.tick(0, &value);
ASSERT_TRUE(process.finished());
ASSERT_EQ(value, 2);
ASSERT_NE(&process, &other);
ASSERT_EQ(other.get_allocator(), allocator);
ASSERT_FALSE(other.get_allocator() != allocator);
}
+65 -40
View File
@@ -1,3 +1,4 @@
#include <cstdint>
#include <functional>
#include <memory>
#include <utility>
@@ -5,34 +6,46 @@
#include <entt/process/process.hpp>
#include <entt/process/scheduler.hpp>
struct foo_process: entt::process<foo_process, entt::scheduler::delta_type> {
foo_process(std::function<void()> upd, std::function<void()> abort)
: on_update{std::move(upd)}, on_aborted{std::move(abort)} {}
void update(delta_type, void *) const {
class foo_process: public entt::process {
void update(const delta_type, void *) override {
on_update();
}
void aborted() const {
void aborted() override {
on_aborted();
}
public:
using allocator_type = typename entt::process::allocator_type;
foo_process(const allocator_type &allocator, std::function<void()> upd, std::function<void()> abort)
: entt::process{allocator},
on_update{std::move(upd)},
on_aborted{std::move(abort)} {}
private:
std::function<void()> on_update;
std::function<void()> on_aborted;
};
struct succeeded_process: entt::process<succeeded_process, entt::scheduler::delta_type> {
void update(delta_type, void *data) {
class succeeded_process: public entt::process {
void update(const delta_type, void *data) override {
++static_cast<std::pair<int, int> *>(data)->first;
succeed();
}
public:
using entt::process::process;
};
struct failed_process: entt::process<failed_process, entt::scheduler::delta_type> {
void update(delta_type, void *data) {
class failed_process: public entt::process {
void update(const delta_type, void *data) override {
++static_cast<std::pair<int, int> *>(data)->second;
fail();
}
public:
using entt::process::process;
};
TEST(Scheduler, Functionalities) {
@@ -47,9 +60,7 @@ TEST(Scheduler, Functionalities) {
ASSERT_EQ(scheduler.size(), 0u);
ASSERT_TRUE(scheduler.empty());
scheduler.attach<foo_process>(
[&updated]() { updated = true; },
[&aborted]() { aborted = true; });
scheduler.attach<foo_process>([&updated]() { updated = true; }, [&aborted]() { aborted = true; });
ASSERT_NE(scheduler.size(), 0u);
ASSERT_FALSE(scheduler.empty());
@@ -74,7 +85,7 @@ TEST(Scheduler, Swap) {
entt::scheduler other{};
int counter{};
scheduler.attach([&counter](auto &&...) { ++counter; });
scheduler.attach([&counter](entt::process &, std::uint32_t, void *) { ++counter; });
ASSERT_EQ(scheduler.size(), 1u);
ASSERT_EQ(other.size(), 0u);
@@ -96,22 +107,37 @@ TEST(Scheduler, Swap) {
ASSERT_EQ(counter, 2);
}
TEST(Scheduler, Then) {
TEST(Scheduler, SharedFromThis) {
entt::scheduler scheduler{};
auto &process = scheduler.attach<succeeded_process>();
const auto &then = process.then<failed_process>();
auto other = process.shared_from_this();
ASSERT_TRUE(other);
ASSERT_NE(&process, &then);
ASSERT_EQ(&process, other.get());
ASSERT_EQ(process.get_allocator(), scheduler.get_allocator());
ASSERT_EQ(process.get_allocator(), other->get_allocator());
ASSERT_EQ(then.get_allocator(), scheduler.get_allocator());
}
TEST(Scheduler, AttachThen) {
entt::scheduler scheduler{};
std::pair<int, int> counter{};
scheduler
// failing process with successor
.attach<succeeded_process>()
// failing process with successor
scheduler.attach<succeeded_process>()
.then<succeeded_process>()
.then<failed_process>()
.then<succeeded_process>();
// failing process without successor
scheduler.attach<succeeded_process>()
.then<succeeded_process>()
// failing process without successor
.attach<succeeded_process>()
.then<succeeded_process>()
.then<failed_process>()
// non-failing process
.attach<succeeded_process>()
.then<failed_process>();
// non-failing process
scheduler.attach<succeeded_process>()
.then<succeeded_process>();
while(!scheduler.empty()) {
@@ -128,19 +154,18 @@ TEST(Scheduler, Functor) {
bool first_functor = false;
bool second_functor = false;
auto attach = [&first_functor](auto, void *, auto resolve, auto) {
ASSERT_FALSE(first_functor);
first_functor = true;
resolve();
};
auto then = [&second_functor](auto, void *, auto, auto reject) {
ASSERT_FALSE(second_functor);
second_functor = true;
reject();
};
scheduler.attach(std::move(attach)).then(std::move(then)).then([](auto...) { FAIL(); });
scheduler
.attach([&first_functor](entt::process &proc, std::uint32_t, void *) {
ASSERT_FALSE(first_functor);
first_functor = true;
proc.succeed();
})
.then([&second_functor](entt::process &proc, std::uint32_t, void *) {
ASSERT_FALSE(second_functor);
second_functor = true;
proc.fail();
})
.then([](entt::process &, std::uint32_t, void *) { FAIL(); });
while(!scheduler.empty()) {
scheduler.update(0);
@@ -155,9 +180,9 @@ TEST(Scheduler, SpawningProcess) {
entt::scheduler scheduler{};
std::pair<int, int> counter{};
scheduler.attach([&scheduler](auto, void *, auto resolve, auto) {
scheduler.attach([&scheduler](entt::process &proc, std::uint32_t, void *) {
scheduler.attach<succeeded_process>().then<failed_process>();
resolve();
proc.succeed();
});
while(!scheduler.empty()) {
@@ -175,7 +200,7 @@ TEST(Scheduler, CustomAllocator) {
ASSERT_EQ(scheduler.get_allocator(), allocator);
ASSERT_FALSE(scheduler.get_allocator() != allocator);
scheduler.attach([](auto &&...) {});
scheduler.attach([](entt::process &, std::uint32_t, void *) {});
const decltype(scheduler) other{std::move(scheduler), allocator};
ASSERT_EQ(other.size(), 1u);

Some files were not shown because too many files have changed in this diff Show More