Skip to content

Commit

Permalink
tirvial-abi - trivial relocation (#23)
Browse files Browse the repository at this point in the history
* tirvial-abi - concepts::is_trivially_relocatable
* add trivial relocation to storage and functions
* nodiscard, clang::trivial_abi on expected void
---------

Co-authored-by: Artur Bać <[email protected]>
  • Loading branch information
arturbac and Artur Bać authored Jan 16, 2025
1 parent 164f10b commit f8db89f
Show file tree
Hide file tree
Showing 8 changed files with 413 additions and 126 deletions.
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

0 comments on commit f8db89f

Please sign in to comment.