Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tirvial-abi - concepts::is_trivially_relocatable #23

Merged
merged 9 commits into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion CMakePresets.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"name": "cfg-ninja",
"hidden": true,
"generator": "Ninja",
"cacheVariables": { "CMAKE_BUILD_TYPE": "Release" }
"cacheVariables": { "CMAKE_BUILD_TYPE": "Release" }
},
{
"name": "cfg-c++20",
Expand All @@ -41,6 +41,17 @@
"SMALL_VECTORS_ENABLE_LLD_LINKER" : "ON"
}
},
{
"name": "clang-debug",
"generator": "Ninja",
"inherits": [ "cfg-ninja", "cfg-c++26" ],
"cacheVariables": { "CMAKE_CXX_COMPILER" : "clang++", "CMAKE_BUILD_TYPE": "Debug" }
},
{
"name": "clang-20-release",
"inherits": [ "cfg-common", "cfg-ninja", "cfg-c++26" ],
"cacheVariables": { "CMAKE_CXX_COMPILER" : "clang++-20" }
},
{
"name": "clang-19-release",
"inherits": [ "cfg-common", "cfg-ninja", "cfg-c++26" ],
Expand Down
15 changes: 15 additions & 0 deletions include/small_vectors/concepts/concepts.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,21 @@ template<typename T>
concept trivially_destructible_after_move
= explicit_trivially_destructible_after_move<T> || std::is_trivially_destructible_v<T>;

template<typename T>
concept is_trivially_relocatable =
// !std::is_volatile_v<std::remove_all_extents_t<T>> // && (relocatable_tag<std::remove_all_extents_t<T>>::value(0) ||
(std::is_trivially_move_constructible_v<std::remove_all_extents_t<T>>
&& std::is_trivially_move_assignable_v<std::remove_all_extents_t<T>>
&& std::is_trivially_destructible_v<std::remove_all_extents_t<T>>)
#if __has_builtin(__is_trivially_relocatable)
|| __is_trivially_relocatable(std::remove_all_extents_t<T>)
#endif
;
template<class T, class... Args>
concept nothrow_relocatable_or_move_constr_and_constr_v
= (is_trivially_relocatable<T> or std::is_nothrow_move_constructible_v<T>)
and std::is_nothrow_constructible_v<T, Args...>;

template<typename T, typename... Args>
concept same_as_any_of = std::disjunction_v<std::is_same<T, Args>...>;

Expand Down
92 changes: 76 additions & 16 deletions include/small_vectors/detail/uninitialized_constexpr.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <small_vectors/concepts/concepts.h>
#include <memory>
#include <cstring>
#include <cassert>
#include <algorithm>

namespace small_vectors::inline v3_3::detail
Expand Down Expand Up @@ -64,20 +65,20 @@ template<bool use_nothrow, typename InputIt>
struct range_unwinder
{
using value_type = typename std::iterator_traits<InputIt>::value_type;

static constexpr bool skip_unwind = use_nothrow or std::is_trivially_destructible_v<value_type>;
InputIt first_res_, last_;

constexpr range_unwinder(InputIt first_res) noexcept : first_res_{first_res}, last_{first_res} {}

constexpr void release()
constexpr void release() noexcept
{
if constexpr(use_nothrow || !std::is_trivially_destructible_v<value_type>)
if constexpr(not skip_unwind)
first_res_ = last_;
}

constexpr ~range_unwinder()
constexpr ~range_unwinder() noexcept
{
if constexpr(use_nothrow || !std::is_trivially_destructible_v<value_type>)
if constexpr(not skip_unwind)
if(first_res_ != last_)
std::destroy(first_res_, last_);
}
Expand Down Expand Up @@ -177,19 +178,60 @@ template<typename Iter>
concept contiguous_iterator_with_trivialy_copy_constructible
= std::contiguous_iterator<Iter> && std::is_trivially_copy_constructible_v<std::iter_value_t<Iter>>;

template<concepts::iterator InputIterator, std::integral size_type, concepts::forward_iterator ForwardIterator>
inline auto uninitialized_trivial_memcpy(InputIterator first, size_type count, ForwardIterator result)
-> ForwardIterator
{
static constexpr auto elem_size{sizeof(std::iter_value_t<InputIterator>)};
if constexpr(std::contiguous_iterator<InputIterator> and std::contiguous_iterator<ForwardIterator>)
{
if(count > 0)
{
small_vectors_clang_unsafe_buffer_usage_begin //
assert(std::addressof(*first) != nullptr);
assert(std::addressof(*result) != nullptr);
std::memcpy(
static_cast<void *>(std::addressof(*result)),
static_cast<void const *>(std::addressof(*first)),
elem_size * std::size_t(count)
);
small_vectors_clang_unsafe_buffer_usage_end //
}
return std::next(result, ptrdiff_t(count));
}
else
{
small_vectors_clang_unsafe_buffer_usage_begin //
for(; count > 0; --count, (void)++first, ++result)
std::memcpy(std::addressof(*result), std::addressof(*first), elem_size);
small_vectors_clang_unsafe_buffer_usage_end //
return result;
}
}

// -------------------------------
// -- uninitialized_copy --

template<
contiguous_iterator_with_trivialy_copy_constructible InputIterator,
std::integral Size,
contiguous_iterator_with_trivialy_copy_constructible OutputIterator>
inline auto uninitialized_copy_n_impl(InputIterator first, Size count, OutputIterator out)
inline auto uninitialized_copy_n_impl(InputIterator first, Size count, OutputIterator out) -> OutputIterator
{
// static constexpr auto elem_size{sizeof(std::iter_value_t<InputIterator>)};
return std::uninitialized_copy_n(first, count, out);
// std::memcpy(std::addressof(*out), std::addressof(*first), elem_size * std::size_t(count));
// return std::next(out, std::ptrdiff_t(count));
static constexpr auto elem_size{sizeof(std::iter_value_t<InputIterator>)};
if(count > 0)
{
small_vectors_clang_unsafe_buffer_usage_begin //
assert(std::addressof(*first) != nullptr);
assert(std::addressof(*out) != nullptr);
std::memmove(
static_cast<void *>(std::addressof(*out)),
static_cast<void const *>(std::addressof(*first)),
elem_size * std::size_t(count)
);
small_vectors_clang_unsafe_buffer_usage_end //
}
return std::next(out, ptrdiff_t(count));
}

template<concepts::input_iterator InputIterator, std::integral Size, concepts::forward_iterator ForwardIterator>
Expand Down Expand Up @@ -315,7 +357,7 @@ auto uninitialized_move_n_impl(InputIterator first, Size count, ForwardIterator
contiguous_iterator_with_trivialy_move_constructible<InputIterator>
&& contiguous_iterator_with_trivialy_move_constructible<ForwardIterator>
));
constexpr bool use_nothrow = std::is_nothrow_constructible_v<iterator_value_type_t<InputIterator>>;
constexpr bool use_nothrow = std::is_nothrow_move_constructible_v<iterator_value_type_t<InputIterator>>;
using unwind = range_unwinder<use_nothrow, ForwardIterator>;
unwind cur{result};
small_vectors_clang_unsafe_buffer_usage_begin //
Expand Down Expand Up @@ -391,13 +433,30 @@ inline constexpr void uninitialized_move_if_noexcept_n(
// -- uninitialized_relocate --

template<concepts::iterator InputIterator, std::integral size_type, concepts::forward_iterator ForwardIterator>
requires(true == std::is_nothrow_move_constructible_v<iterator_value_type_t<InputIterator>>)
requires(
concepts::is_trivially_relocatable<iterator_value_type_t<InputIterator>>
or std::is_nothrow_move_constructible_v<iterator_value_type_t<InputIterator>>
)
inline constexpr void uninitialized_relocate_n(InputIterator first, size_type count, ForwardIterator result) noexcept
{
using value_type = iterator_value_type_t<InputIterator>;
uninitialized_move_n(first, count, result);
if constexpr(!concepts::trivially_destructible_after_move<value_type>)
destroy_range(first, size_type(0u), count);
if(std::is_constant_evaluated())
{
uninitialized_move_n(first, count, result);
if constexpr(not concepts::trivially_destructible_after_move<value_type>)
destroy_range(first, size_type(0u), count);
}
else
{
if constexpr(concepts::is_trivially_relocatable<value_type>)
uninitialized_trivial_memcpy(first, count, result);
else
{
uninitialized_move_n(first, count, result);
if constexpr(not concepts::trivially_destructible_after_move<value_type>)
destroy_range(first, size_type(0u), count);
}
}
}

template<concepts::iterator InputIterator, std::integral size_type, concepts::forward_iterator ForwardIterator>
Expand All @@ -407,7 +466,8 @@ inline constexpr void uninitialized_relocate_if_noexcept_n(
{
using value_type = iterator_value_type_t<InputIterator>;

constexpr bool use_nothrow = std::is_nothrow_move_constructible_v<iterator_value_type_t<InputIterator>>;
constexpr bool use_nothrow
= concepts::is_trivially_relocatable<value_type> or std::is_nothrow_move_constructible_v<value_type>;
if constexpr(use_nothrow)
uninitialized_relocate_n(first, count, result);
else
Expand Down
Loading