update subtree entt Merge commit '90ce4bda4e1dc23508bbd6b6923156cd5a370c18'

This commit is contained in:
2023-10-02 15:30:10 +02:00
153 changed files with 24263 additions and 14220 deletions

View File

@ -51,7 +51,20 @@ function(SETUP_TARGET TARGET_NAME)
target_compile_options(
${TARGET_NAME}
PRIVATE
/EHsc /W1 /wd4996 /w14800
# vs2017 emits too many false positives for my tastes
$<IF:$<EQUAL:${MSVC_TOOLSET_VERSION},141>, /W1, /W4>
# clang-cl goes a little wrong with some warnings instead
$<$<STREQUAL:"${CMAKE_CXX_COMPILER_ID}","Clang">:
-Wno-deprecated-declarations
-Wno-ignored-qualifiers
-Wno-unknown-warning-option
-Wno-exceptions
-Wno-unused-local-typedef
-Wno-unused-private-field
>
# documentation diagnostic turned on for clang-cl only
$<$<STREQUAL:"${CMAKE_CXX_COMPILER_ID}","Clang">:-Wdocumentation>
/EHsc /wd4324 /wd4996
$<$<CONFIG:Debug>:/Od>
$<$<CONFIG:Release>:/O2>
)
@ -94,21 +107,23 @@ function(SETUP_BASIC_TEST TEST_NAME TEST_SOURCES)
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME})
endfunction()
function(SETUP_LIB_TEST TEST_NAME)
add_library(_${TEST_NAME} SHARED $<TARGET_OBJECTS:odr> lib/${TEST_NAME}/lib.cpp)
SETUP_TARGET(_${TEST_NAME} ENTT_API_EXPORT)
SETUP_BASIC_TEST(lib_${TEST_NAME} lib/${TEST_NAME}/main.cpp ENTT_API_IMPORT)
target_link_libraries(lib_${TEST_NAME} PRIVATE _${TEST_NAME})
function(SETUP_LIB_SHARED_TEST TEST_NAME SUB_PATH)
set(TARGET_NAME ${TEST_NAME}_${SUB_PATH})
add_library(_${TARGET_NAME} SHARED $<TARGET_OBJECTS:odr> lib/${TEST_NAME}/${SUB_PATH}/lib.cpp)
SETUP_TARGET(_${TARGET_NAME} ENTT_API_EXPORT)
SETUP_BASIC_TEST(lib_${TARGET_NAME} lib/${TEST_NAME}/${SUB_PATH}/main.cpp ENTT_API_IMPORT)
target_link_libraries(lib_${TARGET_NAME} PRIVATE _${TARGET_NAME})
endfunction()
function(SETUP_PLUGIN_TEST TEST_NAME)
add_library(_${TEST_NAME} MODULE $<TARGET_OBJECTS:odr> lib/${TEST_NAME}/plugin.cpp)
SETUP_TARGET(_${TEST_NAME} ${ARGVN})
SETUP_BASIC_TEST(lib_${TEST_NAME} lib/${TEST_NAME}/main.cpp PLUGIN="$<TARGET_FILE:_${TEST_NAME}>" ${ARGVN})
target_include_directories(_${TEST_NAME} PRIVATE ${cr_INCLUDE_DIR})
target_include_directories(lib_${TEST_NAME} PRIVATE ${cr_INCLUDE_DIR})
target_link_libraries(lib_${TEST_NAME} PRIVATE ${CMAKE_DL_LIBS})
add_dependencies(lib_${TEST_NAME} _${TEST_NAME})
function(SETUP_LIB_PLUGIN_TEST TEST_NAME SUB_PATH)
set(TARGET_NAME ${TEST_NAME}_${SUB_PATH})
add_library(_${TARGET_NAME} MODULE $<TARGET_OBJECTS:odr> lib/${TEST_NAME}/${SUB_PATH}/plugin.cpp)
SETUP_TARGET(_${TARGET_NAME} ${ARGVN})
SETUP_BASIC_TEST(lib_${TARGET_NAME} lib/${TEST_NAME}/${SUB_PATH}/main.cpp PLUGIN="$<TARGET_FILE:_${TARGET_NAME}>" ${ARGVN})
target_include_directories(_${TARGET_NAME} PRIVATE ${cr_INCLUDE_DIR})
target_include_directories(lib_${TARGET_NAME} PRIVATE ${cr_INCLUDE_DIR})
target_link_libraries(lib_${TARGET_NAME} PRIVATE ${CMAKE_DL_LIBS})
add_dependencies(lib_${TARGET_NAME} _${TARGET_NAME})
endfunction()
# Test benchmark
@ -142,19 +157,21 @@ if(ENTT_BUILD_LIB)
set(cr_INCLUDE_DIR ${cr_SOURCE_DIR})
endif()
SETUP_LIB_TEST(dispatcher)
SETUP_LIB_TEST(emitter)
SETUP_LIB_TEST(locator)
SETUP_LIB_TEST(meta)
SETUP_LIB_TEST(registry)
SETUP_LIB_SHARED_TEST(dispatcher shared)
SETUP_LIB_PLUGIN_TEST(dispatcher plugin)
SETUP_PLUGIN_TEST(dispatcher_plugin)
SETUP_PLUGIN_TEST(emitter_plugin)
SETUP_PLUGIN_TEST(locator_plugin)
SETUP_PLUGIN_TEST(meta_plugin)
SETUP_PLUGIN_TEST(registry_plugin)
SETUP_LIB_SHARED_TEST(emitter shared)
SETUP_LIB_PLUGIN_TEST(emitter plugin)
SETUP_PLUGIN_TEST(meta_plugin_std ENTT_STANDARD_CPP)
SETUP_LIB_SHARED_TEST(locator shared)
SETUP_LIB_PLUGIN_TEST(locator plugin)
SETUP_LIB_SHARED_TEST(meta shared)
SETUP_LIB_PLUGIN_TEST(meta plugin)
SETUP_LIB_PLUGIN_TEST(meta plugin_std ENTT_STANDARD_CPP)
SETUP_LIB_SHARED_TEST(registry shared)
SETUP_LIB_PLUGIN_TEST(registry plugin)
endif()
# Test snapshot
@ -215,10 +232,11 @@ SETUP_BASIC_TEST(observer entt/entity/observer.cpp)
SETUP_BASIC_TEST(organizer entt/entity/organizer.cpp)
SETUP_BASIC_TEST(registry entt/entity/registry.cpp)
SETUP_BASIC_TEST(runtime_view entt/entity/runtime_view.cpp)
SETUP_BASIC_TEST(sigh_mixin entt/entity/sigh_mixin.cpp)
SETUP_BASIC_TEST(snapshot entt/entity/snapshot.cpp)
SETUP_BASIC_TEST(sparse_set entt/entity/sparse_set.cpp)
SETUP_BASIC_TEST(storage entt/entity/storage.cpp)
SETUP_BASIC_TEST(storage_mixin entt/entity/storage_mixin.cpp)
SETUP_BASIC_TEST(storage_entity entt/entity/storage_entity.cpp)
SETUP_BASIC_TEST(view entt/entity/view.cpp)
# Test graph

View File

@ -19,7 +19,9 @@ struct stable_position: position {
};
template<auto>
struct comp { int x; };
struct comp {
int x;
};
struct timer final {
timer()
@ -34,16 +36,24 @@ private:
std::chrono::time_point<std::chrono::system_clock> start;
};
template<typename Func, typename... Args>
void generic_with(Func func) {
timer timer;
func();
timer.elapsed();
}
template<typename Iterable, typename Func>
void generic(Iterable &&iterable, Func func) {
void iterate_with(Iterable &&iterable, Func func) {
timer timer;
std::forward<Iterable>(iterable).each(func);
timer.elapsed();
}
template<typename Func>
void pathological(Func func) {
void pathological_with(Func func) {
entt::registry registry;
auto view = func(registry);
for(std::uint64_t i = 0; i < 500000L; i++) {
const auto entity = registry.create();
@ -54,10 +64,21 @@ void pathological(Func func) {
for(auto i = 0; i < 10; ++i) {
registry.each([i = 0, &registry](const auto entity) mutable {
if(!(++i % 7)) { registry.remove<position>(entity); }
if(!(++i % 11)) { registry.remove<velocity>(entity); }
if(!(++i % 13)) { registry.remove<comp<0>>(entity); }
if(!(++i % 17)) { registry.destroy(entity); }
if(!(++i % 7)) {
registry.remove<position>(entity);
}
if(!(++i % 11)) {
registry.remove<velocity>(entity);
}
if(!(++i % 13)) {
registry.remove<comp<0>>(entity);
}
if(!(++i % 17)) {
registry.destroy(entity);
}
});
for(std::uint64_t j = 0; j < 50000L; j++) {
@ -69,7 +90,7 @@ void pathological(Func func) {
}
timer timer;
func(registry).each([](auto &...comp) { ((comp.x = {}), ...); });
view.each([](auto &...comp) { ((comp.x = {}), ...); });
timer.elapsed();
}
@ -78,13 +99,11 @@ TEST(Benchmark, Create) {
std::cout << "Creating 1000000 entities" << std::endl;
timer timer;
for(std::uint64_t i = 0; i < 1000000L; i++) {
static_cast<void>(registry.create());
}
timer.elapsed();
generic_with([&]() {
for(std::uint64_t i = 0; i < 1000000L; i++) {
static_cast<void>(registry.create());
}
});
}
TEST(Benchmark, CreateMany) {
@ -93,9 +112,9 @@ TEST(Benchmark, CreateMany) {
std::cout << "Creating 1000000 entities at once" << std::endl;
timer timer;
registry.create(entities.begin(), entities.end());
timer.elapsed();
generic_with([&]() {
registry.create(entities.begin(), entities.end());
});
}
TEST(Benchmark, CreateManyAndEmplaceComponents) {
@ -104,15 +123,14 @@ TEST(Benchmark, CreateManyAndEmplaceComponents) {
std::cout << "Creating 1000000 entities at once and emplace components" << std::endl;
timer timer;
registry.create(entities.begin(), entities.end());
generic_with([&]() {
registry.create(entities.begin(), entities.end());
for(const auto entity: entities) {
registry.emplace<position>(entity);
registry.emplace<velocity>(entity);
}
timer.elapsed();
for(const auto entity: entities) {
registry.emplace<position>(entity);
registry.emplace<velocity>(entity);
}
});
}
TEST(Benchmark, CreateManyWithComponents) {
@ -121,79 +139,107 @@ TEST(Benchmark, CreateManyWithComponents) {
std::cout << "Creating 1000000 entities at once with components" << std::endl;
timer timer;
registry.create(entities.begin(), entities.end());
registry.insert<position>(entities.begin(), entities.end());
registry.insert<velocity>(entities.begin(), entities.end());
timer.elapsed();
generic_with([&]() {
registry.create(entities.begin(), entities.end());
registry.insert<position>(entities.begin(), entities.end());
registry.insert<velocity>(entities.begin(), entities.end());
});
}
TEST(Benchmark, Erase) {
entt::registry registry;
std::vector<entt::entity> entities(1000000);
auto view = registry.view<int>();
auto view = registry.view<position>();
std::cout << "Erasing 1000000 components from their entities" << std::endl;
registry.create(entities.begin(), entities.end());
registry.insert<int>(entities.begin(), entities.end());
registry.insert<position>(entities.begin(), entities.end());
timer timer;
for(auto entity: view) {
registry.erase<int>(entity);
}
timer.elapsed();
generic_with([&]() {
for(auto entity: view) {
registry.erase<position>(entity);
}
});
}
TEST(Benchmark, EraseMany) {
entt::registry registry;
std::vector<entt::entity> entities(1000000);
auto view = registry.view<int>();
auto view = registry.view<position>();
std::cout << "Erasing 1000000 components from their entities at once" << std::endl;
registry.create(entities.begin(), entities.end());
registry.insert<int>(entities.begin(), entities.end());
registry.insert<position>(entities.begin(), entities.end());
timer timer;
registry.erase<int>(view.begin(), view.end());
timer.elapsed();
generic_with([&]() {
registry.erase<position>(view.begin(), view.end());
});
}
TEST(Benchmark, EraseManyMulti) {
entt::registry registry;
std::vector<entt::entity> entities(1000000);
auto view = registry.view<position>();
std::cout << "Erasing 1000000 components per type from their entities at once" << std::endl;
registry.create(entities.begin(), entities.end());
registry.insert<position>(entities.begin(), entities.end());
registry.insert<velocity>(entities.begin(), entities.end());
generic_with([&]() {
registry.erase<position, velocity>(view.begin(), view.end());
});
}
TEST(Benchmark, Remove) {
entt::registry registry;
std::vector<entt::entity> entities(1000000);
auto view = registry.view<int>();
auto view = registry.view<position>();
std::cout << "Removing 1000000 components from their entities" << std::endl;
registry.create(entities.begin(), entities.end());
registry.insert<int>(entities.begin(), entities.end());
registry.insert<position>(entities.begin(), entities.end());
timer timer;
for(auto entity: view) {
registry.remove<int>(entity);
}
timer.elapsed();
generic_with([&]() {
for(auto entity: view) {
registry.remove<position>(entity);
}
});
}
TEST(Benchmark, RemoveMany) {
entt::registry registry;
std::vector<entt::entity> entities(1000000);
auto view = registry.view<int>();
auto view = registry.view<position>();
std::cout << "Removing 1000000 components from their entities at once" << std::endl;
registry.create(entities.begin(), entities.end());
registry.insert<int>(entities.begin(), entities.end());
registry.insert<position>(entities.begin(), entities.end());
timer timer;
registry.remove<int>(view.begin(), view.end());
timer.elapsed();
generic_with([&]() {
registry.remove<position>(view.begin(), view.end());
});
}
TEST(Benchmark, RemoveManyMulti) {
entt::registry registry;
std::vector<entt::entity> entities(1000000);
auto view = registry.view<position>();
std::cout << "Removing 1000000 components per type from their entities at once" << std::endl;
registry.create(entities.begin(), entities.end());
registry.insert<position>(entities.begin(), entities.end());
registry.insert<velocity>(entities.begin(), entities.end());
generic_with([&]() {
registry.remove<position, velocity>(view.begin(), view.end());
});
}
TEST(Benchmark, Clear) {
@ -203,11 +249,40 @@ TEST(Benchmark, Clear) {
std::cout << "Clearing 1000000 components from their entities" << std::endl;
registry.create(entities.begin(), entities.end());
registry.insert<int>(entities.begin(), entities.end());
registry.insert<position>(entities.begin(), entities.end());
timer timer;
registry.clear<int>();
timer.elapsed();
generic_with([&]() {
registry.clear<position>();
});
}
TEST(Benchmark, ClearMulti) {
entt::registry registry;
std::vector<entt::entity> entities(1000000);
std::cout << "Clearing 1000000 components per type from their entities" << std::endl;
registry.create(entities.begin(), entities.end());
registry.insert<position>(entities.begin(), entities.end());
registry.insert<velocity>(entities.begin(), entities.end());
generic_with([&]() {
registry.clear<position, velocity>();
});
}
TEST(Benchmark, ClearStable) {
entt::registry registry;
std::vector<entt::entity> entities(1000000);
std::cout << "Clearing 1000000 stable components from their entities" << std::endl;
registry.create(entities.begin(), entities.end());
registry.insert<stable_position>(entities.begin(), entities.end());
generic_with([&]() {
registry.clear<stable_position>();
});
}
TEST(Benchmark, Recycle) {
@ -217,18 +292,13 @@ TEST(Benchmark, Recycle) {
std::cout << "Recycling 1000000 entities" << std::endl;
registry.create(entities.begin(), entities.end());
registry.destroy(entities.begin(), entities.end());
registry.each([&registry](auto entity) {
registry.destroy(entity);
generic_with([&]() {
for(auto next = entities.size(); next; --next) {
entities[next] = registry.create();
}
});
timer timer;
for(auto next = entities.size(); next; --next) {
static_cast<void>(registry.create());
}
timer.elapsed();
}
TEST(Benchmark, RecycleMany) {
@ -238,62 +308,121 @@ TEST(Benchmark, RecycleMany) {
std::cout << "Recycling 1000000 entities" << std::endl;
registry.create(entities.begin(), entities.end());
registry.destroy(entities.begin(), entities.end());
registry.each([&registry](auto entity) {
registry.destroy(entity);
generic_with([&]() {
registry.create(entities.begin(), entities.end());
});
timer timer;
registry.create(entities.begin(), entities.end());
timer.elapsed();
}
TEST(Benchmark, Destroy) {
entt::registry registry;
std::vector<entt::entity> entities(1000000);
auto view = registry.view<int>();
auto view = registry.view<position>();
std::cout << "Destroying 1000000 entities" << std::endl;
registry.create(entities.begin(), entities.end());
registry.insert<int>(entities.begin(), entities.end());
registry.insert<position>(entities.begin(), entities.end());
timer timer;
for(auto entity: view) {
registry.destroy(entity);
}
timer.elapsed();
generic_with([&]() {
for(auto entity: view) {
registry.destroy(entity);
}
});
}
TEST(Benchmark, DestroyMany) {
entt::registry registry;
std::vector<entt::entity> entities(1000000);
auto view = registry.view<int>();
auto view = registry.view<position>();
std::cout << "Destroying 1000000 entities at once" << std::endl;
registry.create(entities.begin(), entities.end());
registry.insert<int>(entities.begin(), entities.end());
registry.insert<position>(entities.begin(), entities.end());
timer timer;
registry.destroy(view.begin(), view.end());
timer.elapsed();
generic_with([&]() {
registry.destroy(view.begin(), view.end());
});
}
TEST(Benchmark, DestroyManyFastPath) {
TEST(Benchmark, DestroyManyMulti) {
entt::registry registry;
std::vector<entt::entity> entities(1000000);
auto view = registry.view<position>();
std::cout << "Destroying 1000000 entities at once, multiple components" << std::endl;
registry.create(entities.begin(), entities.end());
registry.insert<position>(entities.begin(), entities.end());
registry.insert<velocity>(entities.begin(), entities.end());
generic_with([&]() {
registry.destroy(view.begin(), view.end());
});
}
TEST(Benchmark, GetFromRegistry) {
entt::registry registry;
std::vector<entt::entity> entities(1000000);
std::cout << "Destroying 1000000 entities at once, fast path" << std::endl;
registry.create(entities.begin(), entities.end());
registry.insert<position>(entities.begin(), entities.end());
generic_with([&]() {
for(auto entity: entities) {
registry.get<position>(entity).x = 0u;
}
});
}
TEST(Benchmark, GetFromRegistryMulti) {
entt::registry registry;
std::vector<entt::entity> entities(1000000);
registry.create(entities.begin(), entities.end());
registry.insert<int>(entities.begin(), entities.end());
registry.insert<position>(entities.begin(), entities.end());
registry.insert<velocity>(entities.begin(), entities.end());
timer timer;
registry.destroy(entities.begin(), entities.end());
timer.elapsed();
generic_with([&]() {
for(auto entity: entities) {
registry.get<position>(entity).x = 0u;
registry.get<velocity>(entity).y = 0u;
}
});
}
TEST(Benchmark, GetFromView) {
entt::registry registry;
std::vector<entt::entity> entities(1000000);
auto view = registry.view<position>();
registry.create(entities.begin(), entities.end());
registry.insert<position>(entities.begin(), entities.end());
generic_with([&]() {
for(auto entity: entities) {
view.get<position>(entity).x = 0u;
}
});
}
TEST(Benchmark, GetFromViewMulti) {
entt::registry registry;
std::vector<entt::entity> entities(1000000);
auto view = registry.view<position, velocity>();
registry.create(entities.begin(), entities.end());
registry.insert<position>(entities.begin(), entities.end());
registry.insert<velocity>(entities.begin(), entities.end());
generic_with([&]() {
for(auto entity: entities) {
view.get<position>(entity).x = 0u;
view.get<velocity>(entity).y = 0u;
}
});
}
TEST(Benchmark, IterateSingleComponent1M) {
@ -306,22 +435,22 @@ TEST(Benchmark, IterateSingleComponent1M) {
registry.emplace<position>(entity);
}
generic(registry.view<position>(), [](auto &...comp) {
iterate_with(registry.view<position>(), [](auto &...comp) {
((comp.x = {}), ...);
});
}
TEST(Benchmark, IterateSingleComponentTombstonePolicy1M) {
TEST(Benchmark, IterateSingleStableComponent1M) {
entt::registry registry;
std::cout << "Iterating over 1000000 entities, one component, tombstone policy" << std::endl;
std::cout << "Iterating over 1000000 entities, one stable component" << std::endl;
for(std::uint64_t i = 0; i < 1000000L; i++) {
const auto entity = registry.create();
registry.emplace<stable_position>(entity);
}
generic(registry.view<stable_position>(), [](auto &...comp) {
iterate_with(registry.view<stable_position>(), [](auto &...comp) {
((comp.x = {}), ...);
});
}
@ -339,7 +468,7 @@ TEST(Benchmark, IterateSingleComponentRuntime1M) {
entt::runtime_view view{};
view.iterate(registry.storage<position>());
generic(view, [&registry](auto entity) {
iterate_with(view, [&](auto entity) {
registry.get<position>(entity).x = {};
});
}
@ -355,15 +484,15 @@ TEST(Benchmark, IterateTwoComponents1M) {
registry.emplace<velocity>(entity);
}
generic(registry.view<position, velocity>(), [](auto &...comp) {
iterate_with(registry.view<position, velocity>(), [](auto &...comp) {
((comp.x = {}), ...);
});
}
TEST(Benchmark, IterateTombstonePolicyTwoComponentsTombstonePolicy1M) {
TEST(Benchmark, IterateTwoStableComponents1M) {
entt::registry registry;
std::cout << "Iterating over 1000000 entities, two components, tombstone policy" << std::endl;
std::cout << "Iterating over 1000000 entities, two stable components" << std::endl;
for(std::uint64_t i = 0; i < 1000000L; i++) {
const auto entity = registry.create();
@ -371,7 +500,7 @@ TEST(Benchmark, IterateTombstonePolicyTwoComponentsTombstonePolicy1M) {
registry.emplace<velocity>(entity);
}
generic(registry.view<stable_position, velocity>(), [](auto &...comp) {
iterate_with(registry.view<stable_position, velocity>(), [](auto &...comp) {
((comp.x = {}), ...);
});
}
@ -390,7 +519,7 @@ TEST(Benchmark, IterateTwoComponents1MHalf) {
}
}
generic(registry.view<position, velocity>(), [](auto &...comp) {
iterate_with(registry.view<position, velocity>(), [](auto &...comp) {
((comp.x = {}), ...);
});
}
@ -409,7 +538,7 @@ TEST(Benchmark, IterateTwoComponents1MOne) {
}
}
generic(registry.view<position, velocity>(), [](auto &...comp) {
iterate_with(registry.view<position, velocity>(), [](auto &...comp) {
((comp.x = {}), ...);
});
}
@ -425,7 +554,7 @@ TEST(Benchmark, IterateTwoComponentsNonOwningGroup1M) {
registry.emplace<velocity>(entity);
}
generic(registry.group<>(entt::get<position, velocity>), [](auto &...comp) {
iterate_with(registry.group<>(entt::get<position, velocity>), [](auto &...comp) {
((comp.x = {}), ...);
});
}
@ -441,7 +570,7 @@ TEST(Benchmark, IterateTwoComponentsFullOwningGroup1M) {
registry.emplace<velocity>(entity);
}
generic(registry.group<position, velocity>(), [](auto &...comp) {
iterate_with(registry.group<position, velocity>(), [](auto &...comp) {
((comp.x = {}), ...);
});
}
@ -457,7 +586,7 @@ TEST(Benchmark, IterateTwoComponentsPartialOwningGroup1M) {
registry.emplace<velocity>(entity);
}
generic(registry.group<position>(entt::get<velocity>), [](auto &...comp) {
iterate_with(registry.group<position>(entt::get<velocity>), [](auto &...comp) {
((comp.x = {}), ...);
});
}
@ -477,7 +606,7 @@ TEST(Benchmark, IterateTwoComponentsRuntime1M) {
view.iterate(registry.storage<position>())
.iterate(registry.storage<velocity>());
generic(view, [&registry](auto entity) {
iterate_with(view, [&](auto entity) {
registry.get<position>(entity).x = {};
registry.get<velocity>(entity).x = {};
});
@ -501,7 +630,7 @@ TEST(Benchmark, IterateTwoComponentsRuntime1MHalf) {
view.iterate(registry.storage<position>())
.iterate(registry.storage<velocity>());
generic(view, [&registry](auto entity) {
iterate_with(view, [&](auto entity) {
registry.get<position>(entity).x = {};
registry.get<velocity>(entity).x = {};
});
@ -525,7 +654,7 @@ TEST(Benchmark, IterateTwoComponentsRuntime1MOne) {
view.iterate(registry.storage<position>())
.iterate(registry.storage<velocity>());
generic(view, [&registry](auto entity) {
iterate_with(view, [&](auto entity) {
registry.get<position>(entity).x = {};
registry.get<velocity>(entity).x = {};
});
@ -543,15 +672,15 @@ TEST(Benchmark, IterateThreeComponents1M) {
registry.emplace<comp<0>>(entity);
}
generic(registry.view<position, velocity, comp<0>>(), [](auto &...comp) {
iterate_with(registry.view<position, velocity, comp<0>>(), [](auto &...comp) {
((comp.x = {}), ...);
});
}
TEST(Benchmark, IterateThreeComponentsTombstonePolicy1M) {
TEST(Benchmark, IterateThreeStableComponents1M) {
entt::registry registry;
std::cout << "Iterating over 1000000 entities, three components, tombstone policy" << std::endl;
std::cout << "Iterating over 1000000 entities, three stable components" << std::endl;
for(std::uint64_t i = 0; i < 1000000L; i++) {
const auto entity = registry.create();
@ -560,7 +689,7 @@ TEST(Benchmark, IterateThreeComponentsTombstonePolicy1M) {
registry.emplace<comp<0>>(entity);
}
generic(registry.view<stable_position, velocity, comp<0>>(), [](auto &...comp) {
iterate_with(registry.view<stable_position, velocity, comp<0>>(), [](auto &...comp) {
((comp.x = {}), ...);
});
}
@ -580,7 +709,7 @@ TEST(Benchmark, IterateThreeComponents1MHalf) {
}
}
generic(registry.view<position, velocity, comp<0>>(), [](auto &...comp) {
iterate_with(registry.view<position, velocity, comp<0>>(), [](auto &...comp) {
((comp.x = {}), ...);
});
}
@ -600,7 +729,7 @@ TEST(Benchmark, IterateThreeComponents1MOne) {
}
}
generic(registry.view<position, velocity, comp<0>>(), [](auto &...comp) {
iterate_with(registry.view<position, velocity, comp<0>>(), [](auto &...comp) {
((comp.x = {}), ...);
});
}
@ -617,7 +746,7 @@ TEST(Benchmark, IterateThreeComponentsNonOwningGroup1M) {
registry.emplace<comp<0>>(entity);
}
generic(registry.group<>(entt::get<position, velocity, comp<0>>), [](auto &...comp) {
iterate_with(registry.group<>(entt::get<position, velocity, comp<0>>), [](auto &...comp) {
((comp.x = {}), ...);
});
}
@ -634,7 +763,7 @@ TEST(Benchmark, IterateThreeComponentsFullOwningGroup1M) {
registry.emplace<comp<0>>(entity);
}
generic(registry.group<position, velocity, comp<0>>(), [](auto &...comp) {
iterate_with(registry.group<position, velocity, comp<0>>(), [](auto &...comp) {
((comp.x = {}), ...);
});
}
@ -651,7 +780,7 @@ TEST(Benchmark, IterateThreeComponentsPartialOwningGroup1M) {
registry.emplace<comp<0>>(entity);
}
generic(registry.group<position, velocity>(entt::get<comp<0>>), [](auto &...comp) {
iterate_with(registry.group<position, velocity>(entt::get<comp<0>>), [](auto &...comp) {
((comp.x = {}), ...);
});
}
@ -673,7 +802,7 @@ TEST(Benchmark, IterateThreeComponentsRuntime1M) {
.iterate(registry.storage<velocity>())
.iterate(registry.storage<comp<0>>());
generic(view, [&registry](auto entity) {
iterate_with(view, [&](auto entity) {
registry.get<position>(entity).x = {};
registry.get<velocity>(entity).x = {};
registry.get<comp<0>>(entity).x = {};
@ -700,7 +829,7 @@ TEST(Benchmark, IterateThreeComponentsRuntime1MHalf) {
.iterate(registry.storage<velocity>())
.iterate(registry.storage<comp<0>>());
generic(view, [&registry](auto entity) {
iterate_with(view, [&](auto entity) {
registry.get<position>(entity).x = {};
registry.get<velocity>(entity).x = {};
registry.get<comp<0>>(entity).x = {};
@ -727,7 +856,7 @@ TEST(Benchmark, IterateThreeComponentsRuntime1MOne) {
.iterate(registry.storage<velocity>())
.iterate(registry.storage<comp<0>>());
generic(view, [&registry](auto entity) {
iterate_with(view, [&](auto entity) {
registry.get<position>(entity).x = {};
registry.get<velocity>(entity).x = {};
registry.get<comp<0>>(entity).x = {};
@ -748,15 +877,15 @@ TEST(Benchmark, IterateFiveComponents1M) {
registry.emplace<comp<2>>(entity);
}
generic(registry.view<position, velocity, comp<0>, comp<1>, comp<2>>(), [](auto &...comp) {
iterate_with(registry.view<position, velocity, comp<0>, comp<1>, comp<2>>(), [](auto &...comp) {
((comp.x = {}), ...);
});
}
TEST(Benchmark, IterateFiveComponentsTombstonePolicy1M) {
TEST(Benchmark, IterateFiveStableComponents1M) {
entt::registry registry;
std::cout << "Iterating over 1000000 entities, five components, tombstone policy" << std::endl;
std::cout << "Iterating over 1000000 entities, five stable components" << std::endl;
for(std::uint64_t i = 0; i < 1000000L; i++) {
const auto entity = registry.create();
@ -767,7 +896,7 @@ TEST(Benchmark, IterateFiveComponentsTombstonePolicy1M) {
registry.emplace<comp<2>>(entity);
}
generic(registry.view<stable_position, velocity, comp<0>, comp<1>, comp<2>>(), [](auto &...comp) {
iterate_with(registry.view<stable_position, velocity, comp<0>, comp<1>, comp<2>>(), [](auto &...comp) {
((comp.x = {}), ...);
});
}
@ -789,7 +918,7 @@ TEST(Benchmark, IterateFiveComponents1MHalf) {
}
}
generic(registry.view<position, velocity, comp<0>, comp<1>, comp<2>>(), [](auto &...comp) {
iterate_with(registry.view<position, velocity, comp<0>, comp<1>, comp<2>>(), [](auto &...comp) {
((comp.x = {}), ...);
});
}
@ -811,7 +940,7 @@ TEST(Benchmark, IterateFiveComponents1MOne) {
}
}
generic(registry.view<position, velocity, comp<0>, comp<1>, comp<2>>(), [](auto &...comp) {
iterate_with(registry.view<position, velocity, comp<0>, comp<1>, comp<2>>(), [](auto &...comp) {
((comp.x = {}), ...);
});
}
@ -830,7 +959,7 @@ TEST(Benchmark, IterateFiveComponentsNonOwningGroup1M) {
registry.emplace<comp<2>>(entity);
}
generic(registry.group<>(entt::get<position, velocity, comp<0>, comp<1>, comp<2>>), [](auto &...comp) {
iterate_with(registry.group<>(entt::get<position, velocity, comp<0>, comp<1>, comp<2>>), [](auto &...comp) {
((comp.x = {}), ...);
});
}
@ -849,7 +978,7 @@ TEST(Benchmark, IterateFiveComponentsFullOwningGroup1M) {
registry.emplace<comp<2>>(entity);
}
generic(registry.group<position, velocity, comp<0>, comp<1>, comp<2>>(), [](auto &...comp) {
iterate_with(registry.group<position, velocity, comp<0>, comp<1>, comp<2>>(), [](auto &...comp) {
((comp.x = {}), ...);
});
}
@ -868,7 +997,7 @@ TEST(Benchmark, IterateFiveComponentsPartialFourOfFiveOwningGroup1M) {
registry.emplace<comp<2>>(entity);
}
generic(registry.group<position, velocity, comp<0>, comp<1>>(entt::get<comp<2>>), [](auto &...comp) {
iterate_with(registry.group<position, velocity, comp<0>, comp<1>>(entt::get<comp<2>>), [](auto &...comp) {
((comp.x = {}), ...);
});
}
@ -887,7 +1016,7 @@ TEST(Benchmark, IterateFiveComponentsPartialThreeOfFiveOwningGroup1M) {
registry.emplace<comp<2>>(entity);
}
generic(registry.group<position, velocity, comp<0>>(entt::get<comp<1>, comp<2>>), [](auto &...comp) {
iterate_with(registry.group<position, velocity, comp<0>>(entt::get<comp<1>, comp<2>>), [](auto &...comp) {
((comp.x = {}), ...);
});
}
@ -913,7 +1042,7 @@ TEST(Benchmark, IterateFiveComponentsRuntime1M) {
.iterate(registry.storage<comp<1>>())
.iterate(registry.storage<comp<2>>());
generic(view, [&registry](auto entity) {
iterate_with(view, [&](auto entity) {
registry.get<position>(entity).x = {};
registry.get<velocity>(entity).x = {};
registry.get<comp<0>>(entity).x = {};
@ -946,7 +1075,7 @@ TEST(Benchmark, IterateFiveComponentsRuntime1MHalf) {
.iterate(registry.storage<comp<1>>())
.iterate(registry.storage<comp<2>>());
generic(view, [&registry](auto entity) {
iterate_with(view, [&](auto entity) {
registry.get<position>(entity).x = {};
registry.get<velocity>(entity).x = {};
registry.get<comp<0>>(entity).x = {};
@ -979,7 +1108,7 @@ TEST(Benchmark, IterateFiveComponentsRuntime1MOne) {
.iterate(registry.storage<comp<1>>())
.iterate(registry.storage<comp<2>>());
generic(view, [&registry](auto entity) {
iterate_with(view, [&](auto entity) {
registry.get<position>(entity).x = {};
registry.get<velocity>(entity).x = {};
registry.get<comp<0>>(entity).x = {};
@ -990,22 +1119,22 @@ TEST(Benchmark, IterateFiveComponentsRuntime1MOne) {
TEST(Benchmark, IteratePathological) {
std::cout << "Pathological case" << std::endl;
pathological([](auto &registry) { return registry.template view<position, velocity, comp<0>>(); });
pathological_with([](auto &registry) { return registry.template view<position, velocity, comp<0>>(); });
}
TEST(Benchmark, IteratePathologicalNonOwningGroup) {
std::cout << "Pathological case (non-owning group)" << std::endl;
pathological([](auto &registry) { return registry.template group<>(entt::get<position, velocity, comp<0>>); });
pathological_with([](auto &registry) { return registry.template group<>(entt::get<position, velocity, comp<0>>); });
}
TEST(Benchmark, IteratePathologicalFullOwningGroup) {
std::cout << "Pathological case (full-owning group)" << std::endl;
pathological([](auto &registry) { return registry.template group<position, velocity, comp<0>>(); });
pathological_with([](auto &registry) { return registry.template group<position, velocity, comp<0>>(); });
}
TEST(Benchmark, IteratePathologicalPartialOwningGroup) {
std::cout << "Pathological case (partial-owning group)" << std::endl;
pathological([](auto &registry) { return registry.template group<position, velocity>(entt::get<comp<0>>); });
pathological_with([](auto &registry) { return registry.template group<position, velocity>(entt::get<comp<0>>); });
}
TEST(Benchmark, SortSingle) {
@ -1018,9 +1147,9 @@ TEST(Benchmark, SortSingle) {
registry.emplace<position>(entity, i, i);
}
timer timer;
registry.sort<position>([](const auto &lhs, const auto &rhs) { return lhs.x < rhs.x && lhs.y < rhs.y; });
timer.elapsed();
generic_with([&]() {
registry.sort<position>([](const auto &lhs, const auto &rhs) { return lhs.x < rhs.x && lhs.y < rhs.y; });
});
}
TEST(Benchmark, SortMulti) {
@ -1036,9 +1165,9 @@ TEST(Benchmark, SortMulti) {
registry.sort<position>([](const auto &lhs, const auto &rhs) { return lhs.x < rhs.x && lhs.y < rhs.y; });
timer timer;
registry.sort<velocity, position>();
timer.elapsed();
generic_with([&]() {
registry.sort<velocity, position>();
});
}
TEST(Benchmark, AlmostSortedStdSort) {
@ -1062,9 +1191,9 @@ TEST(Benchmark, AlmostSortedStdSort) {
registry.emplace<position>(entity, 50000 * i, 50000 * i);
}
timer timer;
registry.sort<position>([](const auto &lhs, const auto &rhs) { return lhs.x > rhs.x && lhs.y > rhs.y; });
timer.elapsed();
generic_with([&]() {
registry.sort<position>([](const auto &lhs, const auto &rhs) { return lhs.x > rhs.x && lhs.y > rhs.y; });
});
}
TEST(Benchmark, AlmostSortedInsertionSort) {
@ -1088,7 +1217,7 @@ TEST(Benchmark, AlmostSortedInsertionSort) {
registry.emplace<position>(entity, 50000 * i, 50000 * i);
}
timer timer;
registry.sort<position>([](const auto &lhs, const auto &rhs) { return lhs.x > rhs.x && lhs.y > rhs.y; }, entt::insertion_sort{});
timer.elapsed();
generic_with([&]() {
registry.sort<position>([](const auto &lhs, const auto &rhs) { return lhs.x > rhs.x && lhs.y > rhs.y; }, entt::insertion_sort{});
});
}

View File

@ -22,7 +22,7 @@ struct basic_test_allocator: std::allocator<Type> {
return *this;
}
bool operator==(const basic_test_allocator &other) {
bool operator==(const basic_test_allocator &other) const {
return (this == &other);
}
};

View File

@ -25,14 +25,14 @@ public:
using propagate_on_container_swap = std::true_type;
using exception_type = test_exception;
template<class Other>
template<typename Other>
struct rebind {
using other = throwing_allocator<Other>;
};
throwing_allocator() = default;
template<class Other>
template<typename Other>
throwing_allocator(const throwing_allocator<Other> &other)
: base{other} {}

View File

@ -100,7 +100,7 @@ TEST(DenseMap, Functionalities) {
}
TEST(DenseMap, Constructors) {
static constexpr std::size_t minimum_bucket_count = 8u;
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_map<int, int> map;
ASSERT_EQ(map.bucket_count(), minimum_bucket_count);
@ -395,7 +395,7 @@ TEST(DenseMap, Insert) {
}
TEST(DenseMap, InsertRehash) {
static constexpr std::size_t minimum_bucket_count = 8u;
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_map<std::size_t, std::size_t, entt::identity> map;
ASSERT_EQ(map.size(), 0u);
@ -429,7 +429,7 @@ TEST(DenseMap, InsertRehash) {
}
TEST(DenseMap, InsertSameBucket) {
static constexpr std::size_t minimum_bucket_count = 8u;
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_map<std::size_t, std::size_t, entt::identity> map;
for(std::size_t next{}; next < minimum_bucket_count; ++next) {
@ -598,7 +598,7 @@ TEST(DenseMap, Emplace) {
}
TEST(DenseMap, EmplaceRehash) {
static constexpr std::size_t minimum_bucket_count = 8u;
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_map<std::size_t, std::size_t, entt::identity> map;
ASSERT_EQ(map.size(), 0u);
@ -633,7 +633,7 @@ TEST(DenseMap, EmplaceRehash) {
}
TEST(DenseMap, EmplaceSameBucket) {
static constexpr std::size_t minimum_bucket_count = 8u;
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_map<std::size_t, std::size_t, entt::identity> map;
for(std::size_t next{}; next < minimum_bucket_count; ++next) {
@ -681,7 +681,7 @@ TEST(DenseMap, TryEmplace) {
}
TEST(DenseMap, TryEmplaceRehash) {
static constexpr std::size_t minimum_bucket_count = 8u;
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_map<std::size_t, std::size_t, entt::identity> map;
ASSERT_EQ(map.size(), 0u);
@ -715,7 +715,7 @@ TEST(DenseMap, TryEmplaceRehash) {
}
TEST(DenseMap, TryEmplaceSameBucket) {
static constexpr std::size_t minimum_bucket_count = 8u;
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_map<std::size_t, std::size_t, entt::identity> map;
for(std::size_t next{}; next < minimum_bucket_count; ++next) {
@ -749,7 +749,7 @@ TEST(DenseMap, TryEmplaceMovableType) {
}
TEST(DenseMap, Erase) {
static constexpr std::size_t minimum_bucket_count = 8u;
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_map<std::size_t, std::size_t, entt::identity> map;
for(std::size_t next{}, last = minimum_bucket_count + 1u; next < last; ++next) {
@ -799,7 +799,7 @@ TEST(DenseMap, Erase) {
}
TEST(DenseMap, EraseWithMovableKeyValue) {
static constexpr std::size_t minimum_bucket_count = 8u;
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_map<std::string, std::size_t> map;
map.emplace("0", 0u);
@ -817,7 +817,7 @@ TEST(DenseMap, EraseWithMovableKeyValue) {
}
TEST(DenseMap, EraseFromBucket) {
static constexpr std::size_t minimum_bucket_count = 8u;
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_map<std::size_t, std::size_t, entt::identity> map;
ASSERT_EQ(map.bucket_count(), minimum_bucket_count);
@ -995,7 +995,7 @@ TEST(DenseMap, LocalIterator) {
static_assert(std::is_same_v<iterator::pointer, entt::input_iterator_pointer<std::pair<const std::size_t &, std::size_t &>>>);
static_assert(std::is_same_v<iterator::reference, std::pair<const std::size_t &, std::size_t &>>);
static constexpr std::size_t minimum_bucket_count = 8u;
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_map<std::size_t, std::size_t, entt::identity> map;
map.emplace(3u, 42u);
map.emplace(3u + minimum_bucket_count, 99u);
@ -1023,7 +1023,7 @@ TEST(DenseMap, ConstLocalIterator) {
static_assert(std::is_same_v<iterator::pointer, entt::input_iterator_pointer<std::pair<const std::size_t &, const std::size_t &>>>);
static_assert(std::is_same_v<iterator::reference, std::pair<const std::size_t &, const std::size_t &>>);
static constexpr std::size_t minimum_bucket_count = 8u;
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_map<std::size_t, std::size_t, entt::identity> map;
map.emplace(3u, 42u);
map.emplace(3u + minimum_bucket_count, 99u);
@ -1064,7 +1064,7 @@ TEST(DenseMap, LocalIteratorConversion) {
}
TEST(DenseMap, Rehash) {
static constexpr std::size_t minimum_bucket_count = 8u;
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_map<std::size_t, std::size_t, entt::identity> map;
map[32u] = 99u;
@ -1147,7 +1147,7 @@ TEST(DenseMap, Rehash) {
}
TEST(DenseMap, Reserve) {
static constexpr std::size_t minimum_bucket_count = 8u;
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_map<int, int> map;
ASSERT_EQ(map.bucket_count(), minimum_bucket_count);
@ -1159,7 +1159,7 @@ TEST(DenseMap, Reserve) {
map.reserve(minimum_bucket_count);
ASSERT_EQ(map.bucket_count(), 2 * minimum_bucket_count);
ASSERT_EQ(map.bucket_count(), entt::next_power_of_two(std::ceil(minimum_bucket_count / map.max_load_factor())));
ASSERT_EQ(map.bucket_count(), entt::next_power_of_two(static_cast<std::size_t>(std::ceil(minimum_bucket_count / map.max_load_factor()))));
}
TEST(DenseMap, ThrowingAllocator) {
@ -1167,7 +1167,7 @@ TEST(DenseMap, ThrowingAllocator) {
using packed_allocator = test::throwing_allocator<entt::internal::dense_map_node<std::size_t, std::size_t>>;
using packed_exception = typename packed_allocator::exception_type;
static constexpr std::size_t minimum_bucket_count = 8u;
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_map<std::size_t, std::size_t, std::hash<std::size_t>, std::equal_to<std::size_t>, allocator> map{};
packed_allocator::trigger_on_allocate = true;

View File

@ -98,7 +98,7 @@ TEST(DenseSet, Functionalities) {
}
TEST(DenseSet, Constructors) {
static constexpr std::size_t minimum_bucket_count = 8u;
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_set<int> set;
ASSERT_EQ(set.bucket_count(), minimum_bucket_count);
@ -357,7 +357,7 @@ TEST(DenseSet, Insert) {
}
TEST(DenseSet, InsertRehash) {
static constexpr std::size_t minimum_bucket_count = 8u;
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_set<std::size_t, entt::identity> set;
ASSERT_EQ(set.size(), 0u);
@ -388,7 +388,7 @@ TEST(DenseSet, InsertRehash) {
}
TEST(DenseSet, InsertSameBucket) {
static constexpr std::size_t minimum_bucket_count = 8u;
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_set<std::size_t, entt::identity> set;
for(std::size_t next{}; next < minimum_bucket_count; ++next) {
@ -451,7 +451,7 @@ TEST(DenseSet, Emplace) {
}
TEST(DenseSet, EmplaceRehash) {
static constexpr std::size_t minimum_bucket_count = 8u;
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_set<std::size_t, entt::identity> set;
ASSERT_EQ(set.size(), 0u);
@ -483,7 +483,7 @@ TEST(DenseSet, EmplaceRehash) {
}
TEST(DenseSet, EmplaceSameBucket) {
static constexpr std::size_t minimum_bucket_count = 8u;
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_set<std::size_t, entt::identity> set;
for(std::size_t next{}; next < minimum_bucket_count; ++next) {
@ -503,7 +503,7 @@ TEST(DenseSet, EmplaceSameBucket) {
}
TEST(DenseSet, Erase) {
static constexpr std::size_t minimum_bucket_count = 8u;
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_set<std::size_t, entt::identity> set;
for(std::size_t next{}, last = minimum_bucket_count + 1u; next < last; ++next) {
@ -553,7 +553,7 @@ TEST(DenseSet, Erase) {
}
TEST(DenseSet, EraseWithMovableKeyValue) {
static constexpr std::size_t minimum_bucket_count = 8u;
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_set<std::string> set;
set.emplace("0");
@ -570,7 +570,7 @@ TEST(DenseSet, EraseWithMovableKeyValue) {
}
TEST(DenseSet, EraseFromBucket) {
static constexpr std::size_t minimum_bucket_count = 8u;
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_set<std::size_t, entt::identity> set;
ASSERT_EQ(set.bucket_count(), minimum_bucket_count);
@ -721,7 +721,7 @@ TEST(DenseSet, LocalIterator) {
static_assert(std::is_same_v<iterator::pointer, const std::size_t *>);
static_assert(std::is_same_v<iterator::reference, const std::size_t &>);
static constexpr std::size_t minimum_bucket_count = 8u;
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_set<std::size_t, entt::identity> set;
set.emplace(3u);
set.emplace(3u + minimum_bucket_count);
@ -749,7 +749,7 @@ TEST(DenseSet, ConstLocalIterator) {
static_assert(std::is_same_v<iterator::pointer, const std::size_t *>);
static_assert(std::is_same_v<iterator::reference, const std::size_t &>);
static constexpr std::size_t minimum_bucket_count = 8u;
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_set<std::size_t, entt::identity> set;
set.emplace(3u);
set.emplace(3u + minimum_bucket_count);
@ -790,7 +790,7 @@ TEST(DenseSet, LocalIteratorConversion) {
}
TEST(DenseSet, Rehash) {
static constexpr std::size_t minimum_bucket_count = 8u;
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_set<std::size_t, entt::identity> set;
set.emplace(32u);
@ -865,7 +865,7 @@ TEST(DenseSet, Rehash) {
}
TEST(DenseSet, Reserve) {
static constexpr std::size_t minimum_bucket_count = 8u;
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_set<int> set;
ASSERT_EQ(set.bucket_count(), minimum_bucket_count);
@ -877,7 +877,7 @@ TEST(DenseSet, Reserve) {
set.reserve(minimum_bucket_count);
ASSERT_EQ(set.bucket_count(), 2 * minimum_bucket_count);
ASSERT_EQ(set.bucket_count(), entt::next_power_of_two(std::ceil(minimum_bucket_count / set.max_load_factor())));
ASSERT_EQ(set.bucket_count(), entt::next_power_of_two(static_cast<std::size_t>(std::ceil(minimum_bucket_count / set.max_load_factor()))));
}
TEST(DenseSet, ThrowingAllocator) {
@ -885,7 +885,7 @@ TEST(DenseSet, ThrowingAllocator) {
using packed_allocator = test::throwing_allocator<std::pair<std::size_t, std::size_t>>;
using packed_exception = typename packed_allocator::exception_type;
static constexpr std::size_t minimum_bucket_count = 8u;
constexpr std::size_t minimum_bucket_count = 8u;
entt::dense_set<std::size_t, std::hash<std::size_t>, std::equal_to<std::size_t>, allocator> set{};
packed_allocator::trigger_on_allocate = true;

View File

@ -2,6 +2,7 @@
#include <cstdint>
#include <cstring>
#include <iterator>
#include <memory>
#include <type_traits>
#include <unordered_map>
#include <utility>
@ -39,21 +40,9 @@ struct not_comparable {
bool operator==(const not_comparable &) const = delete;
};
struct not_copyable {
not_copyable()
: payload{} {}
not_copyable(const not_copyable &) = delete;
not_copyable(not_copyable &&) = default;
not_copyable &operator=(const not_copyable &) = delete;
not_copyable &operator=(not_copyable &&) = default;
double payload;
};
struct not_movable {
not_movable() = default;
not_movable(const not_movable &) = default;
not_movable(not_movable &&) = delete;
@ -1183,13 +1172,12 @@ TEST_F(Any, AnyCast) {
ASSERT_EQ(entt::any_cast<int &>(any), 42);
ASSERT_EQ(entt::any_cast<const int &>(cany), 42);
not_copyable instance{};
instance.payload = 42.;
auto instance = std::make_unique<double>(42.);
entt::any ref{entt::forward_as_any(instance)};
entt::any cref{entt::forward_as_any(std::as_const(instance).payload)};
entt::any cref{entt::forward_as_any(std::as_const(*instance))};
ASSERT_EQ(entt::any_cast<not_copyable>(std::move(ref)).payload, 42.);
ASSERT_EQ(entt::any_cast<double>(std::move(cref)), 42.);
ASSERT_EQ(*entt::any_cast<std::unique_ptr<double>>(std::move(ref)), 42.);
ASSERT_EQ(entt::any_cast<int>(entt::any{42}), 42);
}
@ -1197,16 +1185,15 @@ ENTT_DEBUG_TEST_F(AnyDeathTest, AnyCast) {
entt::any any{42};
const auto &cany = any;
ASSERT_DEATH(entt::any_cast<double &>(any), "");
ASSERT_DEATH(entt::any_cast<const double &>(cany), "");
ASSERT_DEATH([[maybe_unused]] auto &elem = entt::any_cast<double &>(any), "");
ASSERT_DEATH([[maybe_unused]] const auto &elem = entt::any_cast<const double &>(cany), "");
not_copyable instance{};
instance.payload = 42.;
auto instance = std::make_unique<double>(42.);
entt::any ref{entt::forward_as_any(instance)};
entt::any cref{entt::forward_as_any(std::as_const(instance).payload)};
entt::any cref{entt::forward_as_any(std::as_const(*instance))};
ASSERT_DEATH(entt::any_cast<not_copyable>(std::as_const(ref).as_ref()), "");
ASSERT_DEATH(entt::any_cast<double>(entt::any{42}), "");
ASSERT_DEATH([[maybe_unused]] auto elem = entt::any_cast<std::unique_ptr<double>>(std::as_const(ref).as_ref()), "");
ASSERT_DEATH([[maybe_unused]] auto elem = entt::any_cast<double>(entt::any{42}), "");
}
TEST_F(Any, MakeAny) {
@ -1263,8 +1250,8 @@ TEST_F(Any, ForwardAsAny) {
}
TEST_F(Any, NotCopyableType) {
const not_copyable value{};
entt::any any{std::in_place_type<not_copyable>};
const std::unique_ptr<int> value{};
entt::any any{std::in_place_type<std::unique_ptr<int>>};
entt::any other = entt::forward_as_any(value);
ASSERT_TRUE(any);
@ -1296,7 +1283,7 @@ TEST_F(Any, NotCopyableType) {
TEST_F(Any, NotCopyableValueType) {
std::vector<entt::any> vec{};
vec.emplace_back(std::in_place_type<not_copyable>);
vec.emplace_back(std::in_place_type<std::unique_ptr<int>>);
vec.shrink_to_fit();
ASSERT_EQ(vec.size(), 1u);
@ -1304,7 +1291,7 @@ TEST_F(Any, NotCopyableValueType) {
ASSERT_TRUE(vec[0u]);
// strong exception guarantee due to noexcept move ctor
vec.emplace_back(std::in_place_type<not_copyable>);
vec.emplace_back(std::in_place_type<std::unique_ptr<int>>);
ASSERT_EQ(vec.size(), 2u);
ASSERT_TRUE(vec[0u]);
@ -1411,7 +1398,7 @@ TEST_F(Any, SBOVsZeroedSBOSize) {
}
TEST_F(Any, SboAlignment) {
static constexpr auto alignment = alignof(over_aligned);
constexpr auto alignment = alignof(over_aligned);
entt::basic_any<alignment, alignment> sbo[2] = {over_aligned{}, over_aligned{}};
const auto *data = sbo[0].data();
@ -1427,7 +1414,7 @@ TEST_F(Any, SboAlignment) {
}
TEST_F(Any, NoSboAlignment) {
static constexpr auto alignment = alignof(over_aligned);
constexpr auto alignment = alignof(over_aligned);
entt::basic_any<alignment> nosbo[2] = {over_aligned{}, over_aligned{}};
const auto *data = nosbo[0].data();

View File

@ -6,19 +6,19 @@
#include <entt/core/hashed_string.hpp>
template<typename>
struct foobar_t;
struct expected;
template<>
struct foobar_t<std::uint32_t> {
struct expected<std::uint32_t> {
static constexpr auto value = 0xbf9cf968;
};
template<>
struct foobar_t<std::uint64_t> {
struct expected<std::uint64_t> {
static constexpr auto value = 0x85944171f73967e8;
};
inline constexpr auto foobar_v = foobar_t<entt::id_type>::value;
inline constexpr auto expected_v = expected<entt::id_type>::value;
TEST(BasicHashedString, DeductionGuide) {
static_assert(std::is_same_v<decltype(entt::basic_hashed_string{"foo"}), entt::hashed_string>);
@ -47,8 +47,8 @@ TEST(HashedString, Functionalities) {
entt::hashed_string hs{"foobar"};
ASSERT_EQ(static_cast<hash_type>(hs), foobar_v);
ASSERT_EQ(hs.value(), foobar_v);
ASSERT_EQ(static_cast<hash_type>(hs), expected_v);
ASSERT_EQ(hs.value(), expected_v);
ASSERT_EQ(foo_hs, "foo"_hs);
ASSERT_NE(bar_hs, "foo"_hs);
@ -78,13 +78,13 @@ TEST(HashedString, Correctness) {
const char *foobar = "foobar";
std::string_view view{"foobar__", 6};
ASSERT_EQ(entt::hashed_string{foobar}, foobar_v);
ASSERT_EQ((entt::hashed_string{view.data(), view.size()}), foobar_v);
ASSERT_EQ(entt::hashed_string{"foobar"}, foobar_v);
ASSERT_EQ(entt::hashed_string{foobar}, expected_v);
ASSERT_EQ((entt::hashed_string{view.data(), view.size()}), expected_v);
ASSERT_EQ(entt::hashed_string{"foobar"}, expected_v);
ASSERT_EQ(entt::hashed_string::value(foobar), foobar_v);
ASSERT_EQ(entt::hashed_string::value(view.data(), view.size()), foobar_v);
ASSERT_EQ(entt::hashed_string::value("foobar"), foobar_v);
ASSERT_EQ(entt::hashed_string::value(foobar), expected_v);
ASSERT_EQ(entt::hashed_string::value(view.data(), view.size()), expected_v);
ASSERT_EQ(entt::hashed_string::value("foobar"), expected_v);
ASSERT_EQ(entt::hashed_string{foobar}.size(), 6u);
ASSERT_EQ((entt::hashed_string{view.data(), view.size()}).size(), 6u);
@ -111,16 +111,16 @@ TEST(HashedString, Constexprness) {
constexpr std::string_view view{"foobar__", 6};
static_assert(entt::hashed_string{"quux"} == "quux"_hs);
static_assert(entt::hashed_string{"foobar"} == foobar_v);
static_assert(entt::hashed_string{"foobar"} == expected_v);
static_assert(entt::hashed_string::value("quux") == "quux"_hs);
static_assert(entt::hashed_string::value("foobar") == foobar_v);
static_assert(entt::hashed_string::value("foobar") == expected_v);
static_assert(entt::hashed_string{"quux", 4} == "quux"_hs);
static_assert(entt::hashed_string{view.data(), view.size()} == foobar_v);
static_assert(entt::hashed_string{view.data(), view.size()} == expected_v);
static_assert(entt::hashed_string::value("quux", 4) == "quux"_hs);
static_assert(entt::hashed_string::value(view.data(), view.size()) == foobar_v);
static_assert(entt::hashed_string::value(view.data(), view.size()) == expected_v);
static_assert(entt::hashed_string{"bar"} < "foo"_hs);
static_assert(entt::hashed_string{"bar"} <= "bar"_hs);
@ -151,8 +151,8 @@ TEST(HashedWString, Functionalities) {
entt::hashed_wstring hws{L"foobar"};
ASSERT_EQ(static_cast<hash_type>(hws), foobar_v);
ASSERT_EQ(hws.value(), foobar_v);
ASSERT_EQ(static_cast<hash_type>(hws), expected_v);
ASSERT_EQ(hws.value(), expected_v);
ASSERT_EQ(foo_hws, L"foo"_hws);
ASSERT_NE(bar_hws, L"foo"_hws);
@ -172,13 +172,13 @@ TEST(HashedWString, Correctness) {
const wchar_t *foobar = L"foobar";
std::wstring_view view{L"foobar__", 6};
ASSERT_EQ(entt::hashed_wstring{foobar}, foobar_v);
ASSERT_EQ((entt::hashed_wstring{view.data(), view.size()}), foobar_v);
ASSERT_EQ(entt::hashed_wstring{L"foobar"}, foobar_v);
ASSERT_EQ(entt::hashed_wstring{foobar}, expected_v);
ASSERT_EQ((entt::hashed_wstring{view.data(), view.size()}), expected_v);
ASSERT_EQ(entt::hashed_wstring{L"foobar"}, expected_v);
ASSERT_EQ(entt::hashed_wstring::value(foobar), foobar_v);
ASSERT_EQ(entt::hashed_wstring::value(view.data(), view.size()), foobar_v);
ASSERT_EQ(entt::hashed_wstring::value(L"foobar"), foobar_v);
ASSERT_EQ(entt::hashed_wstring::value(foobar), expected_v);
ASSERT_EQ(entt::hashed_wstring::value(view.data(), view.size()), expected_v);
ASSERT_EQ(entt::hashed_wstring::value(L"foobar"), expected_v);
ASSERT_EQ(entt::hashed_wstring{foobar}.size(), 6u);
ASSERT_EQ((entt::hashed_wstring{view.data(), view.size()}).size(), 6u);
@ -205,16 +205,16 @@ TEST(HashedWString, Constexprness) {
constexpr std::wstring_view view{L"foobar__", 6};
static_assert(entt::hashed_wstring{L"quux"} == L"quux"_hws);
static_assert(entt::hashed_wstring{L"foobar"} == foobar_v);
static_assert(entt::hashed_wstring{L"foobar"} == expected_v);
static_assert(entt::hashed_wstring::value(L"quux") == L"quux"_hws);
static_assert(entt::hashed_wstring::value(L"foobar") == foobar_v);
static_assert(entt::hashed_wstring::value(L"foobar") == expected_v);
static_assert(entt::hashed_wstring{L"quux", 4} == L"quux"_hws);
static_assert(entt::hashed_wstring{view.data(), view.size()} == foobar_v);
static_assert(entt::hashed_wstring{view.data(), view.size()} == expected_v);
static_assert(entt::hashed_wstring::value(L"quux", 4) == L"quux"_hws);
static_assert(entt::hashed_wstring::value(view.data(), view.size()) == foobar_v);
static_assert(entt::hashed_wstring::value(view.data(), view.size()) == expected_v);
static_assert(entt::hashed_wstring{L"bar"} < L"foo"_hws);
static_assert(entt::hashed_wstring{L"bar"} <= L"bar"_hws);

View File

@ -24,6 +24,12 @@ TEST(ToAddress, Functionalities) {
TEST(PoccaPocmaAndPocs, Functionalities) {
test::basic_test_allocator<int> lhs, rhs;
test::basic_test_allocator<int, std::false_type> no_pocs;
// code coverage purposes
ASSERT_FALSE(lhs == rhs);
ASSERT_NO_FATAL_FAILURE(entt::propagate_on_container_swap(no_pocs, no_pocs));
// honestly, I don't even know how one is supposed to test such a thing :)
entt::propagate_on_container_copy_assignment(lhs, rhs);
entt::propagate_on_container_move_assignment(lhs, rhs);
@ -31,8 +37,8 @@ TEST(PoccaPocmaAndPocs, Functionalities) {
}
ENTT_DEBUG_TEST(PoccaPocmaAndPocsDeathTest, Functionalities) {
using pocs = std::false_type;
test::basic_test_allocator<int, pocs> lhs, rhs;
test::basic_test_allocator<int, std::false_type> lhs, rhs;
ASSERT_DEATH(entt::propagate_on_container_swap(lhs, rhs), "");
}
@ -60,8 +66,8 @@ TEST(NextPowerOfTwo, Functionalities) {
ASSERT_EQ(entt::next_power_of_two(17u), 32u);
ASSERT_EQ(entt::next_power_of_two(32u), 32u);
ASSERT_EQ(entt::next_power_of_two(33u), 64u);
ASSERT_EQ(entt::next_power_of_two(std::pow(2, 16)), std::pow(2, 16));
ASSERT_EQ(entt::next_power_of_two(std::pow(2, 16) + 1u), std::pow(2, 17));
ASSERT_EQ(entt::next_power_of_two(static_cast<std::size_t>(std::pow(2, 16))), static_cast<std::size_t>(std::pow(2, 16)));
ASSERT_EQ(entt::next_power_of_two(static_cast<std::size_t>(std::pow(2, 16) + 1u)), static_cast<std::size_t>(std::pow(2, 17)));
}
ENTT_DEBUG_TEST(NextPowerOfTwoDeathTest, Functionalities) {

View File

@ -34,5 +34,5 @@ TEST(Tuple, UnwrapTuple) {
TEST(Tuple, ForwardApply) {
ASSERT_EQ(entt::forward_apply{[](auto &&...args) { return sizeof...(args); }}(std::make_tuple()), 0u);
ASSERT_EQ(entt::forward_apply{[](int i) { return i; }}(std::make_tuple(42)), 42);
ASSERT_EQ(entt::forward_apply{[](auto... args) { return (args + ...); }}(std::make_tuple('a', 1u)), 'b');
ASSERT_EQ(entt::forward_apply{[](auto... args) { return (args + ...); }}(std::make_tuple('a', 1)), 'b');
}

View File

@ -89,7 +89,7 @@ TEST(TypeList, Functionalities) {
static_assert(std::is_same_v<entt::type_list_cat_t<type, other, type, other>, entt::type_list<int, char, double, int, char, double>>);
static_assert(std::is_same_v<entt::type_list_cat_t<type, other>, entt::type_list<int, char, double>>);
static_assert(std::is_same_v<entt::type_list_cat_t<type, type>, entt::type_list<int, char, int, char>>);
static_assert(std::is_same_v<entt::type_list_unique_t<entt::type_list_cat_t<type, type>>, entt::type_list<int, char>>);
static_assert(std::is_same_v<entt::type_list_unique_t<entt::type_list_cat_t<type, type>>, type>);
static_assert(entt::type_list_contains_v<type, int>);
static_assert(entt::type_list_contains_v<type, char>);
@ -112,6 +112,14 @@ TEST(TypeList, Functionalities) {
static_assert(std::is_same_v<entt::type_list_transform_t<entt::type_list<int, char>, entt::type_identity>, entt::type_list<int, char>>);
static_assert(std::is_same_v<entt::type_list_transform_t<entt::type_list<int, char>, std::add_const>, entt::type_list<const int, const char>>);
static_assert(std::is_same_v<entt::type_list_transform_t<entt::type_list<int, char>, multi_argument_operation>, entt::type_list<void, void>>);
static_assert(std::tuple_size_v<entt::type_list<>> == 0u);
static_assert(std::tuple_size_v<entt::type_list<int>> == 1u);
static_assert(std::tuple_size_v<entt::type_list<int, float>> == 2u);
static_assert(std::is_same_v<int, std::tuple_element_t<0, entt::type_list<int>>>);
static_assert(std::is_same_v<int, std::tuple_element_t<0, entt::type_list<int, float>>>);
static_assert(std::is_same_v<float, std::tuple_element_t<1, entt::type_list<int, float>>>);
}
TEST(ValueList, Functionalities) {
@ -125,10 +133,33 @@ TEST(ValueList, Functionalities) {
static_assert(std::is_same_v<entt::value_list_cat_t<value, other, value, other>, entt::value_list<0, 2, 1, 0, 2, 1>>);
static_assert(std::is_same_v<entt::value_list_cat_t<value, other>, entt::value_list<0, 2, 1>>);
static_assert(std::is_same_v<entt::value_list_cat_t<value, value>, entt::value_list<0, 2, 0, 2>>);
static_assert(std::is_same_v<entt::value_list_unique_t<entt::value_list_cat_t<value, value>>, value>);
static_assert(entt::value_list_contains_v<value, 0>);
static_assert(entt::value_list_contains_v<value, 2>);
static_assert(!entt::value_list_contains_v<value, 1>);
static_assert(entt::value_list_element_v<0u, value> == 0);
static_assert(entt::value_list_element_v<1u, value> == 2);
static_assert(entt::value_list_element_v<0u, other> == 1);
static_assert(entt::value_list_index_v<0, value> == 0u);
static_assert(entt::value_list_index_v<2, value> == 1u);
static_assert(entt::value_list_index_v<1, other> == 0u);
static_assert(std::is_same_v<entt::value_list_diff_t<entt::value_list<0, 1, 2>, entt::value_list<3, 4>>, entt::value_list<0, 1, 2>>);
static_assert(std::is_same_v<entt::value_list_diff_t<entt::value_list<0, 1, 2>, entt::value_list<0, 1, 2>>, entt::value_list<>>);
static_assert(std::is_same_v<entt::value_list_diff_t<entt::value_list<0, 1, 2>, entt::value_list<0, 1>>, entt::value_list<2>>);
static_assert(std::is_same_v<entt::value_list_diff_t<entt::value_list<0, 1, 2>, entt::value_list<1, 2>>, entt::value_list<0>>);
static_assert(std::is_same_v<entt::value_list_diff_t<entt::value_list<0, 1, 2>, entt::value_list<1>>, entt::value_list<0, 2>>);
static_assert(std::tuple_size_v<entt::value_list<>> == 0u);
static_assert(std::tuple_size_v<entt::value_list<42>> == 1u);
static_assert(std::tuple_size_v<entt::value_list<42, 'a'>> == 2u);
static_assert(std::is_same_v<int, std::tuple_element_t<0, entt::value_list<42>>>);
static_assert(std::is_same_v<int, std::tuple_element_t<0, entt::value_list<42, 'a'>>>);
static_assert(std::is_same_v<char, std::tuple_element_t<1, entt::value_list<42, 'a'>>>);
}
TEST(IsApplicable, Functionalities) {
@ -183,6 +214,7 @@ TEST(IsEqualityComparable, Functionalities) {
static_assert(entt::is_equality_comparable_v<std::vector<not_comparable>::iterator>);
static_assert(entt::is_equality_comparable_v<nlohmann_json_like>);
static_assert(!entt::is_equality_comparable_v<int[3u]>);
static_assert(!entt::is_equality_comparable_v<not_comparable>);
static_assert(!entt::is_equality_comparable_v<const not_comparable>);
static_assert(!entt::is_equality_comparable_v<std::vector<not_comparable>>);

View File

@ -30,50 +30,43 @@ struct entt::component_traits<traits_based> {
};
TEST(Component, VoidType) {
using traits = entt::component_traits<void>;
using traits_type = entt::component_traits<void>;
static_assert(traits::in_place_delete);
static_assert(entt::ignore_as_empty_v<typename traits::type>);
// we don't really care about this thanks to ignore_as_empty_v
static_assert(traits::page_size != 0u);
static_assert(!traits_type::in_place_delete);
static_assert(traits_type::page_size == 0u);
}
TEST(Component, Empty) {
using traits = entt::component_traits<empty>;
using traits_type = entt::component_traits<empty>;
static_assert(!traits::in_place_delete);
static_assert(entt::ignore_as_empty_v<typename traits::type>);
static_assert(traits::page_size == 0u);
static_assert(!traits_type::in_place_delete);
static_assert(traits_type::page_size == 0u);
}
TEST(Component, NonEmpty) {
using traits = entt::component_traits<non_empty>;
using traits_type = entt::component_traits<non_empty>;
static_assert(!traits::in_place_delete);
static_assert(!entt::ignore_as_empty_v<typename traits::type>);
static_assert(traits::page_size == ENTT_PACKED_PAGE);
static_assert(!traits_type::in_place_delete);
static_assert(traits_type::page_size == ENTT_PACKED_PAGE);
}
TEST(Component, NonMovable) {
using traits = entt::component_traits<non_movable>;
using traits_type = entt::component_traits<non_movable>;
static_assert(traits::in_place_delete);
static_assert(!entt::ignore_as_empty_v<typename traits::type>);
static_assert(traits::page_size == ENTT_PACKED_PAGE);
static_assert(traits_type::in_place_delete);
static_assert(traits_type::page_size == ENTT_PACKED_PAGE);
}
TEST(Component, SelfContained) {
using traits = entt::component_traits<self_contained>;
using traits_type = entt::component_traits<self_contained>;
static_assert(traits::in_place_delete);
static_assert(!entt::ignore_as_empty_v<typename traits::type>);
static_assert(traits::page_size == 4u);
static_assert(traits_type::in_place_delete);
static_assert(traits_type::page_size == 4u);
}
TEST(Component, TraitsBased) {
using traits = entt::component_traits<traits_based>;
using traits_type = entt::component_traits<traits_based>;
static_assert(!traits::in_place_delete);
static_assert(!entt::ignore_as_empty_v<typename traits::type>);
static_assert(traits::page_size == 8u);
static_assert(!traits_type::in_place_delete);
static_assert(traits_type::page_size == 8u);
}

View File

@ -29,6 +29,12 @@ TEST(Entity, Traits) {
ASSERT_EQ(traits_type::combine(entt::tombstone, entt::null), tombstone);
ASSERT_EQ(traits_type::combine(entt::null, entt::tombstone), null);
ASSERT_EQ(traits_type::next(entity), traits_type::construct(entt::to_integral(entity), entt::to_version(entity) + 1u));
ASSERT_EQ(traits_type::next(other), traits_type::construct(entt::to_integral(other), entt::to_version(other) + 1u));
ASSERT_EQ(traits_type::next(entt::tombstone), traits_type::construct(entt::null, {}));
ASSERT_EQ(traits_type::next(entt::null), traits_type::construct(entt::null, {}));
}
TEST(Entity, Null) {

View File

@ -8,6 +8,7 @@
#include <gtest/gtest.h>
#include <entt/entity/group.hpp>
#include <entt/entity/registry.hpp>
#include "../common/config.h"
struct empty_type {};
@ -56,7 +57,7 @@ TEST(NonOwningGroup, Functionalities) {
for(auto entity: group) {
ASSERT_EQ(std::get<0>(cgroup.get<const int, const char>(entity)), 42);
ASSERT_EQ(std::get<1>(group.get<int, char>(entity)), '2');
ASSERT_EQ(cgroup.get<const char>(entity), '2');
ASSERT_EQ(cgroup.get<1>(entity), '2');
}
ASSERT_EQ(group.handle().data()[0u], e1);
@ -93,6 +94,7 @@ TEST(NonOwningGroup, Handle) {
ASSERT_TRUE(handle.empty());
ASSERT_FALSE(handle.contains(entity));
ASSERT_EQ(&handle, &group.handle());
ASSERT_NE(&handle, group.storage<int>());
registry.emplace<int>(entity);
registry.emplace<char>(entity);
@ -187,10 +189,10 @@ TEST(NonOwningGroup, Each) {
auto cgroup = std::as_const(registry).group_if_exists(entt::get<const int, const char>);
registry.emplace<int>(entity[0u], 0);
registry.emplace<char>(entity[0u], 0);
registry.emplace<char>(entity[0u], static_cast<char>(0));
registry.emplace<int>(entity[1u], 1);
registry.emplace<char>(entity[1u], 1);
registry.emplace<char>(entity[1u], static_cast<char>(1));
auto iterable = group.each();
auto citerable = cgroup.each();
@ -201,16 +203,18 @@ TEST(NonOwningGroup, Each) {
auto it = iterable.begin();
ASSERT_EQ(it.base(), group.begin());
ASSERT_EQ((it++, ++it), iterable.end());
ASSERT_EQ(it.base(), group.end());
group.each([expected = 1u](auto entt, int &ivalue, char &cvalue) mutable {
ASSERT_EQ(entt::to_integral(entt), expected);
group.each([expected = 1](auto entt, int &ivalue, char &cvalue) mutable {
ASSERT_EQ(static_cast<int>(entt::to_integral(entt)), expected);
ASSERT_EQ(ivalue, expected);
ASSERT_EQ(cvalue, expected);
--expected;
});
cgroup.each([expected = 1u](const int &ivalue, const char &cvalue) mutable {
cgroup.each([expected = 1](const int &ivalue, const char &cvalue) mutable {
ASSERT_EQ(ivalue, expected);
ASSERT_EQ(cvalue, expected);
--expected;
@ -224,8 +228,8 @@ TEST(NonOwningGroup, Each) {
// do not use iterable, make sure an iterable group works when created from a temporary
for(auto [entt, ivalue, cvalue]: registry.group(entt::get<int, char>).each()) {
ASSERT_EQ(entt::to_integral(entt), ivalue);
ASSERT_EQ(entt::to_integral(entt), cvalue);
ASSERT_EQ(static_cast<int>(entt::to_integral(entt)), ivalue);
ASSERT_EQ(static_cast<char>(entt::to_integral(entt)), cvalue);
}
}
@ -273,9 +277,9 @@ TEST(NonOwningGroup, Sort) {
ASSERT_EQ(group.handle().data()[1u], e1);
ASSERT_EQ(group.handle().data()[2u], e2);
ASSERT_EQ((group.get<const int, unsigned int>(e0)), (std::make_tuple(0, 0u)));
ASSERT_EQ((group.get<const int, unsigned int>(e1)), (std::make_tuple(1, 1u)));
ASSERT_EQ((group.get<const int, unsigned int>(e2)), (std::make_tuple(2, 2u)));
ASSERT_EQ((group.get<0, 1>(e0)), (std::make_tuple(0, 0u)));
ASSERT_EQ((group.get<0, 1>(e1)), (std::make_tuple(1, 1u)));
ASSERT_EQ((group.get<0, 1>(e2)), (std::make_tuple(2, 2u)));
ASSERT_FALSE(group.contains(e3));
@ -323,10 +327,10 @@ TEST(NonOwningGroup, SortAsAPool) {
}
registry.sort<unsigned int>(std::less<unsigned int>{});
group.sort<unsigned int>();
group.sort_as(*group.storage<unsigned int>());
ASSERT_EQ((group.get<const int, unsigned int>(e0)), (std::make_tuple(0, 0u)));
ASSERT_EQ((group.get<const int, unsigned int>(e1)), (std::make_tuple(1, 1u)));
ASSERT_EQ((group.get<0, 1>(e1)), (std::make_tuple(1, 1u)));
ASSERT_EQ((group.get<const int, unsigned int>(e2)), (std::make_tuple(2, 2u)));
ASSERT_FALSE(group.contains(e3));
@ -384,9 +388,18 @@ TEST(NonOwningGroup, ConstNonConstAndAllInBetween) {
ASSERT_EQ(group.size(), 1u);
static_assert(std::is_same_v<decltype(group.get<0>({})), int &>);
static_assert(std::is_same_v<decltype(group.get<int>({})), int &>);
static_assert(std::is_same_v<decltype(group.get<1>({})), void>);
static_assert(std::is_same_v<decltype(group.get<empty_type>({})), void>);
static_assert(std::is_same_v<decltype(group.get<2>({})), const char &>);
static_assert(std::is_same_v<decltype(group.get<const char>({})), const char &>);
static_assert(std::is_same_v<decltype(group.get<int, const char>({})), std::tuple<int &, const char &>>);
static_assert(std::is_same_v<decltype(group.get<int, empty_type, const char>({})), std::tuple<int &, const char &>>);
static_assert(std::is_same_v<decltype(group.get<0, 1, 2>({})), std::tuple<int &, const char &>>);
static_assert(std::is_same_v<decltype(group.get({})), std::tuple<int &, const char &>>);
static_assert(std::is_same_v<decltype(std::as_const(registry).group_if_exists(entt::get<int, char>)), decltype(std::as_const(registry).group_if_exists(entt::get<const int, const char>))>);
@ -475,7 +488,7 @@ TEST(NonOwningGroup, ExcludedComponents) {
if(entity == e0) {
ASSERT_EQ(group.get<int>(e0), 0);
} else if(entity == e2) {
ASSERT_EQ(group.get<int>(e2), 2);
ASSERT_EQ(group.get<0>(e2), 2);
}
}
@ -493,7 +506,7 @@ TEST(NonOwningGroup, ExcludedComponents) {
if(entity == e1) {
ASSERT_EQ(group.get<int>(e1), 1);
} else if(entity == e3) {
ASSERT_EQ(group.get<int>(e3), 3);
ASSERT_EQ(group.get<0>(e3), 3);
}
}
}
@ -663,28 +676,100 @@ TEST(NonOwningGroup, IterableGroupAlgorithmCompatibility) {
TEST(NonOwningGroup, Storage) {
entt::registry registry;
const auto entity = registry.create();
const auto group = registry.group(entt::get<int, const char>);
auto group = registry.group(entt::get<int, const char>, entt::exclude<double, const float>);
static_assert(std::is_same_v<decltype(group.storage<0u>()), entt::storage_type_t<int> &>);
static_assert(std::is_same_v<decltype(group.storage<int>()), entt::storage_type_t<int> &>);
static_assert(std::is_same_v<decltype(group.storage<1u>()), const entt::storage_type_t<char> &>);
static_assert(std::is_same_v<decltype(group.storage<const char>()), const entt::storage_type_t<char> &>);
static_assert(std::is_same_v<decltype(group.storage<0u>()), entt::storage_type_t<int> *>);
static_assert(std::is_same_v<decltype(group.storage<int>()), entt::storage_type_t<int> *>);
static_assert(std::is_same_v<decltype(group.storage<const int>()), entt::storage_type_t<int> *>);
static_assert(std::is_same_v<decltype(group.storage<1u>()), const entt::storage_type_t<char> *>);
static_assert(std::is_same_v<decltype(group.storage<char>()), const entt::storage_type_t<char> *>);
static_assert(std::is_same_v<decltype(group.storage<const char>()), const entt::storage_type_t<char> *>);
static_assert(std::is_same_v<decltype(group.storage<2u>()), entt::storage_type_t<double> *>);
static_assert(std::is_same_v<decltype(group.storage<double>()), entt::storage_type_t<double> *>);
static_assert(std::is_same_v<decltype(group.storage<const double>()), entt::storage_type_t<double> *>);
static_assert(std::is_same_v<decltype(group.storage<3u>()), const entt::storage_type_t<float> *>);
static_assert(std::is_same_v<decltype(group.storage<float>()), const entt::storage_type_t<float> *>);
static_assert(std::is_same_v<decltype(group.storage<const float>()), const entt::storage_type_t<float> *>);
ASSERT_TRUE(group);
ASSERT_NE(group.storage<int>(), nullptr);
ASSERT_NE(group.storage<1u>(), nullptr);
ASSERT_NE(group.storage<double>(), nullptr);
ASSERT_NE(group.storage<3u>(), nullptr);
ASSERT_EQ(group.size(), 0u);
group.storage<int>().emplace(entity);
group.storage<int>()->emplace(entity);
group.storage<double>()->emplace(entity);
registry.emplace<char>(entity);
registry.emplace<float>(entity);
ASSERT_EQ(group.size(), 0u);
ASSERT_EQ(group.begin(), group.end());
ASSERT_TRUE(group.storage<int>()->contains(entity));
ASSERT_TRUE(group.storage<const char>()->contains(entity));
ASSERT_TRUE(group.storage<double>()->contains(entity));
ASSERT_TRUE(group.storage<const float>()->contains(entity));
ASSERT_TRUE((registry.all_of<int, char, double, float>(entity)));
group.storage<double>()->erase(entity);
registry.erase<float>(entity);
ASSERT_EQ(group.size(), 1u);
ASSERT_TRUE(group.storage<int>().contains(entity));
ASSERT_TRUE(group.storage<const char>().contains(entity));
ASSERT_NE(group.begin(), group.end());
ASSERT_TRUE(group.storage<const int>()->contains(entity));
ASSERT_TRUE(group.storage<char>()->contains(entity));
ASSERT_FALSE(group.storage<const double>()->contains(entity));
ASSERT_FALSE(group.storage<float>()->contains(entity));
ASSERT_TRUE((registry.all_of<int, char>(entity)));
ASSERT_FALSE((registry.any_of<double, float>(entity)));
group.storage<0u>().erase(entity);
group.storage<0u>()->erase(entity);
ASSERT_EQ(group.size(), 0u);
ASSERT_TRUE(group.storage<1u>().contains(entity));
ASSERT_FALSE((registry.all_of<int, char>(entity)));
ASSERT_EQ(group.begin(), group.end());
ASSERT_FALSE(group.storage<0u>()->contains(entity));
ASSERT_TRUE(group.storage<1u>()->contains(entity));
ASSERT_FALSE(group.storage<2u>()->contains(entity));
ASSERT_FALSE(group.storage<3u>()->contains(entity));
ASSERT_TRUE((registry.all_of<char>(entity)));
ASSERT_FALSE((registry.any_of<int, double, float>(entity)));
group = {};
ASSERT_FALSE(group);
ASSERT_EQ(group.storage<0u>(), nullptr);
ASSERT_EQ(group.storage<const char>(), nullptr);
ASSERT_EQ(group.storage<2u>(), nullptr);
ASSERT_EQ(group.storage<const float>(), nullptr);
}
TEST(NonOwningGroup, Overlapping) {
entt::registry registry;
auto group = registry.group(entt::get<char>, entt::exclude<double>);
auto other = registry.group<int>(entt::get<char>, entt::exclude<double>);
ASSERT_TRUE(group.empty());
ASSERT_TRUE(other.empty());
const auto entity = registry.create();
registry.emplace<char>(entity, '1');
ASSERT_FALSE(group.empty());
ASSERT_TRUE(other.empty());
registry.emplace<int>(entity, 42);
ASSERT_FALSE(group.empty());
ASSERT_FALSE(other.empty());
registry.emplace<double>(entity, 3.);
ASSERT_TRUE(group.empty());
ASSERT_TRUE(other.empty());
}
TEST(OwningGroup, Functionalities) {
@ -721,16 +806,17 @@ TEST(OwningGroup, Functionalities) {
ASSERT_EQ(group.size(), 1u);
ASSERT_EQ(cgroup.storage<const int>().raw()[0u][0u], 42);
ASSERT_EQ(group.storage<int>().raw()[0u][0u], 42);
ASSERT_EQ(cgroup.storage<const int>()->raw()[0u][0u], 42);
ASSERT_EQ(group.storage<int>()->raw()[0u][0u], 42);
for(auto entity: group) {
ASSERT_EQ(std::get<0>(cgroup.get<const int, const char>(entity)), 42);
ASSERT_EQ(std::get<1>(group.get<int, char>(entity)), '2');
ASSERT_EQ(cgroup.get<const char>(entity), '2');
ASSERT_EQ(cgroup.get<1>(entity), '2');
}
ASSERT_EQ(group.storage<int>().raw()[0u][0u], 42);
ASSERT_EQ(group.handle().data()[0u], e1);
ASSERT_EQ(group.storage<int>()->raw()[0u][0u], 42);
registry.erase<char>(e0);
registry.erase<char>(e1);
@ -748,6 +834,26 @@ TEST(OwningGroup, Functionalities) {
ASSERT_FALSE(invalid);
}
TEST(OwningGroup, Handle) {
entt::registry registry;
const auto entity = registry.create();
auto group = registry.group<int>(entt::get<char>);
auto &&handle = group.handle();
ASSERT_TRUE(handle.empty());
ASSERT_FALSE(handle.contains(entity));
ASSERT_EQ(&handle, &group.handle());
ASSERT_EQ(&handle, group.storage<int>());
registry.emplace<int>(entity);
registry.emplace<char>(entity);
ASSERT_FALSE(handle.empty());
ASSERT_TRUE(handle.contains(entity));
ASSERT_EQ(&handle, &group.handle());
}
TEST(OwningGroup, Invalid) {
entt::registry registry{};
auto group = std::as_const(registry).group_if_exists<const int>(entt::get<const empty_type>);
@ -831,10 +937,10 @@ TEST(OwningGroup, Each) {
auto cgroup = std::as_const(registry).group_if_exists<const int>(entt::get<const char>);
registry.emplace<int>(entity[0u], 0);
registry.emplace<char>(entity[0u], 0);
registry.emplace<char>(entity[0u], static_cast<char>(0));
registry.emplace<int>(entity[1u], 1);
registry.emplace<char>(entity[1u], 1);
registry.emplace<char>(entity[1u], static_cast<char>(1));
auto iterable = group.each();
auto citerable = cgroup.each();
@ -845,16 +951,18 @@ TEST(OwningGroup, Each) {
auto it = iterable.begin();
ASSERT_EQ(it.base(), group.begin());
ASSERT_EQ((it++, ++it), iterable.end());
ASSERT_EQ(it.base(), group.end());
group.each([expected = 1u](auto entt, int &ivalue, char &cvalue) mutable {
ASSERT_EQ(entt::to_integral(entt), expected);
group.each([expected = 1](auto entt, int &ivalue, char &cvalue) mutable {
ASSERT_EQ(static_cast<int>(entt::to_integral(entt)), expected);
ASSERT_EQ(ivalue, expected);
ASSERT_EQ(cvalue, expected);
--expected;
});
cgroup.each([expected = 1u](const int &ivalue, const char &cvalue) mutable {
cgroup.each([expected = 1](const int &ivalue, const char &cvalue) mutable {
ASSERT_EQ(ivalue, expected);
ASSERT_EQ(cvalue, expected);
--expected;
@ -868,8 +976,8 @@ TEST(OwningGroup, Each) {
// do not use iterable, make sure an iterable group works when created from a temporary
for(auto [entt, ivalue, cvalue]: registry.group<int>(entt::get<char>).each()) {
ASSERT_EQ(entt::to_integral(entt), ivalue);
ASSERT_EQ(entt::to_integral(entt), cvalue);
ASSERT_EQ(static_cast<int>(entt::to_integral(entt)), ivalue);
ASSERT_EQ(static_cast<char>(entt::to_integral(entt)), cvalue);
}
}
@ -893,27 +1001,27 @@ TEST(OwningGroup, SortOrdered) {
registry.emplace<boxed_int>(entities[4], 2);
group.sort([&group](const entt::entity lhs, const entt::entity rhs) {
return group.get<boxed_int>(lhs).value < group.get<boxed_int>(rhs).value;
return group.get<boxed_int>(lhs).value < group.get<0>(rhs).value;
});
ASSERT_EQ(group.storage<boxed_int>().data()[0u], entities[0]);
ASSERT_EQ(group.storage<boxed_int>().data()[1u], entities[1]);
ASSERT_EQ(group.storage<boxed_int>().data()[2u], entities[2]);
ASSERT_EQ(group.storage<boxed_int>().data()[3u], entities[3]);
ASSERT_EQ(group.storage<boxed_int>().data()[4u], entities[4]);
ASSERT_EQ(group.handle().data()[0u], entities[0]);
ASSERT_EQ(group.handle().data()[1u], entities[1]);
ASSERT_EQ(group.handle().data()[2u], entities[2]);
ASSERT_EQ(group.handle().data()[3u], entities[3]);
ASSERT_EQ(group.handle().data()[4u], entities[4]);
ASSERT_EQ(group.storage<boxed_int>().raw()[0u][0u].value, 12);
ASSERT_EQ(group.storage<boxed_int>().raw()[0u][1u].value, 9);
ASSERT_EQ(group.storage<boxed_int>().raw()[0u][2u].value, 6);
ASSERT_EQ(group.storage<boxed_int>().raw()[0u][3u].value, 1);
ASSERT_EQ(group.storage<boxed_int>().raw()[0u][4u].value, 2);
ASSERT_EQ(group.storage<boxed_int>()->raw()[0u][0u].value, 12);
ASSERT_EQ(group.storage<boxed_int>()->raw()[0u][1u].value, 9);
ASSERT_EQ(group.storage<boxed_int>()->raw()[0u][2u].value, 6);
ASSERT_EQ(group.storage<boxed_int>()->raw()[0u][3u].value, 1);
ASSERT_EQ(group.storage<boxed_int>()->raw()[0u][4u].value, 2);
ASSERT_EQ(group.storage<char>().raw()[0u][0u], 'a');
ASSERT_EQ(group.storage<char>().raw()[0u][1u], 'b');
ASSERT_EQ(group.storage<char>().raw()[0u][2u], 'c');
ASSERT_EQ(group.storage<char>()->raw()[0u][0u], 'a');
ASSERT_EQ(group.storage<char>()->raw()[0u][1u], 'b');
ASSERT_EQ(group.storage<char>()->raw()[0u][2u], 'c');
ASSERT_EQ((group.get<boxed_int, char>(entities[0])), (std::make_tuple(boxed_int{12}, 'a')));
ASSERT_EQ((group.get<boxed_int, char>(entities[1])), (std::make_tuple(boxed_int{9}, 'b')));
ASSERT_EQ((group.get<0, 1>(entities[1])), (std::make_tuple(boxed_int{9}, 'b')));
ASSERT_EQ((group.get<boxed_int, char>(entities[2])), (std::make_tuple(boxed_int{6}, 'c')));
ASSERT_FALSE(group.contains(entities[3]));
@ -943,24 +1051,24 @@ TEST(OwningGroup, SortReverse) {
return lhs.value < rhs.value;
});
ASSERT_EQ(group.storage<boxed_int>().data()[0u], entities[2]);
ASSERT_EQ(group.storage<boxed_int>().data()[1u], entities[1]);
ASSERT_EQ(group.storage<boxed_int>().data()[2u], entities[0]);
ASSERT_EQ(group.storage<boxed_int>().data()[3u], entities[3]);
ASSERT_EQ(group.storage<boxed_int>().data()[4u], entities[4]);
ASSERT_EQ(group.handle().data()[0u], entities[2]);
ASSERT_EQ(group.handle().data()[1u], entities[1]);
ASSERT_EQ(group.handle().data()[2u], entities[0]);
ASSERT_EQ(group.handle().data()[3u], entities[3]);
ASSERT_EQ(group.handle().data()[4u], entities[4]);
ASSERT_EQ(group.storage<boxed_int>().raw()[0u][0u].value, 12);
ASSERT_EQ(group.storage<boxed_int>().raw()[0u][1u].value, 9);
ASSERT_EQ(group.storage<boxed_int>().raw()[0u][2u].value, 6);
ASSERT_EQ(group.storage<boxed_int>().raw()[0u][3u].value, 1);
ASSERT_EQ(group.storage<boxed_int>().raw()[0u][4u].value, 2);
ASSERT_EQ(group.storage<boxed_int>()->raw()[0u][0u].value, 12);
ASSERT_EQ(group.storage<boxed_int>()->raw()[0u][1u].value, 9);
ASSERT_EQ(group.storage<boxed_int>()->raw()[0u][2u].value, 6);
ASSERT_EQ(group.storage<boxed_int>()->raw()[0u][3u].value, 1);
ASSERT_EQ(group.storage<boxed_int>()->raw()[0u][4u].value, 2);
ASSERT_EQ(group.storage<char>().raw()[0u][0u], 'c');
ASSERT_EQ(group.storage<char>().raw()[0u][1u], 'b');
ASSERT_EQ(group.storage<char>().raw()[0u][2u], 'a');
ASSERT_EQ(group.storage<char>()->raw()[0u][0u], 'c');
ASSERT_EQ(group.storage<char>()->raw()[0u][1u], 'b');
ASSERT_EQ(group.storage<char>()->raw()[0u][2u], 'a');
ASSERT_EQ((group.get<boxed_int, char>(entities[0])), (std::make_tuple(boxed_int{6}, 'a')));
ASSERT_EQ((group.get<boxed_int, char>(entities[1])), (std::make_tuple(boxed_int{9}, 'b')));
ASSERT_EQ((group.get<0, 1>(entities[1])), (std::make_tuple(boxed_int{9}, 'b')));
ASSERT_EQ((group.get<boxed_int, char>(entities[2])), (std::make_tuple(boxed_int{12}, 'c')));
ASSERT_FALSE(group.contains(entities[3]));
@ -998,27 +1106,27 @@ TEST(OwningGroup, SortUnordered) {
return std::get<1>(lhs) < std::get<1>(rhs);
});
ASSERT_EQ(group.storage<boxed_int>().data()[0u], entities[4]);
ASSERT_EQ(group.storage<boxed_int>().data()[1u], entities[3]);
ASSERT_EQ(group.storage<boxed_int>().data()[2u], entities[0]);
ASSERT_EQ(group.storage<boxed_int>().data()[3u], entities[1]);
ASSERT_EQ(group.storage<boxed_int>().data()[4u], entities[2]);
ASSERT_EQ(group.storage<boxed_int>().data()[5u], entities[5]);
ASSERT_EQ(group.storage<boxed_int>().data()[6u], entities[6]);
ASSERT_EQ(group.handle().data()[0u], entities[4]);
ASSERT_EQ(group.handle().data()[1u], entities[3]);
ASSERT_EQ(group.handle().data()[2u], entities[0]);
ASSERT_EQ(group.handle().data()[3u], entities[1]);
ASSERT_EQ(group.handle().data()[4u], entities[2]);
ASSERT_EQ(group.handle().data()[5u], entities[5]);
ASSERT_EQ(group.handle().data()[6u], entities[6]);
ASSERT_EQ(group.storage<boxed_int>().raw()[0u][0u].value, 12);
ASSERT_EQ(group.storage<boxed_int>().raw()[0u][1u].value, 9);
ASSERT_EQ(group.storage<boxed_int>().raw()[0u][2u].value, 6);
ASSERT_EQ(group.storage<boxed_int>().raw()[0u][3u].value, 3);
ASSERT_EQ(group.storage<boxed_int>().raw()[0u][4u].value, 1);
ASSERT_EQ(group.storage<boxed_int>().raw()[0u][5u].value, 4);
ASSERT_EQ(group.storage<boxed_int>().raw()[0u][6u].value, 5);
ASSERT_EQ(group.storage<boxed_int>()->raw()[0u][0u].value, 12);
ASSERT_EQ(group.storage<boxed_int>()->raw()[0u][1u].value, 9);
ASSERT_EQ(group.storage<boxed_int>()->raw()[0u][2u].value, 6);
ASSERT_EQ(group.storage<boxed_int>()->raw()[0u][3u].value, 3);
ASSERT_EQ(group.storage<boxed_int>()->raw()[0u][4u].value, 1);
ASSERT_EQ(group.storage<boxed_int>()->raw()[0u][5u].value, 4);
ASSERT_EQ(group.storage<boxed_int>()->raw()[0u][6u].value, 5);
ASSERT_EQ(group.get<char>(group.storage<boxed_int>().data()[0u]), 'e');
ASSERT_EQ(group.get<char>(group.storage<boxed_int>().data()[1u]), 'd');
ASSERT_EQ(group.get<char>(group.storage<boxed_int>().data()[2u]), 'c');
ASSERT_EQ(group.get<char>(group.storage<boxed_int>().data()[3u]), 'b');
ASSERT_EQ(group.get<char>(group.storage<boxed_int>().data()[4u]), 'a');
ASSERT_EQ(group.get<char>(group.handle().data()[0u]), 'e');
ASSERT_EQ(group.get<1>(group.handle().data()[1u]), 'd');
ASSERT_EQ(group.get<char>(group.handle().data()[2u]), 'c');
ASSERT_EQ(group.get<1>(group.handle().data()[3u]), 'b');
ASSERT_EQ(group.get<char>(group.handle().data()[4u]), 'a');
ASSERT_FALSE(group.contains(entities[5]));
ASSERT_FALSE(group.contains(entities[6]));
@ -1026,7 +1134,7 @@ TEST(OwningGroup, SortUnordered) {
TEST(OwningGroup, SortWithExclusionList) {
entt::registry registry;
auto group = registry.group<boxed_int>({}, entt::exclude<char>);
auto group = registry.group<boxed_int>(entt::get<>, entt::exclude<char>);
entt::entity entities[5]{};
registry.create(std::begin(entities), std::end(entities));
@ -1043,20 +1151,20 @@ TEST(OwningGroup, SortWithExclusionList) {
return lhs < rhs;
});
ASSERT_EQ(group.storage<boxed_int>().data()[0u], entities[4]);
ASSERT_EQ(group.storage<boxed_int>().data()[1u], entities[3]);
ASSERT_EQ(group.storage<boxed_int>().data()[2u], entities[1]);
ASSERT_EQ(group.storage<boxed_int>().data()[3u], entities[0]);
ASSERT_EQ(group.handle().data()[0u], entities[4]);
ASSERT_EQ(group.handle().data()[1u], entities[3]);
ASSERT_EQ(group.handle().data()[2u], entities[1]);
ASSERT_EQ(group.handle().data()[3u], entities[0]);
ASSERT_EQ(group.storage<boxed_int>().raw()[0u][0u].value, 4);
ASSERT_EQ(group.storage<boxed_int>().raw()[0u][1u].value, 3);
ASSERT_EQ(group.storage<boxed_int>().raw()[0u][2u].value, 1);
ASSERT_EQ(group.storage<boxed_int>().raw()[0u][3u].value, 0);
ASSERT_EQ(group.storage<boxed_int>()->raw()[0u][0u].value, 4);
ASSERT_EQ(group.storage<boxed_int>()->raw()[0u][1u].value, 3);
ASSERT_EQ(group.storage<boxed_int>()->raw()[0u][2u].value, 1);
ASSERT_EQ(group.storage<boxed_int>()->raw()[0u][3u].value, 0);
ASSERT_EQ(group.get<boxed_int>(entities[0]).value, 0);
ASSERT_EQ(group.get<boxed_int>(entities[1]).value, 1);
ASSERT_EQ(group.get<0>(entities[1]).value, 1);
ASSERT_EQ(group.get<boxed_int>(entities[3]).value, 3);
ASSERT_EQ(group.get<boxed_int>(entities[4]).value, 4);
ASSERT_EQ(group.get<0>(entities[4]).value, 4);
ASSERT_FALSE(group.contains(entities[2]));
}
@ -1110,11 +1218,24 @@ TEST(OwningGroup, ConstNonConstAndAllInBetween) {
ASSERT_EQ(group.size(), 1u);
static_assert(std::is_same_v<decltype(group.get<0>({})), int &>);
static_assert(std::is_same_v<decltype(group.get<int>({})), int &>);
static_assert(std::is_same_v<decltype(group.get<1>({})), const char &>);
static_assert(std::is_same_v<decltype(group.get<const char>({})), const char &>);
static_assert(std::is_same_v<decltype(group.get<2>({})), void>);
static_assert(std::is_same_v<decltype(group.get<empty_type>({})), void>);
static_assert(std::is_same_v<decltype(group.get<3>({})), double &>);
static_assert(std::is_same_v<decltype(group.get<double>({})), double &>);
static_assert(std::is_same_v<decltype(group.get<4>({})), const float &>);
static_assert(std::is_same_v<decltype(group.get<const float>({})), const float &>);
static_assert(std::is_same_v<decltype(group.get<int, const char, double, const float>({})), std::tuple<int &, const char &, double &, const float &>>);
static_assert(std::is_same_v<decltype(group.get<int, const char, empty_type, double, const float>({})), std::tuple<int &, const char &, double &, const float &>>);
static_assert(std::is_same_v<decltype(group.get<0, 1, 2, 3, 4>({})), std::tuple<int &, const char &, double &, const float &>>);
static_assert(std::is_same_v<decltype(group.get({})), std::tuple<int &, const char &, double &, const float &>>);
static_assert(std::is_same_v<decltype(std::as_const(registry).group_if_exists<int>(entt::get<char>)), decltype(std::as_const(registry).group_if_exists<const int>(entt::get<const char>))>);
@ -1192,7 +1313,7 @@ TEST(OwningGroup, ExcludedComponents) {
registry.emplace<int>(e1, 1);
registry.emplace<char>(e1);
const auto group = registry.group<int>({}, entt::exclude<char, double>);
const auto group = registry.group<int>(entt::get<>, entt::exclude<char, double>);
const auto e2 = registry.create();
registry.emplace<int>(e2, 2);
@ -1207,7 +1328,7 @@ TEST(OwningGroup, ExcludedComponents) {
if(entity == e0) {
ASSERT_EQ(group.get<int>(e0), 0);
} else if(entity == e2) {
ASSERT_EQ(group.get<int>(e2), 2);
ASSERT_EQ(group.get<0>(e2), 2);
}
}
@ -1225,7 +1346,7 @@ TEST(OwningGroup, ExcludedComponents) {
if(entity == e1) {
ASSERT_EQ(group.get<int>(e1), 1);
} else if(entity == e3) {
ASSERT_EQ(group.get<int>(e3), 3);
ASSERT_EQ(group.get<0>(e3), 3);
}
}
}
@ -1263,8 +1384,8 @@ TEST(OwningGroup, EmptyAndNonEmptyTypes) {
TEST(OwningGroup, TrackEntitiesOnComponentDestruction) {
entt::registry registry;
const auto group = registry.group<int>({}, entt::exclude<char>);
const auto cgroup = std::as_const(registry).group_if_exists<const int>({}, entt::exclude<char>);
const auto group = registry.group<int>(entt::get<>, entt::exclude<char>);
const auto cgroup = std::as_const(registry).group_if_exists<const int>(entt::get<>, entt::exclude<char>);
const auto entity = registry.create();
registry.emplace<int>(entity);
@ -1403,7 +1524,7 @@ TEST(OwningGroup, SwappingValuesIsAllowed) {
// thanks to @andranik3949 for pointing out this missing test
registry.view<const boxed_int>().each([](const auto entity, const auto &value) {
ASSERT_EQ(entt::to_integral(entity), value.value);
ASSERT_EQ(static_cast<int>(entt::to_integral(entity)), value.value);
});
}
@ -1443,26 +1564,81 @@ TEST(OwningGroup, IterableGroupAlgorithmCompatibility) {
TEST(OwningGroup, Storage) {
entt::registry registry;
const auto entity = registry.create();
const auto group = registry.group<int>(entt::get<const char>);
auto group = registry.group<int>(entt::get<const char>, entt::exclude<double, const float>);
static_assert(std::is_same_v<decltype(group.storage<0u>()), entt::storage_type_t<int> &>);
static_assert(std::is_same_v<decltype(group.storage<int>()), entt::storage_type_t<int> &>);
static_assert(std::is_same_v<decltype(group.storage<1u>()), const entt::storage_type_t<char> &>);
static_assert(std::is_same_v<decltype(group.storage<const char>()), const entt::storage_type_t<char> &>);
static_assert(std::is_same_v<decltype(group.storage<0u>()), entt::storage_type_t<int> *>);
static_assert(std::is_same_v<decltype(group.storage<int>()), entt::storage_type_t<int> *>);
static_assert(std::is_same_v<decltype(group.storage<const int>()), entt::storage_type_t<int> *>);
static_assert(std::is_same_v<decltype(group.storage<1u>()), const entt::storage_type_t<char> *>);
static_assert(std::is_same_v<decltype(group.storage<char>()), const entt::storage_type_t<char> *>);
static_assert(std::is_same_v<decltype(group.storage<const char>()), const entt::storage_type_t<char> *>);
static_assert(std::is_same_v<decltype(group.storage<2u>()), entt::storage_type_t<double> *>);
static_assert(std::is_same_v<decltype(group.storage<double>()), entt::storage_type_t<double> *>);
static_assert(std::is_same_v<decltype(group.storage<const double>()), entt::storage_type_t<double> *>);
static_assert(std::is_same_v<decltype(group.storage<3u>()), const entt::storage_type_t<float> *>);
static_assert(std::is_same_v<decltype(group.storage<float>()), const entt::storage_type_t<float> *>);
static_assert(std::is_same_v<decltype(group.storage<const float>()), const entt::storage_type_t<float> *>);
ASSERT_TRUE(group);
ASSERT_NE(group.storage<int>(), nullptr);
ASSERT_NE(group.storage<1u>(), nullptr);
ASSERT_NE(group.storage<double>(), nullptr);
ASSERT_NE(group.storage<3u>(), nullptr);
ASSERT_EQ(group.size(), 0u);
group.storage<int>().emplace(entity);
group.storage<int>()->emplace(entity);
group.storage<double>()->emplace(entity);
registry.emplace<char>(entity);
registry.emplace<float>(entity);
ASSERT_EQ(group.size(), 0u);
ASSERT_EQ(group.begin(), group.end());
ASSERT_TRUE(group.storage<int>()->contains(entity));
ASSERT_TRUE(group.storage<const char>()->contains(entity));
ASSERT_TRUE(group.storage<double>()->contains(entity));
ASSERT_TRUE(group.storage<const float>()->contains(entity));
ASSERT_TRUE((registry.all_of<int, char, double, float>(entity)));
group.storage<double>()->erase(entity);
registry.erase<float>(entity);
ASSERT_EQ(group.size(), 1u);
ASSERT_TRUE(group.storage<int>().contains(entity));
ASSERT_TRUE(group.storage<const char>().contains(entity));
ASSERT_NE(group.begin(), group.end());
ASSERT_TRUE(group.storage<const int>()->contains(entity));
ASSERT_TRUE(group.storage<char>()->contains(entity));
ASSERT_FALSE(group.storage<const double>()->contains(entity));
ASSERT_FALSE(group.storage<float>()->contains(entity));
ASSERT_TRUE((registry.all_of<int, char>(entity)));
ASSERT_FALSE((registry.any_of<double, float>(entity)));
group.storage<0u>().erase(entity);
group.storage<0u>()->erase(entity);
ASSERT_EQ(group.size(), 0u);
ASSERT_TRUE(group.storage<1u>().contains(entity));
ASSERT_FALSE((registry.all_of<int, char>(entity)));
ASSERT_EQ(group.begin(), group.end());
ASSERT_FALSE(group.storage<0u>()->contains(entity));
ASSERT_TRUE(group.storage<1u>()->contains(entity));
ASSERT_FALSE(group.storage<2u>()->contains(entity));
ASSERT_FALSE(group.storage<3u>()->contains(entity));
ASSERT_TRUE((registry.all_of<char>(entity)));
ASSERT_FALSE((registry.any_of<int, double, float>(entity)));
group = {};
ASSERT_FALSE(group);
ASSERT_EQ(group.storage<0u>(), nullptr);
ASSERT_EQ(group.storage<const char>(), nullptr);
ASSERT_EQ(group.storage<2u>(), nullptr);
ASSERT_EQ(group.storage<const float>(), nullptr);
}
ENTT_DEBUG_TEST(OwningGroupDeathTest, Overlapping) {
entt::registry registry;
registry.group<char>(entt::get<int>, entt::exclude<double>);
ASSERT_DEATH((registry.group<char, float>(entt::get<float>, entt::exclude<double>)), "");
ASSERT_DEATH(registry.group<char>(entt::get<int, float>, entt::exclude<double>), "");
ASSERT_DEATH(registry.group<char>(entt::get<int>, entt::exclude<double, float>), "");
}

View File

@ -83,8 +83,8 @@ TEST(BasicHandle, Destruction) {
ASSERT_FALSE(handle);
ASSERT_FALSE(handle.valid());
ASSERT_NE(handle.registry(), nullptr);
ASSERT_EQ(handle.entity(), entity);
ASSERT_EQ(registry.current(entity), typename entt::registry::version_type{});
ASSERT_EQ(handle.entity(), entt::entity{entt::null});
handle = entt::handle{registry, registry.create()};
@ -98,8 +98,8 @@ TEST(BasicHandle, Destruction) {
ASSERT_FALSE(handle);
ASSERT_FALSE(handle.valid());
ASSERT_NE(handle.registry(), nullptr);
ASSERT_EQ(handle.entity(), entity);
ASSERT_NE(registry.current(entity), typename entt::registry::version_type{});
ASSERT_EQ(handle.entity(), entt::entity{entt::null});
}
TEST(BasicHandle, Comparison) {
@ -275,6 +275,8 @@ TEST(BasicHandle, HandleStorageIterator) {
registry.emplace<int>(entity);
registry.emplace<double>(entity);
// required to test the find-first initialization step
registry.storage<entt::entity>().erase(entity);
auto test = [](auto iterable) {
auto end{iterable.begin()};
@ -290,6 +292,13 @@ TEST(BasicHandle, HandleStorageIterator) {
ASSERT_EQ(++begin, iterable.end());
};
test(entt::handle{registry, entity}.storage());
test(entt::const_handle{std::as_const(registry), entity}.storage());
const auto handle = entt::handle{registry, entity};
const auto chandle = entt::const_handle{std::as_const(registry), entity};
ASSERT_FALSE(registry.valid(entity));
ASSERT_FALSE(handle);
ASSERT_FALSE(chandle);
test(handle.storage());
test(chandle.storage());
}

View File

@ -16,6 +16,10 @@ struct stable_type {
int value;
};
void sigh_callback(int &value) {
++value;
}
TEST(Helper, AsView) {
entt::registry registry;
const entt::registry cregistry;
@ -48,7 +52,7 @@ TEST(Helper, Invoke) {
TEST(Helper, ToEntity) {
entt::registry registry;
const entt::entity null = entt::null;
constexpr auto page_size = entt::component_traits<int>::page_size;
constexpr auto page_size = entt::storage_type_t<int>::traits_type::page_size;
const int value = 42;
ASSERT_EQ(entt::to_entity(registry, 42), null);
@ -88,7 +92,7 @@ TEST(Helper, ToEntity) {
TEST(Helper, ToEntityStableType) {
entt::registry registry;
const entt::entity null = entt::null;
constexpr auto page_size = entt::component_traits<stable_type>::page_size;
constexpr auto page_size = entt::storage_type_t<stable_type>::traits_type::page_size;
const stable_type value{42};
ASSERT_EQ(entt::to_entity(registry, stable_type{42}), null);
@ -124,3 +128,44 @@ TEST(Helper, ToEntityStableType) {
ASSERT_EQ(entt::to_entity(registry, stable_type{42}), null);
ASSERT_EQ(entt::to_entity(registry, value), null);
}
TEST(Helper, SighHelper) {
using namespace entt::literals;
entt::registry registry{};
const auto entt = registry.create();
entt::sigh_helper helper{registry};
int counter{};
ASSERT_EQ(&helper.registry(), &registry);
helper.with<int>()
.on_construct<&sigh_callback>(counter)
.on_update<&sigh_callback>(counter)
.on_destroy<&sigh_callback>(counter);
ASSERT_EQ(counter, 0);
registry.emplace<int>(entt);
registry.replace<int>(entt);
registry.erase<int>(entt);
ASSERT_EQ(counter, 3);
helper.with<double>("other"_hs)
.on_construct<&sigh_callback>(counter)
.on_update<&sigh_callback>(counter)
.on_destroy<&sigh_callback>(counter);
registry.emplace<double>(entt);
registry.replace<double>(entt);
registry.erase<double>(entt);
ASSERT_EQ(counter, 3);
registry.storage<double>("other"_hs).emplace(entt);
registry.storage<double>("other"_hs).patch(entt);
registry.storage<double>("other"_hs).erase(entt);
ASSERT_EQ(counter, 6);
}

View File

@ -1,5 +1,7 @@
#include <cstddef>
#include <utility>
#include <gtest/gtest.h>
#include <entt/core/type_info.hpp>
#include <entt/entity/organizer.hpp>
#include <entt/entity/registry.hpp>
@ -20,7 +22,7 @@ struct clazz {
static void ro_int_char_with_payload(clazz &, entt::view<entt::get_t<const int, const char>>) {}
};
void to_args_integrity(entt::view<entt::get_t<int>> view, std::size_t &value, entt::registry &registry) {
void to_args_integrity(entt::view<entt::get_t<int>> view, std::size_t &value, entt::registry &) {
value = view.size();
}
@ -363,6 +365,10 @@ TEST(Organizer, Prepare) {
ASSERT_FALSE(registry.ctx().contains<char>());
ASSERT_FALSE(registry.ctx().contains<double>());
ASSERT_EQ(std::as_const(registry).storage<int>(), nullptr);
ASSERT_EQ(std::as_const(registry).storage<char>(), nullptr);
ASSERT_EQ(std::as_const(registry).storage<double>(), nullptr);
for(auto &&vertex: graph) {
vertex.prepare(registry);
}
@ -370,6 +376,10 @@ TEST(Organizer, Prepare) {
ASSERT_FALSE(registry.ctx().contains<int>());
ASSERT_FALSE(registry.ctx().contains<char>());
ASSERT_TRUE(registry.ctx().contains<double>());
ASSERT_NE(std::as_const(registry).storage<int>(), nullptr);
ASSERT_NE(std::as_const(registry).storage<char>(), nullptr);
ASSERT_EQ(std::as_const(registry).storage<double>(), nullptr);
}
TEST(Organizer, Dependencies) {
@ -428,5 +438,5 @@ TEST(Organizer, ToArgsIntegrity) {
auto graph = organizer.graph();
graph[0u].callback()(graph[0u].data(), registry);
ASSERT_EQ(registry.ctx().at<std::size_t>(), 0u);
ASSERT_EQ(registry.ctx().get<std::size_t>(), 0u);
}

View File

@ -40,18 +40,16 @@ struct aggregate {
};
struct listener {
template<typename Component>
template<typename Type>
static void sort(entt::registry &registry) {
registry.sort<Component>([](auto lhs, auto rhs) { return lhs < rhs; });
registry.sort<Type>([](auto lhs, auto rhs) { return lhs < rhs; });
}
template<typename Component>
void incr(const entt::registry &, entt::entity entity) {
last = entity;
++counter;
}
template<typename Component>
void decr(const entt::registry &, entt::entity entity) {
last = entity;
--counter;
@ -75,11 +73,11 @@ struct destruction_order {
destruction_order(const entt::registry &ref, bool &ctx)
: registry{&ref},
ctx_check{&ctx} {
*ctx_check = (registry->ctx().find<int>() != nullptr);
*ctx_check = (registry->ctx().find<ctx_check_type>() != nullptr);
}
~destruction_order() {
*ctx_check = *ctx_check && (registry->ctx().find<int>() != nullptr);
*ctx_check = *ctx_check && (registry->ctx().find<ctx_check_type>() != nullptr);
}
private:
@ -87,6 +85,22 @@ private:
bool *ctx_check{};
};
enum class small_entity : std::uint32_t {};
struct small_entity_traits {
using value_type = small_entity;
using entity_type = uint32_t;
using version_type = uint16_t;
static constexpr entity_type entity_mask = 0xFF;
static constexpr entity_type version_mask = 0x00;
};
template<>
struct entt::entt_traits<small_entity>: entt::basic_entt_traits<small_entity_traits> {
using base_type = entt::basic_entt_traits<small_entity_traits>;
static constexpr auto page_size = ENTT_SPARSE_PAGE;
};
TEST(Registry, Context) {
entt::registry registry;
auto &ctx = registry.ctx();
@ -126,8 +140,8 @@ TEST(Registry, Context) {
ASSERT_EQ(ctx.emplace<const int>(0), 42);
ASSERT_EQ(ctx.find<const int>(), cctx.find<int>());
ASSERT_EQ(ctx.at<int>(), cctx.at<const int>());
ASSERT_EQ(ctx.at<int>(), 42);
ASSERT_EQ(ctx.get<int>(), cctx.get<const int>());
ASSERT_EQ(ctx.get<int>(), 42);
ASSERT_EQ(ctx.find<double>(), nullptr);
ASSERT_EQ(cctx.find<double>(), nullptr);
@ -139,8 +153,8 @@ TEST(Registry, Context) {
ASSERT_EQ(ctx.insert_or_assign<const int>(0), 0);
ASSERT_EQ(ctx.find<const int>(), cctx.find<int>());
ASSERT_EQ(ctx.at<int>(), cctx.at<const int>());
ASSERT_EQ(ctx.at<int>(), 0);
ASSERT_EQ(ctx.get<int>(), cctx.get<const int>());
ASSERT_EQ(ctx.get<int>(), 0);
}
TEST(Registry, ContextHint) {
@ -376,13 +390,12 @@ TEST(Registry, Functionalities) {
TEST(Registry, Constructors) {
entt::registry registry;
entt::registry other{42};
const entt::entity entity = entt::tombstone;
ASSERT_TRUE(registry.empty());
ASSERT_TRUE(other.empty());
ASSERT_EQ(registry.released(), entity);
ASSERT_EQ(other.released(), entity);
ASSERT_EQ(registry.released(), 0u);
ASSERT_EQ(other.released(), 0u);
}
TEST(Registry, Move) {
@ -486,6 +499,8 @@ TEST(Registry, Identifiers) {
}
TEST(Registry, Data) {
using traits_type = entt::entt_traits<entt::entity>;
entt::registry registry;
ASSERT_EQ(std::as_const(registry).data(), nullptr);
@ -497,8 +512,8 @@ TEST(Registry, Data) {
const auto other = registry.create();
registry.release(entity);
ASSERT_NE(*std::as_const(registry).data(), entity);
ASSERT_EQ(*(std::as_const(registry).data() + 1u), other);
ASSERT_EQ(*std::as_const(registry).data(), other);
ASSERT_EQ(*(std::as_const(registry).data() + 1u), traits_type::next(entity));
}
TEST(Registry, CreateManyEntitiesAtOnce) {
@ -533,7 +548,7 @@ TEST(Registry, CreateManyEntitiesAtOnceWithListener) {
entt::entity entities[3];
listener listener;
registry.on_construct<int>().connect<&listener::incr<int>>(listener);
registry.on_construct<int>().connect<&listener::incr>(listener);
registry.create(std::begin(entities), std::end(entities));
registry.insert(std::begin(entities), std::end(entities), 42);
registry.insert(std::begin(entities), std::end(entities), 'c');
@ -542,8 +557,8 @@ TEST(Registry, CreateManyEntitiesAtOnceWithListener) {
ASSERT_EQ(registry.get<char>(entities[1]), 'c');
ASSERT_EQ(listener.counter, 3);
registry.on_construct<int>().disconnect<&listener::incr<int>>(listener);
registry.on_construct<empty_type>().connect<&listener::incr<empty_type>>(listener);
registry.on_construct<int>().disconnect<&listener::incr>(listener);
registry.on_construct<empty_type>().connect<&listener::incr>(listener);
registry.create(std::begin(entities), std::end(entities));
registry.insert(std::begin(entities), std::end(entities), 'a');
registry.insert<empty_type>(std::begin(entities), std::end(entities));
@ -560,8 +575,9 @@ TEST(Registry, CreateWithHint) {
auto e3 = registry.create(entt::entity{3});
auto e2 = registry.create(entt::entity{3});
ASSERT_EQ(e2, entt::entity{2});
ASSERT_FALSE(registry.valid(entt::entity{1}));
ASSERT_EQ(e2, entt::entity{1});
ASSERT_FALSE(registry.valid(entt::entity{0}));
ASSERT_FALSE(registry.valid(entt::entity{2}));
ASSERT_EQ(e3, entt::entity{3});
registry.release(e2);
@ -572,10 +588,10 @@ TEST(Registry, CreateWithHint) {
e2 = registry.create();
auto e1 = registry.create(entt::entity{2});
ASSERT_EQ(traits_type::to_entity(e2), 2u);
ASSERT_EQ(traits_type::to_entity(e2), 1u);
ASSERT_EQ(traits_type::to_version(e2), 1u);
ASSERT_EQ(traits_type::to_entity(e1), 1u);
ASSERT_EQ(traits_type::to_entity(e1), 2u);
ASSERT_EQ(traits_type::to_version(e1), 0u);
registry.release(e1);
@ -640,6 +656,14 @@ TEST(Registry, CreateDestroyReleaseCornerCase) {
ASSERT_EQ(registry.current(e1), 1u);
}
ENTT_DEBUG_TEST(RegistryDeathTest, CreateTooManyEntities) {
entt::basic_registry<small_entity> registry;
std::vector<small_entity> entities(entt::entt_traits<small_entity>::to_entity(entt::null));
registry.create(entities.begin(), entities.end());
ASSERT_DEATH([[maybe_unused]] const auto entity = registry.create(), "");
}
TEST(Registry, DestroyVersion) {
entt::registry registry;
@ -666,7 +690,7 @@ ENTT_DEBUG_TEST(RegistryDeathTest, DestroyVersion) {
ASSERT_DEATH(registry.destroy(entity, 3), "");
}
TEST(Registry, RangeDestroy) {
TEST(Registry, DestroyRange) {
entt::registry registry;
const auto iview = registry.view<int>();
const auto icview = registry.view<int, char>();
@ -722,6 +746,24 @@ TEST(Registry, RangeDestroy) {
ASSERT_FALSE(registry.valid(entities[1u]));
ASSERT_FALSE(registry.valid(entities[2u]));
ASSERT_EQ(registry.storage<int>().size(), 0u);
entt::sparse_set managed{};
registry.create(std::begin(entities), std::end(entities));
managed.push(std::begin(entities), std::end(entities));
registry.insert<int>(managed.begin(), managed.end());
ASSERT_TRUE(registry.valid(managed[0u]));
ASSERT_TRUE(registry.valid(managed[1u]));
ASSERT_TRUE(registry.valid(managed[2u]));
ASSERT_EQ(registry.storage<int>().size(), 3u);
registry.destroy(managed.begin(), managed.end());
ASSERT_FALSE(registry.valid(managed[0u]));
ASSERT_FALSE(registry.valid(managed[1u]));
ASSERT_FALSE(registry.valid(managed[2u]));
ASSERT_EQ(registry.storage<int>().size(), 0u);
}
TEST(Registry, StableDestroy) {
@ -792,7 +834,7 @@ ENTT_DEBUG_TEST(RegistryDeathTest, ReleaseVersion) {
ASSERT_DEATH(registry.release(entity, 3), "");
}
TEST(Registry, RangeRelease) {
TEST(Registry, ReleaseRange) {
entt::registry registry;
entt::entity entities[3u];
@ -930,10 +972,12 @@ TEST(Registry, Orphans) {
TEST(Registry, View) {
entt::registry registry;
auto mview = registry.view<int, char>();
entt::entity entities[3u];
auto iview = registry.view<int>();
auto cview = registry.view<char>();
entt::entity entities[3u];
auto mview = registry.view<int, char>();
auto fview = registry.view<int>(entt::exclude<char>);
registry.create(std::begin(entities), std::end(entities));
@ -948,10 +992,55 @@ TEST(Registry, View) {
ASSERT_EQ(iview.size(), 3u);
ASSERT_EQ(cview.size(), 2u);
std::size_t cnt{};
mview.each([&cnt](auto...) { ++cnt; });
ASSERT_EQ(mview.size_hint(), 3u);
ASSERT_EQ(fview.size_hint(), 3u);
ASSERT_EQ(cnt, 2u);
mview.refresh();
fview.refresh();
ASSERT_EQ(mview.size_hint(), 2u);
ASSERT_EQ(fview.size_hint(), 3u);
ASSERT_NE(mview.begin(), mview.end());
ASSERT_NE(fview.begin(), fview.end());
ASSERT_EQ(std::distance(mview.begin(), mview.end()), 2);
ASSERT_EQ(std::distance(fview.begin(), fview.end()), 1);
mview.each([&entities, first = true](auto entity, auto &&...) mutable {
ASSERT_EQ(entity, entities[2u * first]);
first = false;
});
fview.each([&entities](auto entity, auto &&...) {
ASSERT_EQ(entity, entities[1u]);
});
}
TEST(Registry, ExcludeOnlyView) {
entt::registry registry;
entt::entity entities[4u];
auto view = registry.view<entt::entity>(entt::exclude<int>);
registry.create(std::begin(entities), std::end(entities));
registry.emplace<int>(entities[0u], 0);
registry.emplace<int>(entities[2u], 0);
registry.emplace<int>(entities[3u], 0);
registry.destroy(entities[3u]);
ASSERT_EQ(view.size_hint(), 4u);
ASSERT_NE(view.begin(), view.end());
// returns all matching identifiers, both in-use and available ones
ASSERT_EQ(std::distance(view.begin(), view.end()), 2);
// skips available identifiers automatically, only returns in-use elements
view.each([&entities](auto entity, auto &&...) {
ASSERT_EQ(entity, entities[1u]);
});
}
TEST(Registry, NonOwningGroupInitOnFirstUse) {
@ -964,7 +1053,7 @@ TEST(Registry, NonOwningGroupInitOnFirstUse) {
registry.emplace<char>(entities[2u], 'c');
std::size_t cnt{};
auto group = registry.group<>(entt::get<int, char>);
auto group = registry.group(entt::get<int, char>);
group.each([&cnt](auto...) { ++cnt; });
ASSERT_FALSE((registry.owned<int, char>()));
@ -974,7 +1063,7 @@ TEST(Registry, NonOwningGroupInitOnFirstUse) {
TEST(Registry, NonOwningGroupInitOnEmplace) {
entt::registry registry;
entt::entity entities[3u];
auto group = registry.group<>(entt::get<int, char>);
auto group = registry.group(entt::get<int, char>);
registry.create(std::begin(entities), std::end(entities));
registry.insert<int>(std::begin(entities), std::end(entities), 0);
@ -1097,7 +1186,7 @@ TEST(Registry, CleanViewAfterRemoveAndClear) {
TEST(Registry, CleanNonOwningGroupViewAfterRemoveAndClear) {
entt::registry registry;
auto group = registry.group<>(entt::get<int, char>);
auto group = registry.group(entt::get<int, char>);
const auto entity = registry.create();
registry.emplace<int>(entity, 0);
@ -1188,107 +1277,21 @@ TEST(Registry, CleanPartialOwningGroupViewAfterRemoveAndClear) {
ASSERT_EQ(group.size(), 0u);
}
TEST(Registry, NestedGroups) {
ENTT_DEBUG_TEST(RegistryDeathTest, NestedGroups) {
entt::registry registry;
entt::entity entities[10];
registry.group<int, double>(entt::get<char>);
registry.create(std::begin(entities), std::end(entities));
registry.insert<int>(std::begin(entities), std::end(entities));
registry.insert<char>(std::begin(entities), std::end(entities));
const auto g1 = registry.group<int>(entt::get<char>, entt::exclude<double>);
ASSERT_DEATH(registry.group<int>(entt::get<char>), "");
ASSERT_DEATH(registry.group<int>(entt::get<char, double>), "");
ASSERT_DEATH(registry.group<int>(entt::get<char>, entt::exclude<double>), "");
ASSERT_DEATH((registry.group<int, double>()), "");
}
ASSERT_TRUE(registry.sortable(g1));
ASSERT_EQ(g1.size(), 10u);
ENTT_DEBUG_TEST(RegistryDeathTest, ConflictingGroups) {
entt::registry registry;
const auto g2 = registry.group<int>(entt::get<char>);
ASSERT_TRUE(registry.sortable(g1));
ASSERT_FALSE(registry.sortable(g2));
ASSERT_EQ(g1.size(), 10u);
ASSERT_EQ(g2.size(), 10u);
for(auto i = 0u; i < 5u; ++i) {
ASSERT_TRUE(g1.contains(entities[i * 2 + 1]));
ASSERT_TRUE(g1.contains(entities[i * 2]));
ASSERT_TRUE(g2.contains(entities[i * 2 + 1]));
ASSERT_TRUE(g2.contains(entities[i * 2]));
registry.emplace<double>(entities[i * 2]);
}
ASSERT_EQ(g1.size(), 5u);
ASSERT_EQ(g2.size(), 10u);
for(auto i = 0u; i < 5u; ++i) {
ASSERT_TRUE(g1.contains(entities[i * 2 + 1]));
ASSERT_FALSE(g1.contains(entities[i * 2]));
ASSERT_TRUE(g2.contains(entities[i * 2 + 1]));
ASSERT_TRUE(g2.contains(entities[i * 2]));
registry.erase<int>(entities[i * 2 + 1]);
}
ASSERT_EQ(g1.size(), 0u);
ASSERT_EQ(g2.size(), 5u);
const auto g3 = registry.group<int, float>(entt::get<char>, entt::exclude<double>);
ASSERT_FALSE(registry.sortable(g1));
ASSERT_FALSE(registry.sortable(g2));
ASSERT_TRUE(registry.sortable(g3));
ASSERT_EQ(g1.size(), 0u);
ASSERT_EQ(g2.size(), 5u);
ASSERT_EQ(g3.size(), 0u);
for(auto i = 0u; i < 5u; ++i) {
ASSERT_FALSE(g1.contains(entities[i * 2 + 1]));
ASSERT_FALSE(g1.contains(entities[i * 2]));
ASSERT_FALSE(g2.contains(entities[i * 2 + 1]));
ASSERT_TRUE(g2.contains(entities[i * 2]));
ASSERT_FALSE(g3.contains(entities[i * 2 + 1]));
ASSERT_FALSE(g3.contains(entities[i * 2]));
registry.emplace<int>(entities[i * 2 + 1]);
}
ASSERT_EQ(g1.size(), 5u);
ASSERT_EQ(g2.size(), 10u);
ASSERT_EQ(g3.size(), 0u);
for(auto i = 0u; i < 5u; ++i) {
ASSERT_TRUE(g1.contains(entities[i * 2 + 1]));
ASSERT_FALSE(g1.contains(entities[i * 2]));
ASSERT_TRUE(g2.contains(entities[i * 2 + 1]));
ASSERT_TRUE(g2.contains(entities[i * 2]));
ASSERT_FALSE(g3.contains(entities[i * 2 + 1]));
ASSERT_FALSE(g3.contains(entities[i * 2]));
registry.emplace<float>(entities[i * 2]);
}
ASSERT_EQ(g1.size(), 5u);
ASSERT_EQ(g2.size(), 10u);
ASSERT_EQ(g3.size(), 0u);
for(auto i = 0u; i < 5u; ++i) {
registry.erase<double>(entities[i * 2]);
}
ASSERT_EQ(g1.size(), 10u);
ASSERT_EQ(g2.size(), 10u);
ASSERT_EQ(g3.size(), 5u);
for(auto i = 0u; i < 5u; ++i) {
ASSERT_TRUE(g1.contains(entities[i * 2 + 1]));
ASSERT_TRUE(g1.contains(entities[i * 2]));
ASSERT_TRUE(g2.contains(entities[i * 2 + 1]));
ASSERT_TRUE(g2.contains(entities[i * 2]));
ASSERT_FALSE(g3.contains(entities[i * 2 + 1]));
ASSERT_TRUE(g3.contains(entities[i * 2]));
registry.erase<int>(entities[i * 2 + 1]);
registry.erase<int>(entities[i * 2]);
}
ASSERT_EQ(g1.size(), 0u);
ASSERT_EQ(g2.size(), 0u);
ASSERT_EQ(g3.size(), 0u);
registry.group<char>(entt::get<int>, entt::exclude<double>);
ASSERT_DEATH(registry.group<char>(entt::get<float>, entt::exclude<double>), "");
}
TEST(Registry, SortSingle) {
@ -1379,10 +1382,10 @@ TEST(Registry, Signals) {
entt::entity entities[2u];
listener listener;
registry.on_construct<empty_type>().connect<&listener::incr<empty_type>>(listener);
registry.on_destroy<empty_type>().connect<&listener::decr<empty_type>>(listener);
registry.on_construct<int>().connect<&listener::incr<int>>(listener);
registry.on_destroy<int>().connect<&listener::decr<int>>(listener);
registry.on_construct<empty_type>().connect<&listener::incr>(listener);
registry.on_destroy<empty_type>().connect<&listener::decr>(listener);
registry.on_construct<int>().connect<&listener::incr>(listener);
registry.on_destroy<int>().connect<&listener::decr>(listener);
registry.create(std::begin(entities), std::end(entities));
registry.insert<empty_type>(std::begin(entities), std::end(entities));
@ -1400,16 +1403,16 @@ TEST(Registry, Signals) {
ASSERT_EQ(listener.counter, 2);
ASSERT_EQ(listener.last, entities[0u]);
registry.on_destroy<empty_type>().disconnect<&listener::decr<empty_type>>(listener);
registry.on_destroy<int>().disconnect<&listener::decr<int>>(listener);
registry.on_destroy<empty_type>().disconnect<&listener::decr>(listener);
registry.on_destroy<int>().disconnect<&listener::decr>(listener);
registry.erase<empty_type, int>(entities[1u]);
ASSERT_EQ(listener.counter, 2);
ASSERT_EQ(listener.last, entities[0u]);
registry.on_construct<empty_type>().disconnect<&listener::incr<empty_type>>(listener);
registry.on_construct<int>().disconnect<&listener::incr<int>>(listener);
registry.on_construct<empty_type>().disconnect<&listener::incr>(listener);
registry.on_construct<int>().disconnect<&listener::incr>(listener);
registry.emplace<empty_type>(entities[1u]);
registry.emplace<int>(entities[1u]);
@ -1417,8 +1420,8 @@ TEST(Registry, Signals) {
ASSERT_EQ(listener.counter, 2);
ASSERT_EQ(listener.last, entities[0u]);
registry.on_construct<int>().connect<&listener::incr<int>>(listener);
registry.on_destroy<int>().connect<&listener::decr<int>>(listener);
registry.on_construct<int>().connect<&listener::incr>(listener);
registry.on_destroy<int>().connect<&listener::decr>(listener);
registry.emplace<int>(entities[0u]);
registry.erase<int>(entities[1u]);
@ -1426,8 +1429,8 @@ TEST(Registry, Signals) {
ASSERT_EQ(listener.counter, 2);
ASSERT_EQ(listener.last, entities[1u]);
registry.on_construct<empty_type>().connect<&listener::incr<empty_type>>(listener);
registry.on_destroy<empty_type>().connect<&listener::decr<empty_type>>(listener);
registry.on_construct<empty_type>().connect<&listener::incr>(listener);
registry.on_destroy<empty_type>().connect<&listener::decr>(listener);
registry.erase<empty_type>(entities[1u]);
registry.emplace<empty_type>(entities[0u]);
@ -1454,8 +1457,8 @@ TEST(Registry, Signals) {
ASSERT_EQ(listener.counter, 2);
ASSERT_EQ(listener.last, entities[0u]);
registry.on_destroy<empty_type>().disconnect<&listener::decr<empty_type>>(listener);
registry.on_destroy<int>().disconnect<&listener::decr<int>>(listener);
registry.on_destroy<empty_type>().disconnect<&listener::decr>(listener);
registry.on_destroy<int>().disconnect<&listener::decr>(listener);
registry.emplace_or_replace<empty_type>(entities[0u]);
registry.emplace_or_replace<int>(entities[0u]);
@ -1463,8 +1466,8 @@ TEST(Registry, Signals) {
ASSERT_EQ(listener.counter, 2);
ASSERT_EQ(listener.last, entities[0u]);
registry.on_update<empty_type>().connect<&listener::incr<empty_type>>(listener);
registry.on_update<int>().connect<&listener::incr<int>>(listener);
registry.on_update<empty_type>().connect<&listener::incr>(listener);
registry.on_update<int>().connect<&listener::incr>(listener);
registry.emplace_or_replace<empty_type>(entities[0u]);
registry.emplace_or_replace<int>(entities[0u]);
@ -1479,6 +1482,84 @@ TEST(Registry, Signals) {
ASSERT_EQ(listener.last, entities[0u]);
}
TEST(Registry, SignalsOnRuntimePool) {
using namespace entt::literals;
entt::registry registry;
const auto entity = registry.create();
listener listener;
registry.on_construct<int>("custom"_hs).connect<&listener::incr>(listener);
registry.on_update<int>("custom"_hs).connect<&listener::incr>(listener);
registry.on_destroy<int>("custom"_hs).connect<&listener::incr>(listener);
ASSERT_EQ(listener.counter, 0);
registry.emplace<int>(entity);
registry.patch<int>(entity);
registry.erase<int>(entity);
ASSERT_EQ(listener.counter, 0);
registry.storage<int>("custom"_hs).emplace(entity);
registry.storage<int>("custom"_hs).patch(entity);
registry.storage<int>("custom"_hs).erase(entity);
ASSERT_EQ(listener.counter, 3);
}
TEST(Registry, SignalsOnEntity) {
entt::registry registry;
listener listener;
registry.on_construct<entt::entity>().connect<&listener::incr>(listener);
entt::entity entity = registry.create();
entt::entity other = registry.create();
ASSERT_EQ(listener.counter, 2);
ASSERT_EQ(listener.last, other);
registry.destroy(other);
registry.destroy(entity);
ASSERT_EQ(listener.counter, 2);
ASSERT_EQ(listener.last, other);
registry.on_construct<entt::entity>().disconnect(&listener);
other = registry.create();
entity = registry.create();
ASSERT_EQ(listener.counter, 2);
ASSERT_NE(listener.last, entity);
ASSERT_NE(listener.last, other);
registry.on_update<entt::entity>().connect<&listener::decr>(listener);
registry.patch<entt::entity>(entity);
ASSERT_EQ(listener.counter, 1);
ASSERT_EQ(listener.last, entity);
registry.on_update<entt::entity>().disconnect(&listener);
registry.patch<entt::entity>(other);
ASSERT_EQ(listener.counter, 1);
ASSERT_NE(listener.last, other);
registry.on_destroy<entt::entity>().connect<&listener::decr>(listener);
registry.destroy(entity);
ASSERT_EQ(listener.counter, 0);
ASSERT_EQ(listener.last, entity);
registry.on_destroy<entt::entity>().disconnect(&listener);
registry.destroy(other);
ASSERT_EQ(listener.counter, 0);
ASSERT_NE(listener.last, other);
}
TEST(Registry, SignalWhenDestroying) {
entt::registry registry;
const auto entity = registry.create();
@ -1576,6 +1657,17 @@ TEST(Registry, Erase) {
ASSERT_EQ(registry.storage<char>().size(), 0u);
ASSERT_EQ(registry.storage<double>().size(), 1u);
registry.insert<int>(std::begin(entities) + 1, std::end(entities) - 1u);
registry.insert<char>(std::begin(entities) + 1, std::end(entities) - 1u);
ASSERT_EQ(registry.storage<int>().size(), 1u);
ASSERT_EQ(registry.storage<char>().size(), 1u);
registry.erase<int, char>(iview.begin(), iview.end());
ASSERT_EQ(registry.storage<int>().size(), 0u);
ASSERT_EQ(registry.storage<char>().size(), 0u);
registry.insert<int>(std::begin(entities), std::end(entities));
registry.insert<char>(std::begin(entities), std::end(entities));
@ -1643,6 +1735,39 @@ TEST(Registry, StableErase) {
ASSERT_EQ(registry.storage<double>().size(), 1u);
}
TEST(Registry, EraseIf) {
using namespace entt::literals;
entt::registry registry;
const auto entity = registry.create();
registry.emplace<int>(entity);
registry.storage<int>("other"_hs).emplace(entity);
registry.emplace<char>(entity);
ASSERT_TRUE(registry.storage<int>().contains(entity));
ASSERT_TRUE(registry.storage<int>("other"_hs).contains(entity));
ASSERT_TRUE(registry.storage<char>().contains(entity));
registry.erase_if(entity, [](auto &&...) { return false; });
ASSERT_TRUE(registry.storage<int>().contains(entity));
ASSERT_TRUE(registry.storage<int>("other"_hs).contains(entity));
ASSERT_TRUE(registry.storage<char>().contains(entity));
registry.erase_if(entity, [](entt::id_type id, auto &&...) { return id == "other"_hs; });
ASSERT_TRUE(registry.storage<int>().contains(entity));
ASSERT_FALSE(registry.storage<int>("other"_hs).contains(entity));
ASSERT_TRUE(registry.storage<char>().contains(entity));
registry.erase_if(entity, [](auto, const auto &storage) { return storage.type() == entt::type_id<char>(); });
ASSERT_TRUE(registry.storage<int>().contains(entity));
ASSERT_FALSE(registry.storage<int>("other"_hs).contains(entity));
ASSERT_FALSE(registry.storage<char>().contains(entity));
}
TEST(Registry, Remove) {
entt::registry registry;
const auto iview = registry.view<int>();
@ -1689,6 +1814,18 @@ TEST(Registry, Remove) {
ASSERT_EQ(registry.storage<char>().size(), 0u);
ASSERT_EQ(registry.storage<double>().size(), 1u);
registry.insert<int>(std::begin(entities) + 1, std::end(entities) - 1u);
registry.insert<char>(std::begin(entities) + 1, std::end(entities) - 1u);
ASSERT_EQ(registry.storage<int>().size(), 1u);
ASSERT_EQ(registry.storage<char>().size(), 1u);
registry.remove<int, char>(iview.begin(), iview.end());
registry.remove<int, char>(iview.begin(), iview.end());
ASSERT_EQ(registry.storage<int>().size(), 0u);
ASSERT_EQ(registry.storage<char>().size(), 0u);
registry.insert<int>(std::begin(entities), std::end(entities));
registry.insert<char>(std::begin(entities), std::end(entities));
@ -1791,7 +1928,7 @@ TEST(Registry, NonOwningGroupInterleaved) {
registry.emplace<int>(entity);
registry.emplace<char>(entity);
const auto group = registry.group<>(entt::get<int, char>);
const auto group = registry.group(entt::get<int, char>);
entity = registry.create();
registry.emplace<int>(entity);
@ -1845,7 +1982,7 @@ TEST(Registry, PartialOwningGroupInterleaved) {
TEST(Registry, NonOwningGroupSortInterleaved) {
entt::registry registry;
const auto group = registry.group<>(entt::get<int, char>);
const auto group = registry.group(entt::get<int, char>);
const auto e0 = registry.create();
registry.emplace<int>(e0, 0);
@ -2009,7 +2146,7 @@ TEST(Registry, ScramblingPoolsIsAllowed) {
// thanks to @andranik3949 for pointing out this missing test
registry.view<const int>().each([](const auto entity, const auto &value) {
ASSERT_EQ(entt::to_integral(entity), value);
ASSERT_EQ(static_cast<int>(entt::to_integral(entity)), value);
});
}
@ -2021,7 +2158,7 @@ TEST(Registry, RuntimePools) {
const auto entity = registry.create();
static_assert(std::is_same_v<decltype(registry.storage<empty_type>()), entt::storage_type_t<empty_type> &>);
static_assert(std::is_same_v<decltype(std::as_const(registry).storage<empty_type>()), const entt::storage_type_t<empty_type> &>);
static_assert(std::is_same_v<decltype(std::as_const(registry).storage<empty_type>()), const entt::storage_type_t<empty_type> *>);
static_assert(std::is_same_v<decltype(registry.storage("other"_hs)), entt::storage_type_t<empty_type>::base_type *>);
static_assert(std::is_same_v<decltype(std::as_const(registry).storage("other"_hs)), const entt::storage_type_t<empty_type>::base_type *>);
@ -2030,7 +2167,7 @@ TEST(Registry, RuntimePools) {
ASSERT_EQ(std::as_const(registry).storage("rehto"_hs), nullptr);
ASSERT_EQ(&registry.storage<empty_type>("other"_hs), &storage);
ASSERT_NE(&std::as_const(registry).storage<empty_type>(), &storage);
ASSERT_NE(std::as_const(registry).storage<empty_type>(), &storage);
ASSERT_FALSE(registry.any_of<empty_type>(entity));
ASSERT_FALSE(storage.contains(entity));
@ -2070,6 +2207,7 @@ TEST(Registry, Storage) {
entt::registry registry;
const auto entity = registry.create();
auto &storage = registry.storage<int>("int"_hs);
storage.emplace(entity);
@ -2149,8 +2287,7 @@ TEST(Registry, RegistryStorageIterator) {
TEST(Registry, RegistryStorageIteratorConversion) {
entt::registry registry;
const auto entity = registry.create();
registry.emplace<int>(entity);
registry.storage<int>();
auto proxy = registry.storage();
auto cproxy = std::as_const(registry).storage();
@ -2176,6 +2313,22 @@ TEST(Registry, RegistryStorageIteratorConversion) {
ASSERT_NE(++cit, it);
}
TEST(Registry, VoidType) {
using namespace entt::literals;
entt::registry registry;
const auto entity = registry.create();
auto &storage = registry.storage<void>("custom"_hs);
storage.emplace(entity);
ASSERT_TRUE(registry.storage<void>().empty());
ASSERT_FALSE(registry.storage<void>("custom"_hs).empty());
ASSERT_TRUE(registry.storage<void>("custom"_hs).contains(entity));
ASSERT_EQ(registry.storage<void>().type(), entt::type_id<void>());
ASSERT_EQ(registry.storage<void>("custom"_hs).type(), entt::type_id<void>());
}
TEST(Registry, NoEtoType) {
entt::registry registry;
const auto entity = registry.create();

View File

@ -1,5 +1,6 @@
#include <iterator>
#include <gtest/gtest.h>
#include <entt/entity/mixin.hpp>
#include <entt/entity/registry.hpp>
#include <entt/entity/storage.hpp>
#include "../common/throwing_allocator.hpp"
@ -30,9 +31,20 @@ void listener(counter &counter, Registry &, typename Registry::entity_type) {
++counter.value;
}
TEST(SighStorageMixin, GenericType) {
struct empty_each_tag final {};
template<>
struct entt::basic_storage<empty_each_tag, entt::entity, std::allocator<empty_each_tag>>: entt::basic_storage<void, entt::entity, std::allocator<void>> {
basic_storage(const std::allocator<empty_each_tag> &) {}
[[nodiscard]] iterable each() noexcept {
return {internal::extended_storage_iterator{base_type::end()}, internal::extended_storage_iterator{base_type::end()}};
}
};
TEST(SighMixin, GenericType) {
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
entt::sigh_storage_mixin<entt::storage<int>> pool;
entt::sigh_mixin<entt::storage<int>> pool;
entt::sparse_set &base = pool;
entt::registry registry;
@ -40,10 +52,21 @@ TEST(SighStorageMixin, GenericType) {
counter on_destroy{};
pool.bind(entt::forward_as_any(registry));
ASSERT_TRUE(pool.empty());
pool.insert(entities, entities + 1u);
pool.erase(entities[0u]);
ASSERT_TRUE(pool.empty());
ASSERT_EQ(on_construct.value, 0);
ASSERT_EQ(on_destroy.value, 0);
pool.on_construct().connect<&listener<entt::registry>>(on_construct);
pool.on_destroy().connect<&listener<entt::registry>>(on_destroy);
ASSERT_NE(base.emplace(entities[0u]), base.end());
ASSERT_NE(base.push(entities[0u]), base.end());
pool.emplace(entities[1u]);
@ -61,7 +84,7 @@ TEST(SighStorageMixin, GenericType) {
ASSERT_EQ(on_destroy.value, 2);
ASSERT_TRUE(pool.empty());
ASSERT_NE(base.insert(std::begin(entities), std::end(entities)), base.end());
ASSERT_NE(base.push(std::begin(entities), std::end(entities)), base.end());
ASSERT_EQ(pool.get(entities[0u]), 0);
ASSERT_EQ(pool.get(entities[1u]), 0);
@ -95,9 +118,9 @@ TEST(SighStorageMixin, GenericType) {
ASSERT_TRUE(pool.empty());
}
TEST(SighStorageMixin, StableType) {
TEST(SighMixin, StableType) {
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
entt::sigh_storage_mixin<entt::storage<stable_type>> pool;
entt::sigh_mixin<entt::storage<stable_type>> pool;
entt::sparse_set &base = pool;
entt::registry registry;
@ -108,7 +131,7 @@ TEST(SighStorageMixin, StableType) {
pool.on_construct().connect<&listener<entt::registry>>(on_construct);
pool.on_destroy().connect<&listener<entt::registry>>(on_destroy);
ASSERT_NE(base.emplace(entities[0u]), base.end());
ASSERT_NE(base.push(entities[0u]), base.end());
pool.emplace(entities[1u]);
@ -126,7 +149,7 @@ TEST(SighStorageMixin, StableType) {
ASSERT_EQ(on_destroy.value, 2);
ASSERT_FALSE(pool.empty());
ASSERT_NE(base.insert(std::begin(entities), std::end(entities)), base.end());
ASSERT_NE(base.push(std::begin(entities), std::end(entities)), base.end());
ASSERT_EQ(pool.get(entities[0u]).value, 0);
ASSERT_EQ(pool.get(entities[1u]).value, 0);
@ -160,9 +183,9 @@ TEST(SighStorageMixin, StableType) {
ASSERT_FALSE(pool.empty());
}
TEST(SighStorageMixin, EmptyType) {
TEST(SighMixin, EmptyType) {
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
entt::sigh_storage_mixin<entt::storage<empty_type>> pool;
entt::sigh_mixin<entt::storage<empty_type>> pool;
entt::sparse_set &base = pool;
entt::registry registry;
@ -173,7 +196,7 @@ TEST(SighStorageMixin, EmptyType) {
pool.on_construct().connect<&listener<entt::registry>>(on_construct);
pool.on_destroy().connect<&listener<entt::registry>>(on_destroy);
ASSERT_NE(base.emplace(entities[0u]), base.end());
ASSERT_NE(base.push(entities[0u]), base.end());
pool.emplace(entities[1u]);
@ -191,7 +214,7 @@ TEST(SighStorageMixin, EmptyType) {
ASSERT_EQ(on_destroy.value, 2);
ASSERT_TRUE(pool.empty());
ASSERT_NE(base.insert(std::begin(entities), std::end(entities)), base.end());
ASSERT_NE(base.push(std::begin(entities), std::end(entities)), base.end());
ASSERT_TRUE(pool.contains(entities[0u]));
ASSERT_TRUE(pool.contains(entities[1u]));
@ -225,9 +248,9 @@ TEST(SighStorageMixin, EmptyType) {
ASSERT_TRUE(pool.empty());
}
TEST(SighStorageMixin, NonDefaultConstructibleType) {
TEST(SighMixin, NonDefaultConstructibleType) {
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
entt::sigh_storage_mixin<entt::storage<non_default_constructible>> pool;
entt::sigh_mixin<entt::storage<non_default_constructible>> pool;
entt::sparse_set &base = pool;
entt::registry registry;
@ -238,12 +261,12 @@ TEST(SighStorageMixin, NonDefaultConstructibleType) {
pool.on_construct().connect<&listener<entt::registry>>(on_construct);
pool.on_destroy().connect<&listener<entt::registry>>(on_destroy);
ASSERT_EQ(base.emplace(entities[0u]), base.end());
ASSERT_EQ(base.push(entities[0u]), base.end());
pool.emplace(entities[1u], 3);
ASSERT_EQ(pool.size(), 1u);
ASSERT_EQ(on_construct.value, 2);
ASSERT_EQ(on_construct.value, 1);
ASSERT_EQ(on_destroy.value, 0);
ASSERT_FALSE(pool.empty());
@ -253,11 +276,11 @@ TEST(SighStorageMixin, NonDefaultConstructibleType) {
base.erase(entities[1u]);
ASSERT_EQ(pool.size(), 0u);
ASSERT_EQ(on_construct.value, 2);
ASSERT_EQ(on_construct.value, 1);
ASSERT_EQ(on_destroy.value, 1);
ASSERT_TRUE(pool.empty());
ASSERT_EQ(base.insert(std::begin(entities), std::end(entities)), base.end());
ASSERT_EQ(base.push(std::begin(entities), std::end(entities)), base.end());
ASSERT_FALSE(pool.contains(entities[0u]));
ASSERT_FALSE(pool.contains(entities[1u]));
@ -266,7 +289,7 @@ TEST(SighStorageMixin, NonDefaultConstructibleType) {
pool.insert(std::begin(entities), std::end(entities), 3);
ASSERT_EQ(pool.size(), 2u);
ASSERT_EQ(on_construct.value, 6);
ASSERT_EQ(on_construct.value, 3);
ASSERT_EQ(on_destroy.value, 1);
ASSERT_FALSE(pool.empty());
@ -276,13 +299,13 @@ TEST(SighStorageMixin, NonDefaultConstructibleType) {
pool.erase(std::begin(entities), std::end(entities));
ASSERT_EQ(pool.size(), 0u);
ASSERT_EQ(on_construct.value, 6);
ASSERT_EQ(on_construct.value, 3);
ASSERT_EQ(on_destroy.value, 3);
ASSERT_TRUE(pool.empty());
}
TEST(SighStorageMixin, VoidType) {
entt::sigh_storage_mixin<entt::storage<void>> pool;
TEST(SighMixin, VoidType) {
entt::sigh_mixin<entt::storage<void>> pool;
entt::registry registry;
counter on_construct{};
@ -297,7 +320,7 @@ TEST(SighStorageMixin, VoidType) {
ASSERT_EQ(pool.type(), entt::type_id<void>());
ASSERT_TRUE(pool.contains(entt::entity{99}));
entt::sigh_storage_mixin<entt::storage<void>> other{std::move(pool)};
entt::sigh_mixin<entt::storage<void>> other{std::move(pool)};
ASSERT_FALSE(pool.contains(entt::entity{99}));
ASSERT_TRUE(other.contains(entt::entity{99}));
@ -313,8 +336,8 @@ TEST(SighStorageMixin, VoidType) {
ASSERT_EQ(on_destroy.value, 1);
}
TEST(SighStorageMixin, Move) {
entt::sigh_storage_mixin<entt::storage<int>> pool;
TEST(SighMixin, Move) {
entt::sigh_mixin<entt::storage<int>> pool;
entt::registry registry;
counter on_construct{};
@ -330,7 +353,7 @@ TEST(SighStorageMixin, Move) {
ASSERT_TRUE(std::is_move_assignable_v<decltype(pool)>);
ASSERT_EQ(pool.type(), entt::type_id<int>());
entt::sigh_storage_mixin<entt::storage<int>> other{std::move(pool)};
entt::sigh_mixin<entt::storage<int>> other{std::move(pool)};
ASSERT_TRUE(pool.empty());
ASSERT_FALSE(other.empty());
@ -347,7 +370,7 @@ TEST(SighStorageMixin, Move) {
ASSERT_EQ(pool.get(entt::entity{3}), 3);
ASSERT_EQ(other.at(0u), static_cast<entt::entity>(entt::null));
other = entt::sigh_storage_mixin<entt::storage<int>>{};
other = entt::sigh_mixin<entt::storage<int>>{};
other.bind(entt::forward_as_any(registry));
other.emplace(entt::entity{42}, 42);
@ -365,9 +388,9 @@ TEST(SighStorageMixin, Move) {
ASSERT_EQ(on_destroy.value, 1);
}
TEST(SighStorageMixin, Swap) {
entt::sigh_storage_mixin<entt::storage<int>> pool;
entt::sigh_storage_mixin<entt::storage<int>> other;
TEST(SighMixin, Swap) {
entt::sigh_mixin<entt::storage<int>> pool;
entt::sigh_mixin<entt::storage<int>> other;
entt::registry registry;
counter on_construct{};
@ -411,7 +434,100 @@ TEST(SighStorageMixin, Swap) {
ASSERT_EQ(on_destroy.value, 3);
}
TEST(SighStorageMixin, CustomAllocator) {
TEST(SighMixin, EmptyEachStorage) {
entt::sigh_mixin<entt::storage<empty_each_tag>> pool;
entt::registry registry;
counter on_destroy{};
pool.bind(entt::forward_as_any(registry));
pool.on_destroy().connect<&listener<entt::registry>>(on_destroy);
ASSERT_TRUE(pool.empty());
ASSERT_EQ(on_destroy.value, 0);
pool.push(entt::entity{42});
ASSERT_FALSE(pool.empty());
ASSERT_EQ(on_destroy.value, 0);
ASSERT_NE(pool.begin(), pool.end());
ASSERT_EQ(pool.each().begin(), pool.each().end());
ASSERT_EQ(on_destroy.value, 0);
pool.clear();
ASSERT_EQ(pool.begin(), pool.end());
ASSERT_EQ(pool.each().begin(), pool.each().end());
// no signal at all because of the (fake) empty iterable
ASSERT_EQ(on_destroy.value, 0);
}
TEST(SighMixin, StorageEntity) {
using traits_type = entt::entt_traits<entt::entity>;
entt::sigh_mixin<entt::storage<entt::entity>> pool;
entt::registry registry;
counter on_construct{};
counter on_destroy{};
pool.bind(entt::forward_as_any(registry));
pool.on_construct().connect<&listener<entt::registry>>(on_construct);
pool.on_destroy().connect<&listener<entt::registry>>(on_destroy);
pool.push(entt::entity{1});
ASSERT_EQ(on_construct.value, 1);
ASSERT_EQ(on_destroy.value, 0);
ASSERT_EQ(pool.size(), 2u);
ASSERT_EQ(pool.in_use(), 1u);
pool.erase(entt::entity{1});
ASSERT_EQ(on_construct.value, 1);
ASSERT_EQ(on_destroy.value, 1);
ASSERT_EQ(pool.size(), 2u);
ASSERT_EQ(pool.in_use(), 0u);
pool.push(traits_type::construct(0, 2));
pool.push(traits_type::construct(2, 1));
ASSERT_TRUE(pool.contains(traits_type::construct(0, 2)));
ASSERT_TRUE(pool.contains(traits_type::construct(1, 1)));
ASSERT_TRUE(pool.contains(traits_type::construct(2, 1)));
ASSERT_EQ(on_construct.value, 3);
ASSERT_EQ(on_destroy.value, 1);
ASSERT_EQ(pool.size(), 3u);
ASSERT_EQ(pool.in_use(), 2u);
pool.clear();
ASSERT_EQ(pool.size(), 0u);
ASSERT_EQ(pool.in_use(), 0u);
ASSERT_EQ(on_construct.value, 3);
ASSERT_EQ(on_destroy.value, 3);
pool.emplace();
pool.emplace(entt::entity{0});
entt::entity entities[1u]{};
pool.insert(entities, entities + 1u);
ASSERT_EQ(on_construct.value, 6);
ASSERT_EQ(on_destroy.value, 3);
ASSERT_EQ(pool.size(), 3u);
ASSERT_EQ(pool.in_use(), 3u);
pool.clear();
ASSERT_EQ(pool.size(), 0u);
ASSERT_EQ(pool.in_use(), 0u);
}
TEST(SighMixin, CustomAllocator) {
auto test = [](auto pool, auto alloc) {
using registry_type = typename decltype(pool)::registry_type;
registry_type registry;
@ -466,12 +582,12 @@ TEST(SighStorageMixin, CustomAllocator) {
test::throwing_allocator<entt::entity> allocator{};
test(entt::sigh_storage_mixin<entt::basic_storage<int, entt::entity, test::throwing_allocator<int>>>{allocator}, allocator);
test(entt::sigh_storage_mixin<entt::basic_storage<std::true_type, entt::entity, test::throwing_allocator<std::true_type>>>{allocator}, allocator);
test(entt::sigh_storage_mixin<entt::basic_storage<stable_type, entt::entity, test::throwing_allocator<stable_type>>>{allocator}, allocator);
test(entt::sigh_mixin<entt::basic_storage<int, entt::entity, test::throwing_allocator<int>>>{allocator}, allocator);
test(entt::sigh_mixin<entt::basic_storage<std::true_type, entt::entity, test::throwing_allocator<std::true_type>>>{allocator}, allocator);
test(entt::sigh_mixin<entt::basic_storage<stable_type, entt::entity, test::throwing_allocator<stable_type>>>{allocator}, allocator);
}
TEST(SighStorageMixin, ThrowingAllocator) {
TEST(SighMixin, ThrowingAllocator) {
auto test = [](auto pool) {
using pool_allocator_type = typename decltype(pool)::allocator_type;
using value_type = typename decltype(pool)::value_type;
@ -511,7 +627,7 @@ TEST(SighStorageMixin, ThrowingAllocator) {
test::throwing_allocator<entt::entity>::trigger_on_allocate = true;
ASSERT_THROW(base.emplace(entt::entity{0}), test::throwing_allocator<entt::entity>::exception_type);
ASSERT_THROW(base.push(entt::entity{0}), test::throwing_allocator<entt::entity>::exception_type);
ASSERT_FALSE(base.contains(entt::entity{0}));
ASSERT_TRUE(base.empty());
@ -543,12 +659,12 @@ TEST(SighStorageMixin, ThrowingAllocator) {
ASSERT_EQ(on_destroy.value, 1);
};
test(entt::sigh_storage_mixin<entt::basic_storage<int, entt::entity, test::throwing_allocator<int>>>{});
test(entt::sigh_storage_mixin<entt::basic_storage<stable_type, entt::entity, test::throwing_allocator<stable_type>>>{});
test(entt::sigh_mixin<entt::basic_storage<int, entt::entity, test::throwing_allocator<int>>>{});
test(entt::sigh_mixin<entt::basic_storage<stable_type, entt::entity, test::throwing_allocator<stable_type>>>{});
}
TEST(SighStorageMixin, ThrowingComponent) {
entt::sigh_storage_mixin<entt::storage<test::throwing_type>> pool;
TEST(SighMixin, ThrowingComponent) {
entt::sigh_mixin<entt::storage<test::throwing_type>> pool;
using registry_type = typename decltype(pool)::registry_type;
registry_type registry;

File diff suppressed because it is too large Load Diff

View File

@ -26,6 +26,7 @@ TEST(SparseSet, Functionalities) {
ASSERT_EQ(set.capacity(), 42u);
ASSERT_TRUE(set.empty());
ASSERT_EQ(set.size(), 0u);
ASSERT_TRUE(set.contiguous());
ASSERT_EQ(std::as_const(set).begin(), std::as_const(set).end());
ASSERT_EQ(set.begin(), set.end());
ASSERT_FALSE(set.contains(entt::entity{0}));
@ -36,10 +37,11 @@ TEST(SparseSet, Functionalities) {
ASSERT_EQ(set.capacity(), 42u);
ASSERT_TRUE(set.empty());
set.emplace(entt::entity{42});
set.push(entt::entity{42});
ASSERT_FALSE(set.empty());
ASSERT_EQ(set.size(), 1u);
ASSERT_TRUE(set.contiguous());
ASSERT_NE(std::as_const(set).begin(), std::as_const(set).end());
ASSERT_NE(set.begin(), set.end());
ASSERT_FALSE(set.contains(entt::entity{0}));
@ -48,12 +50,13 @@ TEST(SparseSet, Functionalities) {
ASSERT_EQ(set.at(0u), entt::entity{42});
ASSERT_EQ(set.at(1u), static_cast<entt::entity>(entt::null));
ASSERT_EQ(set[0u], entt::entity{42});
ASSERT_EQ(set.get(entt::entity{42}), nullptr);
ASSERT_EQ(set.value(entt::entity{42}), nullptr);
set.erase(entt::entity{42});
ASSERT_TRUE(set.empty());
ASSERT_EQ(set.size(), 0u);
ASSERT_TRUE(set.contiguous());
ASSERT_EQ(std::as_const(set).begin(), std::as_const(set).end());
ASSERT_EQ(set.begin(), set.end());
ASSERT_FALSE(set.contains(entt::entity{0}));
@ -61,7 +64,7 @@ TEST(SparseSet, Functionalities) {
ASSERT_EQ(set.at(0u), static_cast<entt::entity>(entt::null));
ASSERT_EQ(set.at(1u), static_cast<entt::entity>(entt::null));
set.emplace(entt::entity{42});
set.push(entt::entity{42});
ASSERT_FALSE(set.empty());
ASSERT_EQ(set.index(entt::entity{42}), 0u);
@ -73,6 +76,7 @@ TEST(SparseSet, Functionalities) {
ASSERT_TRUE(set.empty());
ASSERT_EQ(set.size(), 0u);
ASSERT_TRUE(set.contiguous());
ASSERT_EQ(std::as_const(set).begin(), std::as_const(set).end());
ASSERT_EQ(set.begin(), set.end());
ASSERT_FALSE(set.contains(entt::entity{0}));
@ -86,11 +90,11 @@ TEST(SparseSet, Contains) {
entt::sparse_set set{entt::deletion_policy::in_place};
set.emplace(entt::entity{0});
set.emplace(entt::entity{3});
set.emplace(entt::entity{42});
set.emplace(entt::entity{99});
set.emplace(traits_type::construct(1, 5));
set.push(entt::entity{0});
set.push(entt::entity{3});
set.push(entt::entity{42});
set.push(entt::entity{99});
set.push(traits_type::construct(1, 5));
ASSERT_FALSE(set.contains(entt::null));
ASSERT_FALSE(set.contains(entt::tombstone));
@ -133,8 +137,8 @@ TEST(SparseSet, Current) {
ASSERT_EQ(set.current(traits_type::construct(0, 0)), traits_type::to_version(entt::tombstone));
ASSERT_EQ(set.current(traits_type::construct(3, 3)), traits_type::to_version(entt::tombstone));
set.emplace(traits_type::construct(0, 0));
set.emplace(traits_type::construct(3, 3));
set.push(traits_type::construct(0, 0));
set.push(traits_type::construct(3, 3));
ASSERT_NE(set.current(traits_type::construct(0, 0)), traits_type::to_version(entt::tombstone));
ASSERT_NE(set.current(traits_type::construct(3, 3)), traits_type::to_version(entt::tombstone));
@ -153,8 +157,8 @@ TEST(SparseSet, Index) {
entt::sparse_set set{};
set.emplace(traits_type::construct(0, 0));
set.emplace(traits_type::construct(3, 3));
set.push(traits_type::construct(0, 0));
set.push(traits_type::construct(3, 3));
ASSERT_EQ(set.index(traits_type::construct(0, 0)), 0u);
ASSERT_EQ(set.index(traits_type::construct(3, 3)), 1u);
@ -175,7 +179,7 @@ ENTT_DEBUG_TEST(SparseSetDeathTest, Index) {
TEST(SparseSet, Move) {
entt::sparse_set set;
set.emplace(entt::entity{42});
set.push(entt::entity{42});
ASSERT_TRUE(std::is_move_constructible_v<decltype(set)>);
ASSERT_TRUE(std::is_move_assignable_v<decltype(set)>);
@ -195,7 +199,7 @@ TEST(SparseSet, Move) {
ASSERT_EQ(other.at(0u), static_cast<entt::entity>(entt::null));
other = entt::sparse_set{};
other.emplace(entt::entity{3});
other.push(entt::entity{3});
other = std::move(set);
ASSERT_TRUE(set.empty());
@ -208,10 +212,10 @@ TEST(SparseSet, Swap) {
entt::sparse_set set;
entt::sparse_set other{entt::deletion_policy::in_place};
set.emplace(entt::entity{42});
set.push(entt::entity{42});
other.emplace(entt::entity{9});
other.emplace(entt::entity{3});
other.push(entt::entity{9});
other.push(entt::entity{3});
other.erase(entt::entity{9});
ASSERT_EQ(set.size(), 1u);
@ -233,12 +237,12 @@ TEST(SparseSet, Pagination) {
ASSERT_EQ(set.extent(), 0u);
set.emplace(entt::entity{traits_type::page_size - 1u});
set.push(entt::entity{traits_type::page_size - 1u});
ASSERT_EQ(set.extent(), traits_type::page_size);
ASSERT_TRUE(set.contains(entt::entity{traits_type::page_size - 1u}));
set.emplace(entt::entity{traits_type::page_size});
set.push(entt::entity{traits_type::page_size});
ASSERT_EQ(set.extent(), 2 * traits_type::page_size);
ASSERT_TRUE(set.contains(entt::entity{traits_type::page_size - 1u}));
@ -263,17 +267,17 @@ TEST(SparseSet, Pagination) {
ASSERT_EQ(set.extent(), 2 * traits_type::page_size);
}
TEST(SparseSet, Emplace) {
TEST(SparseSet, Push) {
entt::sparse_set set{entt::deletion_policy::in_place};
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
ASSERT_TRUE(set.empty());
ASSERT_NE(set.emplace(entities[0u]), set.end());
ASSERT_NE(set.push(entities[0u]), set.end());
set.erase(entities[0u]);
ASSERT_NE(set.emplace(entities[1u]), set.end());
ASSERT_NE(set.emplace(entities[0u]), set.end());
ASSERT_NE(set.push(entities[1u]), set.end());
ASSERT_NE(set.push(entities[0u]), set.end());
ASSERT_EQ(set.at(0u), entities[1u]);
ASSERT_EQ(set.at(1u), entities[0u]);
@ -282,8 +286,8 @@ TEST(SparseSet, Emplace) {
set.erase(std::begin(entities), std::end(entities));
ASSERT_NE(set.emplace(entities[1u]), set.end());
ASSERT_NE(set.emplace(entities[0u]), set.end());
ASSERT_NE(set.push(entities[1u]), set.end());
ASSERT_NE(set.push(entities[0u]), set.end());
ASSERT_EQ(set.at(0u), entities[1u]);
ASSERT_EQ(set.at(1u), entities[0u]);
@ -291,72 +295,16 @@ TEST(SparseSet, Emplace) {
ASSERT_EQ(set.index(entities[1u]), 0u);
}
ENTT_DEBUG_TEST(SparseSetDeathTest, Emplace) {
entt::sparse_set set{entt::deletion_policy::in_place};
set.emplace(entt::entity{42});
ASSERT_DEATH(set.emplace(entt::entity{42}), "");
}
TEST(SparseSet, EmplaceOutOfBounds) {
using traits_type = entt::entt_traits<entt::entity>;
entt::sparse_set set{entt::deletion_policy::in_place};
entt::entity entities[2u]{entt::entity{0}, entt::entity{traits_type::page_size}};
ASSERT_NE(set.emplace(entities[0u]), set.end());
ASSERT_EQ(set.extent(), traits_type::page_size);
ASSERT_EQ(set.index(entities[0u]), 0u);
set.erase(entities[0u]);
ASSERT_NE(set.emplace(entities[1u]), set.end());
ASSERT_EQ(set.extent(), 2u * traits_type::page_size);
ASSERT_EQ(set.index(entities[1u]), 0u);
}
TEST(SparseSet, Bump) {
using traits_type = entt::entt_traits<entt::entity>;
entt::sparse_set set;
entt::entity entities[3u]{entt::entity{3}, entt::entity{42}, traits_type::construct(9, 3)};
set.insert(std::begin(entities), std::end(entities));
ASSERT_EQ(set.current(entities[0u]), 0u);
ASSERT_EQ(set.current(entities[1u]), 0u);
ASSERT_EQ(set.current(entities[2u]), 3u);
set.bump(entities[0u]);
set.bump(traits_type::construct(traits_type::to_entity(entities[1u]), 1));
set.bump(traits_type::construct(traits_type::to_entity(entities[2u]), 0));
ASSERT_EQ(set.current(entities[0u]), 0u);
ASSERT_EQ(set.current(entities[1u]), 1u);
ASSERT_EQ(set.current(entities[2u]), 0u);
}
ENTT_DEBUG_TEST(SparseSetDeathTest, Bump) {
using traits_type = entt::entt_traits<entt::entity>;
entt::sparse_set set{entt::deletion_policy::in_place};
set.emplace(entt::entity{3});
ASSERT_DEATH(set.bump(entt::null), "");
ASSERT_DEATH(set.bump(entt::tombstone), "");
ASSERT_DEATH(set.bump(entt::entity{42}), "");
ASSERT_DEATH(set.bump(traits_type::construct(traits_type::to_entity(entt::entity{3}), traits_type::to_version(entt::tombstone))), "");
}
TEST(SparseSet, Insert) {
TEST(SparseSet, PushRange) {
entt::sparse_set set{entt::deletion_policy::in_place};
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
set.emplace(entt::entity{12});
set.push(entt::entity{12});
ASSERT_EQ(set.insert(std::end(entities), std::end(entities)), set.end());
ASSERT_NE(set.insert(std::begin(entities), std::end(entities)), set.end());
ASSERT_EQ(set.push(std::end(entities), std::end(entities)), set.end());
ASSERT_NE(set.push(std::begin(entities), std::end(entities)), set.end());
set.emplace(entt::entity{24});
set.push(entt::entity{24});
ASSERT_TRUE(set.contains(entities[0u]));
ASSERT_TRUE(set.contains(entities[1u]));
@ -378,7 +326,7 @@ TEST(SparseSet, Insert) {
set.erase(std::begin(entities), std::end(entities));
ASSERT_NE(set.insert(std::rbegin(entities), std::rend(entities)), set.end());
ASSERT_NE(set.push(std::rbegin(entities), std::rend(entities)), set.end());
ASSERT_EQ(set.size(), 6u);
ASSERT_EQ(set.at(4u), entities[1u]);
@ -387,6 +335,64 @@ TEST(SparseSet, Insert) {
ASSERT_EQ(set.index(entities[1u]), 4u);
}
ENTT_DEBUG_TEST(SparseSetDeathTest, Push) {
entt::sparse_set set{entt::deletion_policy::in_place};
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
set.push(entt::entity{42});
ASSERT_DEATH(set.push(entt::entity{42}), "");
ASSERT_DEATH(set.push(std::begin(entities), std::end(entities)), "");
}
TEST(SparseSet, PushOutOfBounds) {
using traits_type = entt::entt_traits<entt::entity>;
entt::sparse_set set{entt::deletion_policy::in_place};
entt::entity entities[2u]{entt::entity{0}, entt::entity{traits_type::page_size}};
ASSERT_NE(set.push(entities[0u]), set.end());
ASSERT_EQ(set.extent(), traits_type::page_size);
ASSERT_EQ(set.index(entities[0u]), 0u);
set.erase(entities[0u]);
ASSERT_NE(set.push(entities[1u]), set.end());
ASSERT_EQ(set.extent(), 2u * traits_type::page_size);
ASSERT_EQ(set.index(entities[1u]), 0u);
}
TEST(SparseSet, Bump) {
using traits_type = entt::entt_traits<entt::entity>;
entt::sparse_set set;
entt::entity entities[3u]{entt::entity{3}, entt::entity{42}, traits_type::construct(9, 3)};
set.push(std::begin(entities), std::end(entities));
ASSERT_EQ(set.current(entities[0u]), 0u);
ASSERT_EQ(set.current(entities[1u]), 0u);
ASSERT_EQ(set.current(entities[2u]), 3u);
ASSERT_EQ(set.bump(entities[0u]), 0u);
ASSERT_EQ(set.bump(traits_type::construct(traits_type::to_entity(entities[1u]), 1)), 1u);
ASSERT_EQ(set.bump(traits_type::construct(traits_type::to_entity(entities[2u]), 0)), 0u);
ASSERT_EQ(set.current(entities[0u]), 0u);
ASSERT_EQ(set.current(entities[1u]), 1u);
ASSERT_EQ(set.current(entities[2u]), 0u);
}
ENTT_DEBUG_TEST(SparseSetDeathTest, Bump) {
using traits_type = entt::entt_traits<entt::entity>;
entt::sparse_set set{entt::deletion_policy::in_place};
set.push(entt::entity{3});
ASSERT_DEATH(set.bump(entt::null), "");
ASSERT_DEATH(set.bump(entt::tombstone), "");
ASSERT_DEATH(set.bump(entt::entity{42}), "");
ASSERT_DEATH(set.bump(traits_type::construct(traits_type::to_entity(entt::entity{3}), traits_type::to_version(entt::tombstone))), "");
}
TEST(SparseSet, Erase) {
using traits_type = entt::entt_traits<entt::entity>;
@ -396,7 +402,7 @@ TEST(SparseSet, Erase) {
ASSERT_EQ(set.policy(), entt::deletion_policy::swap_and_pop);
ASSERT_TRUE(set.empty());
set.insert(std::begin(entities), std::end(entities));
set.push(std::begin(entities), std::end(entities));
set.erase(set.begin(), set.end());
ASSERT_TRUE(set.empty());
@ -404,7 +410,7 @@ TEST(SparseSet, Erase) {
ASSERT_EQ(set.current(entities[1u]), traits_type::to_version(entt::tombstone));
ASSERT_EQ(set.current(entities[2u]), traits_type::to_version(entt::tombstone));
set.insert(std::begin(entities), std::end(entities));
set.push(std::begin(entities), std::end(entities));
set.erase(entities, entities + 2u);
ASSERT_FALSE(set.empty());
@ -418,7 +424,7 @@ TEST(SparseSet, Erase) {
ASSERT_TRUE(set.empty());
ASSERT_EQ(set.current(entities[2u]), traits_type::to_version(entt::tombstone));
set.insert(std::begin(entities), std::end(entities));
set.push(std::begin(entities), std::end(entities));
std::swap(entities[1u], entities[2u]);
set.erase(entities, entities + 2u);
@ -442,8 +448,8 @@ TEST(SparseSet, CrossErase) {
entt::sparse_set other;
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
set.insert(std::begin(entities), std::end(entities));
other.emplace(entities[1u]);
set.push(std::begin(entities), std::end(entities));
other.push(entities[1u]);
set.erase(other.begin(), other.end());
ASSERT_TRUE(set.contains(entities[0u]));
@ -461,9 +467,9 @@ TEST(SparseSet, StableErase) {
ASSERT_TRUE(set.empty());
ASSERT_EQ(set.size(), 0u);
set.emplace(entities[0u]);
set.emplace(entities[1u]);
set.emplace(entities[2u]);
set.push(entities[0u]);
set.push(entities[1u]);
set.push(entities[2u]);
set.erase(set.begin(), set.end());
@ -476,9 +482,9 @@ TEST(SparseSet, StableErase) {
ASSERT_TRUE(set.at(1u) == entt::tombstone);
ASSERT_TRUE(set.at(2u) == entt::tombstone);
set.emplace(entities[0u]);
set.emplace(entities[1u]);
set.emplace(entities[2u]);
set.push(entities[0u]);
set.push(entities[1u]);
set.push(entities[2u]);
set.erase(entities, entities + 2u);
@ -497,9 +503,9 @@ TEST(SparseSet, StableErase) {
ASSERT_EQ(set.size(), 3u);
ASSERT_EQ(set.current(entities[2u]), traits_type::to_version(entt::tombstone));
set.emplace(entities[0u]);
set.emplace(entities[1u]);
set.emplace(entities[2u]);
set.push(entities[0u]);
set.push(entities[1u]);
set.push(entities[2u]);
std::swap(entities[1u], entities[2u]);
set.erase(entities, entities + 2u);
@ -527,9 +533,9 @@ TEST(SparseSet, StableErase) {
ASSERT_EQ(set.size(), 0u);
ASSERT_EQ(set.current(entities[2u]), traits_type::to_version(entt::tombstone));
set.emplace(entities[0u]);
set.emplace(entities[1u]);
set.emplace(entities[2u]);
set.push(entities[0u]);
set.push(entities[1u]);
set.push(entities[2u]);
set.erase(entities[2u]);
@ -546,13 +552,13 @@ TEST(SparseSet, StableErase) {
ASSERT_EQ(set.current(entities[2u]), traits_type::to_version(entt::tombstone));
ASSERT_TRUE(*set.begin() == entt::tombstone);
set.emplace(entities[0u]);
set.push(entities[0u]);
ASSERT_EQ(*++set.begin(), entities[0u]);
set.emplace(entities[1u]);
set.emplace(entities[2u]);
set.emplace(entt::entity{0});
set.push(entities[1u]);
set.push(entities[2u]);
set.push(entt::entity{0});
ASSERT_EQ(set.size(), 4u);
ASSERT_EQ(*set.begin(), entt::entity{0});
@ -580,8 +586,8 @@ TEST(SparseSet, CrossStableErase) {
entt::sparse_set other{entt::deletion_policy::in_place};
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
set.insert(std::begin(entities), std::end(entities));
other.emplace(entities[1u]);
set.push(std::begin(entities), std::end(entities));
other.push(entities[1u]);
set.erase(other.begin(), other.end());
ASSERT_TRUE(set.contains(entities[0u]));
@ -599,11 +605,11 @@ TEST(SparseSet, Remove) {
ASSERT_TRUE(set.empty());
ASSERT_EQ(set.remove(std::begin(entities), std::end(entities)), 0u);
ASSERT_EQ(set.remove(entities[1u]), 0u);
ASSERT_FALSE(set.remove(entities[1u]));
ASSERT_TRUE(set.empty());
set.insert(std::begin(entities), std::end(entities));
set.push(std::begin(entities), std::end(entities));
ASSERT_EQ(set.remove(set.begin(), set.end()), 3u);
ASSERT_TRUE(set.empty());
@ -611,7 +617,7 @@ TEST(SparseSet, Remove) {
ASSERT_EQ(set.current(entities[1u]), traits_type::to_version(entt::tombstone));
ASSERT_EQ(set.current(entities[2u]), traits_type::to_version(entt::tombstone));
set.insert(std::begin(entities), std::end(entities));
set.push(std::begin(entities), std::end(entities));
ASSERT_EQ(set.remove(entities, entities + 2u), 2u);
ASSERT_FALSE(set.empty());
@ -620,12 +626,12 @@ TEST(SparseSet, Remove) {
ASSERT_EQ(set.current(entities[2u]), traits_type::to_version(entities[2u]));
ASSERT_EQ(*set.begin(), entities[2u]);
ASSERT_EQ(set.remove(entities[2u]), 1u);
ASSERT_EQ(set.remove(entities[2u]), 0u);
ASSERT_TRUE(set.remove(entities[2u]));
ASSERT_FALSE(set.remove(entities[2u]));
ASSERT_TRUE(set.empty());
ASSERT_EQ(set.current(entities[2u]), traits_type::to_version(entt::tombstone));
set.insert(entities, entities + 2u);
set.push(entities, entities + 2u);
ASSERT_EQ(set.remove(std::begin(entities), std::end(entities)), 2u);
ASSERT_EQ(set.current(entities[0u]), traits_type::to_version(entt::tombstone));
@ -633,7 +639,7 @@ TEST(SparseSet, Remove) {
ASSERT_EQ(set.current(entities[2u]), traits_type::to_version(entt::tombstone));
ASSERT_TRUE(set.empty());
set.insert(std::begin(entities), std::end(entities));
set.push(std::begin(entities), std::end(entities));
std::swap(entities[1u], entities[2u]);
ASSERT_EQ(set.remove(entities, entities + 2u), 2u);
@ -641,9 +647,9 @@ TEST(SparseSet, Remove) {
ASSERT_FALSE(set.empty());
ASSERT_EQ(*set.begin(), entities[2u]);
ASSERT_EQ(set.remove(traits_type::construct(9, 0)), 0u);
ASSERT_EQ(set.remove(entt::tombstone), 0u);
ASSERT_EQ(set.remove(entt::null), 0u);
ASSERT_FALSE(set.remove(traits_type::construct(9, 0)));
ASSERT_FALSE(set.remove(entt::tombstone));
ASSERT_FALSE(set.remove(entt::null));
}
TEST(SparseSet, CrossRemove) {
@ -651,8 +657,8 @@ TEST(SparseSet, CrossRemove) {
entt::sparse_set other;
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
set.insert(std::begin(entities), std::end(entities));
other.emplace(entities[1u]);
set.push(std::begin(entities), std::end(entities));
other.push(entities[1u]);
set.remove(other.begin(), other.end());
ASSERT_TRUE(set.contains(entities[0u]));
@ -671,14 +677,14 @@ TEST(SparseSet, StableRemove) {
ASSERT_EQ(set.size(), 0u);
ASSERT_EQ(set.remove(std::begin(entities), std::end(entities)), 0u);
ASSERT_EQ(set.remove(entities[1u]), 0u);
ASSERT_FALSE(set.remove(entities[1u]));
ASSERT_TRUE(set.empty());
ASSERT_EQ(set.size(), 0u);
set.emplace(entities[0u]);
set.emplace(entities[1u]);
set.emplace(entities[2u]);
set.push(entities[0u]);
set.push(entities[1u]);
set.push(entities[2u]);
ASSERT_EQ(set.remove(set.begin(), set.end()), 3u);
ASSERT_EQ(set.remove(set.begin(), set.end()), 0u);
@ -692,9 +698,9 @@ TEST(SparseSet, StableRemove) {
ASSERT_TRUE(set.at(1u) == entt::tombstone);
ASSERT_TRUE(set.at(2u) == entt::tombstone);
set.emplace(entities[0u]);
set.emplace(entities[1u]);
set.emplace(entities[2u]);
set.push(entities[0u]);
set.push(entities[1u]);
set.push(entities[2u]);
ASSERT_EQ(set.remove(entities, entities + 2u), 2u);
ASSERT_EQ(set.remove(entities, entities + 2u), 0u);
@ -708,16 +714,16 @@ TEST(SparseSet, StableRemove) {
ASSERT_TRUE(set.at(0u) == entt::tombstone);
ASSERT_TRUE(set.at(1u) == entt::tombstone);
ASSERT_EQ(set.remove(entities[2u]), 1u);
ASSERT_EQ(set.remove(entities[2u]), 0u);
ASSERT_TRUE(set.remove(entities[2u]));
ASSERT_FALSE(set.remove(entities[2u]));
ASSERT_FALSE(set.empty());
ASSERT_EQ(set.size(), 3u);
ASSERT_EQ(set.current(entities[2u]), traits_type::to_version(entt::tombstone));
set.emplace(entities[0u]);
set.emplace(entities[1u]);
set.emplace(entities[2u]);
set.push(entities[0u]);
set.push(entities[1u]);
set.push(entities[2u]);
std::swap(entities[1u], entities[2u]);
@ -747,19 +753,19 @@ TEST(SparseSet, StableRemove) {
ASSERT_EQ(set.size(), 0u);
ASSERT_EQ(set.current(entities[2u]), traits_type::to_version(entt::tombstone));
set.emplace(entities[0u]);
set.emplace(entities[1u]);
set.emplace(entities[2u]);
set.push(entities[0u]);
set.push(entities[1u]);
set.push(entities[2u]);
ASSERT_EQ(set.remove(entities[2u]), 1u);
ASSERT_EQ(set.remove(entities[2u]), 0u);
ASSERT_TRUE(set.remove(entities[2u]));
ASSERT_FALSE(set.remove(entities[2u]));
ASSERT_NE(set.current(entities[0u]), traits_type::to_version(entt::tombstone));
ASSERT_NE(set.current(entities[1u]), traits_type::to_version(entt::tombstone));
ASSERT_EQ(set.current(entities[2u]), traits_type::to_version(entt::tombstone));
ASSERT_EQ(set.remove(entities[0u]), 1u);
ASSERT_EQ(set.remove(entities[1u]), 1u);
ASSERT_TRUE(set.remove(entities[0u]));
ASSERT_TRUE(set.remove(entities[1u]));
ASSERT_EQ(set.remove(entities, entities + 2u), 0u);
ASSERT_EQ(set.size(), 3u);
@ -768,13 +774,13 @@ TEST(SparseSet, StableRemove) {
ASSERT_EQ(set.current(entities[2u]), traits_type::to_version(entt::tombstone));
ASSERT_TRUE(*set.begin() == entt::tombstone);
set.emplace(entities[0u]);
set.push(entities[0u]);
ASSERT_EQ(*++set.begin(), entities[0u]);
set.emplace(entities[1u]);
set.emplace(entities[2u]);
set.emplace(entt::entity{0});
set.push(entities[1u]);
set.push(entities[2u]);
set.push(entt::entity{0});
ASSERT_EQ(set.size(), 4u);
ASSERT_EQ(*set.begin(), entt::entity{0});
@ -786,8 +792,8 @@ TEST(SparseSet, StableRemove) {
ASSERT_NE(set.current(entities[1u]), traits_type::to_version(entt::tombstone));
ASSERT_NE(set.current(entities[2u]), traits_type::to_version(entt::tombstone));
ASSERT_EQ(set.remove(traits_type::construct(9, 0)), 0u);
ASSERT_EQ(set.remove(entt::null), 0u);
ASSERT_FALSE(set.remove(traits_type::construct(9, 0)));
ASSERT_FALSE(set.remove(entt::null));
}
TEST(SparseSet, CrossStableRemove) {
@ -795,8 +801,8 @@ TEST(SparseSet, CrossStableRemove) {
entt::sparse_set other{entt::deletion_policy::in_place};
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
set.insert(std::begin(entities), std::end(entities));
other.emplace(entities[1u]);
set.push(std::begin(entities), std::end(entities));
other.push(entities[1u]);
set.remove(other.begin(), other.end());
ASSERT_TRUE(set.contains(entities[0u]));
@ -815,13 +821,13 @@ TEST(SparseSet, Compact) {
ASSERT_TRUE(set.empty());
ASSERT_EQ(set.size(), 0u);
set.emplace(entt::entity{0});
set.push(entt::entity{0});
set.compact();
ASSERT_FALSE(set.empty());
ASSERT_EQ(set.size(), 1u);
set.emplace(entt::entity{42});
set.push(entt::entity{42});
set.erase(entt::entity{0});
ASSERT_EQ(set.size(), 2u);
@ -832,7 +838,7 @@ TEST(SparseSet, Compact) {
ASSERT_EQ(set.size(), 1u);
ASSERT_EQ(set.index(entt::entity{42}), 0u);
set.emplace(entt::entity{0});
set.push(entt::entity{0});
set.compact();
ASSERT_EQ(set.size(), 2u);
@ -851,8 +857,8 @@ TEST(SparseSet, SwapEntity) {
entt::sparse_set set;
set.emplace(traits_type::construct(3, 5));
set.emplace(traits_type::construct(42, 99));
set.push(traits_type::construct(3, 5));
set.push(traits_type::construct(42, 99));
ASSERT_EQ(set.index(traits_type::construct(3, 5)), 0u);
ASSERT_EQ(set.index(traits_type::construct(42, 99)), 1u);
@ -878,9 +884,9 @@ ENTT_DEBUG_TEST(SparseSetDeathTest, SwapEntity) {
TEST(SparseSet, Clear) {
entt::sparse_set set{entt::deletion_policy::in_place};
set.emplace(entt::entity{3});
set.emplace(entt::entity{42});
set.emplace(entt::entity{9});
set.push(entt::entity{3});
set.push(entt::entity{42});
set.push(entt::entity{9});
set.erase(entt::entity{42});
ASSERT_FALSE(set.empty());
@ -895,9 +901,9 @@ TEST(SparseSet, Clear) {
ASSERT_EQ(set.find(entt::entity{3}), set.end());
ASSERT_EQ(set.find(entt::entity{9}), set.end());
set.emplace(entt::entity{3});
set.emplace(entt::entity{42});
set.emplace(entt::entity{9});
set.push(entt::entity{3});
set.push(entt::entity{42});
set.push(entt::entity{9});
ASSERT_FALSE(set.empty());
ASSERT_EQ(set.size(), 3u);
@ -913,6 +919,64 @@ TEST(SparseSet, Clear) {
ASSERT_EQ(set.find(entt::entity{9}), set.end());
}
TEST(SparseSet, Contiguous) {
entt::sparse_set swap_and_pop{entt::deletion_policy::swap_and_pop};
entt::sparse_set in_place{entt::deletion_policy::in_place};
const entt::entity entity{42};
const entt::entity other{3};
ASSERT_TRUE(swap_and_pop.contiguous());
ASSERT_TRUE(in_place.contiguous());
swap_and_pop.push(entity);
in_place.push(entity);
swap_and_pop.push(other);
in_place.push(other);
ASSERT_TRUE(swap_and_pop.contiguous());
ASSERT_TRUE(in_place.contiguous());
swap_and_pop.erase(entity);
in_place.erase(entity);
ASSERT_TRUE(swap_and_pop.contiguous());
ASSERT_FALSE(in_place.contiguous());
swap_and_pop.push(entity);
in_place.push(entity);
ASSERT_TRUE(swap_and_pop.contiguous());
ASSERT_TRUE(in_place.contiguous());
swap_and_pop.erase(other);
in_place.erase(other);
ASSERT_TRUE(swap_and_pop.contiguous());
ASSERT_FALSE(in_place.contiguous());
in_place.compact();
ASSERT_TRUE(swap_and_pop.contiguous());
ASSERT_TRUE(in_place.contiguous());
swap_and_pop.push(other);
in_place.push(other);
swap_and_pop.erase(entity);
in_place.erase(entity);
ASSERT_TRUE(swap_and_pop.contiguous());
ASSERT_FALSE(in_place.contiguous());
swap_and_pop.clear();
in_place.clear();
ASSERT_TRUE(swap_and_pop.contiguous());
ASSERT_TRUE(in_place.contiguous());
}
TEST(SparseSet, Iterator) {
using iterator = typename entt::sparse_set::iterator;
@ -921,13 +985,20 @@ TEST(SparseSet, Iterator) {
static_assert(std::is_same_v<iterator::reference, const entt::entity &>);
entt::sparse_set set;
set.emplace(entt::entity{3});
set.push(entt::entity{3});
iterator end{set.begin()};
iterator begin{};
ASSERT_EQ(end.data(), set.data());
ASSERT_EQ(begin.data(), nullptr);
begin = set.end();
std::swap(begin, end);
ASSERT_EQ(end.data(), set.data());
ASSERT_EQ(begin.data(), set.data());
ASSERT_EQ(begin, set.cbegin());
ASSERT_EQ(end, set.cend());
ASSERT_NE(begin, end);
@ -967,7 +1038,7 @@ TEST(SparseSet, Iterator) {
ASSERT_EQ(begin.index(), 0);
ASSERT_EQ(end.index(), -1);
set.emplace(entt::entity{42});
set.push(entt::entity{42});
begin = set.begin();
ASSERT_EQ(begin.index(), 1);
@ -985,7 +1056,7 @@ TEST(SparseSet, ReverseIterator) {
static_assert(std::is_same_v<reverse_iterator::reference, const entt::entity &>);
entt::sparse_set set;
set.emplace(entt::entity{3});
set.push(entt::entity{3});
reverse_iterator end{set.rbegin()};
reverse_iterator begin{};
@ -1031,7 +1102,7 @@ TEST(SparseSet, ReverseIterator) {
ASSERT_EQ(begin.base().index(), -1);
ASSERT_EQ(end.base().index(), 0);
set.emplace(entt::entity{42});
set.push(entt::entity{42});
end = set.rend();
ASSERT_EQ(begin.base().index(), -1);
@ -1045,9 +1116,9 @@ TEST(SparseSet, Find) {
using traits_type = entt::entt_traits<entt::entity>;
entt::sparse_set set;
set.emplace(entt::entity{3});
set.emplace(entt::entity{42});
set.emplace(traits_type::construct(99, 1));
set.push(entt::entity{3});
set.push(entt::entity{42});
set.push(traits_type::construct(99, 1));
ASSERT_NE(set.find(entt::entity{3}), set.end());
ASSERT_NE(set.find(entt::entity{42}), set.end());
@ -1069,9 +1140,9 @@ TEST(SparseSet, Find) {
TEST(SparseSet, Data) {
entt::sparse_set set;
set.emplace(entt::entity{3});
set.emplace(entt::entity{12});
set.emplace(entt::entity{42});
set.push(entt::entity{3});
set.push(entt::entity{12});
set.push(entt::entity{42});
ASSERT_EQ(set.index(entt::entity{3}), 0u);
ASSERT_EQ(set.index(entt::entity{12}), 1u);
@ -1086,7 +1157,7 @@ TEST(SparseSet, SortOrdered) {
entt::sparse_set set;
entt::entity entities[5u]{entt::entity{42}, entt::entity{12}, entt::entity{9}, entt::entity{7}, entt::entity{3}};
set.insert(std::begin(entities), std::end(entities));
set.push(std::begin(entities), std::end(entities));
set.sort(std::less{});
ASSERT_TRUE(std::equal(std::rbegin(entities), std::rend(entities), set.begin(), set.end()));
@ -1096,7 +1167,7 @@ TEST(SparseSet, SortReverse) {
entt::sparse_set set;
entt::entity entities[5u]{entt::entity{3}, entt::entity{7}, entt::entity{9}, entt::entity{12}, entt::entity{42}};
set.insert(std::begin(entities), std::end(entities));
set.push(std::begin(entities), std::end(entities));
set.sort(std::less{});
ASSERT_TRUE(std::equal(std::begin(entities), std::end(entities), set.begin(), set.end()));
@ -1106,7 +1177,7 @@ TEST(SparseSet, SortUnordered) {
entt::sparse_set set;
entt::entity entities[5u]{entt::entity{9}, entt::entity{7}, entt::entity{3}, entt::entity{12}, entt::entity{42}};
set.insert(std::begin(entities), std::end(entities));
set.push(std::begin(entities), std::end(entities));
set.sort(std::less{});
auto begin = set.begin();
@ -1124,7 +1195,7 @@ TEST(SparseSet, SortRange) {
entt::sparse_set set{entt::deletion_policy::in_place};
entt::entity entities[5u]{entt::entity{7}, entt::entity{9}, entt::entity{3}, entt::entity{12}, entt::entity{42}};
set.insert(std::begin(entities), std::end(entities));
set.push(std::begin(entities), std::end(entities));
set.erase(entities[0u]);
ASSERT_EQ(set.size(), 5u);
@ -1139,7 +1210,7 @@ TEST(SparseSet, SortRange) {
set.clear();
set.compact();
set.insert(std::begin(entities), std::end(entities));
set.push(std::begin(entities), std::end(entities));
set.sort_n(0u, std::less{});
ASSERT_TRUE(std::equal(std::rbegin(entities), std::rend(entities), set.begin(), set.end()));
@ -1167,7 +1238,7 @@ ENTT_DEBUG_TEST(SparseSetDeathTest, SortRange) {
entt::sparse_set set{entt::deletion_policy::in_place};
entt::entity entity{42};
set.emplace(entity);
set.push(entity);
set.erase(entity);
ASSERT_DEATH(set.sort_n(0u, std::less{});, "");
@ -1179,11 +1250,11 @@ TEST(SparseSet, RespectDisjoint) {
entt::sparse_set rhs;
entt::entity lhs_entities[3u]{entt::entity{3}, entt::entity{12}, entt::entity{42}};
lhs.insert(std::begin(lhs_entities), std::end(lhs_entities));
lhs.push(std::begin(lhs_entities), std::end(lhs_entities));
ASSERT_TRUE(std::equal(std::rbegin(lhs_entities), std::rend(lhs_entities), lhs.begin(), lhs.end()));
lhs.respect(rhs);
lhs.sort_as(rhs);
ASSERT_TRUE(std::equal(std::rbegin(lhs_entities), std::rend(lhs_entities), lhs.begin(), lhs.end()));
}
@ -1193,15 +1264,15 @@ TEST(SparseSet, RespectOverlap) {
entt::sparse_set rhs;
entt::entity lhs_entities[3u]{entt::entity{3}, entt::entity{12}, entt::entity{42}};
lhs.insert(std::begin(lhs_entities), std::end(lhs_entities));
lhs.push(std::begin(lhs_entities), std::end(lhs_entities));
entt::entity rhs_entities[1u]{entt::entity{12}};
rhs.insert(std::begin(rhs_entities), std::end(rhs_entities));
rhs.push(std::begin(rhs_entities), std::end(rhs_entities));
ASSERT_TRUE(std::equal(std::rbegin(lhs_entities), std::rend(lhs_entities), lhs.begin(), lhs.end()));
ASSERT_TRUE(std::equal(std::rbegin(rhs_entities), std::rend(rhs_entities), rhs.begin(), rhs.end()));
lhs.respect(rhs);
lhs.sort_as(rhs);
auto begin = lhs.begin();
auto end = lhs.end();
@ -1217,15 +1288,15 @@ TEST(SparseSet, RespectOrdered) {
entt::sparse_set rhs;
entt::entity lhs_entities[5u]{entt::entity{1}, entt::entity{2}, entt::entity{3}, entt::entity{4}, entt::entity{5}};
lhs.insert(std::begin(lhs_entities), std::end(lhs_entities));
lhs.push(std::begin(lhs_entities), std::end(lhs_entities));
entt::entity rhs_entities[6u]{entt::entity{6}, entt::entity{1}, entt::entity{2}, entt::entity{3}, entt::entity{4}, entt::entity{5}};
rhs.insert(std::begin(rhs_entities), std::end(rhs_entities));
rhs.push(std::begin(rhs_entities), std::end(rhs_entities));
ASSERT_TRUE(std::equal(std::rbegin(lhs_entities), std::rend(lhs_entities), lhs.begin(), lhs.end()));
ASSERT_TRUE(std::equal(std::rbegin(rhs_entities), std::rend(rhs_entities), rhs.begin(), rhs.end()));
rhs.respect(lhs);
rhs.sort_as(lhs);
ASSERT_TRUE(std::equal(std::rbegin(rhs_entities), std::rend(rhs_entities), rhs.begin(), rhs.end()));
}
@ -1235,15 +1306,15 @@ TEST(SparseSet, RespectReverse) {
entt::sparse_set rhs;
entt::entity lhs_entities[5u]{entt::entity{1}, entt::entity{2}, entt::entity{3}, entt::entity{4}, entt::entity{5}};
lhs.insert(std::begin(lhs_entities), std::end(lhs_entities));
lhs.push(std::begin(lhs_entities), std::end(lhs_entities));
entt::entity rhs_entities[6u]{entt::entity{5}, entt::entity{4}, entt::entity{3}, entt::entity{2}, entt::entity{1}, entt::entity{6}};
rhs.insert(std::begin(rhs_entities), std::end(rhs_entities));
rhs.push(std::begin(rhs_entities), std::end(rhs_entities));
ASSERT_TRUE(std::equal(std::rbegin(lhs_entities), std::rend(lhs_entities), lhs.begin(), lhs.end()));
ASSERT_TRUE(std::equal(std::rbegin(rhs_entities), std::rend(rhs_entities), rhs.begin(), rhs.end()));
rhs.respect(lhs);
rhs.sort_as(lhs);
auto begin = rhs.begin();
auto end = rhs.end();
@ -1262,15 +1333,15 @@ TEST(SparseSet, RespectUnordered) {
entt::sparse_set rhs;
entt::entity lhs_entities[5u]{entt::entity{1}, entt::entity{2}, entt::entity{3}, entt::entity{4}, entt::entity{5}};
lhs.insert(std::begin(lhs_entities), std::end(lhs_entities));
lhs.push(std::begin(lhs_entities), std::end(lhs_entities));
entt::entity rhs_entities[6u]{entt::entity{3}, entt::entity{2}, entt::entity{6}, entt::entity{1}, entt::entity{4}, entt::entity{5}};
rhs.insert(std::begin(rhs_entities), std::end(rhs_entities));
rhs.push(std::begin(rhs_entities), std::end(rhs_entities));
ASSERT_TRUE(std::equal(std::rbegin(lhs_entities), std::rend(lhs_entities), lhs.begin(), lhs.end()));
ASSERT_TRUE(std::equal(std::rbegin(rhs_entities), std::rend(rhs_entities), rhs.begin(), rhs.end()));
rhs.respect(lhs);
rhs.sort_as(lhs);
auto begin = rhs.begin();
auto end = rhs.end();
@ -1291,15 +1362,15 @@ TEST(SparseSet, RespectInvalid) {
entt::sparse_set rhs;
entt::entity lhs_entities[3u]{entt::entity{1}, entt::entity{2}, traits_type::construct(3, 1)};
lhs.insert(std::begin(lhs_entities), std::end(lhs_entities));
lhs.push(std::begin(lhs_entities), std::end(lhs_entities));
entt::entity rhs_entities[3u]{entt::entity{2}, entt::entity{1}, traits_type::construct(3, 2)};
rhs.insert(std::begin(rhs_entities), std::end(rhs_entities));
rhs.push(std::begin(rhs_entities), std::end(rhs_entities));
ASSERT_TRUE(std::equal(std::rbegin(lhs_entities), std::rend(lhs_entities), lhs.begin(), lhs.end()));
ASSERT_TRUE(std::equal(std::rbegin(rhs_entities), std::rend(rhs_entities), rhs.begin(), rhs.end()));
rhs.respect(lhs);
rhs.sort_as(lhs);
auto begin = rhs.begin();
auto end = rhs.end();
@ -1315,7 +1386,7 @@ TEST(SparseSet, RespectInvalid) {
TEST(SparseSet, CanModifyDuringIteration) {
entt::sparse_set set;
set.emplace(entt::entity{0});
set.push(entt::entity{0});
ASSERT_EQ(set.capacity(), 1u);
@ -1338,8 +1409,8 @@ TEST(SparseSet, CustomAllocator) {
ASSERT_EQ(set.capacity(), 1u);
set.emplace(entt::entity{0});
set.emplace(entt::entity{1});
set.push(entt::entity{0});
set.push(entt::entity{1});
entt::basic_sparse_set<entt::entity, test::throwing_allocator<entt::entity>> other{std::move(set), allocator};
@ -1389,11 +1460,11 @@ TEST(SparseSet, ThrowingAllocator) {
test::throwing_allocator<entt::entity>::trigger_on_allocate = true;
ASSERT_THROW(set.emplace(entt::entity{0}), test::throwing_allocator<entt::entity>::exception_type);
ASSERT_THROW(set.push(entt::entity{0}), test::throwing_allocator<entt::entity>::exception_type);
ASSERT_EQ(set.extent(), traits_type::page_size);
ASSERT_EQ(set.capacity(), 0u);
set.emplace(entt::entity{0});
set.push(entt::entity{0});
test::throwing_allocator<entt::entity>::trigger_on_allocate = true;
ASSERT_THROW(set.reserve(2u), test::throwing_allocator<entt::entity>::exception_type);
@ -1403,7 +1474,7 @@ TEST(SparseSet, ThrowingAllocator) {
test::throwing_allocator<entt::entity>::trigger_on_allocate = true;
ASSERT_THROW(set.emplace(entt::entity{1}), test::throwing_allocator<entt::entity>::exception_type);
ASSERT_THROW(set.push(entt::entity{1}), test::throwing_allocator<entt::entity>::exception_type);
ASSERT_EQ(set.extent(), traits_type::page_size);
ASSERT_TRUE(set.contains(entt::entity{0}));
ASSERT_FALSE(set.contains(entt::entity{1}));
@ -1412,7 +1483,7 @@ TEST(SparseSet, ThrowingAllocator) {
entt::entity entities[2u]{entt::entity{1}, entt::entity{traits_type::page_size}};
test::throwing_allocator<entt::entity>::trigger_after_allocate = true;
ASSERT_THROW(set.insert(std::begin(entities), std::end(entities)), test::throwing_allocator<entt::entity>::exception_type);
ASSERT_THROW(set.push(std::begin(entities), std::end(entities)), test::throwing_allocator<entt::entity>::exception_type);
ASSERT_EQ(set.extent(), 2 * traits_type::page_size);
ASSERT_TRUE(set.contains(entt::entity{0}));
ASSERT_TRUE(set.contains(entt::entity{1}));
@ -1420,7 +1491,7 @@ TEST(SparseSet, ThrowingAllocator) {
ASSERT_EQ(set.capacity(), 2u);
ASSERT_EQ(set.size(), 2u);
set.emplace(entities[1u]);
set.push(entities[1u]);
ASSERT_TRUE(set.contains(entt::entity{traits_type::page_size}));
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,628 @@
#include <type_traits>
#include <utility>
#include <gtest/gtest.h>
#include <entt/entity/storage.hpp>
#include "../common/config.h"
#include "../common/throwing_allocator.hpp"
TEST(StorageEntity, TypeAndPolicy) {
entt::storage<entt::entity> pool;
ASSERT_EQ(pool.type(), entt::type_id<entt::entity>());
ASSERT_EQ(pool.policy(), entt::deletion_policy::swap_and_pop);
}
TEST(StorageEntity, Functionalities) {
entt::entity entities[2u]{entt::entity{0}, entt::entity{1}};
entt::storage<entt::entity> pool;
ASSERT_TRUE(pool.empty());
ASSERT_EQ(pool.size(), 0u);
ASSERT_EQ(pool.in_use(), 0u);
ASSERT_EQ(*pool.push(entt::null), entities[0u]);
ASSERT_EQ(*pool.push(entt::tombstone), entities[1u]);
ASSERT_FALSE(pool.empty());
ASSERT_EQ(pool.size(), 2u);
ASSERT_EQ(pool.in_use(), 2u);
pool.in_use(1u);
ASSERT_FALSE(pool.empty());
ASSERT_EQ(pool.size(), 2u);
ASSERT_EQ(pool.in_use(), 1u);
ASSERT_NO_THROW(pool.get(entities[0u]));
ASSERT_EQ(pool.get_as_tuple(entities[0u]), std::tuple<>{});
pool.erase(entities[0u]);
ASSERT_FALSE(pool.empty());
ASSERT_EQ(pool.size(), 2u);
ASSERT_EQ(pool.in_use(), 0u);
}
ENTT_DEBUG_TEST(StorageEntityDeathTest, Get) {
entt::storage<entt::entity> pool;
pool.emplace(entt::entity{99});
ASSERT_DEATH(pool.get(entt::entity{3}), "");
ASSERT_DEATH([[maybe_unused]] auto tup = pool.get_as_tuple(entt::entity{3}), "");
ASSERT_NO_THROW(pool.get(entt::entity{99}));
ASSERT_NO_THROW([[maybe_unused]] auto tup = pool.get_as_tuple(entt::entity{99}));
pool.erase(entt::entity{99});
ASSERT_DEATH(pool.get(entt::entity{99}), "");
ASSERT_DEATH([[maybe_unused]] auto tup = pool.get_as_tuple(entt::entity{99}), "");
}
TEST(StorageEntity, Move) {
entt::storage<entt::entity> pool;
pool.push(entt::entity{1});
ASSERT_EQ(pool.size(), 2u);
ASSERT_EQ(pool.in_use(), 1u);
ASSERT_TRUE(std::is_move_constructible_v<decltype(pool)>);
ASSERT_TRUE(std::is_move_assignable_v<decltype(pool)>);
entt::storage<entt::entity> other{std::move(pool)};
ASSERT_EQ(pool.size(), 0u);
ASSERT_EQ(other.size(), 2u);
ASSERT_EQ(pool.in_use(), 0u);
ASSERT_EQ(other.in_use(), 1u);
ASSERT_EQ(pool.at(0u), static_cast<entt::entity>(entt::null));
ASSERT_EQ(other.at(0u), entt::entity{1});
pool = std::move(other);
ASSERT_EQ(pool.size(), 2u);
ASSERT_EQ(other.size(), 0u);
ASSERT_EQ(pool.in_use(), 1u);
ASSERT_EQ(other.in_use(), 0u);
ASSERT_EQ(pool.at(0u), entt::entity{1});
ASSERT_EQ(other.at(0u), static_cast<entt::entity>(entt::null));
other = entt::storage<entt::entity>{};
other.push(entt::entity{3});
other = std::move(pool);
ASSERT_EQ(pool.size(), 0u);
ASSERT_EQ(other.size(), 2u);
ASSERT_EQ(pool.in_use(), 0u);
ASSERT_EQ(other.in_use(), 1u);
ASSERT_EQ(pool.at(0u), static_cast<entt::entity>(entt::null));
ASSERT_EQ(other.at(0u), entt::entity{1});
other.clear();
ASSERT_EQ(other.size(), 0u);
ASSERT_EQ(other.in_use(), 0u);
ASSERT_EQ(*other.push(entt::null), entt::entity{0});
}
TEST(StorageEntity, Swap) {
entt::storage<entt::entity> pool;
entt::storage<entt::entity> other;
pool.push(entt::entity{1});
other.push(entt::entity{2});
other.push(entt::entity{0});
other.erase(entt::entity{2});
ASSERT_EQ(pool.size(), 2u);
ASSERT_EQ(other.size(), 3u);
ASSERT_EQ(pool.in_use(), 1u);
ASSERT_EQ(other.in_use(), 1u);
pool.swap(other);
ASSERT_EQ(pool.size(), 3u);
ASSERT_EQ(other.size(), 2u);
ASSERT_EQ(pool.in_use(), 1u);
ASSERT_EQ(other.in_use(), 1u);
ASSERT_EQ(pool.at(0u), entt::entity{0});
ASSERT_EQ(other.at(0u), entt::entity{1});
pool.clear();
other.clear();
ASSERT_EQ(pool.size(), 0u);
ASSERT_EQ(other.size(), 0u);
ASSERT_EQ(pool.in_use(), 0u);
ASSERT_EQ(other.in_use(), 0u);
ASSERT_EQ(*other.push(entt::null), entt::entity{0});
}
TEST(StorageEntity, Push) {
using traits_type = entt::entt_traits<entt::entity>;
entt::storage<entt::entity> pool;
ASSERT_EQ(*pool.push(entt::null), entt::entity{0});
ASSERT_EQ(*pool.push(entt::tombstone), entt::entity{1});
ASSERT_EQ(*pool.push(entt::entity{0}), entt::entity{2});
ASSERT_EQ(*pool.push(traits_type::construct(1, 1)), entt::entity{3});
ASSERT_EQ(*pool.push(traits_type::construct(5, 3)), traits_type::construct(5, 3));
ASSERT_LT(pool.index(entt::entity{0}), pool.in_use());
ASSERT_LT(pool.index(entt::entity{1}), pool.in_use());
ASSERT_LT(pool.index(entt::entity{2}), pool.in_use());
ASSERT_LT(pool.index(entt::entity{3}), pool.in_use());
ASSERT_GE(pool.index(entt::entity{4}), pool.in_use());
ASSERT_LT(pool.index(traits_type::construct(5, 3)), pool.in_use());
ASSERT_EQ(*pool.push(traits_type::construct(4, 42)), traits_type::construct(4, 42));
ASSERT_EQ(*pool.push(traits_type::construct(4, 43)), entt::entity{6});
entt::entity entities[2u]{entt::entity{1}, traits_type::construct(5, 3)};
pool.erase(entities, entities + 2u);
pool.erase(entt::entity{2});
ASSERT_EQ(pool.current(entities[0u]), 1);
ASSERT_EQ(pool.current(entities[1u]), 4);
ASSERT_EQ(pool.current(entt::entity{2}), 1);
ASSERT_LT(pool.index(entt::entity{0}), pool.in_use());
ASSERT_GE(pool.index(traits_type::construct(1, 1)), pool.in_use());
ASSERT_GE(pool.index(traits_type::construct(2, 1)), pool.in_use());
ASSERT_LT(pool.index(entt::entity{3}), pool.in_use());
ASSERT_LT(pool.index(traits_type::construct(4, 42)), pool.in_use());
ASSERT_GE(pool.index(traits_type::construct(5, 4)), pool.in_use());
ASSERT_EQ(*pool.push(entt::null), traits_type::construct(2, 1));
ASSERT_EQ(*pool.push(traits_type::construct(1, 3)), traits_type::construct(1, 3));
ASSERT_EQ(*pool.push(entt::null), traits_type::construct(5, 4));
ASSERT_EQ(*pool.push(entt::null), entt::entity{7});
}
TEST(StorageEntity, Emplace) {
using traits_type = entt::entt_traits<entt::entity>;
entt::storage<entt::entity> pool;
entt::entity entities[2u]{};
ASSERT_EQ(pool.emplace(), entt::entity{0});
ASSERT_EQ(pool.emplace(entt::null), entt::entity{1});
ASSERT_EQ(pool.emplace(entt::tombstone), entt::entity{2});
ASSERT_EQ(pool.emplace(entt::entity{0}), entt::entity{3});
ASSERT_EQ(pool.emplace(traits_type::construct(1, 1)), entt::entity{4});
ASSERT_EQ(pool.emplace(traits_type::construct(6, 3)), traits_type::construct(6, 3));
ASSERT_LT(pool.index(entt::entity{0}), pool.in_use());
ASSERT_LT(pool.index(entt::entity{1}), pool.in_use());
ASSERT_LT(pool.index(entt::entity{2}), pool.in_use());
ASSERT_LT(pool.index(entt::entity{3}), pool.in_use());
ASSERT_LT(pool.index(entt::entity{4}), pool.in_use());
ASSERT_GE(pool.index(entt::entity{5}), pool.in_use());
ASSERT_LT(pool.index(traits_type::construct(6, 3)), pool.in_use());
ASSERT_EQ(pool.emplace(traits_type::construct(5, 42)), traits_type::construct(5, 42));
ASSERT_EQ(pool.emplace(traits_type::construct(5, 43)), entt::entity{7});
pool.erase(entt::entity{2});
ASSERT_EQ(pool.emplace(), traits_type::construct(2, 1));
pool.erase(traits_type::construct(2, 1));
pool.insert(entities, entities + 2u);
ASSERT_EQ(entities[0u], traits_type::construct(2, 2));
ASSERT_EQ(entities[1u], entt::entity{8});
}
TEST(StorageEntity, Patch) {
entt::storage<entt::entity> pool;
const auto entity = pool.emplace();
int counter = 0;
auto callback = [&counter]() { ++counter; };
ASSERT_EQ(counter, 0);
pool.patch(entity);
pool.patch(entity, callback);
pool.patch(entity, callback, callback);
ASSERT_EQ(counter, 3);
}
ENTT_DEBUG_TEST(StorageEntityDeathTest, Patch) {
entt::storage<entt::entity> pool;
ASSERT_DEATH(pool.patch(entt::null), "");
}
TEST(StorageEntity, Insert) {
entt::storage<entt::entity> pool;
entt::entity entities[2u]{};
pool.insert(std::begin(entities), std::end(entities));
ASSERT_TRUE(pool.contains(entities[0u]));
ASSERT_TRUE(pool.contains(entities[1u]));
ASSERT_FALSE(pool.empty());
ASSERT_EQ(pool.size(), 2u);
ASSERT_EQ(pool.in_use(), 2u);
pool.erase(std::begin(entities), std::end(entities));
ASSERT_FALSE(pool.empty());
ASSERT_EQ(pool.size(), 2u);
ASSERT_EQ(pool.in_use(), 0u);
pool.insert(entities, entities + 1u);
ASSERT_TRUE(pool.contains(entities[0u]));
ASSERT_FALSE(pool.contains(entities[1u]));
ASSERT_FALSE(pool.empty());
ASSERT_EQ(pool.size(), 2u);
ASSERT_EQ(pool.in_use(), 1u);
}
TEST(StorageEntity, Pack) {
entt::storage<entt::entity> pool;
entt::entity entities[3u]{entt::entity{1}, entt::entity{3}, entt::entity{42}};
pool.push(entities, entities + 3u);
std::swap(entities[0u], entities[1u]);
const auto len = pool.pack(entities + 1u, entities + 3u);
auto it = pool.each().cbegin().base();
ASSERT_NE(it, pool.cbegin());
ASSERT_NE(it, pool.cend());
ASSERT_EQ(len, 2u);
ASSERT_NE(it + len, pool.cend());
ASSERT_EQ(it + len + 1u, pool.cend());
ASSERT_EQ(*it++, entities[1u]);
ASSERT_EQ(*it++, entities[2u]);
ASSERT_NE(it, pool.cend());
ASSERT_EQ(*it++, entities[0u]);
ASSERT_EQ(it, pool.cend());
}
TEST(StorageEntity, Iterable) {
using iterator = typename entt::storage<entt::entity>::iterable::iterator;
static_assert(std::is_same_v<iterator::value_type, std::tuple<entt::entity>>);
static_assert(std::is_same_v<typename iterator::pointer, entt::input_iterator_pointer<std::tuple<entt::entity>>>);
static_assert(std::is_same_v<typename iterator::reference, typename iterator::value_type>);
entt::storage<entt::entity> pool;
pool.emplace(entt::entity{1});
pool.emplace(entt::entity{3});
pool.emplace(entt::entity{42});
pool.erase(entt::entity{3});
auto iterable = pool.each();
iterator end{iterable.begin()};
iterator begin{};
begin = iterable.end();
std::swap(begin, end);
ASSERT_EQ(begin, iterable.begin());
ASSERT_EQ(end, iterable.end());
ASSERT_NE(begin, end);
ASSERT_NE(begin.base(), pool.begin());
ASSERT_EQ(begin.base(), pool.end() - pool.in_use());
ASSERT_EQ(end.base(), pool.end());
ASSERT_EQ(std::get<0>(*begin.operator->().operator->()), entt::entity{42});
ASSERT_EQ(std::get<0>(*begin), entt::entity{42});
ASSERT_EQ(begin++, iterable.begin());
ASSERT_EQ(begin.base(), pool.end() - 1);
ASSERT_EQ(++begin, iterable.end());
ASSERT_EQ(begin.base(), pool.end());
for(auto [entity]: iterable) {
static_assert(std::is_same_v<decltype(entity), entt::entity>);
ASSERT_TRUE(entity != entt::entity{3});
}
}
TEST(StorageEntity, ConstIterable) {
using iterator = typename entt::storage<entt::entity>::const_iterable::iterator;
static_assert(std::is_same_v<iterator::value_type, std::tuple<entt::entity>>);
static_assert(std::is_same_v<typename iterator::pointer, entt::input_iterator_pointer<std::tuple<entt::entity>>>);
static_assert(std::is_same_v<typename iterator::reference, typename iterator::value_type>);
entt::storage<entt::entity> pool;
pool.emplace(entt::entity{1});
pool.emplace(entt::entity{3});
pool.emplace(entt::entity{42});
pool.erase(entt::entity{3});
auto iterable = std::as_const(pool).each();
iterator end{iterable.cbegin()};
iterator begin{};
begin = iterable.cend();
std::swap(begin, end);
ASSERT_EQ(begin, iterable.cbegin());
ASSERT_EQ(end, iterable.cend());
ASSERT_NE(begin, end);
ASSERT_NE(begin.base(), pool.begin());
ASSERT_EQ(begin.base(), pool.end() - pool.in_use());
ASSERT_EQ(end.base(), pool.end());
ASSERT_EQ(std::get<0>(*begin.operator->().operator->()), entt::entity{42});
ASSERT_EQ(std::get<0>(*begin), entt::entity{42});
ASSERT_EQ(begin++, iterable.begin());
ASSERT_EQ(begin.base(), pool.end() - 1);
ASSERT_EQ(++begin, iterable.end());
ASSERT_EQ(begin.base(), pool.end());
for(auto [entity]: iterable) {
static_assert(std::is_same_v<decltype(entity), entt::entity>);
ASSERT_TRUE(entity != entt::entity{3});
}
}
TEST(StorageEntity, IterableIteratorConversion) {
entt::storage<entt::entity> pool;
pool.emplace(entt::entity{3});
typename entt::storage<entt::entity>::iterable::iterator it = pool.each().begin();
typename entt::storage<entt::entity>::const_iterable::iterator cit = it;
static_assert(std::is_same_v<decltype(*it), std::tuple<entt::entity>>);
static_assert(std::is_same_v<decltype(*cit), std::tuple<entt::entity>>);
ASSERT_EQ(it, cit);
ASSERT_NE(++cit, it);
}
TEST(StorageEntity, IterableAlgorithmCompatibility) {
entt::storage<entt::entity> pool;
pool.emplace(entt::entity{3});
const auto iterable = pool.each();
const auto it = std::find_if(iterable.begin(), iterable.end(), [](auto args) { return std::get<0>(args) == entt::entity{3}; });
ASSERT_EQ(std::get<0>(*it), entt::entity{3});
}
TEST(StorageEntity, ReverseIterable) {
using iterator = typename entt::storage<entt::entity>::reverse_iterable::iterator;
static_assert(std::is_same_v<iterator::value_type, std::tuple<entt::entity>>);
static_assert(std::is_same_v<typename iterator::pointer, entt::input_iterator_pointer<std::tuple<entt::entity>>>);
static_assert(std::is_same_v<typename iterator::reference, typename iterator::value_type>);
entt::storage<entt::entity> pool;
pool.emplace(entt::entity{1});
pool.emplace(entt::entity{3});
pool.emplace(entt::entity{42});
pool.erase(entt::entity{3});
auto iterable = pool.reach();
iterator end{iterable.begin()};
iterator begin{};
begin = iterable.end();
std::swap(begin, end);
ASSERT_EQ(begin, iterable.begin());
ASSERT_EQ(end, iterable.end());
ASSERT_NE(begin, end);
ASSERT_EQ(begin.base(), pool.rbegin());
ASSERT_EQ(end.base(), pool.rbegin() + pool.in_use());
ASSERT_NE(end.base(), pool.rend());
ASSERT_EQ(std::get<0>(*begin.operator->().operator->()), entt::entity{1});
ASSERT_EQ(std::get<0>(*begin), entt::entity{1});
ASSERT_EQ(begin++, iterable.begin());
ASSERT_EQ(begin.base(), pool.rbegin() + 1);
ASSERT_EQ(++begin, iterable.end());
ASSERT_EQ(begin.base(), pool.rbegin() + 2);
for(auto [entity]: iterable) {
static_assert(std::is_same_v<decltype(entity), entt::entity>);
ASSERT_TRUE(entity != entt::entity{3});
}
}
TEST(StorageEntity, ReverseConstIterable) {
using iterator = typename entt::storage<entt::entity>::const_reverse_iterable::iterator;
static_assert(std::is_same_v<iterator::value_type, std::tuple<entt::entity>>);
static_assert(std::is_same_v<typename iterator::pointer, entt::input_iterator_pointer<std::tuple<entt::entity>>>);
static_assert(std::is_same_v<typename iterator::reference, typename iterator::value_type>);
entt::storage<entt::entity> pool;
pool.emplace(entt::entity{1});
pool.emplace(entt::entity{3});
pool.emplace(entt::entity{42});
pool.erase(entt::entity{3});
auto iterable = std::as_const(pool).reach();
iterator end{iterable.cbegin()};
iterator begin{};
begin = iterable.cend();
std::swap(begin, end);
ASSERT_EQ(begin, iterable.cbegin());
ASSERT_EQ(end, iterable.cend());
ASSERT_NE(begin, end);
ASSERT_EQ(begin.base(), pool.rbegin());
ASSERT_EQ(end.base(), pool.rbegin() + pool.in_use());
ASSERT_NE(end.base(), pool.rend());
ASSERT_EQ(std::get<0>(*begin.operator->().operator->()), entt::entity{1});
ASSERT_EQ(std::get<0>(*begin), entt::entity{1});
ASSERT_EQ(begin++, iterable.begin());
ASSERT_EQ(begin.base(), pool.rbegin() + 1);
ASSERT_EQ(++begin, iterable.end());
ASSERT_EQ(begin.base(), pool.rbegin() + 2);
for(auto [entity]: iterable) {
static_assert(std::is_same_v<decltype(entity), entt::entity>);
ASSERT_TRUE(entity != entt::entity{3});
}
}
TEST(StorageEntity, ReverseIterableIteratorConversion) {
entt::storage<entt::entity> pool;
pool.emplace(entt::entity{3});
typename entt::storage<entt::entity>::reverse_iterable::iterator it = pool.reach().begin();
typename entt::storage<entt::entity>::const_reverse_iterable::iterator cit = it;
static_assert(std::is_same_v<decltype(*it), std::tuple<entt::entity>>);
static_assert(std::is_same_v<decltype(*cit), std::tuple<entt::entity>>);
ASSERT_EQ(it, cit);
ASSERT_NE(++cit, it);
}
TEST(StorageEntity, ReverseIterableAlgorithmCompatibility) {
entt::storage<entt::entity> pool;
pool.emplace(entt::entity{3});
const auto iterable = pool.reach();
const auto it = std::find_if(iterable.begin(), iterable.end(), [](auto args) { return std::get<0>(args) == entt::entity{3}; });
ASSERT_EQ(std::get<0>(*it), entt::entity{3});
}
TEST(StorageEntity, SwapElements) {
entt::storage<entt::entity> pool;
pool.push(entt::entity{0});
pool.push(entt::entity{1});
ASSERT_EQ(pool.size(), 2u);
ASSERT_EQ(pool.in_use(), 2u);
ASSERT_TRUE(pool.contains(entt::entity{0}));
ASSERT_TRUE(pool.contains(entt::entity{1}));
ASSERT_EQ(*pool.begin(), entt::entity{1});
ASSERT_EQ(*++pool.begin(), entt::entity{0});
pool.swap_elements(entt::entity{0}, entt::entity{1});
ASSERT_EQ(*pool.begin(), entt::entity{0});
ASSERT_EQ(*++pool.begin(), entt::entity{1});
}
ENTT_DEBUG_TEST(StorageEntityDeathTest, SwapElements) {
entt::storage<entt::entity> pool;
pool.push(entt::entity{1});
ASSERT_EQ(pool.size(), 2u);
ASSERT_EQ(pool.in_use(), 1u);
ASSERT_TRUE(pool.contains(entt::entity{0}));
ASSERT_TRUE(pool.contains(entt::entity{1}));
ASSERT_DEATH(pool.swap_elements(entt::entity{0}, entt::entity{1}), "");
}
ENTT_DEBUG_TEST(StorageEntityDeathTest, InUse) {
entt::storage<entt::entity> pool;
pool.push(entt::entity{0});
pool.push(entt::entity{1});
ASSERT_DEATH(pool.in_use(3u), "");
}
ENTT_DEBUG_TEST(StorageEntityDeathTest, SortAndRespect) {
entt::storage<entt::entity> pool;
entt::storage<entt::entity> other;
pool.push(entt::entity{1});
pool.push(entt::entity{2});
pool.erase(entt::entity{2});
other.push(entt::entity{2});
ASSERT_DEATH(pool.sort([](auto...) { return true; }), "");
ASSERT_DEATH(pool.sort_as(other), "");
}
TEST(StorageEntity, CustomAllocator) {
test::throwing_allocator<entt::entity> allocator{};
entt::basic_storage<entt::entity, entt::entity, test::throwing_allocator<entt::entity>> pool{allocator};
pool.reserve(1u);
ASSERT_EQ(pool.size(), 0u);
ASSERT_EQ(pool.in_use(), 0u);
pool.push(entt::entity{0});
pool.push(entt::entity{1});
ASSERT_EQ(pool.size(), 2u);
ASSERT_EQ(pool.in_use(), 2u);
decltype(pool) other{std::move(pool), allocator};
ASSERT_TRUE(pool.empty());
ASSERT_FALSE(other.empty());
ASSERT_EQ(pool.size(), 0u);
ASSERT_EQ(other.size(), 2u);
ASSERT_EQ(pool.in_use(), 0u);
ASSERT_EQ(other.in_use(), 2u);
pool = std::move(other);
ASSERT_FALSE(pool.empty());
ASSERT_TRUE(other.empty());
ASSERT_EQ(pool.size(), 2u);
ASSERT_EQ(other.size(), 0u);
ASSERT_EQ(pool.in_use(), 2u);
ASSERT_EQ(other.in_use(), 0u);
pool.swap(other);
pool = std::move(other);
ASSERT_FALSE(pool.empty());
ASSERT_TRUE(other.empty());
ASSERT_EQ(pool.size(), 2u);
ASSERT_EQ(other.size(), 0u);
ASSERT_EQ(pool.in_use(), 2u);
ASSERT_EQ(other.in_use(), 0u);
pool.clear();
ASSERT_EQ(pool.size(), 0u);
ASSERT_EQ(pool.in_use(), 0u);
}

View File

@ -24,7 +24,6 @@ TEST(SingleComponentView, Functionalities) {
ASSERT_TRUE(view.empty());
registry.emplace<int>(e1);
registry.emplace<char>(e1);
ASSERT_NO_FATAL_FAILURE(view.begin()++);
@ -70,6 +69,42 @@ TEST(SingleComponentView, Functionalities) {
ASSERT_FALSE(invalid);
}
TEST(SingleComponentView, InvalidView) {
entt::basic_view<entt::get_t<entt::storage<int>>, entt::exclude_t<>> view{};
ASSERT_FALSE(view);
ASSERT_EQ(view.size(), 0u);
ASSERT_TRUE(view.empty());
ASSERT_FALSE(view.contains(entt::null));
ASSERT_EQ(view.find(entt::null), view.end());
ASSERT_EQ(view.front(), static_cast<entt::entity>(entt::null));
ASSERT_EQ(view.back(), static_cast<entt::entity>(entt::null));
ASSERT_EQ(view.begin(), typename decltype(view)::iterator{});
ASSERT_EQ(view.begin(), view.end());
ASSERT_EQ(view.rbegin(), typename decltype(view)::reverse_iterator{});
ASSERT_EQ(view.rbegin(), view.rend());
auto iterable = view.each();
ASSERT_EQ(iterable.begin(), iterable.end());
ASSERT_EQ(iterable.cbegin(), iterable.cend());
view.each([](const int &) { FAIL(); });
view.each([](const entt::entity, const int &) { FAIL(); });
entt::storage<int> storage;
view.storage(storage);
ASSERT_TRUE(view);
view.each([](const int &) { FAIL(); });
view.each([](const entt::entity, const int &) { FAIL(); });
}
TEST(SingleComponentView, Constructors) {
entt::storage<int> storage{};
@ -81,7 +116,8 @@ TEST(SingleComponentView, Constructors) {
ASSERT_TRUE(from_storage);
ASSERT_TRUE(from_tuple);
ASSERT_EQ(&from_storage.handle(), &from_tuple.handle());
ASSERT_NE(from_storage.handle(), nullptr);
ASSERT_EQ(from_storage.handle(), from_tuple.handle());
}
TEST(SingleComponentView, Handle) {
@ -89,17 +125,19 @@ TEST(SingleComponentView, Handle) {
const auto entity = registry.create();
auto view = registry.view<int>();
auto &&handle = view.handle();
auto *handle = view.handle();
ASSERT_TRUE(handle.empty());
ASSERT_FALSE(handle.contains(entity));
ASSERT_EQ(&handle, &view.handle());
ASSERT_NE(handle, nullptr);
ASSERT_TRUE(handle->empty());
ASSERT_FALSE(handle->contains(entity));
ASSERT_EQ(handle, view.handle());
registry.emplace<int>(entity);
ASSERT_FALSE(handle.empty());
ASSERT_TRUE(handle.contains(entity));
ASSERT_EQ(&handle, &view.handle());
ASSERT_FALSE(handle->empty());
ASSERT_TRUE(handle->contains(entity));
ASSERT_EQ(handle, view.handle());
}
TEST(SingleComponentView, LazyTypeFromConstRegistry) {
@ -111,8 +149,8 @@ TEST(SingleComponentView, LazyTypeFromConstRegistry) {
registry.emplace<empty_type>(entity);
registry.emplace<int>(entity);
ASSERT_TRUE(cview);
ASSERT_TRUE(eview);
ASSERT_FALSE(cview);
ASSERT_FALSE(eview);
ASSERT_TRUE(cview.empty());
ASSERT_EQ(eview.size(), 0u);
@ -164,14 +202,6 @@ TEST(SingleComponentView, Contains) {
TEST(SingleComponentView, Empty) {
entt::registry registry;
const auto e0 = registry.create();
registry.emplace<char>(e0);
registry.emplace<double>(e0);
const auto e1 = registry.create();
registry.emplace<char>(e1);
auto view = registry.view<int>();
ASSERT_EQ(view.size(), 0u);
@ -198,15 +228,17 @@ TEST(SingleComponentView, Each) {
auto it = iterable.begin();
ASSERT_EQ(it.base(), view.begin());
ASSERT_EQ((it++, ++it), iterable.end());
ASSERT_EQ(it.base(), view.end());
view.each([expected = 1u](auto entt, int &value) mutable {
ASSERT_EQ(entt::to_integral(entt), expected);
view.each([expected = 1](auto entt, int &value) mutable {
ASSERT_EQ(static_cast<int>(entt::to_integral(entt)), expected);
ASSERT_EQ(value, expected);
--expected;
});
cview.each([expected = 1u](const int &value) mutable {
cview.each([expected = 1](const int &value) mutable {
ASSERT_EQ(value, expected);
--expected;
});
@ -219,7 +251,7 @@ TEST(SingleComponentView, Each) {
// do not use iterable, make sure an iterable view works when created from a temporary
for(auto [entt, value]: view.each()) {
ASSERT_EQ(entt::to_integral(entt), value);
ASSERT_EQ(static_cast<int>(entt::to_integral(entt)), value);
}
}
@ -334,15 +366,13 @@ TEST(SingleComponentView, Find) {
TEST(SingleComponentView, EmptyTypes) {
entt::registry registry;
entt::entity entities[2u];
entt::entity entity = registry.create();
registry.create(std::begin(entities), std::end(entities));
registry.emplace<int>(entities[0u], 0);
registry.emplace<empty_type>(entities[0u]);
registry.emplace<char>(entities[1u], 'c');
registry.emplace<int>(entity, 0);
registry.emplace<empty_type>(entity);
registry.view<empty_type>().each([&](const auto entt) {
ASSERT_EQ(entities[0u], entt);
ASSERT_EQ(entity, entt);
});
registry.view<empty_type>().each([check = true]() mutable {
@ -352,11 +382,11 @@ TEST(SingleComponentView, EmptyTypes) {
for(auto [entt]: registry.view<empty_type>().each()) {
static_assert(std::is_same_v<decltype(entt), entt::entity>);
ASSERT_EQ(entities[0u], entt);
ASSERT_EQ(entity, entt);
}
registry.view<int>().each([&](const auto entt, int) {
ASSERT_EQ(entities[0u], entt);
ASSERT_EQ(entity, entt);
});
registry.view<int>().each([check = true](int) mutable {
@ -367,7 +397,7 @@ TEST(SingleComponentView, EmptyTypes) {
for(auto [entt, iv]: registry.view<int>().each()) {
static_assert(std::is_same_v<decltype(entt), entt::entity>);
static_assert(std::is_same_v<decltype(iv), int &>);
ASSERT_EQ(entities[0u], entt);
ASSERT_EQ(entity, entt);
}
}
@ -459,35 +489,87 @@ TEST(SingleComponentView, StableType) {
TEST(SingleComponentView, Storage) {
entt::registry registry;
const auto entity = registry.create();
const auto view = registry.view<int>();
const auto cview = registry.view<const char>();
auto view = registry.view<int>();
auto cview = registry.view<const char>();
static_assert(std::is_same_v<decltype(view.storage()), entt::storage_type_t<int> &>);
static_assert(std::is_same_v<decltype(view.storage<0u>()), entt::storage_type_t<int> &>);
static_assert(std::is_same_v<decltype(view.storage<int>()), entt::storage_type_t<int> &>);
static_assert(std::is_same_v<decltype(cview.storage()), const entt::storage_type_t<char> &>);
static_assert(std::is_same_v<decltype(cview.storage<0u>()), const entt::storage_type_t<char> &>);
static_assert(std::is_same_v<decltype(cview.storage<const char>()), const entt::storage_type_t<char> &>);
static_assert(std::is_same_v<decltype(view.storage()), entt::storage_type_t<int> *>);
static_assert(std::is_same_v<decltype(view.storage<0u>()), entt::storage_type_t<int> *>);
static_assert(std::is_same_v<decltype(view.storage<int>()), entt::storage_type_t<int> *>);
static_assert(std::is_same_v<decltype(view.storage<const int>()), entt::storage_type_t<int> *>);
static_assert(std::is_same_v<decltype(cview.storage()), const entt::storage_type_t<char> *>);
static_assert(std::is_same_v<decltype(cview.storage<0u>()), const entt::storage_type_t<char> *>);
static_assert(std::is_same_v<decltype(cview.storage<char>()), const entt::storage_type_t<char> *>);
static_assert(std::is_same_v<decltype(cview.storage<const char>()), const entt::storage_type_t<char> *>);
ASSERT_TRUE(view);
ASSERT_TRUE(cview);
ASSERT_NE(view.storage<int>(), nullptr);
ASSERT_NE(cview.storage<0u>(), nullptr);
ASSERT_EQ(view.size(), 0u);
ASSERT_EQ(cview.size(), 0u);
view.storage().emplace(entity);
view.storage()->emplace(entity);
registry.emplace<char>(entity);
ASSERT_EQ(view.size(), 1u);
ASSERT_EQ(cview.size(), 1u);
ASSERT_TRUE(view.storage<int>().contains(entity));
ASSERT_TRUE(cview.storage<0u>().contains(entity));
ASSERT_TRUE(view.storage<int>()->contains(entity));
ASSERT_TRUE(cview.storage<0u>()->contains(entity));
ASSERT_TRUE((registry.all_of<int, char>(entity)));
view.storage().erase(entity);
view.storage()->erase(entity);
ASSERT_EQ(view.size(), 0u);
ASSERT_EQ(cview.size(), 1u);
ASSERT_FALSE(view.storage<0u>().contains(entity));
ASSERT_TRUE(cview.storage<const char>().contains(entity));
ASSERT_FALSE(view.storage<0u>()->contains(entity));
ASSERT_TRUE(cview.storage<const char>()->contains(entity));
ASSERT_FALSE((registry.all_of<int, char>(entity)));
view = {};
cview = {};
ASSERT_FALSE(view);
ASSERT_FALSE(cview);
ASSERT_EQ(view.storage<0u>(), nullptr);
ASSERT_EQ(cview.storage<const char>(), nullptr);
}
TEST(SingleComponentView, SwapStorage) {
using namespace entt::literals;
entt::registry registry;
entt::basic_view<entt::get_t<entt::storage<int>>, entt::exclude_t<>> view;
entt::basic_view<entt::get_t<const entt::storage<int>>, entt::exclude_t<>> cview;
ASSERT_FALSE(view);
ASSERT_FALSE(cview);
ASSERT_EQ(view.storage<0u>(), nullptr);
ASSERT_EQ(cview.storage<const int>(), nullptr);
const entt::entity entity{42u};
registry.emplace<int>(entity);
view.storage(registry.storage<int>());
cview.storage(registry.storage<int>());
ASSERT_TRUE(view);
ASSERT_TRUE(cview);
ASSERT_NE(view.storage<0u>(), nullptr);
ASSERT_NE(cview.storage<const int>(), nullptr);
ASSERT_EQ(view.size(), 1u);
ASSERT_EQ(cview.size(), 1u);
ASSERT_TRUE(view.contains(entity));
ASSERT_TRUE(cview.contains(entity));
view.storage(registry.storage<int>("other"_hs));
cview.storage(registry.storage<int>("other"_hs));
ASSERT_TRUE(view.empty());
ASSERT_TRUE(cview.empty());
}
TEST(MultiComponentView, Functionalities) {
@ -532,6 +614,46 @@ TEST(MultiComponentView, Functionalities) {
ASSERT_FALSE(invalid);
}
TEST(MultiComponentView, InvalidView) {
entt::basic_view<entt::get_t<entt::storage<int>>, entt::exclude_t<entt::storage<char>>> view{};
ASSERT_FALSE(view);
ASSERT_EQ(view.size_hint(), 0u);
ASSERT_FALSE(view.contains(entt::null));
ASSERT_EQ(view.find(entt::null), view.end());
ASSERT_EQ(view.front(), static_cast<entt::entity>(entt::null));
ASSERT_EQ(view.back(), static_cast<entt::entity>(entt::null));
ASSERT_EQ(view.begin(), typename decltype(view)::iterator{});
ASSERT_EQ(view.begin(), view.end());
auto iterable = view.each();
ASSERT_EQ(iterable.begin(), iterable.end());
ASSERT_EQ(iterable.cbegin(), iterable.cend());
view.each([](const int &) { FAIL(); });
view.each([](const entt::entity, const int &) { FAIL(); });
entt::storage<int> storage;
view.storage(storage);
ASSERT_FALSE(view);
view.each([](const int &) { FAIL(); });
view.each([](const entt::entity, const int &) { FAIL(); });
entt::storage<char> other;
view.storage(other);
ASSERT_TRUE(view);
view.each([](const int &) { FAIL(); });
view.each([](const entt::entity, const int &) { FAIL(); });
}
TEST(MultiComponentView, Constructors) {
entt::storage<int> storage{};
@ -543,7 +665,8 @@ TEST(MultiComponentView, Constructors) {
ASSERT_TRUE(from_storage);
ASSERT_TRUE(from_tuple);
ASSERT_EQ(&from_storage.handle(), &from_tuple.handle());
ASSERT_NE(from_storage.handle(), nullptr);
ASSERT_EQ(from_storage.handle(), from_tuple.handle());
}
TEST(MultiComponentView, Handle) {
@ -551,30 +674,34 @@ TEST(MultiComponentView, Handle) {
const auto entity = registry.create();
auto view = registry.view<int, char>();
auto &&handle = view.handle();
auto *handle = view.handle();
ASSERT_TRUE(handle.empty());
ASSERT_FALSE(handle.contains(entity));
ASSERT_EQ(&handle, &view.handle());
ASSERT_NE(handle, nullptr);
ASSERT_TRUE(handle->empty());
ASSERT_FALSE(handle->contains(entity));
ASSERT_EQ(handle, view.handle());
registry.emplace<int>(entity);
ASSERT_FALSE(handle.empty());
ASSERT_TRUE(handle.contains(entity));
ASSERT_EQ(&handle, &view.handle());
ASSERT_FALSE(handle->empty());
ASSERT_TRUE(handle->contains(entity));
ASSERT_EQ(handle, view.handle());
view = view.refresh();
auto &&other = view.handle();
view.refresh();
auto *other = view.handle();
ASSERT_TRUE(other.empty());
ASSERT_FALSE(other.contains(entity));
ASSERT_EQ(&other, &view.handle());
ASSERT_NE(&handle, &other);
ASSERT_NE(other, nullptr);
view = view.use<int>();
ASSERT_TRUE(other->empty());
ASSERT_FALSE(other->contains(entity));
ASSERT_EQ(other, view.handle());
ASSERT_NE(handle, other);
ASSERT_NE(&other, &view.handle());
ASSERT_EQ(&handle, &view.handle());
view.use<int>();
ASSERT_NE(other, view.handle());
ASSERT_EQ(handle, view.handle());
}
TEST(MultiComponentView, LazyTypesFromConstRegistry) {
@ -585,7 +712,7 @@ TEST(MultiComponentView, LazyTypesFromConstRegistry) {
registry.emplace<empty_type>(entity);
registry.emplace<int>(entity);
ASSERT_TRUE(view);
ASSERT_FALSE(view);
ASSERT_EQ(view.size_hint(), 0u);
ASSERT_FALSE(view.contains(entity));
@ -604,7 +731,7 @@ TEST(MultiComponentView, LazyExcludedTypeFromConstRegistry) {
auto view = std::as_const(registry).view<const int>(entt::exclude<char>);
ASSERT_TRUE(view);
ASSERT_FALSE(view);
ASSERT_EQ(view.size_hint(), 1u);
ASSERT_TRUE(view.contains(entity));
@ -683,7 +810,6 @@ TEST(MultiComponentView, SizeHint) {
entt::registry registry;
const auto e0 = registry.create();
registry.emplace<double>(e0);
registry.emplace<int>(e0);
registry.emplace<float>(e0);
@ -705,10 +831,10 @@ TEST(MultiComponentView, Each) {
auto cview = std::as_const(registry).view<const int, const char>();
registry.emplace<int>(entity[0u], 0);
registry.emplace<char>(entity[0u], 0);
registry.emplace<char>(entity[0u], static_cast<char>(0));
registry.emplace<int>(entity[1u], 1);
registry.emplace<char>(entity[1u], 1);
registry.emplace<char>(entity[1u], static_cast<char>(1));
auto iterable = view.each();
auto citerable = cview.each();
@ -719,16 +845,18 @@ TEST(MultiComponentView, Each) {
auto it = iterable.begin();
ASSERT_EQ(it.base(), view.begin());
ASSERT_EQ((it++, ++it), iterable.end());
ASSERT_EQ(it.base(), view.end());
view.each([expected = 1u](auto entt, int &ivalue, char &cvalue) mutable {
ASSERT_EQ(entt::to_integral(entt), expected);
view.each([expected = 1](auto entt, int &ivalue, char &cvalue) mutable {
ASSERT_EQ(static_cast<int>(entt::to_integral(entt)), expected);
ASSERT_EQ(ivalue, expected);
ASSERT_EQ(cvalue, expected);
--expected;
});
cview.each([expected = 1u](const int &ivalue, const char &cvalue) mutable {
cview.each([expected = 1](const int &ivalue, const char &cvalue) mutable {
ASSERT_EQ(ivalue, expected);
ASSERT_EQ(cvalue, expected);
--expected;
@ -742,13 +870,14 @@ TEST(MultiComponentView, Each) {
// do not use iterable, make sure an iterable view works when created from a temporary
for(auto [entt, ivalue, cvalue]: registry.view<int, char>().each()) {
ASSERT_EQ(entt::to_integral(entt), ivalue);
ASSERT_EQ(entt::to_integral(entt), cvalue);
ASSERT_EQ(static_cast<int>(entt::to_integral(entt)), ivalue);
ASSERT_EQ(static_cast<char>(entt::to_integral(entt)), cvalue);
}
}
TEST(MultiComponentView, EachWithSuggestedType) {
entt::registry registry;
auto view = registry.view<int, char>();
for(auto i = 0; i < 3; ++i) {
const auto entity = registry.create();
@ -760,7 +889,8 @@ TEST(MultiComponentView, EachWithSuggestedType) {
const auto entity = registry.create();
registry.emplace<int>(entity, 99);
registry.view<int, char>().use<int>().each([value = 2](const auto curr, const auto) mutable {
view.use<int>();
view.each([value = 2](const auto curr, const auto) mutable {
ASSERT_EQ(curr, value--);
});
@ -768,7 +898,8 @@ TEST(MultiComponentView, EachWithSuggestedType) {
return lhs < rhs;
});
registry.view<int, char>().use<0u>().each([value = 0](const auto curr, const auto) mutable {
view.use<0u>();
view.each([value = 0](const auto curr, const auto) mutable {
ASSERT_EQ(curr, value++);
});
@ -787,8 +918,9 @@ TEST(MultiComponentView, EachWithSuggestedType) {
});
value = {};
view.use<int>();
for(auto &&curr: registry.view<int, char>().use<int>().each()) {
for(auto &&curr: view.each()) {
ASSERT_EQ(std::get<1>(curr), static_cast<int>(value++));
}
}
@ -955,6 +1087,10 @@ TEST(MultiComponentView, ExcludedComponents) {
TEST(MultiComponentView, EmptyTypes) {
entt::registry registry;
auto v1 = registry.view<int, char, empty_type>(entt::exclude<double>);
auto v2 = registry.view<int, empty_type, char>(entt::exclude<double>);
auto v3 = registry.view<empty_type, int, char>(entt::exclude<double>);
const auto entity = registry.create();
registry.emplace<int>(entity);
registry.emplace<char>(entity);
@ -970,57 +1106,61 @@ TEST(MultiComponentView, EmptyTypes) {
registry.emplace<int>(ignored);
registry.emplace<char>(ignored);
registry.view<int, char, empty_type>(entt::exclude<double>).each([entity](const auto entt, int, char) {
v1.each([entity](const auto entt, int, char) {
ASSERT_EQ(entity, entt);
});
for(auto [entt, iv, cv]: registry.view<int, char, empty_type>(entt::exclude<double>).each()) {
for(auto [entt, iv, cv]: v1.each()) {
static_assert(std::is_same_v<decltype(entt), entt::entity>);
static_assert(std::is_same_v<decltype(iv), int &>);
static_assert(std::is_same_v<decltype(cv), char &>);
ASSERT_EQ(entity, entt);
}
registry.view<int, empty_type, char>(entt::exclude<double>).each([check = true](int, char) mutable {
v2.each([check = true](int, char) mutable {
ASSERT_TRUE(check);
check = false;
});
for(auto [entt, iv, cv]: registry.view<int, empty_type, char>(entt::exclude<double>).each()) {
for(auto [entt, iv, cv]: v2.each()) {
static_assert(std::is_same_v<decltype(entt), entt::entity>);
static_assert(std::is_same_v<decltype(iv), int &>);
static_assert(std::is_same_v<decltype(cv), char &>);
ASSERT_EQ(entity, entt);
}
registry.view<empty_type, int, char>(entt::exclude<double>).each([entity](const auto entt, int, char) {
v3.each([entity](const auto entt, int, char) {
ASSERT_EQ(entity, entt);
});
for(auto [entt, iv, cv]: registry.view<empty_type, int, char>(entt::exclude<double>).each()) {
for(auto [entt, iv, cv]: v3.each()) {
static_assert(std::is_same_v<decltype(entt), entt::entity>);
static_assert(std::is_same_v<decltype(iv), int &>);
static_assert(std::is_same_v<decltype(cv), char &>);
ASSERT_EQ(entity, entt);
}
registry.view<empty_type, int, char>(entt::exclude<double>).use<empty_type>().each([entity](const auto entt, int, char) {
v3.use<empty_type>();
v3.each([entity](const auto entt, int, char) {
ASSERT_EQ(entity, entt);
});
for(auto [entt, iv, cv]: registry.view<empty_type, int, char>(entt::exclude<double>).use<0u>().each()) {
v3.use<0u>();
for(auto [entt, iv, cv]: v3.each()) {
static_assert(std::is_same_v<decltype(entt), entt::entity>);
static_assert(std::is_same_v<decltype(iv), int &>);
static_assert(std::is_same_v<decltype(cv), char &>);
ASSERT_EQ(entity, entt);
}
registry.view<int, empty_type, char>(entt::exclude<double>).use<1u>().each([check = true](int, char) mutable {
v2.use<1u>();
v2.each([check = true](int, char) mutable {
ASSERT_TRUE(check);
check = false;
});
for(auto [entt, iv, cv]: registry.view<int, empty_type, char>(entt::exclude<double>).use<empty_type>().each()) {
v2.use<empty_type>();
for(auto [entt, iv, cv]: v2.each()) {
static_assert(std::is_same_v<decltype(entt), entt::entity>);
static_assert(std::is_same_v<decltype(iv), int &>);
static_assert(std::is_same_v<decltype(cv), char &>);
@ -1111,7 +1251,7 @@ TEST(MultiComponentView, StableType) {
ASSERT_EQ(view.size_hint(), 1u);
view = view.use<stable_type>();
view.use<stable_type>();
ASSERT_EQ(view.size_hint(), 2u);
ASSERT_FALSE(view.contains(entity));
@ -1146,7 +1286,9 @@ TEST(MultiComponentView, StableType) {
TEST(MultiComponentView, StableTypeWithExcludedComponent) {
entt::registry registry;
auto view = registry.view<stable_type>(entt::exclude<int>).use<stable_type>();
auto view = registry.view<stable_type>(entt::exclude<int>);
view.use<stable_type>();
const auto entity = registry.create();
const auto other = registry.create();
@ -1223,8 +1365,118 @@ TEST(MultiComponentView, SameComponentTypes) {
ASSERT_EQ(second, 9);
}
ASSERT_EQ(&view.handle(), &storage);
ASSERT_EQ(&view.use<1u>().handle(), &other);
ASSERT_EQ(view.handle(), &storage);
view.use<1u>();
ASSERT_EQ(view.handle(), &other);
}
TEST(MultiComponentView, Storage) {
entt::registry registry;
const auto entity = registry.create();
auto view = registry.view<int, const char>(entt::exclude<double, const float>);
static_assert(std::is_same_v<decltype(view.storage<0u>()), entt::storage_type_t<int> *>);
static_assert(std::is_same_v<decltype(view.storage<int>()), entt::storage_type_t<int> *>);
static_assert(std::is_same_v<decltype(view.storage<const int>()), entt::storage_type_t<int> *>);
static_assert(std::is_same_v<decltype(view.storage<1u>()), const entt::storage_type_t<char> *>);
static_assert(std::is_same_v<decltype(view.storage<char>()), const entt::storage_type_t<char> *>);
static_assert(std::is_same_v<decltype(view.storage<const char>()), const entt::storage_type_t<char> *>);
static_assert(std::is_same_v<decltype(view.storage<2u>()), entt::storage_type_t<double> *>);
static_assert(std::is_same_v<decltype(view.storage<double>()), entt::storage_type_t<double> *>);
static_assert(std::is_same_v<decltype(view.storage<const double>()), entt::storage_type_t<double> *>);
static_assert(std::is_same_v<decltype(view.storage<3u>()), const entt::storage_type_t<float> *>);
static_assert(std::is_same_v<decltype(view.storage<float>()), const entt::storage_type_t<float> *>);
static_assert(std::is_same_v<decltype(view.storage<const float>()), const entt::storage_type_t<float> *>);
ASSERT_TRUE(view);
ASSERT_NE(view.storage<int>(), nullptr);
ASSERT_NE(view.storage<1u>(), nullptr);
ASSERT_NE(view.storage<double>(), nullptr);
ASSERT_NE(view.storage<3u>(), nullptr);
ASSERT_EQ(view.size_hint(), 0u);
view.storage<int>()->emplace(entity);
view.storage<double>()->emplace(entity);
registry.emplace<char>(entity);
registry.emplace<float>(entity);
ASSERT_EQ(view.size_hint(), 1u);
ASSERT_EQ(view.begin(), view.end());
ASSERT_TRUE(view.storage<int>()->contains(entity));
ASSERT_TRUE(view.storage<const char>()->contains(entity));
ASSERT_TRUE(view.storage<double>()->contains(entity));
ASSERT_TRUE(view.storage<const float>()->contains(entity));
ASSERT_TRUE((registry.all_of<int, char, double, float>(entity)));
view.storage<double>()->erase(entity);
registry.erase<float>(entity);
ASSERT_EQ(view.size_hint(), 1u);
ASSERT_NE(view.begin(), view.end());
ASSERT_TRUE(view.storage<const int>()->contains(entity));
ASSERT_TRUE(view.storage<char>()->contains(entity));
ASSERT_FALSE(view.storage<const double>()->contains(entity));
ASSERT_FALSE(view.storage<float>()->contains(entity));
ASSERT_TRUE((registry.all_of<int, char>(entity)));
ASSERT_FALSE((registry.any_of<double, float>(entity)));
view.storage<0u>()->erase(entity);
ASSERT_EQ(view.size_hint(), 0u);
ASSERT_EQ(view.begin(), view.end());
ASSERT_FALSE(view.storage<0u>()->contains(entity));
ASSERT_TRUE(view.storage<1u>()->contains(entity));
ASSERT_FALSE(view.storage<2u>()->contains(entity));
ASSERT_FALSE(view.storage<3u>()->contains(entity));
ASSERT_TRUE((registry.all_of<char>(entity)));
ASSERT_FALSE((registry.any_of<int, double, float>(entity)));
view = {};
ASSERT_FALSE(view);
ASSERT_EQ(view.storage<0u>(), nullptr);
ASSERT_EQ(view.storage<const char>(), nullptr);
ASSERT_EQ(view.storage<2u>(), nullptr);
ASSERT_EQ(view.storage<const float>(), nullptr);
}
TEST(MultiComponentView, SwapStorage) {
using namespace entt::literals;
entt::registry registry;
entt::basic_view<entt::get_t<entt::storage<int>>, entt::exclude_t<const entt::storage<char>>> view;
ASSERT_FALSE(view);
ASSERT_EQ(view.storage<0u>(), nullptr);
ASSERT_EQ(view.storage<const char>(), nullptr);
const entt::entity entity{42u};
registry.emplace<int>(entity);
registry.emplace<char>(entity);
view.storage(registry.storage<int>());
view.storage<1u>(registry.storage<char>());
ASSERT_TRUE(view);
ASSERT_NE(view.storage<int>(), nullptr);
ASSERT_NE(view.storage<1u>(), nullptr);
ASSERT_EQ(view.size_hint(), 1u);
ASSERT_FALSE(view.contains(entity));
view.storage(registry.storage<char>("other"_hs));
ASSERT_EQ(view.size_hint(), 1u);
ASSERT_TRUE(view.contains(entity));
view.storage(registry.storage<int>("empty"_hs));
ASSERT_EQ(view.size_hint(), 0u);
}
TEST(View, Pipe) {
@ -1241,10 +1493,10 @@ TEST(View, Pipe) {
registry.emplace<char>(other);
registry.emplace<stable_type>(other);
const auto view1 = registry.view<int>(entt::exclude<const double>);
const auto view2 = registry.view<const char>(entt::exclude<float>);
const auto view3 = registry.view<empty_type>();
const auto view4 = registry.view<stable_type>();
auto view1 = registry.view<int>(entt::exclude<const double>);
auto view2 = registry.view<const char>(entt::exclude<float>);
auto view3 = registry.view<empty_type>();
auto view4 = registry.view<stable_type>();
static_assert(std::is_same_v<entt::basic_view<entt::get_t<entt::storage_type_t<int>, const entt::storage_type_t<char>>, entt::exclude_t<const entt::storage_type_t<double>, entt::storage_type_t<float>>>, decltype(view1 | view2)>);
static_assert(std::is_same_v<entt::basic_view<entt::get_t<const entt::storage_type_t<char>, entt::storage_type_t<int>>, entt::exclude_t<entt::storage_type_t<float>, const entt::storage_type_t<double>>>, decltype(view2 | view1)>);
@ -1261,30 +1513,26 @@ TEST(View, Pipe) {
ASSERT_FALSE((view1 | view4 | view2).contains(entity));
ASSERT_TRUE((view1 | view4 | view2).contains(other));
}
TEST(MultiComponentView, Storage) {
entt::registry registry;
const auto entity = registry.create();
const auto view = registry.view<int, const char>();
static_assert(std::is_same_v<decltype(view.storage<0u>()), entt::storage_type_t<int> &>);
static_assert(std::is_same_v<decltype(view.storage<int>()), entt::storage_type_t<int> &>);
static_assert(std::is_same_v<decltype(view.storage<1u>()), const entt::storage_type_t<char> &>);
static_assert(std::is_same_v<decltype(view.storage<const char>()), const entt::storage_type_t<char> &>);
ASSERT_EQ(view.size_hint(), 0u);
view.storage<int>().emplace(entity);
registry.emplace<char>(entity);
ASSERT_EQ(view.size_hint(), 1u);
ASSERT_TRUE(view.storage<const char>().contains(entity));
ASSERT_TRUE((registry.all_of<int, char>(entity)));
view.storage<0u>().erase(entity);
ASSERT_EQ(view.size_hint(), 0u);
ASSERT_TRUE(view.storage<1u>().contains(entity));
ASSERT_FALSE((registry.all_of<int, char>(entity)));
view1 = {};
view3 = {};
ASSERT_FALSE(view1);
ASSERT_TRUE(view2);
ASSERT_FALSE(view3);
ASSERT_TRUE(view4);
auto pack14 = view1 | view4;
auto pack32 = view3 | view2;
ASSERT_FALSE(pack14);
ASSERT_FALSE(pack32);
ASSERT_EQ(pack14.storage<int>(), nullptr);
ASSERT_EQ(pack14.storage<const double>(), nullptr);
ASSERT_NE(pack14.storage<stable_type>(), nullptr);
ASSERT_EQ(pack32.storage<empty_type>(), nullptr);
ASSERT_NE(pack32.storage<const char>(), nullptr);
ASSERT_NE(pack32.storage<float>(), nullptr);
}

View File

@ -295,6 +295,23 @@ TEST(AdjacencyMatrix, EdgesDirected) {
ASSERT_EQ(++it, iterable.end());
}
TEST(AdjacencyMatrix, EdgesBackwardOnlyDirected) {
entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{2u};
auto iterable = adjacency_matrix.edges();
ASSERT_EQ(iterable.begin(), iterable.end());
adjacency_matrix.insert(1u, 0u);
iterable = adjacency_matrix.edges();
ASSERT_NE(iterable.begin(), iterable.end());
auto it = iterable.begin();
ASSERT_EQ(*it++, std::make_pair(std::size_t{1u}, std::size_t{0u}));
ASSERT_EQ(it, iterable.end());
}
TEST(AdjacencyMatrix, EdgesUndirected) {
entt::adjacency_matrix<entt::undirected_tag> adjacency_matrix{3u};
auto iterable = adjacency_matrix.edges();
@ -317,6 +334,24 @@ TEST(AdjacencyMatrix, EdgesUndirected) {
ASSERT_EQ(++it, iterable.end());
}
TEST(AdjacencyMatrix, EdgesBackwardOnlyUndirected) {
entt::adjacency_matrix<entt::undirected_tag> adjacency_matrix{2u};
auto iterable = adjacency_matrix.edges();
ASSERT_EQ(iterable.begin(), iterable.end());
adjacency_matrix.insert(1u, 0u);
iterable = adjacency_matrix.edges();
ASSERT_NE(iterable.begin(), iterable.end());
auto it = iterable.begin();
ASSERT_EQ(*it++, std::make_pair(std::size_t{0u}, std::size_t{1u}));
ASSERT_EQ(*it++, std::make_pair(std::size_t{1u}, std::size_t{0u}));
ASSERT_EQ(it, iterable.end());
}
TEST(AdjacencyMatrix, OutEdgesDirected) {
entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{3u};
auto iterable = adjacency_matrix.out_edges(0u);
@ -340,6 +375,28 @@ TEST(AdjacencyMatrix, OutEdgesDirected) {
ASSERT_EQ(it, iterable.cend());
}
TEST(AdjacencyMatrix, OutEdgesBackwardOnlyDirected) {
entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{2u};
auto iterable = adjacency_matrix.out_edges(1u);
ASSERT_EQ(iterable.begin(), iterable.end());
adjacency_matrix.insert(1u, 0u);
iterable = adjacency_matrix.out_edges(1u);
ASSERT_NE(iterable.begin(), iterable.end());
auto it = iterable.begin();
ASSERT_EQ(*it++, std::make_pair(std::size_t{1u}, std::size_t{0u}));
ASSERT_EQ(it, iterable.end());
iterable = adjacency_matrix.out_edges(0u);
it = iterable.cbegin();
ASSERT_EQ(it, iterable.cend());
}
TEST(AdjacencyMatrix, OutEdgesUndirected) {
entt::adjacency_matrix<entt::undirected_tag> adjacency_matrix{3u};
auto iterable = adjacency_matrix.out_edges(0u);
@ -365,6 +422,30 @@ TEST(AdjacencyMatrix, OutEdgesUndirected) {
ASSERT_EQ(it, iterable.cend());
}
TEST(AdjacencyMatrix, OutEdgesBackwardOnlyUndirected) {
entt::adjacency_matrix<entt::undirected_tag> adjacency_matrix{2u};
auto iterable = adjacency_matrix.out_edges(1u);
ASSERT_EQ(iterable.begin(), iterable.end());
adjacency_matrix.insert(1u, 0u);
iterable = adjacency_matrix.out_edges(1u);
ASSERT_NE(iterable.begin(), iterable.end());
auto it = iterable.begin();
ASSERT_EQ(*it++, std::make_pair(std::size_t{1u}, std::size_t{0u}));
ASSERT_EQ(it, iterable.end());
iterable = adjacency_matrix.out_edges(0u);
it = iterable.cbegin();
ASSERT_NE(it, iterable.cend());
ASSERT_EQ(*it++, std::make_pair(std::size_t{0u}, std::size_t{1u}));
ASSERT_EQ(it, iterable.cend());
}
TEST(AdjacencyMatrix, InEdgesDirected) {
entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{3u};
auto iterable = adjacency_matrix.in_edges(1u);
@ -388,6 +469,28 @@ TEST(AdjacencyMatrix, InEdgesDirected) {
ASSERT_EQ(it, iterable.cend());
}
TEST(AdjacencyMatrix, InEdgesBackwardOnlyDirected) {
entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{2u};
auto iterable = adjacency_matrix.in_edges(0u);
ASSERT_EQ(iterable.begin(), iterable.end());
adjacency_matrix.insert(1u, 0u);
iterable = adjacency_matrix.in_edges(0u);
ASSERT_NE(iterable.begin(), iterable.end());
auto it = iterable.begin();
ASSERT_EQ(*it++, std::make_pair(std::size_t{1u}, std::size_t{0u}));
ASSERT_EQ(it, iterable.end());
iterable = adjacency_matrix.in_edges(1u);
it = iterable.cbegin();
ASSERT_EQ(it, iterable.cend());
}
TEST(AdjacencyMatrix, InEdgesUndirected) {
entt::adjacency_matrix<entt::undirected_tag> adjacency_matrix{3u};
auto iterable = adjacency_matrix.in_edges(1u);
@ -403,6 +506,7 @@ TEST(AdjacencyMatrix, InEdgesUndirected) {
auto it = iterable.begin();
ASSERT_EQ(*it++, std::make_pair(std::size_t{0u}, std::size_t{1u}));
ASSERT_EQ(*it++, std::make_pair(std::size_t{2u}, std::size_t{1u}));
ASSERT_EQ(it, iterable.end());
iterable = adjacency_matrix.in_edges(0u);
@ -413,6 +517,30 @@ TEST(AdjacencyMatrix, InEdgesUndirected) {
ASSERT_EQ(it, iterable.cend());
}
TEST(AdjacencyMatrix, InEdgesBackwardOnlyUndirected) {
entt::adjacency_matrix<entt::undirected_tag> adjacency_matrix{2u};
auto iterable = adjacency_matrix.in_edges(0u);
ASSERT_EQ(iterable.begin(), iterable.end());
adjacency_matrix.insert(1u, 0u);
iterable = adjacency_matrix.in_edges(0u);
ASSERT_NE(iterable.begin(), iterable.end());
auto it = iterable.begin();
ASSERT_EQ(*it++, std::make_pair(std::size_t{1u}, std::size_t{0u}));
ASSERT_EQ(it, iterable.end());
iterable = adjacency_matrix.in_edges(1u);
it = iterable.cbegin();
ASSERT_NE(it, iterable.cend());
ASSERT_EQ(*it++, std::make_pair(std::size_t{0u}, std::size_t{1u}));
ASSERT_EQ(it, iterable.cend());
}
TEST(AdjacencyMatrix, ThrowingAllocator) {
using allocator = test::throwing_allocator<std::size_t>;
using exception = typename allocator::exception_type;

View File

@ -1,6 +1,7 @@
#include <gtest/gtest.h>
#include <entt/core/hashed_string.hpp>
#include <entt/graph/flow.hpp>
#include "../common/config.h"
#include "../common/throwing_allocator.hpp"
TEST(Flow, Constructors) {
@ -24,9 +25,9 @@ TEST(Flow, Constructors) {
ASSERT_EQ(flow.size(), 0u);
ASSERT_EQ(other.size(), 3u);
ASSERT_EQ(other[0u], 0);
ASSERT_EQ(other[1u], 3);
ASSERT_EQ(other[2u], 99);
ASSERT_EQ(other[0u], 0u);
ASSERT_EQ(other[1u], 3u);
ASSERT_EQ(other[2u], 99u);
}
TEST(Flow, Copy) {
@ -41,9 +42,9 @@ TEST(Flow, Copy) {
ASSERT_EQ(flow.size(), 3u);
ASSERT_EQ(other.size(), 3u);
ASSERT_EQ(other[0u], 0);
ASSERT_EQ(other[1u], 3);
ASSERT_EQ(other[2u], 99);
ASSERT_EQ(other[0u], 0u);
ASSERT_EQ(other[1u], 3u);
ASSERT_EQ(other[2u], 99u);
flow.bind(1);
other.bind(2);
@ -53,10 +54,10 @@ TEST(Flow, Copy) {
ASSERT_EQ(other.size(), 4u);
ASSERT_EQ(flow.size(), 4u);
ASSERT_EQ(other[0u], 0);
ASSERT_EQ(other[1u], 3);
ASSERT_EQ(other[2u], 99);
ASSERT_EQ(other[3u], 1);
ASSERT_EQ(other[0u], 0u);
ASSERT_EQ(other[1u], 3u);
ASSERT_EQ(other[2u], 99u);
ASSERT_EQ(other[3u], 1u);
}
TEST(Flow, Move) {
@ -71,9 +72,9 @@ TEST(Flow, Move) {
ASSERT_EQ(flow.size(), 0u);
ASSERT_EQ(other.size(), 3u);
ASSERT_EQ(other[0u], 0);
ASSERT_EQ(other[1u], 3);
ASSERT_EQ(other[2u], 99);
ASSERT_EQ(other[0u], 0u);
ASSERT_EQ(other[1u], 3u);
ASSERT_EQ(other[2u], 99u);
flow = {};
flow.bind(1);
@ -84,7 +85,7 @@ TEST(Flow, Move) {
ASSERT_EQ(other.size(), 1u);
ASSERT_EQ(flow.size(), 0u);
ASSERT_EQ(other[0u], 1);
ASSERT_EQ(other[0u], 1u);
}
TEST(Flow, Swap) {
@ -95,13 +96,13 @@ TEST(Flow, Swap) {
ASSERT_EQ(other.size(), 0u);
ASSERT_EQ(flow.size(), 1u);
ASSERT_EQ(flow[0u], 7);
ASSERT_EQ(flow[0u], 7u);
flow.swap(other);
ASSERT_EQ(other.size(), 1u);
ASSERT_EQ(flow.size(), 0u);
ASSERT_EQ(other[0u], 7);
ASSERT_EQ(other[0u], 7u);
}
TEST(Flow, Clear) {
@ -111,8 +112,8 @@ TEST(Flow, Clear) {
flow.bind(99);
ASSERT_EQ(flow.size(), 2u);
ASSERT_EQ(flow[0u], 0);
ASSERT_EQ(flow[1u], 99);
ASSERT_EQ(flow[0u], 0u);
ASSERT_EQ(flow[1u], 99u);
flow.clear();
@ -270,6 +271,57 @@ TEST(Flow, Sync) {
ASSERT_EQ(it, last);
}
ENTT_DEBUG_TEST(FlowDeathTest, NoBind) {
entt::flow flow{};
ASSERT_DEATH(flow.ro(42), "");
ASSERT_DEATH(flow.rw(42), "");
flow.bind(0);
ASSERT_NO_FATAL_FAILURE(flow.ro(1));
ASSERT_NO_FATAL_FAILURE(flow.rw(2));
}
TEST(Flow, DirectRebind) {
entt::flow flow{};
flow.bind(0).ro(10).rw(10).bind(1).ro(10);
auto graph = flow.graph();
ASSERT_EQ(flow.size(), 2u);
ASSERT_EQ(flow.size(), graph.size());
ASSERT_NE(graph.edges().cbegin(), graph.edges().cend());
ASSERT_TRUE(graph.contains(0u, 1u));
ASSERT_FALSE(graph.contains(1u, 0u));
}
TEST(Flow, DeferredRebind) {
entt::flow flow{};
flow.bind(0).ro(10).bind(1).ro(10).bind(0).rw(10);
auto graph = flow.graph();
ASSERT_EQ(flow.size(), 2u);
ASSERT_EQ(flow.size(), graph.size());
ASSERT_NE(graph.edges().cbegin(), graph.edges().cend());
ASSERT_FALSE(graph.contains(0u, 1u));
ASSERT_TRUE(graph.contains(1u, 0u));
}
TEST(Flow, Loop) {
entt::flow flow{};
flow.bind(0).rw(10).bind(1).ro(10).bind(0).rw(10);
auto graph = flow.graph();
ASSERT_EQ(flow.size(), 2u);
ASSERT_EQ(flow.size(), graph.size());
ASSERT_NE(graph.edges().cbegin(), graph.edges().cend());
ASSERT_TRUE(graph.contains(0u, 1u));
ASSERT_TRUE(graph.contains(1u, 0u));
}
TEST(Flow, ThrowingAllocator) {
using allocator = test::throwing_allocator<entt::id_type>;
using task_allocator = test::throwing_allocator<std::pair<std::size_t, entt::id_type>>;

View File

@ -5,45 +5,57 @@
struct base_service {
virtual ~base_service() = default;
virtual void invoke() {}
};
struct null_service: base_service {
void invoke() override {
invoked = true;
}
static inline bool invoked{};
virtual int invoke(int) = 0;
};
struct derived_service: base_service {
void invoke() override {
invoked = true;
derived_service(int val)
: value{val} {}
int invoke(int other) override {
return value + other;
}
static inline bool invoked{};
private:
int value;
};
struct ServiceLocator: ::testing::Test {
void SetUp() override {
null_service::invoked = false;
derived_service::invoked = false;
entt::locator<base_service>::reset();
}
};
using ServiceLocatorDeathTest = ServiceLocator;
TEST(ServiceLocator, Functionalities) {
TEST_F(ServiceLocator, ValueAndTheLike) {
ASSERT_FALSE(entt::locator<base_service>::has_value());
ASSERT_FALSE(derived_service::invoked);
ASSERT_FALSE(null_service::invoked);
ASSERT_EQ(entt::locator<base_service>::value_or<derived_service>(1).invoke(3), 4);
ASSERT_TRUE(entt::locator<base_service>::has_value());
ASSERT_EQ(entt::locator<base_service>::value().invoke(9), 10);
}
entt::locator<base_service>::value_or<null_service>().invoke();
TEST_F(ServiceLocator, Emplace) {
ASSERT_FALSE(entt::locator<base_service>::has_value());
ASSERT_EQ(entt::locator<base_service>::emplace<derived_service>(5).invoke(1), 6);
ASSERT_TRUE(entt::locator<base_service>::has_value());
ASSERT_EQ(entt::locator<base_service>::value().invoke(3), 8);
entt::locator<base_service>::reset();
ASSERT_FALSE(entt::locator<base_service>::has_value());
ASSERT_EQ(entt::locator<base_service>::emplace<derived_service>(std::allocator_arg, std::allocator<derived_service>{}, 5).invoke(1), 6);
ASSERT_TRUE(entt::locator<base_service>::has_value());
ASSERT_EQ(entt::locator<base_service>::value().invoke(3), 8);
}
TEST_F(ServiceLocator, ResetHandle) {
entt::locator<base_service>::emplace<derived_service>(1);
auto handle = entt::locator<base_service>::handle();
ASSERT_TRUE(entt::locator<base_service>::has_value());
ASSERT_TRUE(null_service::invoked);
ASSERT_EQ(entt::locator<base_service>::value().invoke(3), 4);
auto handle = entt::locator<base_service>::handle();
entt::locator<base_service>::reset();
ASSERT_FALSE(entt::locator<base_service>::has_value());
@ -51,28 +63,25 @@ TEST(ServiceLocator, Functionalities) {
entt::locator<base_service>::reset(handle);
ASSERT_TRUE(entt::locator<base_service>::has_value());
entt::locator<base_service>::reset(decltype(handle){});
ASSERT_FALSE(entt::locator<base_service>::has_value());
entt::locator<base_service>::emplace<derived_service>();
entt::locator<base_service>::value().invoke();
ASSERT_TRUE(entt::locator<base_service>::has_value());
ASSERT_TRUE(derived_service::invoked);
derived_service::invoked = false;
entt::locator<base_service>::allocate_emplace<derived_service>(std::allocator<derived_service>{}).invoke();
ASSERT_TRUE(entt::locator<base_service>::has_value());
ASSERT_TRUE(derived_service::invoked);
ASSERT_EQ(entt::locator<base_service>::value().invoke(3), 4);
}
ENTT_DEBUG_TEST(ServiceLocatorDeathTest, UninitializedValue) {
ASSERT_NO_FATAL_FAILURE(entt::locator<base_service>::value_or().invoke());
TEST_F(ServiceLocator, ElementWithDeleter) {
derived_service service{1};
entt::locator<base_service>::reset(&service, [](base_service *serv) { *static_cast<derived_service *>(serv) = derived_service{2}; });
ASSERT_TRUE(entt::locator<base_service>::has_value());
ASSERT_EQ(entt::locator<base_service>::value().invoke(1), 2);
entt::locator<base_service>::reset();
ASSERT_DEATH(entt::locator<base_service>::value().invoke(), "");
ASSERT_EQ(service.invoke(1), 3);
}
ENTT_DEBUG_TEST_F(ServiceLocatorDeathTest, UninitializedValue) {
ASSERT_EQ(entt::locator<base_service>::value_or<derived_service>(1).invoke(1), 2);
entt::locator<base_service>::reset();
ASSERT_DEATH(entt::locator<base_service>::value().invoke(42), "");
}

View File

@ -78,9 +78,6 @@ struct MetaAny: ::testing::Test {
void SetUp() override {
using namespace entt::literals;
entt::meta<double>()
.type("double"_hs);
entt::meta<empty_t>()
.type("empty"_hs)
.dtor<empty_t::destroy>();

View File

@ -15,25 +15,7 @@
struct invalid_type {};
struct MetaContainer: ::testing::Test {
void SetUp() override {
using namespace entt::literals;
entt::meta<double>()
.type("double"_hs);
entt::meta<int>()
.type("int"_hs);
}
void TearDown() override {
entt::meta_reset();
}
};
using MetaContainerDeathTest = MetaContainer;
TEST_F(MetaContainer, InvalidContainer) {
TEST(MetaContainer, InvalidContainer) {
ASSERT_FALSE(entt::meta_any{42}.as_sequence_container());
ASSERT_FALSE(entt::meta_any{42}.as_associative_container());
@ -41,7 +23,7 @@ TEST_F(MetaContainer, InvalidContainer) {
ASSERT_FALSE(entt::meta_any{std::vector<int>{}}.as_associative_container());
}
TEST_F(MetaContainer, EmptySequenceContainer) {
TEST(MetaContainer, EmptySequenceContainer) {
entt::meta_sequence_container container{};
ASSERT_FALSE(container);
@ -52,7 +34,7 @@ TEST_F(MetaContainer, EmptySequenceContainer) {
ASSERT_TRUE(container);
}
TEST_F(MetaContainer, EmptyAssociativeContainer) {
TEST(MetaContainer, EmptyAssociativeContainer) {
entt::meta_associative_container container{};
ASSERT_FALSE(container);
@ -63,7 +45,7 @@ TEST_F(MetaContainer, EmptyAssociativeContainer) {
ASSERT_TRUE(container);
}
TEST_F(MetaContainer, SequenceContainerIterator) {
TEST(MetaContainer, SequenceContainerIterator) {
std::vector<int> vec{2, 3, 4};
auto any = entt::forward_as_meta(vec);
entt::meta_sequence_container::iterator first{};
@ -92,7 +74,7 @@ TEST_F(MetaContainer, SequenceContainerIterator) {
ASSERT_EQ((--first)->cast<int>(), 2);
}
TEST_F(MetaContainer, AssociativeContainerIterator) {
TEST(MetaContainer, AssociativeContainerIterator) {
std::map<int, char> map{{2, 'c'}, {3, 'd'}, {4, 'e'}};
auto any = entt::forward_as_meta(map);
entt::meta_associative_container::iterator first{};
@ -119,7 +101,7 @@ TEST_F(MetaContainer, AssociativeContainerIterator) {
ASSERT_FALSE(first != last);
}
TEST_F(MetaContainer, StdVector) {
TEST(MetaContainer, StdVector) {
std::vector<int> vec{};
auto any = entt::forward_as_meta(vec);
auto view = any.as_sequence_container();
@ -173,7 +155,7 @@ TEST_F(MetaContainer, StdVector) {
ASSERT_EQ(view.size(), 0u);
}
TEST_F(MetaContainer, StdArray) {
TEST(MetaContainer, StdArray) {
std::array<int, 3> arr{};
auto any = entt::forward_as_meta(arr);
auto view = any.as_sequence_container();
@ -214,7 +196,7 @@ TEST_F(MetaContainer, StdArray) {
ASSERT_EQ(view.size(), 3u);
}
TEST_F(MetaContainer, StdList) {
TEST(MetaContainer, StdList) {
std::list<int> list{};
auto any = entt::forward_as_meta(list);
auto view = any.as_sequence_container();
@ -268,7 +250,7 @@ TEST_F(MetaContainer, StdList) {
ASSERT_EQ(view.size(), 0u);
}
TEST_F(MetaContainer, StdDeque) {
TEST(MetaContainer, StdDeque) {
std::deque<int> deque{};
auto any = entt::forward_as_meta(deque);
auto view = any.as_sequence_container();
@ -322,7 +304,7 @@ TEST_F(MetaContainer, StdDeque) {
ASSERT_EQ(view.size(), 0u);
}
TEST_F(MetaContainer, StdMap) {
TEST(MetaContainer, StdMap) {
std::map<int, char> map{{2, 'c'}, {3, 'd'}, {4, 'e'}};
auto any = entt::forward_as_meta(map);
auto view = any.as_associative_container();
@ -365,7 +347,7 @@ TEST_F(MetaContainer, StdMap) {
ASSERT_EQ(view.size(), 0u);
}
TEST_F(MetaContainer, StdSet) {
TEST(MetaContainer, StdSet) {
std::set<int> set{2, 3, 4};
auto any = entt::forward_as_meta(set);
auto view = any.as_associative_container();
@ -407,7 +389,7 @@ TEST_F(MetaContainer, StdSet) {
ASSERT_EQ(view.size(), 0u);
}
TEST_F(MetaContainer, DenseMap) {
TEST(MetaContainer, DenseMap) {
entt::dense_map<int, char> map{};
auto any = entt::forward_as_meta(map);
auto view = any.as_associative_container();
@ -454,7 +436,7 @@ TEST_F(MetaContainer, DenseMap) {
ASSERT_EQ(view.size(), 0u);
}
TEST_F(MetaContainer, DenseSet) {
TEST(MetaContainer, DenseSet) {
entt::dense_set<int> set{};
auto any = entt::forward_as_meta(set);
auto view = any.as_associative_container();
@ -500,7 +482,7 @@ TEST_F(MetaContainer, DenseSet) {
ASSERT_EQ(view.size(), 0u);
}
TEST_F(MetaContainer, ConstSequenceContainer) {
TEST(MetaContainer, ConstSequenceContainer) {
std::vector<int> vec{};
auto any = entt::forward_as_meta(std::as_const(vec));
auto view = any.as_sequence_container();
@ -538,7 +520,7 @@ TEST_F(MetaContainer, ConstSequenceContainer) {
ASSERT_EQ(view.size(), 1u);
}
ENTT_DEBUG_TEST_F(MetaContainerDeathTest, ConstSequenceContainer) {
ENTT_DEBUG_TEST(MetaContainerDeathTest, ConstSequenceContainer) {
std::vector<int> vec{};
auto any = entt::forward_as_meta(std::as_const(vec));
auto view = any.as_sequence_container();
@ -547,7 +529,7 @@ ENTT_DEBUG_TEST_F(MetaContainerDeathTest, ConstSequenceContainer) {
ASSERT_DEATH(view[0].cast<int &>() = 2, "");
}
TEST_F(MetaContainer, ConstKeyValueAssociativeContainer) {
TEST(MetaContainer, ConstKeyValueAssociativeContainer) {
std::map<int, char> map{};
auto any = entt::forward_as_meta(std::as_const(map));
auto view = any.as_associative_container();
@ -580,7 +562,7 @@ TEST_F(MetaContainer, ConstKeyValueAssociativeContainer) {
ASSERT_EQ(view.size(), 1u);
}
ENTT_DEBUG_TEST_F(MetaContainerDeathTest, ConstKeyValueAssociativeContainer) {
ENTT_DEBUG_TEST(MetaContainerDeathTest, ConstKeyValueAssociativeContainer) {
std::map<int, char> map{};
auto any = entt::forward_as_meta(std::as_const(map));
auto view = any.as_associative_container();
@ -589,7 +571,7 @@ ENTT_DEBUG_TEST_F(MetaContainerDeathTest, ConstKeyValueAssociativeContainer) {
ASSERT_DEATH(view.find(2)->second.cast<char &>() = 'a', "");
}
TEST_F(MetaContainer, ConstKeyOnlyAssociativeContainer) {
TEST(MetaContainer, ConstKeyOnlyAssociativeContainer) {
std::set<int> set{};
auto any = entt::forward_as_meta(std::as_const(set));
auto view = any.as_associative_container();
@ -626,7 +608,7 @@ TEST_F(MetaContainer, ConstKeyOnlyAssociativeContainer) {
ASSERT_EQ(view.size(), 1u);
}
TEST_F(MetaContainer, SequenceContainerConstMetaAny) {
TEST(MetaContainer, SequenceContainerConstMetaAny) {
auto test = [](const entt::meta_any any) {
auto view = any.as_sequence_container();
@ -642,7 +624,7 @@ TEST_F(MetaContainer, SequenceContainerConstMetaAny) {
test(entt::forward_as_meta(std::as_const(vec)));
}
ENTT_DEBUG_TEST_F(MetaContainerDeathTest, SequenceContainerConstMetaAny) {
ENTT_DEBUG_TEST(MetaContainerDeathTest, SequenceContainerConstMetaAny) {
auto test = [](const entt::meta_any any) {
auto view = any.as_sequence_container();
@ -657,7 +639,7 @@ ENTT_DEBUG_TEST_F(MetaContainerDeathTest, SequenceContainerConstMetaAny) {
test(entt::forward_as_meta(std::as_const(vec)));
}
TEST_F(MetaContainer, KeyValueAssociativeContainerConstMetaAny) {
TEST(MetaContainer, KeyValueAssociativeContainerConstMetaAny) {
auto test = [](const entt::meta_any any) {
auto view = any.as_associative_container();
@ -673,7 +655,7 @@ TEST_F(MetaContainer, KeyValueAssociativeContainerConstMetaAny) {
test(entt::forward_as_meta(std::as_const(map)));
}
ENTT_DEBUG_TEST_F(MetaContainerDeathTest, KeyValueAssociativeContainerConstMetaAny) {
ENTT_DEBUG_TEST(MetaContainerDeathTest, KeyValueAssociativeContainerConstMetaAny) {
auto test = [](const entt::meta_any any) {
auto view = any.as_associative_container();
@ -688,7 +670,7 @@ ENTT_DEBUG_TEST_F(MetaContainerDeathTest, KeyValueAssociativeContainerConstMetaA
test(entt::forward_as_meta(std::as_const(map)));
}
TEST_F(MetaContainer, KeyOnlyAssociativeContainerConstMetaAny) {
TEST(MetaContainer, KeyOnlyAssociativeContainerConstMetaAny) {
auto test = [](const entt::meta_any any) {
auto view = any.as_associative_container();
@ -708,7 +690,7 @@ TEST_F(MetaContainer, KeyOnlyAssociativeContainerConstMetaAny) {
test(entt::forward_as_meta(std::as_const(set)));
}
TEST_F(MetaContainer, StdVectorBool) {
TEST(MetaContainer, StdVectorBool) {
using proxy_type = typename std::vector<bool>::reference;
using const_proxy_type = typename std::vector<bool>::const_reference;

View File

@ -79,7 +79,7 @@ struct multi_setter_t {
: value{0} {}
void from_double(double val) {
value = val;
value = static_cast<int>(val);
}
void from_string(const char *val) {
@ -103,9 +103,6 @@ struct MetaData: ::testing::Test {
void SetUp() override {
using namespace entt::literals;
entt::meta<double>()
.type("double"_hs);
entt::meta<base_t>()
.type("base"_hs)
.dtor<base_t::destroy>()
@ -167,6 +164,12 @@ TEST_F(MetaData, Functionalities) {
clazz_t instance{};
ASSERT_TRUE(data);
ASSERT_EQ(data, data);
ASSERT_NE(data, entt::meta_data{});
ASSERT_FALSE(data != data);
ASSERT_TRUE(data == data);
ASSERT_EQ(data.arity(), 1u);
ASSERT_EQ(data.type(), entt::resolve<int>());
ASSERT_EQ(data.arg(0u), entt::resolve<int>());

View File

@ -87,12 +87,17 @@ struct func_t {
inline static int value = 0;
};
double double_member(const double &value) {
return value * value;
}
struct MetaFunc: ::testing::Test {
void SetUp() override {
using namespace entt::literals;
entt::meta<double>()
.type("double"_hs);
.type("double"_hs)
.func<&double_member>("member"_hs);
entt::meta<base_t>()
.type("base"_hs)
@ -165,6 +170,12 @@ TEST_F(MetaFunc, Functionalities) {
func_t instance{};
ASSERT_TRUE(func);
ASSERT_EQ(func, func);
ASSERT_NE(func, entt::meta_func{});
ASSERT_FALSE(func != func);
ASSERT_TRUE(func == func);
ASSERT_EQ(func.arity(), 2u);
ASSERT_FALSE(func.is_const());
ASSERT_FALSE(func.is_static());
@ -384,6 +395,30 @@ TEST_F(MetaFunc, StaticAsConstMember) {
ASSERT_EQ(any.cast<int>(), 3);
}
TEST_F(MetaFunc, NonClassTypeMember) {
using namespace entt::literals;
double instance = 3.;
auto func = entt::resolve<double>().func("member"_hs);
auto any = func.invoke(instance);
ASSERT_TRUE(func);
ASSERT_EQ(func.arity(), 0u);
ASSERT_TRUE(func.is_const());
ASSERT_FALSE(func.is_static());
ASSERT_EQ(func.ret(), entt::resolve<double>());
ASSERT_FALSE(func.arg(0u));
ASSERT_EQ(func.prop().cbegin(), func.prop().cend());
ASSERT_FALSE(func.invoke({}));
ASSERT_TRUE(func.invoke(instance));
ASSERT_TRUE(any);
ASSERT_EQ(any.type(), entt::resolve<double>());
ASSERT_EQ(any.cast<double>(), instance * instance);
}
TEST_F(MetaFunc, MetaAnyArgs) {
using namespace entt::literals;

View File

@ -44,12 +44,22 @@ TEST_F(MetaHandle, Functionalities) {
ASSERT_FALSE(handle);
ASSERT_FALSE(chandle);
ASSERT_EQ(handle, chandle);
ASSERT_EQ(handle, entt::meta_handle{});
ASSERT_FALSE(handle != handle);
ASSERT_TRUE(handle == handle);
handle = entt::meta_handle{instance};
chandle = entt::meta_handle{std::as_const(instance)};
ASSERT_TRUE(handle);
ASSERT_TRUE(chandle);
ASSERT_EQ(handle, chandle);
ASSERT_NE(handle, entt::meta_handle{});
ASSERT_FALSE(handle != handle);
ASSERT_TRUE(handle == handle);
ASSERT_TRUE(handle->invoke("incr"_hs));
ASSERT_FALSE(chandle->invoke("incr"_hs));
ASSERT_FALSE(std::as_const(handle)->invoke("incr"_hs));

View File

@ -80,14 +80,6 @@ int test_function() {
return 42;
}
struct not_copyable_t {
not_copyable_t() = default;
not_copyable_t(const not_copyable_t &) = delete;
not_copyable_t(not_copyable_t &&) = default;
not_copyable_t &operator=(const not_copyable_t &) = delete;
not_copyable_t &operator=(not_copyable_t &&) = default;
};
TEST(MetaPointerLike, DereferenceOperatorInvalidType) {
int value = 0;
entt::meta_any any{value};
@ -213,16 +205,16 @@ TEST(MetaPointerLike, DereferenceOperatorSmartPointer) {
}
TEST(MetaPointerLike, PointerToConstMoveOnlyType) {
const not_copyable_t instance;
const std::unique_ptr<int> instance;
entt::meta_any any{&instance};
auto deref = *any;
ASSERT_TRUE(any);
ASSERT_TRUE(deref);
ASSERT_EQ(deref.try_cast<not_copyable_t>(), nullptr);
ASSERT_NE(deref.try_cast<const not_copyable_t>(), nullptr);
ASSERT_EQ(&deref.cast<const not_copyable_t &>(), &instance);
ASSERT_EQ(deref.try_cast<std::unique_ptr<int>>(), nullptr);
ASSERT_NE(deref.try_cast<const std::unique_ptr<int>>(), nullptr);
ASSERT_EQ(&deref.cast<const std::unique_ptr<int> &>(), &instance);
}
TEST(MetaPointerLike, AsRef) {

View File

@ -49,7 +49,23 @@ TEST_F(MetaProp, Functionalities) {
auto prop = entt::resolve<base_1_t>().prop("int"_hs);
ASSERT_TRUE(prop);
ASSERT_EQ(prop.value(), 42);
ASSERT_EQ(prop, prop);
ASSERT_NE(prop, entt::meta_prop{});
ASSERT_FALSE(prop != prop);
ASSERT_TRUE(prop == prop);
auto value = prop.value();
auto cvalue = std::as_const(prop).value();
ASSERT_NE(value.try_cast<int>(), nullptr);
ASSERT_EQ(cvalue.try_cast<int>(), nullptr);
ASSERT_NE(value.try_cast<const int>(), nullptr);
ASSERT_NE(cvalue.try_cast<const int>(), nullptr);
ASSERT_EQ(value, 42);
ASSERT_EQ(cvalue, 42);
}
TEST_F(MetaProp, FromBase) {

View File

@ -378,7 +378,10 @@ TEST_F(MetaType, Invoke) {
clazz_t instance{};
ASSERT_TRUE(type.invoke("member"_hs, instance));
ASSERT_FALSE(type.invoke("rebmem"_hs, {}));
ASSERT_FALSE(type.invoke("rebmem"_hs, instance));
ASSERT_TRUE(type.invoke("func"_hs, {}));
ASSERT_FALSE(type.invoke("cnuf"_hs, {}));
}
TEST_F(MetaType, InvokeFromBase) {

View File

@ -18,7 +18,7 @@ struct common_type: Base {
}
int get() const {
return entt::poly_call<2>(*this);
return static_cast<int>(entt::poly_call<2>(*this));
}
void decr() {
@ -26,11 +26,11 @@ struct common_type: Base {
}
int mul(int v) const {
return entt::poly_call<4>(*this, v);
return static_cast<int>(entt::poly_call<4>(*this, v));
}
int rand() const {
return entt::poly_call<5>(*this);
return static_cast<int>(entt::poly_call<5>(*this));
}
};
@ -385,7 +385,7 @@ TYPED_TEST(Poly, SBOVsZeroedSBOSize) {
}
TYPED_TEST(Poly, SboAlignment) {
static constexpr auto alignment = alignof(over_aligned);
constexpr auto alignment = alignof(over_aligned);
typename TestFixture::template type<alignment, alignment> sbo[2]{over_aligned{}, over_aligned{}};
const auto *data = sbo[0].data();
@ -401,7 +401,7 @@ TYPED_TEST(Poly, SboAlignment) {
}
TYPED_TEST(Poly, NoSboAlignment) {
static constexpr auto alignment = alignof(over_aligned);
constexpr auto alignment = alignof(over_aligned);
typename TestFixture::template type<alignment> nosbo[2]{over_aligned{}, over_aligned{}};
const auto *data = nosbo[0].data();

View File

@ -4,7 +4,7 @@
#include <entt/process/process.hpp>
#include <entt/process/scheduler.hpp>
struct foo_process: entt::process<foo_process, int> {
struct foo_process: entt::process<foo_process, entt::scheduler::delta_type> {
foo_process(std::function<void()> upd, std::function<void()> abort)
: on_update{upd}, on_aborted{abort} {}
@ -20,7 +20,7 @@ struct foo_process: entt::process<foo_process, int> {
std::function<void()> on_aborted;
};
struct succeeded_process: entt::process<succeeded_process, int> {
struct succeeded_process: entt::process<succeeded_process, entt::scheduler::delta_type> {
void update(delta_type, void *) {
++invoked;
succeed();
@ -29,7 +29,7 @@ struct succeeded_process: entt::process<succeeded_process, int> {
static inline unsigned int invoked;
};
struct failed_process: entt::process<failed_process, int> {
struct failed_process: entt::process<failed_process, entt::scheduler::delta_type> {
void update(delta_type, void *) {
++invoked;
fail();
@ -46,7 +46,7 @@ struct Scheduler: ::testing::Test {
};
TEST_F(Scheduler, Functionalities) {
entt::scheduler<int> scheduler{};
entt::scheduler scheduler{};
bool updated = false;
bool aborted = false;
@ -77,7 +77,7 @@ TEST_F(Scheduler, Functionalities) {
}
TEST_F(Scheduler, Then) {
entt::scheduler<int> scheduler;
entt::scheduler scheduler;
// failing process with successor
scheduler.attach<succeeded_process>()
@ -106,7 +106,7 @@ TEST_F(Scheduler, Then) {
}
TEST_F(Scheduler, Functor) {
entt::scheduler<int> scheduler;
entt::scheduler scheduler;
bool first_functor = false;
bool second_functor = false;
@ -135,7 +135,7 @@ TEST_F(Scheduler, Functor) {
}
TEST_F(Scheduler, SpawningProcess) {
entt::scheduler<int> scheduler;
entt::scheduler scheduler;
scheduler.attach([&scheduler](auto, void *, auto resolve, auto) {
scheduler.attach<succeeded_process>().then<failed_process>();

View File

@ -90,12 +90,12 @@ TEST(Resource, ConstNonConstAndAllInBetween) {
ASSERT_TRUE(copy);
ASSERT_EQ(copy, resource);
ASSERT_NE(copy, entt::resource<derived>{});
ASSERT_EQ(copy.handle().use_count(), 3u);
ASSERT_EQ(copy.handle().use_count(), 3);
ASSERT_TRUE(move);
ASSERT_EQ(move, resource);
ASSERT_NE(move, entt::resource<derived>{});
ASSERT_EQ(move.handle().use_count(), 3u);
ASSERT_EQ(move.handle().use_count(), 3);
copy = resource;
move = std::move(resource);
@ -105,7 +105,7 @@ TEST(Resource, ConstNonConstAndAllInBetween) {
ASSERT_TRUE(copy);
ASSERT_TRUE(move);
ASSERT_EQ(copy.handle().use_count(), 2u);
ASSERT_EQ(copy.handle().use_count(), 2);
}
TEST(Resource, DynamicResourceHandleCast) {
@ -113,20 +113,20 @@ TEST(Resource, DynamicResourceHandleCast) {
entt::resource<const base> other = resource;
ASSERT_TRUE(other);
ASSERT_EQ(resource.handle().use_count(), 2u);
ASSERT_EQ(resource.handle().use_count(), 2);
ASSERT_EQ(resource, other);
entt::resource<const derived> cast = dynamic_resource_cast<const derived>(other);
ASSERT_TRUE(cast);
ASSERT_EQ(resource.handle().use_count(), 3u);
ASSERT_EQ(resource.handle().use_count(), 3);
ASSERT_EQ(resource, cast);
other = entt::resource<base>{std::make_shared<base>()};
cast = dynamic_resource_cast<const derived>(other);
ASSERT_FALSE(cast);
ASSERT_EQ(resource.handle().use_count(), 1u);
ASSERT_EQ(resource.handle().use_count(), 1);
}
TEST(Resource, Comparison) {

View File

@ -318,17 +318,17 @@ TEST(ResourceCache, Load) {
}
TEST(ResourceCache, Erase) {
static constexpr std::size_t resource_count = 8u;
constexpr std::size_t resource_count = 8u;
entt::resource_cache<std::size_t> cache;
for(std::size_t next{}, last = resource_count + 1u; next < last; ++next) {
cache.load(next, next);
cache.load(static_cast<entt::id_type>(next), next);
}
ASSERT_EQ(cache.size(), resource_count + 1u);
for(std::size_t next{}, last = resource_count + 1u; next < last; ++next) {
ASSERT_TRUE(cache.contains(next));
ASSERT_TRUE(cache.contains(static_cast<entt::id_type>(next)));
}
auto it = cache.erase(++cache.begin());
@ -346,16 +346,16 @@ TEST(ResourceCache, Erase) {
for(std::size_t next{}, last = resource_count + 1u; next < last; ++next) {
if(next == 1u || next == 8u || next == 6u) {
ASSERT_FALSE(cache.contains(next));
ASSERT_FALSE(cache.contains(static_cast<entt::id_type>(next)));
} else {
ASSERT_TRUE(cache.contains(next));
ASSERT_TRUE(cache.contains(static_cast<entt::id_type>(next)));
}
}
cache.erase(cache.begin(), cache.end());
for(std::size_t next{}, last = resource_count + 1u; next < last; ++next) {
ASSERT_FALSE(cache.contains(next));
ASSERT_FALSE(cache.contains(static_cast<entt::id_type>(next)));
}
ASSERT_EQ(cache.size(), 0u);

View File

@ -5,16 +5,16 @@
#include <entt/signal/delegate.hpp>
#include "../common/config.h"
int delegate_function(const int &i) {
int power_of_two(const int &i) {
return i * i;
}
int curried_by_ref(const int &i, int j) {
int sum_with_ref(const int &i, int j) {
return i + j;
}
int curried_by_ptr(const int *i, int j) {
return (*i) * j;
int sum_with_ptr(const int *i, int j) {
return (*i) + j;
}
int non_const_reference(int &i) {
@ -70,7 +70,7 @@ TEST(Delegate, Functionalities) {
ASSERT_FALSE(mf_del);
ASSERT_EQ(ff_del, mf_del);
ff_del.connect<&delegate_function>();
ff_del.connect<&power_of_two>();
mf_del.connect<&delegate_functor::operator()>(functor);
lf_del.connect([](const void *ptr, int value) { return static_cast<const delegate_functor *>(ptr)->identity(value); }, &functor);
@ -138,44 +138,44 @@ TEST(Delegate, Comparison) {
ASSERT_TRUE(lhs == rhs);
ASSERT_EQ(lhs, rhs);
lhs.connect<&delegate_function>();
lhs.connect<&power_of_two>();
ASSERT_EQ(lhs, entt::delegate<int(int)>{entt::connect_arg<&delegate_function>});
ASSERT_EQ(lhs, entt::delegate<int(int)>{entt::connect_arg<&power_of_two>});
ASSERT_TRUE(lhs != rhs);
ASSERT_FALSE(lhs == rhs);
ASSERT_NE(lhs, rhs);
rhs.connect<&delegate_function>();
rhs.connect<&power_of_two>();
ASSERT_EQ(rhs, entt::delegate<int(int)>{entt::connect_arg<&delegate_function>});
ASSERT_EQ(rhs, entt::delegate<int(int)>{entt::connect_arg<&power_of_two>});
ASSERT_FALSE(lhs != rhs);
ASSERT_TRUE(lhs == rhs);
ASSERT_EQ(lhs, rhs);
lhs.connect<&curried_by_ref>(value);
lhs.connect<&sum_with_ref>(value);
ASSERT_EQ(lhs, (entt::delegate<int(int)>{entt::connect_arg<&curried_by_ref>, value}));
ASSERT_EQ(lhs, (entt::delegate<int(int)>{entt::connect_arg<&sum_with_ref>, value}));
ASSERT_TRUE(lhs != rhs);
ASSERT_FALSE(lhs == rhs);
ASSERT_NE(lhs, rhs);
rhs.connect<&curried_by_ref>(value);
rhs.connect<&sum_with_ref>(value);
ASSERT_EQ(rhs, (entt::delegate<int(int)>{entt::connect_arg<&curried_by_ref>, value}));
ASSERT_EQ(rhs, (entt::delegate<int(int)>{entt::connect_arg<&sum_with_ref>, value}));
ASSERT_FALSE(lhs != rhs);
ASSERT_TRUE(lhs == rhs);
ASSERT_EQ(lhs, rhs);
lhs.connect<&curried_by_ptr>(&value);
lhs.connect<&sum_with_ptr>(&value);
ASSERT_EQ(lhs, (entt::delegate<int(int)>{entt::connect_arg<&curried_by_ptr>, &value}));
ASSERT_EQ(lhs, (entt::delegate<int(int)>{entt::connect_arg<&sum_with_ptr>, &value}));
ASSERT_TRUE(lhs != rhs);
ASSERT_FALSE(lhs == rhs);
ASSERT_NE(lhs, rhs);
rhs.connect<&curried_by_ptr>(&value);
rhs.connect<&sum_with_ptr>(&value);
ASSERT_EQ(rhs, (entt::delegate<int(int)>{entt::connect_arg<&curried_by_ptr>, &value}));
ASSERT_EQ(rhs, (entt::delegate<int(int)>{entt::connect_arg<&sum_with_ptr>, &value}));
ASSERT_FALSE(lhs != rhs);
ASSERT_TRUE(lhs == rhs);
ASSERT_EQ(lhs, rhs);
@ -190,6 +190,8 @@ TEST(Delegate, Comparison) {
rhs.connect<&delegate_functor::operator()>(functor);
ASSERT_EQ(rhs, (entt::delegate<int(int)>{entt::connect_arg<&delegate_functor::operator()>, functor}));
ASSERT_EQ(lhs.target(), rhs.target());
ASSERT_EQ(lhs.data(), rhs.data());
ASSERT_FALSE(lhs != rhs);
ASSERT_TRUE(lhs == rhs);
ASSERT_EQ(lhs, rhs);
@ -197,6 +199,7 @@ TEST(Delegate, Comparison) {
lhs.connect<&delegate_functor::operator()>(other);
ASSERT_EQ(lhs, (entt::delegate<int(int)>{entt::connect_arg<&delegate_functor::operator()>, other}));
ASSERT_EQ(lhs.target(), rhs.target());
ASSERT_NE(lhs.data(), rhs.data());
ASSERT_TRUE(lhs != rhs);
ASSERT_FALSE(lhs == rhs);
@ -205,6 +208,8 @@ TEST(Delegate, Comparison) {
lhs.connect([](const void *ptr, int val) { return static_cast<const delegate_functor *>(ptr)->identity(val) * val; }, &functor);
ASSERT_NE(lhs, (entt::delegate<int(int)>{[](const void *, int val) { return val + val; }, &functor}));
ASSERT_NE(lhs.target(), rhs.target());
ASSERT_EQ(lhs.data(), rhs.data());
ASSERT_TRUE(lhs != rhs);
ASSERT_FALSE(lhs == rhs);
ASSERT_NE(lhs, rhs);
@ -254,11 +259,11 @@ TEST(Delegate, DeductionGuide) {
const_nonconst_noexcept functor;
int value = 0;
entt::delegate func{entt::connect_arg<&delegate_function>};
entt::delegate curried_func_with_ref{entt::connect_arg<&curried_by_ref>, value};
entt::delegate curried_func_with_const_ref{entt::connect_arg<&curried_by_ref>, std::as_const(value)};
entt::delegate curried_func_with_ptr{entt::connect_arg<&curried_by_ptr>, &value};
entt::delegate curried_func_with_const_ptr{entt::connect_arg<&curried_by_ptr>, &std::as_const(value)};
entt::delegate plain_func{entt::connect_arg<&power_of_two>};
entt::delegate sum_func_with_ref{entt::connect_arg<&sum_with_ref>, value};
entt::delegate sum_func_with_const_ref{entt::connect_arg<&sum_with_ref>, std::as_const(value)};
entt::delegate sum_func_with_ptr{entt::connect_arg<&sum_with_ptr>, &value};
entt::delegate sum_func_with_const_ptr{entt::connect_arg<&sum_with_ptr>, &std::as_const(value)};
entt::delegate member_func_f{entt::connect_arg<&const_nonconst_noexcept::f>, functor};
entt::delegate member_func_g{entt::connect_arg<&const_nonconst_noexcept::g>, functor};
entt::delegate member_func_h{entt::connect_arg<&const_nonconst_noexcept::h>, &functor};
@ -270,11 +275,11 @@ TEST(Delegate, DeductionGuide) {
entt::delegate data_member_v_const{entt::connect_arg<&const_nonconst_noexcept::v>, &std::as_const(functor)};
entt::delegate lambda{+[](const void *, int) { return 0; }};
static_assert(std::is_same_v<typename decltype(func)::type, int(const int &)>);
static_assert(std::is_same_v<typename decltype(curried_func_with_ref)::type, int(int)>);
static_assert(std::is_same_v<typename decltype(curried_func_with_const_ref)::type, int(int)>);
static_assert(std::is_same_v<typename decltype(curried_func_with_ptr)::type, int(int)>);
static_assert(std::is_same_v<typename decltype(curried_func_with_const_ptr)::type, int(int)>);
static_assert(std::is_same_v<typename decltype(plain_func)::type, int(const int &)>);
static_assert(std::is_same_v<typename decltype(sum_func_with_ref)::type, int(int)>);
static_assert(std::is_same_v<typename decltype(sum_func_with_const_ref)::type, int(int)>);
static_assert(std::is_same_v<typename decltype(sum_func_with_ptr)::type, int(int)>);
static_assert(std::is_same_v<typename decltype(sum_func_with_const_ptr)::type, int(int)>);
static_assert(std::is_same_v<typename decltype(member_func_f)::type, void()>);
static_assert(std::is_same_v<typename decltype(member_func_g)::type, void()>);
static_assert(std::is_same_v<typename decltype(member_func_h)::type, void()>);
@ -286,11 +291,11 @@ TEST(Delegate, DeductionGuide) {
static_assert(std::is_same_v<typename decltype(data_member_v_const)::type, const int()>);
static_assert(std::is_same_v<typename decltype(lambda)::type, int(int)>);
ASSERT_TRUE(func);
ASSERT_TRUE(curried_func_with_ref);
ASSERT_TRUE(curried_func_with_const_ref);
ASSERT_TRUE(curried_func_with_ptr);
ASSERT_TRUE(curried_func_with_const_ptr);
ASSERT_TRUE(plain_func);
ASSERT_TRUE(sum_func_with_ref);
ASSERT_TRUE(sum_func_with_const_ref);
ASSERT_TRUE(sum_func_with_ptr);
ASSERT_TRUE(sum_func_with_const_ptr);
ASSERT_TRUE(member_func_f);
ASSERT_TRUE(member_func_g);
ASSERT_TRUE(member_func_h);
@ -338,19 +343,46 @@ TEST(Delegate, MoveOnlyType) {
ASSERT_FALSE(ptr);
}
TEST(Delegate, CurriedFunction) {
entt::delegate<int(int)> delegate;
TEST(Delegate, DiscardLast) {
entt::delegate<int(int, const std::unique_ptr<int> &)> delegate;
const auto value = 3;
const auto other = std::make_unique<int>(42);
delegate.connect<&curried_by_ref>(value);
delegate.connect<&power_of_two>();
ASSERT_TRUE(delegate);
ASSERT_EQ(delegate(1), 4);
ASSERT_EQ(delegate(3, other), 9);
delegate.connect<&curried_by_ptr>(&value);
delegate.connect<&sum_with_ref>(value);
ASSERT_TRUE(delegate);
ASSERT_EQ(delegate(2), 6);
ASSERT_EQ(delegate(1, other), 4);
delegate.connect<&sum_with_ptr>(&value);
ASSERT_TRUE(delegate);
ASSERT_EQ(delegate(2, other), 5);
}
TEST(Delegate, SkipFirst) {
entt::delegate<int(const std::unique_ptr<int> &, int)> delegate;
const auto value = 3;
const auto other = std::make_unique<int>(42);
delegate.connect<&power_of_two>();
ASSERT_TRUE(delegate);
ASSERT_EQ(delegate(other, 3), 9);
delegate.connect<&sum_with_ref>(value);
ASSERT_TRUE(delegate);
ASSERT_EQ(delegate(other, 1), 4);
delegate.connect<&sum_with_ptr>(&value);
ASSERT_TRUE(delegate);
ASSERT_EQ(delegate(other, 2), 5);
}
TEST(Delegate, Constructors) {
@ -358,9 +390,9 @@ TEST(Delegate, Constructors) {
const auto value = 2;
entt::delegate<int(int)> empty{};
entt::delegate<int(int)> func{entt::connect_arg<&delegate_function>};
entt::delegate<int(int)> ref{entt::connect_arg<&curried_by_ref>, value};
entt::delegate<int(int)> ptr{entt::connect_arg<&curried_by_ptr>, &value};
entt::delegate<int(int)> func{entt::connect_arg<&power_of_two>};
entt::delegate<int(int)> ref{entt::connect_arg<&sum_with_ref>, value};
entt::delegate<int(int)> ptr{entt::connect_arg<&sum_with_ptr>, &value};
entt::delegate<int(int)> member{entt::connect_arg<&delegate_functor::operator()>, functor};
ASSERT_FALSE(empty);
@ -372,7 +404,7 @@ TEST(Delegate, Constructors) {
ASSERT_EQ(5, ref(3));
ASSERT_TRUE(ptr);
ASSERT_EQ(6, ptr(3));
ASSERT_EQ(5, ptr(3));
ASSERT_TRUE(member);
ASSERT_EQ(6, member(3));
@ -381,7 +413,7 @@ TEST(Delegate, Constructors) {
TEST(Delegate, VoidVsNonVoidReturnType) {
delegate_functor functor;
entt::delegate<void(int)> func{entt::connect_arg<&delegate_function>};
entt::delegate<void(int)> func{entt::connect_arg<&power_of_two>};
entt::delegate<void(int)> member{entt::connect_arg<&delegate_functor::operator()>, &functor};
entt::delegate<void(int)> cmember{entt::connect_arg<&delegate_functor::identity>, &std::as_const(functor)};
@ -411,8 +443,8 @@ TEST(Delegate, TheLessTheBetter) {
entt::delegate<int(delegate_functor &, int, char)> unbound;
delegate_functor functor;
// int delegate_function(const int &);
bound.connect<&delegate_function>();
// int power_of_two(const int &);
bound.connect<&power_of_two>();
ASSERT_EQ(bound(3, 'c'), 9);

View File

@ -25,32 +25,6 @@ struct sigh_listener {
bool k{false};
};
struct before_after {
void add(int v) {
value += v;
}
void mul(int v) {
value *= v;
}
static void static_add(int v) {
before_after::value += v;
}
static void static_mul(before_after &instance, int v) {
instance.value *= v;
}
static inline int value{};
};
struct SigH: ::testing::Test {
void SetUp() override {
before_after::value = 0;
}
};
struct const_nonconst_noexcept {
void f() {
++cnt;
@ -71,7 +45,13 @@ struct const_nonconst_noexcept {
mutable int cnt{0};
};
TEST_F(SigH, Lifetime) {
void connect_and_auto_disconnect(entt::sigh<void(int &)> &sigh, const int &) {
entt::sink sink{sigh};
sink.connect<sigh_listener::f>();
sink.disconnect<&connect_and_auto_disconnect>(sigh);
}
TEST(SigH, Lifetime) {
using signal = entt::sigh<void(void)>;
ASSERT_NO_FATAL_FAILURE(signal{});
@ -86,7 +66,7 @@ TEST_F(SigH, Lifetime) {
ASSERT_NO_FATAL_FAILURE(delete new signal{});
}
TEST_F(SigH, Clear) {
TEST(SigH, Clear) {
entt::sigh<void(int &)> sigh;
entt::sink sink{sigh};
@ -106,7 +86,7 @@ TEST_F(SigH, Clear) {
ASSERT_TRUE(sigh.empty());
}
TEST_F(SigH, Swap) {
TEST(SigH, Swap) {
entt::sigh<void(int &)> sigh1;
entt::sigh<void(int &)> sigh2;
entt::sink sink1{sigh1};
@ -129,7 +109,7 @@ TEST_F(SigH, Swap) {
ASSERT_FALSE(sigh2.empty());
}
TEST_F(SigH, Functions) {
TEST(SigH, Functions) {
entt::sigh<void(int &)> sigh;
entt::sink sink{sigh};
int v = 0;
@ -150,7 +130,7 @@ TEST_F(SigH, Functions) {
ASSERT_EQ(v, 0);
}
TEST_F(SigH, FunctionsWithPayload) {
TEST(SigH, FunctionsWithPayload) {
entt::sigh<void()> sigh;
entt::sink sink{sigh};
int v = 0;
@ -171,13 +151,13 @@ TEST_F(SigH, FunctionsWithPayload) {
ASSERT_EQ(v, 0);
sink.connect<&sigh_listener::f>(v);
sink.disconnect(v);
sink.disconnect(&v);
sigh.publish();
ASSERT_EQ(v, 0);
}
TEST_F(SigH, Members) {
TEST(SigH, Members) {
sigh_listener l1, l2;
entt::sigh<bool(int)> sigh;
entt::sink sink{sigh};
@ -213,7 +193,7 @@ TEST_F(SigH, Members) {
ASSERT_EQ(1u, sigh.size());
}
TEST_F(SigH, Collector) {
TEST(SigH, Collector) {
sigh_listener listener;
entt::sigh<bool(int)> sigh;
entt::sink sink{sigh};
@ -247,7 +227,7 @@ TEST_F(SigH, Collector) {
ASSERT_EQ(cnt, 1);
}
TEST_F(SigH, CollectorVoid) {
TEST(SigH, CollectorVoid) {
sigh_listener listener;
entt::sigh<void(int)> sigh;
entt::sink sink{sigh};
@ -271,7 +251,7 @@ TEST_F(SigH, CollectorVoid) {
ASSERT_EQ(cnt, 1);
}
TEST_F(SigH, Connection) {
TEST(SigH, Connection) {
entt::sigh<void(int &)> sigh;
entt::sink sink{sigh};
int v = 0;
@ -292,7 +272,7 @@ TEST_F(SigH, Connection) {
ASSERT_EQ(0, v);
}
TEST_F(SigH, ScopedConnection) {
TEST(SigH, ScopedConnection) {
sigh_listener listener;
entt::sigh<void(int)> sigh;
entt::sink sink{sigh};
@ -314,7 +294,7 @@ TEST_F(SigH, ScopedConnection) {
ASSERT_TRUE(listener.k);
}
TEST_F(SigH, ScopedConnectionMove) {
TEST(SigH, ScopedConnectionMove) {
sigh_listener listener;
entt::sigh<void(int)> sigh;
entt::sink sink{sigh};
@ -363,7 +343,7 @@ TEST_F(SigH, ScopedConnectionMove) {
ASSERT_TRUE(sigh.empty());
}
TEST_F(SigH, ScopedConnectionConstructorsAndOperators) {
TEST(SigH, ScopedConnectionConstructorsAndOperators) {
sigh_listener listener;
entt::sigh<void(int)> sigh;
entt::sink sink{sigh};
@ -402,7 +382,7 @@ TEST_F(SigH, ScopedConnectionConstructorsAndOperators) {
ASSERT_FALSE(listener.k);
}
TEST_F(SigH, ConstNonConstNoExcept) {
TEST(SigH, ConstNonConstNoExcept) {
entt::sigh<void()> sigh;
entt::sink sink{sigh};
const_nonconst_noexcept functor;
@ -427,83 +407,7 @@ TEST_F(SigH, ConstNonConstNoExcept) {
ASSERT_EQ(cfunctor.cnt, 2);
}
TEST_F(SigH, BeforeFunction) {
entt::sigh<void(int)> sigh;
entt::sink sink{sigh};
before_after functor;
sink.connect<&before_after::add>(functor);
sink.connect<&before_after::static_add>();
sink.before<&before_after::static_add>().connect<&before_after::mul>(functor);
sigh.publish(2);
ASSERT_EQ(functor.value, 6);
}
TEST_F(SigH, BeforeMemberFunction) {
entt::sigh<void(int)> sigh;
entt::sink sink{sigh};
before_after functor;
sink.connect<&before_after::static_add>();
sink.connect<&before_after::add>(functor);
sink.before<&before_after::add>(functor).connect<&before_after::mul>(functor);
sigh.publish(2);
ASSERT_EQ(functor.value, 6);
}
TEST_F(SigH, BeforeFunctionWithPayload) {
entt::sigh<void(int)> sigh;
entt::sink sink{sigh};
before_after functor;
sink.connect<&before_after::static_add>();
sink.connect<&before_after::static_mul>(functor);
sink.before<&before_after::static_mul>(functor).connect<&before_after::add>(functor);
sigh.publish(2);
ASSERT_EQ(functor.value, 8);
}
TEST_F(SigH, BeforeInstanceOrPayload) {
entt::sigh<void(int)> sigh;
entt::sink sink{sigh};
before_after functor;
sink.connect<&before_after::static_mul>(functor);
sink.connect<&before_after::add>(functor);
sink.before(functor).connect<&before_after::static_add>();
sigh.publish(2);
ASSERT_EQ(functor.value, 6);
}
TEST_F(SigH, BeforeAnythingElse) {
entt::sigh<void(int)> sigh;
entt::sink sink{sigh};
before_after functor;
sink.connect<&before_after::add>(functor);
sink.before().connect<&before_after::mul>(functor);
sigh.publish(2);
ASSERT_EQ(functor.value, 2);
}
TEST_F(SigH, BeforeListenerNotPresent) {
entt::sigh<void(int)> sigh;
entt::sink sink{sigh};
before_after functor;
sink.connect<&before_after::mul>(functor);
sink.before<&before_after::add>(&functor).connect<&before_after::add>(functor);
sigh.publish(2);
ASSERT_EQ(functor.value, 2);
}
TEST_F(SigH, UnboundDataMember) {
TEST(SigH, UnboundDataMember) {
sigh_listener listener;
entt::sigh<bool &(sigh_listener &)> sigh;
entt::sink sink{sigh};
@ -516,7 +420,7 @@ TEST_F(SigH, UnboundDataMember) {
ASSERT_TRUE(listener.k);
}
TEST_F(SigH, UnboundMemberFunction) {
TEST(SigH, UnboundMemberFunction) {
sigh_listener listener;
entt::sigh<void(sigh_listener *, int)> sigh;
entt::sink sink{sigh};
@ -529,7 +433,33 @@ TEST_F(SigH, UnboundMemberFunction) {
ASSERT_TRUE(listener.k);
}
TEST_F(SigH, CustomAllocator) {
TEST(SigH, ConnectAndAutoDisconnect) {
sigh_listener listener;
entt::sigh<void(int &)> sigh;
entt::sink sink{sigh};
int v = 0;
sink.connect<&sigh_listener::g>(listener);
sink.connect<&connect_and_auto_disconnect>(sigh);
ASSERT_FALSE(listener.k);
ASSERT_EQ(sigh.size(), 2u);
ASSERT_EQ(v, 0);
sigh.publish(v);
ASSERT_TRUE(listener.k);
ASSERT_EQ(sigh.size(), 2u);
ASSERT_EQ(v, 0);
sigh.publish(v);
ASSERT_FALSE(listener.k);
ASSERT_EQ(sigh.size(), 2u);
ASSERT_EQ(v, 42);
}
TEST(SigH, CustomAllocator) {
std::allocator<void (*)(int)> allocator;
entt::sigh<void(int), decltype(allocator)> sigh{allocator};
@ -542,7 +472,7 @@ TEST_F(SigH, CustomAllocator) {
sink.template connect<&sigh_listener::g>(listener);
decltype(sigh) copy{sigh, allocator};
sink.disconnect(listener);
sink.disconnect(&listener);
ASSERT_TRUE(sigh.empty());
ASSERT_FALSE(copy.empty());

View File

@ -1,10 +1,48 @@
#include <gtest/gtest.h>
#include <entt/core/hashed_string.hpp>
#include <entt/core/utility.hpp>
#include <entt/entity/registry.hpp>
#include <entt/entity/storage.hpp>
#include <entt/meta/factory.hpp>
#include <entt/meta/resolve.hpp>
enum class my_entity : entt::id_type {};
TEST(Example, EntityCopy) {
template<typename Type>
struct meta_mixin: Type {
using allocator_type = typename Type::allocator_type;
using value_type = typename Type::value_type;
explicit meta_mixin(const allocator_type &allocator);
};
template<typename Type, typename Entity>
struct entt::storage_type<Type, Entity> {
using type = meta_mixin<basic_storage<Type, Entity>>;
};
template<typename Type>
meta_mixin<Type>::meta_mixin(const allocator_type &allocator)
: Type{allocator} {
using namespace entt::literals;
entt::meta<value_type>()
// cross registry, same type
.template func<entt::overload<entt::storage_for_t<value_type, entt::entity> &(const entt::id_type)>(&entt::basic_registry<entt::entity>::storage<value_type>), entt::as_ref_t>("storage"_hs)
// cross registry, different types
.template func<entt::overload<entt::storage_for_t<value_type, my_entity> &(const entt::id_type)>(&entt::basic_registry<my_entity>::storage<value_type>), entt::as_ref_t>("storage"_hs);
}
template<typename Type>
struct EntityCopy: testing::Test {
using type = Type;
};
using EntityCopyTypes = ::testing::Types<entt::basic_registry<entt::entity>, entt::basic_registry<my_entity>>;
TYPED_TEST_SUITE(EntityCopy, EntityCopyTypes, );
TEST(EntityCopy, SameRegistry) {
using namespace entt::literals;
entt::registry registry{};
@ -12,52 +50,40 @@ TEST(Example, EntityCopy) {
const auto src = registry.create();
const auto dst = registry.create();
const auto other = registry.create();
custom.emplace(src, 1.);
registry.emplace<int>(src, 42);
registry.emplace<char>(src, 'c');
registry.emplace<double>(other, 3.);
ASSERT_EQ(registry.size(), 2u);
ASSERT_TRUE(custom.contains(src));
ASSERT_FALSE(registry.all_of<double>(src));
ASSERT_TRUE((registry.all_of<int, char>(src)));
ASSERT_FALSE((registry.any_of<int, char, double>(dst)));
ASSERT_FALSE(custom.contains(dst));
ASSERT_TRUE((registry.all_of<int, char>(src)));
ASSERT_FALSE((registry.any_of<int, char>(dst)));
for(auto [id, storage]: registry.storage()) {
// discard the custom storage because why not, this is just an example after all
if(id != "custom"_hs && storage.contains(src)) {
storage.emplace(dst, storage.get(src));
storage.push(dst, storage.value(src));
}
}
ASSERT_TRUE((registry.all_of<int, char>(dst)));
ASSERT_FALSE((registry.all_of<double>(dst)));
ASSERT_EQ(registry.size(), 2u);
ASSERT_TRUE(custom.contains(src));
ASSERT_FALSE(custom.contains(dst));
ASSERT_TRUE((registry.all_of<int, char>(src)));
ASSERT_TRUE((registry.all_of<int, char>(dst)));
ASSERT_EQ(registry.get<int>(dst), 42);
ASSERT_EQ(registry.get<char>(dst), 'c');
}
TEST(Example, DifferentRegistryTypes) {
TYPED_TEST(EntityCopy, CrossRegistry) {
using namespace entt::literals;
entt::basic_registry<entt::entity> src{};
entt::basic_registry<my_entity> dst{};
/*
TODO These are currently needed to ensure that the source and
target registries have the proper storage initialized
prior to copying, as this isn't done automatically
when emplacing storages (as is done below).
There is an open issue about this, and these two
lines should be removed when a fix is properly landed.
https://github.com/skypjack/entt/issues/827
*/
static_cast<void>(src.storage<double>());
static_cast<void>(dst.storage<int>());
// other registry type, see typed test suite
typename TestFixture::type dst{};
const auto entity = src.create();
const auto copy = dst.create();
@ -65,14 +91,31 @@ TEST(Example, DifferentRegistryTypes) {
src.emplace<int>(entity, 42);
src.emplace<char>(entity, 'c');
ASSERT_EQ(src.size(), 1u);
ASSERT_EQ(dst.size(), 1u);
ASSERT_TRUE((src.all_of<int, char>(entity)));
ASSERT_FALSE((dst.template all_of<int, char>(copy)));
for(auto [id, storage]: src.storage()) {
if(auto *other = dst.storage(id); other && storage.contains(entity)) {
other->emplace(copy, storage.get(entity));
if(storage.contains(entity)) {
auto *other = dst.storage(id);
if(!other) {
using namespace entt::literals;
entt::resolve(storage.type()).invoke("storage"_hs, {}, entt::forward_as_meta(dst), id);
other = dst.storage(id);
}
other->push(copy, storage.value(entity));
}
}
ASSERT_EQ(src.size(), 1u);
ASSERT_EQ(dst.size(), 1u);
ASSERT_TRUE((src.all_of<int, char>(entity)));
ASSERT_FALSE(dst.all_of<char>(copy));
ASSERT_TRUE(dst.all_of<int>(copy));
ASSERT_EQ(dst.get<int>(copy), 42);
ASSERT_TRUE((dst.template all_of<int, char>(copy)));
ASSERT_EQ(dst.template get<int>(copy), 42);
ASSERT_EQ(dst.template get<char>(copy), 'c');
}

View File

@ -13,7 +13,7 @@ struct entt::storage_type<Type, Entity> {
template<typename Entity>
struct entt::storage_type<char, Entity> {
// ... unless it's char, because yes.
using type = sigh_storage_mixin<basic_storage<char, Entity>>;
using type = sigh_mixin<basic_storage<char, Entity>>;
};
template<typename, typename, typename = void>

View File

@ -0,0 +1,10 @@
#ifndef ENTT_LIB_DISPATCHER_COMMON_TYPES_H
#define ENTT_LIB_DISPATCHER_COMMON_TYPES_H
struct message {
int payload;
};
struct event {};
#endif

View File

@ -4,7 +4,7 @@
#include <cr.h>
#include <entt/signal/dispatcher.hpp>
#include <entt/signal/sigh.hpp>
#include "types.h"
#include "../common/types.h"
struct listener {
void on(message msg) {

View File

@ -1,6 +1,6 @@
#include <cr.h>
#include <entt/signal/dispatcher.hpp>
#include "types.h"
#include "../common/types.h"
CR_EXPORT int cr_main(cr_plugin *ctx, cr_op operation) {
switch(operation) {

View File

@ -1,6 +1,6 @@
#include <entt/core/attribute.h>
#include <entt/signal/dispatcher.hpp>
#include "types.h"
#include "../common/types.h"
ENTT_API void trigger(entt::dispatcher &dispatcher) {
dispatcher.trigger<event>();

View File

@ -3,7 +3,7 @@
#include <entt/core/utility.hpp>
#include <entt/signal/dispatcher.hpp>
#include <entt/signal/sigh.hpp>
#include "types.h"
#include "../common/types.h"
ENTT_API void trigger(entt::dispatcher &);

View File

@ -1,12 +0,0 @@
#ifndef ENTT_LIB_DISPATCHER_TYPES_H
#define ENTT_LIB_DISPATCHER_TYPES_H
#include <entt/core/attribute.h>
struct ENTT_API message {
int payload;
};
struct ENTT_API event {};
#endif

View File

@ -1,10 +0,0 @@
#ifndef ENTT_LIB_DISPATCHER_PLUGIN_TYPES_H
#define ENTT_LIB_DISPATCHER_PLUGIN_TYPES_H
struct message {
int payload;
};
struct event {};
#endif

View File

@ -1,5 +1,5 @@
#ifndef ENTT_LIB_EMITTER_PLUGIN_TYPES_H
#define ENTT_LIB_EMITTER_PLUGIN_TYPES_H
#ifndef ENTT_LIB_EMITTER_COMMON_TYPES_H
#define ENTT_LIB_EMITTER_COMMON_TYPES_H
#include <entt/signal/emitter.hpp>

View File

@ -2,7 +2,7 @@
#include <gtest/gtest.h>
#include <cr.h>
#include "types.h"
#include "../common/types.h"
TEST(Lib, Emitter) {
test_emitter emitter;

View File

@ -1,5 +1,5 @@
#include <cr.h>
#include "types.h"
#include "../common/types.h"
CR_EXPORT int cr_main(cr_plugin *ctx, cr_op operation) {
switch(operation) {

View File

@ -1,5 +1,5 @@
#include <entt/core/attribute.h>
#include "types.h"
#include "../common/types.h"
ENTT_API void emit(test_emitter &emitter) {
emitter.publish(event{});

View File

@ -1,6 +1,6 @@
#include <gtest/gtest.h>
#include <entt/core/attribute.h>
#include "types.h"
#include "../common/types.h"
ENTT_API void emit(test_emitter &);

View File

@ -1,16 +0,0 @@
#ifndef ENTT_LIB_EMITTER_TYPES_H
#define ENTT_LIB_EMITTER_TYPES_H
#include <entt/core/attribute.h>
#include <entt/signal/emitter.hpp>
struct ENTT_API test_emitter
: entt::emitter<test_emitter> {};
struct ENTT_API message {
int payload;
};
struct ENTT_API event {};
#endif

View File

@ -0,0 +1,8 @@
#ifndef ENTT_LIB_LOCATOR_COMMON_TYPES_H
#define ENTT_LIB_LOCATOR_COMMON_TYPES_H
struct service {
int value;
};
#endif

View File

@ -3,6 +3,7 @@
#include <gtest/gtest.h>
#include <cr.h>
#include <entt/locator/locator.hpp>
#include "../common/types.h"
#include "types.h"
TEST(Lib, Locator) {
@ -10,9 +11,7 @@ TEST(Lib, Locator) {
ASSERT_EQ(entt::locator<service>::value().value, 42);
userdata ud{};
ud.handle = entt::locator<service>::handle();
ud.value = 3;
userdata ud{entt::locator<service>::handle(), 3};
cr_plugin ctx;
ctx.userdata = &ud;

View File

@ -1,5 +1,6 @@
#include <cr.h>
#include <entt/locator/locator.hpp>
#include "../common/types.h"
#include "types.h"
CR_EXPORT int cr_main(cr_plugin *ctx, cr_op operation) {

View File

@ -3,13 +3,10 @@
#include <entt/locator/locator.hpp>
struct service {
int value;
};
struct service;
struct userdata {
using node_type = typename entt::locator<service>::node_type;
node_type handle;
typename entt::locator<service>::node_type handle;
int value;
};

View File

@ -1,6 +1,6 @@
#include <entt/core/attribute.h>
#include <entt/locator/locator.hpp>
#include "types.h"
#include "../common/types.h"
ENTT_API void set_up(const entt::locator<service>::node_type &handle) {
entt::locator<service>::reset(handle);

View File

@ -1,7 +1,7 @@
#include <gtest/gtest.h>
#include <entt/core/attribute.h>
#include <entt/locator/locator.hpp>
#include "types.h"
#include "../common/types.h"
ENTT_API void set_up(const entt::locator<service>::node_type &);
ENTT_API void use_service(int);

View File

@ -1,8 +0,0 @@
#ifndef ENTT_LIB_LOCATOR_TYPES_H
#define ENTT_LIB_LOCATOR_TYPES_H
struct service {
int value;
};
#endif

View File

@ -1,5 +1,5 @@
#ifndef ENTT_LIB_META_TYPES_H
#define ENTT_LIB_META_TYPES_H
#ifndef ENTT_LIB_META_COMMON_TYPES_H
#define ENTT_LIB_META_COMMON_TYPES_H
struct position {
int x;

View File

@ -14,8 +14,7 @@ TEST(Lib, Meta) {
ASSERT_FALSE(entt::resolve("position"_hs));
userdata ud{};
ud.ctx = entt::locator<entt::meta_ctx>::handle();
userdata ud{entt::locator<entt::meta_ctx>::handle(), entt::meta_any{}};
cr_plugin ctx;
ctx.userdata = &ud;

View File

@ -4,6 +4,7 @@
#include <entt/meta/context.hpp>
#include <entt/meta/factory.hpp>
#include <entt/meta/meta.hpp>
#include "../common/types.h"
#include "types.h"
position create_position(int x, int y) {

View File

@ -4,16 +4,6 @@
#include <entt/locator/locator.hpp>
#include <entt/meta/meta.hpp>
struct position {
int x;
int y;
};
struct velocity {
double dx;
double dy;
};
struct userdata {
entt::locator<entt::meta_ctx>::node_type ctx;
entt::meta_any any;

View File

@ -3,6 +3,7 @@
#include <entt/meta/context.hpp>
#include <entt/meta/factory.hpp>
#include <entt/meta/meta.hpp>
#include "../common/types.h"
#include "types.h"
position create_position(int x, int y) {

View File

@ -1,5 +1,5 @@
#ifndef ENTT_LIB_META_PLUGIN_TYPES_STD_H
#define ENTT_LIB_META_PLUGIN_TYPES_STD_H
#ifndef ENTT_LIB_META_PLUGIN_STD_TYPES_H
#define ENTT_LIB_META_PLUGIN_STD_TYPES_H
#include <type_traits>
#include <entt/core/hashed_string.hpp>
@ -17,15 +17,8 @@ struct custom_type_hash;
} \
}
struct position {
int x;
int y;
};
struct velocity {
double dx;
double dy;
};
struct position;
struct velocity;
struct userdata {
entt::locator<entt::meta_ctx>::node_type ctx;

View File

@ -2,7 +2,7 @@
#include <entt/core/hashed_string.hpp>
#include <entt/meta/factory.hpp>
#include <entt/meta/meta.hpp>
#include "types.h"
#include "../common/types.h"
position create_position(int x, int y) {
return position{x, y};

View File

@ -4,7 +4,7 @@
#include <entt/meta/factory.hpp>
#include <entt/meta/meta.hpp>
#include <entt/meta/resolve.hpp>
#include "types.h"
#include "../common/types.h"
ENTT_API void share(entt::locator<entt::meta_ctx>::node_type);
ENTT_API void set_up();

View File

@ -1,5 +1,5 @@
#ifndef ENTT_LIB_REGISTRY_PLUGIN_TYPES_H
#define ENTT_LIB_REGISTRY_PLUGIN_TYPES_H
#ifndef ENTT_LIB_REGISTRY_COMMON_TYPES_H
#define ENTT_LIB_REGISTRY_COMMON_TYPES_H
struct position {
int x;

View File

@ -3,7 +3,7 @@
#include <gtest/gtest.h>
#include <cr.h>
#include <entt/entity/registry.hpp>
#include "types.h"
#include "../common/types.h"
TEST(Lib, Registry) {
entt::registry registry;

View File

@ -1,6 +1,6 @@
#include <cr.h>
#include <entt/entity/registry.hpp>
#include "types.h"
#include "../common/types.h"
CR_EXPORT int cr_main(cr_plugin *ctx, cr_op operation) {
switch(operation) {

View File

@ -1,6 +1,8 @@
#include <entt/core/attribute.h>
#include <entt/entity/registry.hpp>
#include "types.h"
#include "../common/types.h"
template class entt::basic_registry<entt::entity>;
ENTT_API void update_position(entt::registry &registry) {
registry.view<position, velocity>().each([](auto &pos, auto &vel) {

View File

@ -2,7 +2,7 @@
#include <entt/core/attribute.h>
#include <entt/entity/entity.hpp>
#include <entt/entity/registry.hpp>
#include "types.h"
#include "../common/types.h"
ENTT_API void update_position(entt::registry &);
ENTT_API void emplace_velocity(entt::registry &);

View File

@ -1,16 +0,0 @@
#ifndef ENTT_LIB_REGISTRY_TYPES_H
#define ENTT_LIB_REGISTRY_TYPES_H
#include <entt/core/attribute.h>
struct ENTT_API position {
int x;
int y;
};
struct ENTT_API velocity {
double dx;
double dy;
};
#endif

View File

@ -64,11 +64,21 @@ TEST(Snapshot, Full) {
{
// output finishes flushing its contents when it goes out of scope
cereal::JSONOutputArchive output{storage};
entt::snapshot{source}.entities(output).component<position, timer, relationship, entt::tag<"empty"_hs>>(output);
entt::snapshot{source}
.entities(output)
.component<position>(output)
.component<timer>(output)
.component<relationship>(output)
.component<entt::tag<"empty"_hs>>(output);
}
cereal::JSONInputArchive input{storage};
entt::snapshot_loader{destination}.entities(input).component<position, timer, relationship, entt::tag<"empty"_hs>>(input);
entt::snapshot_loader{destination}
.entities(input)
.component<position>(input)
.component<timer>(input)
.component<relationship>(input)
.component<entt::tag<"empty"_hs>>(input);
ASSERT_TRUE(destination.valid(e0));
ASSERT_TRUE(destination.all_of<position>(e0));
@ -129,14 +139,22 @@ TEST(Snapshot, Continuous) {
{
// output finishes flushing its contents when it goes out of scope
cereal::JSONOutputArchive output{storage};
entt::snapshot{source}.entities(output).component<position, relationship, timer, entt::tag<"empty"_hs>>(output);
entt::snapshot{source}
.component<entt::entity>(output)
.component<position>(output)
.component<relationship>(output)
.component<timer>(output)
.component<entt::tag<"empty"_hs>>(output);
}
cereal::JSONInputArchive input{storage};
entt::continuous_loader loader{destination};
loader.entities(input)
.component<position, relationship>(input, &relationship::parent)
.component<timer, entt::tag<"empty"_hs>>(input);
loader
.entities(input)
.component<position>(input)
.component<relationship>(input, &relationship::parent)
.component<timer>(input)
.component<entt::tag<"empty"_hs>>(input);
ASSERT_FALSE(destination.valid(e0));
ASSERT_TRUE(loader.contains(e0));