terminal/src/inc/til/at.h
Dustin L. Howett 09471c3753
Replace gsl::at with a new til::at(span) for pre-checked bounds (#6925)
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.
2020-07-15 10:29:36 -07:00

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
}