Compare commits

...

3 Commits

Author SHA1 Message Date
Carson Radtke
fef7bdeefd
Merge d988e0e19b into f8ec309118 2024-11-14 08:42:47 +01:00
Carson Radtke
f8ec309118
improve performance of span_iterator w/ clang (#1166)
Some checks failed
Compiler Integration Tests / xcode (Release, 23, 15.4) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Debug, 14, , Visual Studio 16 2019, windows-2019) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Debug, 14, , Visual Studio 17 2022, windows-2022) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Debug, 14, -T ClangCL, Visual Studio 16 2019, windows-2019) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Debug, 14, -T ClangCL, Visual Studio 17 2022, windows-2022) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Debug, 17, , Visual Studio 16 2019, windows-2019) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Debug, 17, , Visual Studio 17 2022, windows-2022) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Debug, 17, -T ClangCL, Visual Studio 16 2019, windows-2019) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Debug, 17, -T ClangCL, Visual Studio 17 2022, windows-2022) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Debug, 20, , Visual Studio 16 2019, windows-2019) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Debug, 20, , Visual Studio 17 2022, windows-2022) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Debug, 20, -T ClangCL, Visual Studio 16 2019, windows-2019) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Debug, 20, -T ClangCL, Visual Studio 17 2022, windows-2022) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Debug, 23, , Visual Studio 17 2022, windows-2022) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Debug, 23, -T ClangCL, Visual Studio 17 2022, windows-2022) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Release, 14, , Visual Studio 16 2019, windows-2019) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Release, 14, , Visual Studio 17 2022, windows-2022) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Release, 14, -T ClangCL, Visual Studio 16 2019, windows-2019) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Release, 14, -T ClangCL, Visual Studio 17 2022, windows-2022) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Release, 17, , Visual Studio 16 2019, windows-2019) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Release, 17, , Visual Studio 17 2022, windows-2022) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Release, 17, -T ClangCL, Visual Studio 16 2019, windows-2019) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Release, 17, -T ClangCL, Visual Studio 17 2022, windows-2022) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Release, 20, , Visual Studio 16 2019, windows-2019) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Release, 20, , Visual Studio 17 2022, windows-2022) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Release, 20, -T ClangCL, Visual Studio 16 2019, windows-2019) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Release, 20, -T ClangCL, Visual Studio 17 2022, windows-2022) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Release, 23, , Visual Studio 17 2022, windows-2022) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Release, 23, -T ClangCL, Visual Studio 17 2022, windows-2022) (push) Has been cancelled
CI_iOS / iOS (push) Has been cancelled
* improve performance of span_iterator w/ clang

Issue: #1165

Before this PR, the range-for loop was ~3300x slower. After this PR, it
is ~1.005x slower

The clang optimizer is very good at optimizing `current != end`, so
we changed to this idiom. This moves the Expects assertion into the
constructor instead of on the hot-path which is called whenever either
operator++ or operator* is called.

Note: The codegen for the assertion is still a missed optimization,
but less worrisome as it only happens once per iterator.

Note: benchmarks on M1 Macbook Pro w/ Apple Clang 16.0.0
2024-11-12 15:41:21 -06:00
Carson Radtke
d988e0e19b introduce gsl::swap for swapping gsl::not_null
fixes: https://github.com/microsoft/GSL/issues/1129

* create gsl::swap<T>(T&, T&) which wraps std::swap
* specialize gsl::swap<T>(gsl::not_null<T>&, gsl::not_null<T>&)
* add tests
2024-10-17 06:56:28 -05:00
6 changed files with 60 additions and 9 deletions

View File

@ -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. 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<T>& other) { std::swap(ptr_, other.ptr_); }
```
Swaps contents with another `gsl::not_null` object.
#### Non-member functions #### Non-member functions
```cpp ```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. Creates a `gsl::not_null` object, deducing the target type from the type of the argument.
```cpp
template <typename T, typename = std::enable_if_t<std::is_move_assignable<T>::value && std::is_move_constructible<T>::value>>
void swap(not_null<T>& a, not_null<T>& b);
```
Swaps the contents of two `gsl::not_null` objects.
```cpp ```cpp
template <class T, class U> template <class T, class U>
auto operator==(const not_null<T>& lhs, auto operator==(const not_null<T>& lhs,
@ -858,3 +871,10 @@ constexpr auto at(std::span<T, extent> 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. 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). 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 <class T, std::enable_if_t<std::is_move_assignable<T>::value && std::is_move_constructible<T>::value>>
void swap(T& a, T& b);
```
Swaps the contents of two objects. Exists only to specialize `gsl::swap<T>(gsl::not_null<T>&, gsl::not_null<T>&)`.

View File

@ -139,10 +139,18 @@ public:
not_null& operator-=(std::ptrdiff_t) = delete; not_null& operator-=(std::ptrdiff_t) = delete;
void operator[](std::ptrdiff_t) const = delete; void operator[](std::ptrdiff_t) const = delete;
void swap(not_null<T>& other) { std::swap(ptr_, other.ptr_); }
private: private:
T ptr_; T ptr_;
}; };
template <typename T, typename = std::enable_if_t<std::is_move_assignable<T>::value && std::is_move_constructible<T>::value>>
void swap(not_null<T>& a, not_null<T>& b)
{
a.swap(b);
}
template <class T> template <class T>
auto make_not_null(T&& t) noexcept auto make_not_null(T&& t) noexcept
{ {

View File

@ -140,7 +140,9 @@ namespace details
constexpr span_iterator(pointer begin, pointer end, pointer current) constexpr span_iterator(pointer begin, pointer end, pointer current)
: begin_(begin), end_(end), current_(current) : begin_(begin), end_(end), current_(current)
{} {
Expects(begin_ <= current_ && current <= end_);
}
constexpr operator span_iterator<const Type>() const noexcept constexpr operator span_iterator<const Type>() const noexcept
{ {
@ -149,21 +151,18 @@ namespace details
constexpr reference operator*() const noexcept constexpr reference operator*() const noexcept
{ {
Expects(begin_ && end_); Expects(current_ != end_);
Expects(begin_ <= current_ && current_ < end_);
return *current_; return *current_;
} }
constexpr pointer operator->() const noexcept constexpr pointer operator->() const noexcept
{ {
Expects(begin_ && end_); Expects(current_ != end_);
Expects(begin_ <= current_ && current_ < end_);
return current_; return current_;
} }
constexpr span_iterator& operator++() noexcept constexpr span_iterator& operator++() noexcept
{ {
Expects(begin_ && current_ && end_); Expects(current_ != end_);
Expects(current_ < end_);
// clang-format off // clang-format off
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
// clang-format on // clang-format on
@ -180,8 +179,7 @@ namespace details
constexpr span_iterator& operator--() noexcept constexpr span_iterator& operator--() noexcept
{ {
Expects(begin_ && end_); Expects(begin_ != current_);
Expects(begin_ < current_);
--current_; --current_;
return *this; return *this;
} }

View File

@ -146,6 +146,9 @@ GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
return *(cont.begin() + i); return *(cont.begin() + i);
} }
template <class T, std::enable_if_t<std::is_move_assignable<T>::value && std::is_move_constructible<T>::value>>
void swap(T& a, T& b) { std::swap(a, b); }
#if defined(__cpp_lib_span) && __cpp_lib_span >= 202002L #if defined(__cpp_lib_span) && __cpp_lib_span >= 202002L
template <class T, std::size_t extent = std::dynamic_extent> template <class T, std::size_t extent = std::dynamic_extent>
constexpr auto at(std::span<T, extent> sp, const index i) -> decltype(sp[sp.size()]) constexpr auto at(std::span<T, extent> sp, const index i) -> decltype(sp[sp.size()])

View File

@ -205,6 +205,7 @@ add_executable(gsl_tests
byte_tests.cpp byte_tests.cpp
notnull_tests.cpp notnull_tests.cpp
owner_tests.cpp owner_tests.cpp
pointers_tests.cpp
span_compatibility_tests.cpp span_compatibility_tests.cpp
span_ext_tests.cpp span_ext_tests.cpp
span_tests.cpp span_tests.cpp

21
tests/pointers_tests.cpp Normal file
View File

@ -0,0 +1,21 @@
#include <gtest/gtest.h>
#include <gsl/pointers>
#include <memory>
TEST(pointers_test, swap)
{
// taken from gh-1129:
gsl::not_null<std::unique_ptr<int>> a(std::make_unique<int>(0));
gsl::not_null<std::unique_ptr<int>> b(std::make_unique<int>(1));
EXPECT_TRUE(*a == 0);
EXPECT_TRUE(*b == 1);
gsl::swap(a, b);
EXPECT_TRUE(*a == 1);
EXPECT_TRUE(*b == 0);
}