From f8ec3091183e44b53a36b8f3857f234767f8ed8a Mon Sep 17 00:00:00 2001 From: Carson Radtke Date: Tue, 12 Nov 2024 15:41:21 -0600 Subject: [PATCH] improve performance of span_iterator w/ clang (#1166) * 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 | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index d2ef9f7..a01b687 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -140,7 +140,9 @@ namespace details constexpr span_iterator(pointer begin, pointer end, pointer current) : begin_(begin), end_(end), current_(current) - {} + { + Expects(begin_ <= current_ && current <= end_); + } constexpr operator span_iterator() const noexcept { @@ -149,21 +151,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 +179,7 @@ namespace details constexpr span_iterator& operator--() noexcept { - Expects(begin_ && end_); - Expects(begin_ < current_); + Expects(begin_ != current_); --current_; return *this; }