09471c3753
The recent changes to use gsl::span everywhere added a few bounds checks along codepaths where we were already checking bounds. Some of them may be non-obvious to the optimizer, so we can now use til::at to help them along. To accomplish this, I've added a new overload of til::at that takes a span and directly accesses its backing buffer.
57 lines
2.2 KiB
C++
57 lines
2.2 KiB
C++
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT license.
|
|
|
|
#pragma once
|
|
|
|
namespace til
|
|
{
|
|
namespace details
|
|
{
|
|
// This was lifted from gsl::details::is_span.
|
|
template<class T>
|
|
struct is_span_oracle : std::false_type
|
|
{
|
|
};
|
|
|
|
#ifdef GSL_SPAN_H
|
|
template<class ElementType, std::size_t Extent>
|
|
struct is_span_oracle<gsl::span<ElementType, Extent>> : std::true_type
|
|
{
|
|
};
|
|
#endif
|
|
|
|
template<class T>
|
|
struct is_span : public is_span_oracle<std::remove_cv_t<T>>
|
|
{
|
|
};
|
|
}
|
|
|
|
// The at function declares that you've already sufficiently checked that your array access
|
|
// is in range before retrieving an item inside it at an offset.
|
|
// This is to save double/triple/quadruple testing in circumstances where you are already
|
|
// pivoting on the length of a set and now want to pull elements out of it by offset
|
|
// without checking again.
|
|
// gsl::at will do the check again. As will .at(). And using [] will have a warning in audit.
|
|
// This template is explicitly disabled if T is of type gsl::span, as it would interfere with
|
|
// the overload below.
|
|
template<class T, std::enable_if_t<!details::is_span<T>::value, int> = 0>
|
|
constexpr auto at(T& cont, const size_t i) -> decltype(cont[cont.size()])
|
|
{
|
|
#pragma warning(suppress : 26482) // Suppress bounds.2 check for indexing with constant expressions
|
|
#pragma warning(suppress : 26446) // Suppress bounds.4 check for subscript operator.
|
|
return cont[i];
|
|
}
|
|
|
|
#ifdef GSL_SPAN_H
|
|
// This is an overload of til::at for span that access its backing buffer directly (UNCHECKED)
|
|
template<typename ElementType, size_t Extent>
|
|
constexpr auto at(gsl::span<ElementType, Extent> span, const std::ptrdiff_t i) -> decltype(span[span.size()])
|
|
{
|
|
#pragma warning(suppress : 26481) // Suppress bounds.1 check for doing pointer arithmetic
|
|
#pragma warning(suppress : 26482) // Suppress bounds.2 check for indexing with constant expressions
|
|
#pragma warning(suppress : 26446) // Suppress bounds.4 check for subscript operator.
|
|
return span.data()[i];
|
|
}
|
|
#endif
|
|
}
|