diff --git a/include/sparrow/allocator.hpp b/include/sparrow/allocator.hpp index a6387811..05ba443e 100644 --- a/include/sparrow/allocator.hpp +++ b/include/sparrow/allocator.hpp @@ -16,7 +16,9 @@ #include #include +#include #include +#include namespace sparrow { @@ -47,50 +49,96 @@ namespace sparrow template > class any_allocator { + template + static constexpr bool is_value_stored = + std::is_same_v> || std::is_same_v>; + public: using value_type = T; any_allocator() - : p_allocator(std::make_unique>(DA())) + : m_storage(make_storage(DA())) { } any_allocator(const any_allocator& rhs) - : p_allocator(rhs.p_allocator->clone()) - { - } - - any_allocator& operator=(const any_allocator& rhs) + : m_storage(copy_storage(rhs.m_storage)) { - p_allocator = rhs.p_allocator->clone(); - return *this; } any_allocator(any_allocator&&) = default; - any_allocator& operator=(any_allocator&&) = default; + + any_allocator& operator=(const any_allocator& rhs) = delete; + any_allocator& operator=(any_allocator&& rhs) = delete; template any_allocator(A&& alloc) requires (not std::same_as, any_allocator> and sparrow::allocator) - : p_allocator(std::make_unique>>(std::forward(alloc))) + : m_storage(make_storage(std::forward(alloc))) { } [[nodiscard]] T* allocate(std::size_t n) { - return p_allocator->allocate(n); + return std::visit([n](auto&& arg) + { + using A = std::decay_t; + if constexpr (is_value_stored) + return arg.allocate(n); + else + return arg->allocate(n); + }, m_storage); } void deallocate(T* p, std::size_t n) { - p_allocator->deallocate(p, n); + return std::visit([p, n](auto&& arg) + { + using A = std::decay_t; + if constexpr (is_value_stored) + arg.deallocate(p, n); + else + arg->deallocate(p, n); + }, m_storage); + } + + any_allocator select_on_container_copy_construction() const + { + return any_allocator(*this); } bool equal(const any_allocator& rhs) const { - return p_allocator->equal(*rhs.p_allocator); + // YOLO!! + return std::visit([&rhs](auto&& arg) + { + using A = std::decay_t; + if constexpr (is_value_stored) + { + return std::visit([&arg](auto&& arg2) + { + using A2 = std::decay_t; + if constexpr (is_value_stored && std::same_as) + return arg == arg2; + else + return false; + }, rhs.m_storage); + } + else + { + return std::visit([&arg](auto&& arg2) + { + using A2 = std::decay_t; + if constexpr (is_value_stored) + return false; + else + return arg->equal(*arg2); + }, rhs.m_storage); + } + + }, m_storage); } private: @@ -136,7 +184,39 @@ namespace sparrow } }; - std::unique_ptr p_allocator; + using storage_type = std::variant + < + std::allocator, + std::pmr::polymorphic_allocator, + std::unique_ptr + >; + + template + std::unique_ptr make_storage(A&& alloc) const + { + return std::make_unique>>(std::forward(alloc)); + } + + template + requires is_value_stored + A&& make_storage(A&& alloc) const + { + return std::forward(alloc); + } + + storage_type copy_storage(const storage_type& rhs) const + { + return std::visit([](auto&& arg) -> storage_type + { + using A = std::decay_t; + if constexpr (is_value_stored) + return { A(arg) }; + else + return { arg->clone() }; + }, rhs); + } + + storage_type m_storage; }; template diff --git a/test/test_allocator.cpp b/test/test_allocator.cpp index 8593ea85..9d5ac6bc 100644 --- a/test/test_allocator.cpp +++ b/test/test_allocator.cpp @@ -36,7 +36,7 @@ TEST_SUITE("any_allocator") } } - SUBCASE("copy semantic") + SUBCASE("copy constructor") { using value_type = typename A::value_type; @@ -45,12 +45,11 @@ TEST_SUITE("any_allocator") sparrow::any_allocator b(a); CHECK(a == b); - sparrow::any_allocator c(alloc); - b = c; - CHECK(b == c); + auto d = b.select_on_container_copy_construction(); + CHECK(d == b); } - SUBCASE("move semantic") + SUBCASE("move constructor") { using value_type = typename A::value_type; @@ -59,10 +58,6 @@ TEST_SUITE("any_allocator") sparrow::any_allocator aref(a); sparrow::any_allocator b(std::move(a)); CHECK_EQ(b, aref); - - sparrow::any_allocator c(aref); - b = std::move(c); - CHECK_EQ(b, aref); } }