From 03e8c836be1d7799140b87eb642f8a9ae4f8dab6 Mon Sep 17 00:00:00 2001 From: Tristan Brindle Date: Thu, 3 Sep 2026 19:10:27 +0100 Subject: [PATCH 1/4] Make pointer trivially copyable By giving `slice` defaulted but private copy and assignment (rather than deleted as before) we can in turn default `pointer` copy and assignment operators. The result is that `slice` is still non-copyable and non-movable by external code (as we'd like) but now all specialisations of `pointer` are trivially copyable. --- include/tcb/pointer.hpp | 17 +++++------------ tests/pointer.test.cpp | 15 ++++++--------- 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/include/tcb/pointer.hpp b/include/tcb/pointer.hpp index 76e8043..42df119 100644 --- a/include/tcb/pointer.hpp +++ b/include/tcb/pointer.hpp @@ -468,6 +468,9 @@ struct TCB_PTR_GSL_POINTER(T) slice { constexpr explicit slice(T* addr, std::size_t sz) : addr_(addr), sz_(sz) { } + slice(slice const&) = default; + auto operator=(slice const&) -> slice& = default; + public: using value_type = T; using size_type = std::size_t; @@ -481,9 +484,6 @@ struct TCB_PTR_GSL_POINTER(T) slice { using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; - slice(slice const&) = delete; - void operator=(slice const&) = delete; - constexpr auto operator[](size_type idx) -> reference { if (idx >= sz_) { @@ -655,9 +655,7 @@ struct TCB_PTR_GSL_POINTER(T) pointer { return pointer(ptr, sz); } - constexpr pointer(pointer const& other) noexcept : slice_(other.slice_.addr_, other.slice_.sz_) - { - } + pointer(pointer const&) = default; // If we are const, allow copy-construction from non-const constexpr pointer(pointer[]> const& other) noexcept @@ -666,12 +664,7 @@ struct TCB_PTR_GSL_POINTER(T) pointer { { } - constexpr auto operator=(pointer const& other) noexcept -> pointer& - { - slice_.addr_ = other.slice_.addr_; - slice_.sz_ = other.slice_.sz_; - return *this; - } + auto operator=(pointer const&) -> pointer& = default; constexpr auto operator*() const& noexcept TCB_PTR_LIFETIME_BOUND->element_type& { diff --git a/tests/pointer.test.cpp b/tests/pointer.test.cpp index bb42387..c0bebc0 100755 --- a/tests/pointer.test.cpp +++ b/tests/pointer.test.cpp @@ -143,14 +143,11 @@ constexpr bool test_pointer_static_properties() static_assert(std::swappable

); // pointer special members are all trivial - // (except array pointers, annoyingly) - if constexpr (not std::is_unbounded_array_v) { - static_assert(std::is_trivially_copyable_v

); - static_assert(std::is_trivially_copy_constructible_v

); - static_assert(std::is_trivially_move_constructible_v

); - static_assert(std::is_trivially_copy_assignable_v

); - static_assert(std::is_trivially_move_assignable_v

); - } + static_assert(std::is_trivially_copyable_v

); + static_assert(std::is_trivially_copy_constructible_v

); + static_assert(std::is_trivially_move_constructible_v

); + static_assert(std::is_trivially_copy_assignable_v

); + static_assert(std::is_trivially_move_assignable_v

); static_assert(std::is_trivially_destructible_v

); // pointer special members are all noexcept @@ -1335,7 +1332,7 @@ constexpr bool test_std_optional_specialisation() static_assert(std::default_initializable); static_assert(std::copy_constructible); static_assert(std::move_constructible); - // static_assert(std::copyable); + static_assert(std::copyable); static_assert(std::movable); static_assert(std::destructible); } From c1300f7be4d5efd892130de39a653ef38481b60d Mon Sep 17 00:00:00 2001 From: Tristan Brindle Date: Thu, 3 Sep 2026 19:19:03 +0100 Subject: [PATCH 2/4] Take checked_iterator comparison args by reference `checked_iterator` is three pointers in size, so it's probably better to take it by reference rather than by value in function arguments (if indeed an actual function call is ever generated for these comparison operators...) --- include/tcb/pointer.hpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/include/tcb/pointer.hpp b/include/tcb/pointer.hpp index 42df119..f840652 100644 --- a/include/tcb/pointer.hpp +++ b/include/tcb/pointer.hpp @@ -413,13 +413,15 @@ struct TCB_PTR_GSL_POINTER(T) checked_iterator { return lhs -= rhs; } - friend constexpr auto operator-(checked_iterator lhs, checked_iterator rhs) -> difference_type + friend constexpr auto operator-(checked_iterator const& lhs, checked_iterator const& rhs) + -> difference_type { return lhs.pos_ - rhs.pos_; } - friend auto operator==(checked_iterator, checked_iterator) -> bool = default; - friend auto operator<=>(checked_iterator, checked_iterator) -> std::strong_ordering = default; + friend auto operator==(checked_iterator const&, checked_iterator const&) -> bool = default; + friend auto operator<=>(checked_iterator const&, checked_iterator const&) + -> std::strong_ordering = default; }; #ifndef TCB_PTR_USE_UNCHECKED_ITERATORS From 61b4665a028b2ace353a6f59ab7a0fe5f041d5a1 Mon Sep 17 00:00:00 2001 From: Tristan Brindle Date: Thu, 3 Sep 2026 19:23:19 +0100 Subject: [PATCH 3/4] Tweak pointer equality comparison We want to make triply sure that `operator==` returns the same thing as `operator<=>`, even though it always would do already in practise... --- include/tcb/pointer.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/tcb/pointer.hpp b/include/tcb/pointer.hpp index f840652..ad6cafa 100644 --- a/include/tcb/pointer.hpp +++ b/include/tcb/pointer.hpp @@ -168,7 +168,7 @@ struct TCB_PTR_GSL_POINTER(T) pointer { friend constexpr auto operator==(pointer lhs, pointer rhs) -> bool { - return lhs.addr_ == rhs.addr_; + return std::compare_three_way{}(lhs.addr_, rhs.addr_) == 0; } friend constexpr auto operator<=>(pointer lhs, pointer rhs) -> std::strong_ordering From 59c31ddb201f95b949b65524e99d5cbfdad3ea2c Mon Sep 17 00:00:00 2001 From: Tristan Brindle Date: Thu, 3 Sep 2026 19:24:02 +0100 Subject: [PATCH 4/4] Tiny correction to a comment --- examples/03_conversions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/03_conversions.cpp b/examples/03_conversions.cpp index 766b9f3..4a849b4 100644 --- a/examples/03_conversions.cpp +++ b/examples/03_conversions.cpp @@ -34,7 +34,7 @@ void pointer_conversions() tcb::pointer p3 = tcb::const_pointer_cast(p2); // Similarly, we can implicitly convert from a pointer-to-derived - // to a pointer-to-base, as we'd expect: + // to an unambiguous pointer-to-base, as we'd expect: Derived d{}; tcb::pointer p_base = tcb::ptr_to_mut(d);