Compare commits

...

545 Commits

Author SHA1 Message Date
skypjack
5c6ed1a7c0 test: prepare stl_ext files with the right includes 2026-05-01 15:44:49 +02:00
skypjack
bd689292e9 test: setup stl_ext tests 2026-05-01 15:41:48 +02:00
skypjack
60ada2efb7 test: internal changes 2026-05-01 15:39:35 +02:00
skypjack
bcbd39db35 test: cleanup 2026-05-01 15:34:58 +02:00
skypjack
4bfd609f69 test: prepare for stl injection tests 2026-05-01 15:15:07 +02:00
skypjack
8e313cf099 updated TODO 2026-05-01 15:07:01 +02:00
skypjack
c37cc47dc8 compressed_pair: internal changes 2026-04-30 12:13:25 +02:00
skypjack
8c2cbe88e5 stl: fix the last things with guarded specializations that are std:: only 2026-04-30 12:11:16 +02:00
skypjack
2d69562088 stl: cleanup 2026-04-29 17:20:48 +02:00
skypjack
74947434d7 stl: cleanup 2026-04-29 13:33:16 +02:00
skypjack
5fa956395a stl: drop version.hpp - some things do not fit custom implementations, that's all 2026-04-29 13:25:51 +02:00
skypjack
c11e6be645 test: cleanup 2026-04-29 11:10:39 +02:00
skypjack
a931a83870 stl: drop ranges.hpp - some things do not fit custom implementations, that's all 2026-04-29 11:10:29 +02:00
skypjack
4c47abaca7 stl: cannot specialize variables across namespaces 2026-04-28 16:17:26 +02:00
skypjack
7d527e2633 stl: undef internal macros 2026-04-28 15:17:26 +02:00
skypjack
938be3d9c5 stl: get rid of ENTT_HAS_RANGES 2026-04-28 15:08:46 +02:00
skypjack
377dde3e24 stl: drop ENTT_HAS_VERSION 2026-04-28 15:04:37 +02:00
skypjack
a0c7b53e67 stl: std::hash 2026-04-27 08:26:17 +02:00
skypjack
165c6df6a2 stl: <ranges> & co. 2026-04-24 15:22:55 +02:00
skypjack
9055a66364 stl: std::swap 2026-04-24 15:22:37 +02:00
skypjack
625622c8ad flow: cleanup 2026-04-24 11:35:09 +02:00
skypjack
0a62b17fce stl: std::uses_allocator_v 2026-04-24 09:11:39 +02:00
skypjack
7a42ec61b3 stl: std::stringstream 2026-04-24 09:09:12 +02:00
skypjack
682184ba08 stl: std::boolalpha 2026-04-24 09:08:28 +02:00
skypjack
dda9428140 stl: <ios> 2026-04-24 09:07:23 +02:00
skypjack
e9bbcb6cea stl: <sstream> 2026-04-24 09:05:12 +02:00
skypjack
0c3db25cf4 stl: std::ostream 2026-04-22 10:16:35 +02:00
skypjack
04b9bcc563 stl: added <ostream> 2026-04-21 17:25:52 +02:00
skypjack
18f8a103a8 stl: std::pointer_traits 2026-04-21 15:04:53 +02:00
skypjack
576baa5c57 std: stl::destroy 2026-04-21 14:59:49 +02:00
skypjack
514521888c stl: std::default_delete 2026-04-21 14:58:45 +02:00
skypjack
f0a306aa6f stl: std::integral 2026-04-21 08:18:27 +02:00
skypjack
749411c1a9 stl: std::enable_shared_from_this 2026-04-21 08:17:04 +02:00
skypjack
de04de17b9 stl: std::less 2026-04-21 08:15:17 +02:00
skypjack
4104c7db7b doc: minor changes 2026-04-20 18:40:44 +02:00
skypjack
490bf05f3e stl: stl::nullptr_t 2026-04-20 18:40:33 +02:00
skypjack
c0c5b81993 stl: std::uninitialized_fill 2026-04-20 18:35:58 +02:00
skypjack
18477eb65b stl: std::advance 2026-04-20 18:33:30 +02:00
skypjack
8a1940c0fa stl: std::allocate_shared 2026-04-20 18:31:05 +02:00
skypjack
ea6b70f263 stl: std::invoke 2026-04-20 16:46:50 +02:00
skypjack
780da3c78b stl: std::find_if 2026-04-20 16:44:19 +02:00
skypjack
882cbd2251 stl: std::any_of 2026-04-20 16:42:27 +02:00
skypjack
2975d14352 stl: std::all_of 2026-04-20 15:45:24 +02:00
skypjack
b88c1903a0 stl: std::none_of 2026-04-20 15:44:47 +02:00
skypjack
f7bf2d1245 stl: std::byte 2026-04-20 15:43:22 +02:00
skypjack
200f35130f stl: std::ceil 2026-04-20 15:42:17 +02:00
skypjack
793d4a9738 stl: std::popcount 2026-04-17 11:29:10 +02:00
skypjack
adff45e6a3 stl: std::default_initializable 2026-04-17 11:27:11 +02:00
skypjack
7d5b8c9a0e stl: std::has_single_bit 2026-04-17 11:24:00 +02:00
skypjack
0a1b4f9adc stl: std::unsigned_integral 2026-04-17 10:14:45 +02:00
skypjack
c6b343ae7d stl: std::invocable 2026-04-17 10:11:26 +02:00
skypjack
b451c43058 stl: std::make_shared 2026-04-17 09:15:13 +02:00
skypjack
750b450cd2 stl: std::derived_from 2026-04-17 09:13:18 +02:00
skypjack
080966ad8f doc: minor changes 2026-04-17 09:12:27 +02:00
skypjack
b5cd97f915 stl: std::constructible_from 2026-04-17 09:11:48 +02:00
skypjack
398a8c70a5 stl: std::same_as 2026-04-17 09:10:46 +02:00
skypjack
0ebf92f015 stl: concepts.hpp 2026-04-17 09:09:46 +02:00
skypjack
92a03e184d stl: std::static_pointer_cast 2026-04-16 15:40:18 +02:00
skypjack
be026136db stl: std::addressof 2026-04-16 15:38:50 +02:00
skypjack
1dff52db92 stl: std::is_member_function_pointer_v 2026-04-16 11:35:49 +02:00
skypjack
685d6c643f stl: std::allocator 2026-04-16 11:34:21 +02:00
skypjack
20c21bbfd6 stl: std::equal_to 2026-04-16 11:08:54 +02:00
skypjack
431556c069 stl: replace <functional> everywhere 2026-04-16 11:01:08 +02:00
skypjack
3b9304480a stl: refine functional.hpp + std::function 2026-04-16 10:58:25 +02:00
skypjack
fee356c7f9 stl: std::is_base_of_v 2026-04-15 14:30:57 +02:00
skypjack
d700f800aa stl: std::is_class_v 2026-04-15 14:28:46 +02:00
skypjack
e27826abc5 stl: std::is_signed_v 2026-04-15 14:27:53 +02:00
skypjack
2f7fc36e9e stl: std::is_integral_v 2026-04-15 14:27:22 +02:00
skypjack
d4cfc844a9 stl: std::is_arithmetic_v 2026-04-15 14:26:09 +02:00
skypjack
75f95b367c doc: minor changes 2026-04-15 14:23:42 +02:00
skypjack
64a71a4e8d stl: std::allocator_arg[_t] 2026-04-15 14:22:26 +02:00
skypjack
5623d2f9dc stl: std::allocator_traits 2026-04-15 14:20:49 +02:00
skypjack
a039eed54e stl: std::shared_ptr 2026-04-15 09:23:31 +02:00
skypjack
ddeea943f2 stl: std::unique_ptr 2026-04-15 09:21:56 +02:00
skypjack
6b7513eb1a stl: std::make_unique 2026-04-15 09:20:39 +02:00
skypjack
d200d8b3dc stl: prepare to move all <memory> stuff 2026-04-15 09:19:17 +02:00
skypjack
2b09786326 stl: version.hpp and ENTT_HAS_VERSION macro 2026-04-15 09:15:30 +02:00
skypjack
8ed97c2d98 stl: move only to memory.hpp 2026-04-14 14:12:05 +02:00
skypjack
04dda74792 stl: std::is_move_constructible_v 2026-04-14 14:07:41 +02:00
skypjack
71f3780ba7 stl: missed std::make_from_tuple 2026-04-14 14:06:38 +02:00
skypjack
3281239bed stl: std::get 2026-04-14 14:04:55 +02:00
skypjack
a5c0595896 stl: add string_view.hpp and replace std::string_view 2026-04-14 08:38:52 +02:00
skypjack
dfb94864db stl: add string.hpp and replace std::string 2026-04-14 08:35:42 +02:00
skypjack
879a7a301a stl: include cmath.hpp 2026-04-13 09:24:42 +02:00
skypjack
dcf5f8fdcc stl: std::bit_ceil 2026-04-13 09:09:36 +02:00
skypjack
43dcf712b7 stl: include bit.hpp 2026-04-13 09:08:27 +02:00
skypjack
94898f6083 stl: std::numeric_limits 2026-04-13 09:05:36 +02:00
skypjack
7674036b67 stl: include limits.hpp 2026-04-13 08:50:35 +02:00
skypjack
e2418206da stl: std::is_reference_v 2026-04-10 16:09:19 +02:00
skypjack
c2db759653 stl: std::is_member_pointer_v 2026-04-10 12:03:03 +02:00
skypjack
f16ff7071b stl: std::make_index_sequence 2026-04-10 12:02:21 +02:00
skypjack
402f040f16 stl: std::index_sequence 2026-04-10 12:00:30 +02:00
skypjack
9a5ad4235d updated TODO 2026-04-10 11:58:19 +02:00
skypjack
3bffa25af2 stl: std::ptrdiff_t 2026-04-10 11:13:01 +02:00
skypjack
80ad8de444 stl: std::index_sequence_for 2026-04-10 10:15:57 +02:00
skypjack
5f6b0c2fa1 stl: std::integral_constant 2026-04-10 10:13:51 +02:00
skypjack
e929304ed4 stl: std::uint8/16/32/64_t 2026-04-10 10:12:16 +02:00
skypjack
6b9f69d0e5 stl: std::size_t 2026-04-10 10:05:59 +02:00
skypjack
5cc2397069 stl: add cstdint.hpp 2026-04-09 10:28:05 +02:00
skypjack
0cd14686dd stl: add cstddef.hpp 2026-04-09 10:22:44 +02:00
skypjack
b75a7191f8 stl: std::std::is_final_v 2026-04-08 09:50:09 +02:00
skypjack
a75a608d0c stl: std::is_empty_v 2026-04-08 09:49:42 +02:00
skypjack
2690c8af2b stl: std::in_place* 2026-04-08 09:48:29 +02:00
skypjack
61a2aaa0c9 stl: std::is_enum_v 2026-04-08 09:45:30 +02:00
skypjack
5d823e6853 stl: std::piecewise_construct[_t] 2026-04-08 09:45:04 +02:00
skypjack
0c5ca42180 stl: std::sort 2026-04-08 09:42:46 +02:00
skypjack
213ddb74d5 stl: add algorithm.hpp 2026-04-07 18:15:49 +02:00
skypjack
0d3cecbff1 stl: std::conditional_t 2026-04-07 11:38:36 +02:00
skypjack
4d91f8cc5a stl: std::is_convertible_v 2026-04-07 11:35:04 +02:00
skypjack
d596ba854f stl: std::common_type_t 2026-04-07 11:33:42 +02:00
skypjack
03299cedad stl: std::is_constructible_v 2026-04-07 11:31:49 +02:00
skypjack
68e8b36684 stl: std::is_nothrow_* 2026-04-07 11:23:21 +02:00
skypjack
9bd285bfa8 stl: std::is_invocable* 2026-04-07 11:19:44 +02:00
skypjack
2d4324d7cb stl: std::is_nothrow_constructible_v 2026-04-07 09:13:29 +02:00
skypjack
61ecf3906d stl: std::extent_v 2026-04-07 09:11:54 +02:00
skypjack
9f0d0d9aeb stl: std::array 2026-04-02 17:29:23 +02:00
skypjack
a8fe00242a stl: array header 2026-04-02 17:27:53 +02:00
skypjack
486f02dcb0 enum: fixed stl scope 2026-04-02 10:10:31 +02:00
skypjack
c60e076f80 stl: std::underlying_type_t 2026-04-02 10:09:36 +02:00
skypjack
8f411924b4 stl: std::bool_constant 2026-04-02 10:07:58 +02:00
skypjack
15f4e28205 stl: std::is_array_v 2026-04-02 10:03:36 +02:00
skypjack
4ac884dfd1 stl: std::is_copy_constructible_v 2026-04-02 10:02:38 +02:00
skypjack
ed026bbc7e stl: std::is_function_v 2026-04-02 10:02:05 +02:00
skypjack
10bfb24bf1 stl: std::is_move_assignable_v 2026-04-02 10:00:44 +02:00
skypjack
50346a4cf8 stl: std::is_copy_assignable_v 2026-04-02 10:00:09 +02:00
skypjack
69331f4796 stl: std::is_const_v 2026-04-02 09:58:39 +02:00
skypjack
573d982c1c stl: std::is_default_constructible_v 2026-04-02 09:44:56 +02:00
skypjack
257117ce8f stl: std::is_aggregate_v 2026-04-02 09:44:20 +02:00
skypjack
c3a52a4f27 stl: std::decay_t 2026-04-02 09:44:11 +02:00
skypjack
35435d3d82 stl: std::is_nothrow_move_constructible_v 2026-04-02 09:41:22 +02:00
skypjack
7a672f6a1e stl: std::remove_const_t 2026-04-02 09:41:10 +02:00
skypjack
cf7199e83e stl: std::is_trivially_destructible_v 2026-04-02 09:38:52 +02:00
skypjack
272b93c8fb stl: std::remove_reference_t 2026-04-02 09:38:41 +02:00
skypjack
9efe86621d stl: std::is_lvalue_reference_v 2026-04-02 09:34:38 +02:00
skypjack
86e2235b83 stl: std::is_pointer_v 2026-04-02 09:34:29 +02:00
skypjack
98604629c7 stl: std::is_void_v 2026-04-02 09:32:12 +02:00
skypjack
990eff8e73 stl: std::true_type/std::false_type 2026-04-02 09:32:02 +02:00
skypjack
1763f8b192 stl: std::invoke_result_t 2026-04-01 16:57:12 +02:00
skypjack
06cd683d31 stl: std::remove_pointer_t 2026-04-01 16:57:00 +02:00
skypjack
bfe84b59d0 stl: std::pair/std::make_pair 2026-04-01 16:50:07 +02:00
skypjack
80fdab4f21 stl: std::as_const 2026-04-01 16:49:39 +02:00
skypjack
b32ec7f656 stl: std::move 2026-04-01 09:34:50 +02:00
skypjack
9aeffebc7b stl: std::forward 2026-04-01 09:34:28 +02:00
skypjack
4f1897e864 stl: std::declval 2026-04-01 09:31:13 +02:00
skypjack
8f67d4fa06 stl: std::exchange 2026-04-01 09:30:47 +02:00
skypjack
8c8949a312 stl: introduce utility.hpp 2026-04-01 09:29:27 +02:00
skypjack
17953cb28a stl: moved some type traits here and there 2026-04-01 09:27:17 +02:00
skypjack
6054e22df2 stl: introduce type_traits.hpp 2026-04-01 09:20:25 +02:00
skypjack
f2d89c93c9 stl: cleanup 2026-03-31 10:32:42 +02:00
skypjack
8f3f5b99c1 stl: iterator_traits 2026-03-31 10:32:22 +02:00
skypjack
8396a8c884 stl: std::reverse_iterator 2026-03-31 08:57:07 +02:00
skypjack
fc9eb2a9f2 stl: std::distance 2026-03-31 08:56:56 +02:00
skypjack
be840ee569 stl: iterator tags 2026-03-31 08:54:09 +02:00
skypjack
fc7ca524f2 stl: more on iterator 2026-03-31 08:52:27 +02:00
skypjack
a2a72bcce6 stl: atomic header 2026-03-31 08:20:12 +02:00
skypjack
e7be9a94e8 stl: minor changes 2026-03-30 20:00:51 +02:00
skypjack
3652d47932 stl: tuple header 2026-03-30 18:59:56 +02:00
skypjack
898b50a39c build: update ENTT_INCLUDE_HEADERS list 2026-03-30 18:58:32 +02:00
skypjack
68f1bb1872 entt: add doc for entt::stl 2026-03-30 18:57:43 +02:00
skypjack
c7556f9245 stl: vector 2026-03-30 18:57:01 +02:00
skypjack
008dd6987c cleanup headers 2026-03-27 17:12:04 +01:00
skypjack
1333fa5312 entity: refine requires on entt_traits for enum 2026-03-27 15:41:04 +01:00
skypjack
171700153e stl: internal changes 2026-03-26 18:31:26 +01:00
skypjack
0ebf837e6a entt_traits: relax class constraints for backward compatibility 2026-03-26 17:42:05 +01:00
skypjack
093bb5bd89 entity: let the traits check the concept for us 2026-03-25 10:02:23 +01:00
skypjack
720dda4103 entity_like: move the concept to the file it belongs to, and fix it - see #1244 2026-03-25 10:01:15 +01:00
skypjack
05d11b7fa0 sparse_set: reduce impact of entity_like, and prepare to fix it 2026-03-25 00:03:59 +01:00
skypjack
9b94f09999 component_traits: reduce impact of entity_like, and prepare to fix it 2026-03-24 15:50:47 +01:00
skypjack
ca32a3668a test: reduce impact of entity_like, and prepare to fix it 2026-03-24 15:45:30 +01:00
skypjack
060eda7586 davey: reduce impact of entity_like, and prepare to fix it 2026-03-24 15:44:40 +01:00
skypjack
7c463516b1 storage_for 2026-03-24 14:16:05 +01:00
skypjack
f23f923608 storage_type: reduce impact of entity_like, and prepare to fix it 2026-03-24 14:15:12 +01:00
skypjack
8cc2eb43b3 storage: reduce impact of entity_like, and prepare to fix it 2026-03-24 14:12:43 +01:00
skypjack
6d31b33a10 view: minor changes on internal stuff 2026-03-24 14:11:26 +01:00
skypjack
fe517b0592 registry: reduce impact of entity_like, and prepare to fix it 2026-03-24 14:10:17 +01:00
skypjack
06bcc770f0 config: config injection 2026-03-23 16:46:24 +01:00
skypjack
75769cde27 build: refine SETUP_BASIC_TEST to also support include directories 2026-03-21 15:29:21 +01:00
skypjack
eec10a861e storage: minor change to suppress doc warning 2026-03-19 19:20:37 +01:00
skypjack
e099db8e15 storage: no fwd ref, no NOLINT 2026-03-19 19:09:37 +01:00
skypjack
9905ed6cff type_info: no fwd ref, no NOLINT 2026-03-19 18:33:12 +01:00
skypjack
6d6ba9b175 doc: a note about context variables - close #1326 2026-03-18 15:40:16 +01:00
skypjack
793ea69195 dispatcher: refine ::trigger API - close #1307 2026-03-17 15:27:10 +01:00
skypjack
ef088a298f updated TODO 2026-03-17 15:25:06 +01:00
skypjack
814a3e1404 cleanup 2026-03-16 14:29:01 +01:00
skypjack
f79c6dbde1 storage: constrain iterator types - close #1323 2026-03-16 14:15:33 +01:00
skypjack
6ca3db7de4 storage: reintroduce support to args for empty types - see #1323 2026-03-16 14:10:10 +01:00
skypjack
9c5281c79a sparse_set: make ::pop_all check pages before filling them 2026-03-12 09:50:27 +01:00
skypjack
136b137940 test: cover sparse_set::clear with empty pages (and make the sanitizer complain on the CI hopefully) 2026-03-12 09:29:25 +01:00
skypjack
1de7c8bbd2 view: avoid warnings and add a test to trigger them on the CI in future - close #1328 2026-03-11 16:38:01 +01:00
skypjack
93cb729322 test: use the mixin design a little more 2026-03-03 15:29:32 +01:00
skypjack
7d931a8df3 meta: avoid shadow warnings 2026-03-03 12:40:54 +01:00
skypjack
e3a736a2a5 test: use the mixin design a little more 2026-03-03 11:13:02 +01:00
skypjack
6b8fe4deff test: use the mixin design a little more 2026-03-03 10:10:46 +01:00
skypjack
3cf061201a test: use the mixin design a little more 2026-03-03 09:42:52 +01:00
skypjack
70d908d854 test: minor changes 2026-03-02 14:58:54 +01:00
skypjack
ca9a5f22d0 test: empty_mixin 2026-03-02 14:51:10 +01:00
skypjack
b7e8bb265f test: use the mixin design a little more 2026-03-02 14:30:43 +01:00
skypjack
b5797912d3 test: use the mixin design a little more 2026-03-02 14:09:26 +01:00
skypjack
c113dfe082 test: use the mixin design a little more 2026-03-02 13:54:46 +01:00
skypjack
24a7cc0deb sparse_set: review internal functions (perf) 2026-03-02 13:54:28 +01:00
skypjack
4d7fce0edc doc: review meta container support section 2026-02-27 17:36:34 +01:00
skypjack
79188ad748 storage: refine ::pop to improve perf for trivially destructible types - close #1311 2026-02-26 09:34:50 +01:00
skypjack
b1758e221b storage: small improvement for shrink_to_size 2026-02-26 09:19:52 +01:00
skypjack
017123be3e storage: skip ::clear for-loop for trivially destructible types - see #1311 2026-02-25 15:54:03 +01:00
skypjack
b43bbd5e25 updated TODO 2026-02-25 15:52:55 +01:00
skypjack
bb6a4abd6b sparse_set: ::pop_all early exit on empty sets 2026-02-24 15:08:01 +01:00
skypjack
3209cd854e test: meta dereference const correctness for non-pointer non-pointer-like types 2026-02-24 15:07:16 +01:00
skypjack
d20fc9551f meta: coding style 2026-02-23 11:24:59 +01:00
skypjack
9fdc43f6f8 meta: std::forward_iterator -> entt::stl::forward_iterator 2026-02-23 09:06:18 +01:00
skypjack
4e7833540c updated TODO 2026-02-23 08:37:02 +01:00
skypjack
1c456e2cb6 test: refine common classes to cover both trivially destructible and non trivially destructible types in the storage tests - see #1311 2026-02-23 08:36:47 +01:00
skypjack
17fc67de1f meta: revert last commit, the intermediate class is actually useful for user customizations 2026-02-23 08:29:19 +01:00
skypjack
3e47fb6bbd meta: cleanup 2026-02-22 18:16:50 +01:00
skypjack
8d4597ead0 meta: auto-detect meta containers, use traits to opt-out 2026-02-22 15:17:02 +01:00
skypjack
e14033b215 meta: get rid of reserve_aware_container 2026-02-20 11:55:40 +01:00
skypjack
41a8a7d921 test: cleanup 2026-02-20 10:31:54 +01:00
skypjack
3b3638ac8a test: non_trivially_destructible with storage (test coverage for future optimizations) 2026-02-20 10:27:59 +01:00
skypjack
34d2994cf3 test: non_trivially_destructible type 2026-02-20 10:26:54 +01:00
skypjack
011054e515 sparse_set: internal change (perf) - see #1311 2026-02-20 09:38:56 +01:00
skypjack
4321f5ece8 cleanup TODO 2026-02-20 09:38:28 +01:00
skypjack
0b3827366d davey: wrap imgui with __has_include - close #1312 2026-02-19 09:41:29 +01:00
skypjack
7cd612cc87 davey: walk up bases - close #1313 2026-02-18 15:18:04 +01:00
skypjack
657f2aade4 doc: more about the dispatcher - close #1299 2026-02-17 09:45:29 +01:00
skypjack
8cfb5534ab build: update bazel file 2026-02-16 10:58:51 +01:00
skypjack
737676f23f meta: support all dereferenceable types (i.e. optional) 2026-02-16 10:49:00 +01:00
skypjack
c6a8cf3de6 meta: pointer vs pointer-like rework (prepare to support all dereferenceable types) 2026-02-16 10:39:06 +01:00
skypjack
c18f1c3c07 test: internal changes 2026-02-16 10:25:59 +01:00
skypjack
fc4605a6b2 meta: non-const meta_any::operator* 2026-02-13 13:07:29 +01:00
skypjack
849852464e meta: prepare to support all dereferenceable types with meta_any 2026-02-12 19:06:14 +01:00
skypjack
071febbc0c any: as_ref() on empty returns empty 2026-02-12 09:18:26 +01:00
skypjack
0bb54130c9 meta: invalid meta_any when copying non-copyable types 2026-02-11 18:43:36 +01:00
skypjack
e7650e263f entt: cleanup 2026-02-10 16:37:49 +01:00
skypjack
f93d28981f entt: there is a reason why an allocator concept does not exist... 2026-02-10 16:29:46 +01:00
skypjack
106af0f6d8 container: cleanup 2026-02-09 17:01:10 +01:00
skypjack
3b71902777 entt: constrain allocator types 2026-02-09 16:57:59 +01:00
skypjack
7b46448cd9 test: please older compilers (like g++13) 2026-02-06 18:49:49 +01:00
skypjack
ed590b7ac8 concepts: allocator_like 2026-02-06 18:33:57 +01:00
skypjack
bde5d86690 test: concepts 2026-02-06 18:30:46 +01:00
skypjack
06491c6a0a updated TODO 2026-02-06 17:05:05 +01:00
skypjack
f22c7d931b test: iterator concepts workarounds 2026-02-05 18:43:22 +01:00
skypjack
2edc59d8bf cleanup TODO 2026-02-05 18:29:50 +01:00
skypjack
7fd8c1d2b1 sigh: minor changes 2026-02-04 09:59:05 +01:00
skypjack
4e191a95f4 test: cleanup 2026-02-04 09:56:08 +01:00
skypjack
a15a7653ee entity: more concepts, less sfinae 2026-02-04 09:14:49 +01:00
skypjack
a77b34f929 view: minor changes 2026-02-03 17:56:55 +01:00
skypjack
c5ae1fc8f5 doc: update to reflect the last changes 2026-02-03 10:36:10 +01:00
skypjack
39806a525f is_meta_pointer_like: refine definition 2026-02-03 10:35:58 +01:00
skypjack
8718ee3279 component_traits: refine definition 2026-02-03 10:35:38 +01:00
skypjack
b79d78350f type_info: refine definitions 2026-02-03 10:35:03 +01:00
skypjack
e08302e169 test: enclose expression in parentheses 2026-02-02 14:04:46 +01:00
skypjack
6ce08bc01d entt: enclose expression in parentheses 2026-02-02 14:04:39 +01:00
skypjack
8e5b05301b any: less sfinae, more concepts 2026-02-02 14:01:35 +01:00
skypjack
0e5537e4a9 meta: less sfinae, more concepts 2026-02-02 14:01:20 +01:00
skypjack
f28104bfac test: less sfinae, more concepts 2026-02-02 14:01:06 +01:00
skypjack
c7828b380d resource: less sfinae, more concepts 2026-02-02 14:00:26 +01:00
skypjack
101535b666 poly: less sfinae, more concepts 2026-02-02 13:59:34 +01:00
skypjack
efe67a700d container: less sfinae, more concepts 2026-02-02 13:59:13 +01:00
skypjack
7d2321efde type_traits: more concepts, less sfinae 2026-02-02 09:34:40 +01:00
skypjack
0891adb135 updated TODO 2026-02-02 09:34:24 +01:00
skypjack
222cb7b16e meta: refine concepts for the best 2026-01-30 18:47:48 +01:00
skypjack
924cb5f9e0 test: typo 2026-01-30 18:47:36 +01:00
skypjack
392e522b62 meta: more concepts, less sfinae 2026-01-30 18:31:08 +01:00
skypjack
3cc3a03c40 test: internal changes 2026-01-30 18:30:50 +01:00
skypjack
ebed6d8b7a any: more concept-ness :) 2026-01-30 18:30:36 +01:00
skypjack
e09593b44b entt: use cvref_unqualified as needed 2026-01-30 18:15:35 +01:00
skypjack
3971113c3c concepts: cvref_unqualified (QoL series) 2026-01-30 18:15:25 +01:00
skypjack
e74aac0626 entt: more concepts, less sfinae 2026-01-30 17:53:35 +01:00
skypjack
9509d37431 stl: refine iterator concepts 2026-01-29 16:59:28 +01:00
skypjack
cabdc1d1e3 stl: typo 2026-01-29 15:28:03 +01:00
skypjack
cf7be25ec9 workflow: try to enable C++23 2026-01-29 15:01:26 +01:00
skypjack
75d09d6f8d stl: cleanup 2026-01-29 15:01:04 +01:00
skypjack
413f1cba9e updated TODO 2026-01-29 14:29:32 +01:00
skypjack
20263bace1 meta_factory: refine internal logic 2026-01-29 14:28:11 +01:00
skypjack
f1708811e4 stl: typo 2026-01-29 14:19:54 +01:00
skypjack
a7f0371f9c stl: minor changes 2026-01-29 14:15:42 +01:00
skypjack
9c66e7219d stl: concepts.hpp -> iterator.hpp 2026-01-29 13:54:55 +01:00
skypjack
b00038a034 concepts: refine iterator concepts 2026-01-29 13:51:45 +01:00
skypjack
2a5f049de8 entity: replace std::output_iterator with stl::output_iterator 2026-01-29 13:42:13 +01:00
skypjack
c53b9c0b30 entt::stl -> stl:: 2026-01-29 13:41:20 +01:00
skypjack
84ba626acd dense_map: get rid of unnecessary template parameter 2026-01-29 12:49:59 +01:00
skypjack
9d0028e036 stl: fake iterator concepts to make up for the lack on some platforms 2026-01-29 12:36:02 +01:00
skypjack
ad330e4c94 meta: support name clashing between meta data/func and type 2026-01-29 09:43:38 +01:00
skypjack
6ac13b140f meta: avoid unnecessary allocations 2026-01-29 08:26:48 +01:00
skypjack
f6e22dc4ba meta: avoid looking up meta types again and again 2026-01-29 08:20:52 +01:00
skypjack
5c2326fa50 updated TODO 2026-01-28 16:17:23 +01:00
skypjack
1000562b1c container: more concepts, less sfinae 2026-01-28 12:31:29 +01:00
skypjack
22d39a0163 storage: update basic_storage definition 2026-01-28 12:30:41 +01:00
skypjack
272844ac90 view: use concepts to get rid of dummy template parameters 2026-01-28 12:29:50 +01:00
skypjack
fdbf30abc4 view: update basic_view definition 2026-01-28 12:29:00 +01:00
skypjack
5e92b9113f component_traits: refine internal checks 2026-01-28 12:27:55 +01:00
skypjack
4b43368116 is_iterator: more concepts, less sfinae 2026-01-28 12:27:18 +01:00
skypjack
c5743a6d6c compressed_pair: add missing parentheses 2026-01-27 19:11:30 +01:00
skypjack
d77d6fac48 compressed_pair: more concepts, less sfinae 2026-01-27 19:04:17 +01:00
skypjack
b16c5c3454 meta: more concepts, less sfinae 2026-01-27 18:51:06 +01:00
skypjack
ad69bec438 mixin: more concepts, less sfinae 2026-01-27 18:50:38 +01:00
skypjack
42c9e41c37 has_value_type: more concepts, less sfinae 2026-01-26 14:44:30 +01:00
skypjack
32dc7a37c2 is_transparent: more concepts, less sfinae 2026-01-26 14:44:08 +01:00
skypjack
c2e7139a70 test: internal changes 2026-01-26 14:43:29 +01:00
skypjack
778d78d98c compressed_pair: more concepts, less sfinae 2026-01-26 10:20:48 +01:00
skypjack
04bf3bcbfa meta: meta_policy concept 2026-01-26 09:19:57 +01:00
skypjack
9173c4d2f1 clang-format: refine config 2026-01-26 09:19:45 +01:00
skypjack
0d575c9a97 doc: typo 2026-01-23 19:00:07 +01:00
skypjack
4a2213ef4e tuple: fixed typo 2026-01-23 18:46:30 +01:00
skypjack
c6235fc047 ident: minor changes 2026-01-23 18:46:15 +01:00
skypjack
0cc794e921 clang-format: update config 2026-01-23 18:23:32 +01:00
skypjack
23dc5eb501 bit: refine fast_mod implementation 2026-01-23 18:06:06 +01:00
skypjack
100edffc96 enum: add missing include 2026-01-23 18:05:52 +01:00
skypjack
f7d1a7d849 doc: typo 2026-01-23 18:01:51 +01:00
skypjack
1bb590a57e enum: enum_bitmask concept 2026-01-23 18:01:16 +01:00
skypjack
80bb50c06d entity: coding style 2026-01-23 18:01:07 +01:00
skypjack
b8cb5de8dd dispatcher: try to also please g++12 2026-01-22 17:54:02 +01:00
skypjack
beda424de1 dispatcher: support enqueueing the same event type from listeners - close #1303 2026-01-22 17:19:16 +01:00
skypjack
7b456b9044 natvis: update dispatcher views 2026-01-22 15:46:25 +01:00
skypjack
6cf91dc0e0 updated TODO 2026-01-22 15:46:11 +01:00
skypjack
f69bfbb9f1 locator: oops :) 2026-01-21 16:43:54 +01:00
skypjack
5ea023c853 cleanup TODO 2026-01-21 16:43:40 +01:00
skypjack
9687efcaf6 locator: constrain a bit the interface 2026-01-21 16:25:17 +01:00
skypjack
5df5d165af stl: refine to_address impl 2026-01-21 16:24:56 +01:00
skypjack
c4cc708538 entity: clang-format only changes 2026-01-21 16:23:54 +01:00
skypjack
d552039b95 update clang-format config 2026-01-21 16:23:35 +01:00
skypjack
ee3738d5e7 doxy: TURN_OFF_DOXYGEN -> ENTT_INTERNAL 2026-01-21 15:27:41 +01:00
skypjack
80ffcda35d iota_iterator: constrain value type 2026-01-21 15:00:05 +01:00
skypjack
7d50da0463 iterable_adaptor: constrain iterator types 2026-01-21 14:58:31 +01:00
skypjack
47a6a27378 meta: internal changes/share common base 2026-01-21 14:56:09 +01:00
skypjack
a4315a9241 meta: export meta_base 2026-01-20 09:24:35 +01:00
skypjack
7ef8da9e87 natvis: meta_base view 2026-01-20 09:17:40 +01:00
skypjack
2aecdfe497 meta: added meta_base to further reduce implicit hidden lookups 2026-01-20 09:17:24 +01:00
skypjack
d43c5427e6 doc: minor changes 2026-01-20 09:05:35 +01:00
skypjack
9697549749 natvis: refine views for meta 2026-01-20 09:05:21 +01:00
skypjack
68e64d33ec meta: cleanup 2026-01-19 17:14:58 +01:00
skypjack
9cd81bcc37 natvis: meta 2026-01-19 17:14:23 +01:00
skypjack
72b2c5ac8e meta: update meta_custom_node for consistency 2026-01-19 17:14:17 +01:00
skypjack
94d05fab2f updated TODO 2026-01-19 17:10:41 +01:00
skypjack
be45cfafda meta: cleanup/prepare for meta_base first citizen type 2026-01-19 17:10:17 +01:00
skypjack
f0d2f0a415 meta: cleanup 2026-01-19 16:24:01 +01:00
skypjack
bba3722b2e algorithm: constrain iterator types 2026-01-19 15:48:31 +01:00
skypjack
5b9aa95a65 graph: cleanup 2026-01-19 15:48:17 +01:00
skypjack
818ddc4e3e entity: cleanup 2026-01-19 15:48:08 +01:00
skypjack
77a66812d4 container: cleanup 2026-01-19 15:47:59 +01:00
skypjack
5feca37a78 updated TODO 2026-01-19 15:47:47 +01:00
skypjack
682f6b2392 entity: constrain iterator types 2026-01-19 13:56:39 +01:00
skypjack
d447f8c14a meta: constrain iterator types 2026-01-19 12:00:11 +01:00
skypjack
ea5deaf3c9 updated TODO 2026-01-19 11:49:44 +01:00
skypjack
4793cbfd20 graph: constrain iterator types 2026-01-18 17:04:29 +01:00
skypjack
504768ffb3 container: constrain iterator types 2026-01-18 16:18:17 +01:00
skypjack
0ed7e3163e build: cxx standard update 2026-01-17 17:41:33 +01:00
skypjack
11deba942c doc: typo 2026-01-17 01:07:48 +01:00
skypjack
d13851f3b9 entity: add missing include 2026-01-17 01:02:19 +01:00
skypjack
00729e19b4 view: cleanup 2026-01-17 00:59:50 +01:00
skypjack
cbeda51f8d updated copyright :) 2026-01-16 09:43:20 +01:00
skypjack
c91b1c9155 entity: use entity_like as needed to constrain types in the ecs module 2026-01-16 08:28:24 +01:00
skypjack
cb499c5aea handle: cleanup operators 2026-01-16 08:12:15 +01:00
skypjack
f951d5d5a7 entity: review operators, and cleanup things 2026-01-15 18:24:24 +01:00
skypjack
5d9afc070e entity: constrained entt_traits, and null_t/tombstone_t functionalities 2026-01-15 18:23:19 +01:00
skypjack
6dfd760649 updated TODO 2026-01-15 18:21:48 +01:00
skypjack
439265c486 entity: introduce the entity_like concept 2026-01-15 18:21:37 +01:00
skypjack
f81f34e6fa entity: constrained type instead of sfinae based design for traits 2026-01-15 18:21:03 +01:00
skypjack
cc7d4aaeea handle: minor changes 2026-01-14 15:20:32 +01:00
skypjack
9ac749d7b6 hashed_string: operator==/operator<=> 2026-01-14 15:20:17 +01:00
skypjack
a2c2422fdf storage: avoid warnings/errors due to name conflicts 2026-01-13 16:01:25 +01:00
skypjack
dc6366d6d1 registry_storage_iterator: operator==/operator<=> 2026-01-13 15:32:13 +01:00
skypjack
5a3faa7256 view: review operators 2026-01-13 15:31:57 +01:00
skypjack
4df87a007d table: operator==/operator<=> 2026-01-13 15:31:39 +01:00
skypjack
5b5821ecc1 storage_iterator: operator==/operator<=> 2026-01-12 15:36:13 +01:00
skypjack
b3eef84102 sparse_set_iterator: operator==/operator<=> 2026-01-12 15:35:46 +01:00
skypjack
3066d0ed5c resource: operator==/operator<=> 2026-01-12 15:33:06 +01:00
skypjack
88e5fc2609 resource_cache_iterator: operator==/operator<=> 2026-01-12 15:32:50 +01:00
skypjack
20f395ba36 meta_range_iterator: operator==/operator<=> 2026-01-12 13:06:21 +01:00
skypjack
df10c0fcdc type_info: operator==/operator<=> 2026-01-12 12:59:02 +01:00
skypjack
f119bff9d5 container: use raw pointers to avoid issues with __wrap_iter 2026-01-12 12:01:37 +01:00
skypjack
1f41b86665 test: add missing include 2026-01-10 18:27:04 +01:00
skypjack
5ef5d31419 container: add missing include 2026-01-10 18:26:58 +01:00
skypjack
86148d12ee dense_set: operator==/operator<=> 2026-01-09 15:58:19 +01:00
skypjack
3cae3fbb2b dense_map: operator==/operator<=> 2026-01-09 15:58:09 +01:00
skypjack
40109e9ae4 group: internal changes (coding style) 2026-01-09 15:35:46 +01:00
skypjack
767013e0cb handle: cleanup 2026-01-09 15:35:17 +01:00
skypjack
9b47f44c48 registry: cleanup 2026-01-09 15:35:02 +01:00
skypjack
8a51b5950c iota_iterator: internal changes (coding style) 2026-01-09 15:34:29 +01:00
skypjack
e54add5eab adjacency_matrix: internal changes (coding style) 2026-01-09 15:33:44 +01:00
skypjack
7d4933790b test: internal changes to modernize the codebase 2026-01-09 15:32:42 +01:00
skypjack
ad147da839 entity: discard the no longer necessary operator!= 2026-01-08 12:12:56 +01:00
skypjack
dd5043fa81 handle: discard the no longer necessary operator!= 2026-01-08 12:12:29 +01:00
skypjack
656a2d2036 any: discard the no longer necessary operator!= 2026-01-08 11:53:10 +01:00
skypjack
e35b698f26 iota_iterator: discard the no longer necessary operator!= 2026-01-08 11:52:56 +01:00
skypjack
cfabb3b21c group: discard the no longer necessary operator!= 2026-01-08 11:47:08 +01:00
skypjack
ecb82e1555 resource: discard the no longer necessary operator!= 2026-01-08 11:46:50 +01:00
skypjack
9588c3cc5a cache: discard the no longer necessary operator!= 2026-01-08 11:46:15 +01:00
skypjack
f5983aa751 table: discard the no longer necessary operator!= 2026-01-08 11:44:00 +01:00
skypjack
dd8e28a734 dense_set: discard the no longer necessary operator!= 2026-01-08 11:43:52 +01:00
skypjack
42acf469cf dense_map: discard the no longer necessary operator!= 2026-01-08 11:43:34 +01:00
skypjack
7eca5e840f registry: discard the no longer necessary operator!= 2026-01-08 11:42:14 +01:00
skypjack
fa579eea59 meta: discard the no longer necessary operator!= 2026-01-08 11:36:14 +01:00
skypjack
9e8c10a443 meta_range_iterator: discard the no longer necessary operator!= 2026-01-08 11:35:46 +01:00
skypjack
60a8e9dc2e view: discard the no longer necessary operator!= 2026-01-08 11:35:23 +01:00
skypjack
c6dbcf6c5f sparse_set: discard the no longer necessary operator!= 2026-01-08 11:35:00 +01:00
skypjack
12ec00ac28 storage: discard the no longer necessary operator!= 2026-01-08 11:34:50 +01:00
skypjack
bc93bf2f79 runtime_view: discard the no longer necessary operator!= 2026-01-08 11:34:36 +01:00
skypjack
55a6fd65aa delegate: discard the no longer necessary operator!= 2026-01-08 11:31:40 +01:00
skypjack
16a8c25bd6 graph: discard the no longer necessary operator!= 2026-01-08 11:31:19 +01:00
skypjack
d5aa3973db type_info: discard the no longer necessary operator!= 2026-01-08 11:30:45 +01:00
skypjack
b3718b329d hashed_string: discard the no longer necessary operator!= 2026-01-08 11:25:50 +01:00
skypjack
8992822fe7 test: discard the no longer necessary operator!= 2026-01-08 11:14:37 +01:00
skypjack
32f030a346 natvis: meta_ctx view 2026-01-07 12:35:45 +01:00
skypjack
3961aff10c davey: updated to string_view names 2026-01-07 10:31:11 +01:00
skypjack
f4b6b513fa doc: added MonsterWar to the list 2026-01-07 10:13:22 +01:00
skypjack
deed237bbe meta: return a string_view from name() 2026-01-05 12:16:55 +01:00
skypjack
d26a9baa1c test: avoid shadow warning 2026-01-05 11:39:36 +01:00
skypjack
3e9bddff98 test: avoid shadow warnings 2026-01-05 11:38:32 +01:00
skypjack
e2044f34a8 test: avoid shadow warnings 2026-01-05 11:35:34 +01:00
skypjack
bfd7320609 meta: prepare to more perf improvements 2026-01-03 11:48:02 +01:00
skypjack
4756933039 meta: minor changes 2026-01-02 16:21:09 +01:00
skypjack
cfdffa64a1 entt: cleanup TODO file 2025-12-29 17:27:33 +01:00
skypjack
ed1fd2dc26 test: add missing template keywords 2025-12-29 17:27:02 +01:00
skypjack
3552f45b83 build: delete SETUP_BASIC_TEST_DEPRECATED 2025-12-28 20:07:50 +01:00
skypjack
8f6e1588e5 build: review entity tests 2025-12-28 20:07:13 +01:00
skypjack
1f7efe511d build: review example tests 2025-12-24 10:26:01 +01:00
skypjack
9bcd14f31f build: refine lib tests 2025-12-23 17:28:28 +01:00
skypjack
37b56a535d doc: stl is a no-doc area 2025-12-23 17:26:25 +01:00
skypjack
21a9525b44 build: refine meta tests 2025-12-23 17:24:01 +01:00
skypjack
374b612c15 build: refine signal tests 2025-12-23 15:31:41 +01:00
skypjack
741fdc3810 build: review core tests 2025-12-23 15:25:28 +01:00
skypjack
e9d4c05825 build: review container tests 2025-12-23 15:23:33 +01:00
skypjack
7b273db8b8 build: review config tests 2025-12-23 15:22:35 +01:00
skypjack
6f2ba58e21 build: review graph tests 2025-12-23 15:22:16 +01:00
skypjack
b3b794aef5 build: review stl tests 2025-12-23 15:20:01 +01:00
skypjack
f2fc45dd36 build: review resource tests 2025-12-23 15:17:06 +01:00
skypjack
c210375657 build: review process tests 2025-12-23 15:16:25 +01:00
skypjack
85503302cb build: review poly tests 2025-12-23 15:14:25 +01:00
skypjack
aaeeba2167 build: review locator tests 2025-12-23 15:13:55 +01:00
skypjack
e734078bb0 build: review benchmark test 2025-12-23 15:12:14 +01:00
skypjack
98cf280aae build: prepare test refactoring 2025-12-23 15:11:11 +01:00
skypjack
d14707ed3a test: prepare for refactoring 2025-12-22 16:40:11 +01:00
skypjack
b157dfbf86 test: prepare for refactoring 2025-12-22 11:33:00 +01:00
skypjack
ebb9cf017a entt: replaced identity with stl::identity 2025-12-22 10:24:34 +01:00
skypjack
09b9099b1c stl: functional.hpp for identity 2025-12-22 10:22:46 +01:00
skypjack
b469b2b353 doc: remove reference to identity 2025-12-22 08:56:25 +01:00
skypjack
93bfd66fc6 stl: cleanup 2025-12-19 18:19:35 +01:00
skypjack
66f42d358a doc: config.md 2025-12-19 18:09:59 +01:00
skypjack
036196bed3 config: ENTT_USE_STL (mainly for test purposes) 2025-12-19 17:47:17 +01:00
skypjack
5460315b6e *: updated TODO 2025-12-19 17:43:55 +01:00
skypjack
3ab0000b31 config: ENTT_NOEXCEPTION -> ENTT_NO_EXCEPTION 2025-12-19 17:16:43 +01:00
skypjack
fbffdaf176 stl: refine memory.hpp 2025-12-19 16:57:55 +01:00
skypjack
884f698fab core: make inclusion of custom to_address conditional 2025-12-19 15:37:54 +01:00
skypjack
5843c75b80 doc: cleanup 2025-12-19 15:35:43 +01:00
skypjack
0a6968f3a4 *: updated TODO 2025-12-19 15:35:30 +01:00
skypjack
c2d68e242a core: reintroduce to_address (it's not available everywhere yet, I need to find a solution to inject it when needed) 2025-12-19 10:03:33 +01:00
skypjack
b69d856ee3 core: entt::to_address -> std::to_address 2025-12-19 08:20:55 +01:00
skypjack
8dd00aea29 config: reintroduce ENTT_CONSTEVAL to make consteval easier for older compilers 2025-12-18 18:06:04 +01:00
skypjack
e40537afc2 test: try to make clang 16 happy again on the CI 2025-12-18 18:00:19 +01:00
skypjack
e50ee6a956 entity: rollback some consteval to constexpr to please all compilers 2025-12-18 17:48:35 +01:00
skypjack
06784b8d63 view: make it clear to clang that I'm using the this pointer 2025-12-18 17:45:00 +01:00
skypjack
ad9ef0320b test: more consteval-ness 2025-12-18 17:28:52 +01:00
skypjack
efe1e0830a signal: more consteval-ness 2025-12-18 17:28:45 +01:00
skypjack
16cf5b96a6 poly: more consteval-ness 2025-12-18 17:28:39 +01:00
skypjack
489bf2fbec meta: more consteval-ness 2025-12-18 17:28:30 +01:00
skypjack
b35045ac78 entity: more consteval-ness 2025-12-18 17:28:20 +01:00
skypjack
4f994cbec2 core: more consteval-ness 2025-12-18 17:27:52 +01:00
skypjack
8e7b810a3c doc: more consteval-ness 2025-12-18 17:27:30 +01:00
skypjack
afc94e62f2 config: drop ENTT_CONSTEVAL 2025-12-17 14:00:57 +01:00
skypjack
2f2fe11343 entt: std::remove_const_t<std::remove_reference_t<...>> -> std::remove_cvref_t<...> 2025-12-17 11:22:58 +01:00
skypjack
3390e3c563 doc: std::remove_const_t<std::remove_reference_t<...>> -> std::remove_cvref_t<...> 2025-12-17 11:22:38 +01:00
skypjack
df37ba35ac any: cleanup 2025-12-17 11:11:17 +01:00
skypjack
1232d7c285 test: cleanup 2025-12-17 11:11:11 +01:00
skypjack
3a32f18c78 view: missing template keywords 2025-12-16 23:19:12 +01:00
skypjack
e504310399 view: support converting views 2025-12-16 16:14:59 +01:00
skypjack
8d64106372 view: refine storage view conversion logic 2025-12-16 16:14:03 +01:00
skypjack
6b4365bec9 view: support multi-to-single view conversions 2025-12-16 12:31:24 +01:00
skypjack
fc936c3e6f view: support converting storage views 2025-12-15 11:43:15 +01:00
skypjack
ff13ce5f83 *: cleanup TODO 2025-12-15 11:06:48 +01:00
skypjack
cc4f7b3ab8 doc: updated links 2025-12-15 11:06:41 +01:00
skypjack
a6681e97c9 doc: update requirements 2025-12-12 13:40:27 +01:00
skypjack
6d6d60d2a7 build: update min cmake version (no patch value) 2025-12-12 13:40:07 +01:00
skypjack
60bdaacfdf build: update min doxy version 2025-12-12 13:39:46 +01:00
skypjack
3cfd6e1739 *: cleanup TODO 2025-12-12 11:57:56 +01:00
skypjack
b34131ef4b build: refine cereal config 2025-12-12 11:57:46 +01:00
skypjack
d2b00fc03a build: refine docs config 2025-12-12 11:09:59 +01:00
skypjack
66d02050a8 build: refine testbed config 2025-12-11 18:57:56 +01:00
skypjack
9a4ffa2142 build: bump cmake version 2025-12-11 18:57:31 +01:00
skypjack
9fc1245013 view: cleanup 2025-12-11 18:28:56 +01:00
skypjack
aeaf6f7304 davey: add missing typename 2025-12-10 15:52:17 +01:00
skypjack
140eeae80d *: updated TODO 2025-12-10 14:42:23 +01:00
skypjack
84646ad457 doc: updated links 2025-12-10 14:39:50 +01:00
skypjack
e54928794f davey: cleanup 2025-12-10 14:37:16 +01:00
skypjack
4c2ed7380f doc: minor changes 2025-12-10 14:36:57 +01:00
Starman
85a042b7c9 doc: add KODZA game engine link to documentation (#1298)
I made it btw, love this project
2025-12-10 14:36:04 +01:00
skypjack
06df4003e8 entity: cleanup 2025-12-09 15:32:20 +01:00
skypjack
a56e19993b meta: cleanup 2025-12-08 16:07:17 +01:00
skypjack
83dc6f4a97 signal: cleanup 2025-12-08 15:00:16 +01:00
skypjack
9e7a31cc74 core: cleanup 2025-12-08 14:59:48 +01:00
skypjack
c72a42d38d doc: update 2025-12-05 23:43:46 +01:00
skypjack
f1e59c4ea4 container: cleanup 2025-12-05 18:11:23 +01:00
skypjack
7f397f6aa0 process: cleanup 2025-12-05 18:10:57 +01:00
skypjack
48dbba6c70 poly: cleanup 2025-12-05 18:08:19 +01:00
skypjack
56b9486460 graph: cleanup 2025-12-05 18:08:04 +01:00
skypjack
f76191d27c resource: cleanup 2025-12-05 18:07:50 +01:00
skypjack
4a18647aa9 test: minor changes 2025-12-05 14:42:54 +01:00
skypjack
f4f6edbc73 *: updated TODO 2025-12-05 14:41:30 +01:00
skypjack
d878089ecc doc: cleanup 2025-12-05 14:38:47 +01:00
skypjack
29dba57433 test: cleanup entity 2025-12-05 14:38:26 +01:00
skypjack
46552b0663 *: updated TODO 2025-12-05 14:38:17 +01:00
skypjack
784ba1e9cd test: cleanup core 2025-12-05 14:38:09 +01:00
skypjack
b7040d940f test: cleanup meta 2025-12-04 11:53:42 +01:00
skypjack
494714504f test: cleanup container 2025-12-04 11:53:33 +01:00
skypjack
f6c688d9e3 test: cleanup resource 2025-12-04 11:53:21 +01:00
skypjack
6e68159b5e test: thanks msvc, as usual :) 2025-12-03 18:32:24 +01:00
skypjack
c8c5905913 test: cleanup process 2025-12-03 18:28:54 +01:00
skypjack
b90607f87b test: cleanup poly 2025-12-03 18:28:37 +01:00
skypjack
cfcee56b95 test: cleanup graph 2025-12-03 18:28:19 +01:00
skypjack
90d1a8b92d test: cleanup signal 2025-12-03 18:28:00 +01:00
skypjack
12d9660016 test: cleanup examples 2025-12-03 18:27:45 +01:00
skypjack
4cbbdf5ffb test: re-enable commented test 2025-12-03 18:10:07 +01:00
skypjack
da254e1552 registry: cleanup 2025-12-02 18:29:28 +01:00
skypjack
afad2972dd build: cmake does not support toolset 144 apparently 2025-12-02 18:25:40 +01:00
skypjack
05bf0aa505 build: update vs toolsets 2025-12-02 17:57:08 +01:00
skypjack
13a479eff0 storage: exploit std::allocator<void> cross constructors 2025-12-02 17:30:05 +01:00
skypjack
52b41cfab5 registry: exploit std::allocator<void> cross constructors 2025-12-02 17:29:59 +01:00
skypjack
be2b93549f core: drop type_identity[_t] 2025-12-02 17:29:10 +01:00
skypjack
a6638cd026 config: drop ENTT_CONSTEXPR 2025-12-02 17:28:22 +01:00
skypjack
ce2c8b3b91 core: reintroduce entt::identity (it's not available everywhere yet, I need to find a solution to inject it when needed) 2025-12-01 17:08:22 +01:00
skypjack
cd28e6269b core: next_power_of_two -> std::bit_ceil 2025-12-01 17:04:28 +01:00
skypjack
760b2aaccf *: entt::has_single_bit -> std::has_single_bit 2025-11-27 17:26:03 +01:00
skypjack
537ffb48a7 *: entt::popcount -> std::popcount 2025-11-26 14:37:26 +01:00
skypjack
7f0caeb7bc doc: cleanup the bit section 2025-11-26 14:37:04 +01:00
skypjack
13395a88f1 core: drop entt::identity 2025-11-25 15:29:30 +01:00
skypjack
9869ab7209 resource: use std::identity instead of entt::identity 2025-11-25 15:29:10 +01:00
skypjack
0503932abf test: use std::identity instead of entt::identity 2025-11-25 15:28:58 +01:00
skypjack
2df0073f53 signal: use std::identity instead of entt::identity 2025-11-25 15:28:39 +01:00
skypjack
311f6cac91 meta: use std::identity instead of entt::identity 2025-11-25 15:28:25 +01:00
skypjack
3bf839b89a flow: use std::identity instead of entt::identity 2025-11-25 15:27:52 +01:00
skypjack
eece255765 registry: use std::identity instead of entt::identity 2025-11-25 15:27:25 +01:00
skypjack
5ce5968d44 algorithm: use std::identity instead of entt::identity 2025-11-25 15:27:01 +01:00
skypjack
64982c34ad doc: remove reference to entt::identity 2025-11-25 15:25:01 +01:00
skypjack
024d478409 doc: minor changes 2025-11-25 15:23:55 +01:00
skypjack
c84ff3bcd8 build: C++20 2025-11-25 11:55:39 +01:00
skypjack
e9b64a21a2 doc: updated README 2025-11-24 17:06:36 +01:00
skypjack
ea3de5499e any: remove deprecated functions 2025-11-24 15:52:15 +01:00
skypjack
de32688d46 meta: remove deprecated functions/types 2025-11-24 15:52:03 +01:00
skypjack
98872fc1cc poly: remove deprecated functions 2025-11-24 14:53:02 +01:00
skypjack
75fa927f31 sparse set: remove deprecated functions 2025-11-24 14:52:36 +01:00
skypjack
dc784ba2e7 doc: remove unreal page, no longer applies 2025-11-24 09:49:46 +01:00
skypjack
57b52a25a4 bazel: switch to C++20 2025-11-22 19:30:31 +01:00
skypjack
d558d06dcf build: update conan test to C++20 2025-11-22 19:29:11 +01:00
skypjack
db024cff7d build: C++20 only workflows (but still ready for C++23) 2025-11-22 19:09:52 +01:00
skypjack
c4904e8bcf build: update docs custom target 2025-11-21 16:56:39 +01:00
skypjack
889d6217d1 now working on version 4.0.x 2025-11-21 16:55:45 +01:00
254 changed files with 7256 additions and 6843 deletions

View File

@@ -5,8 +5,8 @@ build --enable_runfiles
build --incompatible_strict_action_env
# required for googletest
build:linux --cxxopt=-std=c++17
build:macos --cxxopt=-std=c++17
build:linux --cxxopt=-std=c++20
build:macos --cxxopt=-std=c++20
common:ci --announce_rc
common:ci --verbose_failures

View File

@@ -3,6 +3,7 @@ BasedOnStyle: llvm
AccessModifierOffset: -4
AlignEscapedNewlines: DontAlign
AllowShortBlocksOnASingleLine: Always
AllowShortCompoundRequirementOnASingleLine: true
AllowShortEnumsOnASingleLine: true
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: WithoutElse
@@ -10,6 +11,8 @@ AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: true
AlwaysBreakTemplateDeclarations: Yes
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeBraces: Attach
BreakBeforeConceptDeclarations: Always
BreakBeforeTernaryOperators: true
ColumnLimit: 0
DerivePointerAlignment: false
@@ -26,17 +29,33 @@ IncludeCategories:
Priority: 5
IncludeIsMainRegex: "^$"
IndentPPDirectives: AfterHash
IndentRequiresClause: false
IndentWidth: 4
InsertBraces: true
InsertNewlineAtEOF: true
KeepEmptyLinesAtTheStartOfBlocks: false
Language: Cpp
PointerAlignment: Right
RequiresClausePosition: OwnLineWithBrace
RequiresExpressionIndentation: OuterScope
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: false
SpaceAroundPointerQualifiers: After
SpaceBeforeCaseColon: false
SpaceBeforeCtorInitializerColon: false
SpaceBeforeInheritanceColon: false
SpaceBeforeParens: Never
SpaceBeforeParens: Custom
SpaceBeforeParensOptions:
AfterControlStatements: false
AfterForeachMacros: false
AfterFunctionDeclarationName: false
AfterFunctionDefinitionName: false
AfterIfMacros: false
AfterOverloadedOperator: false
AfterPlacementOperator: false
AfterRequiresInClause: true
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceBeforeRangeBasedForLoopColon: false
Standard: Latest
TabWidth: 4

View File

@@ -40,10 +40,8 @@ jobs:
windows:
strategy:
matrix:
toolset: [default, v142, v143, clang-cl]
toolset: [default, v143, clang-cl]
include:
- toolset: v142
toolset_option: -T"v142"
- toolset: v143
toolset_option: -T"v143"
- toolset: clang-cl
@@ -87,7 +85,7 @@ jobs:
matrix:
os: [windows-latest, macOS-latest, ubuntu-latest]
id_type: ["std::uint32_t", "std::uint64_t"]
cxx_std: [cxx_std_17, cxx_std_20]
cxx_std: [cxx_std_20, cxx_std_23]
timeout-minutes: 15
runs-on: ${{ matrix.os }}

View File

@@ -11,7 +11,7 @@ jobs:
matrix:
compiler: [clang++]
id_type: ["std::uint32_t", "std::uint64_t"]
cxx_std: [cxx_std_17, cxx_std_20]
cxx_std: [cxx_std_20, cxx_std_23]
runs-on: ubuntu-latest

View File

@@ -1,6 +1,6 @@
# EnTT
cmake_minimum_required(VERSION 3.15.7)
cmake_minimum_required(VERSION 3.28)
# Read project version
@@ -25,7 +25,7 @@ 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>")
message(VERBOSE "* Copyright (c) 2017-2026 Michele Caini <michele.caini@gmail.com>")
message(VERBOSE "*")
# CMake stuff
@@ -93,7 +93,7 @@ target_include_directories(
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
target_compile_features(EnTT INTERFACE cxx_std_17)
target_compile_features(EnTT INTERFACE cxx_std_20)
if(ENTT_HAS_LIBCPP)
target_compile_options(EnTT BEFORE INTERFACE -stdlib=libc++)
@@ -133,6 +133,7 @@ if(ENTT_INCLUDE_HEADERS)
core/any.hpp
core/bit.hpp
core/compressed_pair.hpp
core/concepts.hpp
core/enum.hpp
core/family.hpp
core/fwd.hpp
@@ -194,6 +195,27 @@ if(ENTT_INCLUDE_HEADERS)
signal/emitter.hpp
signal/fwd.hpp
signal/sigh.hpp
stl/algorithm.hpp
stl/array.hpp
stl/atomic.hpp
stl/bit.hpp
stl/cmath.hpp
stl/concepts.hpp
stl/cstddef.hpp
stl/cstdint.hpp
stl/functional.hpp
stl/ios.hpp
stl/iterator.hpp
stl/limits.hpp
stl/memory.hpp
stl/ostream.hpp
stl/sstream.hpp
stl/string.hpp
stl/string_view.hpp
stl/tuple.hpp
stl/type_traits.hpp
stl/utility.hpp
stl/vector.hpp
tools/davey.hpp
entt.hpp
fwd.hpp
@@ -330,7 +352,7 @@ option(ENTT_BUILD_TESTBED "Enable building testbed." 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")
set(ENTT_CXX_STD cxx_std_20 CACHE STRING "C++ standard revision to use for tests and testbed")
# Tests and tesetbed do not work together because SDL gets confused with EnTT tests
if(ENTT_BUILD_TESTING)

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2017-2025 Michele Caini, author of EnTT
Copyright (c) 2017-2026 Michele Caini, author of EnTT
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -217,12 +217,12 @@ the include paths.
## Requirements
To be able to use `EnTT`, users must provide a full-featured compiler that
supports at least C++17.<br/>
supports at least C++20.<br/>
The requirements below are mandatory to compile the tests and to extract the
documentation:
* `CMake` version 3.7 or later.
* `Doxygen` version 1.8 or later.
* `CMake` version 3.28 or later.
* `Doxygen` version 1.14 or later.
Alternatively, [Bazel](https://bazel.build) is also supported as a build system
(credits to [zaucy](https://github.com/zaucy) who offered to maintain it).<br/>
@@ -325,7 +325,7 @@ If you spot errors or have suggestions, any contribution is welcome!
`bazel` project, add the following to your `MODULE.bazel` file:
```starlark
bazel_dep(name = "entt", version = "3.12.2")
bazel_dep(name = "entt", version = "3.16.0")
```
EnTT will now be available as `@entt` (short for `@entt//:entt`) to be used
@@ -409,7 +409,7 @@ know who has participated so far.
# License
Code and documentation Copyright (c) 2017-2025 Michele Caini.<br/>
Code and documentation Copyright (c) 2017-2026 Michele Caini.<br/>
Colorful logo Copyright (c) 2018-2021 Richard Caseres.
Code released under

12
TODO
View File

@@ -10,22 +10,17 @@ DOC:
* bump entities, reserved bits on identifiers
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
* 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
* 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
* 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
* allow passing arguments to meta setter/getter (we can fallback on meta invoke probably)
* 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)
* review build process for testbed (i.e. tests first due to SDL)
* use unique_ptr or any for meta_custom_node
@@ -33,5 +28,10 @@ TODO:
* 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
* redesign snapshot as a whole
* explore "runtime" mode for hashed string where the source is copied internally
* storage: shrink_to_fit does not work with reentrant destructor?
* make meta_any buffer size configurable (propagate to any)
* test trivially_destructible optimization
* document stl and injections support

View File

@@ -2,11 +2,11 @@ load("@bazel_skylib//lib:selects.bzl", "selects")
COPTS = selects.with_or({
("//conditions:default", "@rules_cc//cc/compiler:clang", "@rules_cc//cc/compiler:gcc", "@rules_cc//cc/compiler:mingw-gcc"): [
"-std=c++17",
"-std=c++20",
"-w",
],
("@rules_cc//cc/compiler:msvc-cl", "@rules_cc//cc/compiler:clang-cl"): [
"/std:c++17",
"/std:c++20",
"/permissive-",
"/w",
],

View File

@@ -1,9 +1,9 @@
cmake_minimum_required(VERSION 3.7.2)
cmake_minimum_required(VERSION 3.28)
project(test_package)
set(CMAKE_VERBOSE_MAKEFILE TRUE)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)

View File

@@ -1,6 +1,6 @@
# Doxygen configuration (documentation)
find_package(Doxygen 1.13)
find_package(Doxygen 1.14)
if(DOXYGEN_FOUND)
include(FetchContent)
@@ -12,15 +12,10 @@ if(DOXYGEN_FOUND)
GIT_SHALLOW 1
)
FetchContent_GetProperties(doxygen-awesome-css)
if(NOT doxygen-awesome-css_POPULATED)
FetchContent_Populate(doxygen-awesome-css)
set(doxygen-awesome-css_INCLUDE_DIR ${doxygen-awesome-css_SOURCE_DIR})
endif()
FetchContent_MakeAvailable(doxygen-awesome-css)
set(DOXY_SOURCE_DIRECTORY ${EnTT_SOURCE_DIR}/src)
set(DOXY_CSS_DIRECTORY ${doxygen-awesome-css_INCLUDE_DIR})
set(DOXY_CSS_DIRECTORY ${doxygen-awesome-css_SOURCE_DIR})
set(DOXY_DOCS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
set(DOXY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
@@ -37,6 +32,7 @@ if(DOXYGEN_FOUND)
md/core.md
md/entity.md
md/faq.md
md/graph.md
md/lib.md
md/links.md
md/locator.md
@@ -46,7 +42,6 @@ if(DOXYGEN_FOUND)
md/reference.md
md/resource.md
md/signal.md
md/unreal.md
doxy.in
)

View File

@@ -4,7 +4,8 @@
* [Introduction](#introduction)
* [Definitions](#definitions)
* [ENTT_NOEXCEPTION](#entt_noexception)
* [ENTT_USE_STL](#entt_use_stl)
* [ENTT_NO_EXCEPTION](#entt_no_exception)
* [ENTT_USE_ATOMIC](#entt_use_atomic)
* [ENTT_ID_TYPE](#entt_id_type)
* [ENTT_SPARSE_PAGE](#entt_sparse_page)
@@ -13,7 +14,9 @@
* [ENTT_ASSERT_CONSTEXPR](#entt_assert_constexpr)
* [ENTT_DISABLE_ASSERT](#entt_disable_assert)
* [ENTT_NO_ETO](#entt_no_eto)
* [ENTT_NO_MIXIN](#entt_no_mixin)
* [ENTT_STANDARD_CPP](#entt_standard_cpp)
* [Configuration injection](#configuration-injection)
# Introduction
@@ -33,7 +36,14 @@ Each parameter can result in internal library definitions. It is not recommended
to try to also modify these definitions, since there is no guarantee that they
will remain stable over time unlike the options below.
## ENTT_NOEXCEPTION
## ENTT_USE_STL
Intended for testing purposes, it forces the use of built-in replacements of
some parts of the standard library that aren't always available otherwise.<br/>
`EnTT` _detects_ these cases on its own, and users should never define this
variable explicitly. However, it's still possible if desired.
## ENTT_NO_EXCEPTION
Define this variable without assigning any value to it to turn off exception
handling in `EnTT`.<br/>
@@ -106,6 +116,13 @@ never instantiated nor stored by the ECS module of `EnTT`.<br/>
Use this variable to treat these types like all others and therefore to create a
dedicated storage for them.
## ENTT_NO_MIXIN
`EnTT` automatically assigns mixins to all storage types to support signaling
when creating, destroying, and modifying elements.<br/>
Mixins can have a (most likely negligible) cost in terms of performance and
compilation time. If unwanted, this macro suppresses automatic generation.
## ENTT_STANDARD_CPP
`EnTT` mixes non-standard language features with others that are perfectly
@@ -114,3 +131,14 @@ This definition prevents the library from using non-standard techniques, that
is, functionalities that are not fully compliant with the standard C++.<br/>
While there are no known portability issues at the time of this writing, this
should make the library fully portable anyway if needed.
# Configuration injection
Configuration variables are provided via code or injected directly from the
outside via a dedicated file.<br/>
`EnTT` uses `__has_include` internally and looks for a specific path, namely
`<entt/ext/config.h>`. This can be provided by the user by setting the include
paths appropriately.<br/>
For example, `CMake` allows users to _bind_ additional include directories to a
target with `target_include_directories`. See the test suite, and in particular
the `config_ext` test for a practical example.

View File

@@ -201,19 +201,15 @@ in order to meet them.
# Bit
Finding out the population count of an unsigned integral value (`popcount`),
whether a number is a power of two or not (`has_single_bit`) as well as the next
power of two given a random value (`next_power_of_two`) can be useful.<br/>
For example, it helps to allocate memory in pages having a size suitable for the
fast modulus:
Some general purpose utilities, such as the fast module function:
```cpp
const std::size_t result = entt::fast_mod(value, modulus);
```
Where `modulus` is necessarily a power of two. Perhaps not everyone knows that
this type of operation is far superior in terms of performance to the basic
modulus and for this reason preferred in many areas.
Where `modulus` is necessarily a power of two. This type of operation is far
superior in terms of performance to the basic modulus and for this reason
preferred in many areas.
# Compressed pair
@@ -449,9 +445,9 @@ Some are geared towards simplifying the implementation of (internal or external)
allocator aware containers. Others are designed to help the developer with
everyday problems.
The former are very specific and for niche problems. These are tools designed to
unwrap fancy or plain pointers (`to_address`) or to help forget the meaning of
acronyms like _POCCA_, _POCMA_ or _POCS_.<br/>
The former are very specific and for niche problems. For example, there are
tools designed to help forget the meaning of acronyms like _POCCA_, _POCMA_ or
_POCS_.<br/>
I will not describe them here in detail. Instead, I recommend reading the inline
documentation to those interested in the subject.
@@ -528,12 +524,13 @@ Basically, the whole system relies on a handful of classes. In particular:
associative containers or for positional accesses in a vector or an array.
An external generator can also be used if needed. In fact, `type_index` can be
specialized by type and is also _sfinae-friendly_ in order to allow more
specialized by type or constrained with a concept in order to allow more
refined specializations such as:
```cpp
template<typename Type>
struct entt::type_index<Type, std::void_d<decltype(Type::index())>> {
requires requires { { Type::index() } -> std::same_as<entt::id_type>; }
struct entt::type_index<Type> {
static entt::id_type value() noexcept {
return Type::index();
}
@@ -562,8 +559,8 @@ Basically, the whole system relies on a handful of classes. In particular:
identifiers remain stable across executions. Moreover, they are generated
at runtime and are no longer a compile-time thing.
As it happens with `type_index`, also `type_hash` is a _sfinae-friendly_ class
that can be specialized in order to customize its behavior globally or on a
As it happens with `type_index`, also `type_hash` can be specialized or
constrained with a concept in order to customize its behavior globally or on a
per-type or per-traits basis.
* The name associated with a given type:
@@ -593,8 +590,8 @@ Basically, the whole system relies on a handful of classes. In particular:
purposes. Users can prevent the library from using these features by means of
the `ENTT_STANDARD_CPP` definition. In this case, the name is just empty.
As it happens with `type_index`, also `type_name` is a _sfinae-friendly_ class
that can be specialized in order to customize its behavior globally or on a
As it happens with `type_index`, also `type_name` can be specialized or
constrained with a concept in order to customize its behavior globally or on a
per-type or per-traits basis.
These are then combined into utilities that aim to offer an API that is somewhat
@@ -639,7 +636,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_const_t<std::remove_reference_t<a_type>>>::value();
auto idx = entt::type_index<std::remove_cvref_t<a_type>>::value();
```
* The hash value associated with a given type:
@@ -651,7 +648,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_const_t<std::remove_reference_t<a_type>>>::value();
auto hash = entt::type_hash<std::remove_cvref_t<a_type>>::value();
```
* The name associated with a given type:
@@ -663,7 +660,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_const_t<std::remove_reference_t<a_type>>>::value();
auto name = entt::type_name<std::remove_cvref_t<a_type>>::value();
```
Where all accessed features are available at compile-time, the `type_info` class
@@ -919,10 +916,6 @@ It is not possible to escape the temptation to add utilities of some kind to a
library. In fact, `EnTT` also provides a handful of tools to simplify the
life of developers:
* `entt::identity`: the identity function object that will be available with
C++20. It returns its argument unchanged and nothing more. It is useful as a
sort of _do nothing_ function in template programming.
* `entt::overload`: a tool to disambiguate different overloads from their
function type. It works with both free and member functions.<br/>
Consider the following definition:

View File

@@ -1035,9 +1035,10 @@ registry.ctx().erase<my_type>();
registry.ctx().erase<my_type>("my_variable"_hs);
```
A context variable must be both default constructible and movable. If the
supplied type does not match that of the variable when using a _name_, the
operation fails.<br/>
There are no strict requirements on the type of a context variable, such as that
it must be constructible or movable by default. However, if the supplied type
does not match that of the variable when using a _name_, the operation
fails.<br/>
For all users who want to use the context but do not want to create elements,
the `contains` and `find` functions are also available:
@@ -1350,7 +1351,8 @@ struct transform {
The `component_traits` class template takes care of _extracting_ the properties
from the supplied type.<br/>
Plus, it is _sfinae-friendly_ and also supports feature-based specializations.
Plus, it can be specialized and constrained with a concept to further customize
it on a per type or per feature basis.
## Empty type optimization
@@ -1378,7 +1380,7 @@ optimization selectively rather than globally.
## Void storage
A void storage (or `entt::storage<void>` or `entt::basic_storage<Type, void>`),
A void storage (`entt::storage<void>` or `entt::basic_storage<void, Entity>`),
is a fully functional storage type used to create pools not associated with a
particular component type.<br/>
From a technical point of view, it is in all respects similar to a storage for
@@ -1877,7 +1879,7 @@ specific _queries_.<br/>
The type returned when combining multiple elements together is itself a view,
more in general a multi component one.
Combining different elements tries to mimic C++20 ranges:
Combining different elements tries to mimic ranges:
```cpp
auto view = registry.view<position>();

View File

@@ -194,11 +194,11 @@ a solution in this case:
```cpp
template<>
struct entt::type_hash<Type> final {
[[nodiscard]] static constexpr id_type value() noexcept {
[[nodiscard]] static consteval id_type value() noexcept {
return hashed_string::value("Type");
}
[[nodiscard]] constexpr operator id_type() const noexcept {
[[nodiscard]] consteval operator id_type() const noexcept {
return value();
}
};

View File

@@ -145,6 +145,10 @@ I hope the following lists can grow much more in the future.
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`.
* [Bim!](https://github.com/j-jorge/bim): a last-man-standing arcade online
game for Android.
* [MonsterWar](https://github.com/WispSnow/MonsterWar): a tower defense game
developed in C++ with `SDL3`, `EnTT`, and a few other libraries.
## Engines and the like:
@@ -247,6 +251,9 @@ I hope the following lists can grow much more in the future.
(or those yet to be).
* [Physecs](https://github.com/thfProjects/Physecs): real-time 3D rigid body
physics simulation built on `EnTT`.
* [KODZA](https://gitlab.com/arqitek/kodza/): A work in progress game engine.
* [Omnix](https://github.com/Ace-codes-swift/Omnix): An under-development,
multi-purpose 3D engine for `macOS`, using `EnTT` for the ECS.
## Articles, videos and blog posts:

View File

@@ -335,31 +335,27 @@ Moreover, _containers_ does not necessarily mean those offered by the C++
standard library. In fact, user defined data structures can also work with the
meta system in many cases.
To make a container be recognized as such by the meta system, users are required
to provide specializations for either the `meta_sequence_container_traits` class
or the `meta_associative_container_traits` class, according to the actual _type_
of the container.<br/>
`EnTT` already exports the specializations for some common classes. In
particular:
Containers are automatically _detected_ based on some common _traits_.<br/>
For example, and not limited to, a sequence container must have a `begin`/`end`
pair that returns a forward iterator, while an associative container must also
provide a `key_type` member and a `find` function.<br/>
If a container is not recognized as such, it is still possible to provide an
_adapter_ by specializing the template classes `meta_sequence_container_traits`
and `meta_associative_container_traits`. Similarly, users can _inhibit_ the
detection of a type as a meta container by specializing the right traits class
but without providing any definition.
* `std::vector`, `std::array`, `std::deque` and `std::list` (but not
`std::forward_list`) are supported as _sequence containers_.
* `std::map`, `std::set` and their unordered counterparts are supported as
_associative containers_.
It is important to include the header file `container.hpp` to make these
specializations available to the compiler when needed.<br/>
The same file also contains many examples for the users that are interested in
Standard library containers are generally exported as meta containers out of the
box (with the exception of `std::string`, which is not considered a sequence
container on purpose).<br/>
However, it is important to include the header file `container.hpp` to make
the right specializations available to the compiler when needed.<br/>
The same file also contains some examples for the users that are interested in
making their own containers available to the meta system.
When a specialization of the `meta_sequence_container_traits` class exists, the
meta system treats the wrapped type as a sequence container. In a similar way,
a type is treated as an associative container if a specialization of the
`meta_associative_container_traits` class is found for it.<br/>
Proxy objects are returned by dedicated members of the `meta_any` class. The
following is a deliberately verbose example of how users can access a proxy
object for a sequence container:
For meta containers, the `meta_any` class returns properly initialized proxy
objects for ease of use. The following is a deliberately verbose example of how
users can access a proxy object for a sequence container:
```cpp
std::vector<int> vec{1, 2, 3};
@@ -372,7 +368,7 @@ if(any.type().is_sequence_container()) {
}
```
The method to use to get a proxy object for associative containers is
Proxy object for associative containers are accessed in the same way by calling
`as_associative_container` instead.<br/>
It is not necessary to perform a double check actually. Instead, it is enough to
query the meta type or verify that the proxy object is valid. In fact, proxies

View File

@@ -230,14 +230,14 @@ For a deduced concept, inheritance is achieved in a few steps:
```cpp
struct DrawableAndErasable: entt::type_list<> {
template<typename Base>
struct type: typename Drawable::type<Base> {
struct type: Drawable::type<Base> {
static constexpr auto base = Drawable::impl<Drawable::type<entt::poly_inspector>>::size;
void erase() { entt::poly_call<base + 0>(*this); }
};
template<typename Type>
using impl = entt::value_list_cat_t<
typename Drawable::impl<Type>,
Drawable::impl<Type>,
entt::value_list<&Type::erase>
>;
};

View File

@@ -57,8 +57,8 @@ Here is a minimal example for the sake of curiosity:
```cpp
struct my_process: entt::process {
using allocator_type = typename entt::process::allocator_type;
using delta_type = typename entt::process::delta_type;
using allocator_type = entt::process::allocator_type;
using delta_type = entt::process::delta_type;
my_process(const allocator_type &allocator, delta_type delay)
: entt::process{allocator},

View File

@@ -9,6 +9,7 @@
* [Raw access](#raw-access)
* [Signals](#signals)
* [Event dispatcher](#event-dispatcher)
* [Connect, disconnect, publish](#connect-disconnect-publish)]
* [Named queues](#named-queues)
* [Event emitter](#event-emitter)
@@ -382,34 +383,45 @@ signal.collect(std::ref(collector));
# Event dispatcher
The event dispatcher class allows users to trigger immediate events or to queue
and publish them all together later.<br/>
This class lazily instantiates its queues. Therefore, it is not necessary to
_announce_ the event types in advance:
and publish them all together later:
```cpp
// define a general purpose dispatcher
entt::dispatcher dispatcher{};
```
A listener registered with a dispatcher is such that its type offers one or more
member functions that take arguments of type `Event &` for any type of event,
regardless of the return value.<br/>
These functions are linked directly via `connect` to a _sink_:
This class lazily instantiates its queues. Therefore, it is not necessary to
_announce_ the event types in advance.
## Connect, disconnect, publish
Listeners registered with a dispatcher are mainly of two types: free and member
functions. Lambdas as template functions are also accepted and belong to the
first group.<br/>
In all cases, a listener accepts an argument of type `Event &` for any type
of event, regardless of the return value.
Listeners are linked directly via `connect` to a _sink_ object:
```cpp
struct an_event { int value; };
struct another_event {};
void on_event(const an_event &event) { /* ... */ }
struct listener {
void receive(const an_event &) { /* ... */ }
void method(const another_event &) { /* ... */ }
// Member function listener
void on_event(const another_event &) { /* ... */ }
};
// ...
// free function listener
dispatcher.sink<an_event>().connect<&on_event>();
listener listener;
dispatcher.sink<an_event>().connect<&listener::receive>(listener);
dispatcher.sink<another_event>().connect<&listener::method>(listener);
// member function listener
dispatcher.sink<another_event>().connect<&listener::on_event>(listener);
```
Note that connecting listeners within event handlers can result in undefined
@@ -418,7 +430,13 @@ The `disconnect` member function is used to remove one listener at a time or all
of them at once:
```cpp
dispatcher.sink<an_event>().disconnect<&listener::receive>(listener);
// disconnects a free function
dispatcher.sink<an_event>().disconnect<&on_event>();
// disconnect a member function of an instance
dispatcher.sink<another_event>().disconnect<&listener::on_event>(listener);
// disconnect all member functions of an instance, if any
dispatcher.sink<another_event>().disconnect(&listener);
```
@@ -427,7 +445,7 @@ to all the listeners registered so far:
```cpp
dispatcher.trigger(an_event{42});
dispatcher.trigger<another_event>();
dispatcher.trigger(another_event{});
```
Listeners are invoked immediately, order of execution is not guaranteed. This

View File

@@ -1,103 +0,0 @@
# EnTT and Unreal Engine
# Table of Contents
* [Enable Cpp17](#enable-cpp17)
* [EnTT as a third party module](#entt-as-a-third-party-module)
* [Include EnTT](#include-entt)
## Enable Cpp17
> Skip this part if you are working with UE5, Since UE5 uses cpp17 by default.
As of writing (Unreal Engine v4.25), the default C++ standard of Unreal Engine
is C++14.<br/>
On the other hand, note that `EnTT` requires C++17 to compile. To enable it, in
the main module of the project there should be a `<Game Name>.Build.cs` file,
the constructor of which must contain the following lines:
```cs
PCHUsage = PCHUsageMode.NoSharedPCHs;
PrivatePCHHeaderFile = "<PCH filename>.h";
CppStandard = CppStandardVersion.Cpp17;
```
Replace `<PCH filename>.h` with the name of the already existing PCH header
file, if any.<br/>
In case the project does not already contain a file of this type, it is possible
to create one with the following content:
```cpp
#pragma once
#include "CoreMinimal.h"
```
Remember to remove any old `PCHUsage = <...>` line that was previously there. At
this point, C++17 support should be in place.<br/>
Try to compile the project to ensure it works as expected before following
further steps.
Note that updating a *project* to C++17 does not necessarily mean that the IDE
in use will also start to recognize its syntax.<br/>
If the plan is to use C++17 in the project too, check the specific instructions
for the IDE in use.
## EnTT as a third party module
Once this point is reached, the `Source` directory should look like this:
```
Source
| MyGame.Target.cs
| MyGameEditor.Target.cs
|
+---MyGame
| | MyGame.Build.cs
| | MyGame.h (PCH Header file)
|
\---ThirdParty
\---EnTT
| EnTT.Build.cs
|
\---entt (GitHub repository content inside)
```
To make this happen, create the folder `ThirdParty` under `Source` if it does
not exist already. Then, add an `EnTT` folder under `ThirdParty`.<br/>
Within the latter, create a new file `EnTT.Build.cs` with the following content:
```cs
using System.IO;
using UnrealBuildTool;
public class EnTT: ModuleRules {
public EnTT(ReadOnlyTargetRules Target) : base(Target) {
Type = ModuleType.External;
PublicIncludePaths.Add(Path.Combine(ModuleDirectory, "entt", "src", "entt"));
}
}
```
The last line indicates that the actual files will be found in the directory
`EnTT/entt/src/entt`.<br/>
Download the repository for `EnTT` and place it next to `EnTT.Build.cs` or
update the path above accordingly.
Finally, open the `<Game Name>.Build.cs` file and add `EnTT` as a dependency at
the end of the list:
```cs
PublicDependencyModuleNames.AddRange(new[] {
"Core", "CoreUObject", "Engine", "InputCore", [...], "EnTT"
});
```
Note that some IDEs might require a restart to start recognizing the new module
for code-highlighting features and such.
## Include EnTT
In any source file of the project, add `#include "entt.hpp"` or any other path
to the file from `EnTT` to use it.<br/>
Try to create a registry as `entt::registry registry;` to make sure everything
compiles fine.

View File

@@ -1,46 +1,47 @@
#ifndef ENTT_CONFIG_CONFIG_H
#define ENTT_CONFIG_CONFIG_H
#if __has_include(<entt/ext/config.h>)
# include <entt/ext/config.h>
#endif
#include <version>
#include "version.h"
// NOLINTBEGIN(cppcoreguidelines-macro-usage)
#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION)
# define ENTT_CONSTEXPR
#ifdef ENTT_USE_STL
# define ENTT_FORCE_STL
#endif
#if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION)
# define ENTT_THROW throw
# define ENTT_TRY try
# define ENTT_CATCH catch(...)
#else
# define ENTT_CONSTEXPR constexpr // use only with throwing functions (waiting for C++20)
# define ENTT_THROW
# define ENTT_TRY if(true)
# define ENTT_CATCH if(false)
#endif
#if __has_include(<version>)
# include <version>
#
# if defined(__cpp_consteval)
# define ENTT_CONSTEVAL consteval
# endif
#endif
#ifndef ENTT_CONSTEVAL
#if defined(__cpp_consteval)
# define ENTT_CONSTEVAL consteval
#else
# define ENTT_CONSTEVAL constexpr
#endif
#ifdef ENTT_USE_ATOMIC
# include <atomic>
# define ENTT_MAYBE_ATOMIC(Type) std::atomic<Type>
# include "../stl/atomic.hpp"
# define ENTT_MAYBE_ATOMIC(Type) stl::atomic<Type>
#else
# define ENTT_MAYBE_ATOMIC(Type) Type
#endif
#ifndef ENTT_ID_TYPE
# include <cstdint>
# define ENTT_ID_TYPE std::uint32_t
# include "../stl/cstdint.hpp"
# define ENTT_ID_TYPE stl::uint32_t
#else
# include <cstdint> // provides coverage for types in the std namespace
# include "../stl/cstdint.hpp" // provides coverage for types in the std namespace
#endif
#ifndef ENTT_SPARSE_PAGE

View File

@@ -5,8 +5,8 @@
// NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*)
#define ENTT_VERSION_MAJOR 3
#define ENTT_VERSION_MINOR 16
#define ENTT_VERSION_MAJOR 4
#define ENTT_VERSION_MINOR 0
#define ENTT_VERSION_PATCH 0
#define ENTT_VERSION \

View File

@@ -1,56 +1,57 @@
#ifndef ENTT_CONTAINER_DENSE_MAP_HPP
#define ENTT_CONTAINER_DENSE_MAP_HPP
#include <cmath>
#include <cstddef>
#include <functional>
#include <iterator>
#include <limits>
#include <memory>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
#include <compare>
#include "../config/config.h"
#include "../core/bit.hpp"
#include "../core/compressed_pair.hpp"
#include "../core/iterator.hpp"
#include "../core/memory.hpp"
#include "../core/type_traits.hpp"
#include "../stl/bit.hpp"
#include "../stl/cmath.hpp"
#include "../stl/concepts.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/functional.hpp"
#include "../stl/iterator.hpp"
#include "../stl/limits.hpp"
#include "../stl/memory.hpp"
#include "../stl/tuple.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "../stl/vector.hpp"
#include "fwd.hpp"
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
static constexpr std::size_t dense_map_placeholder_position = (std::numeric_limits<std::size_t>::max)();
static constexpr stl::size_t dense_map_placeholder_position = (stl::numeric_limits<stl::size_t>::max)();
template<typename Key, typename Type>
struct dense_map_node final {
using value_type = std::pair<Key, Type>;
using value_type = stl::pair<Key, Type>;
template<typename... Args>
dense_map_node(const std::size_t pos, Args &&...args)
dense_map_node(const stl::size_t pos, Args &&...args)
: next{pos},
element{std::forward<Args>(args)...} {}
element{stl::forward<Args>(args)...} {}
template<typename Allocator, typename... Args>
dense_map_node(std::allocator_arg_t, const Allocator &allocator, const std::size_t pos, Args &&...args)
template<typename... Args>
dense_map_node(stl::allocator_arg_t, const auto &allocator, const stl::size_t pos, Args &&...args)
: next{pos},
element{entt::make_obj_using_allocator<value_type>(allocator, std::forward<Args>(args)...)} {}
element{entt::make_obj_using_allocator<value_type>(allocator, stl::forward<Args>(args)...)} {}
template<typename Allocator>
dense_map_node(std::allocator_arg_t, const Allocator &allocator, const dense_map_node &other)
dense_map_node(stl::allocator_arg_t, const auto &allocator, const dense_map_node &other)
: next{other.next},
element{entt::make_obj_using_allocator<value_type>(allocator, other.element)} {}
template<typename Allocator>
dense_map_node(std::allocator_arg_t, const Allocator &allocator, dense_map_node &&other)
dense_map_node(stl::allocator_arg_t, const auto &allocator, dense_map_node &&other)
: next{other.next},
element{entt::make_obj_using_allocator<value_type>(allocator, std::move(other.element))} {}
element{entt::make_obj_using_allocator<value_type>(allocator, stl::move(other.element))} {}
std::size_t next;
stl::size_t next;
value_type element;
};
@@ -59,16 +60,17 @@ class dense_map_iterator final {
template<typename>
friend class dense_map_iterator;
using first_type = decltype(std::as_const(std::declval<It>()->element.first));
using second_type = decltype((std::declval<It>()->element.second));
static_assert(stl::is_pointer_v<It>, "Not a pointer type");
using first_type = decltype(stl::as_const(stl::declval<It>()->element.first));
using second_type = decltype((stl::declval<It>()->element.second));
public:
using value_type = std::pair<first_type, second_type>;
using value_type = stl::pair<first_type, second_type>;
using pointer = input_iterator_pointer<value_type>;
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category = std::input_iterator_tag;
using iterator_concept = std::random_access_iterator_tag;
using difference_type = stl::ptrdiff_t;
using iterator_category = stl::input_iterator_tag;
using iterator_concept = stl::random_access_iterator_tag;
constexpr dense_map_iterator() noexcept
: it{} {}
@@ -76,7 +78,8 @@ public:
constexpr dense_map_iterator(const It iter) noexcept
: it{iter} {}
template<typename Other, typename = std::enable_if_t<!std::is_same_v<It, Other> && std::is_constructible_v<It, Other>>>
template<typename Other>
requires (!stl::same_as<It, Other> && stl::constructible_from<It, Other>)
constexpr dense_map_iterator(const dense_map_iterator<Other> &other) noexcept
: it{other.it} {}
@@ -128,83 +131,56 @@ public:
return operator[](0);
}
template<typename Lhs, typename Rhs>
friend constexpr std::ptrdiff_t operator-(const dense_map_iterator<Lhs> &, const dense_map_iterator<Rhs> &) noexcept;
template<typename Other>
[[nodiscard]] constexpr stl::ptrdiff_t operator-(const dense_map_iterator<Other> &other) const noexcept {
return it - other.it;
}
template<typename Lhs, typename Rhs>
friend constexpr bool operator==(const dense_map_iterator<Lhs> &, const dense_map_iterator<Rhs> &) noexcept;
template<typename Other>
[[nodiscard]] constexpr bool operator==(const dense_map_iterator<Other> &other) const noexcept {
return it == other.it;
}
template<typename Lhs, typename Rhs>
friend constexpr bool operator<(const dense_map_iterator<Lhs> &, const dense_map_iterator<Rhs> &) noexcept;
template<typename Other>
[[nodiscard]] constexpr auto operator<=>(const dense_map_iterator<Other> &other) const noexcept {
return it <=> other.it;
}
private:
It it;
};
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr std::ptrdiff_t operator-(const dense_map_iterator<Lhs> &lhs, const dense_map_iterator<Rhs> &rhs) noexcept {
return lhs.it - rhs.it;
}
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr bool operator==(const dense_map_iterator<Lhs> &lhs, const dense_map_iterator<Rhs> &rhs) noexcept {
return lhs.it == rhs.it;
}
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr bool operator!=(const dense_map_iterator<Lhs> &lhs, const dense_map_iterator<Rhs> &rhs) noexcept {
return !(lhs == rhs);
}
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr bool operator<(const dense_map_iterator<Lhs> &lhs, const dense_map_iterator<Rhs> &rhs) noexcept {
return lhs.it < rhs.it;
}
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr bool operator>(const dense_map_iterator<Lhs> &lhs, const dense_map_iterator<Rhs> &rhs) noexcept {
return rhs < lhs;
}
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr bool operator<=(const dense_map_iterator<Lhs> &lhs, const dense_map_iterator<Rhs> &rhs) noexcept {
return !(lhs > rhs);
}
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr bool operator>=(const dense_map_iterator<Lhs> &lhs, const dense_map_iterator<Rhs> &rhs) noexcept {
return !(lhs < rhs);
}
template<typename It>
class dense_map_local_iterator final {
template<typename>
friend class dense_map_local_iterator;
using first_type = decltype(std::as_const(std::declval<It>()->element.first));
using second_type = decltype((std::declval<It>()->element.second));
static_assert(stl::is_pointer_v<It>, "Not a pointer type");
using first_type = decltype(stl::as_const(stl::declval<It>()->element.first));
using second_type = decltype((stl::declval<It>()->element.second));
public:
using value_type = std::pair<first_type, second_type>;
using value_type = stl::pair<first_type, second_type>;
using pointer = input_iterator_pointer<value_type>;
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category = std::input_iterator_tag;
using iterator_concept = std::forward_iterator_tag;
using difference_type = stl::ptrdiff_t;
using iterator_category = stl::input_iterator_tag;
using iterator_concept = stl::forward_iterator_tag;
constexpr dense_map_local_iterator() noexcept = default;
constexpr dense_map_local_iterator(It iter, const std::size_t pos) noexcept
constexpr dense_map_local_iterator(It iter, const stl::size_t pos) noexcept
: it{iter},
offset{pos} {}
template<typename Other, typename = std::enable_if_t<!std::is_same_v<It, Other> && std::is_constructible_v<It, Other>>>
template<typename Other>
requires (!stl::same_as<It, Other> && stl::constructible_from<It, Other>)
constexpr dense_map_local_iterator(const dense_map_local_iterator<Other> &other) noexcept
: it{other.it},
offset{other.offset} {}
constexpr dense_map_local_iterator &operator++() noexcept {
return (offset = it[static_cast<typename It::difference_type>(offset)].next), *this;
return (offset = it[static_cast<difference_type>(offset)].next), *this;
}
constexpr dense_map_local_iterator operator++(int) noexcept {
@@ -217,29 +193,24 @@ public:
}
[[nodiscard]] constexpr reference operator*() const noexcept {
const auto idx = static_cast<typename It::difference_type>(offset);
const auto idx = static_cast<difference_type>(offset);
return {it[idx].element.first, it[idx].element.second};
}
[[nodiscard]] constexpr std::size_t index() const noexcept {
template<typename Other>
[[nodiscard]] constexpr bool operator==(const dense_map_local_iterator<Other> &other) const noexcept {
return offset == other.offset;
}
[[nodiscard]] constexpr stl::size_t index() const noexcept {
return offset;
}
private:
It it{};
std::size_t offset{dense_map_placeholder_position};
stl::size_t offset{dense_map_placeholder_position};
};
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr bool operator==(const dense_map_local_iterator<Lhs> &lhs, const dense_map_local_iterator<Rhs> &rhs) noexcept {
return lhs.index() == rhs.index();
}
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr bool operator!=(const dense_map_local_iterator<Lhs> &lhs, const dense_map_local_iterator<Rhs> &rhs) noexcept {
return !(lhs == rhs);
}
} // namespace internal
/*! @endcond */
@@ -259,37 +230,34 @@ template<typename Lhs, typename Rhs>
template<typename Key, typename Type, typename Hash, typename KeyEqual, typename Allocator>
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;
static constexpr stl::size_t minimum_capacity = 8u;
static constexpr stl::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>;
static_assert(std::is_same_v<typename alloc_traits::value_type, std::pair<const Key, Type>>, "Invalid value type");
using sparse_container_type = std::vector<std::size_t, typename alloc_traits::template rebind_alloc<std::size_t>>;
using packed_container_type = std::vector<node_type, typename alloc_traits::template rebind_alloc<node_type>>;
using alloc_traits = stl::allocator_traits<Allocator>;
static_assert(stl::is_same_v<typename alloc_traits::value_type, stl::pair<const Key, Type>>, "Invalid value type");
using sparse_container_type = stl::vector<stl::size_t, typename alloc_traits::template rebind_alloc<stl::size_t>>;
using packed_container_type = stl::vector<node_type, typename alloc_traits::template rebind_alloc<node_type>>;
template<typename Other>
[[nodiscard]] std::size_t key_to_bucket(const Other &key) const noexcept {
[[nodiscard]] stl::size_t key_to_bucket(const auto &key) const noexcept {
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
return fast_mod(static_cast<size_type>(sparse.second()(key)), bucket_count());
}
template<typename Other>
[[nodiscard]] auto constrained_find(const Other &key, const std::size_t bucket) {
[[nodiscard]] auto constrained_find(const auto &key, const stl::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);
return begin() + static_cast<iterator::difference_type>(offset);
}
}
return end();
}
template<typename Other>
[[nodiscard]] auto constrained_find(const Other &key, const std::size_t bucket) const {
[[nodiscard]] auto constrained_find(const auto &key, const stl::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);
return cbegin() + static_cast<const_iterator::difference_type>(offset);
}
}
@@ -301,14 +269,14 @@ class dense_map {
const auto index = key_to_bucket(key);
if(auto it = constrained_find(key, index); it != end()) {
return std::make_pair(it, false);
return stl::make_pair(it, false);
}
packed.first().emplace_back(sparse.first()[index], std::piecewise_construct, std::forward_as_tuple(std::forward<Other>(key)), std::forward_as_tuple(std::forward<Args>(args)...));
packed.first().emplace_back(sparse.first()[index], stl::piecewise_construct, stl::forward_as_tuple(stl::forward<Other>(key)), stl::forward_as_tuple(stl::forward<Args>(args)...));
sparse.first()[index] = packed.first().size() - 1u;
rehash_if_required();
return std::make_pair(--end(), true);
return stl::make_pair(--end(), true);
}
template<typename Other, typename Arg>
@@ -316,21 +284,21 @@ class dense_map {
const auto index = key_to_bucket(key);
if(auto it = constrained_find(key, index); it != end()) {
it->second = std::forward<Arg>(value);
return std::make_pair(it, false);
it->second = stl::forward<Arg>(value);
return stl::make_pair(it, false);
}
packed.first().emplace_back(sparse.first()[index], std::forward<Other>(key), std::forward<Arg>(value));
packed.first().emplace_back(sparse.first()[index], stl::forward<Other>(key), stl::forward<Arg>(value));
sparse.first()[index] = packed.first().size() - 1u;
rehash_if_required();
return std::make_pair(--end(), true);
return stl::make_pair(--end(), true);
}
void move_and_pop(const std::size_t pos) {
void move_and_pop(const stl::size_t pos) {
if(const auto last = size() - 1u; pos != last) {
size_type *curr = &sparse.first()[key_to_bucket(packed.first().back().element.first)];
packed.first()[pos] = std::move(packed.first().back());
packed.first()[pos] = stl::move(packed.first().back());
for(; *curr != last; curr = &packed.first()[*curr].next) {}
*curr = pos;
}
@@ -352,23 +320,23 @@ public:
/*! @brief Mapped type of the container. */
using mapped_type = Type;
/*! @brief Key-value type of the container. */
using value_type = std::pair<const Key, Type>;
using value_type = stl::pair<const Key, Type>;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
using size_type = stl::size_t;
/*! @brief Signed integer type. */
using difference_type = std::ptrdiff_t;
using difference_type = stl::ptrdiff_t;
/*! @brief Type of function to use to hash the keys. */
using hasher = Hash;
/*! @brief Type of function to use to compare the keys for equality. */
using key_equal = KeyEqual;
/*! @brief Input iterator type. */
using iterator = internal::dense_map_iterator<typename packed_container_type::iterator>;
using iterator = internal::dense_map_iterator<typename packed_container_type::pointer>;
/*! @brief Constant input iterator type. */
using const_iterator = internal::dense_map_iterator<typename packed_container_type::const_iterator>;
using const_iterator = internal::dense_map_iterator<typename packed_container_type::const_pointer>;
/*! @brief Input iterator type. */
using local_iterator = internal::dense_map_local_iterator<typename packed_container_type::iterator>;
using local_iterator = internal::dense_map_local_iterator<typename packed_container_type::pointer>;
/*! @brief Constant input iterator type. */
using const_local_iterator = internal::dense_map_local_iterator<typename packed_container_type::const_iterator>;
using const_local_iterator = internal::dense_map_local_iterator<typename packed_container_type::const_pointer>;
/*! @brief Default constructor. */
dense_map()
@@ -423,8 +391,8 @@ public:
* @param allocator The allocator to use.
*/
dense_map(const dense_map &other, const allocator_type &allocator)
: sparse{std::piecewise_construct, std::forward_as_tuple(other.sparse.first(), allocator), std::forward_as_tuple(other.sparse.second())},
packed{std::piecewise_construct, std::forward_as_tuple(other.packed.first(), allocator), std::forward_as_tuple(other.packed.second())},
: sparse{stl::piecewise_construct, stl::forward_as_tuple(other.sparse.first(), allocator), stl::forward_as_tuple(other.sparse.second())},
packed{stl::piecewise_construct, stl::forward_as_tuple(other.packed.first(), allocator), stl::forward_as_tuple(other.packed.second())},
threshold{other.threshold} {}
/*! @brief Default move constructor. */
@@ -436,8 +404,8 @@ public:
* @param allocator The allocator to use.
*/
dense_map(dense_map &&other, const allocator_type &allocator)
: sparse{std::piecewise_construct, std::forward_as_tuple(std::move(other.sparse.first()), allocator), std::forward_as_tuple(std::move(other.sparse.second()))},
packed{std::piecewise_construct, std::forward_as_tuple(std::move(other.packed.first()), allocator), std::forward_as_tuple(std::move(other.packed.second()))},
: sparse{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.sparse.first()), allocator), stl::forward_as_tuple(stl::move(other.sparse.second()))},
packed{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.packed.first()), allocator), stl::forward_as_tuple(stl::move(other.packed.second()))},
threshold{other.threshold} {}
/*! @brief Default destructor. */
@@ -460,7 +428,7 @@ public:
* @param other Container to exchange the content with.
*/
void swap(dense_map &other) noexcept {
using std::swap;
using stl::swap;
swap(sparse, other.sparse);
swap(packed, other.packed);
swap(threshold, other.threshold);
@@ -482,7 +450,7 @@ public:
* @return An iterator to the first instance of the internal array.
*/
[[nodiscard]] const_iterator cbegin() const noexcept {
return packed.first().begin();
return packed.first().data();
}
/*! @copydoc cbegin */
@@ -492,7 +460,7 @@ public:
/*! @copydoc begin */
[[nodiscard]] iterator begin() noexcept {
return packed.first().begin();
return packed.first().data();
}
/**
@@ -501,7 +469,7 @@ public:
* internal array.
*/
[[nodiscard]] const_iterator cend() const noexcept {
return packed.first().end();
return packed.first().data() + packed.first().size();
}
/*! @copydoc cend */
@@ -511,7 +479,7 @@ public:
/*! @copydoc end */
[[nodiscard]] iterator end() noexcept {
return packed.first().end();
return packed.first().data() + packed.first().size();
}
/**
@@ -552,13 +520,13 @@ public:
* the element that prevented the insertion) and a bool denoting whether the
* insertion took place.
*/
std::pair<iterator, bool> insert(const value_type &value) {
stl::pair<iterator, bool> insert(const value_type &value) {
return insert_or_do_nothing(value.first, value.second);
}
/*! @copydoc insert */
std::pair<iterator, bool> insert(value_type &&value) {
return insert_or_do_nothing(std::move(value.first), std::move(value.second));
stl::pair<iterator, bool> insert(value_type &&value) {
return insert_or_do_nothing(stl::move(value.first), stl::move(value.second));
}
/**
@@ -566,19 +534,17 @@ public:
* @tparam Arg Type of the key-value pair to insert into the container.
*/
template<typename Arg>
std::enable_if_t<std::is_constructible_v<value_type, Arg &&>, std::pair<iterator, bool>>
insert(Arg &&value) {
return insert_or_do_nothing(std::forward<Arg>(value).first, std::forward<Arg>(value).second);
requires stl::constructible_from<value_type, Arg &&>
stl::pair<iterator, bool> insert(Arg &&value) {
return insert_or_do_nothing(stl::forward<Arg>(value).first, stl::forward<Arg>(value).second);
}
/**
* @brief Inserts elements into the container, if their keys do not exist.
* @tparam It Type of input iterator.
* @param first An iterator to the first element of the range of elements.
* @param last An iterator past the last element of the range of elements.
*/
template<typename It>
void insert(It first, It last) {
void insert(stl::input_iterator auto first, stl::input_iterator auto last) {
for(; first != last; ++first) {
insert(*first);
}
@@ -594,14 +560,14 @@ public:
* denoting whether the insertion took place.
*/
template<typename Arg>
std::pair<iterator, bool> insert_or_assign(const key_type &key, Arg &&value) {
return insert_or_overwrite(key, std::forward<Arg>(value));
stl::pair<iterator, bool> insert_or_assign(const key_type &key, Arg &&value) {
return insert_or_overwrite(key, stl::forward<Arg>(value));
}
/*! @copydoc insert_or_assign */
template<typename Arg>
std::pair<iterator, bool> insert_or_assign(key_type &&key, Arg &&value) {
return insert_or_overwrite(std::move(key), std::forward<Arg>(value));
stl::pair<iterator, bool> insert_or_assign(key_type &&key, Arg &&value) {
return insert_or_overwrite(stl::move(key), stl::forward<Arg>(value));
}
/**
@@ -618,26 +584,26 @@ public:
* insertion took place.
*/
template<typename... Args>
std::pair<iterator, bool> emplace([[maybe_unused]] Args &&...args) {
stl::pair<iterator, bool> emplace([[maybe_unused]] Args &&...args) {
if constexpr(sizeof...(Args) == 0u) {
return insert_or_do_nothing(key_type{});
} else if constexpr(sizeof...(Args) == 1u) {
return insert_or_do_nothing(std::forward<Args>(args).first..., std::forward<Args>(args).second...);
return insert_or_do_nothing(stl::forward<Args>(args).first..., stl::forward<Args>(args).second...);
} else if constexpr(sizeof...(Args) == 2u) {
return insert_or_do_nothing(std::forward<Args>(args)...);
return insert_or_do_nothing(stl::forward<Args>(args)...);
} else {
auto &node = packed.first().emplace_back(packed.first().size(), std::forward<Args>(args)...);
auto &node = packed.first().emplace_back(packed.first().size(), stl::forward<Args>(args)...);
const auto index = key_to_bucket(node.element.first);
if(auto it = constrained_find(node.element.first, index); it != end()) {
packed.first().pop_back();
return std::make_pair(it, false);
return stl::make_pair(it, false);
}
std::swap(node.next, sparse.first()[index]);
stl::swap(node.next, sparse.first()[index]);
rehash_if_required();
return std::make_pair(--end(), true);
return stl::make_pair(--end(), true);
}
}
@@ -653,14 +619,14 @@ public:
* insertion took place.
*/
template<typename... Args>
std::pair<iterator, bool> try_emplace(const key_type &key, Args &&...args) {
return insert_or_do_nothing(key, std::forward<Args>(args)...);
stl::pair<iterator, bool> try_emplace(const key_type &key, Args &&...args) {
return insert_or_do_nothing(key, stl::forward<Args>(args)...);
}
/*! @copydoc try_emplace */
template<typename... Args>
std::pair<iterator, bool> try_emplace(key_type &&key, Args &&...args) {
return insert_or_do_nothing(std::move(key), std::forward<Args>(args)...);
stl::pair<iterator, bool> try_emplace(key_type &&key, Args &&...args) {
return insert_or_do_nothing(stl::move(key), stl::forward<Args>(args)...);
}
/**
@@ -728,22 +694,19 @@ public:
/**
* @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 {
[[nodiscard]] mapped_type const &at(const auto &key) const
requires is_transparent_v<hasher> && is_transparent_v<key_equal> {
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) {
[[nodiscard]] mapped_type &at(const auto &key)
requires is_transparent_v<hasher> && is_transparent_v<key_equal> {
auto it = find(key);
ENTT_ASSERT(it != end(), "Invalid key");
return it->second;
@@ -764,7 +727,7 @@ public:
* @return A reference to the mapped value of the requested element.
*/
[[nodiscard]] mapped_type &operator[](key_type &&key) {
return insert_or_do_nothing(std::move(key)).first->second;
return insert_or_do_nothing(stl::move(key)).first->second;
}
/**
@@ -778,13 +741,11 @@ public:
/**
* @brief Returns the number of elements matching a key (either 1 or 0).
* @tparam Other Type of the key value of an element to search for.
* @param key Key value of an element to search for.
* @return Number of elements matching the key (either 1 or 0).
*/
template<typename Other>
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, size_type>>
count(const Other &key) const {
[[nodiscard]] size_type count(const auto &key) const
requires is_transparent_v<hasher> && is_transparent_v<key_equal> {
return find(key) != end();
}
@@ -806,21 +767,18 @@ public:
/**
* @brief Finds an element with a key that compares _equivalent_ to a given
* key.
* @tparam Other Type of the key value of an element to search for.
* @param key Key value of an element to search for.
* @return An iterator to an element with the given key. If no such element
* is found, a past-the-end iterator is returned.
*/
template<typename Other>
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, iterator>>
find(const Other &key) {
[[nodiscard]] iterator find(const auto &key)
requires is_transparent_v<hasher> && is_transparent_v<key_equal> {
return constrained_find(key, key_to_bucket(key));
}
/*! @copydoc find */
template<typename Other>
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, const_iterator>>
find(const Other &key) const {
[[nodiscard]] const_iterator find(const auto &key) const
requires is_transparent_v<hasher> && is_transparent_v<key_equal> {
return constrained_find(key, key_to_bucket(key));
}
@@ -830,13 +788,13 @@ public:
* @return A pair of iterators pointing to the first element and past the
* last element of the range.
*/
[[nodiscard]] std::pair<iterator, iterator> equal_range(const key_type &key) {
[[nodiscard]] stl::pair<iterator, iterator> equal_range(const key_type &key) {
const auto it = find(key);
return {it, it + !(it == end())};
}
/*! @copydoc equal_range */
[[nodiscard]] std::pair<const_iterator, const_iterator> equal_range(const key_type &key) const {
[[nodiscard]] stl::pair<const_iterator, const_iterator> equal_range(const key_type &key) const {
const auto it = find(key);
return {it, it + !(it == cend())};
}
@@ -844,22 +802,19 @@ public:
/**
* @brief Returns a range containing all elements that compare _equivalent_
* to a given key.
* @tparam Other Type of an element to search for.
* @param key Key value of an element to search for.
* @return A pair of iterators pointing to the first element and past the
* last element of the range.
*/
template<typename Other>
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, std::pair<iterator, iterator>>>
equal_range(const Other &key) {
[[nodiscard]] stl::pair<iterator, iterator> equal_range(const auto &key)
requires is_transparent_v<hasher> && is_transparent_v<key_equal> {
const auto it = find(key);
return {it, it + !(it == end())};
}
/*! @copydoc equal_range */
template<typename Other>
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, std::pair<const_iterator, const_iterator>>>
equal_range(const Other &key) const {
[[nodiscard]] stl::pair<const_iterator, const_iterator> equal_range(const auto &key) const
requires is_transparent_v<hasher> && is_transparent_v<key_equal> {
const auto it = find(key);
return {it, it + !(it == cend())};
}
@@ -876,13 +831,11 @@ public:
/**
* @brief Checks if the container contains an element with a key that
* compares _equivalent_ to a given value.
* @tparam Other Type of the key value of an element to search for.
* @param key Key value of an element to search for.
* @return True if there is such an element, false otherwise.
*/
template<typename Other>
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, bool>>
contains(const Other &key) const {
[[nodiscard]] bool contains(const auto &key) const
requires is_transparent_v<hasher> && is_transparent_v<key_equal> {
return (find(key) != cend());
}
@@ -892,7 +845,7 @@ public:
* @return An iterator to the beginning of the given bucket.
*/
[[nodiscard]] const_local_iterator cbegin(const size_type index) const {
return {packed.first().begin(), sparse.first()[index]};
return {packed.first().data(), sparse.first()[index]};
}
/**
@@ -910,7 +863,7 @@ public:
* @return An iterator to the beginning of the given bucket.
*/
[[nodiscard]] local_iterator begin(const size_type index) {
return {packed.first().begin(), sparse.first()[index]};
return {packed.first().data(), sparse.first()[index]};
}
/**
@@ -962,7 +915,7 @@ public:
* @return The number of elements in the given bucket.
*/
[[nodiscard]] size_type bucket_size(const size_type index) const {
return static_cast<size_type>(std::distance(begin(index), end(index)));
return static_cast<size_type>(stl::distance(begin(index), end(index)));
}
/**
@@ -1010,7 +963,7 @@ public:
const auto cap = static_cast<size_type>(static_cast<float>(size()) / max_load_factor());
value = value > cap ? value : cap;
if(const auto sz = next_power_of_two(value); sz != bucket_count()) {
if(const auto sz = stl::bit_ceil(value); sz != bucket_count()) {
sparse.first().resize(sz);
for(auto &&elem: sparse.first()) {
@@ -1019,7 +972,7 @@ public:
for(size_type pos{}, last = size(); pos < last; ++pos) {
const auto index = key_to_bucket(packed.first()[pos].element.first);
packed.first()[pos].next = std::exchange(sparse.first()[index], pos);
packed.first()[pos].next = stl::exchange(sparse.first()[index], pos);
}
}
}
@@ -1031,7 +984,7 @@ public:
*/
void reserve(const size_type cnt) {
packed.first().reserve(cnt);
rehash(static_cast<size_type>(std::ceil(static_cast<float>(cnt) / max_load_factor())));
rehash(static_cast<size_type>(stl::ceil(static_cast<float>(cnt) / max_load_factor())));
}
/**
@@ -1058,12 +1011,14 @@ private:
} // namespace entt
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
#include <utility>
namespace std {
template<typename Key, typename Value, typename Allocator>
struct uses_allocator<entt::internal::dense_map_node<Key, Value>, Allocator>
: std::true_type {};
: entt::stl::true_type {};
} // namespace std
/*! @endcond */

View File

@@ -1,40 +1,45 @@
#ifndef ENTT_CONTAINER_DENSE_SET_HPP
#define ENTT_CONTAINER_DENSE_SET_HPP
#include <cmath>
#include <cstddef>
#include <functional>
#include <iterator>
#include <limits>
#include <memory>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
#include <compare>
#include "../config/config.h"
#include "../core/bit.hpp"
#include "../core/compressed_pair.hpp"
#include "../core/type_traits.hpp"
#include "../stl/bit.hpp"
#include "../stl/cmath.hpp"
#include "../stl/concepts.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/functional.hpp"
#include "../stl/iterator.hpp"
#include "../stl/limits.hpp"
#include "../stl/memory.hpp"
#include "../stl/tuple.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "../stl/vector.hpp"
#include "fwd.hpp"
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
static constexpr std::size_t dense_set_placeholder_position = (std::numeric_limits<std::size_t>::max)();
static constexpr stl::size_t dense_set_placeholder_position = (stl::numeric_limits<stl::size_t>::max)();
template<typename It>
class dense_set_iterator final {
template<typename>
friend class dense_set_iterator;
static_assert(stl::is_pointer_v<It>, "Not a pointer type");
public:
using value_type = typename It::value_type::second_type;
using value_type = stl::remove_const_t<stl::remove_pointer_t<It>>::second_type;
using pointer = const value_type *;
using reference = const value_type &;
using difference_type = std::ptrdiff_t;
using iterator_category = std::random_access_iterator_tag;
using difference_type = stl::ptrdiff_t;
using iterator_category = stl::random_access_iterator_tag;
constexpr dense_set_iterator() noexcept
: it{} {}
@@ -42,7 +47,8 @@ public:
constexpr dense_set_iterator(const It iter) noexcept
: it{iter} {}
template<typename Other, typename = std::enable_if_t<!std::is_same_v<It, Other> && std::is_constructible_v<It, Other>>>
template<typename Other>
requires (!stl::same_as<It, Other> && stl::constructible_from<It, Other>)
constexpr dense_set_iterator(const dense_set_iterator<Other> &other) noexcept
: it{other.it} {}
@@ -87,86 +93,60 @@ public:
}
[[nodiscard]] constexpr pointer operator->() const noexcept {
return std::addressof(operator[](0));
return stl::addressof(operator[](0));
}
[[nodiscard]] constexpr reference operator*() const noexcept {
return operator[](0);
}
template<typename Lhs, typename Rhs>
friend constexpr std::ptrdiff_t operator-(const dense_set_iterator<Lhs> &, const dense_set_iterator<Rhs> &) noexcept;
template<typename Other>
[[nodiscard]] constexpr stl::ptrdiff_t operator-(const dense_set_iterator<Other> &other) const noexcept {
return it - other.it;
}
template<typename Lhs, typename Rhs>
friend constexpr bool operator==(const dense_set_iterator<Lhs> &, const dense_set_iterator<Rhs> &) noexcept;
template<typename Other>
[[nodiscard]] constexpr bool operator==(const dense_set_iterator<Other> &other) const noexcept {
return it == other.it;
}
template<typename Lhs, typename Rhs>
friend constexpr bool operator<(const dense_set_iterator<Lhs> &, const dense_set_iterator<Rhs> &) noexcept;
template<typename Other>
[[nodiscard]] constexpr auto operator<=>(const dense_set_iterator<Other> &other) const noexcept {
return it <=> other.it;
}
private:
It it;
};
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr std::ptrdiff_t operator-(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
return lhs.it - rhs.it;
}
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr bool operator==(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
return lhs.it == rhs.it;
}
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr bool operator!=(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
return !(lhs == rhs);
}
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr bool operator<(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
return lhs.it < rhs.it;
}
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr bool operator>(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
return rhs < lhs;
}
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr bool operator<=(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
return !(lhs > rhs);
}
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr bool operator>=(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
return !(lhs < rhs);
}
template<typename It>
class dense_set_local_iterator final {
template<typename>
friend class dense_set_local_iterator;
static_assert(stl::is_pointer_v<It>, "Not a pointer type");
public:
using value_type = typename It::value_type::second_type;
using value_type = stl::remove_const_t<stl::remove_pointer_t<It>>::second_type;
using pointer = const value_type *;
using reference = const value_type &;
using difference_type = std::ptrdiff_t;
using iterator_category = std::forward_iterator_tag;
using difference_type = stl::ptrdiff_t;
using iterator_category = stl::forward_iterator_tag;
constexpr dense_set_local_iterator() noexcept = default;
constexpr dense_set_local_iterator(It iter, const std::size_t pos) noexcept
constexpr dense_set_local_iterator(It iter, const stl::size_t pos) noexcept
: it{iter},
offset{pos} {}
template<typename Other, typename = std::enable_if_t<!std::is_same_v<It, Other> && std::is_constructible_v<It, Other>>>
template<typename Other>
requires (!stl::same_as<It, Other> && stl::constructible_from<It, Other>)
constexpr dense_set_local_iterator(const dense_set_local_iterator<Other> &other) noexcept
: it{other.it},
offset{other.offset} {}
constexpr dense_set_local_iterator &operator++() noexcept {
return offset = it[static_cast<typename It::difference_type>(offset)].first, *this;
return offset = it[static_cast<difference_type>(offset)].first, *this;
}
constexpr dense_set_local_iterator operator++(int) noexcept {
@@ -175,32 +155,27 @@ public:
}
[[nodiscard]] constexpr pointer operator->() const noexcept {
return std::addressof(it[static_cast<typename It::difference_type>(offset)].second);
return stl::addressof(it[static_cast<difference_type>(offset)].second);
}
[[nodiscard]] constexpr reference operator*() const noexcept {
return *operator->();
}
[[nodiscard]] constexpr std::size_t index() const noexcept {
template<typename Other>
[[nodiscard]] constexpr bool operator==(const dense_set_local_iterator<Other> &other) const noexcept {
return offset == other.offset;
}
[[nodiscard]] constexpr stl::size_t index() const noexcept {
return offset;
}
private:
It it{};
std::size_t offset{dense_set_placeholder_position};
stl::size_t offset{dense_set_placeholder_position};
};
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr bool operator==(const dense_set_local_iterator<Lhs> &lhs, const dense_set_local_iterator<Rhs> &rhs) noexcept {
return lhs.index() == rhs.index();
}
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr bool operator!=(const dense_set_local_iterator<Lhs> &lhs, const dense_set_local_iterator<Rhs> &rhs) noexcept {
return !(lhs == rhs);
}
} // namespace internal
/*! @endcond */
@@ -219,36 +194,33 @@ template<typename Lhs, typename Rhs>
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;
static constexpr stl::size_t minimum_capacity = 8u;
static constexpr stl::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>;
static_assert(std::is_same_v<typename alloc_traits::value_type, Type>, "Invalid value type");
using sparse_container_type = std::vector<std::size_t, typename alloc_traits::template rebind_alloc<std::size_t>>;
using packed_container_type = std::vector<node_type, typename alloc_traits::template rebind_alloc<node_type>>;
using node_type = stl::pair<stl::size_t, Type>;
using alloc_traits = stl::allocator_traits<Allocator>;
static_assert(stl::is_same_v<typename alloc_traits::value_type, Type>, "Invalid value type");
using sparse_container_type = stl::vector<stl::size_t, typename alloc_traits::template rebind_alloc<stl::size_t>>;
using packed_container_type = stl::vector<node_type, typename alloc_traits::template rebind_alloc<node_type>>;
template<typename Other>
[[nodiscard]] std::size_t value_to_bucket(const Other &value) const noexcept {
[[nodiscard]] stl::size_t value_to_bucket(const auto &value) const noexcept {
return fast_mod(static_cast<size_type>(sparse.second()(value)), bucket_count());
}
template<typename Other>
[[nodiscard]] auto constrained_find(const Other &value, const std::size_t bucket) {
[[nodiscard]] auto constrained_find(const auto &value, const stl::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);
return begin() + static_cast<iterator::difference_type>(offset);
}
}
return end();
}
template<typename Other>
[[nodiscard]] auto constrained_find(const Other &value, const std::size_t bucket) const {
[[nodiscard]] auto constrained_find(const auto &value, const stl::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);
return cbegin() + static_cast<const_iterator::difference_type>(offset);
}
}
@@ -260,20 +232,20 @@ class dense_set {
const auto index = value_to_bucket(value);
if(auto it = constrained_find(value, index); it != end()) {
return std::make_pair(it, false);
return stl::make_pair(it, false);
}
packed.first().emplace_back(sparse.first()[index], std::forward<Other>(value));
packed.first().emplace_back(sparse.first()[index], stl::forward<Other>(value));
sparse.first()[index] = packed.first().size() - 1u;
rehash_if_required();
return std::make_pair(--end(), true);
return stl::make_pair(--end(), true);
}
void move_and_pop(const std::size_t pos) {
void move_and_pop(const stl::size_t pos) {
if(const auto last = size() - 1u; pos != last) {
size_type *curr = &sparse.first()[value_to_bucket(packed.first().back().second)];
packed.first()[pos] = std::move(packed.first().back());
packed.first()[pos] = stl::move(packed.first().back());
for(; *curr != last; curr = &packed.first()[*curr].first) {}
*curr = pos;
}
@@ -295,25 +267,25 @@ public:
/*! @brief Value type of the container. */
using value_type = Type;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
using size_type = stl::size_t;
/*! @brief Signed integer type. */
using difference_type = std::ptrdiff_t;
using difference_type = stl::ptrdiff_t;
/*! @brief Type of function to use to hash the elements. */
using hasher = Hash;
/*! @brief Type of function to use to compare the elements for equality. */
using key_equal = KeyEqual;
/*! @brief Random access iterator type. */
using iterator = internal::dense_set_iterator<typename packed_container_type::iterator>;
using iterator = internal::dense_set_iterator<typename packed_container_type::pointer>;
/*! @brief Constant random access iterator type. */
using const_iterator = internal::dense_set_iterator<typename packed_container_type::const_iterator>;
using const_iterator = internal::dense_set_iterator<typename packed_container_type::const_pointer>;
/*! @brief Reverse iterator type. */
using reverse_iterator = std::reverse_iterator<iterator>;
using reverse_iterator = stl::reverse_iterator<iterator>;
/*! @brief Constant reverse iterator type. */
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using const_reverse_iterator = stl::reverse_iterator<const_iterator>;
/*! @brief Forward iterator type. */
using local_iterator = internal::dense_set_local_iterator<typename packed_container_type::iterator>;
using local_iterator = internal::dense_set_local_iterator<typename packed_container_type::pointer>;
/*! @brief Constant forward iterator type. */
using const_local_iterator = internal::dense_set_local_iterator<typename packed_container_type::const_iterator>;
using const_local_iterator = internal::dense_set_local_iterator<typename packed_container_type::const_pointer>;
/*! @brief Default constructor. */
dense_set()
@@ -368,8 +340,8 @@ public:
* @param allocator The allocator to use.
*/
dense_set(const dense_set &other, const allocator_type &allocator)
: sparse{std::piecewise_construct, std::forward_as_tuple(other.sparse.first(), allocator), std::forward_as_tuple(other.sparse.second())},
packed{std::piecewise_construct, std::forward_as_tuple(other.packed.first(), allocator), std::forward_as_tuple(other.packed.second())},
: sparse{stl::piecewise_construct, stl::forward_as_tuple(other.sparse.first(), allocator), stl::forward_as_tuple(other.sparse.second())},
packed{stl::piecewise_construct, stl::forward_as_tuple(other.packed.first(), allocator), stl::forward_as_tuple(other.packed.second())},
threshold{other.threshold} {}
/*! @brief Default move constructor. */
@@ -381,8 +353,8 @@ public:
* @param allocator The allocator to use.
*/
dense_set(dense_set &&other, const allocator_type &allocator)
: sparse{std::piecewise_construct, std::forward_as_tuple(std::move(other.sparse.first()), allocator), std::forward_as_tuple(std::move(other.sparse.second()))},
packed{std::piecewise_construct, std::forward_as_tuple(std::move(other.packed.first()), allocator), std::forward_as_tuple(std::move(other.packed.second()))},
: sparse{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.sparse.first()), allocator), stl::forward_as_tuple(stl::move(other.sparse.second()))},
packed{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.packed.first()), allocator), stl::forward_as_tuple(stl::move(other.packed.second()))},
threshold{other.threshold} {}
/*! @brief Default destructor. */
@@ -405,7 +377,7 @@ public:
* @param other Container to exchange the content with.
*/
void swap(dense_set &other) noexcept {
using std::swap;
using stl::swap;
swap(sparse, other.sparse);
swap(packed, other.packed);
swap(threshold, other.threshold);
@@ -427,7 +399,7 @@ public:
* @return An iterator to the first instance of the internal array.
*/
[[nodiscard]] const_iterator cbegin() const noexcept {
return packed.first().begin();
return packed.first().data();
}
/*! @copydoc cbegin */
@@ -437,7 +409,7 @@ public:
/*! @copydoc begin */
[[nodiscard]] iterator begin() noexcept {
return packed.first().begin();
return packed.first().data();
}
/**
@@ -446,7 +418,7 @@ public:
* internal array.
*/
[[nodiscard]] const_iterator cend() const noexcept {
return packed.first().end();
return packed.first().data() + packed.first().size();
}
/*! @copydoc cend */
@@ -456,7 +428,7 @@ public:
/*! @copydoc end */
[[nodiscard]] iterator end() noexcept {
return packed.first().end();
return packed.first().data() + packed.first().size();
}
/**
@@ -467,7 +439,7 @@ public:
* @return An iterator to the first instance of the reversed internal array.
*/
[[nodiscard]] const_reverse_iterator crbegin() const noexcept {
return std::make_reverse_iterator(cend());
return stl::make_reverse_iterator(cend());
}
/*! @copydoc crbegin */
@@ -477,7 +449,7 @@ public:
/*! @copydoc rbegin */
[[nodiscard]] reverse_iterator rbegin() noexcept {
return std::make_reverse_iterator(end());
return stl::make_reverse_iterator(end());
}
/**
@@ -486,7 +458,7 @@ public:
* reversed internal array.
*/
[[nodiscard]] const_reverse_iterator crend() const noexcept {
return std::make_reverse_iterator(cbegin());
return stl::make_reverse_iterator(cbegin());
}
/*! @copydoc crend */
@@ -496,7 +468,7 @@ public:
/*! @copydoc rend */
[[nodiscard]] reverse_iterator rend() noexcept {
return std::make_reverse_iterator(begin());
return stl::make_reverse_iterator(begin());
}
/**
@@ -537,23 +509,21 @@ public:
* the element that prevented the insertion) and a bool denoting whether the
* insertion took place.
*/
std::pair<iterator, bool> insert(const value_type &value) {
stl::pair<iterator, bool> insert(const value_type &value) {
return insert_or_do_nothing(value);
}
/*! @copydoc insert */
std::pair<iterator, bool> insert(value_type &&value) {
return insert_or_do_nothing(std::move(value));
stl::pair<iterator, bool> insert(value_type &&value) {
return insert_or_do_nothing(stl::move(value));
}
/**
* @brief Inserts elements into the container, if they do not exist.
* @tparam It Type of input iterator.
* @param first An iterator to the first element of the range of elements.
* @param last An iterator past the last element of the range of elements.
*/
template<typename It>
void insert(It first, It last) {
void insert(stl::input_iterator auto first, stl::input_iterator auto last) {
for(; first != last; ++first) {
insert(*first);
}
@@ -573,22 +543,22 @@ public:
* insertion took place.
*/
template<typename... Args>
std::pair<iterator, bool> emplace(Args &&...args) {
if constexpr(((sizeof...(Args) == 1u) && ... && std::is_same_v<std::decay_t<Args>, value_type>)) {
return insert_or_do_nothing(std::forward<Args>(args)...);
stl::pair<iterator, bool> emplace(Args &&...args) {
if constexpr(((sizeof...(Args) == 1u) && ... && stl::is_same_v<stl::decay_t<Args>, value_type>)) {
return insert_or_do_nothing(stl::forward<Args>(args)...);
} else {
auto &node = packed.first().emplace_back(std::piecewise_construct, std::make_tuple(packed.first().size()), std::forward_as_tuple(std::forward<Args>(args)...));
auto &node = packed.first().emplace_back(stl::piecewise_construct, stl::make_tuple(packed.first().size()), stl::forward_as_tuple(stl::forward<Args>(args)...));
const auto index = value_to_bucket(node.second);
if(auto it = constrained_find(node.second, index); it != end()) {
packed.first().pop_back();
return std::make_pair(it, false);
return stl::make_pair(it, false);
}
std::swap(node.first, sparse.first()[index]);
stl::swap(node.first, sparse.first()[index]);
rehash_if_required();
return std::make_pair(--end(), true);
return stl::make_pair(--end(), true);
}
}
@@ -648,13 +618,11 @@ public:
/**
* @brief Returns the number of elements matching a key (either 1 or 0).
* @tparam Other Type of the key value of an element to search for.
* @param key Key value of an element to search for.
* @return Number of elements matching the key (either 1 or 0).
*/
template<typename Other>
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, size_type>>
count(const Other &key) const {
[[nodiscard]] size_type count(const auto &key) const
requires is_transparent_v<hasher> && is_transparent_v<key_equal> {
return find(key) != end();
}
@@ -675,21 +643,18 @@ public:
/**
* @brief Finds an element that compares _equivalent_ to a given value.
* @tparam Other Type of an element to search for.
* @param value Value of an element to search for.
* @return An iterator to an element with the given value. If no such
* element is found, a past-the-end iterator is returned.
*/
template<typename Other>
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, iterator>>
find(const Other &value) {
[[nodiscard]] iterator find(const auto &value)
requires is_transparent_v<hasher> && is_transparent_v<key_equal> {
return constrained_find(value, value_to_bucket(value));
}
/*! @copydoc find */
template<typename Other>
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, const_iterator>>
find(const Other &value) const {
[[nodiscard]] const_iterator find(const auto &value) const
requires is_transparent_v<hasher> && is_transparent_v<key_equal> {
return constrained_find(value, value_to_bucket(value));
}
@@ -699,13 +664,13 @@ public:
* @return A pair of iterators pointing to the first element and past the
* last element of the range.
*/
[[nodiscard]] std::pair<iterator, iterator> equal_range(const value_type &value) {
[[nodiscard]] stl::pair<iterator, iterator> equal_range(const value_type &value) {
const auto it = find(value);
return {it, it + !(it == end())};
}
/*! @copydoc equal_range */
[[nodiscard]] std::pair<const_iterator, const_iterator> equal_range(const value_type &value) const {
[[nodiscard]] stl::pair<const_iterator, const_iterator> equal_range(const value_type &value) const {
const auto it = find(value);
return {it, it + !(it == cend())};
}
@@ -713,22 +678,19 @@ public:
/**
* @brief Returns a range containing all elements that compare _equivalent_
* to a given value.
* @tparam Other Type of an element to search for.
* @param value Value of an element to search for.
* @return A pair of iterators pointing to the first element and past the
* last element of the range.
*/
template<typename Other>
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, std::pair<iterator, iterator>>>
equal_range(const Other &value) {
[[nodiscard]] stl::pair<iterator, iterator> equal_range(const auto &value)
requires is_transparent_v<hasher> && is_transparent_v<key_equal> {
const auto it = find(value);
return {it, it + !(it == end())};
}
/*! @copydoc equal_range */
template<typename Other>
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, std::pair<const_iterator, const_iterator>>>
equal_range(const Other &value) const {
[[nodiscard]] stl::pair<const_iterator, const_iterator> equal_range(const auto &value) const
requires is_transparent_v<hasher> && is_transparent_v<key_equal> {
const auto it = find(value);
return {it, it + !(it == cend())};
}
@@ -745,13 +707,11 @@ public:
/**
* @brief Checks if the container contains an element that compares
* _equivalent_ to a given value.
* @tparam Other Type of an element to search for.
* @param value Value of an element to search for.
* @return True if there is such an element, false otherwise.
*/
template<typename Other>
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, bool>>
contains(const Other &value) const {
[[nodiscard]] bool contains(const auto &value) const
requires is_transparent_v<hasher> && is_transparent_v<key_equal> {
return (find(value) != cend());
}
@@ -761,7 +721,7 @@ public:
* @return An iterator to the beginning of the given bucket.
*/
[[nodiscard]] const_local_iterator cbegin(const size_type index) const {
return {packed.first().begin(), sparse.first()[index]};
return {packed.first().data(), sparse.first()[index]};
}
/**
@@ -779,7 +739,7 @@ public:
* @return An iterator to the beginning of the given bucket.
*/
[[nodiscard]] local_iterator begin(const size_type index) {
return {packed.first().begin(), sparse.first()[index]};
return {packed.first().data(), sparse.first()[index]};
}
/**
@@ -831,7 +791,7 @@ public:
* @return The number of elements in the given bucket.
*/
[[nodiscard]] size_type bucket_size(const size_type index) const {
return static_cast<size_type>(std::distance(begin(index), end(index)));
return static_cast<size_type>(stl::distance(begin(index), end(index)));
}
/**
@@ -879,7 +839,7 @@ public:
const auto cap = static_cast<size_type>(static_cast<float>(size()) / max_load_factor());
value = value > cap ? value : cap;
if(const auto sz = next_power_of_two(value); sz != bucket_count()) {
if(const auto sz = stl::bit_ceil(value); sz != bucket_count()) {
sparse.first().resize(sz);
for(auto &&elem: sparse.first()) {
@@ -888,7 +848,7 @@ public:
for(size_type pos{}, last = size(); pos < last; ++pos) {
const auto index = value_to_bucket(packed.first()[pos].second);
packed.first()[pos].first = std::exchange(sparse.first()[index], pos);
packed.first()[pos].first = stl::exchange(sparse.first()[index], pos);
}
}
}
@@ -900,7 +860,7 @@ public:
*/
void reserve(const size_type cnt) {
packed.first().reserve(cnt);
rehash(static_cast<size_type>(std::ceil(static_cast<float>(cnt) / max_load_factor())));
rehash(static_cast<size_type>(stl::ceil(static_cast<float>(cnt) / max_load_factor())));
}
/**

View File

@@ -1,26 +1,26 @@
#ifndef ENTT_CONTAINER_FWD_HPP
#define ENTT_CONTAINER_FWD_HPP
#include <functional>
#include <memory>
#include <utility>
#include <vector>
#include "../stl/functional.hpp"
#include "../stl/memory.hpp"
#include "../stl/utility.hpp"
#include "../stl/vector.hpp"
namespace entt {
template<
typename Key,
typename Type,
typename = std::hash<Key>,
typename = std::equal_to<>,
typename = std::allocator<std::pair<const Key, Type>>>
typename = stl::hash<Key>,
typename = stl::equal_to<>,
typename = stl::allocator<stl::pair<const Key, Type>>>
class dense_map;
template<
typename Type,
typename = std::hash<Type>,
typename = std::equal_to<>,
typename = std::allocator<Type>>
typename = stl::hash<Type>,
typename = stl::equal_to<>,
typename = stl::allocator<Type>>
class dense_set;
template<typename...>
@@ -31,7 +31,7 @@ class basic_table;
* @tparam Type Element types.
*/
template<typename... Type>
using table = basic_table<std::vector<Type>...>;
using table = basic_table<stl::vector<Type>...>;
} // namespace entt

View File

@@ -1,18 +1,18 @@
#ifndef ENTT_CONTAINER_TABLE_HPP
#define ENTT_CONTAINER_TABLE_HPP
#include <cstddef>
#include <iterator>
#include <tuple>
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "../core/iterator.hpp"
#include "../stl/concepts.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/iterator.hpp"
#include "../stl/tuple.hpp"
#include "../stl/utility.hpp"
#include "fwd.hpp"
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
template<typename... It>
@@ -21,12 +21,12 @@ class table_iterator {
friend class table_iterator;
public:
using value_type = decltype(std::forward_as_tuple(*std::declval<It>()...));
using value_type = decltype(stl::forward_as_tuple(*stl::declval<It>()...));
using pointer = input_iterator_pointer<value_type>;
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category = std::input_iterator_tag;
using iterator_concept = std::random_access_iterator_tag;
using difference_type = stl::ptrdiff_t;
using iterator_category = stl::input_iterator_tag;
using iterator_concept = stl::random_access_iterator_tag;
constexpr table_iterator() noexcept
: it{} {}
@@ -34,12 +34,13 @@ public:
constexpr table_iterator(It... from) noexcept
: it{from...} {}
template<typename... Other, typename = std::enable_if_t<(std::is_constructible_v<It, Other> && ...)>>
template<typename... Other>
requires (stl::constructible_from<It, Other> && ...)
constexpr table_iterator(const table_iterator<Other...> &other) noexcept
: table_iterator{std::get<Other>(other.it)...} {}
: table_iterator{stl::get<Other>(other.it)...} {}
constexpr table_iterator &operator++() noexcept {
return (++std::get<It>(it), ...), *this;
return (++stl::get<It>(it), ...), *this;
}
constexpr table_iterator operator++(int) noexcept {
@@ -48,7 +49,7 @@ public:
}
constexpr table_iterator &operator--() noexcept {
return (--std::get<It>(it), ...), *this;
return (--stl::get<It>(it), ...), *this;
}
constexpr table_iterator operator--(int) noexcept {
@@ -57,7 +58,7 @@ public:
}
constexpr table_iterator &operator+=(const difference_type value) noexcept {
return ((std::get<It>(it) += value), ...), *this;
return ((stl::get<It>(it) += value), ...), *this;
}
constexpr table_iterator operator+(const difference_type value) const noexcept {
@@ -74,7 +75,7 @@ public:
}
[[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept {
return std::forward_as_tuple(std::get<It>(it)[value]...);
return stl::forward_as_tuple(stl::get<It>(it)[value]...);
}
[[nodiscard]] constexpr pointer operator->() const noexcept {
@@ -85,54 +86,25 @@ public:
return operator[](0);
}
template<typename... Lhs, typename... Rhs>
friend constexpr std::ptrdiff_t operator-(const table_iterator<Lhs...> &, const table_iterator<Rhs...> &) noexcept;
template<typename... Other>
[[nodiscard]] constexpr stl::ptrdiff_t operator-(const table_iterator<Other...> &other) const noexcept {
return stl::get<0>(it) - stl::get<0>(other.it);
}
template<typename... Lhs, typename... Rhs>
friend constexpr bool operator==(const table_iterator<Lhs...> &, const table_iterator<Rhs...> &) noexcept;
template<typename... Other>
[[nodiscard]] constexpr bool operator==(const table_iterator<Other...> &other) const noexcept {
return stl::get<0>(it) == stl::get<0>(other.it);
}
template<typename... Lhs, typename... Rhs>
friend constexpr bool operator<(const table_iterator<Lhs...> &, const table_iterator<Rhs...> &) noexcept;
template<typename... Other>
[[nodiscard]] constexpr auto operator<=>(const table_iterator<Other...> &other) const noexcept {
return stl::get<0>(it) <=> stl::get<0>(other.it);
}
private:
std::tuple<It...> it;
stl::tuple<It...> it;
};
template<typename... Lhs, typename... Rhs>
[[nodiscard]] constexpr std::ptrdiff_t operator-(const table_iterator<Lhs...> &lhs, const table_iterator<Rhs...> &rhs) noexcept {
return std::get<0>(lhs.it) - std::get<0>(rhs.it);
}
template<typename... Lhs, typename... Rhs>
[[nodiscard]] constexpr bool operator==(const table_iterator<Lhs...> &lhs, const table_iterator<Rhs...> &rhs) noexcept {
return std::get<0>(lhs.it) == std::get<0>(rhs.it);
}
template<typename... Lhs, typename... Rhs>
[[nodiscard]] constexpr bool operator!=(const table_iterator<Lhs...> &lhs, const table_iterator<Rhs...> &rhs) noexcept {
return !(lhs == rhs);
}
template<typename... Lhs, typename... Rhs>
[[nodiscard]] constexpr bool operator<(const table_iterator<Lhs...> &lhs, const table_iterator<Rhs...> &rhs) noexcept {
return std::get<0>(lhs.it) < std::get<0>(rhs.it);
}
template<typename... Lhs, typename... Rhs>
[[nodiscard]] constexpr bool operator>(const table_iterator<Lhs...> &lhs, const table_iterator<Rhs...> &rhs) noexcept {
return rhs < lhs;
}
template<typename... Lhs, typename... Rhs>
[[nodiscard]] constexpr bool operator<=(const table_iterator<Lhs...> &lhs, const table_iterator<Rhs...> &rhs) noexcept {
return !(lhs > rhs);
}
template<typename... Lhs, typename... Rhs>
[[nodiscard]] constexpr bool operator>=(const table_iterator<Lhs...> &lhs, const table_iterator<Rhs...> &rhs) noexcept {
return !(lhs < rhs);
}
} // namespace internal
/*! @endcond */
@@ -147,13 +119,13 @@ template<typename... Lhs, typename... Rhs>
*/
template<typename... Container>
class basic_table {
using container_type = std::tuple<Container...>;
using container_type = stl::tuple<Container...>;
public:
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
using size_type = stl::size_t;
/*! @brief Signed integer type. */
using difference_type = std::ptrdiff_t;
using difference_type = stl::ptrdiff_t;
/*! @brief Input iterator type. */
using iterator = internal::table_iterator<typename Container::iterator...>;
/*! @brief Constant input iterator type. */
@@ -174,7 +146,7 @@ public:
*/
explicit basic_table(const Container &...container) noexcept
: payload{container...} {
ENTT_ASSERT((((std::get<Container>(payload).size() * sizeof...(Container)) == (std::get<Container>(payload).size() + ...)) && ...), "Unexpected container size");
ENTT_ASSERT((((stl::get<Container>(payload).size() * sizeof...(Container)) == (stl::get<Container>(payload).size() + ...)) && ...), "Unexpected container size");
}
/**
@@ -182,8 +154,8 @@ public:
* @param container The containers to move from.
*/
explicit basic_table(Container &&...container) noexcept
: payload{std::move(container)...} {
ENTT_ASSERT((((std::get<Container>(payload).size() * sizeof...(Container)) == (std::get<Container>(payload).size() + ...)) && ...), "Unexpected container size");
: payload{stl::move(container)...} {
ENTT_ASSERT((((stl::get<Container>(payload).size() * sizeof...(Container)) == (stl::get<Container>(payload).size() + ...)) && ...), "Unexpected container size");
}
/*! @brief Default copy constructor, deleted on purpose. */
@@ -194,15 +166,13 @@ public:
* @param other The instance to move from.
*/
basic_table(basic_table &&other) noexcept
: payload{std::move(other.payload)} {}
: payload{stl::move(other.payload)} {}
/**
* @brief Constructs the underlying containers using a given allocator.
* @tparam Allocator Type of allocator.
* @param allocator A valid allocator.
*/
template<typename Allocator>
explicit basic_table(const Allocator &allocator)
explicit basic_table(const auto &allocator)
: payload{Container{allocator}...} {}
/**
@@ -214,7 +184,7 @@ public:
template<class Allocator>
basic_table(const Container &...container, const Allocator &allocator) noexcept
: payload{Container{container, allocator}...} {
ENTT_ASSERT((((std::get<Container>(payload).size() * sizeof...(Container)) == (std::get<Container>(payload).size() + ...)) && ...), "Unexpected container size");
ENTT_ASSERT((((stl::get<Container>(payload).size() * sizeof...(Container)) == (stl::get<Container>(payload).size() + ...)) && ...), "Unexpected container size");
}
/**
@@ -225,8 +195,8 @@ public:
*/
template<class Allocator>
basic_table(Container &&...container, const Allocator &allocator) noexcept
: payload{Container{std::move(container), allocator}...} {
ENTT_ASSERT((((std::get<Container>(payload).size() * sizeof...(Container)) == (std::get<Container>(payload).size() + ...)) && ...), "Unexpected container size");
: payload{Container{stl::move(container), allocator}...} {
ENTT_ASSERT((((stl::get<Container>(payload).size() * sizeof...(Container)) == (stl::get<Container>(payload).size() + ...)) && ...), "Unexpected container size");
}
/**
@@ -237,7 +207,7 @@ public:
*/
template<class Allocator>
basic_table(basic_table &&other, const Allocator &allocator)
: payload{Container{std::move(std::get<Container>(other.payload)), allocator}...} {}
: payload{Container{stl::move(stl::get<Container>(other.payload)), allocator}...} {}
/*! @brief Default destructor. */
~basic_table() = default;
@@ -263,7 +233,7 @@ public:
* @param other Table to exchange the content with.
*/
void swap(basic_table &other) noexcept {
using std::swap;
using stl::swap;
swap(payload, other.payload);
}
@@ -276,7 +246,7 @@ public:
* @param cap Desired capacity.
*/
void reserve(const size_type cap) {
(std::get<Container>(payload).reserve(cap), ...);
(stl::get<Container>(payload).reserve(cap), ...);
}
/**
@@ -285,12 +255,12 @@ public:
* @return Capacity of the table.
*/
[[nodiscard]] size_type capacity() const noexcept {
return std::get<0>(payload).capacity();
return stl::get<0>(payload).capacity();
}
/*! @brief Requests the removal of unused capacity. */
void shrink_to_fit() {
(std::get<Container>(payload).shrink_to_fit(), ...);
(stl::get<Container>(payload).shrink_to_fit(), ...);
}
/**
@@ -298,7 +268,7 @@ public:
* @return Number of rows.
*/
[[nodiscard]] size_type size() const noexcept {
return std::get<0>(payload).size();
return stl::get<0>(payload).size();
}
/**
@@ -306,7 +276,7 @@ public:
* @return True if the table is empty, false otherwise.
*/
[[nodiscard]] bool empty() const noexcept {
return std::get<0>(payload).empty();
return stl::get<0>(payload).empty();
}
/**
@@ -317,7 +287,7 @@ public:
* @return An iterator to the first row of the table.
*/
[[nodiscard]] const_iterator cbegin() const noexcept {
return {std::get<Container>(payload).cbegin()...};
return {stl::get<Container>(payload).cbegin()...};
}
/*! @copydoc cbegin */
@@ -327,7 +297,7 @@ public:
/*! @copydoc begin */
[[nodiscard]] iterator begin() noexcept {
return {std::get<Container>(payload).begin()...};
return {stl::get<Container>(payload).begin()...};
}
/**
@@ -335,7 +305,7 @@ public:
* @return An iterator to the element following the last row of the table.
*/
[[nodiscard]] const_iterator cend() const noexcept {
return {std::get<Container>(payload).cend()...};
return {stl::get<Container>(payload).cend()...};
}
/*! @copydoc cend */
@@ -345,7 +315,7 @@ public:
/*! @copydoc end */
[[nodiscard]] iterator end() noexcept {
return {std::get<Container>(payload).end()...};
return {stl::get<Container>(payload).end()...};
}
/**
@@ -356,7 +326,7 @@ public:
* @return An iterator to the first row of the reversed table.
*/
[[nodiscard]] const_reverse_iterator crbegin() const noexcept {
return {std::get<Container>(payload).crbegin()...};
return {stl::get<Container>(payload).crbegin()...};
}
/*! @copydoc crbegin */
@@ -366,7 +336,7 @@ public:
/*! @copydoc rbegin */
[[nodiscard]] reverse_iterator rbegin() noexcept {
return {std::get<Container>(payload).rbegin()...};
return {stl::get<Container>(payload).rbegin()...};
}
/**
@@ -375,7 +345,7 @@ public:
* table.
*/
[[nodiscard]] const_reverse_iterator crend() const noexcept {
return {std::get<Container>(payload).crend()...};
return {stl::get<Container>(payload).crend()...};
}
/*! @copydoc crend */
@@ -385,7 +355,7 @@ public:
/*! @copydoc rend */
[[nodiscard]] reverse_iterator rend() noexcept {
return {std::get<Container>(payload).rend()...};
return {stl::get<Container>(payload).rend()...};
}
/**
@@ -395,11 +365,11 @@ public:
* @return A reference to the newly created row data.
*/
template<typename... Args>
std::tuple<typename Container::value_type &...> emplace(Args &&...args) {
stl::tuple<typename Container::value_type &...> emplace(Args &&...args) {
if constexpr(sizeof...(Args) == 0u) {
return std::forward_as_tuple(std::get<Container>(payload).emplace_back()...);
return stl::forward_as_tuple(stl::get<Container>(payload).emplace_back()...);
} else {
return std::forward_as_tuple(std::get<Container>(payload).emplace_back(std::forward<Args>(args))...);
return stl::forward_as_tuple(stl::get<Container>(payload).emplace_back(stl::forward<Args>(args))...);
}
}
@@ -410,7 +380,7 @@ public:
*/
iterator erase(const_iterator pos) {
const auto diff = pos - begin();
return {std::get<Container>(payload).erase(std::get<Container>(payload).begin() + diff)...};
return {stl::get<Container>(payload).erase(stl::get<Container>(payload).begin() + diff)...};
}
/**
@@ -427,20 +397,20 @@ public:
* @param pos The row for which to return the data.
* @return The row data at specified location.
*/
[[nodiscard]] std::tuple<const typename Container::value_type &...> operator[](const size_type pos) const {
[[nodiscard]] stl::tuple<const typename Container::value_type &...> operator[](const size_type pos) const {
ENTT_ASSERT(pos < size(), "Index out of bounds");
return std::forward_as_tuple(std::get<Container>(payload)[pos]...);
return stl::forward_as_tuple(stl::get<Container>(payload)[pos]...);
}
/*! @copydoc operator[] */
[[nodiscard]] std::tuple<typename Container::value_type &...> operator[](const size_type pos) {
[[nodiscard]] stl::tuple<typename Container::value_type &...> operator[](const size_type pos) {
ENTT_ASSERT(pos < size(), "Index out of bounds");
return std::forward_as_tuple(std::get<Container>(payload)[pos]...);
return stl::forward_as_tuple(stl::get<Container>(payload)[pos]...);
}
/*! @brief Clears a table. */
void clear() {
(std::get<Container>(payload).clear(), ...);
(stl::get<Container>(payload).clear(), ...);
}
private:
@@ -449,12 +419,14 @@ private:
} // namespace entt
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
#include <utility>
namespace std {
template<typename... Container, typename Allocator>
struct uses_allocator<entt::basic_table<Container...>, Allocator>
: std::bool_constant<(std::uses_allocator_v<Container, Allocator> && ...)> {};
: entt::stl::bool_constant<(entt::stl::uses_allocator_v<Container, Allocator> && ...)> {};
} // namespace std
/*! @endcond */

View File

@@ -1,21 +1,22 @@
#ifndef ENTT_CORE_ALGORITHM_HPP
#define ENTT_CORE_ALGORITHM_HPP
#include <algorithm>
#include <functional>
#include <iterator>
#include <utility>
#include <vector>
#include "utility.hpp"
#include "../stl/algorithm.hpp"
#include "../stl/concepts.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/functional.hpp"
#include "../stl/iterator.hpp"
#include "../stl/utility.hpp"
#include "../stl/vector.hpp"
namespace entt {
/**
* @brief Function object to wrap `std::sort` in a class type.
* @brief Function object to wrap `stl::sort` in a class type.
*
* Unfortunately, `std::sort` cannot be passed as template argument to a class
* Unfortunately, `stl::sort` cannot be passed as template argument to a class
* template or a function template.<br/>
* This class fills the gap by wrapping some flavors of `std::sort` in a
* This class fills the gap by wrapping some flavors of `stl::sort` in a
* function object.
*/
struct std_sort {
@@ -24,7 +25,6 @@ struct std_sort {
*
* Sorts the elements in a range using the given binary comparison function.
*
* @tparam It Type of random access iterator.
* @tparam Compare Type of comparison function object.
* @tparam Args Types of arguments to forward to the sort function.
* @param first An iterator to the first element of the range to sort.
@@ -32,9 +32,9 @@ struct std_sort {
* @param compare A valid comparison function object.
* @param args Arguments to forward to the sort function, if any.
*/
template<typename It, typename Compare = std::less<>, typename... Args>
void operator()(It first, It last, Compare compare = Compare{}, Args &&...args) const {
std::sort(std::forward<Args>(args)..., std::move(first), std::move(last), std::move(compare));
template<typename Compare = stl::less<>, typename... Args>
void operator()(stl::random_access_iterator auto first, stl::random_access_iterator auto last, Compare compare = Compare{}, Args &&...args) const {
stl::sort(stl::forward<Args>(args)..., stl::move(first), stl::move(last), stl::move(compare));
}
};
@@ -45,26 +45,25 @@ struct insertion_sort {
*
* Sorts the elements in a range using the given binary comparison function.
*
* @tparam It Type of random access iterator.
* @tparam Compare Type of comparison function object.
* @param first An iterator to the first element of the range to sort.
* @param last An iterator past the last element of the range to sort.
* @param compare A valid comparison function object.
*/
template<typename It, typename Compare = std::less<>>
void operator()(It first, It last, Compare compare = Compare{}) const {
template<typename Compare = stl::less<>>
void operator()(stl::random_access_iterator auto first, stl::random_access_iterator auto last, Compare compare = Compare{}) const {
if(first < last) {
for(auto it = first + 1; it < last; ++it) {
auto value = std::move(*it);
auto value = stl::move(*it);
auto pre = it;
// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic)
for(; pre > first && compare(value, *(pre - 1)); --pre) {
*pre = std::move(*(pre - 1));
*pre = stl::move(*(pre - 1));
}
// NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
*pre = std::move(value);
*pre = stl::move(value);
}
}
}
@@ -75,10 +74,9 @@ struct insertion_sort {
* @tparam Bit Number of bits processed per pass.
* @tparam N Maximum number of bits to sort.
*/
template<std::size_t Bit, std::size_t N>
template<stl::size_t Bit, stl::size_t N>
requires ((N % Bit) == 0) // The maximum number of bits to sort must be a multiple of the number of bits processed per pass
struct radix_sort {
static_assert((N % Bit) == 0, "The maximum number of bits to sort must be a multiple of the number of bits processed per pass");
/**
* @brief Sorts the elements in a range.
*
@@ -94,47 +92,47 @@ struct radix_sort {
* @param last An iterator past the last element of the range to sort.
* @param getter A valid _getter_ function object.
*/
template<typename It, typename Getter = identity>
template<stl::random_access_iterator It, typename Getter = stl::identity>
void operator()(It first, It last, Getter getter = Getter{}) const {
if(first < last) {
constexpr auto passes = N / Bit;
using value_type = typename std::iterator_traits<It>::value_type;
using difference_type = typename std::iterator_traits<It>::difference_type;
std::vector<value_type> aux(static_cast<std::size_t>(std::distance(first, last)));
using value_type = stl::iterator_traits<It>::value_type;
using difference_type = stl::iterator_traits<It>::difference_type;
stl::vector<value_type> aux(static_cast<stl::size_t>(stl::distance(first, last)));
auto part = [getter = std::move(getter)](auto from, auto to, auto out, auto start) {
auto part = [getter = stl::move(getter)](auto from, auto to, auto out, auto start) {
constexpr auto mask = (1 << Bit) - 1;
constexpr auto buckets = 1 << Bit;
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays, misc-const-correctness)
std::size_t count[buckets]{};
stl::size_t count[buckets]{};
for(auto it = from; it != to; ++it) {
++count[(getter(*it) >> start) & mask];
}
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
std::size_t index[buckets]{};
stl::size_t index[buckets]{};
for(std::size_t pos{}, end = buckets - 1u; pos < end; ++pos) {
for(stl::size_t pos{}, end = buckets - 1u; pos < end; ++pos) {
index[pos + 1u] = index[pos] + count[pos];
}
for(auto it = from; it != to; ++it) {
const auto pos = index[(getter(*it) >> start) & mask]++;
out[static_cast<difference_type>(pos)] = std::move(*it);
out[static_cast<difference_type>(pos)] = stl::move(*it);
}
};
for(std::size_t pass = 0; pass < (passes & ~1u); pass += 2) {
for(stl::size_t pass = 0; pass < (passes & ~1u); pass += 2) {
part(first, last, aux.begin(), pass * Bit);
part(aux.begin(), aux.end(), first, (pass + 1) * Bit);
}
if constexpr(passes & 1) {
part(first, last, aux.begin(), (passes - 1) * Bit);
std::move(aux.begin(), aux.end(), first);
stl::move(aux.begin(), aux.end(), first);
}
}
}

View File

@@ -1,11 +1,14 @@
#ifndef ENTT_CORE_ANY_HPP
#define ENTT_CORE_ANY_HPP
#include <cstddef>
#include <memory>
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "../core/concepts.hpp"
#include "../stl/concepts.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/cstdint.hpp"
#include "../stl/memory.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "fwd.hpp"
#include "type_info.hpp"
#include "type_traits.hpp"
@@ -13,10 +16,10 @@
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
enum class any_request : std::uint8_t {
enum class any_request : stl::uint8_t {
info,
transfer,
assign,
@@ -25,28 +28,28 @@ enum class any_request : std::uint8_t {
move
};
template<std::size_t Len, std::size_t Align>
template<stl::size_t Len, stl::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];
alignas(Align) stl::byte buffer[Len];
};
};
template<std::size_t Align>
template<stl::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>
template<typename Type, stl::size_t Len, stl::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>> {};
struct in_situ: stl::bool_constant<(Len != 0u) && alignof(Type) <= Align && sizeof(Type) <= Len && stl::is_nothrow_move_constructible_v<Type>> {};
template<std::size_t Len, std::size_t Align>
struct in_situ<void, Len, Align>: std::false_type {};
template<stl::size_t Len, stl::size_t Align>
struct in_situ<void, Len, Align>: stl::false_type {};
} // namespace internal
/*! @endcond */
@@ -56,7 +59,7 @@ struct in_situ<void, Len, Align>: std::false_type {};
* @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>
template<stl::size_t Len, stl::size_t Align>
class basic_any: private internal::basic_any_storage<Len, Align> {
using request = internal::any_request;
using base_type = internal::basic_any_storage<Len, Align>;
@@ -66,59 +69,57 @@ class basic_any: private internal::basic_any_storage<Len, Align> {
template<typename Type>
static constexpr bool in_situ_v = internal::in_situ<Type, Len, Align>::value;
template<typename Type>
template<cvref_unqualified Type>
static const void *basic_vtable(const request req, const basic_any &value, const void *other) {
static_assert(std::is_same_v<std::remove_const_t<std::remove_reference_t<Type>>, Type>, "Invalid type");
switch(const auto *elem = static_cast<const Type *>(value.data()); req) {
case request::info:
using enum internal::any_request;
case info:
return &type_id<Type>();
case request::transfer:
if constexpr(std::is_move_assignable_v<Type>) {
case transfer:
if constexpr(stl::is_move_assignable_v<Type>) {
// NOLINTNEXTLINE(bugprone-casting-through-void)
*const_cast<Type *>(elem) = std::move(*static_cast<Type *>(const_cast<void *>(other)));
*const_cast<Type *>(elem) = stl::move(*static_cast<Type *>(const_cast<void *>(other)));
return other;
}
[[fallthrough]];
case request::assign:
if constexpr(std::is_copy_assignable_v<Type>) {
case assign:
if constexpr(stl::is_copy_assignable_v<Type>) {
*const_cast<Type *>(elem) = *static_cast<const Type *>(other);
return other;
}
break;
case request::compare:
if constexpr(!std::is_function_v<Type> && !std::is_array_v<Type> && is_equality_comparable_v<Type>) {
case compare:
if constexpr(!stl::is_function_v<Type> && !stl::is_array_v<Type> && is_equality_comparable_v<Type>) {
return (*elem == *static_cast<const Type *>(other)) ? other : nullptr;
} else {
return (elem == other) ? other : nullptr;
}
case request::copy:
if constexpr(std::is_copy_constructible_v<Type>) {
case copy:
if constexpr(stl::is_copy_constructible_v<Type>) {
// NOLINTNEXTLINE(bugprone-casting-through-void)
static_cast<basic_any *>(const_cast<void *>(other))->initialize<Type>(*elem);
}
break;
case request::move:
case move:
ENTT_ASSERT(value.mode == any_policy::embedded, "Unexpected policy");
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))->buffer) Type{std::move(*const_cast<Type *>(elem))};
return ::new(&static_cast<basic_any *>(const_cast<void *>(other))->buffer) Type{stl::move(*const_cast<Type *>(elem))};
}
}
return nullptr;
}
template<typename Type>
template<cvref_unqualified 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");
ENTT_ASSERT((value.mode == any_policy::dynamic) || ((value.mode == any_policy::embedded) && !stl::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>) {
} else if constexpr(stl::is_array_v<Type>) {
delete[] elem;
} else {
delete elem;
@@ -127,23 +128,23 @@ class basic_any: private internal::basic_any_storage<Len, Align> {
template<typename Type, typename... Args>
void initialize([[maybe_unused]] Args &&...args) {
using plain_type = std::remove_const_t<std::remove_reference_t<Type>>;
using plain_type = stl::remove_cvref_t<Type>;
vtable = basic_vtable<plain_type>;
underlying_type = type_hash<plain_type>::value();
if constexpr(std::is_void_v<Type>) {
if constexpr(stl::is_void_v<Type>) {
deleter = nullptr;
mode = any_policy::empty;
this->instance = nullptr;
} else if constexpr(std::is_lvalue_reference_v<Type>) {
} else if constexpr(stl::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");
mode = stl::is_const_v<stl::remove_reference_t<Type>> ? any_policy::cref : any_policy::ref;
static_assert((stl::is_lvalue_reference_v<Args> && ...) && (sizeof...(Args) == 1u), "Invalid arguments");
// NOLINTNEXTLINE(bugprone-multi-level-implicit-pointer-conversion)
this->instance = (std::addressof(args), ...);
this->instance = (stl::addressof(args), ...);
} else if constexpr(in_situ_v<plain_type>) {
if constexpr(std::is_trivially_destructible_v<plain_type>) {
if constexpr(stl::is_trivially_destructible_v<plain_type>) {
deleter = nullptr;
} else {
deleter = &basic_deleter<plain_type>;
@@ -151,23 +152,23 @@ class basic_any: private internal::basic_any_storage<Len, Align> {
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)...};
if constexpr(stl::is_aggregate_v<plain_type> && (sizeof...(Args) != 0u || !stl::is_default_constructible_v<plain_type>)) {
::new(&this->buffer) plain_type{stl::forward<Args>(args)...};
} else {
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
::new(&this->buffer) plain_type(std::forward<Args>(args)...);
::new(&this->buffer) plain_type(stl::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>) {
if constexpr(stl::is_aggregate_v<plain_type> && (sizeof...(Args) != 0u || !stl::is_default_constructible_v<plain_type>)) {
this->instance = new plain_type{stl::forward<Args>(args)...};
} else if constexpr(stl::is_array_v<plain_type>) {
static_assert(sizeof...(Args) == 0u, "Invalid arguments");
this->instance = new plain_type[std::extent_v<plain_type>]();
this->instance = new plain_type[stl::extent_v<plain_type>]();
} else {
this->instance = new plain_type(std::forward<Args>(args)...);
this->instance = new plain_type(stl::forward<Args>(args)...);
}
}
}
@@ -186,7 +187,7 @@ public:
/*! @brief Default constructor. */
constexpr basic_any() noexcept
: basic_any{std::in_place_type<void>} {}
: basic_any{stl::in_place_type<void>} {}
/**
* @brief Constructs a wrapper by directly initializing the new object.
@@ -195,9 +196,9 @@ public:
* @param args Parameters to use to construct the instance.
*/
template<typename Type, typename... Args>
explicit basic_any(std::in_place_type_t<Type>, Args &&...args)
explicit basic_any(stl::in_place_type_t<Type>, Args &&...args)
: base_type{} {
initialize<Type>(std::forward<Args>(args)...);
initialize<Type>(stl::forward<Args>(args)...);
}
/**
@@ -206,10 +207,9 @@ public:
* @param value A pointer to an object to take ownership of.
*/
template<typename Type>
explicit basic_any(std::in_place_t, Type *value)
requires (!stl::is_const_v<Type> && !stl::is_void_v<Type>)
explicit basic_any(stl::in_place_t, Type *value)
: base_type{} {
static_assert(!std::is_const_v<Type> && !std::is_void_v<Type>, "Non-const non-void pointer required");
if(value == nullptr) {
initialize<void>();
} else {
@@ -224,9 +224,10 @@ public:
* @tparam Type Type of object to use to initialize the wrapper.
* @param value An instance of an object to use to initialize the wrapper.
*/
template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, basic_any>>>
template<typename Type>
requires (!stl::same_as<stl::remove_cvref_t<Type>, basic_any>)
basic_any(Type &&value)
: basic_any{std::in_place_type<std::decay_t<Type>>, std::forward<Type>(value)} {}
: basic_any{stl::in_place_type<stl::decay_t<Type>>, stl::forward<Type>(value)} {}
/**
* @brief Copy constructor.
@@ -250,7 +251,7 @@ public:
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);
this->instance = stl::exchange(other.instance, nullptr);
}
}
@@ -290,7 +291,7 @@ public:
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);
this->instance = stl::exchange(other.instance, nullptr);
}
vtable = other.vtable;
@@ -308,9 +309,10 @@ public:
* @param value An instance of an object to use to initialize the wrapper.
* @return This any object.
*/
template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, basic_any>>>
template<typename Type>
requires (!stl::same_as<stl::remove_cvref_t<Type>, basic_any>)
basic_any &operator=(Type &&value) {
emplace<std::decay_t<Type>>(std::forward<Type>(value));
emplace<stl::decay_t<Type>>(stl::forward<Type>(value));
return *this;
}
@@ -340,9 +342,8 @@ public:
* @return False if the wrapper does not contain the expected type, true
* otherwise.
*/
template<typename Type>
template<cvref_unqualified 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());
}
@@ -354,11 +355,6 @@ public:
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();
}
/**
* @brief Returns an opaque pointer to the contained instance.
* @return An opaque pointer the contained instance, if any.
@@ -387,7 +383,7 @@ public:
*/
template<typename Type>
[[nodiscard]] const Type *data() const noexcept {
return has_value<std::remove_const_t<Type>>() ? static_cast<const Type *>(data()) : nullptr;
return has_value<stl::remove_const_t<Type>>() ? static_cast<const Type *>(data()) : nullptr;
}
/**
@@ -395,7 +391,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 *>(stl::as_const(*this).data());
}
/**
@@ -404,7 +400,7 @@ 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 *>(stl::as_const(*this).data(req));
}
/**
@@ -414,10 +410,10 @@ public:
*/
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>>();
if constexpr(stl::is_const_v<Type>) {
return stl::as_const(*this).template data<stl::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>>());
return (mode == any_policy::cref) ? nullptr : const_cast<Type *>(stl::as_const(*this).template data<stl::remove_const_t<Type>>());
}
}
@@ -430,7 +426,7 @@ public:
template<typename Type, typename... Args>
void emplace(Args &&...args) {
invoke_deleter_if_exists();
initialize<Type>(std::forward<Args>(args)...);
initialize<Type>(stl::forward<Args>(args)...);
}
/**
@@ -450,7 +446,7 @@ public:
// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
bool assign(basic_any &&other) {
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 (other.mode == any_policy::cref) ? (vtable(request::assign, *this, stl::as_const(other).data()) != nullptr) : (vtable(request::transfer, *this, other.data()) != nullptr);
}
return false;
@@ -483,22 +479,24 @@ public:
return (!*this && !other);
}
/**
* @brief Checks if two wrappers differ in their content.
* @param other Wrapper with which to compare.
* @return True if the two objects differ in their content, false otherwise.
*/
[[nodiscard]] bool operator!=(const basic_any &other) const noexcept {
return !(*this == other);
}
/**
* @brief Aliasing constructor.
* @return A wrapper that shares a reference to an unmanaged object.
*/
[[nodiscard]] basic_any as_ref() noexcept {
basic_any other = std::as_const(*this).as_ref();
other.mode = (mode == any_policy::cref ? any_policy::cref : any_policy::ref);
basic_any other = stl::as_const(*this).as_ref();
switch(mode) {
using enum any_policy;
case cref:
case empty:
other.mode = mode;
break;
default:
other.mode = any_policy::ref;
break;
}
return other;
}
@@ -543,51 +541,51 @@ private:
* @param data Target any object.
* @return The element converted to the requested type.
*/
template<typename Type, std::size_t Len, std::size_t Align>
[[nodiscard]] std::remove_const_t<Type> any_cast(const basic_any<Len, Align> &data) noexcept {
const auto *const instance = any_cast<std::remove_reference_t<Type>>(&data);
template<typename Type, stl::size_t Len, stl::size_t Align>
[[nodiscard]] stl::remove_const_t<Type> any_cast(const basic_any<Len, Align> &data) noexcept {
const auto *const instance = any_cast<stl::remove_reference_t<Type>>(&data);
ENTT_ASSERT(instance, "Invalid instance");
return static_cast<Type>(*instance);
}
/*! @copydoc any_cast */
template<typename Type, std::size_t Len, std::size_t Align>
[[nodiscard]] std::remove_const_t<Type> any_cast(basic_any<Len, Align> &data) noexcept {
template<typename Type, stl::size_t Len, stl::size_t Align>
[[nodiscard]] stl::remove_const_t<Type> any_cast(basic_any<Len, Align> &data) noexcept {
// forces const on non-reference types to make them work also with wrappers for const references
auto *const instance = any_cast<std::remove_reference_t<const Type>>(&data);
auto *const instance = any_cast<stl::remove_reference_t<const Type>>(&data);
ENTT_ASSERT(instance, "Invalid instance");
return static_cast<Type>(*instance);
}
/*! @copydoc any_cast */
template<typename Type, std::size_t Len, std::size_t Align>
template<typename Type, stl::size_t Len, stl::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_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));
[[nodiscard]] stl::remove_const_t<Type> any_cast(basic_any<Len, Align> &&data) noexcept {
if constexpr(stl::is_copy_constructible_v<stl::remove_cvref_t<Type>>) {
if(auto *const instance = any_cast<stl::remove_reference_t<Type>>(&data); instance) {
return static_cast<Type>(stl::move(*instance));
}
return any_cast<Type>(data);
} else {
auto *const instance = any_cast<std::remove_reference_t<Type>>(&data);
auto *const instance = any_cast<stl::remove_reference_t<Type>>(&data);
ENTT_ASSERT(instance, "Invalid instance");
return static_cast<Type>(std::move(*instance));
return static_cast<Type>(stl::move(*instance));
}
}
/*! @copydoc any_cast */
template<typename Type, std::size_t Len, std::size_t Align>
template<typename Type, stl::size_t Len, stl::size_t Align>
[[nodiscard]] const Type *any_cast(const basic_any<Len, Align> *data) noexcept {
return data->template data<std::remove_const_t<Type>>();
return data->template data<stl::remove_const_t<Type>>();
}
/*! @copydoc any_cast */
template<typename Type, std::size_t Len, std::size_t Align>
template<typename Type, stl::size_t Len, stl::size_t Align>
[[nodiscard]] Type *any_cast(basic_any<Len, Align> *data) noexcept {
if constexpr(std::is_const_v<Type>) {
if constexpr(stl::is_const_v<Type>) {
// last attempt to make wrappers for const references return their values
return any_cast<Type>(&std::as_const(*data));
return any_cast<Type>(&stl::as_const(*data));
} else {
return data->template data<Type>();
}
@@ -602,9 +600,9 @@ template<typename Type, std::size_t Len, std::size_t Align>
* @param args Parameters to use to construct the instance.
* @return A properly initialized wrapper for an object of the given type.
*/
template<typename Type, std::size_t Len = basic_any<>::length, std::size_t Align = basic_any<Len>::alignment, typename... Args>
template<typename Type, stl::size_t Len = basic_any<>::length, stl::size_t Align = basic_any<Len>::alignment, typename... Args>
[[nodiscard]] basic_any<Len, Align> make_any(Args &&...args) {
return basic_any<Len, Align>{std::in_place_type<Type>, std::forward<Args>(args)...};
return basic_any<Len, Align>{stl::in_place_type<Type>, stl::forward<Args>(args)...};
}
/**
@@ -615,9 +613,9 @@ template<typename Type, std::size_t Len = basic_any<>::length, std::size_t Align
* @param value Parameter to use to construct the instance.
* @return A properly initialized and not necessarily owning wrapper.
*/
template<std::size_t Len = basic_any<>::length, std::size_t Align = basic_any<Len>::alignment, typename Type>
template<stl::size_t Len = basic_any<>::length, stl::size_t Align = basic_any<Len>::alignment, typename Type>
[[nodiscard]] basic_any<Len, Align> forward_as_any(Type &&value) {
return basic_any<Len, Align>{std::in_place_type<Type &&>, std::forward<Type>(value)};
return basic_any<Len, Align>{stl::in_place_type<Type &&>, stl::forward<Type>(value)};
}
} // namespace entt

View File

@@ -1,57 +1,13 @@
#ifndef ENTT_CORE_BIT_HPP
#define ENTT_CORE_BIT_HPP
#include <cstddef>
#include <limits>
#include <type_traits>
#include "../config/config.h"
#include "../stl/bit.hpp"
#include "../stl/concepts.hpp"
#include "../stl/cstddef.hpp"
namespace entt {
/**
* @brief Returns the number of set bits in a value (waiting for C++20 and
* `std::popcount`).
* @tparam Type Unsigned integer type.
* @param value A value of unsigned integer type.
* @return The number of set bits in the value.
*/
template<typename Type>
[[nodiscard]] constexpr std::enable_if_t<std::is_unsigned_v<Type>, int> popcount(const Type value) noexcept {
return value ? (int(value & 1) + popcount(static_cast<Type>(value >> 1))) : 0;
}
/**
* @brief Checks whether a value is a power of two or not (waiting for C++20 and
* `std::has_single_bit`).
* @tparam Type Unsigned integer type.
* @param value A value of unsigned integer type.
* @return True if the value is a power of two, false otherwise.
*/
template<typename Type>
[[nodiscard]] constexpr std::enable_if_t<std::is_unsigned_v<Type>, bool> has_single_bit(const Type value) noexcept {
return value && ((value & (value - 1)) == 0);
}
/**
* @brief Computes the smallest power of two greater than or equal to a value
* (waiting for C++20 and `std::bit_ceil`).
* @tparam Type Unsigned integer type.
* @param value A value of unsigned integer type.
* @return The smallest power of two greater than or equal to the given value.
*/
template<typename Type>
[[nodiscard]] constexpr std::enable_if_t<std::is_unsigned_v<Type>, Type> next_power_of_two(const Type value) noexcept {
// NOLINTNEXTLINE(bugprone-assert-side-effect)
ENTT_ASSERT_CONSTEXPR(value < (Type{1u} << (std::numeric_limits<Type>::digits - 1)), "Numeric limits exceeded");
Type curr = value - (value != 0u);
for(int next = 1; next < std::numeric_limits<Type>::digits; next = next * 2) {
curr |= (curr >> next);
}
return ++curr;
}
/**
* @brief Fast module utility function (powers of two only).
* @tparam Type Unsigned integer type.
@@ -59,9 +15,9 @@ template<typename Type>
* @param mod _Modulus_, it must be a power of two.
* @return The common remainder.
*/
template<typename Type>
[[nodiscard]] constexpr std::enable_if_t<std::is_unsigned_v<Type>, Type> fast_mod(const Type value, const std::size_t mod) noexcept {
ENTT_ASSERT_CONSTEXPR(has_single_bit(mod), "Value must be a power of two");
template<stl::unsigned_integral Type>
[[nodiscard]] constexpr Type fast_mod(const Type value, const stl::size_t mod) noexcept {
ENTT_ASSERT_CONSTEXPR(stl::has_single_bit(mod), "Value must be a power of two");
return static_cast<Type>(value & (mod - 1u));
}

View File

@@ -1,34 +1,36 @@
#ifndef ENTT_CORE_COMPRESSED_PAIR_HPP
#define ENTT_CORE_COMPRESSED_PAIR_HPP
#include <cstddef>
#include <tuple>
#include <type_traits>
#include <utility>
#include "../stl/concepts.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/tuple.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "fwd.hpp"
#include "type_traits.hpp"
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
template<typename Type, std::size_t, typename = void>
template<typename Type, stl::size_t>
struct compressed_pair_element {
using reference = Type &;
using const_reference = const Type &;
template<typename Dummy = Type, typename = std::enable_if_t<std::is_default_constructible_v<Dummy>>>
// NOLINTNEXTLINE(modernize-use-equals-default)
constexpr compressed_pair_element() noexcept(std::is_nothrow_default_constructible_v<Type>) {}
constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v<Type>)
requires stl::default_initializable<Type> {}
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)} {}
template<typename Arg>
constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v<Type, Arg>)
requires (!stl::same_as<stl::remove_cvref_t<Arg>, compressed_pair_element>)
: value{stl::forward<Arg>(arg)} {}
template<typename... Args, std::size_t... Index>
constexpr compressed_pair_element(std::tuple<Args...> args, std::index_sequence<Index...>) noexcept(std::is_nothrow_constructible_v<Type, Args...>)
: value{std::forward<Args>(std::get<Index>(args))...} {}
template<typename... Args, stl::size_t... Index>
constexpr compressed_pair_element(stl::tuple<Args...> args, stl::index_sequence<Index...>) noexcept(stl::is_nothrow_constructible_v<Type, Args...>)
: value{stl::forward<Args>(stl::get<Index>(args))...} {}
[[nodiscard]] constexpr reference get() noexcept {
return value;
@@ -42,23 +44,25 @@ private:
Type value{};
};
template<typename Type, std::size_t Tag>
struct compressed_pair_element<Type, Tag, std::enable_if_t<is_ebco_eligible_v<Type>>>: Type {
template<typename Type, stl::size_t Tag>
requires is_ebco_eligible_v<Type>
struct compressed_pair_element<Type, Tag>: Type {
using reference = Type &;
using const_reference = const Type &;
using base_type = Type;
template<typename Dummy = Type, typename = std::enable_if_t<std::is_default_constructible_v<Dummy>>>
constexpr compressed_pair_element() noexcept(std::is_nothrow_default_constructible_v<base_type>)
constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v<base_type>)
requires stl::default_initializable<Type>
: base_type{} {}
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)} {}
template<typename Arg>
constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v<base_type, Arg>)
requires (!stl::same_as<stl::remove_cvref_t<Arg>, compressed_pair_element>)
: base_type{stl::forward<Arg>(arg)} {}
template<typename... Args, std::size_t... Index>
constexpr compressed_pair_element(std::tuple<Args...> args, std::index_sequence<Index...>) noexcept(std::is_nothrow_constructible_v<base_type, Args...>)
: base_type{std::forward<Args>(std::get<Index>(args))...} {}
template<typename... Args, stl::size_t... Index>
constexpr compressed_pair_element(stl::tuple<Args...> args, stl::index_sequence<Index...>) noexcept(stl::is_nothrow_constructible_v<base_type, Args...>)
: base_type{stl::forward<Args>(stl::get<Index>(args))...} {}
[[nodiscard]] constexpr reference get() noexcept {
return *this;
@@ -99,11 +103,9 @@ public:
*
* This constructor is only available when the types that the pair stores
* are both at least default constructible.
*
* @tparam Dummy Dummy template parameter used for internal purposes.
*/
template<bool Dummy = true, typename = std::enable_if_t<Dummy && std::is_default_constructible_v<first_type> && std::is_default_constructible_v<second_type>>>
constexpr compressed_pair() noexcept(std::is_nothrow_default_constructible_v<first_base> && std::is_nothrow_default_constructible_v<second_base>)
constexpr compressed_pair() noexcept(stl::is_nothrow_default_constructible_v<first_base> && stl::is_nothrow_default_constructible_v<second_base>)
requires stl::default_initializable<first_type> && stl::default_initializable<second_type>
: first_base{},
second_base{} {}
@@ -127,9 +129,9 @@ public:
* @param other Value to use to initialize the second element.
*/
template<typename Arg, typename Other>
constexpr compressed_pair(Arg &&arg, Other &&other) noexcept(std::is_nothrow_constructible_v<first_base, Arg> && std::is_nothrow_constructible_v<second_base, Other>)
: first_base{std::forward<Arg>(arg)},
second_base{std::forward<Other>(other)} {}
constexpr compressed_pair(Arg &&arg, Other &&other) noexcept(stl::is_nothrow_constructible_v<first_base, Arg> && stl::is_nothrow_constructible_v<second_base, Other>)
: first_base{stl::forward<Arg>(arg)},
second_base{stl::forward<Other>(other)} {}
/**
* @brief Constructs a pair by forwarding the arguments to its parts.
@@ -139,9 +141,9 @@ public:
* @param other Arguments to use to initialize the second element.
*/
template<typename... Args, typename... Other>
constexpr compressed_pair(std::piecewise_construct_t, std::tuple<Args...> args, std::tuple<Other...> other) noexcept(std::is_nothrow_constructible_v<first_base, Args...> && std::is_nothrow_constructible_v<second_base, Other...>)
: first_base{std::move(args), std::index_sequence_for<Args...>{}},
second_base{std::move(other), std::index_sequence_for<Other...>{}} {}
constexpr compressed_pair(stl::piecewise_construct_t, stl::tuple<Args...> args, stl::tuple<Other...> other) noexcept(stl::is_nothrow_constructible_v<first_base, Args...> && stl::is_nothrow_constructible_v<second_base, Other...>)
: first_base{stl::move(args), stl::index_sequence_for<Args...>{}},
second_base{stl::move(other), stl::index_sequence_for<Other...>{}} {}
/*! @brief Default destructor. */
~compressed_pair() = default;
@@ -191,7 +193,7 @@ public:
* @param other The compressed pair to swap with.
*/
constexpr void swap(compressed_pair &other) noexcept {
using std::swap;
using stl::swap;
swap(first(), other.first());
swap(second(), other.second());
}
@@ -202,23 +204,23 @@ public:
* @return Returns a reference to the first element if `Index` is 0 and a
* reference to the second element if `Index` is 1.
*/
template<std::size_t Index>
template<stl::size_t Index>
requires (Index <= 1u)
[[nodiscard]] constexpr decltype(auto) get() noexcept {
if constexpr(Index == 0u) {
return first();
} else {
static_assert(Index == 1u, "Index out of bounds");
return second();
}
}
/*! @copydoc get */
template<std::size_t Index>
template<stl::size_t Index>
requires (Index <= 1u)
[[nodiscard]] constexpr decltype(auto) get() const noexcept {
if constexpr(Index == 0u) {
return first();
} else {
static_assert(Index == 1u, "Index out of bounds");
return second();
}
}
@@ -230,7 +232,7 @@ public:
* @tparam Other Type of value to use to initialize the second element.
*/
template<typename Type, typename Other>
compressed_pair(Type &&, Other &&) -> compressed_pair<std::decay_t<Type>, std::decay_t<Other>>;
compressed_pair(Type &&, Other &&) -> compressed_pair<stl::decay_t<Type>, stl::decay_t<Other>>;
/**
* @brief Swaps two compressed pair objects.
@@ -246,27 +248,19 @@ constexpr void swap(compressed_pair<First, Second> &lhs, compressed_pair<First,
} // namespace entt
/*! @cond ENTT_INTERNAL */
#include <utility>
namespace std {
/**
* @brief `std::tuple_size` specialization for `compressed_pair`s.
* @tparam First The type of the first element that the pair stores.
* @tparam Second The type of the second element that the pair stores.
*/
template<typename First, typename Second>
struct tuple_size<entt::compressed_pair<First, Second>>: integral_constant<size_t, 2u> {};
struct tuple_size<entt::compressed_pair<First, Second>>: integral_constant<entt::stl::size_t, 2u> {};
/**
* @brief `std::tuple_element` specialization for `compressed_pair`s.
* @tparam Index The index of the type to return.
* @tparam First The type of the first element that the pair stores.
* @tparam Second The type of the second element that the pair stores.
*/
template<size_t Index, typename First, typename Second>
struct tuple_element<Index, entt::compressed_pair<First, Second>>: conditional<Index == 0u, First, Second> {
static_assert(Index < 2u, "Index out of bounds");
};
template<entt::stl::size_t Index, typename First, typename Second>
requires (Index <= 1u)
struct tuple_element<Index, entt::compressed_pair<First, Second>>: conditional<Index == 0u, First, Second> {};
} // namespace std
/*! @endcond */
#endif

View File

@@ -0,0 +1,17 @@
#ifndef ENTT_CORE_CONCEPTS_HPP
#define ENTT_CORE_CONCEPTS_HPP
#include "../stl/type_traits.hpp"
namespace entt {
/**
* @brief Specifies that a type is not a cv-qualified reference.
* @tparam Type Type to check.
*/
template<typename Type>
concept cvref_unqualified = stl::is_same_v<stl::remove_cvref_t<Type>, Type>;
} // namespace entt
#endif

View File

@@ -1,7 +1,8 @@
#ifndef ENTT_CORE_ENUM_HPP
#define ENTT_CORE_ENUM_HPP
#include <type_traits>
#include "../stl/concepts.hpp"
#include "../stl/type_traits.hpp"
namespace entt {
@@ -9,12 +10,16 @@ namespace entt {
* @brief Enable bitmask support for enum classes.
* @tparam Type The enum type for which to enable bitmask support.
*/
template<typename Type, typename = void>
struct enum_as_bitmask: std::false_type {};
template<typename Type>
struct enum_as_bitmask: stl::false_type {};
/*! @copydoc enum_as_bitmask */
template<typename Type>
struct enum_as_bitmask<Type, std::void_t<decltype(Type::_entt_enum_as_bitmask)>>: std::is_enum<Type> {};
requires requires {
requires stl::is_enum_v<Type>;
{ Type::_entt_enum_as_bitmask } -> stl::same_as<Type>;
}
struct enum_as_bitmask<Type>: stl::true_type {};
/**
* @brief Helper variable template.
@@ -23,6 +28,14 @@ struct enum_as_bitmask<Type, std::void_t<decltype(Type::_entt_enum_as_bitmask)>>
template<typename Type>
inline constexpr bool enum_as_bitmask_v = enum_as_bitmask<Type>::value;
/**
* @brief Specifies that an enum class supports bitmask operations.
* @tparam Type Enum class type.
*/
template<typename Type>
// check again that it is an enum to deal with incorrect specializations
concept enum_bitmask = stl::is_enum_v<Type> && enum_as_bitmask_v<Type>;
} // namespace entt
/**
@@ -33,24 +46,21 @@ inline constexpr bool enum_as_bitmask_v = enum_as_bitmask<Type>::value;
* @return The result of invoking the operator on the underlying types of the
* two values provided.
*/
template<typename Type>
[[nodiscard]] constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type>
operator|(const Type lhs, const Type rhs) noexcept {
return static_cast<Type>(static_cast<std::underlying_type_t<Type>>(lhs) | static_cast<std::underlying_type_t<Type>>(rhs));
template<entt::enum_bitmask Type>
[[nodiscard]] constexpr Type operator|(const Type lhs, const Type rhs) noexcept {
return static_cast<Type>(static_cast<entt::stl::underlying_type_t<Type>>(lhs) | static_cast<entt::stl::underlying_type_t<Type>>(rhs));
}
/*! @copydoc operator| */
template<typename Type>
[[nodiscard]] constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type>
operator&(const Type lhs, const Type rhs) noexcept {
return static_cast<Type>(static_cast<std::underlying_type_t<Type>>(lhs) & static_cast<std::underlying_type_t<Type>>(rhs));
template<entt::enum_bitmask Type>
[[nodiscard]] constexpr Type operator&(const Type lhs, const Type rhs) noexcept {
return static_cast<Type>(static_cast<entt::stl::underlying_type_t<Type>>(lhs) & static_cast<entt::stl::underlying_type_t<Type>>(rhs));
}
/*! @copydoc operator| */
template<typename Type>
[[nodiscard]] constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type>
operator^(const Type lhs, const Type rhs) noexcept {
return static_cast<Type>(static_cast<std::underlying_type_t<Type>>(lhs) ^ static_cast<std::underlying_type_t<Type>>(rhs));
template<entt::enum_bitmask Type>
[[nodiscard]] constexpr Type operator^(const Type lhs, const Type rhs) noexcept {
return static_cast<Type>(static_cast<entt::stl::underlying_type_t<Type>>(lhs) ^ static_cast<entt::stl::underlying_type_t<Type>>(rhs));
}
/**
@@ -60,37 +70,32 @@ operator^(const Type lhs, const Type rhs) noexcept {
* @return The result of invoking the operator on the underlying types of the
* value provided.
*/
template<typename Type>
[[nodiscard]] constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type>
operator~(const Type value) noexcept {
return static_cast<Type>(~static_cast<std::underlying_type_t<Type>>(value));
template<entt::enum_bitmask Type>
[[nodiscard]] constexpr Type operator~(const Type value) noexcept {
return static_cast<Type>(~static_cast<entt::stl::underlying_type_t<Type>>(value));
}
/*! @copydoc operator~ */
template<typename Type>
[[nodiscard]] constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, bool>
operator!(const Type value) noexcept {
return !static_cast<std::underlying_type_t<Type>>(value);
template<entt::enum_bitmask Type>
[[nodiscard]] constexpr bool operator!(const Type value) noexcept {
return !static_cast<entt::stl::underlying_type_t<Type>>(value);
}
/*! @copydoc operator| */
template<typename Type>
constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type &>
operator|=(Type &lhs, const Type rhs) noexcept {
template<entt::enum_bitmask Type>
constexpr Type &operator|=(Type &lhs, const Type rhs) noexcept {
return (lhs = (lhs | rhs));
}
/*! @copydoc operator| */
template<typename Type>
constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type &>
operator&=(Type &lhs, const Type rhs) noexcept {
template<entt::enum_bitmask Type>
constexpr Type &operator&=(Type &lhs, const Type rhs) noexcept {
return (lhs = (lhs & rhs));
}
/*! @copydoc operator| */
template<typename Type>
constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type &>
operator^=(Type &lhs, const Type rhs) noexcept {
template<entt::enum_bitmask Type>
constexpr Type &operator^=(Type &lhs, const Type rhs) noexcept {
return (lhs = (lhs ^ rhs));
}

View File

@@ -26,7 +26,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
// at the time I'm writing, clang crashes during compilation if auto is used instead of value_type
inline static const value_type value = identifier();
};

View File

@@ -1,14 +1,14 @@
#ifndef ENTT_CORE_FWD_HPP
#define ENTT_CORE_FWD_HPP
#include <cstddef>
#include <cstdint>
#include "../config/config.h"
#include "../stl/cstddef.hpp"
#include "../stl/cstdint.hpp"
namespace entt {
/*! @brief Possible modes of an any object. */
enum class any_policy : std::uint8_t {
enum class any_policy : stl::uint8_t {
/*! @brief Default mode, no element available. */
empty,
/*! @brief Owning mode, dynamically allocated element. */
@@ -22,7 +22,7 @@ enum class any_policy : std::uint8_t {
};
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
template<std::size_t Len = sizeof(double[2]), std::size_t = alignof(double[2])>
template<stl::size_t Len = sizeof(double[2]), stl::size_t = alignof(double[2])>
class basic_any;
/*! @brief Alias declaration for type identifiers. */

View File

@@ -1,26 +1,26 @@
#ifndef ENTT_CORE_HASHED_STRING_HPP
#define ENTT_CORE_HASHED_STRING_HPP
#include <cstddef>
#include <cstdint>
#include "../stl/cstddef.hpp"
#include "../stl/cstdint.hpp"
#include "fwd.hpp"
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
template<typename = id_type>
struct fnv_1a_params;
template<>
struct fnv_1a_params<std::uint32_t> {
struct fnv_1a_params<stl::uint32_t> {
static constexpr auto offset = 2166136261;
static constexpr auto prime = 16777619;
};
template<>
struct fnv_1a_params<std::uint64_t> {
struct fnv_1a_params<stl::uint64_t> {
static constexpr auto offset = 14695981039346656037ull;
static constexpr auto prime = 1099511628211ull;
};
@@ -28,7 +28,7 @@ struct fnv_1a_params<std::uint64_t> {
template<typename Char>
struct basic_hashed_string {
using value_type = Char;
using size_type = std::size_t;
using size_type = stl::size_t;
using hash_type = id_type;
const value_type *repr{};
@@ -61,19 +61,19 @@ class basic_hashed_string: internal::basic_hashed_string<Char> {
struct const_wrapper {
// non-explicit constructor on purpose
constexpr const_wrapper(const typename base_type::value_type *str) noexcept
constexpr const_wrapper(const base_type::value_type *str) noexcept
: repr{str} {}
const typename base_type::value_type *repr;
const base_type::value_type *repr;
};
public:
/*! @brief Character type. */
using value_type = typename base_type::value_type;
using value_type = base_type::value_type;
/*! @brief Unsigned integer type. */
using size_type = typename base_type::size_type;
using size_type = base_type::size_type;
/*! @brief Unsigned integer type. */
using hash_type = typename base_type::hash_type;
using hash_type = base_type::hash_type;
/**
* @brief Returns directly the numeric representation of a string view.
@@ -91,7 +91,7 @@ public:
* @param str Human-readable identifier.
* @return The numeric representation of the string.
*/
template<std::size_t N>
template<stl::size_t N>
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
[[nodiscard]] static ENTT_CONSTEVAL hash_type value(const value_type (&str)[N]) noexcept {
return basic_hashed_string{str};
@@ -130,7 +130,7 @@ public:
* @tparam N Number of characters of the identifier.
* @param str Human-readable identifier.
*/
template<std::size_t N>
template<stl::size_t N>
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
ENTT_CONSTEVAL basic_hashed_string(const value_type (&str)[N]) noexcept
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
@@ -194,6 +194,24 @@ public:
[[nodiscard]] constexpr operator hash_type() const noexcept {
return value();
}
/**
* @brief Compares two hashed strings.
* @param other A valid hashed string.
* @return True if the two hashed strings are identical, false otherwise.
*/
[[nodiscard]] constexpr bool operator==(const basic_hashed_string &other) const noexcept {
return value() == other.value();
}
/**
* @brief Lexicographically compares two hashed strings.
* @param other A valid hashed string.
* @return The relative order between the two hashed strings.
*/
[[nodiscard]] constexpr auto operator<=>(const basic_hashed_string &other) const noexcept {
return value() <=> other.value();
}
};
/**
@@ -203,7 +221,7 @@ public:
* @param len Length of the string to hash.
*/
template<typename Char>
basic_hashed_string(const Char *str, std::size_t len) -> basic_hashed_string<Char>;
basic_hashed_string(const Char *str, stl::size_t len) -> basic_hashed_string<Char>;
/**
* @brief Deduction guide.
@@ -211,85 +229,10 @@ basic_hashed_string(const Char *str, std::size_t len) -> basic_hashed_string<Cha
* @tparam N Number of characters of the identifier.
* @param str Human-readable identifier.
*/
template<typename Char, std::size_t N>
template<typename Char, stl::size_t N>
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
basic_hashed_string(const Char (&str)[N]) -> basic_hashed_string<Char>;
/**
* @brief Compares two hashed strings.
* @tparam Char Character type.
* @param lhs A valid hashed string.
* @param rhs A valid hashed string.
* @return True if the two hashed strings are identical, false otherwise.
*/
template<typename Char>
[[nodiscard]] constexpr bool operator==(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept {
return lhs.value() == rhs.value();
}
/**
* @brief Compares two hashed strings.
* @tparam Char Character type.
* @param lhs A valid hashed string.
* @param rhs A valid hashed string.
* @return True if the two hashed strings differ, false otherwise.
*/
template<typename Char>
[[nodiscard]] constexpr bool operator!=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept {
return !(lhs == rhs);
}
/**
* @brief Compares two hashed strings.
* @tparam Char Character type.
* @param lhs A valid hashed string.
* @param rhs A valid hashed string.
* @return True if the first element is less than the second, false otherwise.
*/
template<typename Char>
[[nodiscard]] constexpr bool operator<(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept {
return lhs.value() < rhs.value();
}
/**
* @brief Compares two hashed strings.
* @tparam Char Character type.
* @param lhs A valid hashed string.
* @param rhs A valid hashed string.
* @return True if the first element is less than or equal to the second, false
* otherwise.
*/
template<typename Char>
[[nodiscard]] constexpr bool operator<=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept {
return !(rhs < lhs);
}
/**
* @brief Compares two hashed strings.
* @tparam Char Character type.
* @param lhs A valid hashed string.
* @param rhs A valid hashed string.
* @return True if the first element is greater than the second, false
* otherwise.
*/
template<typename Char>
[[nodiscard]] constexpr bool operator>(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept {
return rhs < lhs;
}
/**
* @brief Compares two hashed strings.
* @tparam Char Character type.
* @param lhs A valid hashed string.
* @param rhs A valid hashed string.
* @return True if the first element is greater than or equal to the second,
* false otherwise.
*/
template<typename Char>
[[nodiscard]] constexpr bool operator>=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept {
return !(lhs < rhs);
}
inline namespace literals {
/**
@@ -297,7 +240,7 @@ inline namespace literals {
* @param str The literal without its suffix.
* @return A properly initialized hashed string.
*/
[[nodiscard]] ENTT_CONSTEVAL hashed_string operator""_hs(const char *str, std::size_t) noexcept {
[[nodiscard]] ENTT_CONSTEVAL hashed_string operator""_hs(const char *str, stl::size_t) noexcept {
return hashed_string{str};
}
@@ -306,7 +249,7 @@ inline namespace literals {
* @param str The literal without its suffix.
* @return A properly initialized hashed wstring.
*/
[[nodiscard]] ENTT_CONSTEVAL hashed_wstring operator""_hws(const wchar_t *str, std::size_t) noexcept {
[[nodiscard]] ENTT_CONSTEVAL hashed_wstring operator""_hws(const wchar_t *str, stl::size_t) noexcept {
return hashed_wstring{str};
}

View File

@@ -1,9 +1,9 @@
#ifndef ENTT_CORE_IDENT_HPP
#define ENTT_CORE_IDENT_HPP
#include <cstddef>
#include <type_traits>
#include <utility>
#include "../stl/cstddef.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "fwd.hpp"
#include "type_traits.hpp"
@@ -15,10 +15,9 @@ namespace entt {
*/
template<typename... Type>
class ident {
template<typename Curr, std::size_t... Index>
[[nodiscard]] static constexpr id_type get(std::index_sequence<Index...>) noexcept {
static_assert((std::is_same_v<Curr, Type> || ...), "Invalid type");
return (0 + ... + (std::is_same_v<Curr, type_list_element_t<Index, type_list<std::decay_t<Type>...>>> ? id_type{Index} : id_type{}));
template<typename Curr, stl::size_t... Index>
[[nodiscard]] static ENTT_CONSTEVAL id_type get(stl::index_sequence<Index...>) noexcept {
return (0 + ... + (stl::is_same_v<Curr, type_list_element_t<Index, type_list<stl::decay_t<Type>...>>> ? id_type{Index} : id_type{}));
}
public:
@@ -27,7 +26,8 @@ public:
/*! @brief Statically generated unique identifier for the given type. */
template<typename Curr>
static constexpr value_type value = get<std::decay_t<Curr>>(std::index_sequence_for<Type...>{});
requires (stl::is_same_v<stl::remove_cvref_t<Curr>, Type> || ...)
static constexpr value_type value = get<stl::remove_cvref_t<Curr>>(stl::index_sequence_for<Type...>{});
};
} // namespace entt

View File

@@ -1,10 +1,12 @@
#ifndef ENTT_CORE_ITERATOR_HPP
#define ENTT_CORE_ITERATOR_HPP
#include <iterator>
#include <memory>
#include <type_traits>
#include <utility>
#include "../stl/concepts.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/iterator.hpp"
#include "../stl/memory.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
namespace entt {
@@ -25,15 +27,15 @@ struct input_iterator_pointer final {
* @brief Constructs a proxy object by move.
* @param val Value to use to initialize the proxy object.
*/
constexpr input_iterator_pointer(value_type &&val) noexcept(std::is_nothrow_move_constructible_v<value_type>)
: value{std::move(val)} {}
constexpr input_iterator_pointer(value_type &&val) noexcept(stl::is_nothrow_move_constructible_v<value_type>)
: value{stl::move(val)} {}
/**
* @brief Access operator for accessing wrapped values.
* @return A pointer to the wrapped value.
*/
[[nodiscard]] constexpr pointer operator->() noexcept {
return std::addressof(value);
return stl::addressof(value);
}
/**
@@ -52,11 +54,8 @@ private:
* @brief Plain iota iterator (waiting for C++20).
* @tparam Type Value type.
*/
template<typename Type>
class iota_iterator final {
static_assert(std::is_integral_v<Type>, "Not an integral type");
public:
template<stl::integral Type>
struct iota_iterator final {
/*! @brief Value type, likely an integral one. */
using value_type = Type;
/*! @brief Invalid pointer type. */
@@ -64,9 +63,9 @@ public:
/*! @brief Non-reference type, same as value type. */
using reference = value_type;
/*! @brief Difference type. */
using difference_type = std::ptrdiff_t;
using difference_type = stl::ptrdiff_t;
/*! @brief Iterator category. */
using iterator_category = std::input_iterator_tag;
using iterator_category = stl::input_iterator_tag;
/*! @brief Default constructor. */
constexpr iota_iterator() noexcept
@@ -104,50 +103,35 @@ public:
return current;
}
/**
* @brief Comparison operator.
* @param other A properly initialized iota iterator.
* @return True if the two iterators are identical, false otherwise.
*/
[[nodiscard]] constexpr bool operator==(const iota_iterator &other) const noexcept {
return current == other.current;
}
private:
value_type current;
};
/**
* @brief Comparison operator.
* @tparam Type Value type of the iota iterator.
* @param lhs A properly initialized iota iterator.
* @param rhs A properly initialized iota iterator.
* @return True if the two iterators are identical, false otherwise.
*/
template<typename Type>
[[nodiscard]] constexpr bool operator==(const iota_iterator<Type> &lhs, const iota_iterator<Type> &rhs) noexcept {
return *lhs == *rhs;
}
/**
* @brief Comparison operator.
* @tparam Type Value type of the iota iterator.
* @param lhs A properly initialized iota iterator.
* @param rhs A properly initialized iota iterator.
* @return True if the two iterators differ, false otherwise.
*/
template<typename Type>
[[nodiscard]] constexpr bool operator!=(const iota_iterator<Type> &lhs, const iota_iterator<Type> &rhs) noexcept {
return !(lhs == rhs);
}
/**
* @brief Utility class to create an iterable object from a pair of iterators.
* @tparam It Type of iterator.
* @tparam Sentinel Type of sentinel.
*/
template<typename It, typename Sentinel = It>
template<stl::input_or_output_iterator It, stl::sentinel_for<It> Sentinel = It>
struct iterable_adaptor final {
/*! @brief Value type. */
using value_type = typename std::iterator_traits<It>::value_type;
using value_type = stl::iterator_traits<It>::value_type;
/*! @brief Iterator type. */
using iterator = It;
/*! @brief Sentinel type. */
using sentinel = Sentinel;
/*! @brief Default constructor. */
constexpr iterable_adaptor() noexcept(std::is_nothrow_default_constructible_v<iterator> && std::is_nothrow_default_constructible_v<sentinel>)
constexpr iterable_adaptor() noexcept(stl::is_nothrow_default_constructible_v<iterator> && stl::is_nothrow_default_constructible_v<sentinel>)
: first{},
last{} {}
@@ -156,9 +140,9 @@ struct iterable_adaptor final {
* @param from Begin iterator.
* @param to End iterator.
*/
constexpr iterable_adaptor(iterator from, sentinel to) noexcept(std::is_nothrow_move_constructible_v<iterator> && std::is_nothrow_move_constructible_v<sentinel>)
: first{std::move(from)},
last{std::move(to)} {}
constexpr iterable_adaptor(iterator from, sentinel to) noexcept(stl::is_nothrow_move_constructible_v<iterator> && stl::is_nothrow_move_constructible_v<sentinel>)
: first{stl::move(from)},
last{stl::move(to)} {}
/**
* @brief Returns an iterator to the beginning.

View File

@@ -1,30 +1,15 @@
#ifndef ENTT_CORE_MEMORY_HPP
#define ENTT_CORE_MEMORY_HPP
#include <cstddef>
#include <memory>
#include <tuple>
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "../stl/cstddef.hpp"
#include "../stl/memory.hpp"
#include "../stl/tuple.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
namespace entt {
/**
* @brief Unwraps fancy pointers, does nothing otherwise (waiting for C++20).
* @tparam Type Pointer type.
* @param ptr Fancy or raw pointer.
* @return A raw pointer that represents the address of the original pointer.
*/
template<typename Type>
[[nodiscard]] constexpr auto to_address(Type &&ptr) noexcept {
if constexpr(std::is_pointer_v<std::decay_t<Type>>) {
return ptr;
} else {
return to_address(std::forward<Type>(ptr).operator->());
}
}
/**
* @brief Utility function to design allocation-aware containers.
* @tparam Allocator Type of allocator.
@@ -33,7 +18,7 @@ template<typename Type>
*/
template<typename Allocator>
constexpr void propagate_on_container_copy_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept {
if constexpr(std::allocator_traits<Allocator>::propagate_on_container_copy_assignment::value) {
if constexpr(stl::allocator_traits<Allocator>::propagate_on_container_copy_assignment::value) {
lhs = rhs;
}
}
@@ -46,8 +31,8 @@ constexpr void propagate_on_container_copy_assignment([[maybe_unused]] Allocator
*/
template<typename Allocator>
constexpr void propagate_on_container_move_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept {
if constexpr(std::allocator_traits<Allocator>::propagate_on_container_move_assignment::value) {
lhs = std::move(rhs);
if constexpr(stl::allocator_traits<Allocator>::propagate_on_container_move_assignment::value) {
lhs = stl::move(rhs);
}
}
@@ -59,8 +44,8 @@ constexpr void propagate_on_container_move_assignment([[maybe_unused]] Allocator
*/
template<typename Allocator>
constexpr void propagate_on_container_swap([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept {
if constexpr(std::allocator_traits<Allocator>::propagate_on_container_swap::value) {
using std::swap;
if constexpr(stl::allocator_traits<Allocator>::propagate_on_container_swap::value) {
using stl::swap;
swap(lhs, rhs);
} else {
ENTT_ASSERT_CONSTEXPR(lhs == rhs, "Cannot swap the containers");
@@ -76,28 +61,28 @@ struct allocation_deleter: private Allocator {
/*! @brief Allocator type. */
using allocator_type = Allocator;
/*! @brief Pointer type. */
using pointer = typename std::allocator_traits<Allocator>::pointer;
using pointer = stl::allocator_traits<Allocator>::pointer;
/**
* @brief Inherited constructors.
* @param alloc The allocator to use.
*/
constexpr allocation_deleter(const allocator_type &alloc) noexcept(std::is_nothrow_copy_constructible_v<allocator_type>)
constexpr allocation_deleter(const allocator_type &alloc) noexcept(stl::is_nothrow_copy_constructible_v<allocator_type>)
: Allocator{alloc} {}
/**
* @brief Destroys the pointed object and deallocates its memory.
* @param ptr A valid pointer to an object of the given type.
*/
constexpr void operator()(pointer ptr) noexcept(std::is_nothrow_destructible_v<typename allocator_type::value_type>) {
using alloc_traits = std::allocator_traits<Allocator>;
alloc_traits::destroy(*this, to_address(ptr));
constexpr void operator()(pointer ptr) noexcept(stl::is_nothrow_destructible_v<typename allocator_type::value_type>) {
using alloc_traits = stl::allocator_traits<Allocator>;
alloc_traits::destroy(*this, stl::to_address(ptr));
alloc_traits::deallocate(*this, ptr, 1u);
}
};
/**
* @brief Allows `std::unique_ptr` to use allocators (waiting for C++20).
* @brief Allows `stl::unique_ptr` to use allocators (waiting for C++20).
* @tparam Type Type of object to allocate for and to construct.
* @tparam Allocator Type of allocator used to manage memory and elements.
* @tparam Args Types of arguments to use to construct the object.
@@ -106,78 +91,77 @@ struct allocation_deleter: private Allocator {
* @return A properly initialized unique pointer with a custom deleter.
*/
template<typename Type, typename Allocator, typename... Args>
ENTT_CONSTEXPR auto allocate_unique(Allocator &allocator, Args &&...args) {
static_assert(!std::is_array_v<Type>, "Array types are not supported");
constexpr auto allocate_unique(Allocator &allocator, Args &&...args) {
static_assert(!stl::is_array_v<Type>, "Array types are not supported");
using alloc_traits = typename std::allocator_traits<Allocator>::template rebind_traits<Type>;
using allocator_type = typename alloc_traits::allocator_type;
using alloc_traits = stl::allocator_traits<Allocator>::template rebind_traits<Type>;
using allocator_type = alloc_traits::allocator_type;
allocator_type alloc{allocator};
auto ptr = alloc_traits::allocate(alloc, 1u);
ENTT_TRY {
alloc_traits::construct(alloc, to_address(ptr), std::forward<Args>(args)...);
alloc_traits::construct(alloc, stl::to_address(ptr), stl::forward<Args>(args)...);
}
ENTT_CATCH {
alloc_traits::deallocate(alloc, ptr, 1u);
ENTT_THROW;
}
return std::unique_ptr<Type, allocation_deleter<allocator_type>>{ptr, alloc};
return stl::unique_ptr<Type, allocation_deleter<allocator_type>>{ptr, alloc};
}
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
template<typename Type>
struct uses_allocator_construction {
template<typename Allocator, typename... Params>
static constexpr auto args([[maybe_unused]] const Allocator &allocator, Params &&...params) noexcept {
if constexpr(!std::uses_allocator_v<Type, Allocator> && std::is_constructible_v<Type, Params...>) {
return std::forward_as_tuple(std::forward<Params>(params)...);
if constexpr(!stl::uses_allocator_v<Type, Allocator> && stl::is_constructible_v<Type, Params...>) {
return stl::forward_as_tuple(stl::forward<Params>(params)...);
} else {
static_assert(std::uses_allocator_v<Type, Allocator>, "Ill-formed request");
static_assert(stl::uses_allocator_v<Type, Allocator>, "Ill-formed request");
if constexpr(std::is_constructible_v<Type, std::allocator_arg_t, const Allocator &, Params...>) {
return std::tuple<std::allocator_arg_t, const Allocator &, Params &&...>{std::allocator_arg, allocator, std::forward<Params>(params)...};
if constexpr(stl::is_constructible_v<Type, stl::allocator_arg_t, const Allocator &, Params...>) {
return stl::tuple<stl::allocator_arg_t, const Allocator &, Params &&...>{stl::allocator_arg, allocator, stl::forward<Params>(params)...};
} else {
static_assert(std::is_constructible_v<Type, Params..., const Allocator &>, "Ill-formed request");
return std::forward_as_tuple(std::forward<Params>(params)..., allocator);
static_assert(stl::is_constructible_v<Type, Params..., const Allocator &>, "Ill-formed request");
return stl::forward_as_tuple(stl::forward<Params>(params)..., allocator);
}
}
}
};
template<typename Type, typename Other>
struct uses_allocator_construction<std::pair<Type, Other>> {
using type = std::pair<Type, Other>;
struct uses_allocator_construction<stl::pair<Type, Other>> {
using type = stl::pair<Type, Other>;
template<typename Allocator, typename First, typename Second>
static constexpr auto args(const Allocator &allocator, std::piecewise_construct_t, First &&first, Second &&second) noexcept {
return std::make_tuple(
std::piecewise_construct,
std::apply([&allocator](auto &&...curr) { return uses_allocator_construction<Type>::args(allocator, std::forward<decltype(curr)>(curr)...); }, std::forward<First>(first)),
std::apply([&allocator](auto &&...curr) { return uses_allocator_construction<Other>::args(allocator, std::forward<decltype(curr)>(curr)...); }, std::forward<Second>(second)));
template<typename First, typename Second>
static constexpr auto args(const auto &allocator, stl::piecewise_construct_t, First &&first, Second &&second) noexcept {
return stl::make_tuple(
stl::piecewise_construct,
stl::apply([&allocator](auto &&...curr) { return uses_allocator_construction<Type>::args(allocator, stl::forward<decltype(curr)>(curr)...); }, stl::forward<First>(first)),
stl::apply([&allocator](auto &&...curr) { return uses_allocator_construction<Other>::args(allocator, stl::forward<decltype(curr)>(curr)...); }, stl::forward<Second>(second)));
}
template<typename Allocator>
static constexpr auto args(const Allocator &allocator) noexcept {
return uses_allocator_construction<type>::args(allocator, std::piecewise_construct, std::tuple<>{}, std::tuple<>{});
static constexpr auto args(const auto &allocator) noexcept {
return uses_allocator_construction<type>::args(allocator, stl::piecewise_construct, stl::tuple<>{}, stl::tuple<>{});
}
template<typename Allocator, typename First, typename Second>
static constexpr auto args(const Allocator &allocator, First &&first, Second &&second) noexcept {
return uses_allocator_construction<type>::args(allocator, std::piecewise_construct, std::forward_as_tuple(std::forward<First>(first)), std::forward_as_tuple(std::forward<Second>(second)));
template<typename First, typename Second>
static constexpr auto args(const auto &allocator, First &&first, Second &&second) noexcept {
return uses_allocator_construction<type>::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(stl::forward<First>(first)), stl::forward_as_tuple(stl::forward<Second>(second)));
}
template<typename Allocator, typename First, typename Second>
static constexpr auto args(const Allocator &allocator, const std::pair<First, Second> &value) noexcept {
return uses_allocator_construction<type>::args(allocator, std::piecewise_construct, std::forward_as_tuple(value.first), std::forward_as_tuple(value.second));
template<typename First, typename Second>
static constexpr auto args(const auto &allocator, const stl::pair<First, Second> &value) noexcept {
return uses_allocator_construction<type>::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(value.first), stl::forward_as_tuple(value.second));
}
template<typename Allocator, typename First, typename Second>
static constexpr auto args(const Allocator &allocator, std::pair<First, Second> &&value) noexcept {
return uses_allocator_construction<type>::args(allocator, std::piecewise_construct, std::forward_as_tuple(std::move(value.first)), std::forward_as_tuple(std::move(value.second)));
template<typename First, typename Second>
static constexpr auto args(const auto &allocator, stl::pair<First, Second> &&value) noexcept {
return uses_allocator_construction<type>::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(stl::move(value.first)), stl::forward_as_tuple(stl::move(value.second)));
}
};
@@ -191,15 +175,14 @@ struct uses_allocator_construction<std::pair<Type, Other>> {
* create an object of a given type by means of uses-allocator construction.
*
* @tparam Type Type to return arguments for.
* @tparam Allocator Type of allocator used to manage memory and elements.
* @tparam Args Types of arguments to use to construct the object.
* @param allocator The allocator to use.
* @param args Parameters to use to construct the object.
* @return The arguments needed to create an object of the given type.
*/
template<typename Type, typename Allocator, typename... Args>
constexpr auto uses_allocator_construction_args(const Allocator &allocator, Args &&...args) noexcept {
return internal::uses_allocator_construction<Type>::args(allocator, std::forward<Args>(args)...);
template<typename Type, typename... Args>
constexpr auto uses_allocator_construction_args(const auto &allocator, Args &&...args) noexcept {
return internal::uses_allocator_construction<Type>::args(allocator, stl::forward<Args>(args)...);
}
/**
@@ -209,15 +192,14 @@ constexpr auto uses_allocator_construction_args(const Allocator &allocator, Args
* means of uses-allocator construction.
*
* @tparam Type Type of object to create.
* @tparam Allocator Type of allocator used to manage memory and elements.
* @tparam Args Types of arguments to use to construct the object.
* @param allocator The allocator to use.
* @param args Parameters to use to construct the object.
* @return A newly created object of the given type.
*/
template<typename Type, typename Allocator, typename... Args>
constexpr Type make_obj_using_allocator(const Allocator &allocator, Args &&...args) {
return std::make_from_tuple<Type>(internal::uses_allocator_construction<Type>::args(allocator, std::forward<Args>(args)...));
template<typename Type, typename... Args>
constexpr Type make_obj_using_allocator(const auto &allocator, Args &&...args) {
return stl::make_from_tuple<Type>(internal::uses_allocator_construction<Type>::args(allocator, stl::forward<Args>(args)...));
}
/**
@@ -227,16 +209,15 @@ constexpr Type make_obj_using_allocator(const Allocator &allocator, Args &&...ar
* means of uses-allocator construction at an uninitialized memory location.
*
* @tparam Type Type of object to create.
* @tparam Allocator Type of allocator used to manage memory and elements.
* @tparam Args Types of arguments to use to construct the object.
* @param value Memory location in which to place the object.
* @param allocator The allocator to use.
* @param args Parameters to use to construct the object.
* @return A pointer to the newly created object of the given type.
*/
template<typename Type, typename Allocator, typename... Args>
constexpr Type *uninitialized_construct_using_allocator(Type *value, const Allocator &allocator, Args &&...args) {
return std::apply([value](auto &&...curr) { return ::new(value) Type(std::forward<decltype(curr)>(curr)...); }, internal::uses_allocator_construction<Type>::args(allocator, std::forward<Args>(args)...));
template<typename Type, typename... Args>
constexpr Type *uninitialized_construct_using_allocator(Type *value, const auto &allocator, Args &&...args) {
return stl::apply([value](auto &&...curr) { return ::new(value) Type(stl::forward<decltype(curr)>(curr)...); }, internal::uses_allocator_construction<Type>::args(allocator, stl::forward<Args>(args)...));
}
} // namespace entt

View File

@@ -1,20 +1,22 @@
#ifndef ENTT_CORE_RANGES_HPP
#define ENTT_CORE_RANGES_HPP
#if __has_include(<version>)
# include <version>
#
# if defined(__cpp_lib_ranges)
# include <ranges>
# include "iterator.hpp"
#include <version>
#if defined(__cpp_lib_ranges)
# include <ranges>
# include "iterator.hpp"
namespace std::ranges {
template<class... Args>
inline constexpr bool std::ranges::enable_borrowed_range<entt::iterable_adaptor<Args...>>{true};
inline constexpr bool enable_borrowed_range<entt::iterable_adaptor<Args...>>{true};
template<class... Args>
inline constexpr bool std::ranges::enable_view<entt::iterable_adaptor<Args...>>{true};
inline constexpr bool enable_view<entt::iterable_adaptor<Args...>>{true};
} // namespace std::ranges
# endif
#endif
#endif
#endif

View File

@@ -1,9 +1,9 @@
#ifndef ENTT_CORE_TUPLE_HPP
#define ENTT_CORE_TUPLE_HPP
#include <tuple>
#include <type_traits>
#include <utility>
#include "../stl/tuple.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
namespace entt {
@@ -13,14 +13,14 @@ namespace entt {
* @tparam Type The type to test.
*/
template<typename Type>
struct is_tuple: std::false_type {};
struct is_tuple: stl::false_type {};
/**
* @copybrief is_tuple
* @tparam Args Tuple template arguments.
*/
template<typename... Args>
struct is_tuple<std::tuple<Args...>>: std::true_type {};
struct is_tuple<stl::tuple<Args...>>: stl::true_type {};
/**
* @brief Helper variable template.
@@ -38,10 +38,10 @@ inline constexpr bool is_tuple_v = is_tuple<Type>::value;
*/
template<typename Type>
constexpr decltype(auto) unwrap_tuple(Type &&value) noexcept {
if constexpr(std::tuple_size_v<std::remove_reference_t<Type>> == 1u) {
return std::get<0>(std::forward<Type>(value));
if constexpr(stl::tuple_size_v<stl::remove_reference_t<Type>> == 1u) {
return stl::get<0>(stl::forward<Type>(value));
} else {
return std::forward<Type>(value);
return stl::forward<Type>(value);
}
}
@@ -57,8 +57,8 @@ struct forward_apply: private Func {
* @param args Parameters to use to construct the instance.
*/
template<typename... Args>
constexpr forward_apply(Args &&...args) noexcept(std::is_nothrow_constructible_v<Func, Args...>)
: Func{std::forward<Args>(args)...} {}
constexpr forward_apply(Args &&...args) noexcept(stl::is_nothrow_constructible_v<Func, Args...>)
: Func{stl::forward<Args>(args)...} {}
/**
* @brief Forwards and applies the arguments with the underlying function.
@@ -67,14 +67,14 @@ struct forward_apply: private Func {
* @return Return value of the underlying function, if any.
*/
template<typename Type>
constexpr decltype(auto) operator()(Type &&args) noexcept(noexcept(std::apply(std::declval<Func &>(), args))) {
return std::apply(static_cast<Func &>(*this), std::forward<Type>(args));
constexpr decltype(auto) operator()(Type &&args) noexcept(noexcept(stl::apply(stl::declval<Func &>(), args))) {
return stl::apply(static_cast<Func &>(*this), stl::forward<Type>(args));
}
/*! @copydoc operator()() */
template<typename Type>
constexpr decltype(auto) operator()(Type &&args) const noexcept(noexcept(std::apply(std::declval<const Func &>(), args))) {
return std::apply(static_cast<const Func &>(*this), std::forward<Type>(args));
constexpr decltype(auto) operator()(Type &&args) const noexcept(noexcept(stl::apply(stl::declval<const Func &>(), args))) {
return stl::apply(static_cast<const Func &>(*this), stl::forward<Type>(args));
}
};
@@ -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_const_t<Func>>>;
forward_apply(Func) -> forward_apply<stl::remove_cvref_t<Func>>;
} // namespace entt

View File

@@ -1,16 +1,17 @@
#ifndef ENTT_CORE_TYPE_INFO_HPP
#define ENTT_CORE_TYPE_INFO_HPP
#include <string_view>
#include <type_traits>
#include <utility>
#include <compare>
#include "../config/config.h"
#include "../stl/string_view.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "fwd.hpp"
#include "hashed_string.hpp"
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
struct ENTT_API type_index final {
@@ -32,29 +33,29 @@ template<typename Type>
template<typename Type>
[[nodiscard]] constexpr auto stripped_type_name() noexcept {
#if defined ENTT_PRETTY_FUNCTION
const std::string_view full_name{pretty_function<Type>()};
const stl::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 stl::string_view{};
#endif
}
template<typename Type, auto = stripped_type_name<Type>().find_first_of('.')>
[[nodiscard]] constexpr std::string_view type_name(int) noexcept {
[[nodiscard]] ENTT_CONSTEVAL stl::string_view type_name(int) noexcept {
constexpr auto value = stripped_type_name<Type>();
return value;
}
template<typename Type>
[[nodiscard]] std::string_view type_name(char) noexcept {
[[nodiscard]] stl::string_view type_name(char) noexcept {
static const auto value = stripped_type_name<Type>();
return value;
}
template<typename Type, auto = stripped_type_name<Type>().find_first_of('.')>
[[nodiscard]] constexpr id_type type_hash(int) noexcept {
[[nodiscard]] ENTT_CONSTEVAL id_type type_hash(int) noexcept {
constexpr auto stripped = stripped_type_name<Type>();
constexpr auto value = hashed_string::value(stripped.data(), stripped.size());
return value;
@@ -75,7 +76,7 @@ template<typename Type>
* @brief Type sequential identifier.
* @tparam Type Type for which to generate a sequential identifier.
*/
template<typename Type, typename = void>
template<typename Type>
struct ENTT_API type_index final {
/**
* @brief Returns the sequential identifier of a given type.
@@ -96,7 +97,7 @@ struct ENTT_API type_index final {
* @brief Type hash.
* @tparam Type Type for which to generate a hash value.
*/
template<typename Type, typename = void>
template<typename Type>
struct type_hash final {
/**
* @brief Returns the numeric representation of a given type.
@@ -121,18 +122,18 @@ struct type_hash final {
* @brief Type name.
* @tparam Type Type for which to generate a name.
*/
template<typename Type, typename = void>
template<typename Type>
struct type_name final {
/**
* @brief Returns the name of a given type.
* @return The name of the given type.
*/
[[nodiscard]] static constexpr std::string_view value() noexcept {
[[nodiscard]] static constexpr stl::string_view value() noexcept {
return internal::type_name<Type>(0);
}
/*! @copydoc value */
[[nodiscard]] constexpr operator std::string_view() const noexcept {
[[nodiscard]] constexpr operator stl::string_view() const noexcept {
return value();
}
};
@@ -145,10 +146,10 @@ 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_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()} {}
constexpr type_info(stl::in_place_type_t<Type>) noexcept
: seq{type_index<stl::remove_cvref_t<Type>>::value()},
identifier{type_hash<stl::remove_cvref_t<Type>>::value()},
alias{type_name<stl::remove_cvref_t<Type>>::value()} {}
// NOLINTEND(modernize-use-transparent-functors)
/**
@@ -171,79 +172,34 @@ struct type_info final {
* @brief Type name.
* @return Type name.
*/
[[nodiscard]] constexpr std::string_view name() const noexcept {
[[nodiscard]] constexpr stl::string_view name() const noexcept {
return alias;
}
/**
* @brief Compares two type info objects.
* @param other A type info object.
* @return True if the two type info objects are identical, false otherwise.
*/
[[nodiscard]] constexpr bool operator==(const type_info &other) const noexcept {
return identifier == other.identifier;
}
/**
* @brief Lexicographically compares two type info objects.
* @param other A type info object.
* @return The relative order between the two type info objects.
*/
[[nodiscard]] constexpr auto operator<=>(const type_info &other) const noexcept {
return seq <=> other.seq;
}
private:
id_type seq;
id_type identifier;
std::string_view alias;
stl::string_view alias;
};
/**
* @brief Compares the contents of two type info objects.
* @param lhs A type info object.
* @param rhs A type info object.
* @return True if the two type info objects are identical, false otherwise.
*/
[[nodiscard]] constexpr bool operator==(const type_info &lhs, const type_info &rhs) noexcept {
return lhs.hash() == rhs.hash();
}
/**
* @brief Compares the contents of two type info objects.
* @param lhs A type info object.
* @param rhs A type info object.
* @return True if the two type info objects differ, false otherwise.
*/
[[nodiscard]] constexpr bool operator!=(const type_info &lhs, const type_info &rhs) noexcept {
return !(lhs == rhs);
}
/**
* @brief Compares two type info objects.
* @param lhs A valid type info object.
* @param rhs A valid type info object.
* @return True if the first element is less than the second, false otherwise.
*/
[[nodiscard]] constexpr bool operator<(const type_info &lhs, const type_info &rhs) noexcept {
return lhs.index() < rhs.index();
}
/**
* @brief Compares two type info objects.
* @param lhs A valid type info object.
* @param rhs A valid type info object.
* @return True if the first element is less than or equal to the second, false
* otherwise.
*/
[[nodiscard]] constexpr bool operator<=(const type_info &lhs, const type_info &rhs) noexcept {
return !(rhs < lhs);
}
/**
* @brief Compares two type info objects.
* @param lhs A valid type info object.
* @param rhs A valid type info object.
* @return True if the first element is greater than the second, false
* otherwise.
*/
[[nodiscard]] constexpr bool operator>(const type_info &lhs, const type_info &rhs) noexcept {
return rhs < lhs;
}
/**
* @brief Compares two type info objects.
* @param lhs A valid type info object.
* @param rhs A valid type info object.
* @return True if the first element is greater than or equal to the second,
* false otherwise.
*/
[[nodiscard]] constexpr bool operator>=(const type_info &lhs, const type_info &rhs) noexcept {
return !(lhs < rhs);
}
/**
* @brief Returns the type info object associated to a given type.
*
@@ -257,19 +213,18 @@ private:
*/
template<typename Type>
[[nodiscard]] const type_info &type_id() noexcept {
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>};
if constexpr(stl::is_same_v<Type, stl::remove_cvref_t<Type>>) {
static const type_info instance{stl::in_place_type<Type>};
return instance;
} else {
return type_id<std::remove_const_t<std::remove_reference_t<Type>>>();
return type_id<stl::remove_cvref_t<Type>>();
}
}
/*! @copydoc type_id */
template<typename Type>
// NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward)
[[nodiscard]] const type_info &type_id(Type &&) noexcept {
return type_id<std::remove_const_t<std::remove_reference_t<Type>>>();
[[nodiscard]] const type_info &type_id(const Type &) noexcept {
return type_id<stl::remove_cvref_t<Type>>();
}
} // namespace entt

View File

@@ -1,12 +1,13 @@
#ifndef ENTT_CORE_TYPE_TRAITS_HPP
#define ENTT_CORE_TYPE_TRAITS_HPP
#include <cstddef>
#include <iterator>
#include <tuple>
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "../stl/concepts.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/iterator.hpp"
#include "../stl/tuple.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "fwd.hpp"
namespace entt {
@@ -15,10 +16,10 @@ namespace entt {
* @brief Utility class to disambiguate overloaded functions.
* @tparam N Number of choices available.
*/
template<std::size_t N>
template<stl::size_t N>
struct choice_t
// unfortunately, doxygen cannot parse such a construct
: /*! @cond TURN_OFF_DOXYGEN */ choice_t<N - 1> /*! @endcond */
: /*! @cond ENTT_INTERNAL */ choice_t<N - 1> /*! @endcond */
{};
/*! @copybrief choice_t */
@@ -29,49 +30,29 @@ struct choice_t<0> {};
* @brief Variable template for the choice trick.
* @tparam N Number of choices available.
*/
template<std::size_t N>
template<stl::size_t N>
inline constexpr choice_t<N> choice{};
/**
* @brief Identity type trait.
*
* Useful to establish non-deduced contexts in template argument deduction
* (waiting for C++20) or to provide types through function arguments.
*
* @tparam Type A type.
*/
template<typename Type>
struct type_identity {
/*! @brief Identity type. */
using type = Type;
};
/**
* @brief Helper type.
* @tparam Type A type.
*/
template<typename Type>
using type_identity_t = typename type_identity<Type>::type;
/**
* @brief A type-only `sizeof` wrapper that returns 0 where `sizeof` complains.
* @tparam Type The type of which to return the size.
*/
template<typename Type, typename = void>
struct size_of: std::integral_constant<std::size_t, 0u> {};
template<typename Type>
struct size_of: stl::integral_constant<stl::size_t, 0u> {};
/*! @copydoc size_of */
template<typename Type>
struct size_of<Type, std::void_t<decltype(sizeof(Type))>>
requires requires { sizeof(Type); }
struct size_of<Type>
// NOLINTNEXTLINE(bugprone-sizeof-expression)
: std::integral_constant<std::size_t, sizeof(Type)> {};
: stl::integral_constant<stl::size_t, sizeof(Type)> {};
/**
* @brief Helper variable template.
* @tparam Type The type of which to return the size.
*/
template<typename Type>
inline constexpr std::size_t size_of_v = size_of<Type>::value;
inline constexpr stl::size_t size_of_v = size_of<Type>::value;
/**
* @brief Using declaration to be used to _repeat_ the same type a number of
@@ -94,7 +75,7 @@ inline constexpr auto unpack_as_value = Value;
* @tparam Value A static constant.
*/
template<auto Value>
using integral_constant = std::integral_constant<decltype(Value), Value>;
using integral_constant = stl::integral_constant<decltype(Value), Value>;
/**
* @brief Alias template to facilitate the creation of named values.
@@ -116,7 +97,7 @@ struct type_list {
};
/*! @brief Primary template isn't defined on purpose. */
template<std::size_t, typename>
template<stl::size_t, typename>
struct type_list_element;
/**
@@ -125,7 +106,7 @@ struct type_list_element;
* @tparam First First type provided by the type list.
* @tparam Other Other types provided by the type list.
*/
template<std::size_t Index, typename First, typename... Other>
template<stl::size_t Index, typename First, typename... Other>
struct type_list_element<Index, type_list<First, Other...>>
: type_list_element<Index - 1u, type_list<Other...>> {};
@@ -145,8 +126,8 @@ struct type_list_element<0u, type_list<First, Other...>> {
* @tparam Index Index of the type to return.
* @tparam List Type list to search into.
*/
template<std::size_t Index, typename List>
using type_list_element_t = typename type_list_element<Index, List>::type;
template<stl::size_t Index, typename List>
using type_list_element_t = type_list_element<Index, List>::type;
/*! @brief Primary template isn't defined on purpose. */
template<typename, typename>
@@ -161,7 +142,7 @@ struct type_list_index;
template<typename Type, typename First, typename... Other>
struct type_list_index<Type, type_list<First, Other...>> {
/*! @brief Unsigned integer type. */
using value_type = std::size_t;
using value_type = stl::size_t;
/*! @brief Compile-time position of the given type in the sublist. */
static constexpr value_type value = 1u + type_list_index<Type, type_list<Other...>>::value;
};
@@ -175,7 +156,7 @@ template<typename Type, typename... Other>
struct type_list_index<Type, type_list<Type, Other...>> {
static_assert(type_list_index<Type, type_list<Other...>>::value == sizeof...(Other), "Non-unique type");
/*! @brief Unsigned integer type. */
using value_type = std::size_t;
using value_type = stl::size_t;
/*! @brief Compile-time position of the given type in the sublist. */
static constexpr value_type value = 0u;
};
@@ -187,7 +168,7 @@ struct type_list_index<Type, type_list<Type, Other...>> {
template<typename Type>
struct type_list_index<Type, type_list<>> {
/*! @brief Unsigned integer type. */
using value_type = std::size_t;
using value_type = stl::size_t;
/*! @brief Compile-time position of the given type in the sublist. */
static constexpr value_type value = 0u;
};
@@ -198,7 +179,7 @@ struct type_list_index<Type, type_list<>> {
* @tparam Type Type to look for and for which to return the index.
*/
template<typename Type, typename List>
inline constexpr std::size_t type_list_index_v = type_list_index<Type, List>::value;
inline constexpr stl::size_t type_list_index_v = type_list_index<Type, List>::value;
/**
* @brief Concatenates multiple type lists.
@@ -207,7 +188,7 @@ inline constexpr std::size_t type_list_index_v = type_list_index<Type, List>::va
* @return A type list composed by the types of both the type lists.
*/
template<typename... Type, typename... Other>
constexpr type_list<Type..., Other...> operator+(type_list<Type...>, type_list<Other...>) {
ENTT_CONSTEVAL type_list<Type..., Other...> operator+(type_list<Type...>, type_list<Other...>) {
return {};
}
@@ -231,7 +212,7 @@ struct type_list_cat<> {
template<typename... Type, typename... Other, typename... List>
struct type_list_cat<type_list<Type...>, type_list<Other...>, List...> {
/*! @brief A type list composed by the types of all the type lists. */
using type = typename type_list_cat<type_list<Type..., Other...>, List...>::type;
using type = type_list_cat<type_list<Type..., Other...>, List...>::type;
};
/**
@@ -249,9 +230,9 @@ struct type_list_cat<type_list<Type...>> {
* @tparam List Type lists to concatenate.
*/
template<typename... List>
using type_list_cat_t = typename type_list_cat<List...>::type;
using type_list_cat_t = type_list_cat<List...>::type;
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
template<typename...>
@@ -259,7 +240,7 @@ struct type_list_unique;
template<typename First, typename... Other, typename... Type>
struct type_list_unique<type_list<First, Other...>, Type...>
: std::conditional_t<(std::is_same_v<First, Type> || ...), type_list_unique<type_list<Other...>, Type...>, type_list_unique<type_list<Other...>, Type..., First>> {};
: stl::conditional_t<(stl::is_same_v<First, Type> || ...), type_list_unique<type_list<Other...>, Type...>, type_list_unique<type_list<Other...>, Type..., First>> {};
template<typename... Type>
struct type_list_unique<type_list<>, Type...> {
@@ -276,7 +257,7 @@ struct type_list_unique<type_list<>, Type...> {
template<typename List>
struct type_list_unique {
/*! @brief A type list without duplicate types. */
using type = typename internal::type_list_unique<List>::type;
using type = internal::type_list_unique<List>::type;
};
/**
@@ -284,7 +265,7 @@ struct type_list_unique {
* @tparam List Type list.
*/
template<typename List>
using type_list_unique_t = typename type_list_unique<List>::type;
using type_list_unique_t = type_list_unique<List>::type;
/**
* @brief Provides the member constant `value` to true if a type list contains a
@@ -302,7 +283,7 @@ struct type_list_contains;
*/
template<typename... Type, typename Other>
struct type_list_contains<type_list<Type...>, Other>
: std::bool_constant<(std::is_same_v<Type, Other> || ...)> {};
: stl::bool_constant<(stl::is_same_v<Type, Other> || ...)> {};
/**
* @brief Helper variable template.
@@ -324,7 +305,7 @@ struct type_list_diff;
template<typename... Type, typename... Other>
struct type_list_diff<type_list<Type...>, type_list<Other...>> {
/*! @brief A type list that is the difference between the two type lists. */
using type = type_list_cat_t<std::conditional_t<type_list_contains_v<type_list<Other...>, Type>, type_list<>, type_list<Type>>...>;
using type = type_list_cat_t<stl::conditional_t<type_list_contains_v<type_list<Other...>, Type>, type_list<>, type_list<Type>>...>;
};
/**
@@ -332,7 +313,7 @@ struct type_list_diff<type_list<Type...>, type_list<Other...>> {
* @tparam List Type lists between which to compute the difference.
*/
template<typename... List>
using type_list_diff_t = typename type_list_diff<List...>::type;
using type_list_diff_t = type_list_diff<List...>::type;
/*! @brief Primary template isn't defined on purpose. */
template<typename, template<typename...> class>
@@ -356,7 +337,7 @@ struct type_list_transform<type_list<Type...>, Op> {
* @tparam Op Unary operation as template class with a type member named `type`.
*/
template<typename List, template<typename...> class Op>
using type_list_transform_t = typename type_list_transform<List, Op>::type;
using type_list_transform_t = type_list_transform<List, Op>::type;
/**
* @brief A class to use to push around lists of constant values, nothing more.
@@ -371,7 +352,7 @@ struct value_list {
};
/*! @brief Primary template isn't defined on purpose. */
template<std::size_t, typename>
template<stl::size_t, typename>
struct value_list_element;
/**
@@ -380,7 +361,7 @@ struct value_list_element;
* @tparam Value First value provided by the value list.
* @tparam Other Other values provided by the value list.
*/
template<std::size_t Index, auto Value, auto... Other>
template<stl::size_t Index, auto Value, auto... Other>
struct value_list_element<Index, value_list<Value, Other...>>
: value_list_element<Index - 1u, value_list<Other...>> {};
@@ -402,15 +383,15 @@ struct value_list_element<0u, value_list<Value, Other...>> {
* @tparam Index Index of the type to return.
* @tparam List Value list to search into.
*/
template<std::size_t Index, typename List>
using value_list_element_t = typename value_list_element<Index, List>::type;
template<stl::size_t Index, typename List>
using value_list_element_t = value_list_element<Index, List>::type;
/**
* @brief Helper type.
* @tparam Index Index of the value to return.
* @tparam List Value list to search into.
*/
template<std::size_t Index, typename List>
template<stl::size_t Index, typename List>
inline constexpr auto value_list_element_v = value_list_element<Index, List>::value;
/*! @brief Primary template isn't defined on purpose. */
@@ -426,7 +407,7 @@ struct value_list_index;
template<auto Value, auto First, auto... Other>
struct value_list_index<Value, value_list<First, Other...>> {
/*! @brief Unsigned integer type. */
using value_type = std::size_t;
using value_type = stl::size_t;
/*! @brief Compile-time position of the given value in the sublist. */
static constexpr value_type value = 1u + value_list_index<Value, value_list<Other...>>::value;
};
@@ -440,7 +421,7 @@ template<auto Value, auto... Other>
struct value_list_index<Value, value_list<Value, Other...>> {
static_assert(value_list_index<Value, value_list<Other...>>::value == sizeof...(Other), "Non-unique type");
/*! @brief Unsigned integer type. */
using value_type = std::size_t;
using value_type = stl::size_t;
/*! @brief Compile-time position of the given value in the sublist. */
static constexpr value_type value = 0u;
};
@@ -452,7 +433,7 @@ struct value_list_index<Value, value_list<Value, Other...>> {
template<auto Value>
struct value_list_index<Value, value_list<>> {
/*! @brief Unsigned integer type. */
using value_type = std::size_t;
using value_type = stl::size_t;
/*! @brief Compile-time position of the given type in the sublist. */
static constexpr value_type value = 0u;
};
@@ -463,7 +444,7 @@ struct value_list_index<Value, value_list<>> {
* @tparam Value Value to look for and for which to return the index.
*/
template<auto Value, typename List>
inline constexpr std::size_t value_list_index_v = value_list_index<Value, List>::value;
inline constexpr stl::size_t value_list_index_v = value_list_index<Value, List>::value;
/**
* @brief Concatenates multiple value lists.
@@ -472,7 +453,7 @@ inline constexpr std::size_t value_list_index_v = value_list_index<Value, List>:
* @return A value list composed by the values of both the value lists.
*/
template<auto... Value, auto... Other>
constexpr value_list<Value..., Other...> operator+(value_list<Value...>, value_list<Other...>) {
ENTT_CONSTEVAL value_list<Value..., Other...> operator+(value_list<Value...>, value_list<Other...>) {
return {};
}
@@ -496,7 +477,7 @@ struct value_list_cat<> {
template<auto... Value, auto... Other, typename... List>
struct value_list_cat<value_list<Value...>, value_list<Other...>, List...> {
/*! @brief A value list composed by the values of all the value lists. */
using type = typename value_list_cat<value_list<Value..., Other...>, List...>::type;
using type = value_list_cat<value_list<Value..., Other...>, List...>::type;
};
/**
@@ -514,7 +495,7 @@ struct value_list_cat<value_list<Value...>> {
* @tparam List Value lists to concatenate.
*/
template<typename... List>
using value_list_cat_t = typename value_list_cat<List...>::type;
using value_list_cat_t = value_list_cat<List...>::type;
/*! @brief Primary template isn't defined on purpose. */
template<typename>
@@ -528,7 +509,7 @@ struct value_list_unique;
template<auto Value, auto... Other>
struct value_list_unique<value_list<Value, Other...>> {
/*! @brief A value list without duplicate types. */
using type = std::conditional_t<
using type = stl::conditional_t<
((Value == Other) || ...),
typename value_list_unique<value_list<Other...>>::type,
value_list_cat_t<value_list<Value>, typename value_list_unique<value_list<Other...>>::type>>;
@@ -546,7 +527,7 @@ struct value_list_unique<value_list<>> {
* @tparam Type A value list.
*/
template<typename Type>
using value_list_unique_t = typename value_list_unique<Type>::type;
using value_list_unique_t = value_list_unique<Type>::type;
/**
* @brief Provides the member constant `value` to true if a value list contains
@@ -564,7 +545,7 @@ struct value_list_contains;
*/
template<auto... Value, auto Other>
struct value_list_contains<value_list<Value...>, Other>
: std::bool_constant<((Value == Other) || ...)> {};
: stl::bool_constant<((Value == Other) || ...)> {};
/**
* @brief Helper variable template.
@@ -586,7 +567,7 @@ struct value_list_diff;
template<auto... Value, auto... Other>
struct value_list_diff<value_list<Value...>, value_list<Other...>> {
/*! @brief A value list that is the difference between the two value lists. */
using type = value_list_cat_t<std::conditional_t<value_list_contains_v<value_list<Other...>, Value>, value_list<>, value_list<Value>>...>;
using type = value_list_cat_t<stl::conditional_t<value_list_contains_v<value_list<Other...>, Value>, value_list<>, value_list<Value>>...>;
};
/**
@@ -594,11 +575,11 @@ struct value_list_diff<value_list<Value...>, value_list<Other...>> {
* @tparam List Value lists between which to compute the difference.
*/
template<typename... List>
using value_list_diff_t = typename value_list_diff<List...>::type;
using value_list_diff_t = value_list_diff<List...>::type;
/*! @brief Same as std::is_invocable, but with tuples. */
/*! @brief Same as stl::is_invocable, but with tuples. */
template<typename, typename>
struct is_applicable: std::false_type {};
struct is_applicable: stl::false_type {};
/**
* @copybrief is_applicable
@@ -607,7 +588,7 @@ struct is_applicable: std::false_type {};
* @tparam Args The list of arguments to use to probe the function type.
*/
template<typename Func, template<typename...> class Tuple, typename... Args>
struct is_applicable<Func, Tuple<Args...>>: std::is_invocable<Func, Args...> {};
struct is_applicable<Func, Tuple<Args...>>: stl::is_invocable<Func, Args...> {};
/**
* @copybrief is_applicable
@@ -616,7 +597,7 @@ struct is_applicable<Func, Tuple<Args...>>: std::is_invocable<Func, Args...> {};
* @tparam Args The list of arguments to use to probe the function type.
*/
template<typename Func, template<typename...> class Tuple, typename... Args>
struct is_applicable<Func, const Tuple<Args...>>: std::is_invocable<Func, Args...> {};
struct is_applicable<Func, const Tuple<Args...>>: stl::is_invocable<Func, Args...> {};
/**
* @brief Helper variable template.
@@ -626,9 +607,9 @@ struct is_applicable<Func, const Tuple<Args...>>: std::is_invocable<Func, Args..
template<typename Func, typename Args>
inline constexpr bool is_applicable_v = is_applicable<Func, Args>::value;
/*! @brief Same as std::is_invocable_r, but with tuples for arguments. */
/*! @brief Same as stl::is_invocable_r, but with tuples for arguments. */
template<typename, typename, typename>
struct is_applicable_r: std::false_type {};
struct is_applicable_r: stl::false_type {};
/**
* @copybrief is_applicable_r
@@ -638,7 +619,7 @@ struct is_applicable_r: std::false_type {};
* @tparam Args The list of arguments to use to probe the function type.
*/
template<typename Ret, typename Func, typename... Args>
struct is_applicable_r<Ret, Func, std::tuple<Args...>>: std::is_invocable_r<Ret, Func, Args...> {};
struct is_applicable_r<Ret, Func, stl::tuple<Args...>>: stl::is_invocable_r<Ret, Func, Args...> {};
/**
* @brief Helper variable template.
@@ -655,12 +636,13 @@ inline constexpr bool is_applicable_r_v = is_applicable_r<Ret, Func, Args>::valu
* complete, false otherwise.
* @tparam Type The type to test.
*/
template<typename Type, typename = void>
struct is_complete: std::false_type {};
template<typename Type>
struct is_complete: stl::false_type {};
/*! @copydoc is_complete */
template<typename Type>
struct is_complete<Type, std::void_t<decltype(sizeof(Type))>>: std::true_type {};
requires requires { sizeof(Type); }
struct is_complete<Type>: stl::true_type {};
/**
* @brief Helper variable template.
@@ -674,25 +656,26 @@ inline constexpr bool is_complete_v = is_complete<Type>::value;
* iterator, false otherwise.
* @tparam Type The type to test.
*/
template<typename Type, typename = void>
struct is_iterator: std::false_type {};
template<typename Type>
struct is_iterator: stl::false_type {};
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
template<typename, typename = void>
struct has_iterator_category: std::false_type {};
template<typename>
struct has_iterator_category: stl::false_type {};
template<typename Type>
struct has_iterator_category<Type, std::void_t<typename std::iterator_traits<Type>::iterator_category>>: std::true_type {};
requires requires { typename stl::iterator_traits<Type>::iterator_category; }
struct has_iterator_category<Type>: stl::true_type {};
} // namespace internal
/*! @endcond */
/*! @copydoc is_iterator */
template<typename 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> {};
requires (!stl::is_void_v<stl::remove_const_t<stl::remove_pointer_t<Type>>>)
struct is_iterator<Type>: internal::has_iterator_category<Type> {};
/**
* @brief Helper variable template.
@@ -707,8 +690,7 @@ inline constexpr bool is_iterator_v = is_iterator<Type>::value;
* @tparam Type The type to test
*/
template<typename Type>
struct is_ebco_eligible
: std::bool_constant<std::is_empty_v<Type> && !std::is_final_v<Type>> {};
struct is_ebco_eligible: stl::bool_constant<stl::is_empty_v<Type> && !stl::is_final_v<Type>> {};
/**
* @brief Helper variable template.
@@ -722,12 +704,13 @@ inline constexpr bool is_ebco_eligible_v = is_ebco_eligible<Type>::value;
* is valid and denotes a type, false otherwise.
* @tparam Type The type to test.
*/
template<typename Type, typename = void>
struct is_transparent: std::false_type {};
template<typename Type>
struct is_transparent: stl::false_type {};
/*! @copydoc is_transparent */
template<typename Type>
struct is_transparent<Type, std::void_t<typename Type::is_transparent>>: std::true_type {};
requires requires { typename Type::is_transparent; }
struct is_transparent<Type>: stl::true_type {};
/**
* @brief Helper variable template.
@@ -736,52 +719,54 @@ struct is_transparent<Type, std::void_t<typename Type::is_transparent>>: std::tr
template<typename Type>
inline constexpr bool is_transparent_v = is_transparent<Type>::value;
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
template<typename, typename = void>
struct has_tuple_size_value: std::false_type {};
template<typename>
struct has_tuple_size_value: stl::false_type {};
template<typename Type>
struct has_tuple_size_value<Type, std::void_t<decltype(std::tuple_size<const Type>::value)>>: std::true_type {};
template<typename, typename = void>
struct has_value_type: std::false_type {};
template<typename Type>
struct has_value_type<Type, std::void_t<typename Type::value_type>>: std::true_type {};
requires is_complete_v<stl::tuple_size<const Type>>
struct has_tuple_size_value<Type>: stl::true_type {};
template<typename>
[[nodiscard]] constexpr bool dispatch_is_equality_comparable();
struct has_value_type: stl::false_type {};
template<typename Type, std::size_t... Index>
[[nodiscard]] constexpr bool unpack_maybe_equality_comparable(std::index_sequence<Index...>) {
return (dispatch_is_equality_comparable<std::tuple_element_t<Index, Type>>() && ...);
template<typename Type>
requires requires { typename Type::value_type; }
struct has_value_type<Type>: stl::true_type {};
template<typename>
[[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable();
template<typename Type, stl::size_t... Index>
[[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence<Index...>) {
return (dispatch_is_equality_comparable<stl::tuple_element_t<Index, Type>>() && ...);
}
template<typename>
[[nodiscard]] constexpr bool maybe_equality_comparable(char) {
[[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) {
return false;
}
template<typename Type>
[[nodiscard]] constexpr auto maybe_equality_comparable(int) -> decltype(std::declval<Type>() == std::declval<Type>()) {
[[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval<Type>() == stl::declval<Type>()) {
return true;
}
template<typename Type>
[[nodiscard]] constexpr bool dispatch_is_equality_comparable() {
[[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() {
// NOLINTBEGIN(modernize-use-transparent-functors)
if constexpr(std::is_array_v<Type>) {
if constexpr(stl::is_array_v<Type>) {
return false;
} else if constexpr(is_complete_v<std::tuple_size<std::remove_const_t<Type>>>) {
} else if constexpr(is_complete_v<stl::tuple_size<stl::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>{});
return maybe_equality_comparable<Type>(0) && unpack_maybe_equality_comparable<Type>(stl::make_index_sequence<stl::tuple_size<Type>::value>{});
} else {
return maybe_equality_comparable<Type>(0);
}
} else if constexpr(has_value_type<Type>::value) {
if constexpr(is_iterator_v<Type> || std::is_same_v<typename Type::value_type, Type> || dispatch_is_equality_comparable<typename Type::value_type>()) {
if constexpr(is_iterator_v<Type> || stl::is_same_v<typename Type::value_type, Type> || dispatch_is_equality_comparable<typename Type::value_type>()) {
return maybe_equality_comparable<Type>(0);
} else {
return false;
@@ -801,7 +786,7 @@ template<typename Type>
* @tparam Type The type to test.
*/
template<typename Type>
struct is_equality_comparable: std::bool_constant<internal::dispatch_is_equality_comparable<Type>()> {};
struct is_equality_comparable: stl::bool_constant<internal::dispatch_is_equality_comparable<Type>()> {};
/*! @copydoc is_equality_comparable */
template<typename Type>
@@ -822,7 +807,7 @@ inline constexpr bool is_equality_comparable_v = is_equality_comparable<Type>::v
template<typename To, typename From>
struct constness_as {
/*! @brief The type resulting from the transcription of the constness. */
using type = std::remove_const_t<To>;
using type = stl::remove_const_t<To>;
};
/*! @copydoc constness_as */
@@ -838,7 +823,7 @@ struct constness_as<To, const From> {
* @tparam From The type from which to transcribe the constness.
*/
template<typename To, typename From>
using constness_as_t = typename constness_as<To, From>::type;
using constness_as_t = constness_as<To, From>::type;
/**
* @brief Extracts the class of a non-static member object or function.
@@ -846,7 +831,7 @@ using constness_as_t = typename constness_as<To, From>::type;
*/
template<typename Member>
class member_class {
static_assert(std::is_member_pointer_v<Member>, "Invalid pointer type to non-static member object or function");
static_assert(stl::is_member_pointer_v<Member>, "Invalid pointer type to non-static member object or function");
template<typename Class, typename Ret, typename... Args>
static Class *clazz(Ret (Class::*)(Args...));
@@ -859,7 +844,7 @@ class member_class {
public:
/*! @brief The class of the given non-static member object or function. */
using type = std::remove_pointer_t<decltype(clazz(std::declval<Member>()))>;
using type = stl::remove_pointer_t<decltype(clazz(stl::declval<Member>()))>;
};
/**
@@ -867,33 +852,33 @@ public:
* @tparam Member A pointer to a non-static member object or function.
*/
template<typename Member>
using member_class_t = typename member_class<Member>::type;
using member_class_t = member_class<Member>::type;
/**
* @brief Extracts the n-th argument of a _callable_ type.
* @tparam Index The index of the argument to extract.
* @tparam Candidate A valid _callable_ type.
*/
template<std::size_t Index, typename Candidate>
template<stl::size_t Index, typename Candidate>
class nth_argument {
template<typename Ret, typename... Args>
static constexpr type_list<Args...> pick_up(Ret (*)(Args...));
static ENTT_CONSTEVAL type_list<Args...> pick_up(Ret (*)(Args...));
template<typename Ret, typename Class, typename... Args>
static constexpr type_list<Args...> pick_up(Ret (Class ::*)(Args...));
static ENTT_CONSTEVAL type_list<Args...> pick_up(Ret (Class ::*)(Args...));
template<typename Ret, typename Class, typename... Args>
static constexpr type_list<Args...> pick_up(Ret (Class ::*)(Args...) const);
static ENTT_CONSTEVAL type_list<Args...> pick_up(Ret (Class ::*)(Args...) const);
template<typename Type, typename Class>
static constexpr type_list<Type> pick_up(Type Class ::*);
static ENTT_CONSTEVAL type_list<Type> pick_up(Type Class ::*);
template<typename Type>
static constexpr decltype(pick_up(&Type::operator())) pick_up(Type &&);
static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&);
public:
/*! @brief N-th argument of the _callable_ type. */
using type = type_list_element_t<Index, decltype(pick_up(std::declval<Candidate>()))>;
using type = type_list_element_t<Index, decltype(pick_up(stl::declval<Candidate>()))>;
};
/**
@@ -901,21 +886,21 @@ public:
* @tparam Index The index of the argument to extract.
* @tparam Candidate A valid function, member function or data member type.
*/
template<std::size_t Index, typename Candidate>
using nth_argument_t = typename nth_argument<Index, Candidate>::type;
template<stl::size_t Index, typename Candidate>
using nth_argument_t = nth_argument<Index, Candidate>::type;
} // namespace entt
template<typename... Type>
struct std::tuple_size<entt::type_list<Type...>>: std::integral_constant<std::size_t, entt::type_list<Type...>::size> {};
struct entt::stl::tuple_size<entt::type_list<Type...>>: entt::stl::integral_constant<entt::stl::size_t, entt::type_list<Type...>::size> {};
template<std::size_t Index, typename... Type>
struct std::tuple_element<Index, entt::type_list<Type...>>: entt::type_list_element<Index, entt::type_list<Type...>> {};
template<entt::stl::size_t Index, typename... Type>
struct entt::stl::tuple_element<Index, entt::type_list<Type...>>: entt::type_list_element<Index, entt::type_list<Type...>> {};
template<auto... Value>
struct std::tuple_size<entt::value_list<Value...>>: std::integral_constant<std::size_t, entt::value_list<Value...>::size> {};
struct entt::stl::tuple_size<entt::value_list<Value...>>: entt::stl::integral_constant<entt::stl::size_t, entt::value_list<Value...>::size> {};
template<std::size_t Index, auto... Value>
struct std::tuple_element<Index, entt::value_list<Value...>>: entt::value_list_element<Index, entt::value_list<Value...>> {};
template<entt::stl::size_t Index, auto... Value>
struct entt::stl::tuple_element<Index, entt::value_list<Value...>>: entt::value_list_element<Index, entt::value_list<Value...>> {};
#endif

View File

@@ -1,28 +1,11 @@
#ifndef ENTT_CORE_UTILITY_HPP
#define ENTT_CORE_UTILITY_HPP
#include <type_traits>
#include <utility>
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
namespace entt {
/*! @brief Identity function object (waiting for C++20). */
struct identity {
/*! @brief Indicates that this is a transparent function object. */
using is_transparent = void;
/**
* @brief Returns its argument unchanged.
* @tparam Type Type of the argument.
* @param value The actual argument.
* @return The submitted value as-is.
*/
template<typename Type>
[[nodiscard]] constexpr Type &&operator()(Type &&value) const noexcept {
return std::forward<Type>(value);
}
};
/**
* @brief Constant utility to disambiguate overloaded members of a class.
* @tparam Type Type of the desired overload.
@@ -72,8 +55,8 @@ struct y_combinator {
* @brief Constructs a y-combinator from a given function.
* @param recursive A potentially recursive function.
*/
constexpr y_combinator(Func recursive) noexcept(std::is_nothrow_move_constructible_v<Func>)
: func{std::move(recursive)} {}
constexpr y_combinator(Func recursive) noexcept(stl::is_nothrow_move_constructible_v<Func>)
: func{stl::move(recursive)} {}
/**
* @brief Invokes a y-combinator and therefore its underlying function.
@@ -82,14 +65,14 @@ struct y_combinator {
* @return Return value of the underlying function, if any.
*/
template<typename... Args>
constexpr decltype(auto) operator()(Args &&...args) const noexcept(std::is_nothrow_invocable_v<Func, const y_combinator &, Args...>) {
return func(*this, std::forward<Args>(args)...);
constexpr decltype(auto) operator()(Args &&...args) const noexcept(stl::is_nothrow_invocable_v<Func, const y_combinator &, Args...>) {
return func(*this, stl::forward<Args>(args)...);
}
/*! @copydoc operator()() */
template<typename... Args>
constexpr decltype(auto) operator()(Args &&...args) noexcept(std::is_nothrow_invocable_v<Func, y_combinator &, Args...>) {
return func(*this, std::forward<Args>(args)...);
constexpr decltype(auto) operator()(Args &&...args) noexcept(stl::is_nothrow_invocable_v<Func, y_combinator &, Args...>) {
return func(*this, stl::forward<Args>(args)...);
}
private:

View File

@@ -1,35 +1,37 @@
#ifndef ENTT_ENTITY_COMPONENT_HPP
#define ENTT_ENTITY_COMPONENT_HPP
#include <cstddef>
#include <type_traits>
#include "../config/config.h"
#include "../core/concepts.hpp"
#include "../stl/concepts.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/type_traits.hpp"
#include "fwd.hpp"
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
template<typename Type, typename = void>
struct in_place_delete: std::bool_constant<!(std::is_move_constructible_v<Type> && std::is_move_assignable_v<Type>)> {};
template<typename Type>
struct in_place_delete: stl::bool_constant<!(stl::is_move_constructible_v<Type> && stl::is_move_assignable_v<Type>)> {};
template<>
struct in_place_delete<void>: std::false_type {};
struct in_place_delete<void>: stl::false_type {};
template<typename Type>
struct in_place_delete<Type, std::enable_if_t<Type::in_place_delete>>
: std::true_type {};
requires Type::in_place_delete
struct in_place_delete<Type>: stl::true_type {};
template<typename Type, typename = void>
struct page_size: std::integral_constant<std::size_t, !std::is_empty_v<ENTT_ETO_TYPE(Type)> * ENTT_PACKED_PAGE> {};
template<typename Type>
struct page_size: stl::integral_constant<stl::size_t, !stl::is_empty_v<ENTT_ETO_TYPE(Type)> * ENTT_PACKED_PAGE> {};
template<>
struct page_size<void>: std::integral_constant<std::size_t, 0u> {};
struct page_size<void>: stl::integral_constant<stl::size_t, 0u> {};
template<typename Type>
struct page_size<Type, std::void_t<decltype(Type::page_size)>>
: std::integral_constant<std::size_t, Type::page_size> {};
requires stl::is_convertible_v<decltype(Type::page_size), stl::size_t>
struct page_size<Type>: stl::integral_constant<stl::size_t, Type::page_size> {};
} // namespace internal
/*! @endcond */
@@ -39,10 +41,8 @@ struct page_size<Type, std::void_t<decltype(Type::page_size)>>
* @tparam Type Element type.
* @tparam Entity A valid entity type.
*/
template<typename Type, typename Entity, typename>
template<cvref_unqualified Type, typename Entity>
struct component_traits {
static_assert(std::is_same_v<std::decay_t<Type>, Type>, "Unsupported type");
/*! @brief Element type. */
using element_type = Type;
/*! @brief Underlying entity identifier. */
@@ -51,7 +51,7 @@ struct component_traits {
/*! @brief Pointer stability, default is `false`. */
static constexpr bool in_place_delete = internal::in_place_delete<Type>::value;
/*! @brief Page size, default is `ENTT_PACKED_PAGE` for non-empty types. */
static constexpr std::size_t page_size = internal::page_size<Type>::value;
static constexpr stl::size_t page_size = internal::page_size<Type>::value;
};
} // namespace entt

View File

@@ -1,50 +1,56 @@
#ifndef ENTT_ENTITY_ENTITY_HPP
#define ENTT_ENTITY_ENTITY_HPP
#include <cstddef>
#include <cstdint>
#include <type_traits>
#include "../config/config.h"
#include "../core/bit.hpp"
#include "../stl/bit.hpp"
#include "../stl/concepts.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/cstdint.hpp"
#include "../stl/type_traits.hpp"
#include "fwd.hpp"
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
template<typename, typename = void>
template<typename>
struct entt_traits;
template<typename Type>
struct entt_traits<Type, std::enable_if_t<std::is_enum_v<Type>>>
: entt_traits<std::underlying_type_t<Type>> {
requires requires {
requires stl::is_enum_v<Type>;
typename internal::entt_traits<stl::underlying_type_t<Type>>::value_type;
}
struct entt_traits<Type>: entt_traits<stl::underlying_type_t<Type>> {
using value_type = Type;
};
template<typename Type>
struct entt_traits<Type, std::enable_if_t<std::is_class_v<Type>>>
requires requires { typename Type::entity_type; }
struct entt_traits<Type>
: entt_traits<typename Type::entity_type> {
using value_type = Type;
};
template<>
struct entt_traits<std::uint32_t> {
using value_type = std::uint32_t;
struct entt_traits<stl::uint32_t> {
using value_type = stl::uint32_t;
using entity_type = std::uint32_t;
using version_type = std::uint16_t;
using entity_type = stl::uint32_t;
using version_type = stl::uint16_t;
static constexpr entity_type entity_mask = 0xFFFFF;
static constexpr entity_type version_mask = 0xFFF;
};
template<>
struct entt_traits<std::uint64_t> {
using value_type = std::uint64_t;
struct entt_traits<stl::uint64_t> {
using value_type = stl::uint64_t;
using entity_type = std::uint64_t;
using version_type = std::uint32_t;
using entity_type = stl::uint64_t;
using version_type = stl::uint32_t;
static constexpr entity_type entity_mask = 0xFFFFFFFF;
static constexpr entity_type version_mask = 0xFFFFFFFF;
@@ -53,24 +59,33 @@ struct entt_traits<std::uint64_t> {
} // namespace internal
/*! @endcond */
/**
* @brief Specifies that a type is an entity-like type.
* @tparam Type Type to check.
*/
template<typename Type>
concept entity_like = requires {
typename internal::entt_traits<Type>::value_type;
};
/**
* @brief Common basic entity traits implementation.
* @tparam Traits Actual entity traits to use.
*/
template<typename Traits>
class basic_entt_traits {
static constexpr auto length = popcount(Traits::entity_mask);
static constexpr auto length = stl::popcount(Traits::entity_mask);
static_assert(Traits::entity_mask && ((Traits::entity_mask & (Traits::entity_mask + 1)) == 0), "Invalid entity mask");
static_assert((Traits::version_mask & (Traits::version_mask + 1)) == 0, "Invalid version mask");
public:
/*! @brief Value type. */
using value_type = typename Traits::value_type;
using value_type = Traits::value_type;
/*! @brief Underlying entity type. */
using entity_type = typename Traits::entity_type;
using entity_type = Traits::entity_type;
/*! @brief Underlying version type. */
using version_type = typename Traits::version_type;
using version_type = Traits::version_type;
/*! @brief Entity mask size. */
static constexpr entity_type entity_mask = Traits::entity_mask;
@@ -159,12 +174,12 @@ public:
* @brief Entity traits.
* @tparam Type Type of identifier.
*/
template<typename Type>
template<entity_like Type>
struct entt_traits: basic_entt_traits<internal::entt_traits<Type>> {
/*! @brief Base type. */
using base_type = basic_entt_traits<internal::entt_traits<Type>>;
/*! @brief Page size, default is `ENTT_SPARSE_PAGE`. */
static constexpr std::size_t page_size = ENTT_SPARSE_PAGE;
static constexpr stl::size_t page_size = ENTT_SPARSE_PAGE;
};
/**
@@ -174,7 +189,7 @@ struct entt_traits: basic_entt_traits<internal::entt_traits<Type>> {
* @return The integral representation of the given value.
*/
template<typename Entity>
[[nodiscard]] constexpr typename entt_traits<Entity>::entity_type to_integral(const Entity value) noexcept {
[[nodiscard]] constexpr entt_traits<Entity>::entity_type to_integral(const Entity value) noexcept {
return entt_traits<Entity>::to_integral(value);
}
@@ -185,7 +200,7 @@ template<typename Entity>
* @return The integral representation of the entity part.
*/
template<typename Entity>
[[nodiscard]] constexpr typename entt_traits<Entity>::entity_type to_entity(const Entity value) noexcept {
[[nodiscard]] constexpr entt_traits<Entity>::entity_type to_entity(const Entity value) noexcept {
return entt_traits<Entity>::to_entity(value);
}
@@ -196,7 +211,7 @@ template<typename Entity>
* @return The integral representation of the version part.
*/
template<typename Entity>
[[nodiscard]] constexpr typename entt_traits<Entity>::version_type to_version(const Entity value) noexcept {
[[nodiscard]] constexpr entt_traits<Entity>::version_type to_version(const Entity value) noexcept {
return entt_traits<Entity>::to_version(value);
}
@@ -207,11 +222,10 @@ struct null_t {
* @tparam Entity Type of identifier.
* @return The null representation for the given type.
*/
template<typename Entity>
template<entity_like Entity>
[[nodiscard]] constexpr operator Entity() const noexcept {
using traits_type = entt_traits<Entity>;
constexpr auto value = traits_type::construct(traits_type::entity_mask, traits_type::version_mask);
return value;
return traits_type::construct(traits_type::entity_mask, traits_type::version_mask);
}
/**
@@ -223,63 +237,19 @@ struct null_t {
return true;
}
/**
* @brief Compares two null objects.
* @param other A null object.
* @return False in all cases.
*/
[[nodiscard]] constexpr bool operator!=([[maybe_unused]] const null_t other) const noexcept {
return false;
}
/**
* @brief Compares a null object and an identifier of any type.
* @tparam Entity Type of identifier.
* @param entity Identifier with which to compare.
* @return False if the two elements differ, true otherwise.
*/
template<typename Entity>
template<entity_like Entity>
[[nodiscard]] constexpr bool operator==(const Entity entity) const noexcept {
using traits_type = entt_traits<Entity>;
return traits_type::to_entity(entity) == traits_type::to_entity(*this);
}
/**
* @brief Compares a null object and an identifier of any type.
* @tparam Entity Type of identifier.
* @param entity Identifier with which to compare.
* @return True if the two elements differ, false otherwise.
*/
template<typename Entity>
[[nodiscard]] constexpr bool operator!=(const Entity entity) const noexcept {
return !(entity == *this);
}
};
/**
* @brief Compares a null object and an identifier of any type.
* @tparam Entity Type of identifier.
* @param lhs Identifier with which to compare.
* @param rhs A null object yet to be converted.
* @return False if the two elements differ, true otherwise.
*/
template<typename Entity>
[[nodiscard]] constexpr bool operator==(const Entity lhs, const null_t rhs) noexcept {
return rhs.operator==(lhs);
}
/**
* @brief Compares a null object and an identifier of any type.
* @tparam Entity Type of identifier.
* @param lhs Identifier with which to compare.
* @param rhs A null object yet to be converted.
* @return True if the two elements differ, false otherwise.
*/
template<typename Entity>
[[nodiscard]] constexpr bool operator!=(const Entity lhs, const null_t rhs) noexcept {
return !(rhs == lhs);
}
/*! @brief Tombstone object for all identifiers. */
struct tombstone_t {
/**
@@ -287,11 +257,10 @@ struct tombstone_t {
* @tparam Entity Type of identifier.
* @return The tombstone representation for the given type.
*/
template<typename Entity>
template<entity_like Entity>
[[nodiscard]] constexpr operator Entity() const noexcept {
using traits_type = entt_traits<Entity>;
constexpr auto value = traits_type::construct(traits_type::entity_mask, traits_type::version_mask);
return value;
return traits_type::construct(traits_type::entity_mask, traits_type::version_mask);
}
/**
@@ -303,22 +272,13 @@ struct tombstone_t {
return true;
}
/**
* @brief Compares two tombstone objects.
* @param other A tombstone object.
* @return False in all cases.
*/
[[nodiscard]] constexpr bool operator!=([[maybe_unused]] const tombstone_t other) const noexcept {
return false;
}
/**
* @brief Compares a tombstone object and an identifier of any type.
* @tparam Entity Type of identifier.
* @param entity Identifier with which to compare.
* @return False if the two elements differ, true otherwise.
*/
template<typename Entity>
template<entity_like Entity>
[[nodiscard]] constexpr bool operator==(const Entity entity) const noexcept {
using traits_type = entt_traits<Entity>;
@@ -328,43 +288,8 @@ struct tombstone_t {
return (traits_type::to_version(entity) == traits_type::to_version(*this));
}
}
/**
* @brief Compares a tombstone object and an identifier of any type.
* @tparam Entity Type of identifier.
* @param entity Identifier with which to compare.
* @return True if the two elements differ, false otherwise.
*/
template<typename Entity>
[[nodiscard]] constexpr bool operator!=(const Entity entity) const noexcept {
return !(entity == *this);
}
};
/**
* @brief Compares a tombstone object and an identifier of any type.
* @tparam Entity Type of identifier.
* @param lhs Identifier with which to compare.
* @param rhs A tombstone object yet to be converted.
* @return False if the two elements differ, true otherwise.
*/
template<typename Entity>
[[nodiscard]] constexpr bool operator==(const Entity lhs, const tombstone_t rhs) noexcept {
return rhs.operator==(lhs);
}
/**
* @brief Compares a tombstone object and an identifier of any type.
* @tparam Entity Type of identifier.
* @param lhs Identifier with which to compare.
* @param rhs A tombstone object yet to be converted.
* @return True if the two elements differ, false otherwise.
*/
template<typename Entity>
[[nodiscard]] constexpr bool operator!=(const Entity lhs, const tombstone_t rhs) noexcept {
return !(rhs == lhs);
}
/**
* @brief Compile-time constant for null entities.
*

View File

@@ -1,12 +1,13 @@
#ifndef ENTT_ENTITY_FWD_HPP
#define ENTT_ENTITY_FWD_HPP
#include <cstdint>
#include <memory>
#include <type_traits>
#include "../config/config.h"
#include "../core/concepts.hpp"
#include "../core/fwd.hpp"
#include "../core/type_traits.hpp"
#include "../stl/cstdint.hpp"
#include "../stl/memory.hpp"
#include "../stl/type_traits.hpp"
namespace entt {
@@ -14,7 +15,7 @@ namespace entt {
enum class entity : id_type {};
/*! @brief Storage deletion policy. */
enum class deletion_policy : std::uint8_t {
enum class deletion_policy : stl::uint8_t {
/*! @brief Swap-and-pop deletion policy. */
swap_and_pop = 0u,
/*! @brief In-place deletion policy. */
@@ -25,13 +26,13 @@ enum class deletion_policy : std::uint8_t {
unspecified = swap_and_pop
};
template<typename Type, typename Entity = entity, typename = void>
template<cvref_unqualified Type, typename Entity = entity>
struct component_traits;
template<typename Entity = entity, typename = std::allocator<Entity>>
template<typename Entity = entity, typename = stl::allocator<Entity>>
class basic_sparse_set;
template<typename Type, typename = entity, typename = std::allocator<Type>, typename = void>
template<typename Type, typename = entity, typename = stl::allocator<Type>>
class basic_storage;
template<typename, typename>
@@ -40,13 +41,13 @@ class basic_sigh_mixin;
template<typename, typename>
class basic_reactive_mixin;
template<typename Entity = entity, typename = std::allocator<Entity>>
template<typename Entity = entity, typename = stl::allocator<Entity>>
class basic_registry;
template<typename, typename, typename = void>
template<typename, typename>
class basic_view;
template<typename Type, typename = std::allocator<Type *>>
template<typename Type, typename = stl::allocator<Type *>>
class basic_runtime_view;
template<typename, typename, typename>
@@ -139,7 +140,7 @@ using const_runtime_view = basic_runtime_view<const sparse_set>;
template<typename... Type>
struct exclude_t final: type_list<Type...> {
/*! @brief Default constructor. */
explicit constexpr exclude_t() = default;
explicit ENTT_CONSTEVAL exclude_t() = default;
};
/**
@@ -156,7 +157,7 @@ inline constexpr exclude_t<Type...> exclude{};
template<typename... Type>
struct get_t final: type_list<Type...> {
/*! @brief Default constructor. */
explicit constexpr get_t() = default;
explicit ENTT_CONSTEVAL get_t() = default;
};
/**
@@ -173,7 +174,7 @@ inline constexpr get_t<Type...> get{};
template<typename... Type>
struct owned_t final: type_list<Type...> {
/*! @brief Default constructor. */
explicit constexpr owned_t() = default;
explicit ENTT_CONSTEVAL owned_t() = default;
};
/**
@@ -222,7 +223,7 @@ struct type_list_transform<owned_t<Type...>, Op> {
* @tparam Entity A valid entity type.
* @tparam Allocator Type of allocator used to manage memory and elements.
*/
template<typename Type, typename Entity = entity, typename Allocator = std::allocator<Type>, typename = void>
template<typename Type, typename Entity = entity, typename Allocator = stl::allocator<Type>>
struct storage_type {
/*! @brief Type-to-storage conversion result. */
using type = ENTT_STORAGE(sigh_mixin, basic_storage<Type, Entity, Allocator>);
@@ -247,7 +248,7 @@ struct storage_type<reactive, Entity, Allocator> {
* @tparam Args Arguments to forward.
*/
template<typename... Args>
using storage_type_t = typename storage_type<Args...>::type;
using storage_type_t = storage_type<Args...>::type;
/**
* Type-to-storage conversion utility that preserves constness.
@@ -255,10 +256,10 @@ using storage_type_t = typename storage_type<Args...>::type;
* @tparam Entity A valid entity type.
* @tparam Allocator Type of allocator used to manage memory and elements.
*/
template<typename Type, typename Entity = entity, typename Allocator = std::allocator<std::remove_const_t<Type>>>
template<typename Type, typename Entity = entity, typename Allocator = stl::allocator<stl::remove_const_t<Type>>>
struct storage_for {
/*! @brief Type-to-storage conversion result. */
using type = constness_as_t<storage_type_t<std::remove_const_t<Type>, Entity, Allocator>, Type>;
using type = constness_as_t<storage_type_t<stl::remove_const_t<Type>, Entity, Allocator>, Type>;
};
/**
@@ -266,7 +267,7 @@ struct storage_for {
* @tparam Args Arguments to forward.
*/
template<typename... Args>
using storage_for_t = typename storage_for<Args...>::type;
using storage_for_t = storage_for<Args...>::type;
/**
* @brief Alias declaration for the most common use case.

View File

@@ -1,24 +1,25 @@
#ifndef ENTT_ENTITY_GROUP_HPP
#define ENTT_ENTITY_GROUP_HPP
#include <array>
#include <cstddef>
#include <iterator>
#include <tuple>
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "../core/algorithm.hpp"
#include "../core/fwd.hpp"
#include "../core/iterator.hpp"
#include "../core/type_info.hpp"
#include "../core/type_traits.hpp"
#include "../stl/array.hpp"
#include "../stl/concepts.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/iterator.hpp"
#include "../stl/tuple.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "entity.hpp"
#include "fwd.hpp"
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
template<typename, typename, typename>
@@ -28,29 +29,29 @@ template<typename It, typename... Owned, typename... Get>
class extended_group_iterator<It, owned_t<Owned...>, get_t<Get...>> {
template<typename Type>
[[nodiscard]] auto index_to_element([[maybe_unused]] Type &cpool) const {
if constexpr(std::is_void_v<typename Type::value_type>) {
return std::make_tuple();
if constexpr(stl::is_void_v<typename Type::value_type>) {
return stl::make_tuple();
} else {
return std::forward_as_tuple(cpool.rbegin()[it.index()]);
return stl::forward_as_tuple(cpool.rbegin()[it.index()]);
}
}
public:
using iterator_type = It;
using value_type = decltype(std::tuple_cat(std::make_tuple(*std::declval<It>()), std::declval<Owned>().get_as_tuple({})..., std::declval<Get>().get_as_tuple({})...));
using value_type = decltype(stl::tuple_cat(stl::make_tuple(*stl::declval<It>()), stl::declval<Owned>().get_as_tuple({})..., stl::declval<Get>().get_as_tuple({})...));
using pointer = input_iterator_pointer<value_type>;
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category = std::input_iterator_tag;
using iterator_concept = std::forward_iterator_tag;
using difference_type = stl::ptrdiff_t;
using iterator_category = stl::input_iterator_tag;
using iterator_concept = stl::forward_iterator_tag;
constexpr extended_group_iterator()
: it{},
pools{} {}
extended_group_iterator(iterator_type from, std::tuple<Owned *..., Get *...> cpools)
extended_group_iterator(iterator_type from, stl::tuple<Owned *..., Get *...> cpools)
: it{from},
pools{std::move(cpools)} {}
pools{stl::move(cpools)} {}
extended_group_iterator &operator++() noexcept {
return ++it, *this;
@@ -62,7 +63,7 @@ public:
}
[[nodiscard]] reference operator*() const noexcept {
return std::tuple_cat(std::make_tuple(*it), index_to_element(*std::get<Owned *>(pools))..., std::get<Get *>(pools)->get_as_tuple(*it)...);
return stl::tuple_cat(stl::make_tuple(*it), index_to_element(*stl::get<Owned *>(pools))..., stl::get<Get *>(pools)->get_as_tuple(*it)...);
}
[[nodiscard]] pointer operator->() const noexcept {
@@ -73,52 +74,44 @@ public:
return it;
}
template<typename... Lhs, typename... Rhs>
friend constexpr bool operator==(const extended_group_iterator<Lhs...> &, const extended_group_iterator<Rhs...> &) noexcept;
template<typename... Args>
[[nodiscard]] constexpr bool operator==(const extended_group_iterator<Args...> &other) const noexcept {
return it == other.it;
}
private:
It it;
std::tuple<Owned *..., Get *...> pools;
stl::tuple<Owned *..., Get *...> pools;
};
template<typename... Lhs, typename... Rhs>
[[nodiscard]] constexpr bool operator==(const extended_group_iterator<Lhs...> &lhs, const extended_group_iterator<Rhs...> &rhs) noexcept {
return lhs.it == rhs.it;
}
template<typename... Lhs, typename... Rhs>
[[nodiscard]] constexpr bool operator!=(const extended_group_iterator<Lhs...> &lhs, const extended_group_iterator<Rhs...> &rhs) noexcept {
return !(lhs == rhs);
}
struct group_descriptor {
using size_type = std::size_t;
using size_type = stl::size_t;
virtual ~group_descriptor() = default;
[[nodiscard]] virtual bool owned(const id_type) const noexcept {
return false;
}
};
template<typename Type, std::size_t Owned, std::size_t Get, std::size_t Exclude>
template<typename Type, stl::size_t Owned, stl::size_t Get, stl::size_t Exclude>
class group_handler final: public group_descriptor {
using entity_type = typename Type::entity_type;
using entity_type = Type::entity_type;
void swap_elements(const std::size_t pos, const entity_type entt) {
void swap_elements(const stl::size_t pos, const entity_type entt) {
for(size_type next{}; next < Owned; ++next) {
pools[next]->swap_elements((*pools[next])[pos], entt);
}
}
void push_on_construct(const entity_type entt) {
if(std::apply([entt, pos = len](auto *cpool, auto *...other) { return cpool->contains(entt) && !(cpool->index(entt) < pos) && (other->contains(entt) && ...); }, pools)
&& std::apply([entt](auto *...cpool) { return (!cpool->contains(entt) && ...); }, filter)) {
if(stl::apply([entt, pos = len](auto *cpool, auto *...other) { return cpool->contains(entt) && !(cpool->index(entt) < pos) && (other->contains(entt) && ...); }, pools)
&& stl::apply([entt](auto *...cpool) { return (!cpool->contains(entt) && ...); }, filter)) {
swap_elements(len++, entt);
}
}
void push_on_destroy(const entity_type entt) {
if(std::apply([entt, pos = len](auto *cpool, auto *...other) { return cpool->contains(entt) && !(cpool->index(entt) < pos) && (other->contains(entt) && ...); }, pools)
&& std::apply([entt](auto *...cpool) { return (0u + ... + cpool->contains(entt)) == 1u; }, filter)) {
if(stl::apply([entt, pos = len](auto *cpool, auto *...other) { return cpool->contains(entt) && !(cpool->index(entt) < pos) && (other->contains(entt) && ...); }, pools)
&& stl::apply([entt](auto *...cpool) { return (0u + ... + cpool->contains(entt)) == 1u; }, filter)) {
swap_elements(len++, entt);
}
}
@@ -131,21 +124,21 @@ class group_handler final: public group_descriptor {
void common_setup() {
// we cannot iterate backwards because we want to leave behind valid entities in case of owned types
for(auto first = pools[0u]->rbegin(), last = first + static_cast<typename decltype(pools)::difference_type>(pools[0u]->size()); first != last; ++first) {
for(auto first = pools[0u]->rbegin(), last = first + static_cast<decltype(pools)::difference_type>(pools[0u]->size()); first != last; ++first) {
push_on_construct(*first);
}
}
public:
using common_type = Type;
using size_type = typename Type::size_type;
using size_type = Type::size_type;
template<typename... OGType, typename... EType>
group_handler(std::tuple<OGType &...> ogpool, std::tuple<EType &...> epool)
: pools{std::apply([](auto &&...cpool) { return std::array<common_type *, (Owned + Get)>{&cpool...}; }, ogpool)},
filter{std::apply([](auto &&...cpool) { return std::array<common_type *, Exclude>{&cpool...}; }, epool)} {
std::apply([this](auto &...cpool) { ((cpool.on_construct().template connect<&group_handler::push_on_construct>(*this), cpool.on_destroy().template connect<&group_handler::remove_if>(*this)), ...); }, ogpool);
std::apply([this](auto &...cpool) { ((cpool.on_construct().template connect<&group_handler::remove_if>(*this), cpool.on_destroy().template connect<&group_handler::push_on_destroy>(*this)), ...); }, epool);
group_handler(stl::tuple<OGType &...> ogpool, stl::tuple<EType &...> epool)
: pools{stl::apply([](auto &&...cpool) { return stl::array<common_type *, (Owned + Get)>{&cpool...}; }, ogpool)},
filter{stl::apply([](auto &&...cpool) { return stl::array<common_type *, Exclude>{&cpool...}; }, epool)} {
stl::apply([this](auto &...cpool) { ((cpool.on_construct().template connect<&group_handler::push_on_construct>(*this), cpool.on_destroy().template connect<&group_handler::remove_if>(*this)), ...); }, ogpool);
stl::apply([this](auto &...cpool) { ((cpool.on_construct().template connect<&group_handler::remove_if>(*this), cpool.on_destroy().template connect<&group_handler::push_on_destroy>(*this)), ...); }, epool);
common_setup();
}
@@ -163,7 +156,7 @@ public:
return len;
}
template<std::size_t Index>
template<stl::size_t Index>
[[nodiscard]] common_type *storage() const noexcept {
if constexpr(Index < (Owned + Get)) {
return pools[Index];
@@ -173,27 +166,27 @@ public:
}
private:
std::array<common_type *, (Owned + Get)> pools;
std::array<common_type *, Exclude> filter;
std::size_t len{};
stl::array<common_type *, (Owned + Get)> pools;
stl::array<common_type *, Exclude> filter;
stl::size_t len{};
};
template<typename Type, std::size_t Get, std::size_t Exclude>
template<typename Type, stl::size_t Get, stl::size_t Exclude>
class group_handler<Type, 0u, Get, Exclude> final: public group_descriptor {
using entity_type = typename Type::entity_type;
using entity_type = Type::entity_type;
void push_on_construct(const entity_type entt) {
if(!elem.contains(entt)
&& std::apply([entt](auto *...cpool) { return (cpool->contains(entt) && ...); }, pools)
&& std::apply([entt](auto *...cpool) { return (!cpool->contains(entt) && ...); }, filter)) {
&& stl::apply([entt](auto *...cpool) { return (cpool->contains(entt) && ...); }, pools)
&& stl::apply([entt](auto *...cpool) { return (!cpool->contains(entt) && ...); }, filter)) {
elem.push(entt);
}
}
void push_on_destroy(const entity_type entt) {
if(!elem.contains(entt)
&& std::apply([entt](auto *...cpool) { return (cpool->contains(entt) && ...); }, pools)
&& std::apply([entt](auto *...cpool) { return (0u + ... + cpool->contains(entt)) == 1u; }, filter)) {
&& stl::apply([entt](auto *...cpool) { return (cpool->contains(entt) && ...); }, pools)
&& stl::apply([entt](auto *...cpool) { return (0u + ... + cpool->contains(entt)) == 1u; }, filter)) {
elem.push(entt);
}
}
@@ -212,12 +205,12 @@ public:
using common_type = Type;
template<typename Allocator, typename... GType, typename... EType>
group_handler(const Allocator &allocator, std::tuple<GType &...> gpool, std::tuple<EType &...> epool)
: pools{std::apply([](auto &&...cpool) { return std::array<common_type *, Get>{&cpool...}; }, gpool)},
filter{std::apply([](auto &&...cpool) { return std::array<common_type *, Exclude>{&cpool...}; }, epool)},
group_handler(const Allocator &allocator, stl::tuple<GType &...> gpool, stl::tuple<EType &...> epool)
: pools{stl::apply([](auto &&...cpool) { return stl::array<common_type *, Get>{&cpool...}; }, gpool)},
filter{stl::apply([](auto &&...cpool) { return stl::array<common_type *, Exclude>{&cpool...}; }, epool)},
elem{allocator} {
std::apply([this](auto &...cpool) { ((cpool.on_construct().template connect<&group_handler::push_on_construct>(*this), cpool.on_destroy().template connect<&group_handler::remove_if>(*this)), ...); }, gpool);
std::apply([this](auto &...cpool) { ((cpool.on_construct().template connect<&group_handler::remove_if>(*this), cpool.on_destroy().template connect<&group_handler::push_on_destroy>(*this)), ...); }, epool);
stl::apply([this](auto &...cpool) { ((cpool.on_construct().template connect<&group_handler::push_on_construct>(*this), cpool.on_destroy().template connect<&group_handler::remove_if>(*this)), ...); }, gpool);
stl::apply([this](auto &...cpool) { ((cpool.on_construct().template connect<&group_handler::remove_if>(*this), cpool.on_destroy().template connect<&group_handler::push_on_destroy>(*this)), ...); }, epool);
common_setup();
}
@@ -229,7 +222,7 @@ public:
return elem;
}
template<std::size_t Index>
template<stl::size_t Index>
[[nodiscard]] common_type *storage() const noexcept {
if constexpr(Index < Get) {
return pools[Index];
@@ -239,8 +232,8 @@ public:
}
private:
std::array<common_type *, Get> pools;
std::array<common_type *, Exclude> filter;
stl::array<common_type *, Get> pools;
stl::array<common_type *, Exclude> filter;
common_type elem;
};
@@ -280,15 +273,15 @@ class basic_group;
*/
template<typename... Get, typename... Exclude>
class basic_group<owned_t<>, get_t<Get...>, exclude_t<Exclude...>> {
using base_type = std::common_type_t<typename Get::base_type..., typename Exclude::base_type...>;
using underlying_type = typename base_type::entity_type;
using base_type = stl::common_type_t<typename Get::base_type..., typename Exclude::base_type...>;
using underlying_type = base_type::entity_type;
template<typename Type>
static constexpr std::size_t index_of = type_list_index_v<std::remove_const_t<Type>, type_list<typename Get::element_type..., typename Exclude::element_type...>>;
static constexpr stl::size_t index_of = type_list_index_v<stl::remove_const_t<Type>, type_list<typename Get::element_type..., typename Exclude::element_type...>>;
template<std::size_t... Index>
[[nodiscard]] auto pools_for(std::index_sequence<Index...>) const noexcept {
using return_type = std::tuple<Get *...>;
template<stl::size_t... Index>
[[nodiscard]] auto pools_for(stl::index_sequence<Index...>) const noexcept {
using return_type = stl::tuple<Get *...>;
return descriptor ? return_type{static_cast<Get *>(descriptor->template storage<Index>())...} : return_type{};
}
@@ -296,15 +289,15 @@ public:
/*! @brief Underlying entity identifier. */
using entity_type = underlying_type;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
using size_type = stl::size_t;
/*! @brief Signed integer type. */
using difference_type = std::ptrdiff_t;
using difference_type = stl::ptrdiff_t;
/*! @brief Common type among all storage types. */
using common_type = base_type;
/*! @brief Random access iterator type. */
using iterator = typename common_type::iterator;
using iterator = common_type::iterator;
/*! @brief Reverse iterator type. */
using reverse_iterator = typename common_type::reverse_iterator;
using reverse_iterator = common_type::reverse_iterator;
/*! @brief Iterable group type. */
using iterable = iterable_adaptor<internal::extended_group_iterator<iterator, owned_t<>, get_t<Get...>>>;
/*! @brief Group handler type. */
@@ -315,7 +308,7 @@ public:
* @return Group opaque identifier.
*/
static id_type group_id() noexcept {
return type_hash<basic_group<owned_t<>, get_t<std::remove_const_t<Get>...>, exclude_t<std::remove_const_t<Exclude>...>>>::value();
return type_hash<basic_group<owned_t<>, get_t<stl::remove_const_t<Get>...>, exclude_t<stl::remove_const_t<Exclude>...>>>::value();
}
/*! @brief Default constructor to use to create empty, invalid groups. */
@@ -352,7 +345,7 @@ public:
* @tparam Index Index of the storage to return.
* @return The storage for the given index.
*/
template<std::size_t Index>
template<stl::size_t Index>
[[nodiscard]] auto *storage() const noexcept {
using type = type_list_element_t<Index, type_list<Get..., Exclude...>>;
return *this ? static_cast<type *>(descriptor->template storage<Index>()) : nullptr;
@@ -505,16 +498,16 @@ public:
* @param entt A valid identifier.
* @return The elements assigned to the entity.
*/
template<std::size_t... Index>
template<stl::size_t... Index>
[[nodiscard]] decltype(auto) get(const entity_type entt) const {
const auto cpools = pools_for(std::index_sequence_for<Get...>{});
const auto cpools = pools_for(stl::index_sequence_for<Get...>{});
if constexpr(sizeof...(Index) == 0) {
return std::apply([entt](auto *...curr) { return std::tuple_cat(curr->get_as_tuple(entt)...); }, cpools);
return stl::apply([entt](auto *...curr) { return stl::tuple_cat(curr->get_as_tuple(entt)...); }, cpools);
} else if constexpr(sizeof...(Index) == 1) {
return (std::get<Index>(cpools)->get(entt), ...);
return (stl::get<Index>(cpools)->get(entt), ...);
} else {
return std::tuple_cat(std::get<Index>(cpools)->get_as_tuple(entt)...);
return stl::tuple_cat(stl::get<Index>(cpools)->get_as_tuple(entt)...);
}
}
@@ -543,10 +536,10 @@ public:
template<typename Func>
void each(Func func) const {
for(const auto entt: *this) {
if constexpr(is_applicable_v<Func, decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_group>().get({})))>) {
std::apply(func, std::tuple_cat(std::make_tuple(entt), get(entt)));
if constexpr(is_applicable_v<Func, decltype(stl::tuple_cat(stl::tuple<entity_type>{}, stl::declval<basic_group>().get({})))>) {
stl::apply(func, stl::tuple_cat(stl::make_tuple(entt), get(entt)));
} else {
std::apply(func, get(entt));
stl::apply(func, get(entt));
}
}
}
@@ -565,7 +558,7 @@ public:
* @return An iterable object to use to _visit_ the group.
*/
[[nodiscard]] iterable each() const noexcept {
const auto cpools = pools_for(std::index_sequence_for<Get...>{});
const auto cpools = pools_for(stl::index_sequence_for<Get...>{});
return iterable{{begin(), cpools}, {end(), cpools}};
}
@@ -577,7 +570,7 @@ public:
* comparison function should be equivalent to one of the following:
*
* @code{.cpp}
* bool(std::tuple<Type &...>, std::tuple<Type &...>);
* bool(stl::tuple<Type &...>, stl::tuple<Type &...>);
* bool(const Type &..., const Type &...);
* bool(const Entity, const Entity);
* @endcode
@@ -604,7 +597,7 @@ public:
*/
template<typename Type, typename... Other, typename Compare, typename Sort = std_sort, typename... Args>
void sort(Compare compare, Sort algo = Sort{}, Args &&...args) {
sort<index_of<Type>, index_of<Other>...>(std::move(compare), std::move(algo), std::forward<Args>(args)...);
sort<index_of<Type>, index_of<Other>...>(stl::move(compare), stl::move(algo), stl::forward<Args>(args)...);
}
/**
@@ -620,22 +613,22 @@ public:
* @param algo A valid sort function object.
* @param args Arguments to forward to the sort function object, if any.
*/
template<std::size_t... Index, typename Compare, typename Sort = std_sort, typename... Args>
template<stl::size_t... Index, typename Compare, typename Sort = std_sort, typename... Args>
void sort(Compare compare, Sort algo = Sort{}, Args &&...args) {
if(*this) {
if constexpr(sizeof...(Index) == 0) {
static_assert(std::is_invocable_v<Compare, const entity_type, const entity_type>, "Invalid comparison function");
descriptor->handle().sort(std::move(compare), std::move(algo), std::forward<Args>(args)...);
static_assert(stl::is_invocable_v<Compare, const entity_type, const entity_type>, "Invalid comparison function");
descriptor->handle().sort(stl::move(compare), stl::move(algo), stl::forward<Args>(args)...);
} else {
auto comp = [&compare, cpools = pools_for(std::index_sequence_for<Get...>{})](const entity_type lhs, const entity_type rhs) {
auto comp = [&compare, cpools = pools_for(stl::index_sequence_for<Get...>{})](const entity_type lhs, const entity_type rhs) {
if constexpr(sizeof...(Index) == 1) {
return compare((std::get<Index>(cpools)->get(lhs), ...), (std::get<Index>(cpools)->get(rhs), ...));
return compare((stl::get<Index>(cpools)->get(lhs), ...), (stl::get<Index>(cpools)->get(rhs), ...));
} else {
return compare(std::forward_as_tuple(std::get<Index>(cpools)->get(lhs)...), std::forward_as_tuple(std::get<Index>(cpools)->get(rhs)...));
return compare(stl::forward_as_tuple(stl::get<Index>(cpools)->get(lhs)...), stl::forward_as_tuple(stl::get<Index>(cpools)->get(rhs)...));
}
};
descriptor->handle().sort(std::move(comp), std::move(algo), std::forward<Args>(args)...);
descriptor->handle().sort(stl::move(comp), stl::move(algo), stl::forward<Args>(args)...);
}
}
}
@@ -646,12 +639,10 @@ public:
* The shared pool of entities and thus its order is affected by the changes
* to each and every pool that it tracks.
*
* @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 It>
void sort_as(It first, It last) const {
void sort_as(stl::input_iterator auto first, stl::input_iterator auto last) const {
if(*this) {
descriptor->handle().sort_as(first, last);
}
@@ -696,15 +687,15 @@ template<typename... Owned, typename... Get, typename... Exclude>
class basic_group<owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>> {
static_assert(((Owned::storage_policy != deletion_policy::in_place) && ...), "Groups do not support in-place delete");
using base_type = std::common_type_t<typename Owned::base_type..., typename Get::base_type..., typename Exclude::base_type...>;
using underlying_type = typename base_type::entity_type;
using base_type = stl::common_type_t<typename Owned::base_type..., typename Get::base_type..., typename Exclude::base_type...>;
using underlying_type = base_type::entity_type;
template<typename Type>
static constexpr std::size_t index_of = type_list_index_v<std::remove_const_t<Type>, type_list<typename Owned::element_type..., typename Get::element_type..., typename Exclude::element_type...>>;
static constexpr stl::size_t index_of = type_list_index_v<stl::remove_const_t<Type>, type_list<typename Owned::element_type..., typename Get::element_type..., typename Exclude::element_type...>>;
template<std::size_t... Index, std::size_t... Other>
[[nodiscard]] auto pools_for(std::index_sequence<Index...>, std::index_sequence<Other...>) const noexcept {
using return_type = std::tuple<Owned *..., Get *...>;
template<stl::size_t... Index, stl::size_t... Other>
[[nodiscard]] auto pools_for(stl::index_sequence<Index...>, stl::index_sequence<Other...>) const noexcept {
using return_type = stl::tuple<Owned *..., Get *...>;
return descriptor ? return_type{static_cast<Owned *>(descriptor->template storage<Index>())..., static_cast<Get *>(descriptor->template storage<sizeof...(Owned) + Other>())...} : return_type{};
}
@@ -712,15 +703,15 @@ public:
/*! @brief Underlying entity identifier. */
using entity_type = underlying_type;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
using size_type = stl::size_t;
/*! @brief Signed integer type. */
using difference_type = std::ptrdiff_t;
using difference_type = stl::ptrdiff_t;
/*! @brief Common type among all storage types. */
using common_type = base_type;
/*! @brief Random access iterator type. */
using iterator = typename common_type::iterator;
using iterator = common_type::iterator;
/*! @brief Reverse iterator type. */
using reverse_iterator = typename common_type::reverse_iterator;
using reverse_iterator = common_type::reverse_iterator;
/*! @brief Iterable group type. */
using iterable = iterable_adaptor<internal::extended_group_iterator<iterator, owned_t<Owned...>, get_t<Get...>>>;
/*! @brief Group handler type. */
@@ -731,7 +722,7 @@ public:
* @return Group opaque identifier.
*/
static id_type group_id() noexcept {
return type_hash<basic_group<owned_t<std::remove_const_t<Owned>...>, get_t<std::remove_const_t<Get>...>, exclude_t<std::remove_const_t<Exclude>...>>>::value();
return type_hash<basic_group<owned_t<stl::remove_const_t<Owned>...>, get_t<stl::remove_const_t<Get>...>, exclude_t<stl::remove_const_t<Exclude>...>>>::value();
}
/*! @brief Default constructor to use to create empty, invalid groups. */
@@ -768,7 +759,7 @@ public:
* @tparam Index Index of the storage to return.
* @return The storage for the given index.
*/
template<std::size_t Index>
template<stl::size_t Index>
[[nodiscard]] auto *storage() const noexcept {
using type = type_list_element_t<Index, type_list<Owned..., Get..., Exclude...>>;
return *this ? static_cast<type *>(descriptor->template storage<Index>()) : nullptr;
@@ -906,16 +897,16 @@ public:
* @param entt A valid identifier.
* @return The elements assigned to the entity.
*/
template<std::size_t... Index>
template<stl::size_t... Index>
[[nodiscard]] decltype(auto) get(const entity_type entt) const {
const auto cpools = pools_for(std::index_sequence_for<Owned...>{}, std::index_sequence_for<Get...>{});
const auto cpools = pools_for(stl::index_sequence_for<Owned...>{}, stl::index_sequence_for<Get...>{});
if constexpr(sizeof...(Index) == 0) {
return std::apply([entt](auto *...curr) { return std::tuple_cat(curr->get_as_tuple(entt)...); }, cpools);
return stl::apply([entt](auto *...curr) { return stl::tuple_cat(curr->get_as_tuple(entt)...); }, cpools);
} else if constexpr(sizeof...(Index) == 1) {
return (std::get<Index>(cpools)->get(entt), ...);
return (stl::get<Index>(cpools)->get(entt), ...);
} else {
return std::tuple_cat(std::get<Index>(cpools)->get_as_tuple(entt)...);
return stl::tuple_cat(stl::get<Index>(cpools)->get_as_tuple(entt)...);
}
}
@@ -944,10 +935,10 @@ public:
template<typename Func>
void each(Func func) const {
for(auto args: each()) {
if constexpr(is_applicable_v<Func, decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_group>().get({})))>) {
std::apply(func, args);
if constexpr(is_applicable_v<Func, decltype(stl::tuple_cat(stl::tuple<entity_type>{}, stl::declval<basic_group>().get({})))>) {
stl::apply(func, args);
} else {
std::apply([&func](auto, auto &&...less) { func(std::forward<decltype(less)>(less)...); }, args);
stl::apply([&func](auto, auto &&...less) { func(stl::forward<decltype(less)>(less)...); }, args);
}
}
}
@@ -966,7 +957,7 @@ public:
* @return An iterable object to use to _visit_ the group.
*/
[[nodiscard]] iterable each() const noexcept {
const auto cpools = pools_for(std::index_sequence_for<Owned...>{}, std::index_sequence_for<Get...>{});
const auto cpools = pools_for(stl::index_sequence_for<Owned...>{}, stl::index_sequence_for<Get...>{});
return iterable{{begin(), cpools}, {end(), cpools}};
}
@@ -978,7 +969,7 @@ public:
* comparison function should be equivalent to one of the following:
*
* @code{.cpp}
* bool(std::tuple<Type &...>, std::tuple<Type &...>);
* bool(stl::tuple<Type &...>, stl::tuple<Type &...>);
* bool(const Type &, const Type &);
* bool(const Entity, const Entity);
* @endcode
@@ -1006,7 +997,7 @@ public:
*/
template<typename Type, typename... Other, typename Compare, typename Sort = std_sort, typename... Args>
void sort(Compare compare, Sort algo = Sort{}, Args &&...args) const {
sort<index_of<Type>, index_of<Other>...>(std::move(compare), std::move(algo), std::forward<Args>(args)...);
sort<index_of<Type>, index_of<Other>...>(stl::move(compare), stl::move(algo), stl::forward<Args>(args)...);
}
/**
@@ -1022,23 +1013,23 @@ public:
* @param algo A valid sort function object.
* @param args Arguments to forward to the sort function object, if any.
*/
template<std::size_t... Index, typename Compare, typename Sort = std_sort, typename... Args>
template<stl::size_t... Index, typename Compare, typename Sort = std_sort, typename... Args>
void sort(Compare compare, Sort algo = Sort{}, Args &&...args) const {
const auto cpools = pools_for(std::index_sequence_for<Owned...>{}, std::index_sequence_for<Get...>{});
const auto cpools = pools_for(stl::index_sequence_for<Owned...>{}, stl::index_sequence_for<Get...>{});
if constexpr(sizeof...(Index) == 0) {
static_assert(std::is_invocable_v<Compare, const entity_type, const entity_type>, "Invalid comparison function");
storage<0>()->sort_n(descriptor->length(), std::move(compare), std::move(algo), std::forward<Args>(args)...);
static_assert(stl::is_invocable_v<Compare, const entity_type, const entity_type>, "Invalid comparison function");
storage<0>()->sort_n(descriptor->length(), stl::move(compare), stl::move(algo), stl::forward<Args>(args)...);
} else {
auto comp = [&compare, &cpools](const entity_type lhs, const entity_type rhs) {
if constexpr(sizeof...(Index) == 1) {
return compare((std::get<Index>(cpools)->get(lhs), ...), (std::get<Index>(cpools)->get(rhs), ...));
return compare((stl::get<Index>(cpools)->get(lhs), ...), (stl::get<Index>(cpools)->get(rhs), ...));
} else {
return compare(std::forward_as_tuple(std::get<Index>(cpools)->get(lhs)...), std::forward_as_tuple(std::get<Index>(cpools)->get(rhs)...));
return compare(stl::forward_as_tuple(stl::get<Index>(cpools)->get(lhs)...), stl::forward_as_tuple(stl::get<Index>(cpools)->get(rhs)...));
}
};
storage<0>()->sort_n(descriptor->length(), std::move(comp), std::move(algo), std::forward<Args>(args)...);
storage<0>()->sort_n(descriptor->length(), stl::move(comp), stl::move(algo), stl::forward<Args>(args)...);
}
auto cb = [this](auto *head, auto *...other) {
@@ -1049,7 +1040,7 @@ public:
}
};
std::apply(cb, cpools);
stl::apply(cb, cpools);
}
private:

View File

@@ -1,36 +1,36 @@
#ifndef ENTT_ENTITY_HANDLE_HPP
#define ENTT_ENTITY_HANDLE_HPP
#include <iterator>
#include <tuple>
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "../core/iterator.hpp"
#include "../core/type_traits.hpp"
#include "../stl/iterator.hpp"
#include "../stl/tuple.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "entity.hpp"
#include "fwd.hpp"
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
template<typename It>
class handle_storage_iterator final {
template<typename Other>
template<typename>
friend class handle_storage_iterator;
using underlying_type = std::remove_reference_t<typename It::value_type::second_type>;
using entity_type = typename underlying_type::entity_type;
using underlying_type = stl::remove_reference_t<typename It::value_type::second_type>;
using entity_type = underlying_type::entity_type;
public:
using value_type = typename std::iterator_traits<It>::value_type;
using value_type = stl::iterator_traits<It>::value_type;
using pointer = input_iterator_pointer<value_type>;
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category = std::input_iterator_tag;
using iterator_concept = std::forward_iterator_tag;
using difference_type = stl::ptrdiff_t;
using iterator_category = stl::input_iterator_tag;
using iterator_concept = stl::forward_iterator_tag;
constexpr handle_storage_iterator() noexcept
: entt{null},
@@ -64,8 +64,10 @@ public:
return operator*();
}
template<typename ILhs, typename IRhs>
friend constexpr bool operator==(const handle_storage_iterator<ILhs> &, const handle_storage_iterator<IRhs> &) noexcept;
template<typename Other>
[[nodiscard]] constexpr bool operator==(const handle_storage_iterator<Other> &other) const noexcept {
return it == other.it;
}
private:
entity_type entt;
@@ -73,16 +75,6 @@ private:
It last;
};
template<typename ILhs, typename IRhs>
[[nodiscard]] constexpr bool operator==(const handle_storage_iterator<ILhs> &lhs, const handle_storage_iterator<IRhs> &rhs) noexcept {
return lhs.it == rhs.it;
}
template<typename ILhs, typename IRhs>
[[nodiscard]] constexpr bool operator!=(const handle_storage_iterator<ILhs> &lhs, const handle_storage_iterator<IRhs> &rhs) noexcept {
return !(lhs == rhs);
}
} // namespace internal
/*! @endcond */
@@ -107,13 +99,13 @@ public:
/*! @brief Type of registry accepted by the handle. */
using registry_type = Registry;
/*! @brief Underlying entity identifier. */
using entity_type = typename traits_type::value_type;
using entity_type = traits_type::value_type;
/*! @brief Underlying version type. */
using version_type = typename traits_type::version_type;
using version_type = traits_type::version_type;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
using size_type = stl::size_t;
/*! @brief Iterable handle type. */
using iterable = iterable_adaptor<internal::handle_storage_iterator<typename decltype(std::declval<registry_type>().storage())::iterator>>;
using iterable = iterable_adaptor<internal::handle_storage_iterator<typename decltype(stl::declval<registry_type>().storage())::iterator>>;
/*! @brief Constructs an invalid handle. */
basic_handle() noexcept
@@ -181,7 +173,7 @@ public:
/*! @brief Destroys the entity associated with a handle. */
void destroy() {
owner_or_assert().destroy(std::exchange(entt, null));
owner_or_assert().destroy(stl::exchange(entt, null));
}
/**
@@ -189,7 +181,7 @@ public:
* @param version A desired version upon destruction.
*/
void destroy(const version_type version) {
owner_or_assert().destroy(std::exchange(entt, null), version);
owner_or_assert().destroy(stl::exchange(entt, null), version);
}
/**
@@ -202,8 +194,8 @@ public:
template<typename Type, typename... Args>
// NOLINTNEXTLINE(modernize-use-nodiscard)
decltype(auto) emplace(Args &&...args) const {
static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Type, Scope>), "Invalid type");
return owner_or_assert().template emplace<Type>(entt, std::forward<Args>(args)...);
static_assert(((sizeof...(Scope) == 0) || ... || stl::is_same_v<Type, Scope>), "Invalid type");
return owner_or_assert().template emplace<Type>(entt, stl::forward<Args>(args)...);
}
/**
@@ -215,8 +207,8 @@ public:
*/
template<typename Type, typename... Args>
decltype(auto) emplace_or_replace(Args &&...args) const {
static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Type, Scope>), "Invalid type");
return owner_or_assert().template emplace_or_replace<Type>(entt, std::forward<Args>(args)...);
static_assert(((sizeof...(Scope) == 0) || ... || stl::is_same_v<Type, Scope>), "Invalid type");
return owner_or_assert().template emplace_or_replace<Type>(entt, stl::forward<Args>(args)...);
}
/**
@@ -228,8 +220,8 @@ public:
*/
template<typename Type, typename... Func>
decltype(auto) patch(Func &&...func) const {
static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Type, Scope>), "Invalid type");
return owner_or_assert().template patch<Type>(entt, std::forward<Func>(func)...);
static_assert(((sizeof...(Scope) == 0) || ... || stl::is_same_v<Type, Scope>), "Invalid type");
return owner_or_assert().template patch<Type>(entt, stl::forward<Func>(func)...);
}
/**
@@ -241,8 +233,8 @@ public:
*/
template<typename Type, typename... Args>
decltype(auto) replace(Args &&...args) const {
static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Type, Scope>), "Invalid type");
return owner_or_assert().template replace<Type>(entt, std::forward<Args>(args)...);
static_assert(((sizeof...(Scope) == 0) || ... || stl::is_same_v<Type, Scope>), "Invalid type");
return owner_or_assert().template replace<Type>(entt, stl::forward<Args>(args)...);
}
/**
@@ -308,8 +300,8 @@ public:
*/
template<typename Type, typename... Args>
[[nodiscard]] decltype(auto) get_or_emplace(Args &&...args) const {
static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Type, Scope>), "Invalid type");
return owner_or_assert().template get_or_emplace<Type>(entt, std::forward<Args>(args)...);
static_assert(((sizeof...(Scope) == 0) || ... || stl::is_same_v<Type, Scope>), "Invalid type");
return owner_or_assert().template get_or_emplace<Type>(entt, stl::forward<Args>(args)...);
}
/**
@@ -331,6 +323,27 @@ public:
return owner_or_assert().orphan(entt);
}
/**
* @brief Compares two handles.
* @tparam Other Scope of the other handle.
* @param other A valid handle.
* @return True if both handles refer to the same registry and the same
* entity, false otherwise.
*/
template<typename... Other>
[[nodiscard]] bool operator==(const basic_handle<Other...> &other) const noexcept {
return owner == other.registry() && entt == other.entity();
}
/**
* @brief Compares a handle with the null object.
* @param other A null object yet to be converted.
* @return False if the two elements differ, true otherwise.
*/
[[nodiscard]] constexpr bool operator==(const null_t other) const noexcept {
return (entt == other);
}
/**
* @brief Returns a const handle from a non-const one.
* @tparam Other A valid entity type.
@@ -340,7 +353,7 @@ public:
*/
template<typename Other, typename... Args>
operator basic_handle<Other, Args...>() const noexcept {
static_assert(std::is_same_v<Other, Registry> || std::is_same_v<std::remove_const_t<Other>, Registry>, "Invalid conversion between different handles");
static_assert(stl::is_same_v<Other, Registry> || stl::is_same_v<stl::remove_const_t<Other>, Registry>, "Invalid conversion between different handles");
static_assert((sizeof...(Scope) == 0 || ((sizeof...(Args) != 0 && sizeof...(Args) <= sizeof...(Scope)) && ... && (type_list_contains_v<type_list<Scope...>, Args>))), "Invalid conversion between different handles");
return owner ? basic_handle<Other, Args...>{*owner, entt} : basic_handle<Other, Args...>{};
}
@@ -350,82 +363,6 @@ private:
entity_type entt;
};
/**
* @brief Compares two handles.
* @tparam Args Scope of the first handle.
* @tparam Other Scope of the second handle.
* @param lhs A valid handle.
* @param rhs A valid handle.
* @return True if both handles refer to the same registry and the same
* entity, false otherwise.
*/
template<typename... Args, typename... Other>
[[nodiscard]] bool operator==(const basic_handle<Args...> &lhs, const basic_handle<Other...> &rhs) noexcept {
return lhs.registry() == rhs.registry() && lhs.entity() == rhs.entity();
}
/**
* @brief Compares two handles.
* @tparam Args Scope of the first handle.
* @tparam Other Scope of the second handle.
* @param lhs A valid handle.
* @param rhs A valid handle.
* @return False if both handles refer to the same registry and the same
* entity, true otherwise.
*/
template<typename... Args, typename... Other>
[[nodiscard]] bool operator!=(const basic_handle<Args...> &lhs, const basic_handle<Other...> &rhs) noexcept {
return !(lhs == rhs);
}
/**
* @brief Compares a handle with the null object.
* @tparam Args Scope of the handle.
* @param lhs A valid handle.
* @param rhs A null object yet to be converted.
* @return False if the two elements differ, true otherwise.
*/
template<typename... Args>
[[nodiscard]] constexpr bool operator==(const basic_handle<Args...> &lhs, const null_t rhs) noexcept {
return (lhs.entity() == rhs);
}
/**
* @brief Compares a handle with the null object.
* @tparam Args Scope of the handle.
* @param lhs A null object yet to be converted.
* @param rhs A valid handle.
* @return False if the two elements differ, true otherwise.
*/
template<typename... Args>
[[nodiscard]] constexpr bool operator==(const null_t lhs, const basic_handle<Args...> &rhs) noexcept {
return (rhs == lhs);
}
/**
* @brief Compares a handle with the null object.
* @tparam Args Scope of the handle.
* @param lhs A valid handle.
* @param rhs A null object yet to be converted.
* @return True if the two elements differ, false otherwise.
*/
template<typename... Args>
[[nodiscard]] constexpr bool operator!=(const basic_handle<Args...> &lhs, const null_t rhs) noexcept {
return (lhs.entity() != rhs);
}
/**
* @brief Compares a handle with the null object.
* @tparam Args Scope of the handle.
* @param lhs A null object yet to be converted.
* @param rhs A valid handle.
* @return True if the two elements differ, false otherwise.
*/
template<typename... Args>
[[nodiscard]] constexpr bool operator!=(const null_t lhs, const basic_handle<Args...> &rhs) noexcept {
return (rhs != lhs);
}
} // namespace entt
#endif

View File

@@ -1,11 +1,11 @@
#ifndef ENTT_ENTITY_HELPER_HPP
#define ENTT_ENTITY_HELPER_HPP
#include <memory>
#include <type_traits>
#include <utility>
#include "../core/fwd.hpp"
#include "../core/type_traits.hpp"
#include "../stl/memory.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "component.hpp"
#include "fwd.hpp"
#include "group.hpp"
@@ -29,7 +29,7 @@ public:
/*! @brief Type of registry to convert. */
using registry_type = Registry;
/*! @brief Underlying entity identifier. */
using entity_type = typename registry_type::entity_type;
using entity_type = registry_type::entity_type;
/**
* @brief Constructs a converter for a given registry.
@@ -61,7 +61,7 @@ template<typename Registry>
class as_group {
template<typename... Owned, typename... Get, typename... Exclude>
[[nodiscard]] auto dispatch(owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>) const {
if constexpr(std::is_const_v<registry_type>) {
if constexpr(stl::is_const_v<registry_type>) {
return reg->template group_if_exists<typename Owned::element_type...>(get_t<typename Get::element_type...>{}, exclude_t<typename Exclude::element_type...>{});
} else {
return reg->template group<constness_as_t<typename Owned::element_type, Owned>...>(get_t<constness_as_t<typename Get::element_type, Get>...>{}, exclude_t<constness_as_t<typename Exclude::element_type, Exclude>...>{});
@@ -72,7 +72,7 @@ public:
/*! @brief Type of registry to convert. */
using registry_type = Registry;
/*! @brief Underlying entity identifier. */
using entity_type = typename registry_type::entity_type;
using entity_type = registry_type::entity_type;
/**
* @brief Constructs a converter for a given registry.
@@ -104,9 +104,9 @@ private:
* @param reg A registry that contains the given entity and its elements.
* @param entt Entity from which to get the element.
*/
template<auto Member, typename Registry = std::decay_t<nth_argument_t<0u, decltype(Member)>>>
template<auto Member, typename Registry = stl::decay_t<nth_argument_t<0u, decltype(Member)>>>
void invoke(Registry &reg, const typename Registry::entity_type entt) {
static_assert(std::is_member_function_pointer_v<decltype(Member)>, "Invalid pointer to non-static member function");
static_assert(stl::is_member_function_pointer_v<decltype(Member)>, "Invalid pointer to non-static member function");
(reg.template get<member_class_t<decltype(Member)>>(entt).*Member)(reg, entt);
}
@@ -123,15 +123,15 @@ void invoke(Registry &reg, const typename Registry::entity_type entt) {
* @return The entity associated with the given element.
*/
template<typename... Args>
typename basic_storage<Args...>::entity_type to_entity(const basic_storage<Args...> &storage, const typename basic_storage<Args...>::value_type &instance) {
basic_storage<Args...>::entity_type to_entity(const basic_storage<Args...> &storage, const typename basic_storage<Args...>::value_type &instance) {
using traits_type = component_traits<typename basic_storage<Args...>::value_type, typename basic_storage<Args...>::entity_type>;
static_assert(traits_type::page_size != 0u, "Unexpected page size");
const auto *page = storage.raw();
// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic)
for(std::size_t pos{}, count = storage.size(); pos < count; pos += traits_type::page_size, ++page) {
if(const auto dist = (std::addressof(instance) - *page); dist >= 0 && dist < static_cast<decltype(dist)>(traits_type::page_size)) {
return *(static_cast<const typename basic_storage<Args...>::base_type &>(storage).rbegin() + static_cast<decltype(dist)>(pos) + dist);
for(stl::size_t pos{}, count = storage.size(); pos < count; pos += traits_type::page_size, ++page) {
if(const auto dist = (stl::addressof(instance) - *page); dist >= 0 && dist < static_cast<decltype(dist)>(traits_type::page_size)) {
return *(static_cast<const basic_storage<Args...>::base_type &>(storage).rbegin() + static_cast<decltype(dist)>(pos) + dist);
}
}
// NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
@@ -210,7 +210,7 @@ struct sigh_helper<Registry, Type> final: sigh_helper<Registry> {
*/
template<auto Candidate, typename... Args>
auto on_construct(Args &&...args) {
this->registry().template on_construct<Type>(name).template connect<Candidate>(std::forward<Args>(args)...);
this->registry().template on_construct<Type>(name).template connect<Candidate>(stl::forward<Args>(args)...);
return *this;
}
@@ -223,7 +223,7 @@ struct sigh_helper<Registry, Type> final: sigh_helper<Registry> {
*/
template<auto Candidate, typename... Args>
auto on_update(Args &&...args) {
this->registry().template on_update<Type>(name).template connect<Candidate>(std::forward<Args>(args)...);
this->registry().template on_update<Type>(name).template connect<Candidate>(stl::forward<Args>(args)...);
return *this;
}
@@ -236,7 +236,7 @@ struct sigh_helper<Registry, Type> final: sigh_helper<Registry> {
*/
template<auto Candidate, typename... Args>
auto on_destroy(Args &&...args) {
this->registry().template on_destroy<Type>(name).template connect<Candidate>(std::forward<Args>(args)...);
this->registry().template on_destroy<Type>(name).template connect<Candidate>(stl::forward<Args>(args)...);
return *this;
}

View File

@@ -1,40 +1,43 @@
#ifndef ENTT_ENTITY_MIXIN_HPP
#define ENTT_ENTITY_MIXIN_HPP
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "../core/any.hpp"
#include "../core/type_info.hpp"
#include "../signal/sigh.hpp"
#include "../stl/concepts.hpp"
#include "../stl/iterator.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "../stl/vector.hpp"
#include "entity.hpp"
#include "fwd.hpp"
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
template<typename, typename, typename = void>
struct has_on_construct final: std::false_type {};
template<typename, typename>
struct has_on_construct final: stl::false_type {};
template<typename Type, typename Registry>
struct has_on_construct<Type, Registry, std::void_t<decltype(Type::on_construct(std::declval<Registry &>(), std::declval<Registry>().create()))>>
: std::true_type {};
requires stl::invocable<decltype(&Type::on_construct), Registry &, typename Registry::entity_type>
struct has_on_construct<Type, Registry>: stl::true_type {};
template<typename, typename, typename = void>
struct has_on_update final: std::false_type {};
template<typename, typename>
struct has_on_update final: stl::false_type {};
template<typename Type, typename Registry>
struct has_on_update<Type, Registry, std::void_t<decltype(Type::on_update(std::declval<Registry &>(), std::declval<Registry>().create()))>>
: std::true_type {};
requires stl::invocable<decltype(&Type::on_update), Registry &, typename Registry::entity_type>
struct has_on_update<Type, Registry>: stl::true_type {};
template<typename, typename, typename = void>
struct has_on_destroy final: std::false_type {};
template<typename, typename>
struct has_on_destroy final: stl::false_type {};
template<typename Type, typename Registry>
struct has_on_destroy<Type, Registry, std::void_t<decltype(Type::on_destroy(std::declval<Registry &>(), std::declval<Registry>().create()))>>
: std::true_type {};
requires stl::invocable<decltype(&Type::on_destroy), Registry &, typename Registry::entity_type>
struct has_on_destroy<Type, Registry>: stl::true_type {};
} // namespace internal
/*! @endcond */
@@ -60,9 +63,9 @@ class basic_sigh_mixin final: public Type {
using basic_registry_type = basic_registry<typename owner_type::entity_type, typename owner_type::allocator_type>;
using sigh_type = sigh<void(owner_type &, const typename underlying_type::entity_type), typename underlying_type::allocator_type>;
using underlying_iterator = typename underlying_type::base_type::basic_iterator;
using underlying_iterator = underlying_type::base_type::basic_iterator;
static_assert(std::is_base_of_v<basic_registry_type, owner_type>, "Invalid registry type");
static_assert(stl::is_base_of_v<basic_registry_type, owner_type>, "Invalid registry type");
[[nodiscard]] auto &owner_or_assert() const noexcept {
ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry");
@@ -85,12 +88,12 @@ private:
void pop_all() final {
if(auto &reg = owner_or_assert(); !destruction.empty()) {
if constexpr(std::is_same_v<typename underlying_type::element_type, entity_type>) {
if constexpr(stl::is_same_v<typename underlying_type::element_type, entity_type>) {
for(typename underlying_type::size_type pos{}, last = underlying_type::free_list(); pos < last; ++pos) {
destruction.publish(reg, underlying_type::base_type::operator[](pos));
}
} else {
for(auto entt: static_cast<typename underlying_type::base_type &>(*this)) {
for(auto entt: static_cast<underlying_type::base_type &>(*this)) {
if constexpr(underlying_type::storage_policy == deletion_policy::in_place) {
if(entt != tombstone) {
destruction.publish(reg, entt);
@@ -105,7 +108,7 @@ private:
underlying_type::pop_all();
}
underlying_iterator try_emplace(const typename underlying_type::entity_type entt, const bool force_back, const void *value) final {
underlying_iterator try_emplace(const underlying_type::entity_type entt, const bool force_back, const void *value) final {
const auto it = underlying_type::try_emplace(entt, force_back, value);
if(auto &reg = owner_or_assert(); it != underlying_type::base_type::end()) {
@@ -118,20 +121,20 @@ private:
void bind_any(any value) noexcept final {
owner = any_cast<basic_registry_type>(&value);
if constexpr(!std::is_same_v<registry_type, basic_registry_type>) {
if constexpr(!stl::is_same_v<registry_type, basic_registry_type>) {
if(owner == nullptr) {
owner = any_cast<registry_type>(&value);
}
}
underlying_type::bind_any(std::move(value));
underlying_type::bind_any(stl::move(value));
}
public:
/*! @brief Allocator type. */
using allocator_type = typename underlying_type::allocator_type;
using allocator_type = underlying_type::allocator_type;
/*! @brief Underlying entity identifier. */
using entity_type = typename underlying_type::entity_type;
using entity_type = underlying_type::entity_type;
/*! @brief Expected registry type. */
using registry_type = owner_type;
@@ -172,9 +175,9 @@ public:
basic_sigh_mixin(basic_sigh_mixin &&other) noexcept
: 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)} {}
construction{stl::move(other.construction)},
destruction{stl::move(other.destruction)},
update{stl::move(other.update)} {}
/**
* @brief Allocator-extended move constructor.
@@ -184,9 +187,9 @@ public:
basic_sigh_mixin(basic_sigh_mixin &&other, const allocator_type &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} {}
construction{stl::move(other.construction), allocator},
destruction{stl::move(other.destruction), allocator},
update{stl::move(other.update), allocator} {}
/*! @brief Default destructor. */
~basic_sigh_mixin() override = default;
@@ -212,7 +215,7 @@ public:
* @param other Storage to exchange the content with.
*/
void swap(basic_sigh_mixin &other) noexcept {
using std::swap;
using stl::swap;
swap(owner, other.owner);
swap(construction, other.construction);
swap(destruction, other.destruction);
@@ -309,11 +312,11 @@ public:
/**
* @brief Assigns each element in a range an identifier.
* @tparam It Type of mutable forward iterator.
* @tparam It Type of output 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>
template<stl::output_iterator<entity_type> It>
void generate(It first, It last) {
underlying_type::generate(first, last);
@@ -333,7 +336,7 @@ public:
*/
template<typename... Args>
decltype(auto) emplace(const entity_type entt, Args &&...args) {
underlying_type::emplace(entt, std::forward<Args>(args)...);
underlying_type::emplace(entt, stl::forward<Args>(args)...);
construction.publish(owner_or_assert(), entt);
return this->get(entt);
}
@@ -347,7 +350,7 @@ public:
*/
template<typename... Func>
decltype(auto) patch(const entity_type entt, Func &&...func) {
underlying_type::patch(entt, std::forward<Func>(func)...);
underlying_type::patch(entt, stl::forward<Func>(func)...);
update.publish(owner_or_assert(), entt);
return this->get(entt);
}
@@ -355,16 +358,15 @@ public:
/**
* @brief Assigns one or more entities to a storage and constructs their
* objects from a given instance.
* @tparam It Type of input iterator.
* @tparam Args Types of arguments to forward to the underlying storage.
* @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.
* @param args Parameters to use to forward to the underlying storage.
*/
template<typename It, typename... Args>
void insert(It first, It last, Args &&...args) {
template<typename... Args>
void insert(stl::input_iterator auto first, stl::input_iterator auto last, Args &&...args) {
auto from = underlying_type::size();
underlying_type::insert(first, last, std::forward<Args>(args)...);
underlying_type::insert(first, last, stl::forward<Args>(args)...);
if(auto &reg = owner_or_assert(); !construction.empty()) {
// fine as long as insert passes force_back true to try_emplace
@@ -391,18 +393,18 @@ class basic_reactive_mixin final: public Type {
using underlying_type = Type;
using owner_type = Registry;
using alloc_traits = std::allocator_traits<typename underlying_type::allocator_type>;
using alloc_traits = stl::allocator_traits<typename underlying_type::allocator_type>;
using basic_registry_type = basic_registry<typename owner_type::entity_type, typename owner_type::allocator_type>;
using container_type = std::vector<connection, typename alloc_traits::template rebind_alloc<connection>>;
using container_type = stl::vector<connection, typename alloc_traits::template rebind_alloc<connection>>;
static_assert(std::is_base_of_v<basic_registry_type, owner_type>, "Invalid registry type");
static_assert(stl::is_base_of_v<basic_registry_type, owner_type>, "Invalid registry type");
[[nodiscard]] auto &owner_or_assert() const noexcept {
ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry");
return static_cast<owner_type &>(*owner);
}
void emplace_element(const Registry &, typename underlying_type::entity_type entity) {
void emplace_element(const Registry &, underlying_type::entity_type entity) {
if(!underlying_type::contains(entity)) {
underlying_type::emplace(entity);
}
@@ -412,20 +414,20 @@ private:
void bind_any(any value) noexcept final {
owner = any_cast<basic_registry_type>(&value);
if constexpr(!std::is_same_v<registry_type, basic_registry_type>) {
if constexpr(!stl::is_same_v<registry_type, basic_registry_type>) {
if(owner == nullptr) {
owner = any_cast<registry_type>(&value);
}
}
underlying_type::bind_any(std::move(value));
underlying_type::bind_any(stl::move(value));
}
public:
/*! @brief Allocator type. */
using allocator_type = typename underlying_type::allocator_type;
using allocator_type = underlying_type::allocator_type;
/*! @brief Underlying entity identifier. */
using entity_type = typename underlying_type::entity_type;
using entity_type = underlying_type::entity_type;
/*! @brief Expected registry type. */
using registry_type = owner_type;
@@ -453,7 +455,7 @@ public:
basic_reactive_mixin(basic_reactive_mixin &&other) noexcept
: underlying_type{static_cast<underlying_type &&>(other)},
owner{other.owner},
conn{std::move(other.conn)} {
conn{stl::move(other.conn)} {
}
/**
@@ -464,7 +466,7 @@ public:
basic_reactive_mixin(basic_reactive_mixin &&other, const allocator_type &allocator)
: underlying_type{static_cast<underlying_type &&>(other), allocator},
owner{other.owner},
conn{std::move(other.conn), allocator} {
conn{stl::move(other.conn), allocator} {
}
/*! @brief Default destructor. */
@@ -496,7 +498,7 @@ public:
template<typename Clazz, auto Candidate = &basic_reactive_mixin::emplace_element>
basic_reactive_mixin &on_construct(const id_type id = type_hash<Clazz>::value()) {
auto curr = owner_or_assert().template storage<Clazz>(id).on_construct().template connect<Candidate>(*this);
conn.push_back(std::move(curr));
conn.push_back(stl::move(curr));
return *this;
}
@@ -510,7 +512,7 @@ public:
template<typename Clazz, auto Candidate = &basic_reactive_mixin::emplace_element>
basic_reactive_mixin &on_update(const id_type id = type_hash<Clazz>::value()) {
auto curr = owner_or_assert().template storage<Clazz>(id).on_update().template connect<Candidate>(*this);
conn.push_back(std::move(curr));
conn.push_back(stl::move(curr));
return *this;
}
@@ -524,7 +526,7 @@ public:
template<typename Clazz, auto Candidate = &basic_reactive_mixin::emplace_element>
basic_reactive_mixin &on_destroy(const id_type id = type_hash<Clazz>::value()) {
auto curr = owner_or_assert().template storage<Clazz>(id).on_destroy().template connect<Candidate>(*this);
conn.push_back(std::move(curr));
conn.push_back(stl::move(curr));
return *this;
}
@@ -560,7 +562,7 @@ public:
view(exclude_t<Exclude...> = exclude_t{}) const {
const owner_type &parent = owner_or_assert();
basic_view<get_t<const basic_reactive_mixin, typename basic_registry_type::template storage_for_type<const Get>...>, exclude_t<typename basic_registry_type::template storage_for_type<const Exclude>...>> elem{};
[&elem](const auto *...curr) { ((curr ? elem.storage(*curr) : void()), ...); }(parent.template storage<std::remove_const_t<Exclude>>()..., parent.template storage<std::remove_const_t<Get>>()..., this);
[&elem](const auto *...curr) { ((curr ? elem.storage(*curr) : void()), ...); }(parent.template storage<stl::remove_const_t<Exclude>>()..., parent.template storage<stl::remove_const_t<Get>>()..., this);
return elem;
}
@@ -568,8 +570,8 @@ public:
template<typename... Get, typename... Exclude>
[[nodiscard]] basic_view<get_t<const basic_reactive_mixin, typename basic_registry_type::template storage_for_type<Get>...>, exclude_t<typename basic_registry_type::template storage_for_type<Exclude>...>>
view(exclude_t<Exclude...> = exclude_t{}) {
std::conditional_t<((std::is_const_v<Get> && ...) && (std::is_const_v<Exclude> && ...)), const owner_type, owner_type> &parent = owner_or_assert();
return {*this, parent.template storage<std::remove_const_t<Get>>()..., parent.template storage<std::remove_const_t<Exclude>>()...};
stl::conditional_t<((stl::is_const_v<Get> && ...) && (stl::is_const_v<Exclude> && ...)), const owner_type, owner_type> &parent = owner_or_assert();
return {*this, parent.template storage<stl::remove_const_t<Get>>()..., parent.template storage<stl::remove_const_t<Exclude>>()...};
}
/*! @brief Releases all connections to the underlying registry, if any. */

View File

@@ -1,50 +1,50 @@
#ifndef ENTT_ENTITY_ORGANIZER_HPP
#define ENTT_ENTITY_ORGANIZER_HPP
#include <cstddef>
#include <type_traits>
#include <utility>
#include <vector>
#include "../core/type_info.hpp"
#include "../core/type_traits.hpp"
#include "../core/utility.hpp"
#include "../graph/adjacency_matrix.hpp"
#include "../graph/flow.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "../stl/vector.hpp"
#include "fwd.hpp"
#include "helper.hpp"
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
template<typename>
struct is_view: std::false_type {};
struct is_view: stl::false_type {};
template<typename... Args>
struct is_view<basic_view<Args...>>: std::true_type {};
struct is_view<basic_view<Args...>>: stl::true_type {};
template<typename Type>
inline constexpr bool is_view_v = is_view<Type>::value;
template<typename>
struct is_group: std::false_type {};
struct is_group: stl::false_type {};
template<typename... Args>
struct is_group<basic_group<Args...>>: std::true_type {};
struct is_group<basic_group<Args...>>: stl::true_type {};
template<typename Type>
inline constexpr bool is_group_v = is_group<Type>::value;
template<typename Type, typename Override>
struct unpack_type {
using ro = std::conditional_t<
type_list_contains_v<Override, const Type> || (std::is_const_v<Type> && !type_list_contains_v<Override, std::remove_const_t<Type>>),
type_list<std::remove_const_t<Type>>,
using ro = stl::conditional_t<
type_list_contains_v<Override, const Type> || (stl::is_const_v<Type> && !type_list_contains_v<Override, stl::remove_const_t<Type>>),
type_list<stl::remove_const_t<Type>>,
type_list<>>;
using rw = std::conditional_t<
type_list_contains_v<Override, std::remove_const_t<Type>> || (!std::is_const_v<Type> && !type_list_contains_v<Override, const Type>),
using rw = stl::conditional_t<
type_list_contains_v<Override, stl::remove_const_t<Type>> || (!stl::is_const_v<Type> && !type_list_contains_v<Override, const Type>),
type_list<Type>,
type_list<>>;
};
@@ -84,23 +84,23 @@ struct resource_traits;
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 args = type_list<stl::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> || ...);
static constexpr auto sync_point = (stl::is_same_v<Args, Registry> || ...);
};
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...));
resource_traits<Registry, type_list<stl::remove_reference_t<Args>...>, type_list<Req...>> free_function_to_resource_traits(Ret (*)(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...));
resource_traits<Registry, type_list<stl::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource_traits(Ret (*)(Type &, 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...));
resource_traits<Registry, type_list<stl::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...) const);
resource_traits<Registry, type_list<stl::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource_traits(Ret (Class::*)(Args...) const);
} // namespace internal
/*! @endcond */
@@ -120,11 +120,11 @@ template<typename Registry>
class basic_organizer final {
using callback_type = void(const void *, Registry &);
using prepare_type = void(Registry &);
using dependency_type = std::size_t(const bool, const type_info **, const std::size_t);
using dependency_type = stl::size_t(const bool, const type_info **, const stl::size_t);
struct vertex_data final {
std::size_t ro_count{};
std::size_t rw_count{};
stl::size_t ro_count{};
stl::size_t rw_count{};
const char *name{};
const void *payload{};
callback_type *callback{};
@@ -135,24 +135,24 @@ class basic_organizer final {
template<typename Type>
[[nodiscard]] static decltype(auto) extract(Registry &reg) {
if constexpr(std::is_same_v<Type, Registry>) {
if constexpr(stl::is_same_v<Type, Registry>) {
return reg;
} else if constexpr(internal::is_view_v<Type>) {
return static_cast<Type>(as_view{reg});
} else if constexpr(internal::is_group_v<Type>) {
return static_cast<Type>(as_group{reg});
} else {
return reg.ctx().template emplace<std::remove_reference_t<Type>>();
return reg.ctx().template emplace<stl::remove_reference_t<Type>>();
}
}
template<typename... Args>
[[nodiscard]] static auto to_args(Registry &reg, type_list<Args...>) {
return std::tuple<decltype(extract<Args>(reg))...>(extract<Args>(reg)...);
return stl::tuple<decltype(extract<Args>(reg))...>(extract<Args>(reg)...);
}
template<typename... Type>
[[nodiscard]] static std::size_t fill_dependencies(type_list<Type...>, [[maybe_unused]] const type_info **buffer, [[maybe_unused]] const std::size_t count) {
[[nodiscard]] static stl::size_t fill_dependencies(type_list<Type...>, [[maybe_unused]] const type_info **buffer, [[maybe_unused]] const stl::size_t count) {
if constexpr(sizeof...(Type) == 0u) {
return {};
} else {
@@ -160,7 +160,7 @@ class basic_organizer final {
const type_info *info[]{&type_id<Type>()...};
const auto length = count < sizeof...(Type) ? count : sizeof...(Type);
for(std::size_t pos{}; pos < length; ++pos) {
for(stl::size_t pos{}; pos < length; ++pos) {
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
buffer[pos] = info[pos];
}
@@ -170,7 +170,7 @@ class basic_organizer final {
}
template<typename... RO, typename... RW>
void track_dependencies(std::size_t index, const bool sync_point, type_list<RO...>, type_list<RW...>) {
void track_dependencies(stl::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(), sync_point || (sizeof...(RO) + sizeof...(RW) == 0u));
(builder.ro(type_hash<RO>::value()), ...);
@@ -181,9 +181,9 @@ public:
/*! Basic registry type. */
using registry_type = Registry;
/*! @brief Underlying entity identifier. */
using entity_type = typename registry_type::entity_type;
using entity_type = registry_type::entity_type;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
using size_type = stl::size_t;
/*! @brief Raw task function type. */
using function_type = callback_type;
@@ -195,10 +195,10 @@ public:
* @param from List of in-edges of the vertex.
* @param to List of out-edges of the vertex.
*/
vertex(vertex_data data, std::vector<std::size_t> from, std::vector<std::size_t> to)
: node{std::move(data)},
in{std::move(from)},
out{std::move(to)} {}
vertex(vertex_data data, stl::vector<stl::size_t> from, stl::vector<stl::size_t> to)
: node{stl::move(data)},
in{stl::move(from)},
out{stl::move(to)} {}
/**
* @brief Fills a buffer with the type info objects for the writable
@@ -207,7 +207,7 @@ public:
* @param length The length of the user-supplied buffer.
* @return The number of type info objects written to the buffer.
*/
[[nodiscard]] size_type ro_dependency(const type_info **buffer, const std::size_t length) const noexcept {
[[nodiscard]] size_type ro_dependency(const type_info **buffer, const stl::size_t length) const noexcept {
return node.dependency(false, buffer, length);
}
@@ -218,7 +218,7 @@ public:
* @param length The length of the user-supplied buffer.
* @return The number of type info objects written to the buffer.
*/
[[nodiscard]] size_type rw_dependency(const type_info **buffer, const std::size_t length) const noexcept {
[[nodiscard]] size_type rw_dependency(const type_info **buffer, const stl::size_t length) const noexcept {
return node.dependency(true, buffer, length);
}
@@ -282,7 +282,7 @@ public:
* @brief Returns the list of in-edges of a vertex.
* @return The list of in-edges of a vertex.
*/
[[nodiscard]] const std::vector<std::size_t> &in_edges() const noexcept {
[[nodiscard]] const stl::vector<stl::size_t> &in_edges() const noexcept {
return in;
}
@@ -290,7 +290,7 @@ public:
* @brief Returns the list of out-edges of a vertex.
* @return The list of out-edges of a vertex.
*/
[[nodiscard]] const std::vector<std::size_t> &out_edges() const noexcept {
[[nodiscard]] const stl::vector<stl::size_t> &out_edges() const noexcept {
return out;
}
@@ -305,8 +305,8 @@ public:
private:
vertex_data node;
std::vector<std::size_t> in;
std::vector<std::size_t> out;
stl::vector<stl::size_t> in;
stl::vector<stl::size_t> out;
};
/**
@@ -320,7 +320,7 @@ public:
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{}));
stl::apply(Candidate, to_args(reg, typename resource_type::args{}));
};
vertex_data vdata{
@@ -329,12 +329,12 @@ public:
name,
nullptr,
callback,
+[](const bool rw, const type_info **buffer, const std::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); },
+[](const bool rw, const type_info **buffer, const stl::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); },
+[](registry_type &reg) { void(to_args(reg, typename resource_type::args{})); },
&type_id<std::integral_constant<decltype(Candidate), Candidate>>()};
&type_id<stl::integral_constant<decltype(Candidate), Candidate>>()};
track_dependencies(vertices.size(), resource_type::sync_point, typename resource_type::ro{}, typename resource_type::rw{});
vertices.push_back(std::move(vdata));
vertices.push_back(stl::move(vdata));
}
/**
@@ -352,7 +352,7 @@ public:
callback_type *callback = +[](const void *payload, registry_type &reg) {
Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
std::apply(Candidate, std::tuple_cat(std::forward_as_tuple(*curr), to_args(reg, typename resource_type::args{})));
stl::apply(Candidate, stl::tuple_cat(stl::forward_as_tuple(*curr), to_args(reg, typename resource_type::args{})));
};
vertex_data vdata{
@@ -361,12 +361,12 @@ public:
name,
&value_or_instance,
callback,
+[](const bool rw, const type_info **buffer, const std::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); },
+[](const bool rw, const type_info **buffer, const stl::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); },
+[](registry_type &reg) { void(to_args(reg, typename resource_type::args{})); },
&type_id<std::integral_constant<decltype(Candidate), Candidate>>()};
&type_id<stl::integral_constant<decltype(Candidate), Candidate>>()};
track_dependencies(vertices.size(), resource_type::sync_point, typename resource_type::ro{}, typename resource_type::rw{});
vertices.push_back(std::move(vdata));
vertices.push_back(stl::move(vdata));
}
/**
@@ -388,25 +388,24 @@ public:
name,
payload,
func,
+[](const bool rw, const type_info **buffer, const std::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); },
+[](const bool rw, const type_info **buffer, const stl::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); },
nullptr,
&type_id<void>()};
vertices.push_back(std::move(vdata));
vertices.push_back(stl::move(vdata));
}
/**
* @brief Generates a task graph for the current content.
* @return The adjacency list of the task graph.
*/
[[nodiscard]] std::vector<vertex> graph() const {
std::vector<vertex> adjacency_list{};
[[nodiscard]] stl::vector<vertex> graph() const {
stl::vector<vertex> adjacency_list{};
adjacency_list.reserve(vertices.size());
auto adjacency_matrix = builder.graph();
for(auto curr: adjacency_matrix.vertices()) {
std::vector<std::size_t> in{};
std::vector<std::size_t> out{};
for(auto adjacency_matrix = builder.graph(); auto curr: adjacency_matrix.vertices()) {
stl::vector<stl::size_t> in{};
stl::vector<stl::size_t> out{};
for(auto &&edge: adjacency_matrix.in_edges(curr)) {
in.push_back(edge.first);
@@ -416,7 +415,7 @@ public:
out.push_back(edge.second);
}
adjacency_list.emplace_back(vertices[curr], std::move(in), std::move(out));
adjacency_list.emplace_back(vertices[curr], stl::move(in), stl::move(out));
}
return adjacency_list;
@@ -429,7 +428,7 @@ public:
}
private:
std::vector<vertex_data> vertices;
stl::vector<vertex_data> vertices;
flow builder;
};

View File

@@ -1,26 +1,28 @@
#ifndef ENTT_ENTITY_RANGES_HPP
#define ENTT_ENTITY_RANGES_HPP
#if __has_include(<version>)
# include <version>
#
# if defined(__cpp_lib_ranges)
# include <ranges>
# include "fwd.hpp"
#include <version>
#if defined(__cpp_lib_ranges)
# include <ranges>
# include "fwd.hpp"
namespace std::ranges {
template<class... Args>
inline constexpr bool std::ranges::enable_borrowed_range<entt::basic_view<Args...>>{true};
inline constexpr bool enable_borrowed_range<entt::basic_view<Args...>>{true};
template<class... Args>
inline constexpr bool std::ranges::enable_borrowed_range<entt::basic_group<Args...>>{true};
inline constexpr bool enable_borrowed_range<entt::basic_group<Args...>>{true};
template<class... Args>
inline constexpr bool std::ranges::enable_view<entt::basic_view<Args...>>{true};
inline constexpr bool enable_view<entt::basic_view<Args...>>{true};
template<class... Args>
inline constexpr bool std::ranges::enable_view<entt::basic_group<Args...>>{true};
inline constexpr bool enable_view<entt::basic_group<Args...>>{true};
} // namespace std::ranges
# endif
#endif
#endif
#endif

View File

@@ -1,26 +1,27 @@
#ifndef ENTT_ENTITY_REGISTRY_HPP
#define ENTT_ENTITY_REGISTRY_HPP
#include <algorithm>
#include <array>
#include <cstddef>
#include <functional>
#include <iterator>
#include <memory>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
#include <compare>
#include "../config/config.h"
#include "../container/dense_map.hpp"
#include "../core/algorithm.hpp"
#include "../core/any.hpp"
#include "../core/concepts.hpp"
#include "../core/fwd.hpp"
#include "../core/iterator.hpp"
#include "../core/memory.hpp"
#include "../core/type_info.hpp"
#include "../core/type_traits.hpp"
#include "../core/utility.hpp"
#include "../stl/algorithm.hpp"
#include "../stl/array.hpp"
#include "../stl/concepts.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/functional.hpp"
#include "../stl/iterator.hpp"
#include "../stl/memory.hpp"
#include "../stl/tuple.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "entity.hpp"
#include "fwd.hpp"
#include "group.hpp"
@@ -31,23 +32,23 @@
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
template<typename It>
class registry_storage_iterator final {
template<typename Other>
template<typename>
friend class registry_storage_iterator;
using mapped_type = std::remove_reference_t<decltype(std::declval<It>()->second)>;
using mapped_type = stl::remove_reference_t<decltype(stl::declval<It>()->second)>;
public:
using value_type = std::pair<id_type, constness_as_t<typename mapped_type::element_type, mapped_type> &>;
using value_type = stl::pair<id_type, constness_as_t<typename mapped_type::element_type, mapped_type> &>;
using pointer = input_iterator_pointer<value_type>;
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category = std::input_iterator_tag;
using iterator_concept = std::random_access_iterator_tag;
using difference_type = stl::ptrdiff_t;
using iterator_category = stl::input_iterator_tag;
using iterator_concept = stl::random_access_iterator_tag;
constexpr registry_storage_iterator() noexcept
: it{} {}
@@ -55,7 +56,8 @@ public:
constexpr registry_storage_iterator(It iter) noexcept
: it{iter} {}
template<typename Other, typename = std::enable_if_t<!std::is_same_v<It, Other> && std::is_constructible_v<It, Other>>>
template<typename Other>
requires (!stl::same_as<It, Other> && stl::constructible_from<It, Other>)
constexpr registry_storage_iterator(const registry_storage_iterator<Other> &other) noexcept
: registry_storage_iterator{other.it} {}
@@ -107,58 +109,29 @@ public:
return operator*();
}
template<typename Lhs, typename Rhs>
friend constexpr std::ptrdiff_t operator-(const registry_storage_iterator<Lhs> &, const registry_storage_iterator<Rhs> &) noexcept;
template<typename Other>
[[nodiscard]] constexpr stl::ptrdiff_t operator-(const registry_storage_iterator<Other> &other) const noexcept {
return it - other.it;
}
template<typename Lhs, typename Rhs>
friend constexpr bool operator==(const registry_storage_iterator<Lhs> &, const registry_storage_iterator<Rhs> &) noexcept;
template<typename Other>
[[nodiscard]] constexpr bool operator==(const registry_storage_iterator<Other> &other) const noexcept {
return it == other.it;
}
template<typename Lhs, typename Rhs>
friend constexpr bool operator<(const registry_storage_iterator<Lhs> &, const registry_storage_iterator<Rhs> &) noexcept;
template<typename Other>
[[nodiscard]] constexpr auto operator<=>(const registry_storage_iterator<Other> &other) const noexcept {
return it <=> other.it;
}
private:
It it;
};
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr std::ptrdiff_t operator-(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
return lhs.it - rhs.it;
}
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr bool operator==(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
return lhs.it == rhs.it;
}
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr bool operator!=(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
return !(lhs == rhs);
}
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr bool operator<(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
return lhs.it < rhs.it;
}
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr bool operator>(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
return rhs < lhs;
}
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr bool operator<=(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
return !(lhs > rhs);
}
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr bool operator>=(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
return !(lhs < rhs);
}
template<typename Allocator>
class registry_context {
using alloc_traits = std::allocator_traits<Allocator>;
using allocator_type = typename alloc_traits::template rebind_alloc<std::pair<const id_type, basic_any<0u>>>;
using alloc_traits = stl::allocator_traits<Allocator>;
using allocator_type = alloc_traits::template rebind_alloc<stl::pair<const id_type, basic_any<0u>>>;
public:
explicit registry_context(const allocator_type &allocator)
@@ -170,22 +143,22 @@ public:
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);
return any_cast<Type &>(ctx.try_emplace(id, stl::in_place_type<Type>, stl::forward<Args>(args)...).first->second);
}
template<typename Type, typename... Args>
Type &emplace(Args &&...args) {
return emplace_as<Type>(type_id<Type>().hash(), std::forward<Args>(args)...);
return emplace_as<Type>(type_id<Type>().hash(), stl::forward<Args>(args)...);
}
template<typename Type>
Type &insert_or_assign(const id_type id, Type &&value) {
return any_cast<std::remove_const_t<std::remove_reference_t<Type>> &>(ctx.insert_or_assign(id, std::forward<Type>(value)).first->second);
return any_cast<stl::remove_cvref_t<Type> &>(ctx.insert_or_assign(id, stl::forward<Type>(value)).first->second);
}
template<typename Type>
Type &insert_or_assign(Type &&value) {
return insert_or_assign(type_id<Type>().hash(), std::forward<Type>(value));
return insert_or_assign(type_id<Type>().hash(), stl::forward<Type>(value));
}
template<typename Type>
@@ -223,7 +196,7 @@ public:
}
private:
dense_map<id_type, basic_any<0u>, identity, std::equal_to<>, allocator_type> ctx;
dense_map<id_type, basic_any<0u>, stl::identity, stl::equal_to<>, allocator_type> ctx;
};
} // namespace internal
@@ -237,18 +210,16 @@ private:
template<typename Entity, typename Allocator>
class basic_registry {
using base_type = basic_sparse_set<Entity, Allocator>;
using alloc_traits = std::allocator_traits<Allocator>;
static_assert(std::is_same_v<typename alloc_traits::value_type, Entity>, "Invalid value type");
// std::shared_ptr because of its type erased allocator which is useful here
using pool_container_type = dense_map<id_type, std::shared_ptr<base_type>, identity, std::equal_to<>, typename alloc_traits::template rebind_alloc<std::pair<const id_type, std::shared_ptr<base_type>>>>;
using group_container_type = dense_map<id_type, std::shared_ptr<internal::group_descriptor>, identity, std::equal_to<>, typename alloc_traits::template rebind_alloc<std::pair<const id_type, std::shared_ptr<internal::group_descriptor>>>>;
using alloc_traits = stl::allocator_traits<Allocator>;
static_assert(stl::is_same_v<typename alloc_traits::value_type, Entity>, "Invalid value type");
// stl::shared_ptr because of its type erased allocator which is useful here
using pool_container_type = dense_map<id_type, stl::shared_ptr<base_type>, stl::identity, stl::equal_to<>, typename alloc_traits::template rebind_alloc<stl::pair<const id_type, stl::shared_ptr<base_type>>>>;
using group_container_type = dense_map<id_type, stl::shared_ptr<internal::group_descriptor>, stl::identity, stl::equal_to<>, typename alloc_traits::template rebind_alloc<stl::pair<const id_type, stl::shared_ptr<internal::group_descriptor>>>>;
using traits_type = entt_traits<Entity>;
template<typename Type>
template<cvref_unqualified Type>
[[nodiscard]] auto &assure([[maybe_unused]] const id_type id = type_hash<Type>::value()) {
static_assert(std::is_same_v<Type, std::decay_t<Type>>, "Non-decayed types not allowed");
if constexpr(std::is_same_v<Type, entity_type>) {
if constexpr(stl::is_same_v<Type, entity_type>) {
ENTT_ASSERT(id == type_hash<Type>::value(), "User entity storage not allowed");
return entities;
} else {
@@ -259,16 +230,7 @@ class basic_registry {
return static_cast<storage_type &>(*it->second);
}
using alloc_type = typename storage_type::allocator_type;
typename pool_container_type::mapped_type cpool{};
if constexpr(std::is_void_v<Type> && !std::is_constructible_v<alloc_type, allocator_type>) {
// std::allocator<void> has no cross constructors (waiting for C++20)
cpool = std::allocate_shared<storage_type>(get_allocator(), alloc_type{});
} else {
cpool = std::allocate_shared<storage_type>(get_allocator(), get_allocator());
}
typename pool_container_type::mapped_type cpool = stl::allocate_shared<storage_type>(get_allocator(), get_allocator());
pools.emplace(id, cpool);
cpool->bind(*this);
@@ -276,11 +238,9 @@ class basic_registry {
}
}
template<typename Type>
template<cvref_unqualified Type>
[[nodiscard]] const auto *assure([[maybe_unused]] const id_type id = type_hash<Type>::value()) const {
static_assert(std::is_same_v<Type, std::decay_t<Type>>, "Non-decayed types not allowed");
if constexpr(std::is_same_v<Type, entity_type>) {
if constexpr(stl::is_same_v<Type, entity_type>) {
ENTT_ASSERT(id == type_hash<Type>::value(), "User entity storage not allowed");
return &entities;
} else {
@@ -305,11 +265,11 @@ public:
/*! @brief Allocator type. */
using allocator_type = Allocator;
/*! @brief Underlying entity identifier. */
using entity_type = typename traits_type::value_type;
using entity_type = traits_type::value_type;
/*! @brief Underlying version type. */
using version_type = typename traits_type::version_type;
using version_type = traits_type::version_type;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
using size_type = stl::size_t;
/*! @brief Common type among all storage types. */
using common_type = base_type;
/*! @brief Context type. */
@@ -324,7 +284,7 @@ public:
* @tparam Type Storage value type, eventually const.
*/
template<typename Type>
using storage_for_type = typename storage_for<Type, Entity, typename alloc_traits::template rebind_alloc<std::remove_const_t<Type>>>::type;
using storage_for_type = storage_for<Type, Entity, typename alloc_traits::template rebind_alloc<stl::remove_const_t<Type>>>::type;
/*! @brief Default constructor. */
basic_registry()
@@ -359,10 +319,10 @@ public:
* @param other The instance to move from.
*/
basic_registry(basic_registry &&other) noexcept
: vars{std::move(other.vars)},
pools{std::move(other.pools)},
groups{std::move(other.groups)},
entities{std::move(other.entities)} {
: vars{stl::move(other.vars)},
pools{stl::move(other.pools)},
groups{stl::move(other.groups)},
entities{stl::move(other.entities)} {
rebind();
}
@@ -390,7 +350,7 @@ public:
* @param other Registry to exchange the content with.
*/
void swap(basic_registry &other) noexcept {
using std::swap;
using stl::swap;
swap(vars, other.vars);
swap(pools, other.pools);
@@ -432,7 +392,7 @@ public:
* @return A pointer to the storage if it exists, a null pointer otherwise.
*/
[[nodiscard]] common_type *storage(const id_type id) {
return const_cast<common_type *>(std::as_const(*this).storage(id));
return const_cast<common_type *>(stl::as_const(*this).storage(id));
}
/**
@@ -453,7 +413,7 @@ public:
*/
template<typename Type>
storage_for_type<Type> &storage(const id_type id = type_hash<Type>::value()) {
return assure<std::remove_const_t<Type>>(id);
return assure<stl::remove_const_t<Type>>(id);
}
/**
@@ -464,7 +424,7 @@ public:
*/
template<typename Type>
[[nodiscard]] const storage_for_type<Type> *storage(const id_type id = type_hash<Type>::value()) const {
return assure<std::remove_const_t<Type>>(id);
return assure<stl::remove_const_t<Type>>(id);
}
/**
@@ -522,13 +482,13 @@ public:
*
* @sa create
*
* @tparam It Type of forward iterator.
* @tparam It Type of output 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>
template<stl::output_iterator<entity_type> It>
void create(It first, It last) {
entities.generate(std::move(first), std::move(last));
entities.generate(stl::move(first), stl::move(last));
}
/**
@@ -543,7 +503,7 @@ public:
*/
version_type destroy(const entity_type entt) {
for(size_type pos = pools.size(); pos != 0u; --pos) {
pools.begin()[static_cast<typename pool_container_type::difference_type>(pos - 1u)].second->remove(entt);
pools.begin()[static_cast<pool_container_type::difference_type>(pos - 1u)].second->remove(entt);
}
entities.erase(entt);
@@ -573,14 +533,12 @@ public:
*
* @sa destroy
*
* @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 It>
void destroy(It first, It last) {
void destroy(stl::input_iterator auto first, stl::input_iterator auto last) {
const auto to = entities.sort_as(first, last);
const auto from = entities.cend() - static_cast<typename common_type::difference_type>(entities.free_list());
const auto from = entities.cend() - static_cast<common_type::difference_type>(entities.free_list());
for(auto &&curr: pools) {
curr.second->remove(from, to);
@@ -607,7 +565,7 @@ public:
template<typename Type, typename... Args>
decltype(auto) emplace(const entity_type entt, Args &&...args) {
ENTT_ASSERT(valid(entt), "Invalid entity");
return assure<Type>().emplace(entt, std::forward<Args>(args)...);
return assure<Type>().emplace(entt, stl::forward<Args>(args)...);
}
/**
@@ -616,31 +574,14 @@ public:
* @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.
*
* @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.
* @param value An instance of the element to assign.
*/
template<typename Type, typename It>
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);
template<typename Type>
void insert(stl::input_iterator auto first, stl::input_iterator auto last, const Type &value = {}) {
ENTT_ASSERT(stl::all_of(first, last, [this](const auto entt) { return valid(entt); }), "Invalid entity");
assure<Type>().insert(stl::move(first), stl::move(last), value);
}
/**
@@ -655,9 +596,10 @@ public:
* @param last An iterator past the last element of the range of entities.
* @param from An iterator to the first element of the range of elements.
*/
template<typename Type, typename EIt, typename CIt, typename = std::enable_if_t<std::is_same_v<typename std::iterator_traits<CIt>::value_type, Type>>>
template<typename Type, typename EIt, typename CIt>
requires stl::same_as<typename stl::iterator_traits<CIt>::value_type, Type>
void insert(EIt first, EIt last, CIt from) {
ENTT_ASSERT(std::all_of(first, last, [this](const auto entt) { return valid(entt); }), "Invalid entity");
ENTT_ASSERT(stl::all_of(first, last, [this](const auto entt) { return valid(entt); }), "Invalid entity");
assure<Type>().insert(first, last, from);
}
@@ -677,7 +619,7 @@ public:
decltype(auto) emplace_or_replace(const entity_type entt, Args &&...args) {
auto &cpool = assure<Type>();
ENTT_ASSERT(valid(entt), "Invalid entity");
return cpool.contains(entt) ? cpool.patch(entt, [&args...](auto &...curr) { ((curr = Type{std::forward<Args>(args)...}), ...); }) : cpool.emplace(entt, std::forward<Args>(args)...);
return cpool.contains(entt) ? cpool.patch(entt, [&args...](auto &...curr) { ((curr = Type{stl::forward<Args>(args)...}), ...); }) : cpool.emplace(entt, stl::forward<Args>(args)...);
}
/**
@@ -701,7 +643,7 @@ public:
*/
template<typename Type, typename... Func>
decltype(auto) patch(const entity_type entt, Func &&...func) {
return assure<Type>().patch(entt, std::forward<Func>(func)...);
return assure<Type>().patch(entt, stl::forward<Func>(func)...);
}
/**
@@ -721,7 +663,7 @@ public:
*/
template<typename Type, typename... Args>
decltype(auto) replace(const entity_type entt, Args &&...args) {
return patch<Type>(entt, [&args...](auto &...curr) { ((curr = Type{std::forward<Args>(args)...}), ...); });
return patch<Type>(entt, [&args...](auto &...curr) { ((curr = Type{stl::forward<Args>(args)...}), ...); });
}
/**
@@ -748,17 +690,17 @@ public:
* @param last An iterator past the last element of the range of entities.
* @return The number of elements actually removed.
*/
template<typename Type, typename... Other, typename It>
template<typename Type, typename... Other, stl::input_iterator It>
size_type remove(It first, It last) {
size_type count{};
if constexpr(std::is_same_v<It, typename common_type::iterator>) {
std::array cpools{static_cast<common_type *>(&assure<Type>()), static_cast<common_type *>(&assure<Other>())...};
if constexpr(stl::is_same_v<It, typename common_type::iterator>) {
stl::array cpools{static_cast<common_type *>(&assure<Type>()), static_cast<common_type *>(&assure<Other>())...};
for(auto from = cpools.begin(), to = cpools.end(); from != to; ++from) {
if constexpr(sizeof...(Other) != 0u) {
if((*from)->data() == first.data()) {
std::swap((*from), cpools.back());
stl::swap((*from), cpools.back());
}
}
@@ -766,8 +708,8 @@ public:
}
} else {
for(auto cpools = std::forward_as_tuple(assure<Type>(), assure<Other>()...); first != last; ++first) {
count += std::apply([entt = *first](auto &...curr) { return (curr.remove(entt) + ... + 0u); }, cpools);
for(auto cpools = stl::forward_as_tuple(assure<Type>(), assure<Other>()...); first != last; ++first) {
count += stl::apply([entt = *first](auto &...curr) { return (curr.remove(entt) + ... + 0u); }, cpools);
}
}
@@ -801,23 +743,23 @@ public:
* @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... Other, typename It>
template<typename Type, typename... Other, stl::input_iterator It>
void erase(It first, It last) {
if constexpr(std::is_same_v<It, typename common_type::iterator>) {
std::array cpools{static_cast<common_type *>(&assure<Type>()), static_cast<common_type *>(&assure<Other>())...};
if constexpr(stl::is_same_v<It, typename common_type::iterator>) {
stl::array cpools{static_cast<common_type *>(&assure<Type>()), static_cast<common_type *>(&assure<Other>())...};
for(auto from = cpools.begin(), to = cpools.end(); from != to; ++from) {
if constexpr(sizeof...(Other) != 0u) {
if((*from)->data() == first.data()) {
std::swap(*from, cpools.back());
stl::swap(*from, cpools.back());
}
}
(*from)->erase(first, last);
}
} else {
for(auto cpools = std::forward_as_tuple(assure<Type>(), assure<Other>()...); first != last; ++first) {
std::apply([entt = *first](auto &...curr) { (curr.erase(entt), ...); }, cpools);
for(auto cpools = stl::forward_as_tuple(assure<Type>(), assure<Other>()...); first != last; ++first) {
stl::apply([entt = *first](auto &...curr) { (curr.erase(entt), ...); }, cpools);
}
}
}
@@ -840,7 +782,7 @@ public:
template<typename Func>
void erase_if(const entity_type entt, Func func) {
for(auto [id, cpool]: storage()) {
if(cpool.contains(entt) && func(id, std::as_const(cpool))) {
if(cpool.contains(entt) && func(id, stl::as_const(cpool))) {
cpool.erase(entt);
}
}
@@ -871,7 +813,7 @@ public:
template<typename... Type>
[[nodiscard]] bool all_of([[maybe_unused]] const entity_type entt) const {
if constexpr(sizeof...(Type) == 1u) {
auto *cpool = assure<std::remove_const_t<Type>...>();
auto *cpool = assure<stl::remove_const_t<Type>...>();
return cpool && cpool->contains(entt);
} else {
return (all_of<Type>(entt) && ...);
@@ -904,9 +846,9 @@ public:
template<typename... Type>
[[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entt) const {
if constexpr(sizeof...(Type) == 1u) {
return (assure<std::remove_const_t<Type>>()->get(entt), ...);
return (assure<stl::remove_const_t<Type>>()->get(entt), ...);
} else {
return std::forward_as_tuple(get<Type>(entt)...);
return stl::forward_as_tuple(get<Type>(entt)...);
}
}
@@ -914,9 +856,9 @@ public:
template<typename... Type>
[[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entt) {
if constexpr(sizeof...(Type) == 1u) {
return (static_cast<storage_for_type<Type> &>(assure<std::remove_const_t<Type>>()).get(entt), ...);
return (static_cast<storage_for_type<Type> &>(assure<stl::remove_const_t<Type>>()).get(entt), ...);
} else {
return std::forward_as_tuple(get<Type>(entt)...);
return stl::forward_as_tuple(get<Type>(entt)...);
}
}
@@ -939,7 +881,7 @@ public:
[[nodiscard]] decltype(auto) get_or_emplace(const entity_type entt, Args &&...args) {
auto &cpool = assure<Type>();
ENTT_ASSERT(valid(entt), "Invalid entity");
return cpool.contains(entt) ? cpool.get(entt) : cpool.emplace(entt, std::forward<Args>(args)...);
return cpool.contains(entt) ? cpool.get(entt) : cpool.emplace(entt, stl::forward<Args>(args)...);
}
/**
@@ -955,10 +897,10 @@ public:
template<typename... Type>
[[nodiscard]] auto try_get([[maybe_unused]] const entity_type entt) const {
if constexpr(sizeof...(Type) == 1u) {
const auto *cpool = assure<std::remove_const_t<Type>...>();
return (cpool && cpool->contains(entt)) ? std::addressof(cpool->get(entt)) : nullptr;
const auto *cpool = assure<stl::remove_const_t<Type>...>();
return (cpool && cpool->contains(entt)) ? stl::addressof(cpool->get(entt)) : nullptr;
} else {
return std::make_tuple(try_get<Type>(entt)...);
return stl::make_tuple(try_get<Type>(entt)...);
}
}
@@ -966,9 +908,9 @@ public:
template<typename... Type>
[[nodiscard]] auto try_get([[maybe_unused]] const entity_type entt) {
if constexpr(sizeof...(Type) == 1u) {
return (const_cast<Type *>(std::as_const(*this).template try_get<Type>(entt)), ...);
return (const_cast<Type *>(stl::as_const(*this).template try_get<Type>(entt)), ...);
} else {
return std::make_tuple(try_get<Type>(entt)...);
return stl::make_tuple(try_get<Type>(entt)...);
}
}
@@ -980,7 +922,7 @@ public:
void clear() {
if constexpr(sizeof...(Type) == 0u) {
for(size_type pos = pools.size(); pos; --pos) {
pools.begin()[static_cast<typename pool_container_type::difference_type>(pos - 1u)].second->clear();
pools.begin()[static_cast<pool_container_type::difference_type>(pos - 1u)].second->clear();
}
const auto elem = entities.each();
@@ -996,7 +938,7 @@ public:
* @return True if the entity has no elements assigned, false otherwise.
*/
[[nodiscard]] bool orphan(const entity_type entt) const {
return std::none_of(pools.cbegin(), pools.cend(), [entt](auto &&curr) { return curr.second->contains(entt); });
return stl::none_of(pools.cbegin(), pools.cend(), [entt](auto &&curr) { return curr.second->contains(entt); });
}
/**
@@ -1082,7 +1024,7 @@ public:
[[nodiscard]] basic_view<get_t<storage_for_type<const Type>, storage_for_type<const Other>...>, exclude_t<storage_for_type<const Exclude>...>>
view(exclude_t<Exclude...> = exclude_t{}) const {
basic_view<get_t<storage_for_type<const Type>, storage_for_type<const Other>...>, exclude_t<storage_for_type<const Exclude>...>> elem{};
[&elem](const auto *...curr) { ((curr ? elem.storage(*curr) : void()), ...); }(assure<std::remove_const_t<Exclude>>()..., assure<std::remove_const_t<Other>>()..., assure<std::remove_const_t<Type>>());
[&elem](const auto *...curr) { ((curr ? elem.storage(*curr) : void()), ...); }(assure<stl::remove_const_t<Exclude>>()..., assure<stl::remove_const_t<Other>>()..., assure<stl::remove_const_t<Type>>());
return elem;
}
@@ -1090,7 +1032,7 @@ public:
template<typename Type, typename... Other, typename... Exclude>
[[nodiscard]] basic_view<get_t<storage_for_type<Type>, storage_for_type<Other>...>, exclude_t<storage_for_type<Exclude>...>>
view(exclude_t<Exclude...> = exclude_t{}) {
return {assure<std::remove_const_t<Type>>(), assure<std::remove_const_t<Other>>()..., assure<std::remove_const_t<Exclude>>()...};
return {assure<stl::remove_const_t<Type>>(), assure<stl::remove_const_t<Other>>()..., assure<stl::remove_const_t<Exclude>>()...};
}
/**
@@ -1104,19 +1046,19 @@ public:
basic_group<owned_t<storage_for_type<Owned>...>, get_t<storage_for_type<Get>...>, exclude_t<storage_for_type<Exclude>...>>
group(get_t<Get...> = get_t{}, exclude_t<Exclude...> = exclude_t{}) {
using group_type = basic_group<owned_t<storage_for_type<Owned>...>, get_t<storage_for_type<Get>...>, exclude_t<storage_for_type<Exclude>...>>;
using handler_type = typename group_type::handler;
using handler_type = group_type::handler;
if(auto it = groups.find(group_type::group_id()); it != groups.cend()) {
return {*std::static_pointer_cast<handler_type>(it->second)};
return {*stl::static_pointer_cast<handler_type>(it->second)};
}
std::shared_ptr<handler_type> handler{};
stl::shared_ptr<handler_type> handler{};
if constexpr(sizeof...(Owned) == 0u) {
handler = std::allocate_shared<handler_type>(get_allocator(), get_allocator(), std::forward_as_tuple(assure<std::remove_const_t<Get>>()...), std::forward_as_tuple(assure<std::remove_const_t<Exclude>>()...));
handler = stl::allocate_shared<handler_type>(get_allocator(), get_allocator(), stl::forward_as_tuple(assure<stl::remove_const_t<Get>>()...), stl::forward_as_tuple(assure<stl::remove_const_t<Exclude>>()...));
} else {
handler = std::allocate_shared<handler_type>(get_allocator(), std::forward_as_tuple(assure<std::remove_const_t<Owned>>()..., assure<std::remove_const_t<Get>>()...), std::forward_as_tuple(assure<std::remove_const_t<Exclude>>()...));
ENTT_ASSERT(std::all_of(groups.cbegin(), groups.cend(), [](const auto &data) { return !(data.second->owned(type_id<Owned>().hash()) || ...); }), "Conflicting groups");
handler = stl::allocate_shared<handler_type>(get_allocator(), stl::forward_as_tuple(assure<stl::remove_const_t<Owned>>()..., assure<stl::remove_const_t<Get>>()...), stl::forward_as_tuple(assure<stl::remove_const_t<Exclude>>()...));
ENTT_ASSERT(stl::all_of(groups.cbegin(), groups.cend(), [](const auto &data) { return !(data.second->owned(type_id<Owned>().hash()) || ...); }), "Conflicting groups");
}
groups.emplace(group_type::group_id(), handler);
@@ -1128,10 +1070,10 @@ public:
[[nodiscard]] basic_group<owned_t<storage_for_type<const Owned>...>, get_t<storage_for_type<const Get>...>, exclude_t<storage_for_type<const Exclude>...>>
group_if_exists(get_t<Get...> = get_t{}, exclude_t<Exclude...> = exclude_t{}) const {
using group_type = basic_group<owned_t<storage_for_type<const Owned>...>, get_t<storage_for_type<const Get>...>, exclude_t<storage_for_type<const Exclude>...>>;
using handler_type = typename group_type::handler;
using handler_type = group_type::handler;
if(auto it = groups.find(group_type::group_id()); it != groups.cend()) {
return {*std::static_pointer_cast<handler_type>(it->second)};
return {*stl::static_pointer_cast<handler_type>(it->second)};
}
return {};
@@ -1145,7 +1087,7 @@ public:
*/
template<typename... Type>
[[nodiscard]] bool owned() const {
return std::any_of(groups.cbegin(), groups.cend(), [](auto &&data) { return (data.second->owned(type_id<Type>().hash()) || ...); });
return stl::any_of(groups.cbegin(), groups.cend(), [](auto &&data) { return (data.second->owned(type_id<Type>().hash()) || ...); });
}
/**
@@ -1186,11 +1128,11 @@ public:
ENTT_ASSERT(!owned<Type>(), "Cannot sort owned storage");
auto &cpool = assure<Type>();
if constexpr(std::is_invocable_v<Compare, decltype(cpool.get({})), decltype(cpool.get({}))>) {
auto comp = [&cpool, compare = std::move(compare)](const auto lhs, const auto rhs) { return compare(std::as_const(cpool.get(lhs)), std::as_const(cpool.get(rhs))); };
cpool.sort(std::move(comp), std::move(algo), std::forward<Args>(args)...);
if constexpr(stl::is_invocable_v<Compare, decltype(cpool.get({})), decltype(cpool.get({}))>) {
auto comp = [&cpool, compare = stl::move(compare)](const auto lhs, const auto rhs) { return compare(stl::as_const(cpool.get(lhs)), stl::as_const(cpool.get(rhs))); };
cpool.sort(stl::move(comp), stl::move(algo), stl::forward<Args>(args)...);
} else {
cpool.sort(std::move(compare), std::move(algo), std::forward<Args>(args)...);
cpool.sort(stl::move(compare), stl::move(algo), stl::forward<Args>(args)...);
}
}

View File

@@ -1,36 +1,36 @@
#ifndef ENTT_ENTITY_RUNTIME_VIEW_HPP
#define ENTT_ENTITY_RUNTIME_VIEW_HPP
#include <algorithm>
#include <cstddef>
#include <iterator>
#include <utility>
#include <vector>
#include "../stl/algorithm.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/iterator.hpp"
#include "../stl/utility.hpp"
#include "../stl/vector.hpp"
#include "entity.hpp"
#include "fwd.hpp"
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
template<typename Set>
class runtime_view_iterator final {
using iterator_type = typename Set::iterator;
using iterator_traits = std::iterator_traits<iterator_type>;
using iterator_type = Set::iterator;
using iterator_traits = stl::iterator_traits<iterator_type>;
[[nodiscard]] bool valid() const {
return (!tombstone_check || *it != tombstone)
&& std::all_of(++pools->begin(), pools->end(), [entt = *it](const auto *curr) { return curr->contains(entt); })
&& std::none_of(filter->cbegin(), filter->cend(), [entt = *it](const auto *curr) { return curr && curr->contains(entt); });
&& stl::all_of(++pools->begin(), pools->end(), [entt = *it](const auto *curr) { return curr->contains(entt); })
&& stl::none_of(filter->cbegin(), filter->cend(), [entt = *it](const auto *curr) { return curr && curr->contains(entt); });
}
public:
using value_type = typename iterator_traits::value_type;
using pointer = typename iterator_traits::pointer;
using reference = typename iterator_traits::reference;
using difference_type = typename iterator_traits::difference_type;
using iterator_category = std::bidirectional_iterator_tag;
using value_type = iterator_traits::value_type;
using pointer = iterator_traits::pointer;
using reference = iterator_traits::reference;
using difference_type = iterator_traits::difference_type;
using iterator_category = stl::bidirectional_iterator_tag;
constexpr runtime_view_iterator() noexcept
: pools{},
@@ -38,7 +38,7 @@ public:
it{},
tombstone_check{} {}
runtime_view_iterator(const std::vector<Set *> &cpools, iterator_type curr, const std::vector<Set *> &ignore) noexcept
runtime_view_iterator(const stl::vector<Set *> &cpools, iterator_type curr, const stl::vector<Set *> &ignore) noexcept
: pools{&cpools},
filter{&ignore},
it{curr},
@@ -82,13 +82,9 @@ public:
return it == other.it;
}
[[nodiscard]] constexpr bool operator!=(const runtime_view_iterator &other) const noexcept {
return !(*this == other);
}
private:
const std::vector<Set *> *pools;
const std::vector<Set *> *filter;
const stl::vector<Set *> *pools;
const stl::vector<Set *> *filter;
iterator_type it;
bool tombstone_check;
};
@@ -121,9 +117,9 @@ private:
*/
template<typename Type, typename Allocator>
class basic_runtime_view {
using alloc_traits = std::allocator_traits<Allocator>;
static_assert(std::is_same_v<typename alloc_traits::value_type, Type *>, "Invalid value type");
using container_type = std::vector<Type *, Allocator>;
using alloc_traits = stl::allocator_traits<Allocator>;
static_assert(stl::is_same_v<typename alloc_traits::value_type, Type *>, "Invalid value type");
using container_type = stl::vector<Type *, Allocator>;
[[nodiscard]] auto offset() const noexcept {
ENTT_ASSERT(!pools.empty(), "Invalid view");
@@ -135,11 +131,11 @@ public:
/*! @brief Allocator type. */
using allocator_type = Allocator;
/*! @brief Underlying entity identifier. */
using entity_type = typename Type::entity_type;
using entity_type = Type::entity_type;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
using size_type = stl::size_t;
/*! @brief Signed integer type. */
using difference_type = std::ptrdiff_t;
using difference_type = stl::ptrdiff_t;
/*! @brief Common type among all storage types. */
using common_type = Type;
/*! @brief Bidirectional iterator type. */
@@ -178,8 +174,8 @@ public:
* @param allocator The allocator to use.
*/
basic_runtime_view(basic_runtime_view &&other, const allocator_type &allocator)
: pools{std::move(other.pools), allocator},
filter{std::move(other.filter), allocator} {}
: pools{stl::move(other.pools), allocator},
filter{stl::move(other.filter), allocator} {}
/*! @brief Default destructor. */
~basic_runtime_view() = default;
@@ -201,7 +197,7 @@ public:
* @param other View to exchange the content with.
*/
void swap(basic_runtime_view &other) noexcept {
using std::swap;
using stl::swap;
swap(pools, other.pools);
swap(filter, other.filter);
}
@@ -229,7 +225,7 @@ public:
if(pools.empty() || !(base.size() < pools.front()->size())) {
pools.push_back(&base);
} else {
pools.push_back(std::exchange(pools.front(), &base));
pools.push_back(stl::exchange(pools.front(), &base));
}
return *this;
@@ -290,8 +286,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); })
&& stl::all_of(pools.cbegin(), pools.cend(), [entt](const auto *curr) { return curr->contains(entt); })
&& stl::none_of(filter.cbegin(), filter.cend(), [entt](const auto *curr) { return curr && curr->contains(entt); })
&& pools.front()->index(entt) < offset();
}

View File

@@ -1,29 +1,27 @@
#ifndef ENTT_ENTITY_SNAPSHOT_HPP
#define ENTT_ENTITY_SNAPSHOT_HPP
#include <cstddef>
#include <iterator>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
#include "../config/config.h"
#include "../container/dense_map.hpp"
#include "../core/type_traits.hpp"
#include "../stl/concepts.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/iterator.hpp"
#include "../stl/tuple.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "entity.hpp"
#include "fwd.hpp"
#include "view.hpp"
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
template<typename Registry>
void orphans(Registry &registry) {
auto &storage = registry.template storage<typename Registry::entity_type>();
for(auto entt: storage) {
for(auto &storage = registry.template storage<typename Registry::entity_type>(); auto entt: storage) {
if(registry.orphan(entt)) {
storage.erase(entt);
}
@@ -45,14 +43,14 @@ void orphans(Registry &registry) {
*/
template<typename Registry>
class basic_snapshot {
static_assert(!std::is_const_v<Registry>, "Non-const registry type required");
static_assert(!stl::is_const_v<Registry>, "Non-const registry type required");
using traits_type = entt_traits<typename Registry::entity_type>;
public:
/*! Basic registry type. */
using registry_type = Registry;
/*! @brief Underlying entity identifier. */
using entity_type = typename registry_type::entity_type;
using entity_type = registry_type::entity_type;
/**
* @brief Constructs an instance that is bound to a given registry.
@@ -95,10 +93,10 @@ public:
if(const auto *storage = reg->template storage<Type>(id); storage) {
const typename registry_type::common_type &base = *storage;
archive(static_cast<typename traits_type::entity_type>(storage->size()));
archive(static_cast<traits_type::entity_type>(storage->size()));
if constexpr(std::is_same_v<Type, entity_type>) {
archive(static_cast<typename traits_type::entity_type>(storage->free_list()));
if constexpr(stl::is_same_v<Type, entity_type>) {
archive(static_cast<traits_type::entity_type>(storage->free_list()));
for(auto first = base.rbegin(), last = base.rend(); first != last; ++first) {
archive(*first);
@@ -109,12 +107,12 @@ public:
archive(static_cast<entity_type>(null));
} else {
archive(entt);
std::apply([&archive](auto &&...args) { (archive(std::forward<decltype(args)>(args)), ...); }, storage->get_as_tuple(entt));
stl::apply([&archive](auto &&...args) { (archive(stl::forward<decltype(args)>(args)), ...); }, storage->get_as_tuple(entt));
}
}
} else {
for(auto elem: storage->reach()) {
std::apply([&archive](auto &&...args) { (archive(std::forward<decltype(args)>(args)), ...); }, elem);
stl::apply([&archive](auto &&...args) { (archive(stl::forward<decltype(args)>(args)), ...); }, elem);
}
}
} else {
@@ -129,24 +127,23 @@ public:
* the entities in a range.
* @tparam Type Type of elements to serialize.
* @tparam Archive Type of output archive.
* @tparam It Type of input iterator.
* @param archive A valid reference to an output archive.
* @param first An iterator to the first element of the range to serialize.
* @param last An iterator past the last element of the range to serialize.
* @param id Optional name used to map the storage within the registry.
* @return An object of this type to continue creating the snapshot.
*/
template<typename Type, typename Archive, typename It>
const basic_snapshot &get(Archive &archive, It first, It last, const id_type id = type_hash<Type>::value()) const {
static_assert(!std::is_same_v<Type, entity_type>, "Entity types not supported");
template<typename Type, typename Archive>
const basic_snapshot &get(Archive &archive, stl::input_iterator auto first, stl::input_iterator auto last, const id_type id = type_hash<Type>::value()) const {
static_assert(!stl::is_same_v<Type, entity_type>, "Entity types not supported");
if(const auto *storage = reg->template storage<Type>(id); storage && !storage->empty()) {
archive(static_cast<typename traits_type::entity_type>(std::distance(first, last)));
archive(static_cast<traits_type::entity_type>(stl::distance(first, last)));
for(; first != last; ++first) {
if(const auto entt = *first; storage->contains(entt)) {
archive(entt);
std::apply([&archive](auto &&...args) { (archive(std::forward<decltype(args)>(args)), ...); }, storage->get_as_tuple(entt));
stl::apply([&archive](auto &&...args) { (archive(stl::forward<decltype(args)>(args)), ...); }, storage->get_as_tuple(entt));
} else {
archive(static_cast<entity_type>(null));
}
@@ -174,14 +171,14 @@ private:
*/
template<typename Registry>
class basic_snapshot_loader {
static_assert(!std::is_const_v<Registry>, "Non-const registry type required");
static_assert(!stl::is_const_v<Registry>, "Non-const registry type required");
using traits_type = entt_traits<typename Registry::entity_type>;
public:
/*! Basic registry type. */
using registry_type = Registry;
/*! @brief Underlying entity identifier. */
using entity_type = typename registry_type::entity_type;
using entity_type = registry_type::entity_type;
/**
* @brief Constructs an instance that is bound to a given registry.
@@ -229,7 +226,7 @@ public:
archive(length);
if constexpr(std::is_same_v<Type, entity_type>) {
if constexpr(stl::is_same_v<Type, entity_type>) {
typename traits_type::entity_type count{};
entity_type placeholder{};
@@ -253,12 +250,12 @@ public:
const auto entity = other.contains(entt) ? entt : other.generate(entt);
ENTT_ASSERT(entity == entt, "Entity not available for use");
if constexpr(std::tuple_size_v<decltype(storage.get_as_tuple({}))> == 0u) {
if constexpr(stl::tuple_size_v<decltype(storage.get_as_tuple({}))> == 0u) {
storage.emplace(entity);
} else {
Type elem{};
archive(elem);
storage.emplace(entity, std::move(elem));
storage.emplace(entity, stl::move(elem));
}
}
}
@@ -304,16 +301,16 @@ private:
*/
template<typename Registry>
class basic_continuous_loader {
static_assert(!std::is_const_v<Registry>, "Non-const registry type required");
static_assert(!stl::is_const_v<Registry>, "Non-const registry type required");
using traits_type = entt_traits<typename Registry::entity_type>;
void restore(typename Registry::entity_type entt) {
void restore(Registry::entity_type entt) {
if(const auto entity = to_entity(entt); remloc.contains(entity) && remloc[entity].first == entt) {
if(!reg->valid(remloc[entity].second)) {
remloc[entity].second = reg->create();
}
} else {
remloc.insert_or_assign(entity, std::make_pair(entt, reg->create()));
remloc.insert_or_assign(entity, stl::make_pair(entt, reg->create()));
}
}
@@ -323,27 +320,27 @@ class basic_continuous_loader {
Container other;
for(auto &&pair: container) {
using first_type = std::remove_const_t<typename std::decay_t<decltype(pair)>::first_type>;
using second_type = typename std::decay_t<decltype(pair)>::second_type;
using first_type = stl::remove_const_t<typename stl::decay_t<decltype(pair)>::first_type>;
using second_type = stl::decay_t<decltype(pair)>::second_type;
if constexpr(std::is_same_v<first_type, entity_type> && std::is_same_v<second_type, entity_type>) {
if constexpr(stl::is_same_v<first_type, entity_type> && stl::is_same_v<second_type, entity_type>) {
other.emplace(map(pair.first), map(pair.second));
} else if constexpr(std::is_same_v<first_type, entity_type>) {
other.emplace(map(pair.first), std::move(pair.second));
} else if constexpr(stl::is_same_v<first_type, entity_type>) {
other.emplace(map(pair.first), stl::move(pair.second));
} else {
static_assert(std::is_same_v<second_type, entity_type>, "Neither the key nor the value are of entity type");
other.emplace(std::move(pair.first), map(pair.second));
static_assert(stl::is_same_v<second_type, entity_type>, "Neither the key nor the value are of entity type");
other.emplace(stl::move(pair.first), map(pair.second));
}
}
using std::swap;
using stl::swap;
swap(container, other);
}
template<typename Container>
auto update(char, Container &container) -> decltype(typename Container::value_type{}, void()) {
// vector like container
static_assert(std::is_same_v<typename Container::value_type, entity_type>, "Invalid value type");
static_assert(stl::is_same_v<typename Container::value_type, entity_type>, "Invalid value type");
for(auto &&entt: container) {
entt = map(entt);
@@ -352,9 +349,9 @@ class basic_continuous_loader {
template<typename Component, typename Other, typename Member>
void update([[maybe_unused]] Component &instance, [[maybe_unused]] Member Other::*member) {
if constexpr(!std::is_same_v<Component, Other>) {
if constexpr(!stl::is_same_v<Component, Other>) {
return;
} else if constexpr(std::is_same_v<Member, entity_type>) {
} else if constexpr(stl::is_same_v<Member, entity_type>) {
instance.*member = map(instance.*member);
} else {
// maybe a container? let's try...
@@ -366,7 +363,7 @@ public:
/*! Basic registry type. */
using registry_type = Registry;
/*! @brief Underlying entity identifier. */
using entity_type = typename registry_type::entity_type;
using entity_type = registry_type::entity_type;
/**
* @brief Constructs an instance that is bound to a given registry.
@@ -419,18 +416,18 @@ public:
archive(length);
if constexpr(std::is_same_v<Type, entity_type>) {
if constexpr(stl::is_same_v<Type, entity_type>) {
typename traits_type::entity_type in_use{};
storage.reserve(length);
archive(in_use);
for(std::size_t pos{}; pos < in_use; ++pos) {
for(stl::size_t pos{}; pos < in_use; ++pos) {
archive(entt);
restore(entt);
}
for(std::size_t pos = in_use; pos < length; ++pos) {
for(stl::size_t pos = in_use; pos < length; ++pos) {
archive(entt);
if(const auto entity = to_entity(entt); remloc.contains(entity)) {
@@ -450,12 +447,12 @@ public:
if(archive(entt); entt != null) {
restore(entt);
if constexpr(std::tuple_size_v<decltype(storage.get_as_tuple({}))> == 0u) {
if constexpr(stl::tuple_size_v<decltype(storage.get_as_tuple({}))> == 0u) {
storage.emplace(map(entt));
} else {
Type elem{};
archive(elem);
storage.emplace(map(entt), std::move(elem));
storage.emplace(map(entt), stl::move(elem));
}
}
}
@@ -503,7 +500,7 @@ public:
}
private:
dense_map<typename traits_type::entity_type, std::pair<entity_type, entity_type>> remloc;
dense_map<typename traits_type::entity_type, stl::pair<entity_type, entity_type>> remloc;
registry_type *reg;
};

View File

@@ -1,32 +1,34 @@
#ifndef ENTT_ENTITY_SPARSE_SET_HPP
#define ENTT_ENTITY_SPARSE_SET_HPP
#include <cstddef>
#include <iterator>
#include <memory>
#include <type_traits>
#include <utility>
#include <vector>
#include <compare>
#include "../config/config.h"
#include "../core/algorithm.hpp"
#include "../core/any.hpp"
#include "../core/bit.hpp"
#include "../core/type_info.hpp"
#include "../stl/concepts.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/iterator.hpp"
#include "../stl/memory.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "../stl/vector.hpp"
#include "entity.hpp"
#include "fwd.hpp"
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
template<typename Container>
struct sparse_set_iterator final {
using value_type = typename Container::value_type;
using pointer = typename Container::const_pointer;
using reference = typename Container::const_reference;
using difference_type = typename Container::difference_type;
using iterator_category = std::random_access_iterator_tag;
using value_type = Container::value_type;
using pointer = Container::const_pointer;
using reference = Container::const_reference;
using difference_type = Container::difference_type;
using iterator_category = stl::random_access_iterator_tag;
constexpr sparse_set_iterator() noexcept
: packed{},
@@ -73,17 +75,31 @@ struct sparse_set_iterator final {
}
[[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept {
return (*packed)[static_cast<typename Container::size_type>(index() - value)];
return (*packed)[static_cast<Container::size_type>(index() - value)];
}
[[nodiscard]] constexpr pointer operator->() const noexcept {
return std::addressof(operator[](0));
return stl::addressof(operator[](0));
}
[[nodiscard]] constexpr reference operator*() const noexcept {
return operator[](0);
}
[[nodiscard]] constexpr stl::ptrdiff_t operator-(const sparse_set_iterator &other) const noexcept {
// intentionally reversed due to backward iteration
return other.offset - offset;
}
[[nodiscard]] constexpr bool operator==(const sparse_set_iterator &other) const noexcept {
return offset == other.offset;
}
[[nodiscard]] constexpr auto operator<=>(const sparse_set_iterator &other) const noexcept {
// intentionally reversed due to backward iteration
return other.offset <=> offset;
}
[[nodiscard]] constexpr pointer data() const noexcept {
return packed ? packed->data() : nullptr;
}
@@ -97,41 +113,6 @@ private:
difference_type offset;
};
template<typename Container>
[[nodiscard]] constexpr std::ptrdiff_t operator-(const sparse_set_iterator<Container> &lhs, const sparse_set_iterator<Container> &rhs) noexcept {
return rhs.index() - lhs.index();
}
template<typename Container>
[[nodiscard]] constexpr bool operator==(const sparse_set_iterator<Container> &lhs, const sparse_set_iterator<Container> &rhs) noexcept {
return lhs.index() == rhs.index();
}
template<typename Container>
[[nodiscard]] constexpr bool operator!=(const sparse_set_iterator<Container> &lhs, const sparse_set_iterator<Container> &rhs) noexcept {
return !(lhs == rhs);
}
template<typename Container>
[[nodiscard]] constexpr bool operator<(const sparse_set_iterator<Container> &lhs, const sparse_set_iterator<Container> &rhs) noexcept {
return lhs.index() > rhs.index();
}
template<typename Container>
[[nodiscard]] constexpr bool operator>(const sparse_set_iterator<Container> &lhs, const sparse_set_iterator<Container> &rhs) noexcept {
return rhs < lhs;
}
template<typename Container>
[[nodiscard]] constexpr bool operator<=(const sparse_set_iterator<Container> &lhs, const sparse_set_iterator<Container> &rhs) noexcept {
return !(lhs > rhs);
}
template<typename Container>
[[nodiscard]] constexpr bool operator>=(const sparse_set_iterator<Container> &lhs, const sparse_set_iterator<Container> &rhs) noexcept {
return !(lhs < rhs);
}
} // namespace internal
/*! @endcond */
@@ -156,24 +137,24 @@ template<typename Container>
*/
template<typename Entity, typename Allocator>
class basic_sparse_set {
using alloc_traits = std::allocator_traits<Allocator>;
static_assert(std::is_same_v<typename alloc_traits::value_type, Entity>, "Invalid value type");
using sparse_container_type = std::vector<typename alloc_traits::pointer, typename alloc_traits::template rebind_alloc<typename alloc_traits::pointer>>;
using packed_container_type = std::vector<Entity, Allocator>;
using alloc_traits = stl::allocator_traits<Allocator>;
static_assert(stl::is_same_v<typename alloc_traits::value_type, Entity>, "Invalid value type");
using sparse_container_type = stl::vector<typename alloc_traits::pointer, typename alloc_traits::template rebind_alloc<typename alloc_traits::pointer>>;
using packed_container_type = stl::vector<Entity, Allocator>;
using traits_type = entt_traits<Entity>;
static constexpr auto max_size = static_cast<std::size_t>(traits_type::to_entity(null));
static constexpr auto max_size = static_cast<stl::size_t>(traits_type::to_entity(null));
// it could be auto but gcc complains and emits a warning due to a false positive
[[nodiscard]] std::size_t policy_to_head() const noexcept {
return static_cast<size_type>(max_size * static_cast<std::remove_const_t<decltype(max_size)>>(mode != deletion_policy::swap_only));
[[nodiscard]] stl::size_t policy_to_head() const noexcept {
return static_cast<size_type>(max_size * static_cast<stl::remove_const_t<decltype(max_size)>>(mode != deletion_policy::swap_only));
}
[[nodiscard]] auto entity_to_pos(const Entity entt) const noexcept {
return static_cast<size_type>(traits_type::to_entity(entt));
}
[[nodiscard]] auto pos_to_page(const std::size_t pos) const noexcept {
[[nodiscard]] auto pos_to_page(const stl::size_t pos) const noexcept {
return static_cast<size_type>(pos / traits_type::page_size);
}
@@ -205,40 +186,38 @@ class basic_sparse_set {
constexpr entity_type init = null;
auto page_allocator{packed.get_allocator()};
sparse[page] = alloc_traits::allocate(page_allocator, traits_type::page_size);
std::uninitialized_fill(sparse[page], sparse[page] + traits_type::page_size, init);
stl::uninitialized_fill(sparse[page], sparse[page] + traits_type::page_size, init);
}
return sparse[page][fast_mod(pos, traits_type::page_size)];
}
void release_sparse_pages() {
auto page_allocator{packed.get_allocator()};
for(auto &&page: sparse) {
for(auto page_allocator{packed.get_allocator()}; auto &&page: sparse) {
if(page != nullptr) {
std::destroy(page, page + traits_type::page_size);
stl::destroy(page, page + traits_type::page_size);
alloc_traits::deallocate(page_allocator, page, traits_type::page_size);
page = nullptr;
}
}
}
void swap_at(const std::size_t lhs, const std::size_t rhs) {
void swap_at(const stl::size_t lhs, const stl::size_t rhs) {
auto &from = packed[lhs];
auto &to = packed[rhs];
sparse_ref(from) = traits_type::combine(static_cast<typename traits_type::entity_type>(rhs), traits_type::to_integral(from));
sparse_ref(to) = traits_type::combine(static_cast<typename traits_type::entity_type>(lhs), traits_type::to_integral(to));
sparse_ref(from) = traits_type::combine(static_cast<traits_type::entity_type>(rhs), traits_type::to_integral(from));
sparse_ref(to) = traits_type::combine(static_cast<traits_type::entity_type>(lhs), traits_type::to_integral(to));
std::swap(from, to);
stl::swap(from, to);
}
private:
[[nodiscard]] virtual const void *get_at(const std::size_t) const {
[[nodiscard]] virtual const void *get_at(const stl::size_t) const {
return nullptr;
}
virtual void swap_or_move([[maybe_unused]] const std::size_t lhs, [[maybe_unused]] const std::size_t rhs) {
virtual void swap_or_move([[maybe_unused]] const stl::size_t lhs, [[maybe_unused]] const stl::size_t rhs) {
ENTT_ASSERT((mode != deletion_policy::swap_only) || ((lhs < head) == (rhs < head)), "Cross swapping is not supported");
}
@@ -248,25 +227,25 @@ protected:
/**
* @brief Erases an entity from a sparse set.
* @param it An iterator to the element to pop.
* @param entt A valid identifier for the element to pop.
*/
void swap_only(const basic_iterator it) {
void swap_only(const Entity entt) {
ENTT_ASSERT(mode == deletion_policy::swap_only, "Deletion policy mismatch");
const auto pos = index(*it);
bump(traits_type::next(*it));
const auto pos = index(entt);
bump(traits_type::next(entt));
swap_at(pos, head -= (pos < head));
}
/**
* @brief Erases an entity from a sparse set.
* @param it An iterator to the element to pop.
* @param entt A valid identifier for the element to pop.
*/
void swap_and_pop(const basic_iterator it) {
void swap_and_pop(const Entity entt) {
ENTT_ASSERT(mode == deletion_policy::swap_and_pop, "Deletion policy mismatch");
auto &self = sparse_ref(*it);
const auto entt = traits_type::to_entity(self);
sparse_ref(packed.back()) = traits_type::combine(entt, traits_type::to_integral(packed.back()));
packed[static_cast<size_type>(entt)] = packed.back();
auto &self = sparse_ref(entt);
const auto pos = traits_type::to_entity(self);
sparse_ref(packed.back()) = traits_type::combine(pos, traits_type::to_integral(packed.back()));
packed[static_cast<size_type>(pos)] = packed.back();
// unnecessary but it helps to detect nasty bugs
// NOLINTNEXTLINE(bugprone-assert-side-effect)
ENTT_ASSERT((packed.back() = null, true), "");
@@ -277,12 +256,12 @@ protected:
/**
* @brief Erases an entity from a sparse set.
* @param it An iterator to the element to pop.
* @param entt A valid identifier for the element to pop.
*/
void in_place_pop(const basic_iterator it) {
void in_place_pop(const Entity entt) {
ENTT_ASSERT(mode == deletion_policy::in_place, "Deletion policy mismatch");
const auto pos = entity_to_pos(std::exchange(sparse_ref(*it), null));
packed[pos] = traits_type::combine(static_cast<typename traits_type::entity_type>(std::exchange(head, pos)), tombstone);
const auto pos = entity_to_pos(stl::exchange(sparse_ref(entt), null));
packed[pos] = traits_type::combine(static_cast<traits_type::entity_type>(stl::exchange(head, pos)), tombstone);
}
/**
@@ -294,17 +273,17 @@ protected:
switch(mode) {
case deletion_policy::swap_and_pop:
for(; first != last; ++first) {
swap_and_pop(first);
swap_and_pop(*first);
}
break;
case deletion_policy::in_place:
for(; first != last; ++first) {
in_place_pop(first);
in_place_pop(*first);
}
break;
case deletion_policy::swap_only:
for(; first != last; ++first) {
swap_only(first);
swap_only(*first);
}
break;
}
@@ -312,23 +291,15 @@ protected:
/*! @brief Erases all entities of a sparse set. */
virtual void pop_all() {
switch(mode) {
case deletion_policy::in_place:
if(head != max_size) {
for(auto &&elem: packed) {
if(elem != tombstone) {
sparse_ref(elem) = null;
if(!packed.empty()) {
// suboptimal with few entities, but exploits cache way more with many
for(auto &&elem: sparse) {
if(elem) {
for(size_type pos{}; pos < traits_type::page_size; ++pos) {
elem[pos] = null;
}
}
break;
}
[[fallthrough]];
case deletion_policy::swap_only:
case deletion_policy::swap_and_pop:
for(auto &&elem: packed) {
sparse_ref(elem) = null;
}
break;
}
head = policy_to_head();
@@ -351,20 +322,20 @@ protected:
if(head != max_size && !force_back) {
pos = head;
ENTT_ASSERT(elem == null, "Slot not available");
elem = traits_type::combine(static_cast<typename traits_type::entity_type>(head), traits_type::to_integral(entt));
head = entity_to_pos(std::exchange(packed[pos], entt));
elem = traits_type::combine(static_cast<traits_type::entity_type>(head), traits_type::to_integral(entt));
head = entity_to_pos(stl::exchange(packed[pos], entt));
break;
}
[[fallthrough]];
case deletion_policy::swap_and_pop:
packed.push_back(entt);
ENTT_ASSERT(elem == null, "Slot not available");
elem = traits_type::combine(static_cast<typename traits_type::entity_type>(packed.size() - 1u), traits_type::to_integral(entt));
elem = traits_type::combine(static_cast<traits_type::entity_type>(packed.size() - 1u), traits_type::to_integral(entt));
break;
case deletion_policy::swap_only:
if(elem == null) {
packed.push_back(entt);
elem = traits_type::combine(static_cast<typename traits_type::entity_type>(packed.size() - 1u), traits_type::to_integral(entt));
elem = traits_type::combine(static_cast<traits_type::entity_type>(packed.size() - 1u), traits_type::to_integral(entt));
} else {
ENTT_ASSERT(!(entity_to_pos(elem) < head), "Slot not available");
bump(entt);
@@ -386,23 +357,23 @@ public:
/*! @brief Allocator type. */
using allocator_type = Allocator;
/*! @brief Underlying entity identifier. */
using entity_type = typename traits_type::value_type;
using entity_type = traits_type::value_type;
/*! @brief Underlying version type. */
using version_type = typename traits_type::version_type;
using version_type = traits_type::version_type;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
using size_type = stl::size_t;
/*! @brief Signed integer type. */
using difference_type = std::ptrdiff_t;
using difference_type = stl::ptrdiff_t;
/*! @brief Pointer type to contained entities. */
using pointer = typename packed_container_type::const_pointer;
using pointer = packed_container_type::const_pointer;
/*! @brief Random access iterator type. */
using iterator = basic_iterator;
/*! @brief Constant random access iterator type. */
using const_iterator = iterator;
/*! @brief Reverse iterator type. */
using reverse_iterator = std::reverse_iterator<iterator>;
using reverse_iterator = stl::reverse_iterator<iterator>;
/*! @brief Constant reverse iterator type. */
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using const_reverse_iterator = stl::reverse_iterator<const_iterator>;
/*! @brief Default constructor. */
basic_sparse_set()
@@ -447,11 +418,11 @@ public:
* @param other The instance to move from.
*/
basic_sparse_set(basic_sparse_set &&other) noexcept
: sparse{std::move(other.sparse)},
packed{std::move(other.packed)},
: sparse{stl::move(other.sparse)},
packed{stl::move(other.packed)},
descriptor{other.descriptor},
mode{other.mode},
head{std::exchange(other.head, policy_to_head())} {}
head{stl::exchange(other.head, policy_to_head())} {}
/**
* @brief Allocator-extended move constructor.
@@ -459,11 +430,11 @@ public:
* @param allocator The allocator to use.
*/
basic_sparse_set(basic_sparse_set &&other, const allocator_type &allocator)
: sparse{std::move(other.sparse), allocator},
packed{std::move(other.packed), allocator},
: sparse{stl::move(other.sparse), allocator},
packed{stl::move(other.packed), allocator},
descriptor{other.descriptor},
mode{other.mode},
head{std::exchange(other.head, policy_to_head())} {
head{stl::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");
}
@@ -494,7 +465,7 @@ public:
* @param other Sparse set to exchange the content with.
*/
void swap(basic_sparse_set &other) noexcept {
using std::swap;
using stl::swap;
swap(sparse, other.sparse);
swap(packed, other.packed);
swap(descriptor, other.descriptor);
@@ -560,18 +531,16 @@ public:
virtual void shrink_to_fit() {
sparse_container_type other{sparse.get_allocator()};
const auto len = sparse.size();
size_type cnt{};
other.reserve(len);
for(auto &&elem: std::as_const(packed)) {
for(size_type cnt{}; auto &&elem: stl::as_const(packed)) {
if(elem != tombstone) {
if(const auto page = pos_to_page(entity_to_pos(elem)); sparse[page] != nullptr) {
if(const auto sz = page + 1u; sz > other.size()) {
other.resize(sz, nullptr);
}
other[page] = std::exchange(sparse[page], nullptr);
other[page] = stl::exchange(sparse[page], nullptr);
if(++cnt == len) {
// early exit due to lack of pages
@@ -681,7 +650,7 @@ public:
* array.
*/
[[nodiscard]] reverse_iterator rbegin() const noexcept {
return std::make_reverse_iterator(end());
return stl::make_reverse_iterator(end());
}
/*! @copydoc rbegin */
@@ -695,7 +664,7 @@ public:
* reversed sparse set.
*/
[[nodiscard]] reverse_iterator rend() const noexcept {
return std::make_reverse_iterator(begin());
return stl::make_reverse_iterator(begin());
}
/*! @copydoc rend */
@@ -779,7 +748,7 @@ public:
/*! @copydoc value */
[[nodiscard]] void *value(const entity_type entt) noexcept {
return const_cast<void *>(std::as_const(*this).value(entt));
return const_cast<void *>(stl::as_const(*this).value(entt));
}
/**
@@ -805,14 +774,12 @@ public:
* Attempting to assign an entity that already belongs to the sparse set
* results in undefined behavior.
*
* @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.
* @return Iterator pointing to the first element inserted in case of
* success, the `end()` iterator otherwise.
*/
template<typename It>
iterator push(It first, It last) {
iterator push(stl::input_iterator auto first, stl::input_iterator auto last) {
auto curr = end();
for(; first != last; ++first) {
@@ -863,9 +830,9 @@ public:
* @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>
template<stl::input_iterator It>
void erase(It first, It last) {
if constexpr(std::is_same_v<It, basic_iterator>) {
if constexpr(stl::is_same_v<It, basic_iterator>) {
pop(first, last);
} else {
for(; first != last; ++first) {
@@ -890,11 +857,11 @@ public:
* @param last An iterator past the last element of the range of entities.
* @return The number of entities actually removed.
*/
template<typename It>
template<stl::input_iterator It>
size_type remove(It first, It last) {
size_type count{};
if constexpr(std::is_same_v<It, basic_iterator>) {
if constexpr(stl::is_same_v<It, basic_iterator>) {
while(first != last) {
while(first != last && !contains(*first)) {
++first;
@@ -906,7 +873,7 @@ public:
++first;
}
count += static_cast<size_type>(std::distance(it, first));
count += static_cast<size_type>(stl::distance(it, first));
erase(it, first);
}
} else {
@@ -922,17 +889,17 @@ public:
void compact() {
if(mode == deletion_policy::in_place) {
size_type from = packed.size();
size_type pos = std::exchange(head, max_size);
size_type pos = stl::exchange(head, max_size);
for(; from && packed[from - 1u] == tombstone; --from) {}
while(pos != max_size) {
if(const auto to = std::exchange(pos, entity_to_pos(packed[pos])); to < from) {
if(const auto to = stl::exchange(pos, entity_to_pos(packed[pos])); to < from) {
--from;
swap_or_move(from, to);
packed[to] = packed[from];
const auto elem = static_cast<typename traits_type::entity_type>(to);
const auto elem = static_cast<traits_type::entity_type>(to);
sparse_ref(packed[to]) = traits_type::combine(elem, traits_type::to_integral(packed[to]));
for(; from && packed[from - 1u] == tombstone; --from) {}
@@ -1000,7 +967,7 @@ public:
ENTT_ASSERT((mode != deletion_policy::in_place) || (head == max_size), "Sorting with tombstones not allowed");
ENTT_ASSERT(!(length > packed.size()), "Length exceeds the number of elements");
algo(packed.rend() - static_cast<difference_type>(length), packed.rend(), std::move(compare), std::forward<Args>(args)...);
algo(packed.rend() - static_cast<difference_type>(length), packed.rend(), stl::move(compare), stl::forward<Args>(args)...);
for(size_type pos{}; pos < length; ++pos) {
auto curr = pos;
@@ -1011,9 +978,9 @@ public:
const auto entt = packed[curr];
swap_or_move(next, idx);
const auto elem = static_cast<typename traits_type::entity_type>(curr);
const auto elem = static_cast<traits_type::entity_type>(curr);
sparse_ref(entt) = traits_type::combine(elem, traits_type::to_integral(packed[curr]));
curr = std::exchange(next, idx);
curr = stl::exchange(next, idx);
}
}
}
@@ -1033,7 +1000,7 @@ public:
template<typename Compare, typename Sort = std_sort, typename... Args>
void sort(Compare compare, Sort algo = Sort{}, Args &&...args) {
const size_type len = (mode == deletion_policy::swap_only) ? head : packed.size();
sort_n(len, std::move(compare), std::move(algo), std::forward<Args>(args)...);
sort_n(len, stl::move(compare), stl::move(algo), stl::forward<Args>(args)...);
}
/**
@@ -1049,7 +1016,7 @@ public:
* @param last An iterator past the last element of the range of entities.
* @return An iterator past the last of the elements actually shared.
*/
template<typename It>
template<stl::input_iterator It>
iterator sort_as(It first, It last) {
ENTT_ASSERT((mode != deletion_policy::in_place) || (head == max_size), "Sorting with tombstones not allowed");
const size_type len = (mode == deletion_policy::swap_only) ? head : packed.size();
@@ -1086,11 +1053,6 @@ public:
return *descriptor;
}
/*! @copydoc info */
[[deprecated("use ::info instead")]] [[nodiscard]] const type_info &type() const noexcept {
return info();
}
/**
* @brief Forwards variables to derived classes, if any.
* @tparam Type Type of the element to forward.
@@ -1098,7 +1060,7 @@ public:
*/
template<typename Type>
void bind(Type &&value) noexcept {
bind_any(forward_as_any(std::forward<Type>(value)));
bind_any(forward_as_any(stl::forward<Type>(value)));
}
private:

View File

@@ -1,18 +1,20 @@
#ifndef ENTT_ENTITY_STORAGE_HPP
#define ENTT_ENTITY_STORAGE_HPP
#include <cstddef>
#include <iterator>
#include <memory>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
#include <compare>
#include "../config/config.h"
#include "../core/bit.hpp"
#include "../core/iterator.hpp"
#include "../core/memory.hpp"
#include "../core/type_info.hpp"
#include "../stl/concepts.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/iterator.hpp"
#include "../stl/memory.hpp"
#include "../stl/tuple.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "../stl/vector.hpp"
#include "component.hpp"
#include "entity.hpp"
#include "fwd.hpp"
@@ -20,27 +22,28 @@
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
template<typename Container, auto Page>
class storage_iterator final {
friend storage_iterator<const Container, Page>;
template<typename, auto>
friend class storage_iterator;
using container_type = std::remove_const_t<Container>;
using alloc_traits = std::allocator_traits<typename container_type::allocator_type>;
using container_type = stl::remove_const_t<Container>;
using alloc_traits = stl::allocator_traits<typename container_type::allocator_type>;
using iterator_traits = std::iterator_traits<std::conditional_t<
std::is_const_v<Container>,
typename alloc_traits::template rebind_traits<typename std::pointer_traits<typename container_type::value_type>::element_type>::const_pointer,
typename alloc_traits::template rebind_traits<typename std::pointer_traits<typename container_type::value_type>::element_type>::pointer>>;
using iterator_traits = stl::iterator_traits<stl::conditional_t<
stl::is_const_v<Container>,
typename alloc_traits::template rebind_traits<typename stl::pointer_traits<typename container_type::value_type>::element_type>::const_pointer,
typename alloc_traits::template rebind_traits<typename stl::pointer_traits<typename container_type::value_type>::element_type>::pointer>>;
public:
using value_type = typename iterator_traits::value_type;
using pointer = typename iterator_traits::pointer;
using reference = typename iterator_traits::reference;
using difference_type = typename iterator_traits::difference_type;
using iterator_category = std::random_access_iterator_tag;
using value_type = iterator_traits::value_type;
using pointer = iterator_traits::pointer;
using reference = iterator_traits::reference;
using difference_type = iterator_traits::difference_type;
using iterator_category = stl::random_access_iterator_tag;
constexpr storage_iterator() noexcept = default;
@@ -48,8 +51,9 @@ public:
: payload{ref},
offset{idx} {}
template<bool Const = std::is_const_v<Container>, typename = std::enable_if_t<Const>>
constexpr storage_iterator(const storage_iterator<std::remove_const_t<Container>, Page> &other) noexcept
template<stl::same_as<stl::remove_const_t<Container>> Other>
requires stl::is_const_v<Container>
constexpr storage_iterator(const storage_iterator<Other, Page> &other) noexcept
: storage_iterator{other.payload, other.offset} {}
constexpr storage_iterator &operator++() noexcept {
@@ -89,18 +93,35 @@ public:
}
[[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept {
const auto pos = static_cast<typename Container::size_type>(index() - value);
return (*payload)[pos / Page][fast_mod(static_cast<std::size_t>(pos), Page)];
const auto pos = static_cast<Container::size_type>(index() - value);
return (*payload)[pos / Page][fast_mod(static_cast<stl::size_t>(pos), Page)];
}
[[nodiscard]] constexpr pointer operator->() const noexcept {
return std::addressof(operator[](0));
return stl::addressof(operator[](0));
}
[[nodiscard]] constexpr reference operator*() const noexcept {
return operator[](0);
}
template<typename Other, auto Arg>
[[nodiscard]] constexpr stl::ptrdiff_t operator-(const storage_iterator<Other, Arg> &other) const noexcept {
// intentionally reversed due to backward iteration
return other.offset - offset;
}
template<typename Other, auto Arg>
[[nodiscard]] constexpr bool operator==(const storage_iterator<Other, Arg> &other) const noexcept {
return offset == other.offset;
}
template<typename Other, auto Arg>
[[nodiscard]] constexpr auto operator<=>(const storage_iterator<Other, Arg> &other) const noexcept {
// intentionally reversed due to backward iteration
return other.offset <=> offset;
}
[[nodiscard]] constexpr difference_type index() const noexcept {
return offset - 1;
}
@@ -110,54 +131,19 @@ private:
difference_type offset;
};
template<typename Lhs, typename Rhs, auto Page>
[[nodiscard]] constexpr std::ptrdiff_t operator-(const storage_iterator<Lhs, Page> &lhs, const storage_iterator<Rhs, Page> &rhs) noexcept {
return rhs.index() - lhs.index();
}
template<typename Lhs, typename Rhs, auto Page>
[[nodiscard]] constexpr bool operator==(const storage_iterator<Lhs, Page> &lhs, const storage_iterator<Rhs, Page> &rhs) noexcept {
return lhs.index() == rhs.index();
}
template<typename Lhs, typename Rhs, auto Page>
[[nodiscard]] constexpr bool operator!=(const storage_iterator<Lhs, Page> &lhs, const storage_iterator<Rhs, Page> &rhs) noexcept {
return !(lhs == rhs);
}
template<typename Lhs, typename Rhs, auto Page>
[[nodiscard]] constexpr bool operator<(const storage_iterator<Lhs, Page> &lhs, const storage_iterator<Rhs, Page> &rhs) noexcept {
return lhs.index() > rhs.index();
}
template<typename Lhs, typename Rhs, auto Page>
[[nodiscard]] constexpr bool operator>(const storage_iterator<Lhs, Page> &lhs, const storage_iterator<Rhs, Page> &rhs) noexcept {
return rhs < lhs;
}
template<typename Lhs, typename Rhs, auto Page>
[[nodiscard]] constexpr bool operator<=(const storage_iterator<Lhs, Page> &lhs, const storage_iterator<Rhs, Page> &rhs) noexcept {
return !(lhs > rhs);
}
template<typename Lhs, typename Rhs, auto Page>
[[nodiscard]] constexpr bool operator>=(const storage_iterator<Lhs, Page> &lhs, const storage_iterator<Rhs, Page> &rhs) noexcept {
return !(lhs < rhs);
}
template<typename It, typename... Other>
class extended_storage_iterator final {
template<typename Iter, typename... Args>
template<typename, typename...>
friend class extended_storage_iterator;
public:
using iterator_type = It;
using value_type = decltype(std::tuple_cat(std::make_tuple(*std::declval<It>()), std::forward_as_tuple(*std::declval<Other>()...)));
using value_type = decltype(stl::tuple_cat(stl::make_tuple(*stl::declval<It>()), stl::forward_as_tuple(*stl::declval<Other>()...)));
using pointer = input_iterator_pointer<value_type>;
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category = std::input_iterator_tag;
using iterator_concept = std::forward_iterator_tag;
using difference_type = stl::ptrdiff_t;
using iterator_category = stl::input_iterator_tag;
using iterator_concept = stl::forward_iterator_tag;
constexpr extended_storage_iterator()
: it{} {}
@@ -165,12 +151,13 @@ public:
constexpr extended_storage_iterator(iterator_type base, Other... other)
: it{base, other...} {}
template<typename... Args, typename = std::enable_if_t<(!std::is_same_v<Other, Args> && ...) && (std::is_constructible_v<Other, Args> && ...)>>
template<typename... Args>
requires (!stl::same_as<Other, Args> && ...) && (stl::constructible_from<Other, Args> && ...)
constexpr extended_storage_iterator(const extended_storage_iterator<It, Args...> &other)
: it{other.it} {}
constexpr extended_storage_iterator &operator++() noexcept {
return ++std::get<It>(it), (++std::get<Other>(it), ...), *this;
return ++stl::get<It>(it), (++stl::get<Other>(it), ...), *this;
}
constexpr extended_storage_iterator operator++(int) noexcept {
@@ -183,30 +170,22 @@ public:
}
[[nodiscard]] constexpr reference operator*() const noexcept {
return {*std::get<It>(it), *std::get<Other>(it)...};
return {*stl::get<It>(it), *stl::get<Other>(it)...};
}
[[nodiscard]] constexpr iterator_type base() const noexcept {
return std::get<It>(it);
return stl::get<It>(it);
}
template<typename... Lhs, typename... Rhs>
friend constexpr bool operator==(const extended_storage_iterator<Lhs...> &, const extended_storage_iterator<Rhs...> &) noexcept;
template<typename... Args>
[[nodiscard]] constexpr bool operator==(const extended_storage_iterator<Args...> &other) const noexcept {
return stl::get<0>(it) == stl::get<0>(other.it);
}
private:
std::tuple<It, Other...> it;
stl::tuple<It, Other...> it;
};
template<typename... Lhs, typename... Rhs>
[[nodiscard]] constexpr bool operator==(const extended_storage_iterator<Lhs...> &lhs, const extended_storage_iterator<Rhs...> &rhs) noexcept {
return std::get<0>(lhs.it) == std::get<0>(rhs.it);
}
template<typename... Lhs, typename... Rhs>
[[nodiscard]] constexpr bool operator!=(const extended_storage_iterator<Lhs...> &lhs, const extended_storage_iterator<Rhs...> &rhs) noexcept {
return !(lhs == rhs);
}
} // namespace internal
/*! @endcond */
@@ -225,20 +204,20 @@ template<typename... Lhs, typename... Rhs>
* @tparam Entity A valid entity type.
* @tparam Allocator Type of allocator used to manage memory and elements.
*/
template<typename Type, typename Entity, typename Allocator, typename>
class basic_storage: public basic_sparse_set<Entity, typename std::allocator_traits<Allocator>::template rebind_alloc<Entity>> {
using alloc_traits = std::allocator_traits<Allocator>;
static_assert(std::is_same_v<typename alloc_traits::value_type, Type>, "Invalid value type");
using container_type = std::vector<typename alloc_traits::pointer, typename alloc_traits::template rebind_alloc<typename alloc_traits::pointer>>;
template<typename Type, typename Entity, typename Allocator>
class basic_storage: public basic_sparse_set<Entity, typename stl::allocator_traits<Allocator>::template rebind_alloc<Entity>> {
using alloc_traits = stl::allocator_traits<Allocator>;
static_assert(stl::is_same_v<typename alloc_traits::value_type, Type>, "Invalid value type");
using container_type = stl::vector<typename alloc_traits::pointer, typename alloc_traits::template rebind_alloc<typename alloc_traits::pointer>>;
using underlying_type = basic_sparse_set<Entity, typename alloc_traits::template rebind_alloc<Entity>>;
using underlying_iterator = typename underlying_type::basic_iterator;
using underlying_iterator = underlying_type::basic_iterator;
using traits_type = component_traits<Type, Entity>;
[[nodiscard]] auto &element_at(const std::size_t pos) const {
[[nodiscard]] auto &element_at(const stl::size_t pos) const {
return payload[pos / traits_type::page_size][fast_mod(pos, traits_type::page_size)];
}
auto assure_at_least(const std::size_t pos) {
auto assure_at_least(const stl::size_t pos) {
const auto idx = pos / traits_type::page_size;
if(!(idx < payload.size())) {
@@ -265,8 +244,8 @@ class basic_storage: public basic_sparse_set<Entity, typename std::allocator_tra
const auto it = base_type::try_emplace(entt, force_back);
ENTT_TRY {
auto *elem = to_address(assure_at_least(static_cast<size_type>(it.index())));
entt::uninitialized_construct_using_allocator(elem, get_allocator(), std::forward<Args>(args)...);
auto *elem = stl::to_address(assure_at_least(static_cast<size_type>(it.index())));
entt::uninitialized_construct_using_allocator(elem, get_allocator(), stl::forward<Args>(args)...);
}
ENTT_CATCH {
base_type::pop(it, it + 1u);
@@ -276,17 +255,19 @@ class basic_storage: public basic_sparse_set<Entity, typename std::allocator_tra
return it;
}
void shrink_to_size(const std::size_t sz) {
void shrink_to_size(const stl::size_t sz) {
const auto from = (sz + traits_type::page_size - 1u) / traits_type::page_size;
allocator_type allocator{get_allocator()};
for(auto pos = sz, length = base_type::size(); pos < length; ++pos) {
if constexpr(traits_type::in_place_delete) {
if(base_type::data()[pos] != tombstone) {
alloc_traits::destroy(allocator, std::addressof(element_at(pos)));
if constexpr(!stl::is_trivially_destructible_v<element_type>) {
for(auto pos = sz, length = base_type::size(); pos < length; ++pos) {
if constexpr(traits_type::in_place_delete) {
if(base_type::data()[pos] != tombstone) {
alloc_traits::destroy(allocator, stl::addressof(element_at(pos)));
}
} else {
alloc_traits::destroy(allocator, stl::addressof(element_at(pos)));
}
} else {
alloc_traits::destroy(allocator, std::addressof(element_at(pos)));
}
}
@@ -298,25 +279,25 @@ class basic_storage: public basic_sparse_set<Entity, typename std::allocator_tra
payload.shrink_to_fit();
}
void swap_at(const std::size_t lhs, const std::size_t rhs) {
using std::swap;
void swap_at(const stl::size_t lhs, const stl::size_t rhs) {
using stl::swap;
swap(element_at(lhs), element_at(rhs));
}
void move_to(const std::size_t lhs, const std::size_t rhs) {
void move_to(const stl::size_t lhs, const stl::size_t rhs) {
auto &elem = element_at(lhs);
allocator_type allocator{get_allocator()};
entt::uninitialized_construct_using_allocator(to_address(assure_at_least(rhs)), allocator, std::move(elem));
alloc_traits::destroy(allocator, std::addressof(elem));
entt::uninitialized_construct_using_allocator(stl::to_address(assure_at_least(rhs)), allocator, stl::move(elem));
alloc_traits::destroy(allocator, stl::addressof(elem));
}
private:
[[nodiscard]] const void *get_at(const std::size_t pos) const final {
return std::addressof(element_at(pos));
[[nodiscard]] const void *get_at(const stl::size_t pos) const final {
return stl::addressof(element_at(pos));
}
void swap_or_move([[maybe_unused]] const std::size_t from, [[maybe_unused]] const std::size_t to) override {
static constexpr bool is_pinned_type = !(std::is_move_constructible_v<Type> && std::is_move_assignable_v<Type>);
void swap_or_move([[maybe_unused]] const stl::size_t from, [[maybe_unused]] const stl::size_t to) override {
static constexpr bool is_pinned_type = !(stl::is_move_constructible_v<Type> && stl::is_move_assignable_v<Type>);
// use a runtime value to avoid compile-time suppression that drives the code coverage tool crazy
ENTT_ASSERT((from + 1u) && !is_pinned_type, "Pinned type");
@@ -341,31 +322,38 @@ protected:
auto &elem = element_at(base_type::index(*first));
if constexpr(traits_type::in_place_delete) {
base_type::in_place_pop(first);
alloc_traits::destroy(allocator, std::addressof(elem));
base_type::in_place_pop(*first);
alloc_traits::destroy(allocator, stl::addressof(elem));
} else if constexpr(stl::is_trivially_destructible_v<element_type>) {
elem = stl::move(element_at(base_type::size() - 1u));
base_type::swap_and_pop(*first);
} else {
auto &other = element_at(base_type::size() - 1u);
// destroying on exit allows reentrant destructors
[[maybe_unused]] auto unused = std::exchange(elem, std::move(other));
alloc_traits::destroy(allocator, std::addressof(other));
base_type::swap_and_pop(first);
[[maybe_unused]] auto unused = stl::exchange(elem, stl::move(other));
alloc_traits::destroy(allocator, stl::addressof(other));
base_type::swap_and_pop(*first);
}
}
}
/*! @brief Erases all entities of a storage. */
void pop_all() override {
allocator_type allocator{get_allocator()};
if constexpr(stl::is_trivially_destructible_v<element_type>) {
base_type::pop_all();
} else {
allocator_type allocator{get_allocator()};
for(auto first = base_type::begin(); !(first.index() < 0); ++first) {
if constexpr(traits_type::in_place_delete) {
if(*first != tombstone) {
base_type::in_place_pop(first);
alloc_traits::destroy(allocator, std::addressof(element_at(static_cast<size_type>(first.index()))));
for(auto first = base_type::begin(); !(first.index() < 0); ++first) {
if constexpr(traits_type::in_place_delete) {
if(*first != tombstone) {
base_type::in_place_pop(*first);
alloc_traits::destroy(allocator, stl::addressof(element_at(static_cast<size_type>(first.index()))));
}
} else {
base_type::swap_and_pop(*first);
alloc_traits::destroy(allocator, stl::addressof(element_at(static_cast<size_type>(first.index()))));
}
} else {
base_type::swap_and_pop(first);
alloc_traits::destroy(allocator, std::addressof(element_at(static_cast<size_type>(first.index()))));
}
}
}
@@ -379,13 +367,13 @@ protected:
*/
underlying_iterator try_emplace([[maybe_unused]] const Entity entt, [[maybe_unused]] const bool force_back, const void *value) override {
if(value != nullptr) {
if constexpr(std::is_copy_constructible_v<element_type>) {
if constexpr(stl::is_copy_constructible_v<element_type>) {
return emplace_element(entt, force_back, *static_cast<const element_type *>(value));
} else {
return base_type::end();
}
} else {
if constexpr(std::is_default_constructible_v<element_type>) {
if constexpr(stl::is_default_constructible_v<element_type>) {
return emplace_element(entt, force_back);
} else {
return base_type::end();
@@ -405,21 +393,21 @@ public:
/*! @brief Underlying entity identifier. */
using entity_type = Entity;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
using size_type = stl::size_t;
/*! @brief Signed integer type. */
using difference_type = std::ptrdiff_t;
using difference_type = stl::ptrdiff_t;
/*! @brief Pointer type to contained elements. */
using pointer = typename container_type::pointer;
using pointer = container_type::pointer;
/*! @brief Constant pointer type to contained elements. */
using const_pointer = typename alloc_traits::template rebind_traits<typename alloc_traits::const_pointer>::const_pointer;
using const_pointer = alloc_traits::template rebind_traits<typename alloc_traits::const_pointer>::const_pointer;
/*! @brief Random access iterator type. */
using iterator = internal::storage_iterator<container_type, traits_type::page_size>;
/*! @brief Constant random access iterator type. */
using const_iterator = internal::storage_iterator<const container_type, traits_type::page_size>;
/*! @brief Reverse iterator type. */
using reverse_iterator = std::reverse_iterator<iterator>;
using reverse_iterator = stl::reverse_iterator<iterator>;
/*! @brief Constant reverse iterator type. */
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using const_reverse_iterator = stl::reverse_iterator<const_iterator>;
/*! @brief Extended iterable storage proxy. */
using iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::iterator, iterator>>;
/*! @brief Constant extended iterable storage proxy. */
@@ -452,7 +440,7 @@ public:
*/
basic_storage(basic_storage &&other) noexcept
: base_type{static_cast<base_type &&>(other)},
payload{std::move(other.payload)} {}
payload{stl::move(other.payload)} {}
/**
* @brief Allocator-extended move constructor.
@@ -461,7 +449,7 @@ public:
*/
basic_storage(basic_storage &&other, const allocator_type &allocator)
: base_type{static_cast<base_type &&>(other), allocator},
payload{std::move(other.payload), allocator} {
payload{stl::move(other.payload), allocator} {
ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a storage is not allowed");
}
@@ -493,7 +481,7 @@ public:
* @param other Storage to exchange the content with.
*/
void swap(basic_storage &other) noexcept {
using std::swap;
using stl::swap;
swap(payload, other.payload);
base_type::swap(other);
}
@@ -599,7 +587,7 @@ public:
* @return An iterator to the first instance of the reversed internal array.
*/
[[nodiscard]] const_reverse_iterator crbegin() const noexcept {
return std::make_reverse_iterator(cend());
return stl::make_reverse_iterator(cend());
}
/*! @copydoc crbegin */
@@ -609,7 +597,7 @@ public:
/*! @copydoc rbegin */
[[nodiscard]] reverse_iterator rbegin() noexcept {
return std::make_reverse_iterator(end());
return stl::make_reverse_iterator(end());
}
/**
@@ -618,7 +606,7 @@ public:
* reversed internal array.
*/
[[nodiscard]] const_reverse_iterator crend() const noexcept {
return std::make_reverse_iterator(cbegin());
return stl::make_reverse_iterator(cbegin());
}
/*! @copydoc crend */
@@ -628,7 +616,7 @@ public:
/*! @copydoc rend */
[[nodiscard]] reverse_iterator rend() noexcept {
return std::make_reverse_iterator(begin());
return stl::make_reverse_iterator(begin());
}
/**
@@ -647,7 +635,7 @@ public:
/*! @copydoc get */
[[nodiscard]] value_type &get(const entity_type entt) noexcept {
return const_cast<value_type &>(std::as_const(*this).get(entt));
return const_cast<value_type &>(stl::as_const(*this).get(entt));
}
/**
@@ -655,13 +643,13 @@ public:
* @param entt A valid identifier.
* @return The object assigned to the entity as a tuple.
*/
[[nodiscard]] std::tuple<const value_type &> get_as_tuple(const entity_type entt) const noexcept {
return std::forward_as_tuple(get(entt));
[[nodiscard]] stl::tuple<const value_type &> get_as_tuple(const entity_type entt) const noexcept {
return stl::forward_as_tuple(get(entt));
}
/*! @copydoc get_as_tuple */
[[nodiscard]] std::tuple<value_type &> get_as_tuple(const entity_type entt) noexcept {
return std::forward_as_tuple(get(entt));
[[nodiscard]] stl::tuple<value_type &> get_as_tuple(const entity_type entt) noexcept {
return stl::forward_as_tuple(get(entt));
}
/**
@@ -678,11 +666,11 @@ public:
*/
template<typename... Args>
value_type &emplace(const entity_type entt, Args &&...args) {
if constexpr(std::is_aggregate_v<value_type> && (sizeof...(Args) != 0u || !std::is_default_constructible_v<value_type>)) {
const auto it = emplace_element(entt, false, Type{std::forward<Args>(args)...});
if constexpr(stl::is_aggregate_v<value_type> && (sizeof...(Args) != 0u || !stl::is_default_constructible_v<value_type>)) {
const auto it = emplace_element(entt, false, Type{stl::forward<Args>(args)...});
return element_at(static_cast<size_type>(it.index()));
} else {
const auto it = emplace_element(entt, false, std::forward<Args>(args)...);
const auto it = emplace_element(entt, false, stl::forward<Args>(args)...);
return element_at(static_cast<size_type>(it.index()));
}
}
@@ -698,7 +686,7 @@ public:
value_type &patch(const entity_type entt, Func &&...func) {
const auto idx = base_type::index(entt);
auto &elem = element_at(idx);
(std::forward<Func>(func)(elem), ...);
(stl::forward<Func>(func)(elem), ...);
return elem;
}
@@ -710,14 +698,12 @@ public:
* Attempting to assign an entity that already belongs to the storage
* results in undefined behavior.
*
* @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.
* @param value An instance of the object to construct.
* @return Iterator pointing to the first element inserted, if any.
*/
template<typename It>
iterator insert(It first, It last, const value_type &value = {}) {
iterator insert(stl::input_iterator auto first, stl::input_iterator auto last, const value_type &value = {}) {
for(; first != last; ++first) {
emplace_element(*first, true, value);
}
@@ -731,15 +717,15 @@ public:
*
* @sa construct
*
* @tparam EIt Type of input iterator.
* @tparam CIt Type of input iterator.
* @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.
* @param from An iterator to the first element of the range of objects.
* @return Iterator pointing to the first element inserted, if any.
*/
template<typename EIt, typename CIt, typename = std::enable_if_t<std::is_same_v<typename std::iterator_traits<CIt>::value_type, value_type>>>
iterator insert(EIt first, EIt last, CIt from) {
template<stl::input_iterator It>
requires stl::same_as<typename stl::iterator_traits<It>::value_type, value_type>
iterator insert(stl::input_iterator auto first, stl::input_iterator auto last, It from) {
for(; first != last; ++first, ++from) {
emplace_element(*first, true, *from);
}
@@ -786,10 +772,11 @@ private:
/*! @copydoc basic_storage */
template<typename Type, typename Entity, typename Allocator>
class basic_storage<Type, Entity, Allocator, std::enable_if_t<component_traits<Type, Entity>::page_size == 0u>>
: public basic_sparse_set<Entity, typename std::allocator_traits<Allocator>::template rebind_alloc<Entity>> {
using alloc_traits = std::allocator_traits<Allocator>;
static_assert(std::is_same_v<typename alloc_traits::value_type, Type>, "Invalid value type");
requires (component_traits<Type, Entity>::page_size == 0u)
class basic_storage<Type, Entity, Allocator>
: public basic_sparse_set<Entity, typename stl::allocator_traits<Allocator>::template rebind_alloc<Entity>> {
using alloc_traits = stl::allocator_traits<Allocator>;
static_assert(stl::is_same_v<typename alloc_traits::value_type, Type>, "Invalid value type");
using traits_type = component_traits<Type, Entity>;
public:
@@ -804,9 +791,9 @@ public:
/*! @brief Underlying entity identifier. */
using entity_type = Entity;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
using size_type = stl::size_t;
/*! @brief Signed integer type. */
using difference_type = std::ptrdiff_t;
using difference_type = stl::ptrdiff_t;
/*! @brief Extended iterable storage proxy. */
using iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::iterator>>;
/*! @brief Constant extended iterable storage proxy. */
@@ -844,7 +831,7 @@ public:
* @param allocator The allocator to use.
*/
basic_storage(basic_storage &&other, const allocator_type &allocator)
: base_type{std::move(other), allocator} {}
: base_type{stl::move(other), allocator} {}
/*! @brief Default destructor. */
~basic_storage() override = default;
@@ -867,12 +854,7 @@ public:
* @return The associated allocator.
*/
[[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
// std::allocator<void> has no cross constructors (waiting for C++20)
if constexpr(std::is_void_v<element_type> && !std::is_constructible_v<allocator_type, typename base_type::allocator_type>) {
return allocator_type{};
} else {
return allocator_type{base_type::get_allocator()};
}
return allocator_type{base_type::get_allocator()};
}
/**
@@ -893,9 +875,9 @@ public:
* @param entt A valid identifier.
* @return Returns an empty tuple.
*/
[[nodiscard]] std::tuple<> get_as_tuple([[maybe_unused]] const entity_type entt) const noexcept {
[[nodiscard]] stl::tuple<> get_as_tuple([[maybe_unused]] const entity_type entt) const noexcept {
ENTT_ASSERT(base_type::contains(entt), "Invalid entity");
return std::tuple{};
return stl::tuple{};
}
/**
@@ -907,7 +889,7 @@ public:
*
* @param entt A valid identifier.
*/
void emplace(const entity_type entt) {
void emplace(const entity_type entt, const auto &...) {
base_type::try_emplace(entt, false);
}
@@ -920,17 +902,15 @@ public:
template<typename... Func>
void patch([[maybe_unused]] const entity_type entt, Func &&...func) {
ENTT_ASSERT(base_type::contains(entt), "Invalid entity");
(std::forward<Func>(func)(), ...);
(stl::forward<Func>(func)(), ...);
}
/**
* @brief Assigns entities to a storage.
* @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 It>
void insert(It first, It last) {
void insert(stl::input_iterator auto first, stl::input_iterator auto last, const auto &...) {
for(; first != last; ++first) {
base_type::try_emplace(*first, true);
}
@@ -977,13 +957,13 @@ public:
template<typename Entity, typename Allocator>
class basic_storage<Entity, Entity, Allocator>
: public basic_sparse_set<Entity, Allocator> {
using alloc_traits = std::allocator_traits<Allocator>;
static_assert(std::is_same_v<typename alloc_traits::value_type, Entity>, "Invalid value type");
using underlying_iterator = typename basic_sparse_set<Entity, Allocator>::basic_iterator;
using alloc_traits = stl::allocator_traits<Allocator>;
static_assert(stl::is_same_v<typename alloc_traits::value_type, Entity>, "Invalid value type");
using underlying_iterator = basic_sparse_set<Entity, Allocator>::basic_iterator;
using traits_type = entt_traits<Entity>;
auto from_placeholder() noexcept {
const auto entt = traits_type::combine(static_cast<typename traits_type::entity_type>(placeholder), {});
const auto entt = traits_type::combine(static_cast<traits_type::entity_type>(placeholder), {});
ENTT_ASSERT(entt != null, "No more entities available");
placeholder += static_cast<size_type>(entt != null);
return entt;
@@ -1027,9 +1007,9 @@ public:
/*! @brief Underlying entity identifier. */
using entity_type = Entity;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
using size_type = stl::size_t;
/*! @brief Signed integer type. */
using difference_type = std::ptrdiff_t;
using difference_type = stl::ptrdiff_t;
/*! @brief Extended iterable storage proxy. */
using iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::iterator>>;
/*! @brief Constant extended iterable storage proxy. */
@@ -1091,7 +1071,7 @@ public:
*/
basic_storage &operator=(basic_storage &&other) noexcept {
placeholder = other.placeholder;
base_type::operator=(std::move(other));
base_type::operator=(stl::move(other));
return *this;
}
@@ -1100,7 +1080,7 @@ public:
* @param other Storage to exchange the content with.
*/
void swap(basic_storage &other) noexcept {
using std::swap;
using stl::swap;
swap(placeholder, other.placeholder);
base_type::swap(other);
}
@@ -1123,9 +1103,9 @@ public:
* @param entt A valid identifier.
* @return Returns an empty tuple.
*/
[[nodiscard]] std::tuple<> get_as_tuple([[maybe_unused]] const entity_type entt) const noexcept {
[[nodiscard]] stl::tuple<> get_as_tuple([[maybe_unused]] const entity_type entt) const noexcept {
ENTT_ASSERT(base_type::index(entt) < base_type::free_list(), "The requested entity is not a live one");
return std::tuple{};
return stl::tuple{};
}
/**
@@ -1159,11 +1139,11 @@ public:
/**
* @brief Assigns each element in a range an identifier.
* @tparam It Type of mutable forward iterator.
* @tparam It Type of output 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>
template<stl::output_iterator<entity_type> It>
void generate(It first, It last) {
for(const auto sz = base_type::size(); first != last && base_type::free_list() != sz; ++first) {
*first = *base_type::try_emplace(base_type::data()[base_type::free_list()], true);
@@ -1183,7 +1163,7 @@ public:
template<typename... Func>
void patch([[maybe_unused]] const entity_type entt, Func &&...func) {
ENTT_ASSERT(base_type::index(entt) < base_type::free_list(), "The requested entity is not a live one");
(std::forward<Func>(func)(), ...);
(stl::forward<Func>(func)(), ...);
}
/**
@@ -1194,7 +1174,7 @@ public:
* @return An iterable object to use to _visit_ the storage.
*/
[[nodiscard]] iterable each() noexcept {
return std::as_const(*this).each();
return stl::as_const(*this).each();
}
/*! @copydoc each */
@@ -1212,7 +1192,7 @@ public:
* @return A reverse iterable object to use to _visit_ the storage.
*/
[[nodiscard]] reverse_iterable reach() noexcept {
return std::as_const(*this).reach();
return stl::as_const(*this).reach();
}
/*! @copydoc reach */

View File

@@ -1,72 +1,71 @@
#ifndef ENTT_ENTITY_VIEW_HPP
#define ENTT_ENTITY_VIEW_HPP
#include <array>
#include <cstddef>
#include <iterator>
#include <tuple>
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "../core/concepts.hpp"
#include "../core/iterator.hpp"
#include "../core/type_traits.hpp"
#include "../stl/array.hpp"
#include "../stl/concepts.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/iterator.hpp"
#include "../stl/tuple.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "entity.hpp"
#include "fwd.hpp"
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
template<typename... Type>
// NOLINTNEXTLINE(misc-redundant-expression)
static constexpr bool tombstone_check_v = ((sizeof...(Type) == 1u) && ... && (Type::storage_policy == deletion_policy::in_place));
template<typename Type>
template<cvref_unqualified Type>
const Type *view_placeholder() {
static_assert(std::is_same_v<std::remove_const_t<std::remove_reference_t<Type>>, Type>, "Unexpected type");
static const Type placeholder{};
return &placeholder;
}
template<typename It, typename Entity>
[[nodiscard]] bool all_of(It first, const It last, const Entity entt) noexcept {
[[nodiscard]] bool all_of(auto first, const auto last, const auto entt) noexcept {
for(; (first != last) && (*first)->contains(entt); ++first) {}
return first == last;
}
template<typename It, typename Entity>
[[nodiscard]] bool none_of(It first, const It last, const Entity entt) noexcept {
[[nodiscard]] bool none_of(auto first, const auto last, const auto entt) noexcept {
for(; (first != last) && !(*first)->contains(entt); ++first) {}
return first == last;
}
template<typename It>
[[nodiscard]] bool fully_initialized(It first, const It last, const std::remove_pointer_t<typename std::iterator_traits<It>::value_type> *placeholder) noexcept {
[[nodiscard]] bool fully_initialized(It first, const It last, const stl::remove_pointer_t<typename stl::iterator_traits<It>::value_type> *placeholder) noexcept {
for(; (first != last) && *first != placeholder; ++first) {}
return first == last;
}
template<typename Result, typename View, typename Other, std::size_t... GLhs, std::size_t... ELhs, std::size_t... GRhs, std::size_t... ERhs>
[[nodiscard]] Result view_pack(const View &view, const Other &other, std::index_sequence<GLhs...>, std::index_sequence<ELhs...>, std::index_sequence<GRhs...>, std::index_sequence<ERhs...>) {
template<typename Result, typename View, typename Other, stl::size_t... GLhs, stl::size_t... ELhs, stl::size_t... GRhs, stl::size_t... ERhs>
[[nodiscard]] Result view_pack(const View &view, const Other &other, stl::index_sequence<GLhs...>, stl::index_sequence<ELhs...>, stl::index_sequence<GRhs...>, stl::index_sequence<ERhs...>) {
Result elem{};
// friend-initialization, avoid multiple calls to refresh
elem.pools = {view.template storage<GLhs>()..., other.template storage<GRhs>()...};
auto filter_or_placeholder = [placeholder = elem.placeholder](auto *value) { return (value == nullptr) ? placeholder : value; };
[[maybe_unused]] const auto filter_or_placeholder = [placeholder = elem.placeholder](auto *value) { return (value == nullptr) ? placeholder : value; };
elem.filter = {filter_or_placeholder(view.template storage<sizeof...(GLhs) + ELhs>())..., filter_or_placeholder(other.template storage<sizeof...(GRhs) + ERhs>())...};
elem.refresh();
return elem;
}
template<typename Type, bool Checked, std::size_t Get, std::size_t Exclude>
template<typename Type, bool Checked, stl::size_t Get, stl::size_t Exclude>
class view_iterator final {
template<typename, typename...>
friend class extended_view_iterator;
friend struct extended_view_iterator;
using iterator_type = typename Type::const_iterator;
using iterator_traits = std::iterator_traits<iterator_type>;
using iterator_type = Type::const_iterator;
using iterator_traits = stl::iterator_traits<iterator_type>;
[[nodiscard]] bool valid(const typename iterator_traits::value_type entt) const noexcept {
[[nodiscard]] bool valid(const iterator_traits::value_type entt) const noexcept {
return (!Checked || (entt != tombstone))
&& ((Get == 1u) || (internal::all_of(pools.begin(), pools.begin() + index, entt) && internal::all_of(pools.begin() + index + 1, pools.end(), entt)))
&& ((Exclude == 0u) || internal::none_of(filter.begin(), filter.end(), entt));
@@ -77,11 +76,11 @@ class view_iterator final {
}
public:
using value_type = typename iterator_traits::value_type;
using pointer = typename iterator_traits::pointer;
using reference = typename iterator_traits::reference;
using difference_type = typename iterator_traits::difference_type;
using iterator_category = std::forward_iterator_tag;
using value_type = iterator_traits::value_type;
using pointer = iterator_traits::pointer;
using reference = iterator_traits::reference;
using difference_type = iterator_traits::difference_type;
using iterator_category = stl::forward_iterator_tag;
constexpr view_iterator() noexcept
: it{},
@@ -89,7 +88,7 @@ public:
filter{},
index{} {}
view_iterator(iterator_type first, std::array<const Type *, Get> value, std::array<const Type *, Exclude> excl, const std::size_t idx) noexcept
view_iterator(iterator_type first, stl::array<const Type *, Get> value, stl::array<const Type *, Exclude> excl, const stl::size_t idx) noexcept
: it{first},
pools{value},
filter{excl},
@@ -117,41 +116,27 @@ public:
return *operator->();
}
template<typename LhsType, auto... LhsArgs, typename RhsType, auto... RhsArgs>
friend constexpr bool operator==(const view_iterator<LhsType, LhsArgs...> &, const view_iterator<RhsType, RhsArgs...> &) noexcept;
template<typename Other, auto... Args>
[[nodiscard]] constexpr bool operator==(const view_iterator<Other, Args...> &other) const noexcept {
return it == other.it;
}
private:
iterator_type it;
std::array<const Type *, Get> pools;
std::array<const Type *, Exclude> filter;
stl::array<const Type *, Get> pools;
stl::array<const Type *, Exclude> filter;
difference_type index;
};
template<typename LhsType, auto... LhsArgs, typename RhsType, auto... RhsArgs>
[[nodiscard]] constexpr bool operator==(const view_iterator<LhsType, LhsArgs...> &lhs, const view_iterator<RhsType, RhsArgs...> &rhs) noexcept {
return lhs.it == rhs.it;
}
template<typename LhsType, auto... LhsArgs, typename RhsType, auto... RhsArgs>
[[nodiscard]] constexpr bool operator!=(const view_iterator<LhsType, LhsArgs...> &lhs, const view_iterator<RhsType, RhsArgs...> &rhs) noexcept {
return !(lhs == rhs);
}
template<typename It, typename... Get>
class extended_view_iterator final {
template<std::size_t... Index>
[[nodiscard]] auto dereference(std::index_sequence<Index...>) const noexcept {
return std::tuple_cat(std::make_tuple(*it), static_cast<Get *>(const_cast<constness_as_t<typename Get::base_type, Get> *>(std::get<Index>(it.pools)))->get_as_tuple(*it)...);
}
public:
struct extended_view_iterator final {
using iterator_type = It;
using value_type = decltype(std::tuple_cat(std::make_tuple(*std::declval<It>()), std::declval<Get>().get_as_tuple({})...));
using value_type = decltype(stl::tuple_cat(stl::make_tuple(*stl::declval<It>()), stl::declval<Get>().get_as_tuple({})...));
using pointer = input_iterator_pointer<value_type>;
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category = std::input_iterator_tag;
using iterator_concept = std::forward_iterator_tag;
using difference_type = stl::ptrdiff_t;
using iterator_category = stl::input_iterator_tag;
using iterator_concept = stl::forward_iterator_tag;
constexpr extended_view_iterator()
: it{} {}
@@ -169,7 +154,9 @@ public:
}
[[nodiscard]] reference operator*() const noexcept {
return dereference(std::index_sequence_for<Get...>{});
return [this]<auto... Index>(stl::index_sequence<Index...>) {
return stl::tuple_cat(stl::make_tuple(*it), static_cast<Get *>(const_cast<constness_as_t<typename Get::base_type, Get> *>(stl::get<Index>(it.pools)))->get_as_tuple(*it)...);
}(stl::index_sequence_for<Get...>{});
}
[[nodiscard]] pointer operator->() const noexcept {
@@ -180,23 +167,15 @@ public:
return it;
}
template<typename... Lhs, typename... Rhs>
friend bool constexpr operator==(const extended_view_iterator<Lhs...> &, const extended_view_iterator<Rhs...> &) noexcept;
template<typename... Other>
[[nodiscard]] constexpr bool operator==(const extended_view_iterator<Other...> &other) const noexcept {
return it == other.it;
}
private:
It it;
};
template<typename... Lhs, typename... Rhs>
[[nodiscard]] constexpr bool operator==(const extended_view_iterator<Lhs...> &lhs, const extended_view_iterator<Rhs...> &rhs) noexcept {
return lhs.it == rhs.it;
}
template<typename... Lhs, typename... Rhs>
[[nodiscard]] constexpr bool operator!=(const extended_view_iterator<Lhs...> &lhs, const extended_view_iterator<Rhs...> &rhs) noexcept {
return !(lhs == rhs);
}
} // namespace internal
/*! @endcond */
@@ -218,7 +197,7 @@ template<typename... Lhs, typename... Rhs>
* In all other cases, modifying the storage iterated by a view in any way can
* invalidate all iterators.
*/
template<typename, typename, typename>
template<typename, typename>
class basic_view;
/**
@@ -229,12 +208,10 @@ class basic_view;
* @tparam Get Number of storage iterated by the view.
* @tparam Exclude Number of storage used to filter the view.
*/
template<typename Type, bool Checked, std::size_t Get, std::size_t Exclude>
template<cvref_unqualified Type, bool Checked, stl::size_t Get, stl::size_t Exclude>
class basic_common_view {
static_assert(std::is_same_v<std::remove_const_t<std::remove_reference_t<Type>>, Type>, "Unexpected type");
template<typename Return, typename View, typename Other, std::size_t... GLhs, std::size_t... ELhs, std::size_t... GRhs, std::size_t... ERhs>
friend Return internal::view_pack(const View &, const Other &, std::index_sequence<GLhs...>, std::index_sequence<ELhs...>, std::index_sequence<GRhs...>, std::index_sequence<ERhs...>);
template<typename Return, typename View, typename Other, stl::size_t... GLhs, stl::size_t... ELhs, stl::size_t... GRhs, stl::size_t... ERhs>
friend Return internal::view_pack(const View &, const Other &, stl::index_sequence<GLhs...>, stl::index_sequence<ELhs...>, stl::index_sequence<GRhs...>, stl::index_sequence<ERhs...>);
[[nodiscard]] auto offset() const noexcept {
ENTT_ASSERT(index != Get, "Invalid view");
@@ -254,44 +231,44 @@ class basic_common_view {
}
protected:
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
basic_common_view() noexcept {
for(size_type pos{}, last = filter.size(); pos < last; ++pos) {
filter[pos] = placeholder;
}
}
basic_common_view(std::array<const Type *, Get> value, std::array<const Type *, Exclude> excl) noexcept
basic_common_view(stl::array<const Type *, Get> value, stl::array<const Type *, Exclude> excl) noexcept
: pools{value},
filter{excl},
index{Get} {
unchecked_refresh();
}
[[nodiscard]] const Type *pool_at(const std::size_t pos) const noexcept {
[[nodiscard]] const Type *pool_at(const stl::size_t pos) const noexcept {
return pools[pos];
}
void pool_at(const std::size_t pos, const Type *elem) noexcept {
void pool_at(const stl::size_t pos, const Type *elem) noexcept {
ENTT_ASSERT(elem != nullptr, "Unexpected element");
pools[pos] = elem;
refresh();
}
[[nodiscard]] const Type *filter_at(const std::size_t pos) const noexcept {
[[nodiscard]] const Type *filter_at(const stl::size_t pos) const noexcept {
return (filter[pos] == placeholder) ? nullptr : filter[pos];
}
void filter_at(const std::size_t pos, const Type *elem) noexcept {
void filter_at(const stl::size_t pos, const Type *elem) noexcept {
ENTT_ASSERT(elem != nullptr, "Unexpected element");
filter[pos] = elem;
}
[[nodiscard]] bool none_of(const typename Type::entity_type entt) const noexcept {
[[nodiscard]] bool none_of(const Type::entity_type entt) const noexcept {
return internal::none_of(filter.begin(), filter.end(), entt);
}
void use(const std::size_t pos) noexcept {
void use(const stl::size_t pos) noexcept {
index = (index != Get) ? pos : Get;
}
/*! @endcond */
@@ -300,11 +277,11 @@ public:
/*! @brief Common type among all storage types. */
using common_type = Type;
/*! @brief Underlying entity identifier. */
using entity_type = typename Type::entity_type;
using entity_type = Type::entity_type;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
using size_type = stl::size_t;
/*! @brief Signed integer type. */
using difference_type = std::ptrdiff_t;
using difference_type = stl::ptrdiff_t;
/*! @brief Forward iterator type. */
using iterator = internal::view_iterator<common_type, Checked, Get, Exclude>;
@@ -410,8 +387,8 @@ public:
}
private:
std::array<const common_type *, Get> pools{};
std::array<const common_type *, Exclude> filter{};
stl::array<const common_type *, Get> pools{};
stl::array<const common_type *, Exclude> filter{};
const common_type *placeholder{internal::view_placeholder<common_type>()};
size_type index{Get};
};
@@ -429,61 +406,57 @@ private:
* @tparam Exclude Types of storage used to filter the view.
*/
template<typename... Get, typename... Exclude>
class basic_view<get_t<Get...>, exclude_t<Exclude...>, std::enable_if_t<(sizeof...(Get) != 0u)>>
: public basic_common_view<std::common_type_t<typename Get::base_type...>, internal::tombstone_check_v<Get...>, sizeof...(Get), sizeof...(Exclude)> {
using base_type = basic_common_view<std::common_type_t<typename Get::base_type...>, internal::tombstone_check_v<Get...>, sizeof...(Get), sizeof...(Exclude)>;
requires (sizeof...(Get) != 0u)
class basic_view<get_t<Get...>, exclude_t<Exclude...>>
: public basic_common_view<stl::common_type_t<typename Get::base_type...>, internal::tombstone_check_v<Get...>, sizeof...(Get), sizeof...(Exclude)> {
using base_type = basic_common_view<stl::common_type_t<typename Get::base_type...>, internal::tombstone_check_v<Get...>, sizeof...(Get), sizeof...(Exclude)>;
template<std::size_t Index>
template<stl::size_t Index>
using element_at = type_list_element_t<Index, type_list<Get..., Exclude...>>;
template<typename Type>
static constexpr std::size_t index_of = type_list_index_v<std::remove_const_t<Type>, type_list<typename Get::element_type..., typename Exclude::element_type...>>;
static constexpr stl::size_t index_of = type_list_index_v<stl::remove_const_t<Type>, type_list<typename Get::element_type..., typename Exclude::element_type...>>;
template<std::size_t... Index>
[[nodiscard]] auto get(const typename base_type::entity_type entt, std::index_sequence<Index...>) const noexcept {
return std::tuple_cat(storage<Index>()->get_as_tuple(entt)...);
}
template<std::size_t Curr, std::size_t Other, typename... Args>
[[nodiscard]] auto dispatch_get(const std::tuple<typename base_type::entity_type, Args...> &curr) const {
template<stl::size_t Curr, stl::size_t Other, typename... Args>
[[nodiscard]] auto dispatch_get(const stl::tuple<typename base_type::entity_type, Args...> &curr) const {
if constexpr(Curr == Other) {
return std::forward_as_tuple(std::get<Args>(curr)...);
return stl::forward_as_tuple(stl::get<Args>(curr)...);
} else {
return storage<Other>()->get_as_tuple(std::get<0>(curr));
return storage<Other>()->get_as_tuple(stl::get<0>(curr));
}
}
template<std::size_t Curr, typename Func, std::size_t... Index>
void each(Func &func, std::index_sequence<Index...>) const {
template<stl::size_t Curr, typename Func, stl::size_t... Index>
void each(Func func, stl::index_sequence<Index...>) const {
for(const auto curr: storage<Curr>()->each()) {
if(const auto entt = std::get<0>(curr); (!internal::tombstone_check_v<Get...> || (entt != tombstone)) && ((Curr == Index || base_type::pool_at(Index)->contains(entt)) && ...) && base_type::none_of(entt)) {
if constexpr(is_applicable_v<Func, decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_view>().get({})))>) {
std::apply(func, std::tuple_cat(std::make_tuple(entt), dispatch_get<Curr, Index>(curr)...));
if(const auto entt = stl::get<0>(curr); (!internal::tombstone_check_v<Get...> || (entt != tombstone)) && ((Curr == Index || base_type::pool_at(Index)->contains(entt)) && ...) && base_type::none_of(entt)) {
if constexpr(is_applicable_v<Func, decltype(stl::tuple_cat(stl::tuple<entity_type>{}, stl::declval<basic_view>().get({})))>) {
stl::apply(func, stl::tuple_cat(stl::make_tuple(entt), dispatch_get<Curr, Index>(curr)...));
} else {
std::apply(func, std::tuple_cat(dispatch_get<Curr, Index>(curr)...));
stl::apply(func, stl::tuple_cat(dispatch_get<Curr, Index>(curr)...));
}
}
}
}
template<typename Func, std::size_t... Index>
void pick_and_each(Func &func, std::index_sequence<Index...> seq) const {
if(const auto *view = base_type::handle(); view != nullptr) {
((view == base_type::pool_at(Index) ? each<Index>(func, seq) : void()), ...);
template<typename Type>
void storage_if(Type *elem) noexcept {
if(elem != nullptr) {
storage<index_of<typename Type::element_type>>(*elem);
}
}
public:
/*! @brief Common type among all storage types. */
using common_type = typename base_type::common_type;
using common_type = base_type::common_type;
/*! @brief Underlying entity identifier. */
using entity_type = typename base_type::entity_type;
using entity_type = base_type::entity_type;
/*! @brief Unsigned integer type. */
using size_type = typename base_type::size_type;
using size_type = base_type::size_type;
/*! @brief Signed integer type. */
using difference_type = std::ptrdiff_t;
using difference_type = stl::ptrdiff_t;
/*! @brief Forward iterator type. */
using iterator = typename base_type::iterator;
using iterator = base_type::iterator;
/*! @brief Iterable view type. */
using iterable = iterable_adaptor<internal::extended_view_iterator<iterator, Get...>>;
@@ -505,8 +478,21 @@ public:
* @param value The storage for the types to iterate.
* @param excl The storage for the types used to filter the view.
*/
basic_view(std::tuple<Get &...> value, std::tuple<Exclude &...> excl = {}) noexcept
: basic_view{std::make_from_tuple<basic_view>(std::tuple_cat(value, excl))} {}
basic_view(stl::tuple<Get &...> value, stl::tuple<Exclude &...> excl = {}) noexcept
: basic_view{stl::make_from_tuple<basic_view>(stl::tuple_cat(value, excl))} {}
/**
* @brief Constructs a view from a convertible counterpart.
* @tparam Args Storage types managed by the other view.
* @param other A view to convert from.
*/
template<typename... Args>
requires (!stl::same_as<basic_view, basic_view<Args...>>)
basic_view(const basic_view<Args...> &other) noexcept
: basic_view{} {
(storage_if(other.template storage<typename Get::element_type>()), ...);
(storage_if(other.template storage<typename Exclude::element_type>()), ...);
}
/**
* @brief Forces a view to use a given element to drive iterations
@@ -521,7 +507,7 @@ public:
* @brief Forces a view to use a given element to drive iterations
* @tparam Index Index of the element to use to drive iterations.
*/
template<std::size_t Index>
template<stl::size_t Index>
void use() noexcept {
base_type::use(Index);
}
@@ -541,7 +527,7 @@ public:
* @tparam Index Index of the storage to return.
* @return The storage for the given index.
*/
template<std::size_t Index>
template<stl::size_t Index>
[[nodiscard]] auto *storage() const noexcept {
if constexpr(Index < sizeof...(Get)) {
return static_cast<element_at<Index> *>(const_cast<constness_as_t<common_type, element_at<Index>> *>(base_type::pool_at(Index)));
@@ -566,9 +552,9 @@ public:
* @tparam Type Type of storage to assign to the view.
* @param elem A storage to assign to the view.
*/
template<std::size_t Index, typename Type>
template<stl::size_t Index, typename Type>
void storage(Type &elem) noexcept {
static_assert(std::is_convertible_v<Type &, element_at<Index> &>, "Unexpected type");
static_assert(stl::is_convertible_v<Type &, element_at<Index> &>, "Unexpected type");
if constexpr(Index < sizeof...(Get)) {
base_type::pool_at(Index, &elem);
@@ -604,14 +590,16 @@ public:
* @param entt A valid identifier.
* @return The elements assigned to the entity.
*/
template<std::size_t... Index>
template<stl::size_t... Index>
[[nodiscard]] decltype(auto) get(const entity_type entt) const {
if constexpr(sizeof...(Index) == 0) {
return get(entt, std::index_sequence_for<Get...>{});
return [this, entt]<auto... Idx>(stl::index_sequence<Idx...>) {
return stl::tuple_cat(this->storage<Idx>()->get_as_tuple(entt)...);
}(stl::index_sequence_for<Get...>{});
} else if constexpr(sizeof...(Index) == 1) {
return (storage<Index>()->get(entt), ...);
} else {
return std::tuple_cat(storage<Index>()->get_as_tuple(entt)...);
return stl::tuple_cat(storage<Index>()->get_as_tuple(entt)...);
}
}
@@ -632,7 +620,11 @@ public:
*/
template<typename Func>
void each(Func func) const {
pick_and_each(func, std::index_sequence_for<Get...>{});
[this, &func]<auto... Index>(stl::index_sequence<Index...> seq) {
if(const auto *view = base_type::handle(); view != nullptr) {
((view == base_type::pool_at(Index) ? each<Index>(stl::move(func), seq) : void()), ...);
}
}(stl::index_sequence_for<Get...>{});
}
/**
@@ -654,8 +646,8 @@ public:
* @param other The storage for the type to combine the view with.
* @return A more specific view.
*/
template<typename OGet>
[[nodiscard]] std::enable_if_t<std::is_base_of_v<common_type, OGet>, basic_view<get_t<Get..., OGet>, exclude_t<Exclude...>>> operator|(OGet &other) const noexcept {
template<stl::derived_from<common_type> OGet>
[[nodiscard]] basic_view<get_t<Get..., OGet>, exclude_t<Exclude...>> operator|(OGet &other) const noexcept {
return *this | basic_view<get_t<OGet>, exclude_t<>>{other};
}
@@ -666,10 +658,10 @@ public:
* @param other The view to combine with.
* @return A more specific view.
*/
template<typename... OGet, typename... OExclude>
template<stl::derived_from<common_type>... OGet, stl::derived_from<common_type>... OExclude>
[[nodiscard]] auto operator|(const basic_view<get_t<OGet...>, exclude_t<OExclude...>> &other) const noexcept {
return internal::view_pack<basic_view<get_t<Get..., OGet...>, exclude_t<Exclude..., OExclude...>>>(
*this, other, std::index_sequence_for<Get...>{}, std::index_sequence_for<Exclude...>{}, std::index_sequence_for<OGet...>{}, std::index_sequence_for<OExclude...>{});
*this, other, stl::index_sequence_for<Get...>{}, stl::index_sequence_for<Exclude...>{}, stl::index_sequence_for<OGet...>{}, stl::index_sequence_for<OExclude...>{});
}
};
@@ -679,12 +671,10 @@ public:
* @tparam Type Common type among all storage types.
* @tparam Policy Storage policy.
*/
template<typename Type, deletion_policy Policy>
template<cvref_unqualified Type, deletion_policy Policy>
class basic_storage_view {
static_assert(std::is_same_v<std::remove_const_t<std::remove_reference_t<Type>>, Type>, "Unexpected type");
protected:
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
basic_storage_view() noexcept = default;
basic_storage_view(const Type *value) noexcept
@@ -697,15 +687,15 @@ public:
/*! @brief Common type among all storage types. */
using common_type = Type;
/*! @brief Underlying entity identifier. */
using entity_type = typename common_type::entity_type;
using entity_type = common_type::entity_type;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
using size_type = stl::size_t;
/*! @brief Signed integer type. */
using difference_type = std::ptrdiff_t;
using difference_type = stl::ptrdiff_t;
/*! @brief Random access iterator type. */
using iterator = std::conditional_t<Policy == deletion_policy::in_place, internal::view_iterator<common_type, true, 1u, 0u>, typename common_type::iterator>;
using iterator = stl::conditional_t<Policy == deletion_policy::in_place, internal::view_iterator<common_type, true, 1u, 0u>, typename common_type::iterator>;
/*! @brief Reverse iterator type. */
using reverse_iterator = std::conditional_t<Policy == deletion_policy::in_place, void, typename common_type::reverse_iterator>;
using reverse_iterator = stl::conditional_t<Policy == deletion_policy::in_place, void, typename common_type::reverse_iterator>;
/**
* @brief Returns the leading storage of a view, if any.
@@ -717,11 +707,10 @@ public:
/**
* @brief Returns the number of entities that have the given element.
* @tparam Pol Dummy template parameter used for sfinae purposes only.
* @return Number of entities that have the given element.
*/
template<typename..., deletion_policy Pol = Policy>
[[nodiscard]] std::enable_if_t<Pol != deletion_policy::in_place, size_type> size() const noexcept {
[[nodiscard]] size_type size() const noexcept
requires (Policy != deletion_policy::in_place) {
if constexpr(Policy == deletion_policy::swap_and_pop) {
return leading ? leading->size() : size_type{};
} else {
@@ -732,21 +721,19 @@ public:
/**
* @brief Estimates the number of entities iterated by the view.
* @tparam Pol Dummy template parameter used for sfinae purposes only.
* @return Estimated number of entities iterated by the view.
*/
template<typename..., deletion_policy Pol = Policy>
[[nodiscard]] std::enable_if_t<Pol == deletion_policy::in_place, size_type> size_hint() const noexcept {
[[nodiscard]] size_type size_hint() const noexcept
requires (Policy == deletion_policy::in_place) {
return leading ? leading->size() : size_type{};
}
/**
* @brief Checks whether a view is empty.
* @tparam Pol Dummy template parameter used for sfinae purposes only.
* @return True if the view is empty, false otherwise.
*/
template<typename..., deletion_policy Pol = Policy>
[[nodiscard]] std::enable_if_t<Pol != deletion_policy::in_place, bool> empty() const noexcept {
[[nodiscard]] bool empty() const noexcept
requires (Policy != deletion_policy::in_place) {
if constexpr(Policy == deletion_policy::swap_and_pop) {
return !leading || leading->empty();
} else {
@@ -791,23 +778,21 @@ public:
*
* If the view is empty, the returned iterator will be equal to `rend()`.
*
* @tparam Pol Dummy template parameter used for sfinae purposes only.
* @return An iterator to the first entity of the reversed view.
*/
template<typename..., deletion_policy Pol = Policy>
[[nodiscard]] std::enable_if_t<Pol != deletion_policy::in_place, reverse_iterator> rbegin() const noexcept {
[[nodiscard]] reverse_iterator rbegin() const noexcept
requires (Policy != deletion_policy::in_place) {
return leading ? leading->rbegin() : reverse_iterator{};
}
/**
* @brief Returns an iterator that is past the last entity of the reversed
* view.
* @tparam Pol Dummy template parameter used for sfinae purposes only.
* @return An iterator to the entity following the last entity of the
* reversed view.
*/
template<typename..., deletion_policy Pol = Policy>
[[nodiscard]] std::enable_if_t<Pol != deletion_policy::in_place, reverse_iterator> rend() const noexcept {
[[nodiscard]] reverse_iterator rend() const noexcept
requires (Policy != deletion_policy::in_place) {
if constexpr(Policy == deletion_policy::swap_and_pop) {
return leading ? leading->rend() : reverse_iterator{};
} else {
@@ -913,21 +898,27 @@ class basic_view<get_t<Get>, exclude_t<>>
: public basic_storage_view<typename Get::base_type, Get::storage_policy> {
using base_type = basic_storage_view<typename Get::base_type, Get::storage_policy>;
void storage_if(Get *value) noexcept {
if(value != nullptr) {
storage(*value);
}
}
public:
/*! @brief Common type among all storage types. */
using common_type = typename base_type::common_type;
using common_type = base_type::common_type;
/*! @brief Underlying entity identifier. */
using entity_type = typename base_type::entity_type;
using entity_type = base_type::entity_type;
/*! @brief Unsigned integer type. */
using size_type = typename base_type::size_type;
using size_type = base_type::size_type;
/*! @brief Signed integer type. */
using difference_type = std::ptrdiff_t;
using difference_type = stl::ptrdiff_t;
/*! @brief Random access iterator type. */
using iterator = typename base_type::iterator;
using iterator = base_type::iterator;
/*! @brief Reverse iterator type. */
using reverse_iterator = typename base_type::reverse_iterator;
using reverse_iterator = base_type::reverse_iterator;
/*! @brief Iterable view type. */
using iterable = std::conditional_t<Get::storage_policy == deletion_policy::in_place, iterable_adaptor<internal::extended_view_iterator<iterator, Get>>, decltype(std::declval<Get>().each())>;
using iterable = stl::conditional_t<Get::storage_policy == deletion_policy::in_place, iterable_adaptor<internal::extended_view_iterator<iterator, Get>>, decltype(stl::declval<Get>().each())>;
/*! @brief Default constructor to use to create empty, invalid views. */
basic_view() noexcept
@@ -945,17 +936,29 @@ public:
* @brief Constructs a view from a storage class.
* @param value The storage for the type to iterate.
*/
basic_view(std::tuple<Get &> value, std::tuple<> = {}) noexcept
: basic_view{std::get<0>(value)} {}
basic_view(stl::tuple<Get &> value, stl::tuple<> = {}) noexcept
: basic_view{stl::get<0>(value)} {}
/**
* @brief Constructs a view from a convertible counterpart.
* @tparam Args Storage types managed by the other view.
* @param other A view to convert from.
*/
template<typename... Args>
requires (!stl::same_as<basic_view, basic_view<Args...>>)
basic_view(const basic_view<Args...> &other) noexcept
: base_type{} {
storage_if(other.template storage<typename Get::element_type>());
}
/**
* @brief Returns the storage for a given element type, if any.
* @tparam Type Type of element of which to return the storage.
* @return The storage for the given element type.
*/
template<typename Type = typename Get::element_type>
template<typename Type = Get::element_type>
[[nodiscard]] auto *storage() const noexcept {
static_assert(std::is_same_v<std::remove_const_t<Type>, typename Get::element_type>, "Invalid element type");
static_assert(stl::is_same_v<stl::remove_const_t<Type>, typename Get::element_type>, "Invalid element type");
return storage<0>();
}
@@ -964,7 +967,7 @@ public:
* @tparam Index Index of the storage to return.
* @return The storage for the given index.
*/
template<std::size_t Index>
template<stl::size_t Index>
[[nodiscard]] auto *storage() const noexcept {
static_assert(Index == 0u, "Index out of bounds");
return static_cast<Get *>(const_cast<constness_as_t<common_type, Get> *>(base_type::handle()));
@@ -983,7 +986,7 @@ public:
* @tparam Index Index of the storage to assign to the view.
* @param elem A storage to assign to the view.
*/
template<std::size_t Index>
template<stl::size_t Index>
void storage(Get &elem) noexcept {
static_assert(Index == 0u, "Index out of bounds");
*this = basic_view{elem};
@@ -1014,7 +1017,7 @@ public:
*/
template<typename Elem>
[[nodiscard]] decltype(auto) get(const entity_type entt) const {
static_assert(std::is_same_v<std::remove_const_t<Elem>, typename Get::element_type>, "Invalid element type");
static_assert(stl::is_same_v<stl::remove_const_t<Elem>, typename Get::element_type>, "Invalid element type");
return get<0>(entt);
}
@@ -1024,7 +1027,7 @@ public:
* @param entt A valid identifier.
* @return The element assigned to the entity.
*/
template<std::size_t... Index>
template<stl::size_t... Index>
[[nodiscard]] decltype(auto) get(const entity_type entt) const {
if constexpr(sizeof...(Index) == 0) {
return storage()->get_as_tuple(entt);
@@ -1042,7 +1045,7 @@ public:
*
* @code{.cpp}
* void(const entity_type, Type &);
* void(typename Type &);
* void(Type &);
* @endcode
*
* @tparam Func Type of the function object to invoke.
@@ -1050,12 +1053,12 @@ public:
*/
template<typename Func>
void each(Func func) const {
if constexpr(is_applicable_v<Func, decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_view>().get({})))>) {
if constexpr(is_applicable_v<Func, decltype(stl::tuple_cat(stl::tuple<entity_type>{}, stl::declval<basic_view>().get({})))>) {
for(const auto pack: each()) {
std::apply(func, pack);
stl::apply(func, pack);
}
} else if constexpr(Get::storage_policy == deletion_policy::swap_and_pop || Get::storage_policy == deletion_policy::swap_only) {
if constexpr(std::is_void_v<typename Get::value_type>) {
if constexpr(stl::is_void_v<typename Get::value_type>) {
for(size_type pos = base_type::size(); pos; --pos) {
func();
}
@@ -1070,7 +1073,7 @@ public:
static_assert(Get::storage_policy == deletion_policy::in_place, "Unexpected storage policy");
for(const auto pack: each()) {
std::apply([&func](const auto, auto &&...elem) { func(std::forward<decltype(elem)>(elem)...); }, pack);
stl::apply([&func](const auto, auto &&...elem) { func(stl::forward<decltype(elem)>(elem)...); }, pack);
}
}
}
@@ -1099,8 +1102,8 @@ public:
* @param other The storage for the type to combine the view with.
* @return A more specific view.
*/
template<typename OGet>
[[nodiscard]] std::enable_if_t<std::is_base_of_v<common_type, OGet>, basic_view<get_t<Get, OGet>, exclude_t<>>> operator|(OGet &other) const noexcept {
template<stl::derived_from<common_type> OGet>
[[nodiscard]] basic_view<get_t<Get, OGet>, exclude_t<>> operator|(OGet &other) const noexcept {
return *this | basic_view<get_t<OGet>, exclude_t<>>{other};
}
@@ -1111,10 +1114,10 @@ public:
* @param other The view to combine with.
* @return A more specific view.
*/
template<typename... OGet, typename... OExclude>
template<stl::derived_from<common_type>... OGet, stl::derived_from<common_type>... OExclude>
[[nodiscard]] auto operator|(const basic_view<get_t<OGet...>, exclude_t<OExclude...>> &other) const noexcept {
return internal::view_pack<basic_view<get_t<Get, OGet...>, exclude_t<OExclude...>>>(
*this, other, std::index_sequence_for<Get>{}, std::index_sequence_for<>{}, std::index_sequence_for<OGet...>{}, std::index_sequence_for<OExclude...>{});
*this, other, stl::index_sequence_for<Get>{}, stl::index_sequence_for<>{}, stl::index_sequence_for<OGet...>{}, stl::index_sequence_for<OExclude...>{});
}
};
@@ -1132,7 +1135,7 @@ basic_view(Type &...storage) -> basic_view<get_t<Type...>, exclude_t<>>;
* @tparam Exclude Types of elements used to filter the view.
*/
template<typename... Get, typename... Exclude>
basic_view(std::tuple<Get &...>, std::tuple<Exclude &...> = {}) -> basic_view<get_t<Get...>, exclude_t<Exclude...>>;
basic_view(stl::tuple<Get &...>, stl::tuple<Exclude &...> = {}) -> basic_view<get_t<Get...>, exclude_t<Exclude...>>;
} // namespace entt

View File

@@ -1,6 +1,9 @@
/*! @brief `EnTT` default namespace. */
namespace entt {}
/*! @brief Custom `EnTT` namespace for the standard template library. */
namespace entt::stl {}
// IWYU pragma: begin_exports
#include "config/config.h"
#include "config/macro.h"
@@ -12,6 +15,7 @@ namespace entt {}
#include "core/any.hpp"
#include "core/bit.hpp"
#include "core/compressed_pair.hpp"
#include "core/concepts.hpp"
#include "core/enum.hpp"
#include "core/family.hpp"
#include "core/hashed_string.hpp"
@@ -65,4 +69,25 @@ namespace entt {}
#include "signal/dispatcher.hpp"
#include "signal/emitter.hpp"
#include "signal/sigh.hpp"
#include "stl/algorithm.hpp"
#include "stl/array.hpp"
#include "stl/atomic.hpp"
#include "stl/bit.hpp"
#include "stl/cmath.hpp"
#include "stl/concepts.hpp"
#include "stl/cstddef.hpp"
#include "stl/cstdint.hpp"
#include "stl/functional.hpp"
#include "stl/ios.hpp"
#include "stl/iterator.hpp"
#include "stl/limits.hpp"
#include "stl/memory.hpp"
#include "stl/ostream.hpp"
#include "stl/sstream.hpp"
#include "stl/string.hpp"
#include "stl/string_view.hpp"
#include "stl/tuple.hpp"
#include "stl/type_traits.hpp"
#include "stl/utility.hpp"
#include "stl/vector.hpp"
// IWYU pragma: end_exports

View File

@@ -1,42 +1,43 @@
#ifndef ENTT_GRAPH_ADJACENCY_MATRIX_HPP
#define ENTT_GRAPH_ADJACENCY_MATRIX_HPP
#include <cstddef>
#include <iterator>
#include <memory>
#include <type_traits>
#include <utility>
#include <vector>
#include "../config/config.h"
#include "../core/iterator.hpp"
#include "../stl/concepts.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/iterator.hpp"
#include "../stl/memory.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "../stl/vector.hpp"
#include "fwd.hpp"
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
template<typename It>
class edge_iterator {
using size_type = std::size_t;
using size_type = stl::size_t;
void find_next() noexcept {
for(; pos != last && !it[static_cast<typename It::difference_type>(pos)]; pos += offset) {}
for(; pos != last && !it[static_cast<It::difference_type>(pos)]; pos += offset) {}
}
public:
using value_type = std::pair<size_type, size_type>;
using value_type = stl::pair<size_type, size_type>;
using pointer = input_iterator_pointer<value_type>;
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category = std::input_iterator_tag;
using iterator_concept = std::forward_iterator_tag;
using difference_type = stl::ptrdiff_t;
using iterator_category = stl::input_iterator_tag;
using iterator_concept = stl::forward_iterator_tag;
constexpr edge_iterator() noexcept = default;
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
constexpr edge_iterator(It base, const size_type vertices, const size_type from, const size_type to, const size_type step) noexcept
: it{std::move(base)},
: it{stl::move(base)},
vert{vertices},
pos{from},
last{to},
@@ -60,11 +61,12 @@ public:
}
[[nodiscard]] constexpr pointer operator->() const noexcept {
return std::make_pair<size_type>(pos / vert, pos % vert);
return stl::make_pair<size_type>(pos / vert, pos % vert);
}
template<typename Type>
friend constexpr bool operator==(const edge_iterator<Type> &, const edge_iterator<Type> &) noexcept;
[[nodiscard]] constexpr bool operator==(const edge_iterator &other) const noexcept {
return pos == other.pos;
}
private:
It it{};
@@ -74,16 +76,6 @@ private:
size_type offset{};
};
template<typename Container>
[[nodiscard]] constexpr bool operator==(const edge_iterator<Container> &lhs, const edge_iterator<Container> &rhs) noexcept {
return lhs.pos == rhs.pos;
}
template<typename Container>
[[nodiscard]] constexpr bool operator!=(const edge_iterator<Container> &lhs, const edge_iterator<Container> &rhs) noexcept {
return !(lhs == rhs);
}
} // namespace internal
/*! @endcond */
@@ -92,22 +84,21 @@ template<typename Container>
* @tparam Category Either a directed or undirected category tag.
* @tparam Allocator Type of allocator used to manage memory and elements.
*/
template<typename Category, typename Allocator>
template<stl::derived_from<directed_tag> Category, typename Allocator>
class adjacency_matrix {
using alloc_traits = std::allocator_traits<Allocator>;
static_assert(std::is_base_of_v<directed_tag, Category>, "Invalid graph category");
static_assert(std::is_same_v<typename alloc_traits::value_type, std::size_t>, "Invalid value type");
using container_type = std::vector<std::size_t, typename alloc_traits::template rebind_alloc<std::size_t>>;
using alloc_traits = stl::allocator_traits<Allocator>;
static_assert(stl::is_same_v<typename alloc_traits::value_type, stl::size_t>, "Invalid value type");
using container_type = stl::vector<stl::size_t, typename alloc_traits::template rebind_alloc<stl::size_t>>;
public:
/*! @brief Allocator type. */
using allocator_type = Allocator;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
using size_type = stl::size_t;
/*! @brief Vertex type. */
using vertex_type = size_type;
/*! @brief Edge type. */
using edge_type = std::pair<vertex_type, vertex_type>;
using edge_type = stl::pair<vertex_type, vertex_type>;
/*! @brief Vertex iterator type. */
using vertex_iterator = iota_iterator<vertex_type>;
/*! @brief Edge iterator type. */
@@ -162,7 +153,7 @@ public:
* @param allocator The allocator to use.
*/
adjacency_matrix(adjacency_matrix &&other, const allocator_type &allocator)
: matrix{std::move(other.matrix), allocator},
: matrix{stl::move(other.matrix), allocator},
vert{other.vert} {}
/*! @brief Default destructor. */
@@ -185,7 +176,7 @@ public:
* @param other Adjacency matrix to exchange the content with.
*/
void swap(adjacency_matrix &other) noexcept {
using std::swap;
using stl::swap;
swap(matrix, other.matrix);
swap(vert, other.vert);
}
@@ -289,16 +280,16 @@ public:
* the element that prevented the insertion) and a bool denoting whether the
* insertion took place.
*/
std::pair<edge_iterator, bool> insert(const vertex_type lhs, const vertex_type rhs) {
stl::pair<edge_iterator, bool> insert(const vertex_type lhs, const vertex_type rhs) {
const auto pos = lhs * vert + rhs;
if constexpr(std::is_same_v<graph_category, undirected_tag>) {
if constexpr(stl::is_same_v<graph_category, undirected_tag>) {
const auto rev = rhs * vert + lhs;
ENTT_ASSERT(matrix[pos] == matrix[rev], "Something went really wrong");
matrix[rev] = 1u;
}
const auto inserted = !std::exchange(matrix[pos], 1u);
const auto inserted = !stl::exchange(matrix[pos], 1u);
return {edge_iterator{matrix.cbegin(), vert, pos, matrix.size(), 1u}, inserted};
}
@@ -311,13 +302,13 @@ public:
size_type erase(const vertex_type lhs, const vertex_type rhs) {
const auto pos = lhs * vert + rhs;
if constexpr(std::is_same_v<graph_category, undirected_tag>) {
if constexpr(stl::is_same_v<graph_category, undirected_tag>) {
const auto rev = rhs * vert + lhs;
ENTT_ASSERT(matrix[pos] == matrix[rev], "Something went really wrong");
matrix[rev] = 0u;
}
return std::exchange(matrix[pos], 0u);
return stl::exchange(matrix[pos], 0u);
}
/**

View File

@@ -1,8 +1,8 @@
#ifndef ENTT_GRAPH_DOT_HPP
#define ENTT_GRAPH_DOT_HPP
#include <ostream>
#include <type_traits>
#include "../stl/concepts.hpp"
#include "../stl/ostream.hpp"
#include "fwd.hpp"
namespace entt {
@@ -10,16 +10,14 @@ namespace entt {
/**
* @brief Outputs a graph in dot format.
* @tparam Graph Graph type, valid as long as it exposes edges and vertices.
* @tparam Writer Vertex decorator type.
* @param out A standard output stream.
* @param graph The graph to output.
* @param writer Vertex decorator object.
*/
template<typename Graph, typename Writer>
void dot(std::ostream &out, const Graph &graph, Writer writer) {
static_assert(std::is_base_of_v<directed_tag, typename Graph::graph_category>, "Invalid graph category");
if constexpr(std::is_same_v<typename Graph::graph_category, undirected_tag>) {
template<typename Graph>
requires stl::derived_from<typename Graph::graph_category, directed_tag>
void dot(stl::ostream &out, const Graph &graph, stl::invocable<stl::ostream &, typename Graph::vertex_type> auto writer) {
if constexpr(stl::same_as<typename Graph::graph_category, undirected_tag>) {
out << "graph{";
} else {
out << "digraph{";
@@ -32,7 +30,7 @@ void dot(std::ostream &out, const Graph &graph, Writer writer) {
}
for(auto [lhs, rhs]: graph.edges()) {
if constexpr(std::is_same_v<typename Graph::graph_category, undirected_tag>) {
if constexpr(stl::same_as<typename Graph::graph_category, undirected_tag>) {
out << lhs << "--" << rhs << ";";
} else {
out << lhs << "->" << rhs << ";";
@@ -49,7 +47,7 @@ void dot(std::ostream &out, const Graph &graph, Writer writer) {
* @param graph The graph to output.
*/
template<typename Graph>
void dot(std::ostream &out, const Graph &graph) {
void dot(stl::ostream &out, const Graph &graph) {
return dot(out, graph, [](auto &&...) {});
}

View File

@@ -1,21 +1,21 @@
#ifndef ENTT_GRAPH_FLOW_HPP
#define ENTT_GRAPH_FLOW_HPP
#include <algorithm>
#include <cstddef>
#include <functional>
#include <iterator>
#include <memory>
#include <type_traits>
#include <utility>
#include <vector>
#include "../config/config.h"
#include "../container/dense_map.hpp"
#include "../container/dense_set.hpp"
#include "../core/compressed_pair.hpp"
#include "../core/fwd.hpp"
#include "../core/iterator.hpp"
#include "../core/utility.hpp"
#include "../stl/algorithm.hpp"
#include "../stl/concepts.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/functional.hpp"
#include "../stl/iterator.hpp"
#include "../stl/memory.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "../stl/vector.hpp"
#include "adjacency_matrix.hpp"
#include "fwd.hpp"
@@ -27,12 +27,12 @@ namespace entt {
*/
template<typename Allocator>
class basic_flow {
using alloc_traits = std::allocator_traits<Allocator>;
static_assert(std::is_same_v<typename alloc_traits::value_type, id_type>, "Invalid value type");
using task_container_type = dense_set<id_type, identity, std::equal_to<>, typename alloc_traits::template rebind_alloc<id_type>>;
using ro_rw_container_type = std::vector<std::pair<std::size_t, bool>, typename alloc_traits::template rebind_alloc<std::pair<std::size_t, bool>>>;
using deps_container_type = dense_map<id_type, ro_rw_container_type, identity, std::equal_to<>, typename alloc_traits::template rebind_alloc<std::pair<const id_type, ro_rw_container_type>>>;
using adjacency_matrix_type = adjacency_matrix<directed_tag, typename alloc_traits::template rebind_alloc<std::size_t>>;
using alloc_traits = stl::allocator_traits<Allocator>;
static_assert(stl::is_same_v<typename alloc_traits::value_type, id_type>, "Invalid value type");
using task_container_type = dense_set<id_type, stl::identity, stl::equal_to<>, typename alloc_traits::template rebind_alloc<id_type>>;
using ro_rw_container_type = stl::vector<stl::pair<stl::size_t, bool>, typename alloc_traits::template rebind_alloc<stl::pair<stl::size_t, bool>>>;
using deps_container_type = dense_map<id_type, ro_rw_container_type, stl::identity, stl::equal_to<>, typename alloc_traits::template rebind_alloc<stl::pair<const id_type, ro_rw_container_type>>>;
using adjacency_matrix_type = adjacency_matrix<directed_tag, typename alloc_traits::template rebind_alloc<stl::size_t>>;
void emplace(const id_type res, const bool is_rw) {
ENTT_ASSERT(index.first() < vertices.size(), "Invalid node");
@@ -55,7 +55,7 @@ class basic_flow {
if(auto curr = it++; it != last) {
if(it->second) {
matrix.insert(curr->first, it->first);
} else if(const auto next = std::find_if(it, last, [](const auto &value) { return value.second; }); next != last) {
} else if(const auto next = stl::find_if(it, last, [](const auto &value) { return value.second; }); next != last) {
for(; it != next; ++it) {
matrix.insert(curr->first, it->first);
matrix.insert(it->first, next->first);
@@ -68,7 +68,7 @@ class basic_flow {
}
} else {
// ro item (first iteration only)
if(const auto next = std::find_if(it, last, [](const auto &value) { return value.second; }); next != last) {
if(const auto next = stl::find_if(it, last, [](const auto &value) { return value.second; }); next != last) {
for(; it != next; ++it) {
matrix.insert(it->first, next->first);
}
@@ -83,9 +83,9 @@ class basic_flow {
void transitive_closure(adjacency_matrix_type &matrix) const {
const auto length = matrix.size();
for(std::size_t vk{}; vk < length; ++vk) {
for(std::size_t vi{}; vi < length; ++vi) {
for(std::size_t vj{}; vj < length; ++vj) {
for(stl::size_t vk{}; vk < length; ++vk) {
for(stl::size_t vi{}; vi < length; ++vi) {
for(stl::size_t vj{}; vj < length; ++vj) {
if(matrix.contains(vi, vk) && matrix.contains(vk, vj)) {
matrix.insert(vi, vj);
}
@@ -97,14 +97,14 @@ class basic_flow {
void transitive_reduction(adjacency_matrix_type &matrix) const {
const auto length = matrix.size();
for(std::size_t vert{}; vert < length; ++vert) {
for(stl::size_t vert{}; vert < length; ++vert) {
matrix.erase(vert, vert);
}
for(std::size_t vj{}; vj < length; ++vj) {
for(std::size_t vi{}; vi < length; ++vi) {
for(stl::size_t vj{}; vj < length; ++vj) {
for(stl::size_t vi{}; vi < length; ++vi) {
if(matrix.contains(vi, vj)) {
for(std::size_t vk{}; vk < length; ++vk) {
for(stl::size_t vk{}; vk < length; ++vk) {
if(matrix.contains(vj, vk)) {
matrix.erase(vi, vk);
}
@@ -118,7 +118,7 @@ public:
/*! @brief Allocator type. */
using allocator_type = Allocator;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
using size_type = stl::size_t;
/*! @brief Iterable task list. */
using iterable = iterable_adaptor<typename task_container_type::const_iterator>;
/*! @brief Adjacency matrix type. */
@@ -161,8 +161,8 @@ public:
*/
basic_flow(basic_flow &&other, const allocator_type &allocator)
: index{other.index.first(), allocator},
vertices{std::move(other.vertices), allocator},
deps{std::move(other.deps), allocator},
vertices{stl::move(other.vertices), allocator},
deps{stl::move(other.deps), allocator},
sync_on{other.sync_on} {}
/*! @brief Default destructor. */
@@ -185,11 +185,11 @@ public:
* @param other Flow builder to exchange the content with.
*/
void swap(basic_flow &other) noexcept {
using std::swap;
std::swap(index, other.index);
std::swap(vertices, other.vertices);
std::swap(deps, other.deps);
std::swap(sync_on, other.sync_on);
using stl::swap;
swap(index, other.index);
swap(vertices, other.vertices);
swap(deps, other.deps);
swap(sync_on, other.sync_on);
}
/**
@@ -206,7 +206,7 @@ public:
* @return The requested identifier.
*/
[[nodiscard]] id_type operator[](const size_type pos) const {
return vertices.cbegin()[static_cast<typename task_container_type::difference_type>(pos)];
return vertices.cbegin()[static_cast<task_container_type::difference_type>(pos)];
}
/*! @brief Clears the flow builder. */
@@ -283,14 +283,11 @@ public:
/**
* @brief Assigns a range of read-only resources to the current task.
* @tparam It Type of input iterator.
* @param first An iterator to the first element of the range of elements.
* @param last An iterator past the last element of the range of elements.
* @return This flow builder.
*/
template<typename It>
std::enable_if_t<std::is_same_v<std::remove_const_t<typename std::iterator_traits<It>::value_type>, id_type>, basic_flow &>
ro(It first, It last) {
basic_flow &ro(stl::input_iterator auto first, stl::input_iterator auto last) {
for(; first != last; ++first) {
emplace(*first, false);
}
@@ -310,14 +307,11 @@ public:
/**
* @brief Assigns a range of writable resources to the current task.
* @tparam It Type of input iterator.
* @param first An iterator to the first element of the range of elements.
* @param last An iterator past the last element of the range of elements.
* @return This flow builder.
*/
template<typename It>
std::enable_if_t<std::is_same_v<std::remove_const_t<typename std::iterator_traits<It>::value_type>, id_type>, basic_flow &>
rw(It first, It last) {
basic_flow &rw(stl::input_iterator auto first, stl::input_iterator auto last) {
for(; first != last; ++first) {
emplace(*first, true);
}

View File

@@ -1,9 +1,10 @@
#ifndef ENTT_GRAPH_FWD_HPP
#define ENTT_GRAPH_FWD_HPP
#include <cstddef>
#include <memory>
#include "../core/fwd.hpp"
#include "../stl/concepts.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/memory.hpp"
namespace entt {
@@ -13,10 +14,10 @@ struct directed_tag {};
/*! @brief Directed graph category tag. */
struct undirected_tag: directed_tag {};
template<typename, typename = std::allocator<std::size_t>>
template<stl::derived_from<directed_tag>, typename = stl::allocator<stl::size_t>>
class adjacency_matrix;
template<typename = std::allocator<id_type>>
template<typename = stl::allocator<id_type>>
class basic_flow;
/*! @brief Alias declaration for the most common use case. */

View File

@@ -1,9 +1,10 @@
#ifndef ENTT_LOCATOR_LOCATOR_HPP
#define ENTT_LOCATOR_LOCATOR_HPP
#include <memory>
#include <utility>
#include "../config/config.h"
#include "../stl/concepts.hpp"
#include "../stl/memory.hpp"
#include "../stl/utility.hpp"
namespace entt {
@@ -27,7 +28,7 @@ template<typename Service>
class locator final {
class service_handle {
friend class locator<Service>;
std::shared_ptr<Service> value{};
stl::shared_ptr<Service> value{};
};
public:
@@ -84,9 +85,10 @@ public:
* @param args Parameters to use to construct the fallback service.
* @return A reference to a valid service.
*/
template<typename Type = Service, typename... Args>
template<stl::derived_from<Service> Type = Service, typename... Args>
requires stl::constructible_from<Type, Args...>
[[nodiscard]] static Service &value_or(Args &&...args) {
return service ? *service : emplace<Type>(std::forward<Args>(args)...);
return service ? *service : emplace<Type>(stl::forward<Args>(args)...);
}
/**
@@ -96,24 +98,25 @@ public:
* @param args Parameters to use to construct the service.
* @return A reference to a valid service.
*/
template<typename Type = Service, typename... Args>
template<stl::derived_from<Service> Type = Service, typename... Args>
requires stl::constructible_from<Type, Args...>
static Service &emplace(Args &&...args) {
service = std::make_shared<Type>(std::forward<Args>(args)...);
service = stl::make_shared<Type>(stl::forward<Args>(args)...);
return *service;
}
/**
* @brief Sets or replaces a service using a given allocator.
* @tparam Type Service type.
* @tparam Allocator Type of allocator used to manage memory and elements.
* @tparam Args Types of arguments to use to construct the service.
* @param alloc The allocator to use.
* @param args Parameters to use to construct the service.
* @return A reference to a valid service.
*/
template<typename Type = Service, typename Allocator, typename... Args>
static Service &emplace(std::allocator_arg_t, Allocator alloc, Args &&...args) {
service = std::allocate_shared<Type>(alloc, std::forward<Args>(args)...);
template<stl::derived_from<Service> Type = Service, typename... Args>
requires stl::constructible_from<Type, Args...>
static Service &emplace(stl::allocator_arg_t, auto alloc, Args &&...args) {
service = stl::allocate_shared<Type>(alloc, stl::forward<Args>(args)...);
return *service;
}
@@ -142,15 +145,15 @@ public:
* @param elem A pointer to a service to manage.
* @param deleter A deleter to use to destroy the service.
*/
template<typename Type, typename Deleter = std::default_delete<Type>>
template<stl::derived_from<Service> Type, typename Deleter = stl::default_delete<Type>>
static void reset(Type *elem, Deleter deleter = {}) {
service = std::shared_ptr<Service>{elem, std::move(deleter)};
service = stl::shared_ptr<Service>{elem, stl::move(deleter)};
}
private:
// std::shared_ptr because of its type erased allocator which is useful here
// stl::shared_ptr because of its type erased allocator which is useful here
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
inline static std::shared_ptr<Service> service{};
inline static stl::shared_ptr<Service> service{};
};
} // namespace entt

View File

@@ -3,20 +3,13 @@
#ifndef ENTT_META_CONTAINER_HPP
#define ENTT_META_CONTAINER_HPP
#include <array>
#include <cstddef>
#include <deque>
#include <iterator>
#include <list>
#include <map>
#include <set>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "../container/dense_map.hpp"
#include "../container/dense_set.hpp"
#include "../core/concepts.hpp"
#include "../core/type_traits.hpp"
#include "../stl/concepts.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/iterator.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "context.hpp"
#include "fwd.hpp"
#include "meta.hpp"
@@ -24,35 +17,40 @@
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
template<typename Type, typename = void>
template<typename Type>
struct sequence_container_extent: integral_constant<meta_dynamic_extent> {};
template<typename Type>
struct sequence_container_extent<Type, std::enable_if_t<is_complete_v<std::tuple_size<Type>>>>: integral_constant<std::tuple_size_v<Type>> {};
requires is_complete_v<stl::tuple_size<Type>>
struct sequence_container_extent<Type>: integral_constant<stl::tuple_size_v<Type>> {};
template<typename Type>
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 {};
inline constexpr stl::size_t sequence_container_extent_v = sequence_container_extent<Type>::value;
template<typename Type>
struct key_only_associative_container<Type, std::void_t<typename Type::mapped_type>>: std::false_type {};
concept meta_sequence_container_like = requires(Type elem) {
typename Type::value_type;
typename Type::iterator;
requires entt::stl::forward_iterator<typename Type::iterator>;
{ elem.begin() } -> stl::same_as<typename Type::iterator>;
{ elem.end() } -> stl::same_as<typename Type::iterator>;
requires !requires { typename Type::key_type; };
requires !requires { elem.substr(); };
};
template<typename Type>
inline constexpr bool key_only_associative_container_v = key_only_associative_container<Type>::value;
template<typename, typename = void>
struct reserve_aware_container: std::false_type {};
template<typename Type>
struct reserve_aware_container<Type, std::void_t<decltype(&Type::reserve)>>: std::true_type {};
template<typename Type>
inline constexpr bool reserve_aware_container_v = reserve_aware_container<Type>::value;
concept meta_associative_container_like = requires(Type value) {
typename Type::key_type;
typename Type::value_type;
typename Type::iterator;
requires entt::stl::forward_iterator<typename Type::iterator>;
{ value.begin() } -> stl::same_as<typename Type::iterator>;
{ value.end() } -> stl::same_as<typename Type::iterator>;
value.find(stl::declval<typename Type::key_type>());
};
} // namespace internal
/*! @endcond */
@@ -61,19 +59,15 @@ inline constexpr bool reserve_aware_container_v = reserve_aware_container<Type>:
* @brief General purpose implementation of meta sequence container traits.
* @tparam Type Type of underlying sequence container.
*/
template<typename Type>
template<cvref_unqualified Type>
struct basic_meta_sequence_container_traits {
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;
using size_type = meta_sequence_container::size_type;
/*! @brief Meta iterator type. */
using iterator = typename meta_sequence_container::iterator;
using iterator = meta_sequence_container::iterator;
/*! @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);
static constexpr stl::size_t extent = internal::sequence_container_extent_v<Type>;
/**
* @brief Returns the number of elements in a container.
@@ -90,7 +84,7 @@ struct basic_meta_sequence_container_traits {
* @return True in case of success, false otherwise.
*/
[[nodiscard]] static bool clear([[maybe_unused]] void *container) {
if constexpr(extent == meta_dynamic_extent) {
if constexpr(requires(Type elem) { elem.clear(); }) {
static_cast<Type *>(container)->clear();
return true;
} else {
@@ -105,7 +99,7 @@ struct basic_meta_sequence_container_traits {
* @return True in case of success, false otherwise.
*/
[[nodiscard]] static bool reserve([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) {
if constexpr(internal::reserve_aware_container_v<Type>) {
if constexpr(requires(Type elem) { elem.reserve(sz); }) {
static_cast<Type *>(container)->reserve(sz);
return true;
} else {
@@ -120,7 +114,7 @@ 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((extent == meta_dynamic_extent) && std::is_default_constructible_v<typename Type::value_type>) {
if constexpr(stl::is_default_constructible_v<typename Type::value_type> && requires(Type elem) { elem.resize(sz); }) {
static_cast<Type *>(container)->resize(sz);
return true;
} else {
@@ -156,11 +150,11 @@ 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(extent == meta_dynamic_extent) {
if constexpr(requires(Type elem, typename Type::const_iterator iter, Type::value_type instance) { elem.insert(iter, instance); }) {
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))};
(value != nullptr) ? *static_cast<const Type::value_type *>(value) : *static_cast<const stl::remove_reference_t<typename Type::const_reference> *>(cref))};
} else {
return iterator{};
}
@@ -174,7 +168,7 @@ 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(extent == meta_dynamic_extent) {
if constexpr(requires(Type elem, typename Type::const_iterator iter) { elem.erase(iter); }) {
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 {
@@ -187,17 +181,15 @@ struct basic_meta_sequence_container_traits {
* @brief General purpose implementation of meta associative container traits.
* @tparam Type Type of underlying associative container.
*/
template<typename Type>
template<cvref_unqualified Type>
struct basic_meta_associative_container_traits {
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;
using size_type = meta_associative_container::size_type;
/*! @brief Meta iterator type. */
using iterator = typename meta_associative_container::iterator;
using iterator = meta_associative_container::iterator;
/*! @brief True in case of key-only containers, false otherwise. */
static constexpr bool key_only = internal::key_only_associative_container_v<Type>;
static constexpr bool key_only = !requires { typename Type::mapped_type; };
/**
* @brief Returns the number of elements in a container.
@@ -225,7 +217,7 @@ struct basic_meta_associative_container_traits {
* @return True in case of success, false otherwise.
*/
[[nodiscard]] static bool reserve([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) {
if constexpr(internal::reserve_aware_container_v<Type>) {
if constexpr(requires(Type elem) { elem.reserve(sz); }) {
static_cast<Type *>(container)->reserve(sz);
return true;
} else {
@@ -244,8 +236,8 @@ struct basic_meta_associative_container_traits {
*/
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()};
? iterator{area, stl::bool_constant<key_only>{}, end ? static_cast<const Type *>(as_const)->cend() : static_cast<const Type *>(as_const)->cbegin()}
: iterator{area, stl::bool_constant<key_only>{}, end ? static_cast<Type *>(container)->end() : static_cast<Type *>(container)->begin()};
}
/**
@@ -257,9 +249,9 @@ struct basic_meta_associative_container_traits {
*/
[[nodiscard]] static bool insert(void *container, const void *key, [[maybe_unused]] const void *value) {
if constexpr(key_only) {
return static_cast<Type *>(container)->insert(*static_cast<const typename Type::key_type *>(key)).second;
return static_cast<Type *>(container)->insert(*static_cast<const Type::key_type *>(key)).second;
} else {
return static_cast<Type *>(container)->emplace(*static_cast<const typename Type::key_type *>(key), *static_cast<const typename Type::mapped_type *>(value)).second;
return static_cast<Type *>(container)->emplace(*static_cast<const Type::key_type *>(key), *static_cast<const Type::mapped_type *>(value)).second;
}
}
@@ -270,7 +262,7 @@ struct basic_meta_associative_container_traits {
* @return Number of elements removed (either 0 or 1).
*/
[[nodiscard]] static size_type erase(void *container, const void *key) {
return static_cast<Type *>(container)->erase(*static_cast<const typename Type::key_type *>(key));
return static_cast<Type *>(container)->erase(*static_cast<const Type::key_type *>(key));
}
/**
@@ -282,93 +274,24 @@ struct basic_meta_associative_container_traits {
* @return An iterator to the element with the given key, if any.
*/
static iterator find(const meta_ctx &area, void *container, const void *as_const, const void *key) {
return (container != nullptr) ? iterator{area, std::bool_constant<key_only>{}, static_cast<Type *>(container)->find(*static_cast<const typename Type::key_type *>(key))}
: iterator{area, std::bool_constant<key_only>{}, static_cast<const Type *>(as_const)->find(*static_cast<const typename Type::key_type *>(key))};
return (container != nullptr) ? iterator{area, stl::bool_constant<key_only>{}, static_cast<Type *>(container)->find(*static_cast<const Type::key_type *>(key))}
: iterator{area, stl::bool_constant<key_only>{}, static_cast<const Type *>(as_const)->find(*static_cast<const Type::key_type *>(key))};
}
};
/**
* @brief Meta sequence container traits for `std::vector`s of any type.
* @tparam Args Template arguments for the container.
* @brief Traits meta sequence container like types.
* @tparam Type Container type to inspect.
*/
template<typename... Args>
struct meta_sequence_container_traits<std::vector<Args...>>
: basic_meta_sequence_container_traits<std::vector<Args...>> {};
template<internal::meta_sequence_container_like Type>
struct meta_sequence_container_traits<Type>: basic_meta_sequence_container_traits<Type> {};
/**
* @brief Meta sequence container traits for `std::array`s of any type.
* @tparam Type Template arguments for the container.
* @tparam N Template arguments for the container.
* @brief Traits for meta associative container like types.
* @tparam Type Container type to inspect.
*/
template<typename Type, auto N>
struct meta_sequence_container_traits<std::array<Type, N>>
: basic_meta_sequence_container_traits<std::array<Type, N>> {};
/**
* @brief Meta sequence container traits for `std::list`s of any type.
* @tparam Args Template arguments for the container.
*/
template<typename... Args>
struct meta_sequence_container_traits<std::list<Args...>>
: basic_meta_sequence_container_traits<std::list<Args...>> {};
/**
* @brief Meta sequence container traits for `std::deque`s of any type.
* @tparam Args Template arguments for the container.
*/
template<typename... Args>
struct meta_sequence_container_traits<std::deque<Args...>>
: basic_meta_sequence_container_traits<std::deque<Args...>> {};
/**
* @brief Meta associative container traits for `std::map`s of any type.
* @tparam Args Template arguments for the container.
*/
template<typename... Args>
struct meta_associative_container_traits<std::map<Args...>>
: basic_meta_associative_container_traits<std::map<Args...>> {};
/**
* @brief Meta associative container traits for `std::unordered_map`s of any
* type.
* @tparam Args Template arguments for the container.
*/
template<typename... Args>
struct meta_associative_container_traits<std::unordered_map<Args...>>
: basic_meta_associative_container_traits<std::unordered_map<Args...>> {};
/**
* @brief Meta associative container traits for `std::set`s of any type.
* @tparam Args Template arguments for the container.
*/
template<typename... Args>
struct meta_associative_container_traits<std::set<Args...>>
: basic_meta_associative_container_traits<std::set<Args...>> {};
/**
* @brief Meta associative container traits for `std::unordered_set`s of any
* type.
* @tparam Args Template arguments for the container.
*/
template<typename... Args>
struct meta_associative_container_traits<std::unordered_set<Args...>>
: basic_meta_associative_container_traits<std::unordered_set<Args...>> {};
/**
* @brief Meta associative container traits for `dense_map`s of any type.
* @tparam Args Template arguments for the container.
*/
template<typename... Args>
struct meta_associative_container_traits<dense_map<Args...>>
: basic_meta_associative_container_traits<dense_map<Args...>> {};
/**
* @brief Meta associative container traits for `dense_set`s of any type.
* @tparam Args Template arguments for the container.
*/
template<typename... Args>
struct meta_associative_container_traits<dense_set<Args...>>
: basic_meta_associative_container_traits<dense_set<Args...>> {};
template<internal::meta_associative_container_like Type>
struct meta_associative_container_traits<Type>: basic_meta_associative_container_traits<Type> {};
} // namespace entt

View File

@@ -1,21 +1,23 @@
#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 "../stl/functional.hpp"
#include "../stl/memory.hpp"
#include "fwd.hpp"
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
struct meta_type_node;
struct meta_context {
dense_map<id_type, std::unique_ptr<meta_type_node>, identity> value;
using container_type = dense_map<id_type, stl::unique_ptr<meta_type_node>, stl::identity>;
container_type bucket;
[[nodiscard]] inline static meta_context &from(meta_ctx &);
[[nodiscard]] inline static const meta_context &from(const meta_ctx &);
@@ -36,7 +38,7 @@ class meta_ctx: private internal::meta_context {
friend struct internal::meta_context;
};
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
[[nodiscard]] inline internal::meta_context &internal::meta_context::from(meta_ctx &ctx) {
return ctx;
}

View File

@@ -1,13 +1,6 @@
#ifndef ENTT_META_FACTORY_HPP
#define ENTT_META_FACTORY_HPP
#include <cstddef>
#include <cstdint>
#include <functional>
#include <memory>
#include <tuple>
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "../core/bit.hpp"
#include "../core/fwd.hpp"
@@ -15,6 +8,13 @@
#include "../core/type_info.hpp"
#include "../core/type_traits.hpp"
#include "../locator/locator.hpp"
#include "../stl/concepts.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/cstdint.hpp"
#include "../stl/functional.hpp"
#include "../stl/memory.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "context.hpp"
#include "fwd.hpp"
#include "meta.hpp"
@@ -26,125 +26,131 @@
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
class basic_meta_factory {
using invoke_type = std::remove_pointer_t<decltype(meta_func_node::invoke)>;
using invoke_type = stl::remove_pointer_t<decltype(meta_func_node::invoke)>;
[[nodiscard]] auto &fetch_node() noexcept {
return *meta_context::from(*ctx).value[parent];
}
enum class mode {
type,
data,
func
};
[[nodiscard]] auto *find_member_or_assert() {
auto *member = find_member<&meta_data_node::id>(fetch_node().details->data, bucket);
auto *member = find_member(parent->details->data, bucket);
ENTT_ASSERT(member != nullptr, "Cannot find member");
return member;
}
[[nodiscard]] auto *find_overload_or_assert() {
auto *overload = find_overload(find_member<&meta_func_node::id>(fetch_node().details->func, bucket), invoke);
ENTT_ASSERT(invoke != nullptr, "Invoke function not available");
auto *overload = find_overload(find_member(parent->details->func, bucket), invoke);
ENTT_ASSERT(overload != nullptr, "Cannot find overload");
return overload;
}
void reset_bucket(const id_type id, invoke_type *const ref = nullptr) {
invoke = ref;
bucket = id;
}
protected:
void type(const id_type id, const char *name) noexcept {
reset_bucket(parent);
auto &elem = fetch_node();
ENTT_ASSERT(elem.id == id || !resolve(*ctx, id), "Duplicate identifier");
elem.name = name;
elem.id = id;
state = mode::type;
ENTT_ASSERT(parent->id == id || !resolve(*ctx, id), "Duplicate identifier");
parent->name = name;
parent->id = id;
}
template<typename Type>
void insert_or_assign(Type node) {
auto &elem = fetch_node();
state = mode::type;
reset_bucket(parent);
if constexpr(std::is_same_v<Type, meta_base_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>(elem.details->conv, node.type);
member ? (*member = node) : elem.details->conv.emplace_back(node);
if constexpr(stl::is_same_v<Type, meta_base_node>) {
auto *member = find_member(parent->details->base, node.id);
member ? (*member = node) : parent->details->base.emplace_back(node);
} else if constexpr(stl::is_same_v<Type, meta_conv_node>) {
auto *member = find_member(parent->details->conv, node.id);
member ? (*member = node) : parent->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>(elem.details->ctor, node.id);
member ? (*member = node) : elem.details->ctor.emplace_back(node);
static_assert(stl::is_same_v<Type, meta_ctor_node>, "Unexpected type");
auto *member = find_member(parent->details->ctor, node.id);
member ? (*member = node) : parent->details->ctor.emplace_back(node);
}
}
void data(meta_data_node node) {
auto &elem = fetch_node();
state = mode::data;
bucket = node.id;
reset_bucket(node.id);
if(auto *member = find_member<&meta_data_node::id>(elem.details->data, node.id); member == nullptr) {
elem.details->data.emplace_back(std::move(node));
if(auto *member = find_member(parent->details->data, node.id); member == nullptr) {
parent->details->data.emplace_back(stl::move(node));
} else if(member->set != node.set || member->get != node.get) {
*member = std::move(node);
*member = stl::move(node);
}
}
void func(meta_func_node node) {
auto &elem = fetch_node();
state = mode::func;
bucket = node.id;
invoke = node.invoke;
reset_bucket(node.id, node.invoke);
if(auto *member = find_member<&meta_func_node::id>(elem.details->func, node.id); member == nullptr) {
elem.details->func.emplace_back(std::move(node));
if(auto *member = find_member(parent->details->func, node.id); member == nullptr) {
parent->details->func.emplace_back(stl::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_unique<meta_func_node>(std::move(node));
member->next = stl::make_unique<meta_func_node>(stl::move(node));
}
}
void traits(const meta_traits value, const bool unset) {
auto set_or_unset_on = [=](auto &node) {
const auto set_or_unset_on = [=](auto &node) {
node.traits = (unset ? (node.traits & ~value) : (node.traits | value));
};
if(bucket == parent) {
set_or_unset_on(fetch_node());
} else if(invoke == nullptr) {
switch(state) {
case mode::type:
set_or_unset_on(*parent);
break;
case mode::data:
set_or_unset_on(*find_member_or_assert());
} else {
break;
case mode::func:
set_or_unset_on(*find_overload_or_assert());
break;
}
}
void custom(meta_custom_node node) {
if(bucket == parent) {
fetch_node().custom = std::move(node);
} else if(invoke == nullptr) {
find_member_or_assert()->custom = std::move(node);
} else {
find_overload_or_assert()->custom = std::move(node);
switch(state) {
case mode::type:
parent->custom = stl::move(node);
break;
case mode::data:
find_member_or_assert()->custom = stl::move(node);
break;
case mode::func:
find_overload_or_assert()->custom = stl::move(node);
break;
}
}
public:
basic_meta_factory(meta_ctx &area, meta_type_node node)
: ctx{&area},
parent{node.info->hash()},
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>();
bucket{node.info->hash()},
state{mode::type} {
if(const auto it = meta_context::from(*ctx).bucket.find(bucket); it == meta_context::from(*ctx).bucket.cend()) {
parent = meta_context::from(*ctx).bucket.emplace(node.info->hash(), stl::make_unique<meta_type_node>(stl::move(node))).first->second.get();
parent->details = stl::make_unique<meta_type_descriptor>();
} else {
parent = it->second.get();
}
}
private:
meta_ctx *ctx{};
id_type parent{};
id_type bucket{};
invoke_type *invoke{};
meta_type_node *parent{};
mode state{};
};
} // namespace internal
@@ -202,10 +208,18 @@ public:
* @return A meta factory for the parent type.
*/
template<typename Base>
requires stl::derived_from<Type, Base>
meta_factory base() noexcept {
static_assert(!std::is_same_v<Type, Base> && std::is_base_of_v<Base, Type>, "Invalid base type");
auto *const op = +[](const void *instance) noexcept { return static_cast<const void *>(static_cast<const Base *>(static_cast<const Type *>(instance))); };
base_type::insert_or_assign(internal::meta_base_node{type_id<Base>().hash(), &internal::resolve<Base>, op});
if constexpr(!stl::same_as<Type, Base>) {
auto *const op = +[](const void *instance) noexcept { return static_cast<const void *>(static_cast<const Base *>(static_cast<const Type *>(instance))); };
base_type::insert_or_assign(
internal::meta_base_node{
type_id<Base>().hash(),
&internal::resolve<Base>,
op});
}
return *this;
}
@@ -223,9 +237,14 @@ public:
*/
template<auto Candidate>
auto conv() noexcept {
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});
using conv_type = stl::remove_cvref_t<stl::invoke_result_t<decltype(Candidate), Type &>>;
auto *const op = +[](const meta_ctx &area, const void *instance) { return forward_as_meta(area, stl::invoke(Candidate, *static_cast<const Type *>(instance))); };
base_type::insert_or_assign(
internal::meta_conv_node{
type_id<conv_type>().hash(),
op});
return *this;
}
@@ -240,9 +259,14 @@ public:
*/
template<typename To>
meta_factory conv() noexcept {
using conv_type = std::remove_const_t<std::remove_reference_t<To>>;
using conv_type = stl::remove_cvref_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});
base_type::insert_or_assign(
internal::meta_conv_node{
type_id<conv_type>().hash(),
op});
return *this;
}
@@ -263,8 +287,15 @@ public:
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_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>});
static_assert(stl::is_same_v<stl::remove_cvref_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;
}
@@ -283,7 +314,13 @@ public:
// default constructor is already implicitly generated, no need for redundancy
if constexpr(sizeof...(Args) != 0u) {
using descriptor = meta_function_helper_t<Type, Type (*)(Args...)>;
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, Args...>});
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, Args...>});
}
return *this;
@@ -317,8 +354,8 @@ public:
*/
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 &>;
if constexpr(stl::is_member_object_pointer_v<decltype(Data)>) {
using data_type = stl::invoke_result_t<decltype(Data), Type &>;
static_assert(Policy::template value<data_type>, "Invalid return type for the given policy");
base_type::data(
@@ -326,16 +363,16 @@ public:
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,
stl::is_const_v<stl::remove_reference_t<data_type>> ? internal::meta_traits::is_const : internal::meta_traits::is_none,
1u,
&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>>>>,
&internal::resolve<stl::remove_cvref_t<data_type>>,
&meta_arg<type_list<stl::remove_cvref_t<data_type>>>,
&meta_setter<Type, Data>,
&meta_getter<Type, Data, Policy>});
} else {
using data_type = std::remove_pointer_t<decltype(Data)>;
using data_type = stl::remove_pointer_t<decltype(Data)>;
if constexpr(std::is_pointer_v<decltype(Data)>) {
if constexpr(stl::is_pointer_v<decltype(Data)>) {
static_assert(Policy::template value<decltype(*Data)>, "Invalid return type for the given policy");
} else {
static_assert(Policy::template value<data_type>, "Invalid return type for the given policy");
@@ -345,10 +382,10 @@ public:
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,
((!stl::is_pointer_v<decltype(Data)> || stl::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_const_t<std::remove_reference_t<data_type>>>,
&meta_arg<type_list<std::remove_const_t<std::remove_reference_t<data_type>>>>,
&internal::resolve<stl::remove_cvref_t<data_type>>,
&meta_arg<type_list<stl::remove_cvref_t<data_type>>>,
&meta_setter<Type, Data>,
&meta_getter<Type, Data, Policy>});
}
@@ -396,7 +433,7 @@ public:
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");
if constexpr(std::is_same_v<decltype(Setter), std::nullptr_t>) {
if constexpr(stl::is_same_v<decltype(Setter), stl::nullptr_t>) {
base_type::data(
internal::meta_data_node{
id,
@@ -404,12 +441,12 @@ public:
/* this is never static */
internal::meta_traits::is_const,
0u,
&internal::resolve<std::remove_const_t<std::remove_reference_t<typename descriptor::return_type>>>,
&internal::resolve<stl::remove_cvref_t<typename descriptor::return_type>>,
&meta_arg<type_list<>>,
&meta_setter<Type, Setter>,
&meta_getter<Type, Getter, Policy>});
} else {
using args_type = typename meta_function_helper_t<Type, decltype(Setter)>::args_type;
using args_type = meta_function_helper_t<Type, decltype(Setter)>::args_type;
base_type::data(
internal::meta_data_node{
@@ -418,8 +455,8 @@ public:
/* this is never static nor const */
internal::meta_traits::is_none,
1u,
&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>>>,
&internal::resolve<stl::remove_cvref_t<typename descriptor::return_type>>,
&meta_arg<type_list<type_list_element_t<static_cast<stl::size_t>(args_type::size != 1u), args_type>>>,
&meta_setter<Type, Setter>,
&meta_getter<Type, Getter, Policy>});
}
@@ -464,7 +501,7 @@ public:
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_const_t<std::remove_reference_t<typename descriptor::return_type>>>>,
&internal::resolve<stl::conditional_t<stl::is_same_v<Policy, as_void_t>, void, stl::remove_cvref_t<typename descriptor::return_type>>>,
&meta_arg<typename descriptor::args_type>,
&meta_invoke<Type, Candidate, Policy>});
@@ -483,7 +520,7 @@ public:
*/
template<typename Value>
meta_factory traits(const Value value, const bool unset = false) {
static_assert(std::is_enum_v<Value>, "Invalid enum type");
static_assert(stl::is_enum_v<Value>, "Invalid enum type");
base_type::traits(internal::user_to_meta_traits(value), unset);
return *this;
}
@@ -497,7 +534,7 @@ public:
*/
template<typename Value, typename... Args>
meta_factory custom(Args &&...args) {
base_type::custom(internal::meta_custom_node{type_id<Value>().hash(), std::make_shared<Value>(std::forward<Args>(args)...)});
base_type::custom(internal::meta_custom_node{type_id<Value>().hash(), stl::make_shared<Value>(stl::forward<Args>(args)...)});
return *this;
}
};
@@ -517,9 +554,9 @@ public:
inline void meta_reset(meta_ctx &ctx, const id_type id) noexcept {
auto &context = internal::meta_context::from(ctx);
for(auto it = context.value.begin(); it != context.value.end();) {
for(auto it = context.bucket.begin(); it != context.bucket.end();) {
if(it->second->id == id) {
it = context.value.erase(it);
it = context.bucket.erase(it);
} else {
++it;
}
@@ -551,7 +588,7 @@ inline void meta_reset(const id_type id) noexcept {
*/
template<typename Type>
void meta_reset(meta_ctx &ctx) noexcept {
internal::meta_context::from(ctx).value.erase(type_id<Type>().hash());
internal::meta_context::from(ctx).bucket.erase(type_id<Type>().hash());
}
/**
@@ -574,7 +611,7 @@ void meta_reset() noexcept {
* @param ctx The context from which to reset meta types.
*/
inline void meta_reset(meta_ctx &ctx) noexcept {
internal::meta_context::from(ctx).value.clear();
internal::meta_context::from(ctx).bucket.clear();
}
/**

View File

@@ -1,8 +1,8 @@
#ifndef ENTT_META_FWD_HPP
#define ENTT_META_FWD_HPP
#include <cstddef>
#include <limits>
#include "../stl/cstddef.hpp"
#include "../stl/limits.hpp"
namespace entt {
@@ -18,9 +18,11 @@ class meta_handle;
struct meta_custom;
class meta_data;
struct meta_data;
class meta_func;
struct meta_func;
struct meta_base;
class meta_type;
@@ -28,7 +30,7 @@ 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)();
inline constexpr stl::size_t meta_dynamic_extent = (stl::numeric_limits<stl::size_t>::max)();
} // namespace entt

File diff suppressed because it is too large Load Diff

View File

@@ -1,32 +1,32 @@
#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/bit.hpp"
#include "../core/concepts.hpp"
#include "../core/enum.hpp"
#include "../core/fwd.hpp"
#include "../core/type_info.hpp"
#include "../core/type_traits.hpp"
#include "../core/utility.hpp"
#include "../stl/array.hpp"
#include "../stl/bit.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/cstdint.hpp"
#include "../stl/memory.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "../stl/vector.hpp"
#include "context.hpp"
#include "fwd.hpp"
#include "type_traits.hpp"
namespace entt {
class meta_any;
class meta_type;
class meta_handle;
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
enum class meta_traits : std::uint32_t {
enum class meta_traits : stl::uint32_t {
is_none = 0x0000,
is_const = 0x0001,
is_static = 0x0002,
@@ -45,41 +45,41 @@ enum class meta_traits : std::uint32_t {
};
template<typename Type>
requires stl::is_enum_v<Type>
[[nodiscard]] auto meta_to_user_traits(const meta_traits traits) noexcept {
static_assert(std::is_enum_v<Type>, "Invalid enum type");
constexpr auto shift = popcount(static_cast<std::underlying_type_t<meta_traits>>(meta_traits::_user_defined_traits));
return Type{static_cast<std::underlying_type_t<Type>>(static_cast<std::underlying_type_t<meta_traits>>(traits) >> shift)};
constexpr auto shift = stl::popcount(static_cast<stl::underlying_type_t<meta_traits>>(meta_traits::_user_defined_traits));
return Type{static_cast<stl::underlying_type_t<Type>>(static_cast<stl::underlying_type_t<meta_traits>>(traits) >> shift)};
}
template<typename Type>
requires stl::is_enum_v<Type>
[[nodiscard]] auto user_to_meta_traits(const Type value) noexcept {
static_assert(std::is_enum_v<Type>, "Invalid enum type");
constexpr auto shift = popcount(static_cast<std::underlying_type_t<meta_traits>>(meta_traits::_user_defined_traits));
const auto traits = static_cast<std::underlying_type_t<internal::meta_traits>>(static_cast<std::underlying_type_t<Type>>(value));
ENTT_ASSERT(traits < ((~static_cast<std::underlying_type_t<meta_traits>>(meta_traits::_user_defined_traits)) >> shift), "Invalid traits");
constexpr auto shift = stl::popcount(static_cast<stl::underlying_type_t<meta_traits>>(meta_traits::_user_defined_traits));
const auto traits = static_cast<stl::underlying_type_t<internal::meta_traits>>(static_cast<stl::underlying_type_t<Type>>(value));
ENTT_ASSERT(traits < ((~static_cast<stl::underlying_type_t<meta_traits>>(meta_traits::_user_defined_traits)) >> shift), "Invalid traits");
return meta_traits{traits << shift};
}
struct meta_type_node;
struct meta_custom_node {
id_type type{};
std::shared_ptr<void> value{};
id_type id{};
stl::shared_ptr<void> value{};
};
struct meta_base_node {
id_type type{};
const meta_type_node &(*resolve)(const meta_context &) noexcept {};
id_type id{};
const meta_type_node &(*type)(const meta_context &) noexcept {};
const void *(*cast)(const void *) noexcept {};
};
struct meta_conv_node {
id_type type{};
id_type id{};
meta_any (*conv)(const meta_ctx &, const void *){};
};
struct meta_ctor_node {
using size_type = std::size_t;
using size_type = stl::size_t;
id_type id{};
size_type arity{0u};
@@ -88,7 +88,7 @@ struct meta_ctor_node {
};
struct meta_data_node {
using size_type = std::size_t;
using size_type = stl::size_t;
id_type id{};
const char *name{};
@@ -102,7 +102,7 @@ struct meta_data_node {
};
struct meta_func_node {
using size_type = std::size_t;
using size_type = stl::size_t;
id_type id{};
const char *name{};
@@ -111,12 +111,12 @@ struct meta_func_node {
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::unique_ptr<meta_func_node> next;
stl::unique_ptr<meta_func_node> next;
meta_custom_node custom{};
};
struct meta_template_node {
using size_type = std::size_t;
using size_type = stl::size_t;
size_type arity{0u};
const meta_type_node &(*resolve)(const meta_context &) noexcept {};
@@ -124,15 +124,15 @@ struct meta_template_node {
};
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{};
stl::vector<meta_ctor_node> ctor{};
stl::vector<meta_base_node> base{};
stl::vector<meta_conv_node> conv{};
stl::vector<meta_data_node> data{};
stl::vector<meta_func_node> func{};
};
struct meta_type_node {
using size_type = std::size_t;
using size_type = stl::size_t;
const type_info *info{};
id_type id{};
@@ -145,37 +145,37 @@ struct meta_type_node {
meta_any (*from_void)(const meta_ctx &, void *, const void *){};
meta_template_node templ{};
meta_custom_node custom{};
std::unique_ptr<meta_type_descriptor> details{};
stl::unique_ptr<meta_type_descriptor> details{};
};
template<auto Member, typename Type, typename Value>
template<typename Type, typename Value>
[[nodiscard]] auto *find_member(Type &from, const Value value) {
for(auto &&elem: from) {
if((elem.*Member) == value) {
if(elem.id == value) {
return &elem;
}
}
return static_cast<typename Type::value_type *>(nullptr);
return static_cast<Type::value_type *>(nullptr);
}
[[nodiscard]] inline auto *find_overload(meta_func_node *curr, std::remove_pointer_t<decltype(meta_func_node::invoke)> *const ref) {
[[nodiscard]] inline auto *find_overload(meta_func_node *curr, stl::remove_pointer_t<decltype(meta_func_node::invoke)> *const ref) {
while((curr != nullptr) && (curr->invoke != ref)) { curr = curr->next.get(); }
return curr;
}
template<auto Member>
[[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;
using value_type = stl::remove_reference_t<decltype((node.details.get()->*Member))>::value_type;
if(node.details) {
if(auto *member = find_member<&value_type::id>((node.details.get()->*Member), id); member != nullptr) {
if(auto *member = find_member((node.details.get()->*Member), id); member != nullptr) {
return member;
}
if(recursive) {
for(auto &&curr: node.details->base) {
if(auto *elem = look_for<Member>(context, curr.resolve(context), id, recursive); elem) {
if(auto *elem = look_for<Member>(context, curr.type(context), id, recursive); elem) {
return elem;
}
}
@@ -185,13 +185,13 @@ template<auto Member>
return static_cast<value_type *>(nullptr);
}
template<typename Type>
template<cvref_unqualified Type>
const meta_type_node &resolve(const meta_context &) noexcept;
template<typename... Args>
[[nodiscard]] const meta_type_node &meta_arg_node(const meta_context &context, type_list<Args...>, const std::size_t index) noexcept {
[[nodiscard]] const meta_type_node &meta_arg_node(const meta_context &context, type_list<Args...>, const stl::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>>>...};
constexpr stl::array<resolve_type, sizeof...(Args)> list{&resolve<stl::remove_cvref_t<Args>>...};
ENTT_ASSERT(index < sizeof...(Args), "Out of bounds");
return list[index](context);
}
@@ -199,9 +199,9 @@ template<typename... Args>
[[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 *other = curr.cast(instance); curr.type == to) {
if(const void *other = curr.cast(instance); curr.id == to) {
return other;
} else if(const void *elem = try_cast(context, curr.resolve(context), to, other); elem) {
} else if(const void *elem = try_cast(context, curr.type(context), to, other); elem) {
return elem;
}
}
@@ -216,47 +216,47 @@ auto setup_node_for() noexcept {
&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)
| (std::is_array_v<Type> ? meta_traits::is_array : meta_traits::is_none)
| (std::is_enum_v<Type> ? meta_traits::is_enum : meta_traits::is_none)
| (std::is_class_v<Type> ? meta_traits::is_class : meta_traits::is_none)
| (std::is_pointer_v<Type> ? meta_traits::is_pointer : meta_traits::is_none)
(stl::is_arithmetic_v<Type> ? meta_traits::is_arithmetic : meta_traits::is_none)
| (stl::is_integral_v<Type> ? meta_traits::is_integral : meta_traits::is_none)
| (stl::is_signed_v<Type> ? meta_traits::is_signed : meta_traits::is_none)
| (stl::is_array_v<Type> ? meta_traits::is_array : meta_traits::is_none)
| (stl::is_enum_v<Type> ? meta_traits::is_enum : meta_traits::is_none)
| (stl::is_class_v<Type> ? meta_traits::is_class : meta_traits::is_none)
| (stl::is_pointer_v<Type> ? meta_traits::is_pointer : meta_traits::is_none)
| (is_meta_pointer_like_v<Type> ? meta_traits::is_pointer_like : meta_traits::is_none)
| (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<std::remove_const_t<std::remove_pointer_t<Type>>>};
&resolve<stl::remove_const_t<stl::remove_pointer_t<Type>>>};
if constexpr(std::is_default_constructible_v<Type>) {
if constexpr(stl::is_default_constructible_v<Type>) {
node.default_constructor = +[](const meta_ctx &ctx) {
return meta_any{ctx, std::in_place_type<Type>};
return meta_any{ctx, stl::in_place_type<Type>};
};
}
if constexpr(std::is_arithmetic_v<Type>) {
if constexpr(stl::is_arithmetic_v<Type>) {
node.conversion_helper = +[](void *lhs, const void *rhs) {
return lhs ? static_cast<double>(*static_cast<Type *>(lhs) = static_cast<Type>(*static_cast<const double *>(rhs))) : static_cast<double>(*static_cast<const Type *>(rhs));
};
} else if constexpr(std::is_enum_v<Type>) {
} else if constexpr(stl::is_enum_v<Type>) {
node.conversion_helper = +[](void *lhs, const void *rhs) {
return lhs ? static_cast<double>(*static_cast<Type *>(lhs) = static_cast<Type>(static_cast<std::underlying_type_t<Type>>(*static_cast<const double *>(rhs)))) : static_cast<double>(*static_cast<const Type *>(rhs));
return lhs ? static_cast<double>(*static_cast<Type *>(lhs) = static_cast<Type>(static_cast<stl::underlying_type_t<Type>>(*static_cast<const double *>(rhs)))) : static_cast<double>(*static_cast<const Type *>(rhs));
};
}
if constexpr(!std::is_void_v<Type> && !std::is_function_v<Type>) {
if constexpr(!stl::is_void_v<Type> && !stl::is_function_v<Type>) {
node.from_void = +[](const meta_ctx &ctx, void *elem, const void *celem) {
if(elem && celem) { // ownership construction request
return meta_any{ctx, std::in_place, static_cast<std::decay_t<Type> *>(elem)};
return meta_any{ctx, stl::in_place, static_cast<stl::decay_t<Type> *>(elem)};
}
if(elem) { // non-const reference construction request
return meta_any{ctx, std::in_place_type<std::decay_t<Type> &>, *static_cast<std::decay_t<Type> *>(elem)};
return meta_any{ctx, stl::in_place_type<stl::decay_t<Type> &>, *static_cast<stl::decay_t<Type> *>(elem)};
}
// const reference construction request
return meta_any{ctx, std::in_place_type<const std::decay_t<Type> &>, *static_cast<const std::decay_t<Type> *>(celem)};
return meta_any{ctx, stl::in_place_type<const stl::decay_t<Type> &>, *static_cast<const stl::decay_t<Type> *>(celem)};
};
}
@@ -264,20 +264,19 @@ auto setup_node_for() noexcept {
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 -> decltype(auto) { return meta_arg_node(area, typename meta_template_traits<Type>::args_type{}, index); }};
+[](const meta_context &area, const stl::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;
const auto it = context.bucket.find(info.hash());
return (it != context.bucket.end()) ? it->second.get() : nullptr;
}
template<typename Type>
template<cvref_unqualified 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;

View File

@@ -3,56 +3,39 @@
#ifndef ENTT_META_POINTER_HPP
#define ENTT_META_POINTER_HPP
#include <memory>
#include <type_traits>
#include "../stl/memory.hpp"
#include "../stl/type_traits.hpp"
#include "type_traits.hpp"
namespace entt {
/**
* @brief Makes plain pointers pointer-like types for the meta system.
* @tparam Type Element type.
*/
template<typename Type>
struct is_meta_pointer_like<Type *>
: std::true_type {};
/**
* @brief Partial specialization used to reject pointers to arrays.
* @tparam Type Type of elements of the array.
* @tparam N Number of elements of the array.
*/
template<typename Type, std::size_t N>
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
struct is_meta_pointer_like<Type (*)[N]>
: std::false_type {};
/**
* @brief Makes `std::shared_ptr`s of any type pointer-like types for the meta
* @brief Makes `stl::shared_ptr`s of any type pointer-like types for the meta
* system.
* @tparam Type Element type.
*/
template<typename Type>
struct is_meta_pointer_like<std::shared_ptr<Type>>
: std::true_type {};
struct is_meta_pointer_like<stl::shared_ptr<Type>>
: stl::true_type {};
/**
* @brief Makes `std::unique_ptr`s of any type pointer-like types for the meta
* @brief Makes `stl::unique_ptr`s of any type pointer-like types for the meta
* system.
* @tparam Type Element type.
* @tparam Args Other arguments.
*/
template<typename Type, typename... Args>
struct is_meta_pointer_like<std::unique_ptr<Type, Args...>>
: std::true_type {};
struct is_meta_pointer_like<stl::unique_ptr<Type, Args...>>
: stl::true_type {};
/**
* @brief Specialization for self-proclaimed meta pointer like types.
* @tparam Type Element type.
*/
template<typename Type>
struct is_meta_pointer_like<Type, std::void_t<typename Type::is_meta_pointer_like>>
: std::true_type {};
requires requires { typename Type::is_meta_pointer_like; }
struct is_meta_pointer_like<Type>
: stl::true_type {};
} // namespace entt

View File

@@ -1,11 +1,11 @@
#ifndef ENTT_META_POLICY_HPP
#define ENTT_META_POLICY_HPP
#include <type_traits>
#include "../stl/type_traits.hpp"
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
struct meta_policy {};
@@ -15,7 +15,7 @@ struct meta_policy {};
/*! @brief Empty class type used to request the _as-is_ policy. */
struct as_value_t final: private internal::meta_policy {
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
template<typename>
static constexpr bool value = true;
/*! @endcond */
@@ -23,7 +23,7 @@ struct as_value_t final: private internal::meta_policy {
/*! @brief Empty class type used to request the _as void_ policy. */
struct as_void_t final: private internal::meta_policy {
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
template<typename>
static constexpr bool value = true;
/*! @endcond */
@@ -31,23 +31,23 @@ struct as_void_t final: private internal::meta_policy {
/*! @brief Empty class type used to request the _as ref_ policy. */
struct as_ref_t final: private internal::meta_policy {
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
template<typename Type>
static constexpr bool value = std::is_reference_v<Type> && !std::is_const_v<std::remove_reference_t<Type>>;
static constexpr bool value = stl::is_reference_v<Type> && !stl::is_const_v<stl::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 */
/*! @cond ENTT_INTERNAL */
template<typename Type>
static constexpr bool value = std::is_reference_v<Type>;
static constexpr bool value = stl::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 */
/*! @cond ENTT_INTERNAL */
template<typename>
static constexpr bool value = true;
/*! @endcond */
@@ -60,7 +60,7 @@ struct as_is_t final: private internal::meta_policy {
*/
template<typename Type>
struct is_meta_policy
: std::bool_constant<std::is_base_of_v<internal::meta_policy, Type>> {};
: stl::bool_constant<stl::is_base_of_v<internal::meta_policy, Type>> {};
/**
* @brief Helper variable template.
@@ -69,6 +69,13 @@ struct is_meta_policy
template<typename Type>
inline constexpr bool is_meta_policy_v = is_meta_policy<Type>::value;
/**
* @brief Specifies whether a type is a meta policy.
* @tparam Type Type to check.
*/
template<typename Type>
concept meta_policy = is_meta_policy_v<Type>;
} // namespace entt
#endif

View File

@@ -1,28 +1,30 @@
#ifndef ENTT_META_RANGE_HPP
#define ENTT_META_RANGE_HPP
#include <cstddef>
#include <iterator>
#include <utility>
#include <compare>
#include "../core/fwd.hpp"
#include "../core/iterator.hpp"
#include "../stl/concepts.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/iterator.hpp"
#include "../stl/utility.hpp"
#include "context.hpp"
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
struct meta_base_node;
template<typename Type, typename It>
struct meta_range_iterator final {
using value_type = std::pair<id_type, Type>;
using value_type = stl::pair<id_type, Type>;
using pointer = input_iterator_pointer<value_type>;
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category = std::input_iterator_tag;
using iterator_concept = std::random_access_iterator_tag;
using difference_type = stl::ptrdiff_t;
using iterator_category = stl::input_iterator_tag;
using iterator_concept = stl::random_access_iterator_tag;
constexpr meta_range_iterator() noexcept
: it{},
@@ -69,10 +71,8 @@ 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>) {
if constexpr(stl::is_same_v<It, typename meta_context::container_type::const_iterator>) {
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 {
return {it[value].id, Type{*ctx, it[value]}};
}
@@ -86,55 +86,23 @@ struct meta_range_iterator final {
return operator[](0);
}
template<typename... Args>
friend constexpr std::ptrdiff_t operator-(const meta_range_iterator<Args...> &, const meta_range_iterator<Args...> &) noexcept;
[[nodiscard]] constexpr stl::ptrdiff_t operator-(const meta_range_iterator &other) const noexcept {
return it - other.it;
}
template<typename... Args>
friend constexpr bool operator==(const meta_range_iterator<Args...> &, const meta_range_iterator<Args...> &) noexcept;
[[nodiscard]] constexpr bool operator==(const meta_range_iterator &other) const noexcept {
return it == other.it;
}
template<typename... Args>
friend constexpr bool operator<(const meta_range_iterator<Args...> &, const meta_range_iterator<Args...> &) noexcept;
[[nodiscard]] constexpr auto operator<=>(const meta_range_iterator &other) const noexcept {
return it <=> other.it;
}
private:
It it;
const meta_ctx *ctx;
};
template<typename... Args>
[[nodiscard]] constexpr std::ptrdiff_t operator-(const meta_range_iterator<Args...> &lhs, const meta_range_iterator<Args...> &rhs) noexcept {
return lhs.it - rhs.it;
}
template<typename... Args>
[[nodiscard]] constexpr bool operator==(const meta_range_iterator<Args...> &lhs, const meta_range_iterator<Args...> &rhs) noexcept {
return lhs.it == rhs.it;
}
template<typename... Args>
[[nodiscard]] constexpr bool operator!=(const meta_range_iterator<Args...> &lhs, const meta_range_iterator<Args...> &rhs) noexcept {
return !(lhs == rhs);
}
template<typename... Args>
[[nodiscard]] constexpr bool operator<(const meta_range_iterator<Args...> &lhs, const meta_range_iterator<Args...> &rhs) noexcept {
return lhs.it < rhs.it;
}
template<typename... Args>
[[nodiscard]] constexpr bool operator>(const meta_range_iterator<Args...> &lhs, const meta_range_iterator<Args...> &rhs) noexcept {
return rhs < lhs;
}
template<typename... Args>
[[nodiscard]] constexpr bool operator<=(const meta_range_iterator<Args...> &lhs, const meta_range_iterator<Args...> &rhs) noexcept {
return !(lhs > rhs);
}
template<typename... Args>
[[nodiscard]] constexpr bool operator>=(const meta_range_iterator<Args...> &lhs, const meta_range_iterator<Args...> &rhs) noexcept {
return !(lhs < rhs);
}
} // namespace internal
/*! @endcond */
@@ -143,7 +111,7 @@ template<typename... Args>
* @tparam Type Type of meta objects returned.
* @tparam It Type of forward iterator.
*/
template<typename Type, typename It>
template<typename Type, stl::forward_iterator It>
using meta_range = iterable_adaptor<internal::meta_range_iterator<Type, It>>;
} // namespace entt

View File

@@ -1,9 +1,9 @@
#ifndef ENTT_META_RESOLVE_HPP
#define ENTT_META_RESOLVE_HPP
#include <type_traits>
#include "../core/type_info.hpp"
#include "../locator/locator.hpp"
#include "../stl/type_traits.hpp"
#include "context.hpp"
#include "meta.hpp"
#include "node.hpp"
@@ -20,7 +20,7 @@ namespace entt {
template<typename Type>
[[nodiscard]] meta_type resolve(const meta_ctx &ctx) noexcept {
const auto &context = internal::meta_context::from(ctx);
return {ctx, internal::resolve<std::remove_const_t<std::remove_reference_t<Type>>>(context)};
return {ctx, internal::resolve<stl::remove_cvref_t<Type>>(context)};
}
/**
@@ -38,16 +38,16 @@ template<typename Type>
* @param ctx The context from which to search for meta types.
* @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 {
[[nodiscard]] inline meta_range<meta_type, typename internal::meta_context::container_type::const_iterator> resolve(const meta_ctx &ctx) noexcept {
const auto &context = internal::meta_context::from(ctx);
return {{ctx, context.value.cbegin()}, {ctx, context.value.cend()}};
return {{ctx, context.bucket.cbegin()}, {ctx, context.bucket.cend()}};
}
/**
* @brief Returns a range to use to visit all meta types.
* @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() noexcept {
[[nodiscard]] inline meta_range<meta_type, typename internal::meta_context::container_type::const_iterator> resolve() noexcept {
return resolve(locator<meta_ctx>::value_or());
}

View File

@@ -1,8 +1,8 @@
#ifndef ENTT_META_TYPE_TRAITS_HPP
#define ENTT_META_TYPE_TRAITS_HPP
#include <type_traits>
#include <utility>
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
namespace entt {
@@ -31,8 +31,8 @@ struct meta_associative_container_traits;
* @brief Provides the member constant `value` to true if a given type is a
* pointer-like type from the point of view of the meta system, false otherwise.
*/
template<typename, typename = void>
struct is_meta_pointer_like: std::false_type {};
template<typename>
struct is_meta_pointer_like: stl::false_type {};
/**
* @brief Partial specialization to ensure that const pointer-like types are

View File

@@ -1,12 +1,12 @@
#ifndef ENTT_META_UTILITY_HPP
#define ENTT_META_UTILITY_HPP
#include <cstddef>
#include <functional>
#include <type_traits>
#include <utility>
#include "../core/type_traits.hpp"
#include "../locator/locator.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/functional.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "meta.hpp"
#include "node.hpp"
#include "policy.hpp"
@@ -48,8 +48,8 @@ template<typename Type, typename Ret, typename Class, typename... Args>
struct meta_function_descriptor<Type, Ret (Class::*)(Args...) const>
: meta_function_descriptor_traits<
Ret,
std::conditional_t<std::is_base_of_v<Class, Type>, type_list<Args...>, type_list<const Class &, Args...>>,
!std::is_base_of_v<Class, Type>,
stl::conditional_t<stl::is_base_of_v<Class, Type>, type_list<Args...>, type_list<const Class &, Args...>>,
!stl::is_base_of_v<Class, Type>,
true> {};
/**
@@ -63,8 +63,8 @@ template<typename Type, typename Ret, typename Class, typename... Args>
struct meta_function_descriptor<Type, Ret (Class::*)(Args...)>
: meta_function_descriptor_traits<
Ret,
std::conditional_t<std::is_base_of_v<Class, Type>, type_list<Args...>, type_list<Class &, Args...>>,
!std::is_base_of_v<Class, Type>,
stl::conditional_t<stl::is_base_of_v<Class, Type>, type_list<Args...>, type_list<Class &, Args...>>,
!stl::is_base_of_v<Class, Type>,
false> {};
/**
@@ -77,8 +77,8 @@ template<typename Type, typename Ret, typename Class>
struct meta_function_descriptor<Type, Ret Class::*>
: meta_function_descriptor_traits<
Ret &,
std::conditional_t<std::is_base_of_v<Class, Type>, type_list<>, type_list<Class &>>,
!std::is_base_of_v<Class, Type>,
stl::conditional_t<stl::is_base_of_v<Class, Type>, type_list<>, type_list<Class &>>,
!stl::is_base_of_v<Class, Type>,
false> {};
/**
@@ -92,12 +92,12 @@ template<typename Type, typename Ret, typename MaybeType, typename... Args>
struct meta_function_descriptor<Type, Ret (*)(MaybeType, Args...)>
: meta_function_descriptor_traits<
Ret,
std::conditional_t<
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>,
stl::conditional_t<
stl::is_same_v<stl::remove_cvref_t<MaybeType>, Type> || stl::is_base_of_v<stl::remove_cvref_t<MaybeType>, Type>,
type_list<Args...>,
type_list<MaybeType, Args...>>,
!(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>)> {};
!(stl::is_same_v<stl::remove_cvref_t<MaybeType>, Type> || stl::is_base_of_v<stl::remove_cvref_t<MaybeType>, Type>),
stl::is_const_v<stl::remove_reference_t<MaybeType>> && (stl::is_same_v<stl::remove_cvref_t<MaybeType>, Type> || stl::is_base_of_v<stl::remove_cvref_t<MaybeType>, Type>)> {};
/**
* @brief Meta function descriptor.
@@ -124,23 +124,24 @@ struct meta_function_descriptor<Type, Ret (*)()>
template<typename Type, typename Candidate>
class meta_function_helper {
template<typename Ret, typename... Args, typename Class>
static constexpr meta_function_descriptor<Type, Ret (Class::*)(Args...) const> get_rid_of_noexcept(Ret (Class::*)(Args...) const);
static meta_function_descriptor<Type, Ret (Class::*)(Args...) const> get_rid_of_noexcept(Ret (Class::*)(Args...) const);
template<typename Ret, typename... Args, typename Class>
static constexpr meta_function_descriptor<Type, Ret (Class::*)(Args...)> get_rid_of_noexcept(Ret (Class::*)(Args...));
static meta_function_descriptor<Type, Ret (Class::*)(Args...)> get_rid_of_noexcept(Ret (Class::*)(Args...));
template<typename Ret, typename Class, typename = std::enable_if_t<std::is_member_object_pointer_v<Ret Class::*>>>
static constexpr meta_function_descriptor<Type, Ret Class::*> get_rid_of_noexcept(Ret Class::*);
template<typename Ret, typename Class>
requires stl::is_member_object_pointer_v<Ret Class::*>
static meta_function_descriptor<Type, Ret Class::*> get_rid_of_noexcept(Ret Class::*);
template<typename Ret, typename... Args>
static constexpr meta_function_descriptor<Type, Ret (*)(Args...)> get_rid_of_noexcept(Ret (*)(Args...));
static meta_function_descriptor<Type, Ret (*)(Args...)> get_rid_of_noexcept(Ret (*)(Args...));
template<typename Class>
static constexpr meta_function_descriptor<Class, decltype(&Class::operator())> get_rid_of_noexcept(Class);
static meta_function_descriptor<Class, decltype(&Class::operator())> get_rid_of_noexcept(Class);
public:
/*! @brief The meta function descriptor of the given function. */
using type = decltype(get_rid_of_noexcept(std::declval<Candidate>()));
using type = decltype(get_rid_of_noexcept(stl::declval<Candidate>()));
};
/**
@@ -149,7 +150,7 @@ public:
* @tparam Candidate The actual function to associate with the reflected type.
*/
template<typename Type, typename Candidate>
using meta_function_helper_t = typename meta_function_helper<Type, Candidate>::type;
using meta_function_helper_t = meta_function_helper<Type, Candidate>::type;
/**
* @brief Wraps a value depending on the given policy.
@@ -164,17 +165,17 @@ 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_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_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>};
template<meta_policy Policy = as_value_t, typename Type>
[[nodiscard]] meta_any meta_dispatch(const meta_ctx &ctx, [[maybe_unused]] Type &&value) {
if constexpr(stl::is_same_v<Policy, as_cref_t>) {
static_assert(stl::is_lvalue_reference_v<Type>, "Invalid type");
return meta_any{ctx, stl::in_place_type<const stl::remove_reference_t<Type> &>, stl::as_const(value)};
} else if constexpr(stl::is_same_v<Policy, as_ref_t> || (stl::is_same_v<Policy, as_is_t> && stl::is_lvalue_reference_v<Type>)) {
return meta_any{ctx, stl::in_place_type<Type>, value};
} else if constexpr(stl::is_same_v<Policy, as_void_t>) {
return meta_any{ctx, stl::in_place_type<void>};
} else {
return meta_any{ctx, std::forward<Type>(value)};
return meta_any{ctx, stl::forward<Type>(value)};
}
}
@@ -185,40 +186,40 @@ template<typename Policy = as_value_t, typename Type>
* @param value Value to wrap.
* @return A meta any containing the returned value, if any.
*/
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));
template<meta_policy Policy = as_value_t, typename Type>
[[nodiscard]] meta_any meta_dispatch(Type &&value) {
return meta_dispatch<Policy, Type>(locator<meta_ctx>::value_or(), stl::forward<Type>(value));
}
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
template<typename Policy, typename Candidate, typename... Args>
[[nodiscard]] meta_any meta_invoke_with_args(const meta_ctx &ctx, Candidate &&candidate, Args &&...args) {
if constexpr(std::is_void_v<decltype(std::invoke(std::forward<Candidate>(candidate), args...))>) {
std::invoke(std::forward<Candidate>(candidate), args...);
return meta_any{ctx, std::in_place_type<void>};
if constexpr(stl::is_void_v<decltype(stl::invoke(stl::forward<Candidate>(candidate), args...))>) {
stl::invoke(stl::forward<Candidate>(candidate), args...);
return meta_any{ctx, stl::in_place_type<void>};
} else {
return meta_dispatch<Policy>(ctx, std::invoke(std::forward<Candidate>(candidate), args...));
return meta_dispatch<Policy>(ctx, stl::invoke(stl::forward<Candidate>(candidate), args...));
}
}
template<typename Type, typename Policy, typename Candidate, std::size_t... 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>>;
template<typename Type, typename Policy, typename Candidate, stl::size_t... Index>
[[nodiscard]] meta_any meta_invoke(meta_any &instance, Candidate &&candidate, [[maybe_unused]] meta_any *const args, stl::index_sequence<Index...>) {
using descriptor = meta_function_helper_t<Type, stl::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>...>) {
// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and stl::span)
if constexpr(stl::is_invocable_v<stl::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>>()...);
return meta_invoke_with_args<Policy>(instance.context(), stl::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>...>) {
} else if constexpr(stl::is_invocable_v<stl::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>>()...);
return meta_invoke_with_args<Policy>(instance.context(), stl::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(), stl::forward<Candidate>(candidate), (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
}
}
// NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
@@ -226,11 +227,11 @@ template<typename Type, typename Policy, typename Candidate, std::size_t... Inde
return meta_any{meta_ctx_arg, instance.context()};
}
template<typename Type, typename... Args, std::size_t... Index>
[[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, meta_any *const args, std::index_sequence<Index...>) {
// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and std::span)
template<typename Type, typename... Args, stl::size_t... Index>
[[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, meta_any *const args, stl::index_sequence<Index...>) {
// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and stl::span)
if(((args + Index)->allow_cast<Args>() && ...)) {
return meta_any{ctx, std::in_place_type<Type>, (args + Index)->cast<Args>()...};
return meta_any{ctx, stl::in_place_type<Type>, (args + Index)->cast<Args>()...};
}
// NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
@@ -248,7 +249,7 @@ 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]] meta_type meta_arg(const meta_ctx &ctx, const std::size_t index) noexcept {
[[nodiscard]] meta_type meta_arg(const meta_ctx &ctx, const stl::size_t index) noexcept {
const auto &context = internal::meta_context::from(ctx);
return {ctx, internal::meta_arg_node(context, Type{}, index)};
}
@@ -260,7 +261,7 @@ template<typename Type>
* @return The meta type of the i-th element of the list of arguments.
*/
template<typename Type>
[[nodiscard]] meta_type meta_arg(const std::size_t index) noexcept {
[[nodiscard]] meta_type meta_arg(const stl::size_t index) noexcept {
return meta_arg<Type>(locator<meta_ctx>::value_or(), index);
}
@@ -274,27 +275,27 @@ template<typename Type>
*/
template<typename Type, auto Data>
[[nodiscard]] bool meta_setter([[maybe_unused]] meta_handle instance, [[maybe_unused]] meta_any value) {
if constexpr(std::is_member_function_pointer_v<decltype(Data)> || std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>>) {
if constexpr(stl::is_member_function_pointer_v<decltype(Data)> || stl::is_function_v<stl::remove_reference_t<stl::remove_pointer_t<decltype(Data)>>>) {
using descriptor = meta_function_helper_t<Type, decltype(Data)>;
using data_type = type_list_element_t<descriptor::is_static, typename descriptor::args_type>;
if(auto *const clazz = instance->try_cast<Type>(); clazz && value.allow_cast<data_type>()) {
std::invoke(Data, *clazz, value.cast<data_type>());
stl::invoke(Data, *clazz, value.cast<data_type>());
return true;
}
} else if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
using data_type = std::remove_reference_t<typename meta_function_helper_t<Type, decltype(Data)>::return_type>;
} else if constexpr(stl::is_member_object_pointer_v<decltype(Data)>) {
using data_type = stl::remove_reference_t<typename meta_function_helper_t<Type, decltype(Data)>::return_type>;
if constexpr(!std::is_array_v<data_type> && !std::is_const_v<data_type>) {
if constexpr(!stl::is_array_v<data_type> && !stl::is_const_v<data_type>) {
if(auto *const clazz = instance->try_cast<Type>(); clazz && value.allow_cast<data_type>()) {
std::invoke(Data, *clazz) = value.cast<data_type>();
stl::invoke(Data, *clazz) = value.cast<data_type>();
return true;
}
}
} else if constexpr(std::is_pointer_v<decltype(Data)>) {
using data_type = std::remove_reference_t<decltype(*Data)>;
} else if constexpr(stl::is_pointer_v<decltype(Data)>) {
using data_type = stl::remove_reference_t<decltype(*Data)>;
if constexpr(!std::is_array_v<data_type> && !std::is_const_v<data_type>) {
if constexpr(!stl::is_array_v<data_type> && !stl::is_const_v<data_type>) {
if(value.allow_cast<data_type>()) {
*Data = value.cast<data_type>();
return true;
@@ -313,26 +314,26 @@ 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_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_const_t<std::remove_reference_t<std::invoke_result_t<decltype(Data), Type &>>>>) {
if constexpr(std::is_invocable_v<decltype(Data), Type &>) {
template<typename Type, auto Data, meta_policy Policy = as_value_t>
[[nodiscard]] meta_any meta_getter(meta_handle instance) {
if constexpr(stl::is_member_pointer_v<decltype(Data)> || stl::is_function_v<stl::remove_reference_t<stl::remove_pointer_t<decltype(Data)>>>) {
if constexpr(!stl::is_array_v<stl::remove_cvref_t<stl::invoke_result_t<decltype(Data), Type &>>>) {
if constexpr(stl::is_invocable_v<decltype(Data), Type &>) {
if(auto *clazz = instance->try_cast<Type>(); clazz) {
return meta_dispatch<Policy>(instance->context(), std::invoke(Data, *clazz));
return meta_dispatch<Policy>(instance->context(), stl::invoke(Data, *clazz));
}
}
if constexpr(std::is_invocable_v<decltype(Data), const Type &>) {
if constexpr(stl::is_invocable_v<decltype(Data), const Type &>) {
if(auto *fallback = instance->try_cast<const Type>(); fallback) {
return meta_dispatch<Policy>(instance->context(), std::invoke(Data, *fallback));
return meta_dispatch<Policy>(instance->context(), stl::invoke(Data, *fallback));
}
}
}
return meta_any{meta_ctx_arg, instance->context()};
} else if constexpr(std::is_pointer_v<decltype(Data)>) {
if constexpr(std::is_array_v<std::remove_pointer_t<decltype(Data)>>) {
} else if constexpr(stl::is_pointer_v<decltype(Data)>) {
if constexpr(stl::is_array_v<stl::remove_pointer_t<decltype(Data)>>) {
return meta_any{meta_ctx_arg, instance->context()};
} else {
return meta_dispatch<Policy>(instance->context(), *Data);
@@ -352,9 +353,9 @@ template<typename Type, auto Data, typename Policy = as_value_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_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>(*instance.operator->(), std::forward<Candidate>(candidate), args, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<Candidate>>::args_type::size>{});
template<typename Type, meta_policy Policy = as_value_t, typename Candidate>
[[nodiscard]] meta_any meta_invoke(meta_handle instance, Candidate &&candidate, meta_any *const args) {
return internal::meta_invoke<Type, Policy>(*instance.operator->(), stl::forward<Candidate>(candidate), args, stl::make_index_sequence<meta_function_helper_t<Type, stl::remove_reference_t<Candidate>>::args_type::size>{});
}
/**
@@ -366,9 +367,9 @@ template<typename Type, typename Policy = as_value_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_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>(*instance.operator->(), Candidate, args, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<decltype(Candidate)>>::args_type::size>{});
template<typename Type, auto Candidate, meta_policy Policy = as_value_t>
[[nodiscard]] meta_any meta_invoke(meta_handle instance, meta_any *const args) {
return internal::meta_invoke<Type, Policy>(*instance.operator->(), Candidate, args, stl::make_index_sequence<meta_function_helper_t<Type, stl::remove_reference_t<decltype(Candidate)>>::args_type::size>{});
}
/**
@@ -386,7 +387,7 @@ template<typename Type, auto Candidate, typename Policy = as_value_t>
*/
template<typename Type, typename... Args>
[[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, meta_any *const args) {
return internal::meta_construct<Type, Args...>(ctx, args, std::index_sequence_for<Args...>{});
return internal::meta_construct<Type, Args...>(ctx, args, stl::index_sequence_for<Args...>{});
}
/**
@@ -418,12 +419,12 @@ template<typename Type, typename... Args>
*/
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_const_t<std::remove_reference_t<Candidate>>>) {
if constexpr(meta_function_helper_t<Type, Candidate>::is_static || stl::is_class_v<stl::remove_cvref_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>{});
return internal::meta_invoke<Type, Policy>(placeholder, stl::forward<Candidate>(candidate), args, stl::make_index_sequence<meta_function_helper_t<Type, stl::remove_reference_t<Candidate>>::args_type::size>{});
} else {
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and std::span)
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>{});
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and stl::span)
return internal::meta_invoke<Type, Policy>(*args, stl::forward<Candidate>(candidate), args + 1u, stl::make_index_sequence<meta_function_helper_t<Type, stl::remove_reference_t<Candidate>>::args_type::size>{});
}
}
@@ -436,9 +437,9 @@ template<typename Type, typename Policy = as_value_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_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);
template<typename Type, meta_policy Policy = as_value_t, typename Candidate>
[[nodiscard]] meta_any meta_construct(Candidate &&candidate, meta_any *const args) {
return meta_construct<Type, Policy>(locator<meta_ctx>::value_or(), stl::forward<Candidate>(candidate), args);
}
/**
@@ -455,8 +456,8 @@ template<typename Type, typename Policy = as_value_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_value_t>
[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_construct(const meta_ctx &ctx, meta_any *const args) {
template<typename Type, auto Candidate, meta_policy Policy = as_value_t>
[[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, meta_any *const args) {
return meta_construct<Type, Policy>(ctx, Candidate, args);
}
@@ -468,8 +469,8 @@ template<typename Type, auto Candidate, typename Policy = as_value_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_value_t>
[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_construct(meta_any *const args) {
template<typename Type, auto Candidate, meta_policy Policy = as_value_t>
[[nodiscard]] meta_any meta_construct(meta_any *const args) {
return meta_construct<Type, Candidate, Policy>(locator<meta_ctx>::value_or(), args);
}

View File

@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="entt::internal::meta_base_node">
<DisplayString Condition="resolve != nullptr">{{ type={ type } }}</DisplayString>
<DisplayString Condition="type != nullptr">{{ id={ id } }}</DisplayString>
<DisplayString>{{}}</DisplayString>
<Expand>
<Item Name="[type]">type</Item>
<Item Name="[id]">id</Item>
</Expand>
</Type>
<Type Name="entt::internal::meta_conv_node">
<DisplayString Condition="conv != nullptr">{{ type={ type } }}</DisplayString>
<DisplayString Condition="conv != nullptr">{{ id={ id } }}</DisplayString>
<DisplayString>{{}}</DisplayString>
<Expand>
<Item Name="[type]">type</Item>
<Item Name="[type]">id</Item>
</Expand>
</Type>
<Type Name="entt::internal::meta_ctor_node">
@@ -23,10 +23,10 @@
</Expand>
</Type>
<Type Name="entt::internal::meta_custom_node">
<DisplayString Condition="value != nullptr">{{ type={ type } }}</DisplayString>
<DisplayString Condition="value != nullptr">{{ id={ id } }}</DisplayString>
<DisplayString>{{}}</DisplayString>
<Expand>
<Item Name="[type]">type</Item>
<Item Name="[id]">id</Item>
<Item Name="[value]">value</Item>
</Expand>
</Type>
@@ -142,14 +142,14 @@
</Expand>
</Type>
<Type Name="entt::meta_custom">
<DisplayString Condition="node != nullptr">{ node }</DisplayString>
<DisplayString Condition="node != nullptr">{ node,na }</DisplayString>
<DisplayString>{{}}</DisplayString>
<Expand>
<ExpandedItem Condition="node != nullptr">node</ExpandedItem>
</Expand>
</Type>
<Type Name="entt::meta_data">
<DisplayString Condition="node != nullptr">{ node }</DisplayString>
<DisplayString Condition="node != nullptr">{ node,na }</DisplayString>
<DisplayString>{{}}</DisplayString>
<Expand>
<ExpandedItem Condition="node != nullptr">node</ExpandedItem>
@@ -157,7 +157,15 @@
</Expand>
</Type>
<Type Name="entt::meta_func">
<DisplayString Condition="node != nullptr">{ node }</DisplayString>
<DisplayString Condition="node != nullptr">{ node,na }</DisplayString>
<DisplayString>{{}}</DisplayString>
<Expand>
<ExpandedItem Condition="node != nullptr">node</ExpandedItem>
<Item Name="[context]" Condition="ctx != nullptr">ctx,na</Item>
</Expand>
</Type>
<Type Name="entt::meta_base">
<DisplayString Condition="node != nullptr">{ node,na }</DisplayString>
<DisplayString>{{}}</DisplayString>
<Expand>
<ExpandedItem Condition="node != nullptr">node</ExpandedItem>
@@ -165,7 +173,7 @@
</Expand>
</Type>
<Type Name="entt::meta_type">
<DisplayString Condition="node != nullptr">{ node }</DisplayString>
<DisplayString Condition="node != nullptr">{ node,na }</DisplayString>
<DisplayString>{{}}</DisplayString>
<Expand>
<ExpandedItem Condition="node != nullptr">node</ExpandedItem>
@@ -173,14 +181,14 @@
</Expand>
</Type>
<Type Name="entt::meta_ctx">
<Intrinsic Name="element_at" Expression="value.packed.first_base::value[pos].element">
<Intrinsic Name="element_at" Expression="bucket.packed.first_base::value[pos].element">
<Parameter Name="pos" Type="int"/>
</Intrinsic>
<DisplayString>{ value }</DisplayString>
<DisplayString>{ bucket }</DisplayString>
<Expand>
<CustomListItems>
<Variable Name="pos" InitialValue="0"/>
<Variable Name="last" InitialValue="value.size()"/>
<Variable Name="last" InitialValue="bucket.size()"/>
<Loop>
<Break Condition="pos == last"/>
<Item Name="[{ element_at(pos).first }]">element_at(pos).second</Item>

View File

@@ -21,6 +21,7 @@
<DisplayString>{{ size={ events.size() }, event={ "$T1" } }}</DisplayString>
<Expand>
<Item Name="[signal]">signal</Item>
<Item Name="[events]">events,view(simple)</Item>
</Expand>
</Type>
<Type Name="entt::emitter&lt;*&gt;">

View File

@@ -1,12 +1,12 @@
#ifndef ENTT_POLY_FWD_HPP
#define ENTT_POLY_FWD_HPP
#include <cstddef>
#include "../stl/cstddef.hpp"
namespace entt {
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
template<typename, std::size_t Len = sizeof(double[2]), std::size_t = alignof(double[2])>
template<typename, stl::size_t Len = sizeof(double[2]), stl::size_t = alignof(double[2])>
class basic_poly;
/**

View File

@@ -1,14 +1,16 @@
#ifndef ENTT_POLY_POLY_HPP
#define ENTT_POLY_POLY_HPP
#include <cstddef>
#include <functional>
#include <tuple>
#include <type_traits>
#include <utility>
#include "../core/any.hpp"
#include "../core/concepts.hpp"
#include "../core/type_info.hpp"
#include "../core/type_traits.hpp"
#include "../stl/concepts.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/functional.hpp"
#include "../stl/tuple.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "fwd.hpp"
namespace entt {
@@ -29,11 +31,11 @@ struct poly_inspector {
* @param args The arguments to pass to the function.
* @return A poly inspector convertible to any type.
*/
template<std::size_t Member, typename... Args>
template<stl::size_t Member, typename... Args>
[[nodiscard]] poly_inspector invoke(Args &&...args) const;
/*! @copydoc invoke */
template<std::size_t Member, typename... Args>
template<stl::size_t Member, typename... Args>
[[nodiscard]] poly_inspector invoke(Args &&...args);
};
@@ -43,78 +45,80 @@ struct poly_inspector {
* @tparam Len Size of the storage reserved for the small buffer optimization.
* @tparam Align Alignment requirement.
*/
template<typename Concept, std::size_t Len, std::size_t Align>
template<typename Concept, stl::size_t Len, stl::size_t Align>
class poly_vtable {
using inspector = typename Concept::template type<poly_inspector>;
using inspector = Concept::template type<poly_inspector>;
template<typename Ret, typename Clazz, typename... Args>
requires stl::derived_from<inspector, stl::remove_const_t<Clazz>>
static auto vtable_entry(Ret (*)(Clazz &, Args...))
-> std::enable_if_t<std::is_base_of_v<std::remove_const_t<Clazz>, inspector>, Ret (*)(constness_as_t<basic_any<Len, Align>, Clazz> &, Args...)>;
-> Ret (*)(constness_as_t<basic_any<Len, Align>, Clazz> &, Args...);
template<typename Ret, typename... Args>
static auto vtable_entry(Ret (*)(Args...))
-> Ret (*)(const basic_any<Len, Align> &, Args...);
template<typename Ret, typename Clazz, typename... Args>
requires stl::derived_from<inspector, Clazz>
static auto vtable_entry(Ret (Clazz::*)(Args...))
-> std::enable_if_t<std::is_base_of_v<Clazz, inspector>, Ret (*)(basic_any<Len, Align> &, Args...)>;
-> Ret (*)(basic_any<Len, Align> &, Args...);
template<typename Ret, typename Clazz, typename... Args>
requires stl::derived_from<inspector, Clazz>
static auto vtable_entry(Ret (Clazz::*)(Args...) const)
-> std::enable_if_t<std::is_base_of_v<Clazz, inspector>, Ret (*)(const basic_any<Len, Align> &, Args...)>;
-> Ret (*)(const basic_any<Len, Align> &, Args...);
template<auto... Candidate>
static auto make_vtable(value_list<Candidate...>) noexcept
-> decltype(std::make_tuple(vtable_entry(Candidate)...));
-> decltype(stl::make_tuple(vtable_entry(Candidate)...));
template<typename... Func>
[[nodiscard]] static constexpr auto make_vtable(type_list<Func...>) noexcept {
[[nodiscard]] static ENTT_CONSTEVAL auto make_vtable(type_list<Func...>) noexcept {
if constexpr(sizeof...(Func) == 0u) {
return decltype(make_vtable(typename Concept::template impl<inspector>{})){};
} else if constexpr((std::is_function_v<Func> && ...)) {
return decltype(std::make_tuple(vtable_entry(std::declval<Func inspector::*>())...)){};
} else if constexpr((stl::is_function_v<Func> && ...)) {
return decltype(stl::make_tuple(vtable_entry(stl::declval<Func inspector::*>())...)){};
}
}
template<typename Type, auto Candidate, typename Ret, typename Any, typename... Args>
static void fill_vtable_entry(Ret (*&entry)(Any &, Args...)) noexcept {
if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Args...>) {
if constexpr(stl::is_invocable_r_v<Ret, decltype(Candidate), Args...>) {
entry = +[](Any &, Args... args) -> Ret {
return std::invoke(Candidate, std::forward<Args>(args)...);
return stl::invoke(Candidate, stl::forward<Args>(args)...);
};
} else {
entry = +[](Any &instance, Args... args) -> Ret {
return static_cast<Ret>(std::invoke(Candidate, any_cast<constness_as_t<Type, Any> &>(instance), std::forward<Args>(args)...));
return static_cast<Ret>(stl::invoke(Candidate, any_cast<constness_as_t<Type, Any> &>(instance), stl::forward<Args>(args)...));
};
}
}
template<typename Type, auto... Index>
[[nodiscard]] static auto fill_vtable(std::index_sequence<Index...>) noexcept {
[[nodiscard]] static auto fill_vtable(stl::index_sequence<Index...>) noexcept {
vtable_type impl{};
(fill_vtable_entry<Type, value_list_element_v<Index, typename Concept::template impl<Type>>>(std::get<Index>(impl)), ...);
(fill_vtable_entry<Type, value_list_element_v<Index, typename Concept::template impl<Type>>>(stl::get<Index>(impl)), ...);
return impl;
}
using vtable_type = decltype(make_vtable(Concept{}));
static constexpr bool is_mono = std::tuple_size_v<vtable_type> == 1u;
static constexpr bool is_mono = stl::tuple_size_v<vtable_type> == 1u;
public:
/*! @brief Virtual table type. */
using type = std::conditional_t<is_mono, std::tuple_element_t<0u, vtable_type>, const vtable_type *>;
using type = stl::conditional_t<is_mono, stl::tuple_element_t<0u, vtable_type>, const vtable_type *>;
/**
* @brief Returns a static virtual table for a specific concept and type.
* @tparam Type The type for which to generate the virtual table.
* @return A static virtual table for the given concept and type.
*/
template<typename Type>
template<cvref_unqualified Type>
[[nodiscard]] static type instance() noexcept {
static_assert(std::is_same_v<Type, std::decay_t<Type>>, "Type differs from its decayed form");
static const vtable_type vtable = fill_vtable<Type>(std::make_index_sequence<Concept::template impl<Type>::size>{});
static const vtable_type vtable = fill_vtable<Type>(stl::make_index_sequence<Concept::template impl<Type>::size>{});
if constexpr(is_mono) {
return std::get<0>(vtable);
return stl::get<0>(vtable);
} else {
return &vtable;
}
@@ -135,27 +139,27 @@ struct poly_base {
* @param args The arguments to pass to the function.
* @return The return value of the invoked function, if any.
*/
template<std::size_t Member, typename... Args>
template<stl::size_t Member, typename... Args>
[[nodiscard]] decltype(auto) invoke(const poly_base &self, Args &&...args) const {
const auto &poly = static_cast<const Poly &>(self);
if constexpr(std::is_function_v<std::remove_pointer_t<decltype(poly.vtable)>>) {
return poly.vtable(poly.storage, std::forward<Args>(args)...);
if constexpr(stl::is_function_v<stl::remove_pointer_t<decltype(poly.vtable)>>) {
return poly.vtable(poly.storage, stl::forward<Args>(args)...);
} else {
return std::get<Member>(*poly.vtable)(poly.storage, std::forward<Args>(args)...);
return stl::get<Member>(*poly.vtable)(poly.storage, stl::forward<Args>(args)...);
}
}
/*! @copydoc invoke */
template<std::size_t Member, typename... Args>
template<stl::size_t Member, typename... Args>
[[nodiscard]] decltype(auto) invoke(poly_base &self, Args &&...args) {
auto &poly = static_cast<Poly &>(self);
if constexpr(std::is_function_v<std::remove_pointer_t<decltype(poly.vtable)>>) {
if constexpr(stl::is_function_v<stl::remove_pointer_t<decltype(poly.vtable)>>) {
static_assert(Member == 0u, "Unknown member");
return poly.vtable(poly.storage, std::forward<Args>(args)...);
return poly.vtable(poly.storage, stl::forward<Args>(args)...);
} else {
return std::get<Member>(*poly.vtable)(poly.storage, std::forward<Args>(args)...);
return stl::get<Member>(*poly.vtable)(poly.storage, stl::forward<Args>(args)...);
}
}
};
@@ -169,9 +173,9 @@ struct poly_base {
* @param args The arguments to pass to the function.
* @return The return value of the invoked function, if any.
*/
template<std::size_t Member, typename Poly, typename... Args>
template<stl::size_t Member, typename Poly, typename... Args>
decltype(auto) poly_call(Poly &&self, Args &&...args) {
return std::forward<Poly>(self).template invoke<Member>(self, std::forward<Args>(args)...);
return stl::forward<Poly>(self).template invoke<Member>(self, stl::forward<Args>(args)...);
}
/**
@@ -189,15 +193,15 @@ decltype(auto) poly_call(Poly &&self, Args &&...args) {
* @tparam Len Size of the storage reserved for the small buffer optimization.
* @tparam Align Optional alignment requirement.
*/
template<typename Concept, std::size_t Len, std::size_t Align>
template<typename Concept, stl::size_t Len, stl::size_t Align>
class basic_poly: private Concept::template type<poly_base<basic_poly<Concept, Len, Align>>> {
friend struct poly_base<basic_poly>;
public:
/*! @brief Concept type. */
using concept_type = typename Concept::template type<poly_base<basic_poly>>;
using concept_type = Concept::template type<poly_base<basic_poly>>;
/*! @brief Virtual table type. */
using vtable_type = typename poly_vtable<Concept, Len, Align>::type;
using vtable_type = poly_vtable<Concept, Len, Align>::type;
/*! @brief Default constructor. */
basic_poly() noexcept = default;
@@ -209,18 +213,19 @@ public:
* @param args Parameters to use to construct the instance.
*/
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_const_t<std::remove_reference_t<Type>>>()} {}
explicit basic_poly(stl::in_place_type_t<Type>, Args &&...args)
: storage{stl::in_place_type<Type>, stl::forward<Args>(args)...},
vtable{poly_vtable<Concept, Len, Align>::template instance<stl::remove_cvref_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_const_t<std::remove_reference_t<Type>>, basic_poly>>>
template<typename Type>
requires (!stl::same_as<stl::remove_cvref_t<Type>, basic_poly>)
basic_poly(Type &&value) noexcept
: basic_poly{std::in_place_type<std::remove_const_t<std::remove_reference_t<Type>>>, std::forward<Type>(value)} {}
: basic_poly{stl::in_place_type<stl::remove_cvref_t<Type>>, stl::forward<Type>(value)} {}
/**
* @brief Returns the object type info if any, `type_id<void>()` otherwise.
@@ -230,11 +235,6 @@ public:
return storage.info();
}
/*! @copydoc info */
[[deprecated("use ::info instead")]] [[nodiscard]] const type_info &type() const noexcept {
return info();
}
/**
* @brief Returns an opaque pointer to the contained instance.
* @return An opaque pointer the contained instance, if any.
@@ -256,8 +256,8 @@ 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_const_t<std::remove_reference_t<Type>>>();
storage.template emplace<Type>(stl::forward<Args>(args)...);
vtable = poly_vtable<Concept, Len, Align>::template instance<stl::remove_cvref_t<Type>>();
}
/*! @brief Destroys contained object */

View File

@@ -1,22 +1,22 @@
#ifndef ENTT_PROCESS_FWD_HPP
#define ENTT_PROCESS_FWD_HPP
#include <cstdint>
#include <memory>
#include "../stl/cstdint.hpp"
#include "../stl/memory.hpp"
namespace entt {
template<typename, typename = std::allocator<void>>
template<typename, typename = stl::allocator<void>>
class basic_process;
/*! @brief Alias declaration for the most common use case. */
using process = basic_process<std::uint32_t>;
using process = basic_process<stl::uint32_t>;
template<typename, typename = std::allocator<void>>
template<typename, typename = stl::allocator<void>>
class basic_scheduler;
/*! @brief Alias declaration for the most common use case. */
using scheduler = basic_scheduler<std::uint32_t>;
using scheduler = basic_scheduler<stl::uint32_t>;
} // namespace entt

View File

@@ -1,17 +1,17 @@
#ifndef ENTT_PROCESS_PROCESS_HPP
#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 "../stl/cstdint.hpp"
#include "../stl/memory.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "fwd.hpp"
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
template<typename, typename, typename>
@@ -69,8 +69,8 @@ struct process_adaptor;
* @tparam Allocator Type of allocator used to manage memory and elements.
*/
template<typename Delta, typename Allocator>
class basic_process: public std::enable_shared_from_this<basic_process<Delta, Allocator>> {
enum class state : std::uint8_t {
class basic_process: public stl::enable_shared_from_this<basic_process<Delta, Allocator>> {
enum class state : stl::uint8_t {
idle = 0,
running,
paused,
@@ -95,7 +95,7 @@ public:
/*! @brief Type used to provide elapsed time. */
using delta_type = Delta;
/*! @brief Handle type. */
using handle_type = std::shared_ptr<basic_process>;
using handle_type = stl::shared_ptr<basic_process>;
/*! @brief Default constructor. */
basic_process()
@@ -221,7 +221,7 @@ public:
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)...));
return *(next.first() = stl::allocate_shared<Type>(allocator, allocator, stl::forward<Args>(args)...));
}
/**
@@ -234,7 +234,7 @@ public:
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)));
return *(next.first() = stl::allocate_shared<process_type>(allocator, allocator, stl::move(func)));
}
/**
@@ -287,18 +287,18 @@ private:
state current;
};
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
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;
using delta_type = base_type::delta_type;
process_adaptor(const allocator_type &allocator, Func proc)
: base_type{allocator},
func{std::move(proc)} {}
func{stl::move(proc)} {}
void update(const delta_type delta, void *data) override {
func(*this, delta, data);

View File

@@ -1,13 +1,13 @@
#ifndef ENTT_PROCESS_SCHEDULER_HPP
#define ENTT_PROCESS_SCHEDULER_HPP
#include <cstddef>
#include <memory>
#include <type_traits>
#include <utility>
#include <vector>
#include "../config/config.h"
#include "../core/compressed_pair.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/memory.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "../stl/vector.hpp"
#include "fwd.hpp"
#include "process.hpp"
@@ -35,9 +35,9 @@ namespace entt {
template<typename Delta, typename Allocator>
class basic_scheduler {
using base_type = basic_process<Delta, Allocator>;
using alloc_traits = std::allocator_traits<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>;
using alloc_traits = stl::allocator_traits<Allocator>;
using container_allocator = alloc_traits::template rebind_alloc<stl::shared_ptr<base_type>>;
using container_type = stl::vector<stl::shared_ptr<base_type>, container_allocator>;
public:
/*! @brief Process type. */
@@ -45,7 +45,7 @@ public:
/*! @brief Allocator type. */
using allocator_type = Allocator;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
using size_type = stl::size_t;
/*! @brief Unsigned integer type. */
using delta_type = Delta;
@@ -68,7 +68,7 @@ public:
* @param other The instance to move from.
*/
basic_scheduler(basic_scheduler &&other) noexcept
: handlers{std::move(other.handlers)} {}
: handlers{stl::move(other.handlers)} {}
/**
* @brief Allocator-extended move constructor.
@@ -76,7 +76,7 @@ public:
* @param allocator The allocator to use.
*/
basic_scheduler(basic_scheduler &&other, const allocator_type &allocator)
: handlers{container_type{std::move(other.handlers.first()), allocator}, allocator} {
: handlers{container_type{stl::move(other.handlers.first()), allocator}, allocator} {
ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a scheduler is not allowed");
}
@@ -105,7 +105,7 @@ public:
* @param other Scheduler to exchange the content with.
*/
void swap(basic_scheduler &other) noexcept {
using std::swap;
using stl::swap;
swap(handlers, other.handlers);
}
@@ -153,7 +153,7 @@ public:
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)...));
return *handlers.first().emplace_back(stl::allocate_shared<Type>(allocator, allocator, stl::forward<Args>(args)...));
}
/**
@@ -166,7 +166,7 @@ public:
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)));
return *handlers.first().emplace_back(stl::allocate_shared<process_type>(allocator, allocator, stl::move(func)));
}
/**
@@ -192,7 +192,7 @@ public:
}
if(!elem || elem->rejected()) {
elem = std::move(handlers.first().back());
elem = stl::move(handlers.first().back());
handlers.first().pop_back();
}
}

View File

@@ -1,25 +1,26 @@
#ifndef ENTT_RESOURCE_RESOURCE_CACHE_HPP
#define ENTT_RESOURCE_RESOURCE_CACHE_HPP
#include <cstddef>
#include <functional>
#include <iterator>
#include <memory>
#include <tuple>
#include <type_traits>
#include <utility>
#include <compare>
#include "../container/dense_map.hpp"
#include "../core/compressed_pair.hpp"
#include "../core/fwd.hpp"
#include "../core/iterator.hpp"
#include "../core/utility.hpp"
#include "../stl/concepts.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/functional.hpp"
#include "../stl/iterator.hpp"
#include "../stl/memory.hpp"
#include "../stl/tuple.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "fwd.hpp"
#include "loader.hpp"
#include "resource.hpp"
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
template<typename Type, typename It>
@@ -28,20 +29,21 @@ class resource_cache_iterator final {
friend class resource_cache_iterator;
public:
using value_type = std::pair<id_type, resource<Type>>;
using value_type = stl::pair<id_type, resource<Type>>;
using pointer = input_iterator_pointer<value_type>;
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category = std::input_iterator_tag;
using iterator_concept = std::random_access_iterator_tag;
using difference_type = stl::ptrdiff_t;
using iterator_category = stl::input_iterator_tag;
using iterator_concept = stl::random_access_iterator_tag;
constexpr resource_cache_iterator() noexcept = default;
constexpr resource_cache_iterator(const It iter) noexcept
: it{iter} {}
template<typename Other, typename = std::enable_if_t<!std::is_same_v<It, Other> && std::is_constructible_v<It, Other>>>
constexpr resource_cache_iterator(const resource_cache_iterator<std::remove_const_t<Type>, Other> &other) noexcept
template<typename Other>
requires (!stl::same_as<It, Other> && stl::constructible_from<It, Other>)
constexpr resource_cache_iterator(const resource_cache_iterator<stl::remove_const_t<Type>, Other> &other) noexcept
: it{other.it} {}
constexpr resource_cache_iterator &operator++() noexcept {
@@ -92,54 +94,25 @@ public:
return operator*();
}
template<typename... Lhs, typename... Rhs>
friend constexpr std::ptrdiff_t operator-(const resource_cache_iterator<Lhs...> &, const resource_cache_iterator<Rhs...> &) noexcept;
template<typename... Args>
[[nodiscard]] constexpr stl::ptrdiff_t operator-(const resource_cache_iterator<Args...> &other) const noexcept {
return it - other.it;
}
template<typename... Lhs, typename... Rhs>
friend constexpr bool operator==(const resource_cache_iterator<Lhs...> &, const resource_cache_iterator<Rhs...> &) noexcept;
template<typename... Args>
[[nodiscard]] constexpr bool operator==(const resource_cache_iterator<Args...> &other) const noexcept {
return it == other.it;
}
template<typename... Lhs, typename... Rhs>
friend constexpr bool operator<(const resource_cache_iterator<Lhs...> &, const resource_cache_iterator<Rhs...> &) noexcept;
template<typename... Args>
[[nodiscard]] constexpr auto operator<=>(const resource_cache_iterator<Args...> &other) const noexcept {
return it <=> other.it;
}
private:
It it;
};
template<typename... Lhs, typename... Rhs>
[[nodiscard]] constexpr std::ptrdiff_t operator-(const resource_cache_iterator<Lhs...> &lhs, const resource_cache_iterator<Rhs...> &rhs) noexcept {
return lhs.it - rhs.it;
}
template<typename... Lhs, typename... Rhs>
[[nodiscard]] constexpr bool operator==(const resource_cache_iterator<Lhs...> &lhs, const resource_cache_iterator<Rhs...> &rhs) noexcept {
return lhs.it == rhs.it;
}
template<typename... Lhs, typename... Rhs>
[[nodiscard]] constexpr bool operator!=(const resource_cache_iterator<Lhs...> &lhs, const resource_cache_iterator<Rhs...> &rhs) noexcept {
return !(lhs == rhs);
}
template<typename... Lhs, typename... Rhs>
[[nodiscard]] constexpr bool operator<(const resource_cache_iterator<Lhs...> &lhs, const resource_cache_iterator<Rhs...> &rhs) noexcept {
return lhs.it < rhs.it;
}
template<typename... Lhs, typename... Rhs>
[[nodiscard]] constexpr bool operator>(const resource_cache_iterator<Lhs...> &lhs, const resource_cache_iterator<Rhs...> &rhs) noexcept {
return rhs < lhs;
}
template<typename... Lhs, typename... Rhs>
[[nodiscard]] constexpr bool operator<=(const resource_cache_iterator<Lhs...> &lhs, const resource_cache_iterator<Rhs...> &rhs) noexcept {
return !(lhs > rhs);
}
template<typename... Lhs, typename... Rhs>
[[nodiscard]] constexpr bool operator>=(const resource_cache_iterator<Lhs...> &lhs, const resource_cache_iterator<Rhs...> &rhs) noexcept {
return !(lhs < rhs);
}
} // namespace internal
/*! @endcond */
@@ -151,10 +124,10 @@ template<typename... Lhs, typename... Rhs>
*/
template<typename Type, typename Loader, typename Allocator>
class resource_cache {
using alloc_traits = std::allocator_traits<Allocator>;
static_assert(std::is_same_v<typename alloc_traits::value_type, Type>, "Invalid value type");
using container_allocator = typename alloc_traits::template rebind_alloc<std::pair<const id_type, typename Loader::result_type>>;
using container_type = dense_map<id_type, typename Loader::result_type, identity, std::equal_to<>, container_allocator>;
using alloc_traits = stl::allocator_traits<Allocator>;
static_assert(stl::is_same_v<typename alloc_traits::value_type, Type>, "Invalid value type");
using container_allocator = alloc_traits::template rebind_alloc<stl::pair<const id_type, typename Loader::result_type>>;
using container_type = dense_map<id_type, typename Loader::result_type, stl::identity, stl::equal_to<>, container_allocator>;
public:
/*! @brief Allocator type. */
@@ -162,7 +135,7 @@ public:
/*! @brief Resource type. */
using value_type = Type;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
using size_type = stl::size_t;
/*! @brief Loader type. */
using loader_type = Loader;
/*! @brief Input iterator type. */
@@ -198,7 +171,7 @@ public:
* @param allocator The allocator to use.
*/
resource_cache(const resource_cache &other, const allocator_type &allocator)
: pool{std::piecewise_construct, std::forward_as_tuple(other.pool.first(), allocator), std::forward_as_tuple(other.pool.second())} {}
: pool{stl::piecewise_construct, stl::forward_as_tuple(other.pool.first(), allocator), stl::forward_as_tuple(other.pool.second())} {}
/*! @brief Default move constructor. */
resource_cache(resource_cache &&) noexcept = default;
@@ -209,7 +182,7 @@ public:
* @param allocator The allocator to use.
*/
resource_cache(resource_cache &&other, const allocator_type &allocator)
: pool{std::piecewise_construct, std::forward_as_tuple(std::move(other.pool.first()), allocator), std::forward_as_tuple(std::move(other.pool.second()))} {}
: pool{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.pool.first()), allocator), stl::forward_as_tuple(stl::move(other.pool.second()))} {}
/*! @brief Default destructor. */
~resource_cache() = default;
@@ -313,21 +286,21 @@ public:
* insertion took place.
*/
template<typename... Args>
std::pair<iterator, bool> load(const id_type id, Args &&...args) {
stl::pair<iterator, bool> load(const id_type id, Args &&...args) {
if(auto it = pool.first().find(id); it != pool.first().end()) {
return {it, false};
}
return pool.first().emplace(id, pool.second()(std::forward<Args>(args)...));
return pool.first().emplace(id, pool.second()(stl::forward<Args>(args)...));
}
/**
* @brief Force loads a resource, if its identifier does not exist.
* @brief Force loads a resource, even if its identifier already exists.
* @copydetails load
*/
template<typename... Args>
std::pair<iterator, bool> force_load(const id_type id, Args &&...args) {
return {pool.first().insert_or_assign(id, pool.second()(std::forward<Args>(args)...)).first, true};
stl::pair<iterator, bool> force_load(const id_type id, Args &&...args) {
return {pool.first().insert_or_assign(id, pool.second()(stl::forward<Args>(args)...)).first, true};
}
/**

View File

@@ -1,14 +1,14 @@
#ifndef ENTT_RESOURCE_FWD_HPP
#define ENTT_RESOURCE_FWD_HPP
#include <memory>
#include "../stl/memory.hpp"
namespace entt {
template<typename>
struct resource_loader;
template<typename Type, typename = resource_loader<Type>, typename = std::allocator<Type>>
template<typename Type, typename = resource_loader<Type>, typename = stl::allocator<Type>>
class resource_cache;
template<typename>

View File

@@ -1,8 +1,8 @@
#ifndef ENTT_RESOURCE_LOADER_HPP
#define ENTT_RESOURCE_LOADER_HPP
#include <memory>
#include <utility>
#include "../stl/memory.hpp"
#include "../stl/utility.hpp"
#include "fwd.hpp"
namespace entt {
@@ -14,7 +14,7 @@ namespace entt {
template<typename Type>
struct resource_loader {
/*! @brief Result type. */
using result_type = std::shared_ptr<Type>;
using result_type = stl::shared_ptr<Type>;
/**
* @brief Constructs a shared pointer to a resource from its arguments.
@@ -24,7 +24,7 @@ struct resource_loader {
*/
template<typename... Args>
result_type operator()(Args &&...args) const {
return std::make_shared<Type>(std::forward<Args>(args)...);
return stl::make_shared<Type>(stl::forward<Args>(args)...);
}
};

View File

@@ -1,9 +1,10 @@
#ifndef ENTT_RESOURCE_RESOURCE_HPP
#define ENTT_RESOURCE_RESOURCE_HPP
#include <memory>
#include <type_traits>
#include <utility>
#include <compare>
#include "../stl/concepts.hpp"
#include "../stl/memory.hpp"
#include "../stl/utility.hpp"
#include "fwd.hpp"
namespace entt {
@@ -23,14 +24,11 @@ class resource {
template<typename>
friend class resource;
template<typename Other>
static constexpr bool is_acceptable = !std::is_same_v<Type, Other> && std::is_constructible_v<Type &, Other &>;
public:
/*! @brief Resource type. */
using element_type = Type;
/*! @brief Handle type. */
using handle_type = std::shared_ptr<element_type>;
using handle_type = stl::shared_ptr<element_type>;
/*! @brief Default constructor. */
resource() noexcept
@@ -41,7 +39,7 @@ public:
* @param res A handle to a resource.
*/
explicit resource(handle_type res) noexcept
: value{std::move(res)} {}
: value{stl::move(res)} {}
/*! @brief Default copy constructor. */
resource(const resource &) noexcept = default;
@@ -57,14 +55,15 @@ public:
*/
template<typename Other>
resource(const resource<Other> &other, element_type &res) noexcept
: value{other.value, std::addressof(res)} {}
: value{other.value, stl::addressof(res)} {}
/**
* @brief Copy constructs a handle which shares ownership of the resource.
* @tparam Other Type of resource managed by the received handle.
* @param other The handle to copy from.
*/
template<typename Other, typename = std::enable_if_t<is_acceptable<Other>>>
template<typename Other>
requires (!stl::same_as<Type, Other> && stl::constructible_from<Type &, Other &>)
resource(const resource<Other> &other) noexcept
: value{other.value} {}
@@ -73,9 +72,10 @@ public:
* @tparam Other Type of resource managed by the received handle.
* @param other The handle to move from.
*/
template<typename Other, typename = std::enable_if_t<is_acceptable<Other>>>
template<typename Other>
requires (!stl::same_as<Type, Other> && stl::constructible_from<Type &, Other &>)
resource(resource<Other> &&other) noexcept
: value{std::move(other.value)} {}
: value{stl::move(other.value)} {}
/*! @brief Default destructor. */
~resource() = default;
@@ -98,7 +98,8 @@ public:
* @param other The handle to copy from.
* @return This resource handle.
*/
template<typename Other, typename = std::enable_if_t<is_acceptable<Other>>>
template<typename Other>
requires (!stl::same_as<Type, Other> && stl::constructible_from<Type &, Other &>)
resource &operator=(const resource<Other> &other) noexcept {
value = other.value;
return *this;
@@ -110,9 +111,10 @@ public:
* @param other The handle to move from.
* @return This resource handle.
*/
template<typename Other, typename = std::enable_if_t<is_acceptable<Other>>>
template<typename Other>
requires (!stl::same_as<Type, Other> && stl::constructible_from<Type &, Other &>)
resource &operator=(resource<Other> &&other) noexcept {
value = std::move(other.value);
value = stl::move(other.value);
return *this;
}
@@ -121,7 +123,7 @@ public:
* @param other Resource to exchange the content with.
*/
void swap(resource &other) noexcept {
using std::swap;
using stl::swap;
swap(value, other.value);
}
@@ -158,6 +160,28 @@ public:
return static_cast<bool>(value);
}
/**
* @brief Compares two handles.
* @tparam Other Type of resource managed by the other handle.
* @param other A valid handle.
* @return True if both handles refer to the same resource, false otherwise.
*/
template<typename Other>
[[nodiscard]] bool operator==(const resource<Other> &other) const noexcept {
return (stl::addressof(*value) == stl::addressof(*other.value));
}
/**
* @brief Lexicographically compares two handles.
* @tparam Other Type of resource managed by the other handle.
* @param other A valid handle.
* @return The relative order between the two handles.
*/
template<typename Other>
[[nodiscard]] auto operator<=>(const resource<Other> &other) const noexcept {
return (stl::addressof(*value) <=> stl::addressof(*other.value));
}
/*! @brief Releases the ownership of the managed resource. */
void reset() {
value.reset();
@@ -168,7 +192,7 @@ public:
* @param other A handle to a resource.
*/
void reset(handle_type other) {
value = std::move(other);
value = stl::move(other);
}
/**
@@ -183,86 +207,6 @@ private:
handle_type value;
};
/**
* @brief Compares two handles.
* @tparam Lhs Type of resource managed by the first handle.
* @tparam Rhs Type of resource managed by the second handle.
* @param lhs A valid handle.
* @param rhs A valid handle.
* @return True if both handles refer to the same resource, false otherwise.
*/
template<typename Lhs, typename Rhs>
[[nodiscard]] bool operator==(const resource<Lhs> &lhs, const resource<Rhs> &rhs) noexcept {
return (std::addressof(*lhs) == std::addressof(*rhs));
}
/**
* @brief Compares two handles.
* @tparam Lhs Type of resource managed by the first handle.
* @tparam Rhs Type of resource managed by the second handle.
* @param lhs A valid handle.
* @param rhs A valid handle.
* @return False if both handles refer to the same resource, true otherwise.
*/
template<typename Lhs, typename Rhs>
[[nodiscard]] bool operator!=(const resource<Lhs> &lhs, const resource<Rhs> &rhs) noexcept {
return !(lhs == rhs);
}
/**
* @brief Compares two handles.
* @tparam Lhs Type of resource managed by the first handle.
* @tparam Rhs Type of resource managed by the second handle.
* @param lhs A valid handle.
* @param rhs A valid handle.
* @return True if the first handle is less than the second, false otherwise.
*/
template<typename Lhs, typename Rhs>
[[nodiscard]] bool operator<(const resource<Lhs> &lhs, const resource<Rhs> &rhs) noexcept {
return (std::addressof(*lhs) < std::addressof(*rhs));
}
/**
* @brief Compares two handles.
* @tparam Lhs Type of resource managed by the first handle.
* @tparam Rhs Type of resource managed by the second handle.
* @param lhs A valid handle.
* @param rhs A valid handle.
* @return True if the first handle is greater than the second, false otherwise.
*/
template<typename Lhs, typename Rhs>
[[nodiscard]] bool operator>(const resource<Lhs> &lhs, const resource<Rhs> &rhs) noexcept {
return rhs < lhs;
}
/**
* @brief Compares two handles.
* @tparam Lhs Type of resource managed by the first handle.
* @tparam Rhs Type of resource managed by the second handle.
* @param lhs A valid handle.
* @param rhs A valid handle.
* @return True if the first handle is less than or equal to the second, false
* otherwise.
*/
template<typename Lhs, typename Rhs>
[[nodiscard]] bool operator<=(const resource<Lhs> &lhs, const resource<Rhs> &rhs) noexcept {
return !(lhs > rhs);
}
/**
* @brief Compares two handles.
* @tparam Lhs Type of resource managed by the first handle.
* @tparam Rhs Type of resource managed by the second handle.
* @param lhs A valid handle.
* @param rhs A valid handle.
* @return True if the first handle is greater than or equal to the second,
* false otherwise.
*/
template<typename Lhs, typename Rhs>
[[nodiscard]] bool operator>=(const resource<Lhs> &lhs, const resource<Rhs> &rhs) noexcept {
return !(lhs < rhs);
}
} // namespace entt
#endif

View File

@@ -1,41 +1,42 @@
#ifndef ENTT_SIGNAL_DELEGATE_HPP
#define ENTT_SIGNAL_DELEGATE_HPP
#include <cstddef>
#include <functional>
#include <tuple>
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "../core/type_traits.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/functional.hpp"
#include "../stl/tuple.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "fwd.hpp"
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
template<typename Ret, typename... Args>
constexpr auto function_pointer(Ret (*)(Args...)) -> Ret (*)(Args...);
auto function_pointer(Ret (*)(Args...)) -> Ret (*)(Args...);
template<typename Ret, typename Type, typename... Args, typename Other>
constexpr auto function_pointer(Ret (*)(Type, Args...), Other &&) -> Ret (*)(Args...);
auto function_pointer(Ret (*)(Type, Args...), Other &&) -> Ret (*)(Args...);
template<typename Class, typename Ret, typename... Args, typename... Other>
constexpr auto function_pointer(Ret (Class::*)(Args...), Other &&...) -> Ret (*)(Args...);
auto function_pointer(Ret (Class::*)(Args...), Other &&...) -> Ret (*)(Args...);
template<typename Class, typename Ret, typename... Args, typename... Other>
constexpr auto function_pointer(Ret (Class::*)(Args...) const, Other &&...) -> Ret (*)(Args...);
auto function_pointer(Ret (Class::*)(Args...) const, Other &&...) -> Ret (*)(Args...);
template<typename Class, typename Type, typename... Other, typename = std::enable_if_t<std::is_member_object_pointer_v<Type Class::*>>>
constexpr auto function_pointer(Type Class::*, Other &&...) -> Type (*)();
template<typename Class, typename Type, typename... Other>
requires stl::is_member_object_pointer_v<Type Class::*>
auto function_pointer(Type Class::*, Other &&...) -> Type (*)();
template<typename... Type>
using function_pointer_t = decltype(function_pointer(std::declval<Type>()...));
using function_pointer_t = decltype(function_pointer(stl::declval<Type>()...));
template<typename... Class, typename Ret, typename... Args>
[[nodiscard]] constexpr auto index_sequence_for(Ret (*)(Args...)) {
return std::index_sequence_for<Class..., Args...>{};
[[nodiscard]] ENTT_CONSTEVAL auto index_sequence_for(Ret (*)(Args...)) {
return stl::index_sequence_for<Class..., Args...>{};
}
} // namespace internal
@@ -64,35 +65,35 @@ class delegate;
*/
template<typename Ret, typename... Args>
class delegate<Ret(Args...)> {
using return_type = std::remove_const_t<Ret>;
using return_type = stl::remove_const_t<Ret>;
using delegate_type = return_type(const void *, Args...);
template<auto Candidate, std::size_t... Index>
[[nodiscard]] auto wrap(std::index_sequence<Index...>) noexcept {
template<auto Candidate, stl::size_t... Index>
[[nodiscard]] auto wrap(stl::index_sequence<Index...>) noexcept {
return [](const void *, Args... args) -> return_type {
[[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
[[maybe_unused]] constexpr auto offset = !std::is_invocable_r_v<Ret, decltype(Candidate), type_list_element_t<Index, type_list<Args...>>...> * (sizeof...(Args) - sizeof...(Index));
return static_cast<Ret>(std::invoke(Candidate, std::forward<type_list_element_t<Index + offset, type_list<Args...>>>(std::get<Index + offset>(arguments))...));
[[maybe_unused]] const auto arguments = stl::forward_as_tuple(stl::forward<Args>(args)...);
[[maybe_unused]] constexpr auto offset = !stl::is_invocable_r_v<Ret, decltype(Candidate), type_list_element_t<Index, type_list<Args...>>...> * (sizeof...(Args) - sizeof...(Index));
return static_cast<Ret>(stl::invoke(Candidate, stl::forward<type_list_element_t<Index + offset, type_list<Args...>>>(stl::get<Index + offset>(arguments))...));
};
}
template<auto Candidate, typename Type, std::size_t... Index>
[[nodiscard]] auto wrap(Type &, std::index_sequence<Index...>) noexcept {
template<auto Candidate, typename Type, stl::size_t... Index>
[[nodiscard]] auto wrap(Type &, stl::index_sequence<Index...>) noexcept {
return [](const void *payload, Args... args) -> return_type {
Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
[[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
[[maybe_unused]] constexpr auto offset = !std::is_invocable_r_v<Ret, decltype(Candidate), Type &, type_list_element_t<Index, type_list<Args...>>...> * (sizeof...(Args) - sizeof...(Index));
return static_cast<Ret>(std::invoke(Candidate, *curr, std::forward<type_list_element_t<Index + offset, type_list<Args...>>>(std::get<Index + offset>(arguments))...));
[[maybe_unused]] const auto arguments = stl::forward_as_tuple(stl::forward<Args>(args)...);
[[maybe_unused]] constexpr auto offset = !stl::is_invocable_r_v<Ret, decltype(Candidate), Type &, type_list_element_t<Index, type_list<Args...>>...> * (sizeof...(Args) - sizeof...(Index));
return static_cast<Ret>(stl::invoke(Candidate, *curr, stl::forward<type_list_element_t<Index + offset, type_list<Args...>>>(stl::get<Index + offset>(arguments))...));
};
}
template<auto Candidate, typename Type, std::size_t... Index>
[[nodiscard]] auto wrap(Type *, std::index_sequence<Index...>) noexcept {
template<auto Candidate, typename Type, stl::size_t... Index>
[[nodiscard]] auto wrap(Type *, stl::index_sequence<Index...>) noexcept {
return [](const void *payload, Args... args) -> return_type {
Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
[[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
[[maybe_unused]] constexpr auto offset = !std::is_invocable_r_v<Ret, decltype(Candidate), Type *, type_list_element_t<Index, type_list<Args...>>...> * (sizeof...(Args) - sizeof...(Index));
return static_cast<Ret>(std::invoke(Candidate, curr, std::forward<type_list_element_t<Index + offset, type_list<Args...>>>(std::get<Index + offset>(arguments))...));
[[maybe_unused]] const auto arguments = stl::forward_as_tuple(stl::forward<Args>(args)...);
[[maybe_unused]] constexpr auto offset = !stl::is_invocable_r_v<Ret, decltype(Candidate), Type *, type_list_element_t<Index, type_list<Args...>>...> * (sizeof...(Args) - sizeof...(Index));
return static_cast<Ret>(stl::invoke(Candidate, curr, stl::forward<type_list_element_t<Index + offset, type_list<Args...>>>(stl::get<Index + offset>(arguments))...));
};
}
@@ -115,7 +116,7 @@ public:
*/
template<auto Candidate, typename... Type>
delegate(connect_arg_t<Candidate>, Type &&...value_or_instance) noexcept {
connect<Candidate>(std::forward<Type>(value_or_instance)...);
connect<Candidate>(stl::forward<Type>(value_or_instance)...);
}
/**
@@ -136,11 +137,11 @@ public:
void connect() noexcept {
instance = nullptr;
if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Args...>) {
if constexpr(stl::is_invocable_r_v<Ret, decltype(Candidate), Args...>) {
fn = [](const void *, Args... args) -> return_type {
return Ret(std::invoke(Candidate, std::forward<Args>(args)...));
return Ret(stl::invoke(Candidate, stl::forward<Args>(args)...));
};
} else if constexpr(std::is_member_pointer_v<decltype(Candidate)>) {
} else if constexpr(stl::is_member_pointer_v<decltype(Candidate)>) {
fn = wrap<Candidate>(internal::index_sequence_for<type_list_element_t<0, type_list<Args...>>>(internal::function_pointer_t<decltype(Candidate)>{}));
} else {
fn = wrap<Candidate>(internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate)>{}));
@@ -166,10 +167,10 @@ public:
void connect(Type &value_or_instance) noexcept {
instance = &value_or_instance;
if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type &, Args...>) {
if constexpr(stl::is_invocable_r_v<Ret, decltype(Candidate), Type &, Args...>) {
fn = [](const void *payload, Args... args) -> return_type {
Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
return Ret(std::invoke(Candidate, *curr, std::forward<Args>(args)...));
return Ret(stl::invoke(Candidate, *curr, stl::forward<Args>(args)...));
};
} else {
fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
@@ -190,10 +191,10 @@ public:
void connect(Type *value_or_instance) noexcept {
instance = value_or_instance;
if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type *, Args...>) {
if constexpr(stl::is_invocable_r_v<Ret, decltype(Candidate), Type *, Args...>) {
fn = [](const void *payload, Args... args) -> return_type {
Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
return Ret(std::invoke(Candidate, curr, std::forward<Args>(args)...));
return Ret(stl::invoke(Candidate, curr, stl::forward<Args>(args)...));
};
} else {
fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
@@ -259,7 +260,7 @@ public:
*/
Ret operator()(Args... args) const {
ENTT_ASSERT(static_cast<bool>(*this), "Uninitialized delegate");
return fn(instance, std::forward<Args>(args)...);
return fn(instance, stl::forward<Args>(args)...);
}
/**
@@ -285,25 +286,12 @@ private:
delegate_type *fn{};
};
/**
* @brief Compares the contents of two delegates.
* @tparam Ret Return type of a function type.
* @tparam Args Types of arguments of a function type.
* @param lhs A valid delegate object.
* @param rhs A valid delegate object.
* @return True if the two contents differ, false otherwise.
*/
template<typename Ret, typename... Args>
[[nodiscard]] bool operator!=(const delegate<Ret(Args...)> &lhs, const delegate<Ret(Args...)> &rhs) noexcept {
return !(lhs == rhs);
}
/**
* @brief Deduction guide.
* @tparam Candidate Function or member to connect to the delegate.
*/
template<auto Candidate>
delegate(connect_arg_t<Candidate>) -> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate)>>>;
delegate(connect_arg_t<Candidate>) -> delegate<stl::remove_pointer_t<internal::function_pointer_t<decltype(Candidate)>>>;
/**
* @brief Deduction guide.
@@ -311,7 +299,7 @@ delegate(connect_arg_t<Candidate>) -> delegate<std::remove_pointer_t<internal::f
* @tparam Type Type of class or type of payload.
*/
template<auto Candidate, typename Type>
delegate(connect_arg_t<Candidate>, Type &&) -> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate), Type>>>;
delegate(connect_arg_t<Candidate>, Type &&) -> delegate<stl::remove_pointer_t<internal::function_pointer_t<decltype(Candidate), Type>>>;
/**
* @brief Deduction guide.

View File

@@ -1,23 +1,23 @@
#ifndef ENTT_SIGNAL_DISPATCHER_HPP
#define ENTT_SIGNAL_DISPATCHER_HPP
#include <cstddef>
#include <functional>
#include <memory>
#include <type_traits>
#include <utility>
#include <vector>
#include "../container/dense_map.hpp"
#include "../core/compressed_pair.hpp"
#include "../core/concepts.hpp"
#include "../core/fwd.hpp"
#include "../core/type_info.hpp"
#include "../core/utility.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/functional.hpp"
#include "../stl/memory.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "../stl/vector.hpp"
#include "fwd.hpp"
#include "sigh.hpp"
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
/*! @cond ENTT_INTERNAL */
namespace internal {
struct basic_dispatcher_handler {
@@ -25,16 +25,14 @@ struct basic_dispatcher_handler {
virtual void publish() = 0;
virtual void disconnect(void *) = 0;
virtual void clear() noexcept = 0;
[[nodiscard]] virtual std::size_t size() const noexcept = 0;
[[nodiscard]] virtual stl::size_t size() const noexcept = 0;
};
template<typename Type, typename Allocator>
template<cvref_unqualified Type, typename Allocator>
class dispatcher_handler final: public basic_dispatcher_handler {
static_assert(std::is_same_v<Type, std::decay_t<Type>>, "Invalid type");
using alloc_traits = std::allocator_traits<Allocator>;
using alloc_traits = stl::allocator_traits<Allocator>;
using signal_type = sigh<void(Type &), Allocator>;
using container_type = std::vector<Type, typename alloc_traits::template rebind_alloc<Type>>;
using container_type = stl::vector<Type, typename alloc_traits::template rebind_alloc<Type>>;
public:
using allocator_type = Allocator;
@@ -44,13 +42,12 @@ public:
events{allocator} {}
void publish() override {
const auto length = events.size();
container_type other{};
other.swap(events);
for(std::size_t pos{}; pos < length; ++pos) {
signal.publish(events[pos]);
for(auto &&elem: other) {
signal.publish(elem);
}
events.erase(events.cbegin(), events.cbegin() + static_cast<typename container_type::difference_type>(length));
}
void disconnect(void *instance) override {
@@ -65,20 +62,20 @@ public:
return typename signal_type::sink_type{signal};
}
void trigger(Type event) {
void trigger(Type &event) {
signal.publish(event);
}
template<typename... Args>
void enqueue(Args &&...args) {
if constexpr(std::is_aggregate_v<Type> && (sizeof...(Args) != 0u || !std::is_default_constructible_v<Type>)) {
events.push_back(Type{std::forward<Args>(args)...});
if constexpr(stl::is_aggregate_v<Type> && (sizeof...(Args) != 0u || !stl::is_default_constructible_v<Type>)) {
events.push_back(Type{stl::forward<Args>(args)...});
} else {
events.emplace_back(std::forward<Args>(args)...);
events.emplace_back(stl::forward<Args>(args)...);
}
}
[[nodiscard]] std::size_t size() const noexcept override {
[[nodiscard]] stl::size_t size() const noexcept override {
return events.size();
}
@@ -110,30 +107,27 @@ class basic_dispatcher {
using handler_type = internal::dispatcher_handler<Type, Allocator>;
using key_type = id_type;
// std::shared_ptr because of its type erased allocator which is useful here
using mapped_type = std::shared_ptr<internal::basic_dispatcher_handler>;
// stl::shared_ptr because of its type erased allocator which is useful here
using mapped_type = stl::shared_ptr<internal::basic_dispatcher_handler>;
using alloc_traits = std::allocator_traits<Allocator>;
using container_allocator = typename alloc_traits::template rebind_alloc<std::pair<const key_type, mapped_type>>;
using container_type = dense_map<key_type, mapped_type, identity, std::equal_to<>, container_allocator>;
using alloc_traits = stl::allocator_traits<Allocator>;
using container_allocator = alloc_traits::template rebind_alloc<stl::pair<const key_type, mapped_type>>;
using container_type = dense_map<key_type, mapped_type, stl::identity, stl::equal_to<>, container_allocator>;
template<typename Type>
template<cvref_unqualified Type>
[[nodiscard]] handler_type<Type> &assure(const id_type id) {
static_assert(std::is_same_v<Type, std::decay_t<Type>>, "Non-decayed types not allowed");
auto &&ptr = pools.first()[id];
if(!ptr) {
const auto &allocator = get_allocator();
ptr = std::allocate_shared<handler_type<Type>>(allocator, allocator);
ptr = stl::allocate_shared<handler_type<Type>>(allocator, allocator);
}
return static_cast<handler_type<Type> &>(*ptr);
}
template<typename Type>
template<cvref_unqualified Type>
[[nodiscard]] const handler_type<Type> *assure(const id_type id) const {
static_assert(std::is_same_v<Type, std::decay_t<Type>>, "Non-decayed types not allowed");
if(auto it = pools.first().find(id); it != pools.first().cend()) {
return static_cast<const handler_type<Type> *>(it->second.get());
}
@@ -145,7 +139,7 @@ public:
/*! @brief Allocator type. */
using allocator_type = Allocator;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
using size_type = stl::size_t;
/*! @brief Default constructor. */
basic_dispatcher()
@@ -166,7 +160,7 @@ public:
* @param other The instance to move from.
*/
basic_dispatcher(basic_dispatcher &&other) noexcept
: pools{std::move(other.pools)} {}
: pools{stl::move(other.pools)} {}
/**
* @brief Allocator-extended move constructor.
@@ -174,7 +168,7 @@ public:
* @param allocator The allocator to use.
*/
basic_dispatcher(basic_dispatcher &&other, const allocator_type &allocator)
: pools{container_type{std::move(other.pools.first()), allocator}, allocator} {
: pools{container_type{stl::move(other.pools.first()), allocator}, allocator} {
ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a dispatcher is not allowed");
}
@@ -203,7 +197,7 @@ public:
* @param other Dispatcher to exchange the content with.
*/
void swap(basic_dispatcher &other) noexcept {
using std::swap;
using stl::swap;
swap(pools, other.pools);
}
@@ -223,7 +217,7 @@ public:
*/
template<typename Type>
[[nodiscard]] size_type size(const id_type id = type_hash<Type>::value()) const noexcept {
const auto *cpool = assure<std::decay_t<Type>>(id);
const auto *cpool = assure<stl::decay_t<Type>>(id);
return cpool ? cpool->size() : 0u;
}
@@ -271,8 +265,8 @@ public:
* @param value An instance of the given type of event.
*/
template<typename Type>
void trigger(Type &&value = {}) {
trigger(type_hash<std::decay_t<Type>>::value(), std::forward<Type>(value));
void trigger(Type value) {
trigger(type_hash<stl::decay_t<Type>>::value(), value);
}
/**
@@ -282,8 +276,8 @@ public:
* @param id Name used to map the event queue within the dispatcher.
*/
template<typename Type>
void trigger(const id_type id, Type &&value = {}) {
assure<std::decay_t<Type>>(id).trigger(std::forward<Type>(value));
void trigger(const id_type id, Type value) {
assure<stl::decay_t<Type>>(id).trigger(value);
}
/**
@@ -294,7 +288,7 @@ public:
*/
template<typename Type, typename... Args>
void enqueue(Args &&...args) {
enqueue_hint<Type>(type_hash<Type>::value(), std::forward<Args>(args)...);
enqueue_hint<Type>(type_hash<Type>::value(), stl::forward<Args>(args)...);
}
/**
@@ -304,7 +298,7 @@ public:
*/
template<typename Type>
void enqueue(Type &&value) {
enqueue_hint(type_hash<std::decay_t<Type>>::value(), std::forward<Type>(value));
enqueue_hint(type_hash<stl::decay_t<Type>>::value(), stl::forward<Type>(value));
}
/**
@@ -316,7 +310,7 @@ public:
*/
template<typename Type, typename... Args>
void enqueue_hint(const id_type id, Args &&...args) {
assure<Type>(id).enqueue(std::forward<Args>(args)...);
assure<Type>(id).enqueue(stl::forward<Args>(args)...);
}
/**
@@ -327,7 +321,7 @@ public:
*/
template<typename Type>
void enqueue_hint(const id_type id, Type &&value) {
assure<std::decay_t<Type>>(id).enqueue(std::forward<Type>(value));
assure<stl::decay_t<Type>>(id).enqueue(stl::forward<Type>(value));
}
/**

View File

@@ -1,14 +1,13 @@
#ifndef ENTT_SIGNAL_EMITTER_HPP
#define ENTT_SIGNAL_EMITTER_HPP
#include <functional>
#include <type_traits>
#include <utility>
#include "../container/dense_map.hpp"
#include "../core/compressed_pair.hpp"
#include "../core/fwd.hpp"
#include "../core/type_info.hpp"
#include "../core/utility.hpp"
#include "../stl/functional.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "fwd.hpp"
namespace entt {
@@ -35,17 +34,17 @@ namespace entt {
template<typename Derived, typename Allocator>
class emitter {
using key_type = id_type;
using mapped_type = std::function<void(void *)>;
using mapped_type = stl::function<void(void *)>;
using alloc_traits = std::allocator_traits<Allocator>;
using container_allocator = typename alloc_traits::template rebind_alloc<std::pair<const key_type, mapped_type>>;
using container_type = dense_map<key_type, mapped_type, identity, std::equal_to<>, container_allocator>;
using alloc_traits = stl::allocator_traits<Allocator>;
using container_allocator = alloc_traits::template rebind_alloc<stl::pair<const key_type, mapped_type>>;
using container_type = dense_map<key_type, mapped_type, stl::identity, stl::equal_to<>, container_allocator>;
public:
/*! @brief Allocator type. */
using allocator_type = Allocator;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
using size_type = stl::size_t;
/*! @brief Default constructor. */
emitter()
@@ -66,7 +65,7 @@ public:
* @param other The instance to move from.
*/
emitter(emitter &&other) noexcept
: handlers{std::move(other.handlers)} {}
: handlers{stl::move(other.handlers)} {}
/**
* @brief Allocator-extended move constructor.
@@ -74,13 +73,13 @@ public:
* @param allocator The allocator to use.
*/
emitter(emitter &&other, const allocator_type &allocator)
: handlers{container_type{std::move(other.handlers.first()), allocator}, allocator} {
: handlers{container_type{stl::move(other.handlers.first()), allocator}, allocator} {
ENTT_ASSERT(alloc_traits::is_always_equal::value || handlers.second() == other.handlers.second(), "Copying an emitter is not allowed");
}
/*! @brief Default destructor. */
virtual ~emitter() {
static_assert(std::is_base_of_v<emitter<Derived, Allocator>, Derived>, "Invalid emitter type");
static_assert(stl::is_base_of_v<emitter<Derived, Allocator>, Derived>, "Invalid emitter type");
}
/**
@@ -105,7 +104,7 @@ public:
* @param other Emitter to exchange the content with.
*/
void swap(emitter &other) noexcept {
using std::swap;
using stl::swap;
swap(handlers, other.handlers);
}
@@ -135,8 +134,8 @@ public:
* @param func The listener to register.
*/
template<typename Type>
void on(std::function<void(Type &, Derived &)> func) {
handlers.first().insert_or_assign(type_id<Type>().hash(), [func = std::move(func), this](void *value) {
void on(stl::function<void(Type &, Derived &)> func) {
handlers.first().insert_or_assign(type_id<Type>().hash(), [func = stl::move(func), this](void *value) {
func(*static_cast<Type *>(value), static_cast<Derived &>(*this));
});
}
@@ -147,7 +146,7 @@ public:
*/
template<typename Type>
void erase() {
handlers.first().erase(type_hash<std::remove_const_t<std::remove_reference_t<Type>>>::value());
handlers.first().erase(type_hash<stl::remove_cvref_t<Type>>::value());
}
/*! @brief Disconnects all the listeners. */
@@ -162,7 +161,7 @@ public:
*/
template<typename Type>
[[nodiscard]] bool contains() const {
return handlers.first().contains(type_hash<std::remove_const_t<std::remove_reference_t<Type>>>::value());
return handlers.first().contains(type_hash<stl::remove_cvref_t<Type>>::value());
}
/**

View File

@@ -1,17 +1,17 @@
#ifndef ENTT_SIGNAL_FWD_HPP
#define ENTT_SIGNAL_FWD_HPP
#include <memory>
#include "../stl/memory.hpp"
namespace entt {
template<typename>
class delegate;
template<typename = std::allocator<void>>
template<typename = stl::allocator<void>>
class basic_dispatcher;
template<typename, typename = std::allocator<void>>
template<typename, typename = stl::allocator<void>>
class emitter;
class connection;
@@ -21,7 +21,7 @@ struct scoped_connection;
template<typename>
class sink;
template<typename Type, typename = std::allocator<void>>
template<typename Type, typename = stl::allocator<void>>
class sigh;
/*! @brief Alias declaration for the most common use case. */

View File

@@ -1,11 +1,11 @@
#ifndef ENTT_SIGNAL_SIGH_HPP
#define ENTT_SIGNAL_SIGH_HPP
#include <cstddef>
#include <memory>
#include <type_traits>
#include <utility>
#include <vector>
#include "../stl/cstddef.hpp"
#include "../stl/memory.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "../stl/vector.hpp"
#include "delegate.hpp"
#include "fwd.hpp"
@@ -54,15 +54,15 @@ template<typename Ret, typename... Args, typename Allocator>
class sigh<Ret(Args...), Allocator> {
friend class sink<sigh<Ret(Args...), Allocator>>;
using alloc_traits = std::allocator_traits<Allocator>;
using alloc_traits = stl::allocator_traits<Allocator>;
using delegate_type = delegate<Ret(Args...)>;
using container_type = std::vector<delegate_type, typename alloc_traits::template rebind_alloc<delegate_type>>;
using container_type = stl::vector<delegate_type, typename alloc_traits::template rebind_alloc<delegate_type>>;
public:
/*! @brief Allocator type. */
using allocator_type = Allocator;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
using size_type = stl::size_t;
/*! @brief Sink type. */
using sink_type = sink<sigh<Ret(Args...), Allocator>>;
@@ -97,7 +97,7 @@ public:
* @param other The instance to move from.
*/
sigh(sigh &&other) noexcept
: calls{std::move(other.calls)} {}
: calls{stl::move(other.calls)} {}
/**
* @brief Allocator-extended move constructor.
@@ -105,7 +105,7 @@ public:
* @param allocator The allocator to use.
*/
sigh(sigh &&other, const allocator_type &allocator)
: calls{std::move(other.calls), allocator} {}
: calls{stl::move(other.calls), allocator} {}
/*! @brief Default destructor. */
~sigh() = default;
@@ -135,7 +135,7 @@ public:
* @param other Signal handler to exchange the content with.
*/
void swap(sigh &other) noexcept {
using std::swap;
using stl::swap;
swap(calls, other.calls);
}
@@ -193,24 +193,22 @@ public:
template<typename Func>
void collect(Func func, Args... args) const {
for(auto pos = calls.size(); pos; --pos) {
if constexpr(std::is_void_v<Ret> || !std::is_invocable_v<Func, Ret>) {
if constexpr(stl::is_void_v<Ret> || !stl::is_invocable_v<Func, Ret>) {
calls[pos - 1u](args...);
if constexpr(std::is_invocable_r_v<bool, Func>) {
if constexpr(stl::is_invocable_r_v<bool, Func>) {
if(func()) {
break;
}
} else {
func();
}
} else {
if constexpr(std::is_invocable_r_v<bool, Func, Ret>) {
if(func(calls[pos - 1u](args...))) {
break;
}
} else {
func(calls[pos - 1u](args...));
} else if constexpr(stl::is_invocable_r_v<bool, Func, Ret>) {
if(func(calls[pos - 1u](args...))) {
break;
}
} else {
func(calls[pos - 1u](args...));
}
}
}
@@ -287,7 +285,7 @@ struct scoped_connection {
* @param other The scoped connection to move from.
*/
scoped_connection(scoped_connection &&other) noexcept
: conn{std::exchange(other.conn, {})} {}
: conn{stl::exchange(other.conn, {})} {}
/*! @brief Automatically breaks the link on destruction. */
~scoped_connection() {
@@ -306,7 +304,7 @@ struct scoped_connection {
* @return This scoped connection.
*/
scoped_connection &operator=(scoped_connection &&other) noexcept {
conn = std::exchange(other.conn, {});
conn = stl::exchange(other.conn, {});
return *this;
}
@@ -359,8 +357,8 @@ private:
template<typename Ret, typename... Args, typename Allocator>
class sink<sigh<Ret(Args...), Allocator>> {
using signal_type = sigh<Ret(Args...), Allocator>;
using delegate_type = typename signal_type::delegate_type;
using difference_type = typename signal_type::container_type::difference_type;
using delegate_type = signal_type::delegate_type;
using difference_type = signal_type::container_type::difference_type;
template<auto Candidate, typename Type>
static void release(Type value_or_instance, void *signal) {
@@ -378,7 +376,7 @@ class sink<sigh<Ret(Args...), Allocator>> {
for(auto pos = ref.calls.size(); pos; --pos) {
if(auto &elem = ref.calls[pos - 1u]; callback(elem)) {
elem = std::move(ref.calls.back());
elem = stl::move(ref.calls.back());
ref.calls.pop_back();
}
}
@@ -420,7 +418,7 @@ public:
delegate_type call{};
call.template connect<Candidate>();
signal_or_assert().calls.push_back(std::move(call));
signal_or_assert().calls.push_back(stl::move(call));
delegate<void(void *)> conn{};
conn.template connect<&release<Candidate>>();
@@ -449,7 +447,7 @@ public:
delegate_type call{};
call.template connect<Candidate>(value_or_instance);
signal_or_assert().calls.push_back(std::move(call));
signal_or_assert().calls.push_back(stl::move(call));
delegate<void(void *)> conn{};
conn.template connect<&release<Candidate, Type &>>(value_or_instance);
@@ -473,7 +471,7 @@ public:
delegate_type call{};
call.template connect<Candidate>(value_or_instance);
signal_or_assert().calls.push_back(std::move(call));
signal_or_assert().calls.push_back(stl::move(call));
delegate<void(void *)> conn{};
conn.template connect<&release<Candidate, Type *>>(value_or_instance);

View File

@@ -0,0 +1,18 @@
#ifndef ENTT_STL_ALGORITHM_HPP
#define ENTT_STL_ALGORITHM_HPP
#include <algorithm>
/*! @cond ENTT_INTERNAL */
namespace entt::stl {
using std::all_of;
using std::any_of;
using std::find_if;
using std::none_of;
using std::sort;
} // namespace entt::stl
/*! @endcond */
#endif

15
src/entt/stl/array.hpp Normal file
View File

@@ -0,0 +1,15 @@
#ifndef ENTT_STL_ARRAY_HPP
#define ENTT_STL_ARRAY_HPP
#include <array>
/*! @cond ENTT_INTERNAL */
namespace entt::stl {
using std::array;
using std::get;
} // namespace entt::stl
/*! @endcond */
#endif

14
src/entt/stl/atomic.hpp Normal file
View File

@@ -0,0 +1,14 @@
#ifndef ENTT_STL_ATOMIC_HPP
#define ENTT_STL_ATOMIC_HPP
#include <atomic>
/*! @cond ENTT_INTERNAL */
namespace entt::stl {
using std::atomic;
} // namespace entt::stl
/*! @endcond */
#endif

16
src/entt/stl/bit.hpp Normal file
View File

@@ -0,0 +1,16 @@
#ifndef ENTT_STL_BIT_HPP
#define ENTT_STL_BIT_HPP
#include <bit>
/*! @cond ENTT_INTERNAL */
namespace entt::stl {
using std::bit_ceil;
using std::has_single_bit;
using std::popcount;
} // namespace entt::stl
/*! @endcond */
#endif

14
src/entt/stl/cmath.hpp Normal file
View File

@@ -0,0 +1,14 @@
#ifndef ENTT_STL_CMATH_HPP
#define ENTT_STL_CMATH_HPP
#include <cmath>
/*! @cond ENTT_INTERNAL */
namespace entt::stl {
using std::ceil;
} // namespace entt::stl
/*! @endcond */
#endif

20
src/entt/stl/concepts.hpp Normal file
View File

@@ -0,0 +1,20 @@
#ifndef ENTT_STL_CONCEPTS_HPP
#define ENTT_STL_CONCEPTS_HPP
#include <concepts>
/*! @cond ENTT_INTERNAL */
namespace entt::stl {
using std::constructible_from;
using std::default_initializable;
using std::derived_from;
using std::integral;
using std::invocable;
using std::same_as;
using std::unsigned_integral;
} // namespace entt::stl
/*! @endcond */
#endif

17
src/entt/stl/cstddef.hpp Normal file
View File

@@ -0,0 +1,17 @@
#ifndef ENTT_STL_CSTDDEF_HPP
#define ENTT_STL_CSTDDEF_HPP
#include <cstddef>
/*! @cond ENTT_INTERNAL */
namespace entt::stl {
using std::byte;
using std::nullptr_t;
using std::ptrdiff_t;
using std::size_t;
} // namespace entt::stl
/*! @endcond */
#endif

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