From 898db796002971e6fd0a31332c0b44e53cb0b35d Mon Sep 17 00:00:00 2001 From: carson radtke Date: Sat, 9 Nov 2024 14:04:45 -0600 Subject: [PATCH] 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 --- include/gsl/span | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index d2ef9f7..57c04d6 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -140,7 +140,10 @@ namespace details constexpr span_iterator(pointer begin, pointer end, pointer current) : begin_(begin), end_(end), current_(current) - {} + { + Expects(begin && current && end); + Expects(begin <= current && current <= end); + } constexpr operator span_iterator() const noexcept { @@ -149,21 +152,18 @@ namespace details constexpr reference operator*() const noexcept { - Expects(begin_ && end_); - Expects(begin_ <= current_ && current_ < end_); + Expects(current_ != end_); return *current_; } constexpr pointer operator->() const noexcept { - Expects(begin_ && end_); - Expects(begin_ <= current_ && current_ < end_); + Expects(current_ != end_); return current_; } constexpr span_iterator& operator++() noexcept { - Expects(begin_ && current_ && end_); - Expects(current_ < end_); + Expects(current_ != end_); // clang-format off GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute // clang-format on @@ -180,8 +180,7 @@ namespace details constexpr span_iterator& operator--() noexcept { - Expects(begin_ && end_); - Expects(begin_ < current_); + Expects(begin != current_); --current_; return *this; } @@ -195,7 +194,6 @@ namespace details constexpr span_iterator& operator+=(const difference_type n) noexcept { - if (n != 0) Expects(begin_ && current_ && end_); if (n > 0) Expects(end_ - current_ >= n); if (n < 0) Expects(current_ - begin_ >= -n); // clang-format off @@ -220,7 +218,6 @@ namespace details constexpr span_iterator& operator-=(const difference_type n) noexcept { - if (n != 0) Expects(begin_ && current_ && end_); if (n > 0) Expects(current_ - begin_ >= n); if (n < 0) Expects(end_ - current_ >= -n); GSL_SUPPRESS(bounds .1)