Skip to content

Commit

Permalink
add make_unique_small_for_overwrite functions (closes #5)
Browse files Browse the repository at this point in the history
  • Loading branch information
KRM7 committed Feb 18, 2024
1 parent 16e9fc2 commit fcc8c20
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 14 deletions.
75 changes: 67 additions & 8 deletions src/small_unique_ptr.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -528,8 +528,7 @@ namespace detail
struct make_unique_small_impl
{
template<typename T, typename... Args>
requires(!std::is_array_v<T>)
static constexpr small_unique_ptr<T> invoke(Args&&... args)
static constexpr small_unique_ptr<T> invoke_scalar(Args&&... args)
noexcept(std::is_nothrow_constructible_v<T, Args...> && !detail::is_always_heap_allocated_v<T>)
{
small_unique_ptr<T> ptr;
Expand All @@ -552,8 +551,7 @@ namespace detail
}

template<typename T>
requires(std::is_unbounded_array_v<T>)
static constexpr small_unique_ptr<T> invoke(std::size_t count)
static constexpr small_unique_ptr<T> invoke_array(std::size_t count)
{
small_unique_ptr<T> ptr;

Expand All @@ -563,8 +561,49 @@ namespace detail
}
else if constexpr (!detail::is_always_heap_allocated_v<T>)
{
std::uninitialized_value_construct(ptr.buffer(), ptr.buffer() + detail::buffer_elements_v<T>);
ptr.data_ = ptr.buffer();
std::uninitialized_value_construct_n(ptr.buffer(), detail::buffer_elements_v<T>);
ptr.data_ = std::launder(ptr.buffer());
}

return ptr;
}

template<typename T>
static constexpr small_unique_ptr<T> invoke_for_overwrite_scalar()
noexcept(std::is_nothrow_default_constructible_v<T> && !detail::is_always_heap_allocated_v<T>)
{
small_unique_ptr<T> ptr;

if (detail::is_always_heap_allocated_v<T> || std::is_constant_evaluated())
{
ptr.data_ = new T;
}
else if constexpr (!detail::is_always_heap_allocated_v<T> && std::is_polymorphic_v<T> && !detail::has_virtual_move<T>)
{
ptr.data_ = ::new(static_cast<void*>(ptr.buffer())) std::remove_cv_t<T>;
ptr.move_ = detail::move_buffer<std::remove_cv_t<T>>;
}
else if constexpr (!detail::is_always_heap_allocated_v<T>)
{
ptr.data_ = ::new(static_cast<void*>(ptr.buffer())) std::remove_cv_t<T>;
}

return ptr;
}

template<typename T>
static constexpr small_unique_ptr<T> invoke_for_overwrite_array(std::size_t count)
{
small_unique_ptr<T> ptr;

if (detail::is_always_heap_allocated_v<T> || (count > detail::buffer_elements_v<T>) || std::is_constant_evaluated())
{
ptr.data_ = new std::remove_extent_t<T>[count];
}
else if constexpr (!detail::is_always_heap_allocated_v<T>)
{
std::uninitialized_default_construct_n(ptr.buffer(), detail::buffer_elements_v<T>);
ptr.data_ = std::launder(ptr.buffer());
}

return ptr;
Expand All @@ -577,13 +616,33 @@ template<typename T, typename... Args>
[[nodiscard]] constexpr small_unique_ptr<T> make_unique_small(Args&&... args)
noexcept(std::is_nothrow_constructible_v<T, Args...> && !detail::is_always_heap_allocated_v<T>) requires(!std::is_array_v<T>)
{
return detail::make_unique_small_impl::invoke<T>(std::forward<Args>(args)...);
return detail::make_unique_small_impl::invoke_scalar<T>(std::forward<Args>(args)...);
}

template<typename T>
[[nodiscard]] constexpr small_unique_ptr<T> make_unique_small(std::size_t count) requires(std::is_unbounded_array_v<T>)
{
return detail::make_unique_small_impl::invoke<T>(count);
return detail::make_unique_small_impl::invoke_array<T>(count);
}

template<typename T, typename... Args>
[[nodiscard]] constexpr small_unique_ptr<T> make_unique_small(Args&&...) requires(std::is_bounded_array_v<T>) = delete;


template<typename T>
[[nodiscard]] constexpr small_unique_ptr<T> make_unique_small_for_overwrite()
noexcept(std::is_nothrow_default_constructible_v<T> && !detail::is_always_heap_allocated_v<T>) requires(!std::is_array_v<T>)
{
return detail::make_unique_small_impl::invoke_for_overwrite_scalar<T>();
}

template<typename T>
[[nodiscard]] constexpr small_unique_ptr<T> make_unique_small_for_overwrite(std::size_t count) requires(std::is_unbounded_array_v<T>)
{
return detail::make_unique_small_impl::invoke_for_overwrite_array<T>(count);
}

template<typename T, typename... Args>
[[nodiscard]] constexpr small_unique_ptr<T> make_unique_small_for_overwrite(Args&&...) requires(std::is_bounded_array_v<T>) = delete;

#endif // !SMALL_UNIQUE_PTR_HPP
44 changes: 38 additions & 6 deletions test/small_unique_ptr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,10 @@ TEMPLATE_TEST_CASE("construction_scalar", "[small_unique_ptr]", SmallPOD, LargeP
STATIC_REQUIRE( std::invoke([]{ (void) small_unique_ptr<const TestType>(); return true; }) );
STATIC_REQUIRE( std::invoke([]{ (void) small_unique_ptr<TestType>(nullptr); return true; }) );
STATIC_REQUIRE( std::invoke([]{ (void) small_unique_ptr<const TestType>(nullptr); return true; }) );
}

TEMPLATE_TEST_CASE("make_unique_scalar", "[small_unique_ptr]", SmallPOD, LargePOD, Base, SmallDerived, LargeDerived, BaseIntrusive, SmallIntrusive, LargeIntrusive)
{
STATIC_REQUIRE( std::invoke([]{ (void) make_unique_small<TestType>(); return true; }) );
STATIC_REQUIRE( std::invoke([]{ (void) make_unique_small<const TestType>(); return true; }) );

Expand All @@ -158,15 +161,27 @@ TEMPLATE_TEST_CASE("construction_scalar", "[small_unique_ptr]", SmallPOD, LargeP
SUCCEED();
}

TEMPLATE_TEST_CASE("make_unique_for_overwrite_scalar", "[small_unique_ptr]", SmallPOD, LargePOD, Base, SmallDerived, LargeDerived, BaseIntrusive, SmallIntrusive, LargeIntrusive)
{
STATIC_REQUIRE( std::invoke([]{ (void) make_unique_small_for_overwrite<TestType>(); return true; }) );

(void) make_unique_small_for_overwrite<TestType>();

SUCCEED();
}

TEMPLATE_TEST_CASE("construction_array", "[small_unique_ptr]", SmallPOD, LargePOD)
{
STATIC_REQUIRE( std::invoke([]{ (void) small_unique_ptr<TestType[]>(); return true; }) );
STATIC_REQUIRE( std::invoke([]{ (void) small_unique_ptr<const TestType[]>(); return true; }) );
STATIC_REQUIRE( std::invoke([]{ (void) small_unique_ptr<TestType[]>(nullptr); return true; }) );
STATIC_REQUIRE( std::invoke([]{ (void) small_unique_ptr<TestType[]>(nullptr); return true; }) );
STATIC_REQUIRE( std::invoke([]{ (void) small_unique_ptr<TestType[]>(); return true; }) );
STATIC_REQUIRE( std::invoke([]{ (void) small_unique_ptr<const TestType[]>(); return true; }) );
STATIC_REQUIRE( std::invoke([]{ (void) small_unique_ptr<TestType[]>(nullptr); return true; }) );
STATIC_REQUIRE( std::invoke([]{ (void) small_unique_ptr<const TestType[]>(nullptr); return true; }) );
}

STATIC_REQUIRE( std::invoke([]{ (void) make_unique_small<TestType[]>(2); return true; }));
STATIC_REQUIRE( std::invoke([]{ (void) make_unique_small<const TestType[]>(2); return true; }));
TEMPLATE_TEST_CASE("make_unique_array", "[small_unique_ptr]", SmallPOD, LargePOD)
{
STATIC_REQUIRE( std::invoke([]{ (void) make_unique_small<TestType[]>(2); return true; }) );
STATIC_REQUIRE( std::invoke([]{ (void) make_unique_small<const TestType[]>(2); return true; }) );

(void) make_unique_small<TestType[]>(2);
(void) make_unique_small<const TestType[]>(2);
Expand All @@ -176,10 +191,27 @@ TEMPLATE_TEST_CASE("construction_array", "[small_unique_ptr]", SmallPOD, LargePO
SUCCEED();
}

TEST_CASE("make_unique_for_overwrite_array", "[small_unique_ptr]")
{
STATIC_REQUIRE( std::invoke([]{ (void) make_unique_small_for_overwrite<SmallPOD[]>(2); return true; }) );
STATIC_REQUIRE( std::invoke([]{ (void) make_unique_small_for_overwrite<LargePOD[]>(2); return true; }) );

(void) make_unique_small_for_overwrite<SmallPOD[]>(2);
(void) make_unique_small_for_overwrite<LargePOD[]>(2);

(void) make_unique_small_for_overwrite<SmallPOD[]>(0);
(void) make_unique_small_for_overwrite<LargePOD[]>(0);

SUCCEED();
}

TEST_CASE("noexcept_construction", "[small_unique_ptr]")
{
STATIC_REQUIRE(noexcept(make_unique_small<SmallDerived>()));
STATIC_REQUIRE(!noexcept(make_unique_small<LargeDerived>()));

STATIC_REQUIRE(noexcept(make_unique_small_for_overwrite<SmallDerived>()));
STATIC_REQUIRE(!noexcept(make_unique_small_for_overwrite<LargeDerived>()));
}

TEST_CASE("is_always_heap_allocated", "[small_unique_ptr]")
Expand Down

0 comments on commit fcc8c20

Please sign in to comment.