From 3c77d2c3f5eb9b568541eea445a7d742917e0733 Mon Sep 17 00:00:00 2001 From: Adrian Perez Date: Wed, 18 Oct 2023 16:27:51 -0700 Subject: [PATCH] StructureOfArrays can push_back move-only types --- libs/utils/include/utils/StructureOfArrays.h | 56 ++++++++++++++------ libs/utils/test/test_StructureOfArrays.cpp | 10 ++++ 2 files changed, 49 insertions(+), 17 deletions(-) diff --git a/libs/utils/include/utils/StructureOfArrays.h b/libs/utils/include/utils/StructureOfArrays.h index b6ea3bfbe4..497a0fefbd 100644 --- a/libs/utils/include/utils/StructureOfArrays.h +++ b/libs/utils/include/utils/StructureOfArrays.h @@ -352,33 +352,55 @@ public: return push_back_unsafe(std::forward(args)...); } - // in C++20 we could use a lambda with explicit template parameter instead - struct PushBackUnsafeClosure { - size_t last; - std::tuple args; - inline explicit PushBackUnsafeClosure(size_t last, Structure&& args) - : last(last), args(std::forward(args)) {} - template - inline void operator()(TypeAt* p) { - new(p + last) TypeAt{ std::get(args) }; - } - }; + template + struct ElementIndices {}; + + template + struct BuildElementIndices : BuildElementIndices {}; + + template + struct BuildElementIndices<0, Indices...> : ElementIndices {}; + + template + void push_back_unsafe(Structure&& args, ElementIndices){ + size_t last = mSize++; + // Fold expression on the comma operator + ([&]{ + new(std::get(mArrays) + last) Elements{std::get(args)}; + }() , ...); + } + + template + void push_back_unsafe(Elements const& ... args, ElementIndices){ + size_t last = mSize++; + // Fold expression on the comma operator + ([&]{ + new(std::get(mArrays) + last) Elements{args}; + }() , ...); + } + + template + void push_back_unsafe(Elements && ... args, ElementIndices){ + size_t last = mSize++; + // Fold expression on the comma operator + ([&]{ + new(std::get(mArrays) + last) Elements{std::forward(args)}; + }() , ...); + } StructureOfArraysBase& push_back_unsafe(Structure&& args) noexcept { - for_each_index(mArrays, - PushBackUnsafeClosure{ mSize++, std::forward(args) }); + push_back_unsafe(std::forward(args), BuildElementIndices{}); return *this; } StructureOfArraysBase& push_back_unsafe(Elements const& ... args) noexcept { - for_each_index(mArrays, - PushBackUnsafeClosure{ mSize++, { args... } }); + push_back_unsafe(args..., BuildElementIndices{}); + return *this; } StructureOfArraysBase& push_back_unsafe(Elements&& ... args) noexcept { - for_each_index(mArrays, - PushBackUnsafeClosure{ mSize++, { std::forward(args)... }}); + push_back_unsafe(std::forward(args)..., BuildElementIndices{}); return *this; } diff --git a/libs/utils/test/test_StructureOfArrays.cpp b/libs/utils/test/test_StructureOfArrays.cpp index 0b435e7656..652d9d37fe 100644 --- a/libs/utils/test/test_StructureOfArrays.cpp +++ b/libs/utils/test/test_StructureOfArrays.cpp @@ -173,3 +173,13 @@ TEST(StructureOfArraysTest, Simple) { soa.push_back(0.0f, 1.0, std::move(destroyedFloat4)); } +TEST(StructureOfArraysTest, MoveOnly) { + StructureOfArrays> soa; + soa.setCapacity(2); + soa.push_back(1.0f, std::make_unique(1)); + soa.push_back(2.0f, std::make_unique(2)); + EXPECT_EQ(soa.size(), 2); + EXPECT_EQ(*soa.elementAt<1>(0).get(), 1); + EXPECT_EQ(*soa.elementAt<1>(1).get(), 2); +} +