mirror of
https://github.com/gcc-mirror/gcc.git
synced 2026-05-06 14:59:39 +02:00
libstdc++: Avoid redundant assertions in std::span constructors
Any std::span<T, N> constructor with a runtime length has a precondition that the length is equal to N (except when N == std::dynamic_extent). Currently every constructor with a runtime length does: if constexpr (extent != dynamic_extent) __glibcxx_assert(n == extent); We can move those assertions into the __detail::__extent_storage<N> constructor so they are only done in one place. To avoid checking the assertions when we have a constant length we can add a second constructor which is consteval and takes a integral_constant<size_t, N> argument. The std::span constructors can pass a size_t for runtime lengths and a std::integral_constant<size_t, N> for constant lengths that don't need to be checked. The __detail::__extent_storage<dynamic_extent> specialization only needs one constructor, as a std::integral_constant<size_t, N> argument can implicitly convert to size_t. For the member functions that return a subspan with a constant extent we return std::span<T,C>(ptr, C) which is redundant in two ways. Repeating the constant length C when it's already a template argument is redundant, and using the std::span(T*, size_t) constructor implies a runtime length which will do a redundant assertion check. Even though that assertion won't fail and should be optimized away, it's still unnecessary code that doesn't need to be instantiated and then optimized away again. We can avoid that by adding a new private constructor that only takes a pointer (wrapped in a custom tag struct to avoid accidentally using that constructor) and automatically sets _M_extent to the correct value. libstdc++-v3/ChangeLog: * include/std/span (__detail::__extent_storage): Check precondition in constructor. Add consteval constructor for valid lengths and deleted constructor for invalid constant lengths. Make member functions always_inline. (__detail::__span_ptr): New class template. (span): Adjust constructors to use a std::integral_constant value for constant lengths. Declare all specializations of std::span as friends. (span::first<C>, span::last<C>, span::subspan<O,C>): Use new private constructor. (span(__span_ptr<T>)): New private constructor for constant lengths.
This commit is contained in:
committed by
Jonathan Wakely
parent
fa6549c1f0
commit
cbef2c1dbd
@@ -73,10 +73,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
class __extent_storage
|
||||
{
|
||||
public:
|
||||
// Used for runtime sizes that must satisfy the precondition.
|
||||
constexpr
|
||||
__extent_storage(size_t) noexcept
|
||||
__extent_storage([[maybe_unused]] size_t __n) noexcept
|
||||
{ __glibcxx_assert(__n == _Extent); }
|
||||
|
||||
// Used for constant sizes that are already known to be correct.
|
||||
consteval
|
||||
__extent_storage(integral_constant<size_t, _Extent>) noexcept
|
||||
{ }
|
||||
|
||||
// "I've made a huge mistake" - George Oscar Bluth II
|
||||
template<size_t _Gob>
|
||||
__extent_storage(integral_constant<size_t, _Gob>) = delete;
|
||||
|
||||
[[__gnu__::__always_inline__]]
|
||||
static constexpr size_t
|
||||
_M_extent() noexcept
|
||||
{ return _Extent; }
|
||||
@@ -86,11 +97,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
class __extent_storage<dynamic_extent>
|
||||
{
|
||||
public:
|
||||
[[__gnu__::__always_inline__]]
|
||||
constexpr
|
||||
__extent_storage(size_t __extent) noexcept
|
||||
: _M_extent_value(__extent)
|
||||
{ }
|
||||
|
||||
[[__gnu__::__always_inline__]]
|
||||
constexpr size_t
|
||||
_M_extent() const noexcept
|
||||
{ return this->_M_extent_value; }
|
||||
@@ -98,6 +111,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
private:
|
||||
size_t _M_extent_value;
|
||||
};
|
||||
|
||||
template<typename _Type> struct __span_ptr { _Type* const _M_ptr; };
|
||||
|
||||
} // namespace __detail
|
||||
|
||||
template<typename _Type, size_t _Extent = dynamic_extent>
|
||||
@@ -128,6 +144,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
// Nested type so that _Type is not an associated class of iterator.
|
||||
struct __iter_tag;
|
||||
|
||||
template<size_t _Nm>
|
||||
static inline constexpr integral_constant<size_t, _Nm> __v{};
|
||||
|
||||
public:
|
||||
// member types
|
||||
using element_type = _Type;
|
||||
@@ -153,7 +172,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
constexpr
|
||||
span() noexcept
|
||||
requires (_Extent == dynamic_extent || _Extent == 0)
|
||||
: _M_ptr(nullptr), _M_extent(0)
|
||||
: _M_ptr(nullptr), _M_extent(__v<0>)
|
||||
{ }
|
||||
|
||||
template<contiguous_iterator _It>
|
||||
@@ -162,13 +181,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
span(_It __first, size_type __count)
|
||||
noexcept
|
||||
: _M_ptr(std::to_address(__first)), _M_extent(__count)
|
||||
{
|
||||
if constexpr (_Extent != dynamic_extent)
|
||||
{
|
||||
__glibcxx_assert(__count == _Extent);
|
||||
}
|
||||
__glibcxx_requires_valid_range(__first, __first + __count);
|
||||
}
|
||||
{ __glibcxx_requires_valid_range(__first, __first + __count); }
|
||||
|
||||
template<contiguous_iterator _It, sized_sentinel_for<_It> _End>
|
||||
requires __is_compatible_ref<iter_reference_t<_It>>::value
|
||||
@@ -178,33 +191,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
noexcept(noexcept(__last - __first))
|
||||
: _M_ptr(std::to_address(__first)),
|
||||
_M_extent(static_cast<size_type>(__last - __first))
|
||||
{
|
||||
if constexpr (_Extent != dynamic_extent)
|
||||
{
|
||||
__glibcxx_assert((__last - __first) == _Extent);
|
||||
}
|
||||
__glibcxx_requires_valid_range(__first, __last);
|
||||
}
|
||||
{ __glibcxx_requires_valid_range(__first, __last); }
|
||||
|
||||
template<size_t _ArrayExtent>
|
||||
requires (_Extent == dynamic_extent || _ArrayExtent == _Extent)
|
||||
constexpr
|
||||
span(type_identity_t<element_type> (&__arr)[_ArrayExtent]) noexcept
|
||||
: _M_ptr(__arr), _M_extent(_ArrayExtent)
|
||||
: _M_ptr(__arr), _M_extent(__v<_ArrayExtent>)
|
||||
{ }
|
||||
|
||||
template<typename _Tp, size_t _ArrayExtent>
|
||||
requires __is_compatible_array<_Tp, _ArrayExtent>::value
|
||||
constexpr
|
||||
span(array<_Tp, _ArrayExtent>& __arr) noexcept
|
||||
: _M_ptr(__arr.data()), _M_extent(_ArrayExtent)
|
||||
: _M_ptr(__arr.data()), _M_extent(__v<_ArrayExtent>)
|
||||
{ }
|
||||
|
||||
template<typename _Tp, size_t _ArrayExtent>
|
||||
requires __is_compatible_array<const _Tp, _ArrayExtent>::value
|
||||
constexpr
|
||||
span(const array<_Tp, _ArrayExtent>& __arr) noexcept
|
||||
: _M_ptr(__arr.data()), _M_extent(_ArrayExtent)
|
||||
: _M_ptr(__arr.data()), _M_extent(__v<_ArrayExtent>)
|
||||
{ }
|
||||
|
||||
template<typename _Range>
|
||||
@@ -219,12 +226,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
noexcept(noexcept(ranges::data(__range))
|
||||
&& noexcept(ranges::size(__range)))
|
||||
: _M_ptr(ranges::data(__range)), _M_extent(ranges::size(__range))
|
||||
{
|
||||
if constexpr (extent != dynamic_extent)
|
||||
{
|
||||
__glibcxx_assert(ranges::size(__range) == extent);
|
||||
}
|
||||
}
|
||||
{ }
|
||||
|
||||
constexpr
|
||||
span(const span&) noexcept = default;
|
||||
@@ -237,12 +239,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
explicit(extent != dynamic_extent && _OExtent == dynamic_extent)
|
||||
span(const span<_OType, _OExtent>& __s) noexcept
|
||||
: _M_ptr(__s.data()), _M_extent(__s.size())
|
||||
{
|
||||
if constexpr (extent != dynamic_extent)
|
||||
{
|
||||
__glibcxx_assert(__s.size() == extent);
|
||||
}
|
||||
}
|
||||
{ }
|
||||
|
||||
~span() noexcept = default;
|
||||
|
||||
@@ -365,7 +362,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
else
|
||||
static_assert(_Count <= extent);
|
||||
using _Sp = span<element_type, _Count>;
|
||||
return _Sp{ this->data(), _Count };
|
||||
return _Sp{ _SizedPtr{this->data()} };
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
@@ -386,7 +383,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
else
|
||||
static_assert(_Count <= extent);
|
||||
using _Sp = span<element_type, _Count>;
|
||||
return _Sp{ this->data() + (this->size() - _Count), _Count };
|
||||
return _Sp{ _SizedPtr{this->data() + (this->size() - _Count)} };
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
@@ -426,7 +423,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
static_assert(_Count <= extent);
|
||||
static_assert(_Count <= (extent - _Offset));
|
||||
}
|
||||
return _Sp{ this->data() + _Offset, _Count };
|
||||
return _Sp{ _SizedPtr{this->data() + _Offset} };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -447,6 +444,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename, size_t> friend class span;
|
||||
|
||||
// Tag type for pointer that has known extent.
|
||||
using _SizedPtr = __detail::__span_ptr<_Type>;
|
||||
|
||||
// Private constructor with an implied extent.
|
||||
[[__gnu__::__always_inline__]]
|
||||
constexpr explicit
|
||||
span(_SizedPtr __ptr) noexcept
|
||||
requires (extent != dynamic_extent)
|
||||
: _M_ptr(__ptr._M_ptr), _M_extent(__v<extent>)
|
||||
{ }
|
||||
|
||||
pointer _M_ptr;
|
||||
[[no_unique_address]] __detail::__extent_storage<extent> _M_extent;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user