From d988e0e19ba5fa75e4904e716121dd7215f38a4f Mon Sep 17 00:00:00 2001 From: Carson Radtke Date: Thu, 17 Oct 2024 06:56:28 -0500 Subject: [PATCH] introduce gsl::swap for swapping gsl::not_null fixes: https://github.com/microsoft/GSL/issues/1129 * create gsl::swap(T&, T&) which wraps std::swap * specialize gsl::swap(gsl::not_null&, gsl::not_null&) * add tests --- docs/headers.md | 20 ++++++++++++++++++++ include/gsl/pointers | 8 ++++++++ include/gsl/util | 3 +++ tests/CMakeLists.txt | 1 + tests/pointers_tests.cpp | 21 +++++++++++++++++++++ 5 files changed, 53 insertions(+) create mode 100644 tests/pointers_tests.cpp diff --git a/docs/headers.md b/docs/headers.md index 11dd0cd..5f4eef1 100644 --- a/docs/headers.md +++ b/docs/headers.md @@ -294,6 +294,12 @@ void operator[](std::ptrdiff_t) const = delete; Array index operator is explicitly deleted. Pointers point to single objects ([I.13: Do not pass an array as a single pointer](http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Ri-array)), so don't allow treating them as an array. +```cpp +void swap(not_null& other) { std::swap(ptr_, other.ptr_); } +``` + +Swaps contents with another `gsl::not_null` object. + #### Non-member functions ```cpp @@ -303,6 +309,13 @@ auto make_not_null(T&& t) noexcept; Creates a `gsl::not_null` object, deducing the target type from the type of the argument. +```cpp +template ::value && std::is_move_constructible::value>> +void swap(not_null& a, not_null& b); +``` + +Swaps the contents of two `gsl::not_null` objects. + ```cpp template auto operator==(const not_null& lhs, @@ -858,3 +871,10 @@ constexpr auto at(std::span sp, const index i) -> decltype(sp[sp.size This overload returns a reference to the `i`s element of the `std::span` `sp`. It [`Expects`](#user-content-H-assert-expects) that the provided index is within the bounds of the array. For [`gsl::at`](#user-content-H-span_ext-at) for [`gsl::span`](#user-content-H-span-span) see header [`span_ext`](#user-content-H-span_ext). + +```cpp +template ::value && std::is_move_constructible::value>> +void swap(T& a, T& b); +``` + +Swaps the contents of two objects. Exists only to specialize `gsl::swap(gsl::not_null&, gsl::not_null&)`. diff --git a/include/gsl/pointers b/include/gsl/pointers index 63e193e..7ed0789 100644 --- a/include/gsl/pointers +++ b/include/gsl/pointers @@ -139,10 +139,18 @@ public: not_null& operator-=(std::ptrdiff_t) = delete; void operator[](std::ptrdiff_t) const = delete; + void swap(not_null& other) { std::swap(ptr_, other.ptr_); } + private: T ptr_; }; +template ::value && std::is_move_constructible::value>> +void swap(not_null& a, not_null& b) +{ + a.swap(b); +} + template auto make_not_null(T&& t) noexcept { diff --git a/include/gsl/util b/include/gsl/util index 26b2f5f..04c3c34 100644 --- a/include/gsl/util +++ b/include/gsl/util @@ -146,6 +146,9 @@ GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute return *(cont.begin() + i); } +template ::value && std::is_move_constructible::value>> +void swap(T& a, T& b) { std::swap(a, b); } + #if defined(__cpp_lib_span) && __cpp_lib_span >= 202002L template constexpr auto at(std::span sp, const index i) -> decltype(sp[sp.size()]) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9de2519..065a317 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -205,6 +205,7 @@ add_executable(gsl_tests byte_tests.cpp notnull_tests.cpp owner_tests.cpp + pointers_tests.cpp span_compatibility_tests.cpp span_ext_tests.cpp span_tests.cpp diff --git a/tests/pointers_tests.cpp b/tests/pointers_tests.cpp new file mode 100644 index 0000000..fc9fb45 --- /dev/null +++ b/tests/pointers_tests.cpp @@ -0,0 +1,21 @@ +#include + +#include + +#include + +TEST(pointers_test, swap) +{ + // taken from gh-1129: + gsl::not_null> a(std::make_unique(0)); + gsl::not_null> b(std::make_unique(1)); + + EXPECT_TRUE(*a == 0); + EXPECT_TRUE(*b == 1); + + gsl::swap(a, b); + + EXPECT_TRUE(*a == 1); + EXPECT_TRUE(*b == 0); +} +