storage: support chained constructors i.e. parent-to-child propagation

This commit is contained in:
Michele Caini
2022-01-13 12:00:15 +01:00
parent 588c056205
commit 8a19e8dafe
2 changed files with 41 additions and 18 deletions

View File

@@ -638,25 +638,23 @@ public:
*/
template<typename... Args>
value_type &emplace(const entity_type entt, Args &&...args) {
const auto pos = base_type::slot();
auto elem = assure_at_least(pos);
if constexpr(std::is_aggregate_v<value_type>) {
alloc_traits::construct(packed.second(), to_address(elem), Type{std::forward<Args>(args)...});
} else {
alloc_traits::construct(packed.second(), to_address(elem), std::forward<Args>(args)...);
}
// support chained constructors i.e. parent-to-child propagation
base_type::try_emplace(entt);
const auto pos = base_type::index(entt);
ENTT_TRY {
base_type::try_emplace(entt);
ENTT_ASSERT(pos == base_type::index(entt), "Misplaced component");
if constexpr(std::is_aggregate_v<value_type>) {
alloc_traits::construct(packed.second(), to_address(assure_at_least(pos)), Type{std::forward<Args>(args)...});
} else {
alloc_traits::construct(packed.second(), to_address(assure_at_least(pos)), std::forward<Args>(args)...);
}
}
ENTT_CATCH {
std::destroy_at(std::addressof(*elem));
base_type::try_erase(entt);
ENTT_THROW;
}
return *elem;
return element_at(pos);
}
/**

View File

@@ -55,6 +55,20 @@ private:
entt::entity target{entt::null};
};
struct crete_from_constructor {
crete_from_constructor(entt::storage<crete_from_constructor> &ref, entt::entity other)
: child{other} {
if(child != entt::null) {
ref.emplace(child, ref, entt::null);
}
}
crete_from_constructor(crete_from_constructor &&other) ENTT_NOEXCEPT = default;
crete_from_constructor &operator=(crete_from_constructor &&other) ENTT_NOEXCEPT = default;
entt::entity child;
};
template<>
struct entt::component_traits<stable_type>: basic_component_traits {
static constexpr auto in_place_delete = true;
@@ -1537,6 +1551,17 @@ TEST(Storage, UpdateFromDestructor) {
test(entt::entity{0u});
}
TEST(Storage, CreateFromConstructor) {
entt::storage<crete_from_constructor> pool;
const entt::entity entity{0u};
const entt::entity other{1u};
pool.emplace(entity, pool, other);
ASSERT_EQ(pool.get(entity).child, other);
ASSERT_EQ(pool.get(other).child, static_cast<entt::entity>(entt::null));
}
TEST(Storage, CustomAllocator) {
auto test = [](auto pool, auto alloc) {
ASSERT_EQ(pool.get_allocator(), alloc);
@@ -1608,12 +1633,6 @@ TEST(Storage, ThrowingAllocator) {
ASSERT_EQ(pool.capacity(), 0u);
test::throwing_allocator<int>::trigger_on_allocate = true;
ASSERT_THROW(pool.emplace(entt::entity{0}, 0), test::throwing_allocator<int>::exception_type);
ASSERT_FALSE(pool.contains(entt::entity{0}));
ASSERT_TRUE(pool.empty());
test::throwing_allocator<entt::entity>::trigger_on_allocate = true;
ASSERT_THROW(pool.emplace(entt::entity{0}, 0), test::throwing_allocator<entt::entity>::exception_type);
@@ -1626,6 +1645,12 @@ TEST(Storage, ThrowingAllocator) {
ASSERT_FALSE(base.contains(entt::entity{0}));
ASSERT_TRUE(base.empty());
test::throwing_allocator<int>::trigger_on_allocate = true;
ASSERT_THROW(pool.emplace(entt::entity{0}, 0), test::throwing_allocator<int>::exception_type);
ASSERT_FALSE(pool.contains(entt::entity{0}));
ASSERT_TRUE(pool.empty());
pool.emplace(entt::entity{0}, 0);
const entt::entity entities[2u]{entt::entity{1}, entt::entity{ENTT_SPARSE_PAGE}};
test::throwing_allocator<entt::entity>::trigger_after_allocate = true;