Skip to content

Commit

Permalink
add noexcept spec to make_unique_small (closes #3)
Browse files Browse the repository at this point in the history
  • Loading branch information
KRM7 committed Feb 7, 2024
1 parent 5177b84 commit 68d3aef
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 19 deletions.
54 changes: 35 additions & 19 deletions src/small_unique_ptr.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,8 @@ namespace detail
T* data_ = nullptr;
};

struct make_unique_small_impl;

} // namespace detail


Expand Down Expand Up @@ -417,8 +419,7 @@ class small_unique_ptr : private detail::small_unique_ptr_base<T>
template<typename U>
friend class small_unique_ptr;

template<typename U, typename... Args>
friend constexpr small_unique_ptr<U> make_unique_small(Args&&...);
friend struct detail::make_unique_small_impl;
};

template<typename T>
Expand All @@ -440,26 +441,41 @@ namespace std

} // namespace std

template<typename T, typename... Args>
[[nodiscard]] constexpr small_unique_ptr<T> make_unique_small(Args&&... args)
namespace detail
{
small_unique_ptr<T> ptr;

if (detail::is_always_heap_allocated_v<T> || std::is_constant_evaluated())
{
ptr.data_ = new T(std::forward<Args>(args)...);
}
else if constexpr (!detail::is_always_heap_allocated_v<T> && std::is_polymorphic_v<T> && !detail::has_virtual_move<T>)
{
ptr.data_ = std::construct_at(ptr.buffer(), std::forward<Args>(args)...);
ptr.move_ = detail::move_buffer<std::remove_cv_t<T>>;
}
else if constexpr (!detail::is_always_heap_allocated_v<T>)
struct make_unique_small_impl
{
ptr.data_ = std::construct_at(ptr.buffer(), std::forward<Args>(args)...);
}
template<typename T, typename... Args>
static constexpr small_unique_ptr<T> invoke(Args... args)
noexcept(std::is_nothrow_constructible_v<T, Args...> && !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(std::forward<Args>(args)...);
}
else if constexpr (!detail::is_always_heap_allocated_v<T> && std::is_polymorphic_v<T> && !detail::has_virtual_move<T>)
{
ptr.data_ = std::construct_at(ptr.buffer(), std::forward<Args>(args)...);
ptr.move_ = detail::move_buffer<std::remove_cv_t<T>>;
}
else if constexpr (!detail::is_always_heap_allocated_v<T>)
{
ptr.data_ = std::construct_at(ptr.buffer(), std::forward<Args>(args)...);
}

return ptr;
}
};

return ptr;
} // namespace detail

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>)
{
return detail::make_unique_small_impl::invoke<T>(std::forward<Args>(args)...);
}

#endif // !SMALL_UNIQUE_PTR_HPP
6 changes: 6 additions & 0 deletions test/small_unique_ptr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ TEST_CASE("construction", "[small_unique_ptr]")
REQUIRE_NOTHROW(make_unique_small<const LargePOD>());
}

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

TEST_CASE("is_always_heap_allocated", "[small_unique_ptr]")
{
STATIC_REQUIRE(!small_unique_ptr<SmallDerived>::is_always_heap_allocated());
Expand Down

0 comments on commit 68d3aef

Please sign in to comment.