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
This commit is contained in:
carson radtke 2024-11-09 14:04:45 -06:00
parent 87f9d76886
commit 898db79600
No known key found for this signature in database

View File

@ -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 Type>() 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)