StructureOfArrays can push_back move-only types

This commit is contained in:
Adrian Perez
2023-10-18 16:27:51 -07:00
committed by Mathias Agopian
parent 960c6170fe
commit 3c77d2c3f5
2 changed files with 49 additions and 17 deletions

View File

@@ -352,33 +352,55 @@ public:
return push_back_unsafe(std::forward<Elements>(args)...);
}
// in C++20 we could use a lambda with explicit template parameter instead
struct PushBackUnsafeClosure {
size_t last;
std::tuple<Elements...> args;
inline explicit PushBackUnsafeClosure(size_t last, Structure&& args)
: last(last), args(std::forward<Structure>(args)) {}
template<size_t I>
inline void operator()(TypeAt<I>* p) {
new(p + last) TypeAt<I>{ std::get<I>(args) };
}
};
template <std::size_t... Indices>
struct ElementIndices {};
template <std::size_t N, std::size_t... Indices>
struct BuildElementIndices : BuildElementIndices<N - 1, N - 1, Indices...> {};
template <std::size_t... Indices>
struct BuildElementIndices<0, Indices...> : ElementIndices<Indices...> {};
template<std::size_t... Indices>
void push_back_unsafe(Structure&& args, ElementIndices<Indices...>){
size_t last = mSize++;
// Fold expression on the comma operator
([&]{
new(std::get<Indices>(mArrays) + last) Elements{std::get<Indices>(args)};
}() , ...);
}
template<std::size_t... Indices>
void push_back_unsafe(Elements const& ... args, ElementIndices<Indices...>){
size_t last = mSize++;
// Fold expression on the comma operator
([&]{
new(std::get<Indices>(mArrays) + last) Elements{args};
}() , ...);
}
template<std::size_t... Indices>
void push_back_unsafe(Elements && ... args, ElementIndices<Indices...>){
size_t last = mSize++;
// Fold expression on the comma operator
([&]{
new(std::get<Indices>(mArrays) + last) Elements{std::forward<Elements>(args)};
}() , ...);
}
StructureOfArraysBase& push_back_unsafe(Structure&& args) noexcept {
for_each_index(mArrays,
PushBackUnsafeClosure{ mSize++, std::forward<Structure>(args) });
push_back_unsafe(std::forward<Structure>(args), BuildElementIndices<sizeof...(Elements)>{});
return *this;
}
StructureOfArraysBase& push_back_unsafe(Elements const& ... args) noexcept {
for_each_index(mArrays,
PushBackUnsafeClosure{ mSize++, { args... } });
push_back_unsafe(args..., BuildElementIndices<sizeof...(Elements)>{});
return *this;
}
StructureOfArraysBase& push_back_unsafe(Elements&& ... args) noexcept {
for_each_index(mArrays,
PushBackUnsafeClosure{ mSize++, { std::forward<Elements>(args)... }});
push_back_unsafe(std::forward<Elements>(args)..., BuildElementIndices<sizeof...(Elements)>{});
return *this;
}

View File

@@ -173,3 +173,13 @@ TEST(StructureOfArraysTest, Simple) {
soa.push_back(0.0f, 1.0, std::move(destroyedFloat4));
}
TEST(StructureOfArraysTest, MoveOnly) {
StructureOfArrays<float, std::unique_ptr<int32_t>> soa;
soa.setCapacity(2);
soa.push_back(1.0f, std::make_unique<int32_t>(1));
soa.push_back(2.0f, std::make_unique<int32_t>(2));
EXPECT_EQ(soa.size(), 2);
EXPECT_EQ(*soa.elementAt<1>(0).get(), 1);
EXPECT_EQ(*soa.elementAt<1>(1).get(), 2);
}