From 44fa466618513c27cfa304bd5d1942e1f1963bc8 Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Mon, 22 Mar 2021 12:00:21 +0100 Subject: [PATCH] poly: support for alignment requirements --- src/entt/poly/fwd.hpp | 2 +- src/entt/poly/poly.hpp | 24 +++++++++++++----------- test/entt/poly/poly_deduced.cpp | 26 ++++++++++++++++++++++++++ test/entt/poly/poly_defined.cpp | 26 ++++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 12 deletions(-) diff --git a/src/entt/poly/fwd.hpp b/src/entt/poly/fwd.hpp index e6c524515..b6cd5e495 100644 --- a/src/entt/poly/fwd.hpp +++ b/src/entt/poly/fwd.hpp @@ -5,7 +5,7 @@ namespace entt { -template +template class basic_poly; diff --git a/src/entt/poly/poly.hpp b/src/entt/poly/poly.hpp index d450d86cd..7dd570de2 100644 --- a/src/entt/poly/poly.hpp +++ b/src/entt/poly/poly.hpp @@ -46,25 +46,26 @@ struct poly_inspector { * @brief Static virtual table factory. * @tparam Concept Concept descriptor. * @tparam Len Size of the storage reserved for the small buffer optimization. + * @tparam Align Optional alignment requirement. */ -template +template class poly_vtable { using inspector = typename Concept::template type; template - static auto vtable_entry(Ret(*)(inspector &, Args...)) -> Ret(*)(basic_any &, Args...); + static auto vtable_entry(Ret(*)(inspector &, Args...)) -> Ret(*)(basic_any &, Args...); template - static auto vtable_entry(Ret(*)(const inspector &, Args...)) -> Ret(*)(const basic_any &, Args...); + static auto vtable_entry(Ret(*)(const inspector &, Args...)) -> Ret(*)(const basic_any &, Args...); template - static auto vtable_entry(Ret(*)(Args...)) -> Ret(*)(const basic_any &, Args...); + static auto vtable_entry(Ret(*)(Args...)) -> Ret(*)(const basic_any &, Args...); template - static auto vtable_entry(Ret(inspector:: *)(Args...)) -> Ret(*)(basic_any &, Args...); + static auto vtable_entry(Ret(inspector:: *)(Args...)) -> Ret(*)(basic_any &, Args...); template - static auto vtable_entry(Ret(inspector:: *)(Args...) const) -> Ret(*)(const basic_any &, Args...); + static auto vtable_entry(Ret(inspector:: *)(Args...) const) -> Ret(*)(const basic_any &, Args...); template static auto make_vtable(value_list) @@ -174,13 +175,14 @@ decltype(auto) poly_call(Poly &&self, Args &&... args) { * * @tparam Concept Concept descriptor. * @tparam Len Size of the storage reserved for the small buffer optimization. + * @tparam Align Optional alignment requirement. */ -template -class basic_poly: private Concept::template type>> { +template +class basic_poly: private Concept::template type>> { /*! @brief A poly base is allowed to snoop into a poly object. */ friend struct poly_base; - using vtable_type = typename poly_vtable::type; + using vtable_type = typename poly_vtable::type; public: /*! @brief Concept type. */ @@ -201,7 +203,7 @@ public: template explicit basic_poly(std::in_place_type_t, Args &&... args) : storage{std::in_place_type, std::forward(args)...}, - vtable{poly_vtable::template instance>>()} + vtable{poly_vtable::template instance>>()} {} /** @@ -338,7 +340,7 @@ public: } private: - basic_any storage; + basic_any storage; const vtable_type *vtable; }; diff --git a/test/entt/poly/poly_deduced.cpp b/test/entt/poly/poly_deduced.cpp index efc51e601..48840296c 100644 --- a/test/entt/poly/poly_deduced.cpp +++ b/test/entt/poly/poly_deduced.cpp @@ -41,6 +41,8 @@ struct impl { int value{}; }; +struct alignas(64u) over_aligned: impl {}; + TEST(PolyDeduced, Functionalities) { impl instance{}; @@ -227,3 +229,27 @@ TEST(PolyDeduced, SBOVsZeroedSBOSize) { ASSERT_EQ(same->get(), 1); } + +TEST(PolyDeduced, Alignment) { + static constexpr auto alignment = alignof(over_aligned); + + auto test = [](auto *target, auto cb) { + const auto *data = target[0].data(); + + ASSERT_TRUE((reinterpret_cast(target[0u].data()) % alignment) == 0u); + ASSERT_TRUE((reinterpret_cast(target[1u].data()) % alignment) == 0u); + + std::swap(target[0], target[1]); + + ASSERT_TRUE((reinterpret_cast(target[0u].data()) % alignment) == 0u); + ASSERT_TRUE((reinterpret_cast(target[1u].data()) % alignment) == 0u); + + cb(data, target[1].data()); + }; + + entt::basic_poly nosbo[2] = { over_aligned{}, over_aligned{} }; + test(nosbo, [](auto *pre, auto *post) { ASSERT_EQ(pre, post); }); + + entt::basic_poly sbo[2] = { over_aligned{}, over_aligned{} }; + test(sbo, [](auto *pre, auto *post) { ASSERT_NE(pre, post); }); +} diff --git a/test/entt/poly/poly_defined.cpp b/test/entt/poly/poly_defined.cpp index b4a592ea5..c287df6aa 100644 --- a/test/entt/poly/poly_defined.cpp +++ b/test/entt/poly/poly_defined.cpp @@ -47,6 +47,8 @@ struct impl { int value{}; }; +struct alignas(64u) over_aligned: impl {}; + TEST(PolyDefined, Functionalities) { impl instance{}; @@ -233,3 +235,27 @@ TEST(PolyDefined, SBOVsZeroedSBOSize) { ASSERT_EQ(same->get(), 1); } + +TEST(PolyDefined, Alignment) { + static constexpr auto alignment = alignof(over_aligned); + + auto test = [](auto *target, auto cb) { + const auto *data = target[0].data(); + + ASSERT_TRUE((reinterpret_cast(target[0u].data()) % alignment) == 0u); + ASSERT_TRUE((reinterpret_cast(target[1u].data()) % alignment) == 0u); + + std::swap(target[0], target[1]); + + ASSERT_TRUE((reinterpret_cast(target[0u].data()) % alignment) == 0u); + ASSERT_TRUE((reinterpret_cast(target[1u].data()) % alignment) == 0u); + + cb(data, target[1].data()); + }; + + entt::basic_poly nosbo[2] = { over_aligned{}, over_aligned{} }; + test(nosbo, [](auto *pre, auto *post) { ASSERT_EQ(pre, post); }); + + entt::basic_poly sbo[2] = { over_aligned{}, over_aligned{} }; + test(sbo, [](auto *pre, auto *post) { ASSERT_NE(pre, post); }); +}