From 42cfc549e55fc9fece66e7c4485729167a082a53 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 | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index d2ef9f7d..dcae9763 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -136,11 +136,14 @@ namespace details using _Unchecked_type = pointer; using _Prevent_inheriting_unwrap = span_iterator; #endif // _MSC_VER - constexpr span_iterator() = default; + constexpr span_iterator() = delete; 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)