From dcedde8451766156b058dc164d636be65defdefc Mon Sep 17 00:00:00 2001 From: Dennis Hezel Date: Thu, 3 Oct 2024 13:53:59 +0200 Subject: [PATCH] chore: Regenerate amalgamated header --- src/cntgs.hpp | 2087 +++++++++++++++++++++++++------------------------ 1 file changed, 1049 insertions(+), 1038 deletions(-) diff --git a/src/cntgs.hpp b/src/cntgs.hpp index 3c21c8c..1059370 100644 --- a/src/cntgs.hpp +++ b/src/cntgs.hpp @@ -75,20 +75,11 @@ #include #include -#ifdef __cpp_lib_concepts -#include -#endif - namespace cntgs::detail { -#ifdef __cpp_lib_concepts -template -concept DerivedFrom = std::derived_from; -#else template -inline constexpr auto DerivedFrom = - std::is_base_of_v&& std::is_convertible_v; -#endif +inline constexpr auto IS_DERIVED_FROM = + std::is_base_of_v && std::is_convertible_v; #ifdef __cpp_lib_remove_cvref template @@ -108,75 +99,49 @@ template struct EqualSizeof { template - static constexpr auto VALUE = false; + static constexpr bool VALUE = false; }; template <> struct EqualSizeof { template - static constexpr auto VALUE = sizeof(T) == sizeof(U); + static constexpr bool VALUE = sizeof(T) == sizeof(U); }; template -inline constexpr auto EQUAL_SIZEOF = +inline constexpr bool EQUAL_SIZEOF = EqualSizeof<(std::is_same_v || std::is_same_v)>::template VALUE; -template -struct IsByte : std::false_type -{ -}; - -template <> -struct IsByte : std::true_type -{ -}; - -template <> -struct IsByte : std::true_type -{ -}; - -template <> -struct IsByte : std::true_type -{ -}; - -template <> -struct IsByte : std::true_type -{ -}; - +template +inline constexpr bool IS_BYTE = std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v #ifdef __cpp_char8_t -template <> -struct IsByte : std::true_type -{ -}; + || std::is_same_v #endif + ; namespace has_adl_swap_detail { void swap(); // undefined (deliberate shadowing) template -struct HasADLSwap : std::false_type -{ -}; +inline constexpr bool HAS_ADL_SWAP = false; + template -struct HasADLSwap(), std::declval()))>> : std::true_type -{ -}; +inline constexpr bool HAS_ADL_SWAP(), std::declval()))>> = true; } // namespace has_adl_swap_detail -using has_adl_swap_detail::HasADLSwap; // Implementation taken from MSVC _Is_trivially_swappable template -using IsTriviallySwappable = - std::conjunction, std::is_trivially_move_constructible, - std::is_trivially_move_assignable, std::negation>>; +inline constexpr bool IS_TRIVIALLY_SWAPPABLE = + std::is_trivially_destructible_v && std::is_trivially_move_constructible_v && + std::is_trivially_move_assignable_v && !has_adl_swap_detail::HAS_ADL_SWAP; template -inline constexpr auto IS_TRIVIALLY_SWAPPABLE = detail::IsTriviallySwappable::value; +struct IsTriviallySwappable : std::bool_constant> +{ +}; template struct Conditional @@ -195,46 +160,51 @@ struct Conditional template using ConditionalT = typename detail::Conditional::template Type; -template > -struct AreEqualityComparable : std::false_type -{ -}; +template +inline constexpr bool ARE_EQUALITY_COMPARABLE = false; template -struct AreEqualityComparable() == std::declval()), - decltype(std::declval() == std::declval())>> - : std::true_type -{ -}; +inline constexpr bool + ARE_EQUALITY_COMPARABLE() == std::declval()), + decltype(std::declval() == std::declval())>> = true; + +template +inline constexpr bool IS_NOTRHOW_EQUALITY_COMPARABLE = false; template -inline constexpr auto IS_NOTRHOW_EQUALITY_COMPARABLE = noexcept(std::declval() == std::declval()); +inline constexpr bool + IS_NOTRHOW_EQUALITY_COMPARABLE() == std::declval())>> = + noexcept(std::declval() == std::declval()); + +template +inline constexpr bool IS_NOTRHOW_LEXICOGRAPHICAL_COMPARABLE = false; template -inline constexpr auto IS_NOTRHOW_LEXICOGRAPHICAL_COMPARABLE = noexcept(std::declval() < - std::declval()); +inline constexpr bool IS_NOTRHOW_LEXICOGRAPHICAL_COMPARABLE< + T, std::void_t() < std::declval())>> = + noexcept(std::declval() < std::declval()); template -inline constexpr auto MEMCPY_COMPATIBLE = - detail::EQUAL_SIZEOF&& std::is_trivially_copyable_v&& std::is_trivially_copyable_v&& - std::is_floating_point_v == std::is_floating_point_v; +inline constexpr bool MEMCPY_COMPATIBLE = + detail::EQUAL_SIZEOF && std::is_trivially_copyable_v && std::is_trivially_copyable_v && + std::is_floating_point_v == std::is_floating_point_v; // Implementation taken from MSVC _Can_memcmp_elements template && std::is_integral_v && !std::is_volatile_v && std::is_integral_v && !std::is_volatile_v)> -inline constexpr auto EQUALITY_MEMCMP_COMPATIBLE = std::is_same_v || std::is_same_v || T(-1) == U(-1); +inline constexpr bool EQUALITY_MEMCMP_COMPATIBLE = std::is_same_v || std::is_same_v || T(-1) == U(-1); template <> -inline constexpr auto EQUALITY_MEMCMP_COMPATIBLE = true; +inline constexpr bool EQUALITY_MEMCMP_COMPATIBLE = true; template -inline constexpr auto EQUALITY_MEMCMP_COMPATIBLE = +inline constexpr bool EQUALITY_MEMCMP_COMPATIBLE = std::is_same_v, std::remove_cv_t>; template -inline constexpr auto EQUALITY_MEMCMP_COMPATIBLE = false; +inline constexpr bool EQUALITY_MEMCMP_COMPATIBLE = false; template struct EqualityMemcmpCompatible @@ -243,58 +213,46 @@ struct EqualityMemcmpCompatible }; // Implementation taken from MSVC+GCC _Lex_compare_check_element_types_helper and __is_memcmp_ordered -template ::value> -struct LexicographicalMemcmpCompatible : std::bool_constant<((T(-1) > T(1)) && !std::is_volatile_v)> -{ -}; +template > +inline constexpr bool LEXICOGRAPHICAL_MEMCMP_COMPATIBLE = T(-1) > T(1) && !std::is_volatile_v; template <> -struct LexicographicalMemcmpCompatible : std::true_type -{ -}; - -template -struct LexicographicalMemcmpCompatible : std::false_type -{ -}; +inline constexpr bool LEXICOGRAPHICAL_MEMCMP_COMPATIBLE = true; template -using LexicographicalMemcmpCompatibleT = detail::LexicographicalMemcmpCompatible>; +inline constexpr bool LEXICOGRAPHICAL_MEMCMP_COMPATIBLE = false; template -inline constexpr auto LEXICOGRAPHICAL_MEMCMP_COMPATIBLE = detail::LexicographicalMemcmpCompatibleT::value; +struct LexicographicalMemcmpCompatible : std::bool_constant> +{ +}; } // namespace cntgs::detail #endif // CNTGS_DETAIL_TYPETRAITS_HPP - #include #include namespace cntgs::detail { -template > -struct HasOperatorArrow : std::false_type -{ -}; +template +inline constexpr bool HAS_OPERATOR_ARROW = false; template -struct HasOperatorArrow().operator->())>> : std::true_type -{ -}; +inline constexpr bool HAS_OPERATOR_ARROW().operator->())>> = true; template struct ArrowProxy { - T t; + T t_; - constexpr const T* operator->() const noexcept { return &t; } + constexpr const T* operator->() const noexcept { return &t_; } }; template constexpr auto operator_arrow_produces_pointer_to_iterator_reference_type() noexcept { - if constexpr (detail::HasOperatorArrow::value) + if constexpr (detail::HAS_OPERATOR_ARROW) { return std::is_same_v().operator->()), std::add_pointer_t::reference>>; @@ -306,12 +264,12 @@ constexpr auto operator_arrow_produces_pointer_to_iterator_reference_type() noex } template -inline constexpr auto CONTIGUOUS_ITERATOR_V = - detail::DerivedFrom::iterator_category, std::random_access_iterator_tag>&& - std::is_lvalue_reference_v::reference>&& - std::is_same_v::value_type, - detail::RemoveCvrefT::reference>>&& - detail::operator_arrow_produces_pointer_to_iterator_reference_type(); +inline constexpr bool CONTIGUOUS_ITERATOR_V = + detail::IS_DERIVED_FROM::iterator_category, std::random_access_iterator_tag> && + std::is_lvalue_reference_v::reference> && + std::is_same_v::value_type, + detail::RemoveCvrefT::reference>> && + detail::operator_arrow_produces_pointer_to_iterator_reference_type(); } // namespace cntgs::detail #endif // CNTGS_DETAIL_ITERATOR_HPP @@ -331,32 +289,234 @@ inline constexpr auto CONTIGUOUS_ITERATOR_V = namespace cntgs::detail { -template > -struct HasDataAndSize : std::false_type +template +inline constexpr bool HAS_DATA_AND_SIZE = false; + +template +inline constexpr bool HAS_DATA_AND_SIZE< + T, std::void_t())), decltype(std::size(std::declval()))>> = true; + +template +inline constexpr bool IS_RANGE = false; + +template +inline constexpr bool + IS_RANGE())), decltype(std::end(std::declval()))>> = true; +} // namespace cntgs::detail + +#endif // CNTGS_DETAIL_RANGE_HPP + +// #include "cntgs/detail/typeTraits.hpp" + +#include +#include +#include +#include +#include +#include + +namespace cntgs::detail +{ +using Byte = std::underlying_type_t; + +template +struct Aligned { + alignas(N) std::byte v[N]; }; template -struct HasDataAndSize())), decltype(std::size(std::declval()))>> - : std::true_type +auto memcpy(const T* CNTGS_RESTRICT source, std::byte* CNTGS_RESTRICT target, std::size_t size) noexcept { -}; + std::memcpy(target, source, size * sizeof(T)); + return target + size * sizeof(T); +} -template > -struct IsRange : std::false_type +template +constexpr auto uninitialized_move(Range&& source, TargetIterator&& target) { -}; +#ifdef __cpp_lib_ranges + return std::ranges::uninitialized_move( + std::forward(source), + std::ranges::subrange{std::forward(target), std::unreachable_sentinel}) + .out; +#else + return std::uninitialized_move(std::begin(source), std::end(source), std::forward(target)); +#endif +} + +template +constexpr auto uninitialized_copy(Range&& source, TargetIterator&& target) +{ +#ifdef __cpp_lib_ranges + return std::ranges::uninitialized_copy( + std::forward(source), + std::ranges::subrange{std::forward(target), std::unreachable_sentinel}) + .out; +#else + return std::uninitialized_copy(std::begin(source), std::end(source), std::forward(target)); +#endif +} + +template +constexpr auto uninitialized_copy_n(SourceIterator&& source, DifferenceType count, TargetIterator&& target) +{ +#ifdef __cpp_lib_ranges + return std::ranges::uninitialized_copy_n(std::forward(source), + static_cast>(count), + std::forward(target), std::unreachable_sentinel) + .out; +#else + return std::uninitialized_copy_n(std::forward(source), count, std::forward(target)); +#endif +} + +template +auto uninitialized_range_construct(Range&& range, TargetType* address) +{ + using RangeValueType = typename std::iterator_traits::value_type; + if constexpr (IgnoreAliasing && detail::HAS_DATA_AND_SIZE> && + detail::MEMCPY_COMPATIBLE) + { + return detail::memcpy(std::data(range), reinterpret_cast(address), std::size(range)); + } + else + { + if constexpr (!std::is_lvalue_reference_v) + { + return reinterpret_cast(detail::uninitialized_move(std::forward(range), address)); + } + else + { + return reinterpret_cast(detail::uninitialized_copy(std::forward(range), address)); + } + } +} + +template +auto uninitialized_construct(Range&& range, TargetType* address, + std::size_t) -> std::enable_if_t, std::byte*> +{ + return detail::uninitialized_range_construct(std::forward(range), address); +} + +template +auto uninitialized_construct(const Iterator& iterator, TargetType* address, + std::size_t size) -> std::enable_if_t, std::byte*> +{ + using IteratorValueType = typename std::iterator_traits::value_type; + if constexpr (IgnoreAliasing && std::is_pointer_v && + detail::MEMCPY_COMPATIBLE) + { + return detail::memcpy(iterator, reinterpret_cast(address), size); + } + else if constexpr (IgnoreAliasing && detail::CONTIGUOUS_ITERATOR_V && + detail::MEMCPY_COMPATIBLE) + { + return detail::memcpy(iterator.operator->(), reinterpret_cast(address), size); + } + else + { + return reinterpret_cast(detail::uninitialized_copy_n(iterator, size, address)); + } +} + +#ifdef __cpp_lib_ranges +using std::construct_at; +#else +template +constexpr T* construct_at(T* ptr, Args&&... args) +{ + return ::new (const_cast(static_cast(ptr))) T(std::forward(args)...); +} +#endif + +#ifdef __cpp_lib_assume_aligned +using std::assume_aligned; +#else +template +[[nodiscard]] constexpr T* assume_aligned(T* const ptr) noexcept +{ + return static_cast(::__builtin_assume_aligned(ptr, Alignment)); +} +#endif + +[[nodiscard]] inline bool is_aligned(void* ptr, size_t alignment) noexcept +{ + void* void_ptr = ptr; + auto size = std::numeric_limits::max(); + std::align(alignment, 0, void_ptr, size); + return void_ptr == ptr; +} + +[[nodiscard]] constexpr auto align(std::uintptr_t position, std::size_t alignment) noexcept +{ + return (position - 1u + alignment) & (alignment * std::numeric_limits::max()); +} + +template +[[nodiscard]] constexpr auto align(std::uintptr_t position) noexcept +{ + if constexpr (Alignment > 1) + { + return detail::align(position, Alignment); + } + else + { + return position; + } +} + +template +[[nodiscard]] constexpr T* align(T* ptr) noexcept +{ + if constexpr (Alignment > 1) + { + const auto uintptr = reinterpret_cast(ptr); + const auto aligned = detail::align(uintptr); + return detail::assume_aligned(reinterpret_cast(aligned)); + } + else + { + return ptr; + } +} + +template +[[nodiscard]] constexpr auto align_if(T* ptr) noexcept +{ + if constexpr (NeedsAlignment && Alignment > 1) + { + ptr = detail::align(ptr); + } + return detail::assume_aligned(ptr); +} + +template +[[nodiscard]] constexpr auto align_if(std::uintptr_t position) noexcept +{ + if constexpr (NeedsAlignment && Alignment > 1) + { + position = detail::align(position); + } + return position; +} template -struct IsRange())), decltype(std::end(std::declval()))>> - : std::true_type +[[nodiscard]] constexpr T extract_lowest_set_bit(T value) noexcept { -}; -} // namespace cntgs::detail + return value & (~value + T{1}); +} -#endif // CNTGS_DETAIL_RANGE_HPP +[[nodiscard]] constexpr std::size_t trailing_alignment(std::size_t byte_size, std::size_t alignment) noexcept +{ + return (std::min)(detail::extract_lowest_set_bit(byte_size), alignment); +} -// #include "cntgs/detail/typeTraits.hpp" +inline constexpr auto SIZE_T_TRAILING_ALIGNMENT = detail::trailing_alignment(sizeof(std::size_t), alignof(std::size_t)); +} // namespace cntgs::detail + +#endif // CNTGS_DETAIL_MEMORY_HPP // #include "cntgs/detail/utility.hpp" // Copyright (c) 2021 Dennis Hezel @@ -400,13 +560,13 @@ struct Span using iterator = T*; using reverse_iterator = std::reverse_iterator; - iterator first; - iterator last; + iterator first_; + iterator last_; Span() = default; template - constexpr explicit Span(const Span& other) noexcept : first(other.first), last(other.last) + constexpr explicit Span(const Span& other) noexcept : first_(other.first_), last_(other.last_) { } @@ -415,44 +575,43 @@ struct Span Span(Span&& other) = default; Span& operator=(const Span& other) = default; - + Span& operator=(Span&& other) = default; - constexpr Span(iterator first, iterator last) noexcept : first(first), last(last) {} + constexpr Span(iterator first, iterator last) noexcept : first_(first), last_(last) {} - constexpr Span(iterator first, size_type size) noexcept(noexcept(first + size)) : first(first), last(first + size) + constexpr Span(iterator first, size_type size) noexcept(noexcept(first + size)) : first_(first), last_(first + size) { } - [[nodiscard]] constexpr iterator begin() const noexcept { return this->first; } + [[nodiscard]] constexpr iterator begin() const noexcept { return first_; } - [[nodiscard]] constexpr iterator end() const noexcept { return this->last; } + [[nodiscard]] constexpr iterator end() const noexcept { return last_; } - [[nodiscard]] constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{this->end()}; } + [[nodiscard]] constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; } - [[nodiscard]] constexpr reverse_iterator rend() const noexcept { return reverse_iterator{this->begin()}; } + [[nodiscard]] constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; } - [[nodiscard]] constexpr bool empty() const noexcept { return this->first == this->last; } + [[nodiscard]] constexpr bool empty() const noexcept { return first_ == last_; } - [[nodiscard]] constexpr size_type size() const noexcept { return this->last - this->first; } + [[nodiscard]] constexpr size_type size() const noexcept { return last_ - first_; } - [[nodiscard]] constexpr pointer data() const noexcept { return this->first; } + [[nodiscard]] constexpr pointer data() const noexcept { return first_; } - [[nodiscard]] constexpr reference operator[](size_type i) const noexcept { return this->first[i]; } + [[nodiscard]] constexpr reference operator[](size_type i) const noexcept { return first_[i]; } - [[nodiscard]] constexpr reference front() const noexcept { return this->first[0]; } + [[nodiscard]] constexpr reference front() const noexcept { return first_[0]; } - [[nodiscard]] constexpr reference back() const noexcept { return *(this->last - 1); } + [[nodiscard]] constexpr reference back() const noexcept { return *(last_ - 1); } #ifdef __cpp_lib_span - constexpr operator std::span() const noexcept { return std::span{first, last}; } + constexpr operator std::span() const noexcept { return std::span{first_, last_}; } #endif }; } // namespace cntgs #endif // CNTGS_CNTGS_SPAN_HPP - #include namespace cntgs::detail @@ -460,24 +619,24 @@ namespace cntgs::detail template struct MoveDefaultingValue { - T value{}; + T value_{}; MoveDefaultingValue() = default; - constexpr explicit MoveDefaultingValue(T value) noexcept : value(value) {} + constexpr explicit MoveDefaultingValue(T value) noexcept : value_(value) {} ~MoveDefaultingValue() = default; MoveDefaultingValue(const MoveDefaultingValue&) = default; - constexpr MoveDefaultingValue(MoveDefaultingValue&& other) noexcept : value(other.value) { other.value = T{}; } + constexpr MoveDefaultingValue(MoveDefaultingValue&& other) noexcept : value_(other.value_) { other.value_ = T{}; } MoveDefaultingValue& operator=(const MoveDefaultingValue& other) = default; constexpr MoveDefaultingValue& operator=(MoveDefaultingValue&& other) noexcept { - this->value = other.value; - other.value = T{}; + value_ = other.value_; + other.value_ = T{}; return *this; } }; @@ -486,24 +645,24 @@ template && !std::is_final_v)> class EmptyBaseOptimization { private: - T value; + T value_; public: EmptyBaseOptimization() = default; constexpr explicit EmptyBaseOptimization(const T& value) noexcept(std::is_nothrow_copy_constructible_v) - : value{value} + : value_{value} { } constexpr explicit EmptyBaseOptimization(T&& value) noexcept(std::is_nothrow_move_constructible_v) - : value{std::move(value)} + : value_{std::move(value)} { } - constexpr auto& get() noexcept { return value; } + constexpr auto& get() noexcept { return value_; } - constexpr const auto& get() const noexcept { return value; } + constexpr const auto& get() const noexcept { return value_; } }; template @@ -556,195 +715,22 @@ constexpr decltype(auto) as_const_ref(T&& value) noexcept { return detail::as_const(detail::as_ref(std::forward(value))); } -} // namespace cntgs::detail - -#endif // CNTGS_DETAIL_UTILITY_HPP - -// #include "cntgs/span.hpp" - - -#include -#include -#include -#include -#include -#include -#include - -namespace cntgs::detail -{ -using Byte = std::underlying_type_t; - -template -struct alignas(N) AlignedByte -{ - std::byte byte; -}; - -template -auto memcpy(const T* CNTGS_RESTRICT source, std::byte* CNTGS_RESTRICT target, std::size_t size) noexcept -{ - std::memcpy(target, source, size * sizeof(T)); - return target + size * sizeof(T); -} - -template -constexpr auto uninitialized_move(Range&& source, TargetIterator&& target) -{ -#ifdef __cpp_lib_ranges - return std::ranges::uninitialized_move( - std::forward(source), - std::ranges::subrange{std::forward(target), std::unreachable_sentinel}) - .out; -#else - return std::uninitialized_move(std::begin(source), std::end(source), std::forward(target)); -#endif -} - -template -constexpr auto uninitialized_copy(Range&& source, TargetIterator&& target) -{ -#ifdef __cpp_lib_ranges - return std::ranges::uninitialized_copy( - std::forward(source), - std::ranges::subrange{std::forward(target), std::unreachable_sentinel}) - .out; -#else - return std::uninitialized_copy(std::begin(source), std::end(source), std::forward(target)); -#endif -} - -template -constexpr auto uninitialized_copy_n(SourceIterator&& source, DifferenceType count, TargetIterator&& target) -{ -#ifdef __cpp_lib_ranges - return std::ranges::uninitialized_copy_n(std::forward(source), - static_cast>(count), - std::forward(target), std::unreachable_sentinel) - .out; -#else - return std::uninitialized_copy_n(std::forward(source), count, std::forward(target)); -#endif -} - -template -auto uninitialized_range_construct(Range&& CNTGS_RESTRICT range, TargetType* CNTGS_RESTRICT address) -{ - using RangeValueType = typename std::iterator_traits::value_type; - if constexpr (IgnoreAliasing && detail::HasDataAndSize>{} && - detail::MEMCPY_COMPATIBLE) - { - return detail::memcpy(std::data(range), reinterpret_cast(address), std::size(range)); - } - else - { - if constexpr (!std::is_lvalue_reference_v) - { - return reinterpret_cast(detail::uninitialized_move(std::forward(range), address)); - } - else - { - return reinterpret_cast(detail::uninitialized_copy(std::forward(range), address)); - } - } -} -template -auto uninitialized_construct(Range&& CNTGS_RESTRICT range, TargetType* CNTGS_RESTRICT address, std::size_t) - -> std::enable_if_t::value, std::byte*> +template +constexpr decltype(auto) move_if(T& value) { - return detail::uninitialized_range_construct(std::forward(range), address); -} - -template -auto uninitialized_construct(const Iterator& CNTGS_RESTRICT iterator, TargetType* CNTGS_RESTRICT address, - std::size_t size) -> std::enable_if_t::value, std::byte*> -{ - using IteratorValueType = typename std::iterator_traits::value_type; - if constexpr (IgnoreAliasing && std::is_pointer_v && - detail::MEMCPY_COMPATIBLE) - { - return detail::memcpy(iterator, reinterpret_cast(address), size); - } - else if constexpr (IgnoreAliasing && detail::CONTIGUOUS_ITERATOR_V && - detail::MEMCPY_COMPATIBLE) + if constexpr (UseMove) { - return detail::memcpy(iterator.operator->(), reinterpret_cast(address), size); + return std::move(value); } else { - return reinterpret_cast(detail::uninitialized_copy_n(iterator, size, address)); + return (value); } } - -#ifdef __cpp_lib_ranges -using std::construct_at; -#else -template -constexpr T* construct_at(T* ptr, Args&&... args) -{ - return ::new (const_cast(static_cast(ptr))) T(std::forward(args)...); -} -#endif - -#ifdef __cpp_lib_assume_aligned -using std::assume_aligned; -#else -template -[[nodiscard]] constexpr T* assume_aligned(T* const ptr) noexcept -{ - return static_cast(::__builtin_assume_aligned(ptr, Alignment)); -} -#endif - -[[nodiscard]] constexpr auto align(std::uintptr_t position, std::size_t alignment) noexcept -{ - return (position - 1u + alignment) & (alignment * std::numeric_limits::max()); -} - -template -[[nodiscard]] constexpr auto align(std::uintptr_t position) noexcept -{ - if constexpr (Alignment > 1) - { - return detail::align(position, Alignment); - } - else - { - return position; - } -} - -template -[[nodiscard]] constexpr T* align(T* ptr) noexcept -{ - if constexpr (Alignment > 1) - { - const auto uintptr = reinterpret_cast(ptr); - const auto aligned = detail::align(uintptr); - return detail::assume_aligned(reinterpret_cast(aligned)); - } - else - { - return ptr; - } -} - -template -[[nodiscard]] constexpr auto align_if(T* ptr) noexcept -{ - if constexpr (NeedsAlignment && Alignment > 1) - { - ptr = detail::align(ptr); - } - return detail::assume_aligned(ptr); -} } // namespace cntgs::detail -#endif // CNTGS_DETAIL_MEMORY_HPP - -// #include "cntgs/detail/utility.hpp" - +#endif // CNTGS_DETAIL_UTILITY_HPP #include #include @@ -752,8 +738,6 @@ template namespace cntgs::detail { -using TypeErasedAllocator = std::aligned_storage_t<32>; - template class AllocatorAwarePointer { @@ -771,26 +755,26 @@ class AllocatorAwarePointer { using Base = detail::EmptyBaseOptimization; - Pointer ptr{}; - std::size_t size{}; + Pointer ptr_{}; + std::size_t size_{}; Impl() = default; constexpr Impl(Pointer ptr, std::size_t size, const Allocator& allocator) noexcept - : Base{allocator}, ptr(ptr), size(size) + : Base{allocator}, ptr_(ptr), size_(size) { } }; - Impl impl; + Impl impl_; - constexpr auto allocate() { return AllocatorTraits::allocate(this->get_allocator(), this->size()); } + constexpr auto allocate() { return AllocatorTraits::allocate(get_allocator(), size()); } constexpr void deallocate() noexcept { - if (this->get()) + if (get()) { - AllocatorTraits::deallocate(this->get_allocator(), this->get(), this->size()); + AllocatorTraits::deallocate(get_allocator(), get(), size()); } } @@ -809,12 +793,12 @@ class AllocatorAwarePointer AllocatorAwarePointer() = default; constexpr AllocatorAwarePointer(std::size_t size, const Allocator& allocator) - : impl(AllocatorAwarePointer::allocate_if_not_zero(size, allocator), size, allocator) + : impl_(AllocatorAwarePointer::allocate_if_not_zero(size, allocator), size, allocator) { } constexpr AllocatorAwarePointer(pointer ptr, std::size_t size, const Allocator& allocator) noexcept - : impl(ptr, size, allocator) + : impl_(ptr, size, allocator) { } @@ -825,7 +809,7 @@ class AllocatorAwarePointer } constexpr AllocatorAwarePointer(AllocatorAwarePointer&& other) noexcept - : impl(other.release(), other.size(), other.get_allocator()) + : impl_(other.release(), other.size(), other.get_allocator()) { } @@ -834,7 +818,7 @@ class AllocatorAwarePointer #endif ~AllocatorAwarePointer() noexcept { - this->deallocate(); + deallocate(); } constexpr AllocatorAwarePointer& operator=(const AllocatorAwarePointer& other) @@ -844,21 +828,21 @@ class AllocatorAwarePointer if constexpr (AllocatorTraits::propagate_on_container_copy_assignment::value && !AllocatorTraits::is_always_equal::value) { - if (this->get_allocator() != other.get_allocator()) + if (get_allocator() != other.get_allocator()) { - this->deallocate(); - this->propagate_on_container_copy_assignment(other); - this->size() = other.size(); - this->get() = this->allocate(); + deallocate(); + propagate_on_container_copy_assignment(other); + size() = other.size(); + get() = allocate(); return *this; } } - this->propagate_on_container_copy_assignment(other); - if (this->size() < other.size() || !this->get()) + propagate_on_container_copy_assignment(other); + if (size() < other.size() || !get()) { - this->deallocate(); - this->size() = other.size(); - this->get() = this->allocate(); + deallocate(); + size() = other.size(); + get() = allocate(); } } return *this; @@ -868,42 +852,42 @@ class AllocatorAwarePointer { if (this != std::addressof(other)) { - this->propagate_on_container_move_assignment(other); - this->deallocate(); - this->get() = other.release(); - this->size() = other.size(); + propagate_on_container_move_assignment(other); + deallocate(); + get() = other.release(); + size() = other.size(); } return *this; } - constexpr decltype(auto) get_allocator() noexcept { return this->impl.get(); } + constexpr decltype(auto) get_allocator() noexcept { return impl_.get(); } - constexpr auto get_allocator() const noexcept { return this->impl.get(); } + constexpr auto get_allocator() const noexcept { return impl_.get(); } - constexpr auto& get() noexcept { return this->impl.ptr; } + constexpr auto& get() noexcept { return impl_.ptr_; } - constexpr auto get() const noexcept { return this->impl.ptr; } + constexpr auto get() const noexcept { return impl_.ptr_; } - constexpr auto& size() noexcept { return this->impl.size; } + constexpr auto& size() noexcept { return impl_.size_; } - constexpr auto size() const noexcept { return this->impl.size; } + constexpr auto size() const noexcept { return impl_.size_; } - constexpr explicit operator bool() const noexcept { return this->get() != nullptr; } + constexpr explicit operator bool() const noexcept { return get() != nullptr; } - constexpr auto release() noexcept { return std::exchange(this->impl.ptr, nullptr); } + constexpr auto release() noexcept { return std::exchange(impl_.ptr_, nullptr); } constexpr void reset(AllocatorAwarePointer&& other) noexcept { - this->deallocate(); - this->get() = other.release(); - this->size() = other.size(); + deallocate(); + get() = other.release(); + size() = other.size(); } constexpr void propagate_on_container_copy_assignment(const AllocatorAwarePointer& other) noexcept { if constexpr (AllocatorTraits::propagate_on_container_copy_assignment::value) { - this->get_allocator() = other.get_allocator(); + get_allocator() = other.get_allocator(); } } @@ -911,7 +895,7 @@ class AllocatorAwarePointer { if constexpr (AllocatorTraits::propagate_on_container_move_assignment::value) { - this->get_allocator() = std::move(other.get_allocator()); + get_allocator() = std::move(other.get_allocator()); } } }; @@ -928,14 +912,6 @@ constexpr void swap(detail::AllocatorAwarePointer& lhs, swap(lhs.get(), rhs.get()); swap(lhs.size(), rhs.size()); } - -template -auto type_erase_allocator(T&& allocator) noexcept -{ - detail::TypeErasedAllocator result; - detail::construct_at(reinterpret_cast*>(&result), std::forward(allocator)); - return result; -} } // namespace cntgs::detail #endif // CNTGS_DETAIL_ALLOCATOR_HPP @@ -960,7 +936,6 @@ auto type_erase_allocator(T&& allocator) noexcept // #include "cntgs/detail/memory.hpp" - #include #include #include @@ -1033,8 +1008,6 @@ class BasicContiguousVector; template class ContiguousVectorIterator; -class TypeErasedVector; - template class BasicContiguousReference; @@ -1073,7 +1046,7 @@ namespace cntgs::detail template struct Array { - std::array array; + std::array array_; }; template @@ -1087,7 +1060,7 @@ struct Array template constexpr decltype(auto) get(const detail::Array& array) noexcept { - return std::get(array.array); + return std::get(array.array_); } template @@ -1105,7 +1078,7 @@ constexpr auto convert_array_to_size(const detail::Array& array, std::inde template constexpr auto convert_array_to_size(const detail::Array& array) { - return detail::convert_array_to_size(array, std::make_index_sequence{}); + return detail::convert_array_to_size(array, std::make_index_sequence<(std::min)(N, K)>{}); } } // namespace cntgs::detail @@ -1120,8 +1093,6 @@ constexpr auto convert_array_to_size(const detail::Array& array) #ifndef CNTGS_DETAIL_PARAMETERTRAITS_HPP #define CNTGS_DETAIL_PARAMETERTRAITS_HPP -// #include "cntgs/detail/attributes.hpp" - // #include "cntgs/detail/memory.hpp" // #include "cntgs/detail/parameterType.hpp" @@ -1145,8 +1116,6 @@ enum class ParameterType #endif // CNTGS_DETAIL_PARAMETERTYPE_HPP -// #include "cntgs/detail/typeTraits.hpp" - // #include "cntgs/parameter.hpp" // Copyright (c) 2021 Dennis Hezel // @@ -1205,8 +1174,8 @@ struct Allocator // #include "cntgs/span.hpp" - #include +#include #include #include #include @@ -1214,6 +1183,20 @@ struct Allocator namespace cntgs::detail { +struct AlignedSizeInMemory +{ + std::size_t offset; + std::size_t size; + std::size_t padding; +}; + +template +struct VaryingSizeAddresses +{ + T* value; + std::size_t* size; +}; + template struct ParameterTraits : detail::ParameterTraits> { @@ -1230,27 +1213,35 @@ struct ParameterTraits> static constexpr auto TYPE = detail::ParameterType::PLAIN; static constexpr auto ALIGNMENT = Alignment; static constexpr auto VALUE_BYTES = sizeof(T); - static constexpr auto ALIGNED_SIZE_IN_MEMORY = std::max(VALUE_BYTES, ALIGNMENT); + static constexpr auto TRAILING_ALIGNMENT = detail::trailing_alignment(VALUE_BYTES, ALIGNMENT); - template + template static auto load(std::byte* address, std::size_t) noexcept { - address = detail::align_if(address); + address = detail::align_if<(PreviousAlignment < ALIGNMENT), ALIGNMENT>(address); + assert(detail::is_aligned(address, ALIGNMENT)); auto result = std::launder(reinterpret_cast(address)); return std::pair{result, address + VALUE_BYTES}; } - template - CNTGS_RESTRICT_RETURN static std::byte* store(Arg&& arg, std::byte* CNTGS_RESTRICT address, std::size_t) + template + static std::byte* store(Arg&& arg, std::byte* address, std::size_t) { - address = reinterpret_cast(detail::align_if(address)); + address = detail::align_if<(PreviousAlignment < ALIGNMENT), ALIGNMENT>(address); + assert(detail::is_aligned(address, ALIGNMENT)); detail::construct_at(reinterpret_cast(address), std::forward(arg)); return address + VALUE_BYTES; } - static constexpr auto aligned_size_in_memory(std::size_t) noexcept { return ALIGNED_SIZE_IN_MEMORY; } - - static constexpr auto guaranteed_size_in_memory(std::size_t) noexcept { return VALUE_BYTES; } + template + static constexpr AlignedSizeInMemory aligned_size_in_memory(std::size_t offset, std::size_t) noexcept + { + const auto alignment_offset = detail::align_if<(PreviousAlignment < ALIGNMENT), ALIGNMENT>(offset); + const auto size = alignment_offset - offset + VALUE_BYTES; + const auto new_offset = offset + size; + const auto padding_offset = detail::align_if<(TRAILING_ALIGNMENT < NextAlignment), NextAlignment>(new_offset); + return {new_offset, size, padding_offset - new_offset}; + } static auto data_begin(ConstReferenceType reference) noexcept { @@ -1313,6 +1304,8 @@ struct BaseContiguousParameterTraits { using Self = BaseContiguousParameterTraits; + static constexpr auto VALUE_BYTES = sizeof(T); + static auto data_end(const cntgs::Span>& value) noexcept { return reinterpret_cast(std::end(value)); @@ -1415,47 +1408,68 @@ struct ParameterTraits>> : BaseC using IteratorType = T*; static constexpr auto TYPE = detail::ParameterType::VARYING_SIZE; - static constexpr auto ALIGNMENT = Alignment; - static constexpr auto MEMORY_OVERHEAD = sizeof(std::size_t); - static constexpr auto ALIGNED_SIZE_IN_MEMORY = MEMORY_OVERHEAD + ALIGNMENT - 1; + static constexpr auto ALIGNMENT = alignof(std::size_t); + static constexpr auto VALUE_ALIGNMENT = Alignment; + static constexpr auto TRAILING_ALIGNMENT = detail::trailing_alignment(sizeof(T), ALIGNMENT); - template + template static auto load(std::byte* address, std::size_t size) noexcept { + const auto [value_address, size_address] = get_addresses(address); if constexpr (!IsSizeProvided) { - size = *reinterpret_cast(address); + size = *size_address; } - address += MEMORY_OVERHEAD; - const auto first_byte = detail::align_if(address); - const auto first = std::launder(reinterpret_cast(first_byte)); - const auto last = std::launder(reinterpret_cast(first_byte) + size); + const auto first = std::launder(reinterpret_cast(value_address)); + const auto last = std::launder(reinterpret_cast(value_address) + size); return std::pair{PointerType{first, last}, reinterpret_cast(last)}; } - template - CNTGS_RESTRICT_RETURN static std::byte* store(Range&& range, std::byte* CNTGS_RESTRICT address, std::size_t) + template + static std::byte* store(Range&& range, std::byte* address, std::size_t) { - const auto size = reinterpret_cast(address); - address += MEMORY_OVERHEAD; - const auto aligned_address = - reinterpret_cast(detail::align_if(address)); + const auto [value_address, size_address] = get_addresses(address); auto* new_address = - detail::uninitialized_range_construct(std::forward(range), aligned_address); - *size = reinterpret_cast(new_address) - aligned_address; + detail::uninitialized_range_construct(std::forward(range), value_address); + *size_address = reinterpret_cast(new_address) - value_address; return new_address; } - static constexpr auto aligned_size_in_memory(std::size_t) noexcept { return ALIGNED_SIZE_IN_MEMORY; } + template + static constexpr AlignedSizeInMemory aligned_size_in_memory(std::size_t offset, std::size_t) noexcept + { + const auto size_t_alignment_offset = detail::align_if<(PreviousAlignment < ALIGNMENT), ALIGNMENT>(offset); + const auto value_alignment_offset = + detail::align_if<(detail::SIZE_T_TRAILING_ALIGNMENT < VALUE_ALIGNMENT), VALUE_ALIGNMENT>( + size_t_alignment_offset + sizeof(std::size_t)); + const auto trailing_alignment = + detail::trailing_alignment(sizeof(T), detail::extract_lowest_set_bit(value_alignment_offset)); + const auto next_alignment_difference = + trailing_alignment < NextAlignment ? NextAlignment - trailing_alignment : 0; + return {0, value_alignment_offset - offset + next_alignment_difference, 0}; + } static auto data_begin(const cntgs::Span>& value) noexcept { - return reinterpret_cast(ParameterTraits::begin(value)) - MEMORY_OVERHEAD; + return reinterpret_cast(ParameterTraits::begin(value)) - sizeof(std::size_t); } static auto data_begin(const cntgs::Span& value) noexcept { - return reinterpret_cast(ParameterTraits::begin(value)) - MEMORY_OVERHEAD; + return reinterpret_cast(ParameterTraits::begin(value)) - sizeof(std::size_t); + } + + template + static VaryingSizeAddresses get_addresses(std::byte* address) noexcept + { + address = detail::align_if<(PreviousAlignment < ALIGNMENT), ALIGNMENT>(address); + assert(detail::is_aligned(address, ALIGNMENT)); + auto size = reinterpret_cast(address); + address += sizeof(std::size_t); + const auto aligned_address = reinterpret_cast( + detail::align_if<(detail::SIZE_T_TRAILING_ALIGNMENT < VALUE_ALIGNMENT), VALUE_ALIGNMENT>(address)); + assert(detail::is_aligned(aligned_address, VALUE_ALIGNMENT)); + return {aligned_address, size}; } }; @@ -1475,42 +1489,37 @@ struct ParameterTraits>> : BaseCon static constexpr auto TYPE = detail::ParameterType::FIXED_SIZE; static constexpr auto ALIGNMENT = Alignment; - static constexpr auto VALUE_BYTES = sizeof(T); + using ParameterTraits::BaseContiguousParameterTraits::VALUE_BYTES; + static constexpr auto TRAILING_ALIGNMENT = detail::trailing_alignment(VALUE_BYTES, ALIGNMENT); - template + template static auto load(std::byte* address, std::size_t size) noexcept { - const auto first = - std::launder(reinterpret_cast(detail::align_if(address))); + const auto first = std::launder( + reinterpret_cast(detail::align_if<(PreviousAlignment < ALIGNMENT), ALIGNMENT>(address))); + assert(detail::is_aligned(first, ALIGNMENT)); const auto last = first + size; return std::pair{PointerType{first, last}, reinterpret_cast(last)}; } - template - CNTGS_RESTRICT_RETURN static std::byte* store(RangeOrIterator&& range_or_iterator, - std::byte* CNTGS_RESTRICT address, std::size_t size) + template + static std::byte* store(RangeOrIterator&& range_or_iterator, std::byte* address, std::size_t size) { const auto aligned_address = - reinterpret_cast(detail::align_if(address)); + reinterpret_cast(detail::align_if<(PreviousAlignment < ALIGNMENT), ALIGNMENT>(address)); + assert(detail::is_aligned(aligned_address, ALIGNMENT)); return detail::uninitialized_construct(std::forward(range_or_iterator), aligned_address, size); } - static constexpr auto aligned_size_in_memory(std::size_t fixed_size) noexcept - { - if constexpr (ALIGNMENT == 1) - { - return fixed_size * VALUE_BYTES; - } - else - { - return std::max(fixed_size * VALUE_BYTES, ALIGNMENT); - } - } - - static constexpr auto guaranteed_size_in_memory(std::size_t fixed_size) noexcept + template + static constexpr AlignedSizeInMemory aligned_size_in_memory(std::size_t offset, std::size_t fixed_size) noexcept { - return fixed_size * VALUE_BYTES; + const auto alignment_offset = detail::align_if<(PreviousAlignment < ALIGNMENT), ALIGNMENT>(offset); + const auto size = alignment_offset - offset + VALUE_BYTES * fixed_size; + const auto new_offset = offset + size; + const auto padding_offset = detail::align_if<(TRAILING_ALIGNMENT < NextAlignment), NextAlignment>(new_offset); + return {new_offset, size, padding_offset - new_offset}; } static auto data_begin(const cntgs::Span>& value) noexcept @@ -1554,7 +1563,6 @@ struct ParameterTraits>> : BaseCon // #include "cntgs/detail/typeTraits.hpp" - #include #include #include @@ -1619,6 +1627,25 @@ struct ParameterListTraits static constexpr bool IS_ALL_PLAIN = CONTIGUOUS_COUNT == 0; static constexpr bool IS_FIXED_SIZE_OR_PLAIN = IS_ALL_FIXED_SIZE || IS_ALL_PLAIN; + static constexpr std::size_t LARGEST_LEADING_ALIGNMENT_UNTIL_VARYING_SIZE = [] + { + bool stop{}; + std::size_t alignment{}; + ( + [&] + { + if constexpr (detail::ParameterTraits::TYPE == ParameterType::VARYING_SIZE) + { + alignment = (std::max)(alignment, detail::ParameterTraits::VALUE_ALIGNMENT); + stop = true; + } + alignment = (std::max)(alignment, detail::ParameterTraits::ALIGNMENT); + return stop; + }() || + ...); + return alignment; + }(); + using FixedSizes = std::array; using FixedSizesArray = detail::Array; @@ -1627,6 +1654,38 @@ struct ParameterListTraits "to a higher limit."); static constexpr auto make_index_sequence() noexcept { return std::make_index_sequence{}; } + + template + static constexpr std::size_t trailing_alignment() noexcept + { + return detail::trailing_alignment(ParameterTraitsAt<(I)>::VALUE_BYTES, ParameterTraitsAt<(I)>::ALIGNMENT); + } + + template + static constexpr std::size_t next_alignment() noexcept + { + if constexpr (sizeof...(Parameter) - 1 == I) + { + return LARGEST_LEADING_ALIGNMENT_UNTIL_VARYING_SIZE; + } + else + { + return ParameterTraitsAt<(I + 1)>::ALIGNMENT; + } + } + + template + static constexpr std::size_t previous_alignment() noexcept + { + if constexpr (I == 0) + { + return LARGEST_LEADING_ALIGNMENT_UNTIL_VARYING_SIZE; + } + else + { + return trailing_alignment<(I - 1)>(); + } + } }; } // namespace cntgs::detail @@ -1660,7 +1719,6 @@ struct ParameterListTraits // #include "cntgs/detail/typeTraits.hpp" - #include namespace cntgs::detail @@ -1676,7 +1734,6 @@ using ToTupleOfContiguousReferences = #endif // CNTGS_DETAIL_TUPLE_HPP - namespace std { template @@ -1722,7 +1779,6 @@ template // #include "cntgs/detail/typeTraits.hpp" - #include #include #include @@ -1804,7 +1860,6 @@ class ContiguousReferenceSizeGetter // #include "cntgs/detail/tuple.hpp" - #include namespace cntgs::detail @@ -1820,7 +1875,6 @@ struct ContiguousVectorTraits #endif // CNTGS_DETAIL_VECTORTRAITS_HPP - #include #include #include @@ -1828,24 +1882,6 @@ struct ContiguousVectorTraits namespace cntgs::detail { -struct DefaultAlignmentNeeds -{ - template - static constexpr auto VALUE = true; -}; - -struct IgnoreFirstAlignmentNeeds -{ - template - static constexpr auto VALUE = I != 0; -}; - -template -constexpr auto alignment_offset(std::size_t position) noexcept -{ - return detail::align(position) - position; -} - template constexpr void construct_one_if_non_trivial([[maybe_unused]] Source&& source, [[maybe_unused]] const Target& target) { @@ -1860,6 +1896,12 @@ constexpr void construct_one_if_non_trivial([[maybe_unused]] Source&& source, [[ } } +struct ElementSize +{ + std::size_t size; + std::size_t stride; +}; + template class ElementTraits; @@ -1868,15 +1910,21 @@ class ElementTraits, Parameter...> { private: using ListTraits = detail::ParameterListTraits; + + public: + template + using ParameterTraitsAt = typename ListTraits::template ParameterTraitsAt; + + private: using FixedSizesArray = typename ListTraits::FixedSizesArray; using ContiguousPointer = typename detail::ContiguousVectorTraits::PointerType; using ContiguousReference = typename detail::ContiguousVectorTraits::ReferenceType; - using AlignmentNeeds = detail::ConditionalT; using FixedSizeGetter = detail::FixedSizeGetter; - static constexpr auto SKIP = std::numeric_limits::max(); - static constexpr auto MANUAL = SKIP - 1; + static constexpr std::size_t LARGEST_LEADING_ALIGNMENT_UNTIL_VARYING_SIZE = + ListTraits::LARGEST_LEADING_ALIGNMENT_UNTIL_VARYING_SIZE; + static constexpr std::size_t SKIP = std::numeric_limits::max(); + static constexpr std::size_t MANUAL = SKIP - 1; template