mirror of
https://github.com/microsoft/GSL.git
synced 2024-11-03 17:56:43 -05:00
Dev/annagrin/opt neg branch (#721)
* Added c++17 test configurations for clang5.0 and clang6.0 * Added optimization that removes a branch from span::operator[] * minor beauty fix * added a better message for the optimization, fixed signed/unsigned warning * better check fir wrap-around possibility
This commit is contained in:
parent
6241b3faa6
commit
5016ce4a4d
@ -46,8 +46,8 @@
|
|||||||
#define constexpr /*constexpr*/
|
#define constexpr /*constexpr*/
|
||||||
#define GSL_USE_STATIC_CONSTEXPR_WORKAROUND
|
#define GSL_USE_STATIC_CONSTEXPR_WORKAROUND
|
||||||
|
|
||||||
#endif // _MSC_VER < 1910
|
#endif // _MSC_VER < 1910
|
||||||
#endif // _MSC_VER
|
#endif // _MSC_VER
|
||||||
|
|
||||||
// See if we have enough C++17 power to use a static constexpr data member
|
// See if we have enough C++17 power to use a static constexpr data member
|
||||||
// without needing an out-of-line definition
|
// without needing an out-of-line definition
|
||||||
@ -142,15 +142,13 @@ namespace details
|
|||||||
|
|
||||||
constexpr span_iterator(const Span* span, typename Span::index_type idx) noexcept
|
constexpr span_iterator(const Span* span, typename Span::index_type idx) noexcept
|
||||||
: span_(span), index_(idx)
|
: span_(span), index_(idx)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
friend span_iterator<Span, true>;
|
friend span_iterator<Span, true>;
|
||||||
template <bool B, std::enable_if_t<!B && IsConst>* = nullptr>
|
template <bool B, std::enable_if_t<!B && IsConst>* = nullptr>
|
||||||
constexpr span_iterator(const span_iterator<Span, B>& other) noexcept
|
constexpr span_iterator(const span_iterator<Span, B>& other) noexcept
|
||||||
: span_iterator(other.span_, other.index_)
|
: span_iterator(other.span_, other.index_)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
||||||
constexpr reference operator*() const
|
constexpr reference operator*() const
|
||||||
@ -332,8 +330,7 @@ namespace details
|
|||||||
|
|
||||||
template <index_type Other>
|
template <index_type Other>
|
||||||
explicit constexpr extent_type(extent_type<Other> ext) : size_(ext.size())
|
explicit constexpr extent_type(extent_type<Other> ext) : size_(ext.size())
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
explicit constexpr extent_type(index_type size) : size_(size) { Expects(size >= 0); }
|
explicit constexpr extent_type(index_type size) : size_(size) { Expects(size >= 0); }
|
||||||
|
|
||||||
@ -383,35 +380,30 @@ public:
|
|||||||
// since "std::enable_if_t<Extent <= 0>" is ill-formed when Extent is greater than 0.
|
// since "std::enable_if_t<Extent <= 0>" is ill-formed when Extent is greater than 0.
|
||||||
class = std::enable_if_t<(Dependent || Extent <= 0)>>
|
class = std::enable_if_t<(Dependent || Extent <= 0)>>
|
||||||
constexpr span() noexcept : storage_(nullptr, details::extent_type<0>())
|
constexpr span() noexcept : storage_(nullptr, details::extent_type<0>())
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
constexpr span(pointer ptr, index_type count) : storage_(ptr, count) {}
|
constexpr span(pointer ptr, index_type count) : storage_(ptr, count) {}
|
||||||
|
|
||||||
constexpr span(pointer firstElem, pointer lastElem)
|
constexpr span(pointer firstElem, pointer lastElem)
|
||||||
: storage_(firstElem, std::distance(firstElem, lastElem))
|
: storage_(firstElem, std::distance(firstElem, lastElem))
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
template <std::size_t N>
|
template <std::size_t N>
|
||||||
constexpr span(element_type (&arr)[N]) noexcept
|
constexpr span(element_type (&arr)[N]) noexcept
|
||||||
: storage_(KnownNotNull{&arr[0]}, details::extent_type<N>())
|
: storage_(KnownNotNull{&arr[0]}, details::extent_type<N>())
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
template <std::size_t N, class ArrayElementType = std::remove_const_t<element_type>>
|
template <std::size_t N, class ArrayElementType = std::remove_const_t<element_type>>
|
||||||
// GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute // TODO: parser bug
|
// GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute // TODO: parser bug
|
||||||
constexpr span(std::array<ArrayElementType, N>& arr) noexcept
|
constexpr span(std::array<ArrayElementType, N>& arr) noexcept
|
||||||
: storage_(&arr[0], details::extent_type<N>())
|
: storage_(&arr[0], details::extent_type<N>())
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
template <std::size_t N>
|
template <std::size_t N>
|
||||||
// GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute // TODO: parser bug
|
// GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute // TODO: parser bug
|
||||||
constexpr span(const std::array<std::remove_const_t<element_type>, N>& arr) noexcept
|
constexpr span(const std::array<std::remove_const_t<element_type>, N>& arr) noexcept
|
||||||
: storage_(&arr[0], details::extent_type<N>())
|
: storage_(&arr[0], details::extent_type<N>())
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
// NB: the SFINAE here uses .data() as a incomplete/imperfect proxy for the requirement
|
// NB: the SFINAE here uses .data() as a incomplete/imperfect proxy for the requirement
|
||||||
// on Container to be a contiguous sequence container.
|
// on Container to be a contiguous sequence container.
|
||||||
@ -422,8 +414,7 @@ public:
|
|||||||
std::is_convertible<typename Container::pointer,
|
std::is_convertible<typename Container::pointer,
|
||||||
decltype(std::declval<Container>().data())>::value>>
|
decltype(std::declval<Container>().data())>::value>>
|
||||||
constexpr span(Container& cont) : span(cont.data(), narrow<index_type>(cont.size()))
|
constexpr span(Container& cont) : span(cont.data(), narrow<index_type>(cont.size()))
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
template <class Container,
|
template <class Container,
|
||||||
class = std::enable_if_t<
|
class = std::enable_if_t<
|
||||||
@ -432,8 +423,7 @@ public:
|
|||||||
std::is_convertible<typename Container::pointer,
|
std::is_convertible<typename Container::pointer,
|
||||||
decltype(std::declval<Container>().data())>::value>>
|
decltype(std::declval<Container>().data())>::value>>
|
||||||
constexpr span(const Container& cont) : span(cont.data(), narrow<index_type>(cont.size()))
|
constexpr span(const Container& cont) : span(cont.data(), narrow<index_type>(cont.size()))
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
constexpr span(const span& other) noexcept = default;
|
constexpr span(const span& other) noexcept = default;
|
||||||
|
|
||||||
@ -444,8 +434,7 @@ public:
|
|||||||
details::is_allowed_element_type_conversion<OtherElementType, element_type>::value>>
|
details::is_allowed_element_type_conversion<OtherElementType, element_type>::value>>
|
||||||
constexpr span(const span<OtherElementType, OtherExtent>& other)
|
constexpr span(const span<OtherElementType, OtherExtent>& other)
|
||||||
: storage_(other.data(), details::extent_type<OtherExtent>(other.size()))
|
: storage_(other.data(), details::extent_type<OtherExtent>(other.size()))
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
~span() noexcept = default;
|
~span() noexcept = default;
|
||||||
constexpr span& operator=(const span& other) noexcept = default;
|
constexpr span& operator=(const span& other) noexcept = default;
|
||||||
@ -506,7 +495,7 @@ public:
|
|||||||
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
||||||
constexpr reference operator[](index_type idx) const
|
constexpr reference operator[](index_type idx) const
|
||||||
{
|
{
|
||||||
Expects(idx >= 0 && idx < storage_.size());
|
Expects(CheckRange(idx, storage_.size()));
|
||||||
return data()[idx];
|
return data()[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -536,7 +525,7 @@ public:
|
|||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
// Tell MSVC how to unwrap spans in range-based-for
|
// Tell MSVC how to unwrap spans in range-based-for
|
||||||
constexpr pointer _Unchecked_begin() const noexcept { return data(); }
|
constexpr pointer _Unchecked_begin() const noexcept { return data(); }
|
||||||
constexpr pointer _Unchecked_end() const noexcept
|
constexpr pointer _Unchecked_end() const noexcept
|
||||||
{
|
{
|
||||||
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
|
||||||
return data() + size();
|
return data() + size();
|
||||||
@ -544,6 +533,29 @@ public:
|
|||||||
#endif // _MSC_VER
|
#endif // _MSC_VER
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static bool CheckRange(index_type idx, index_type size)
|
||||||
|
{
|
||||||
|
// Optimization:
|
||||||
|
//
|
||||||
|
// idx >= 0 && idx < size
|
||||||
|
// =>
|
||||||
|
// static_cast<size_t>(idx) < static_cast<size_t>(size)
|
||||||
|
//
|
||||||
|
// because size >=0 by span construction, and negative idx will
|
||||||
|
// wrap around to a value always greater than size when casted.
|
||||||
|
|
||||||
|
// check if we have enough space to wrap around
|
||||||
|
if (narrow_cast<unsigned long long>(std::numeric_limits<index_type>::max()) <
|
||||||
|
narrow_cast<unsigned long long>(std::numeric_limits<size_t>::max()))
|
||||||
|
{
|
||||||
|
return narrow_cast<size_t>(idx) < narrow_cast<size_t>(size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return idx >= 0 && idx < size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Needed to remove unnecessary null check in subspans
|
// Needed to remove unnecessary null check in subspans
|
||||||
struct KnownNotNull
|
struct KnownNotNull
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user