Parameterize Expects1 and Ensures` by contract group

Allows independently controlling handling of different categories of bugs, such as bounds checks vs. null checks.
User-extensible: Companies can instantiate their own `contract_group` objects for their own categories of contract checks, including for distinguishing contract "levels" like `Normal` vs. `Audit` by just creating those two groups that can then be controlled independently or in combination.
This commit is contained in:
Herb Sutter 2020-11-27 17:06:01 -08:00
parent c16e4ce59f
commit cbfd8cd734
13 changed files with 129 additions and 124 deletions

View File

@ -44,8 +44,8 @@ shared_ptr | ☑ | an alias to `std::shared_ptr`
stack_array | ☐ | a stack-allocated array stack_array | ☐ | a stack-allocated array
dyn_array | ☐ | a heap-allocated array dyn_array | ☐ | a heap-allocated array
[**3. Assertions**][cg-assertions] | | [**3. Assertions**][cg-assertions] | |
Expects | ☑ | a precondition assertion; on failure it terminates Expects | ☑ | a precondition assertion; on failure it terminates by default if no user-installed handler
Ensures | ☑ | a postcondition assertion; on failure it terminates Ensures | ☑ | a postcondition assertion; on failure it terminates by default if no user-installed handler
[**4. Utilities**][cg-utilities] | | [**4. Utilities**][cg-utilities] | |
move_owner | ☐ | a helper function that moves one `owner` to the other move_owner | ☐ | a helper function that moves one `owner` to the other
byte | ☑ | either an alias to std::byte or a byte type byte | ☑ | either an alias to std::byte or a byte type

View File

@ -17,7 +17,7 @@
#ifndef GSL_ALGORITHM_H #ifndef GSL_ALGORITHM_H
#define GSL_ALGORITHM_H #define GSL_ALGORITHM_H
#include <gsl/assert> // for Expects #include <gsl/assert> // for contracts
#include <gsl/span> // for dynamic_extent, span #include <gsl/span> // for dynamic_extent, span
#include <algorithm> // for copy_n #include <algorithm> // for copy_n
@ -27,7 +27,7 @@
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(push) #pragma warning(push)
// turn off some warnings that are noisy about our Expects statements // turn off some warnings that are noisy about our contract checks
#pragma warning(disable : 4127) // conditional expression is constant #pragma warning(disable : 4127) // conditional expression is constant
#pragma warning(disable : 4996) // unsafe use of std::copy_n #pragma warning(disable : 4996) // unsafe use of std::copy_n
@ -47,7 +47,7 @@ void copy(span<SrcElementType, SrcExtent> src, span<DestElementType, DestExtent>
(SrcExtent <= DestExtent), (SrcExtent <= DestExtent),
"Source range is longer than target range"); "Source range is longer than target range");
Expects(dest.size() >= src.size()); Expects(dest.size() >= src.size(), Bounds);
// clang-format off // clang-format off
GSL_SUPPRESS(stl.1) // NO-FORMAT: attribute GSL_SUPPRESS(stl.1) // NO-FORMAT: attribute
// clang-format on // clang-format on

View File

@ -108,18 +108,23 @@ public:
auto set_handler(handler h) -> handler { return chandler.exchange(h); } auto set_handler(handler h) -> handler { return chandler.exchange(h); }
auto get_handler() -> handler { return chandler; } auto get_handler() -> handler { return chandler; }
auto assertion(bool b) { if (!b && chandler.load()) chandler.load()(); } auto expects(bool b) { assertion(b); }
auto ensures(bool b) { assertion(b); }
private: private:
auto assertion(bool b) { if (!b && chandler.load()) chandler.load()(); }
std::atomic<handler> chandler; std::atomic<handler> chandler;
}; };
auto static cg_default = contract_group{ &gsl::details::terminate }; auto static Default = contract_group{ &gsl::details::terminate };
auto static Bounds = contract_group{ Default.get_handler() };
auto static Null = contract_group{ Default.get_handler() };
auto static Testing = contract_group{ Default.get_handler() };
} // namespace gsl } // namespace gsl
#define Expects(cond) gsl::cg_default.assertion(cond) #define Expects(cond, kind) kind.expects(cond)
#define Ensures(cond) gsl::cg_default.assertion(cond) #define Ensures(cond, kind) kind.ensures(cond)
#if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND) && defined(__clang__) #if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND) && defined(__clang__)
#pragma clang diagnostic pop #pragma clang diagnostic pop

View File

@ -18,7 +18,7 @@
#define GSL_GSL_H #define GSL_GSL_H
#include <gsl/algorithm> // copy #include <gsl/algorithm> // copy
#include <gsl/assert> // Ensures/Expects #include <gsl/assert> // contracts
#include <gsl/byte> // byte #include <gsl/byte> // byte
#include <gsl/pointers> // owner, not_null #include <gsl/pointers> // owner, not_null
#include <gsl/multi_span> // multi_span, strided_span... #include <gsl/multi_span> // multi_span, strided_span...

View File

@ -17,7 +17,7 @@
#ifndef GSL_MULTI_SPAN_H #ifndef GSL_MULTI_SPAN_H
#define GSL_MULTI_SPAN_H #define GSL_MULTI_SPAN_H
#include <gsl/assert> // for Expects #include <gsl/assert> // for contracts
#include <gsl/byte> // for byte #include <gsl/byte> // for byte
#include <gsl/util> // for narrow_cast #include <gsl/util> // for narrow_cast
@ -38,7 +38,7 @@
#if defined(_MSC_VER) && !defined(__clang__) #if defined(_MSC_VER) && !defined(__clang__)
// turn off some warnings that are noisy about our Expects statements // turn off some warnings that are noisy about our contract checks
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4127) // conditional expression is constant #pragma warning(disable : 4127) // conditional expression is constant
#pragma warning(disable : 4702) // unreachable code #pragma warning(disable : 4702) // unreachable code
@ -136,7 +136,7 @@ public:
// clang-format on // clang-format on
constexpr reference operator[](std::size_t component_idx) constexpr reference operator[](std::size_t component_idx)
{ {
Expects(component_idx < Rank); // Component index must be less than rank Expects(component_idx < Rank, Bounds); // Component index must be less than rank
return elems[component_idx]; return elems[component_idx];
} }
@ -147,7 +147,7 @@ public:
// clang-format on // clang-format on
constexpr const_reference operator[](std::size_t component_idx) const constexpr const_reference operator[](std::size_t component_idx) const
{ {
Expects(component_idx < Rank); // Component index must be less than rank Expects(component_idx < Rank, Bounds); // Component index must be less than rank
return elems[component_idx]; return elems[component_idx];
} }
@ -377,7 +377,7 @@ namespace details
constexpr BoundsRanges(const std::ptrdiff_t* const arr) constexpr BoundsRanges(const std::ptrdiff_t* const arr)
: Base(arr + 1), m_bound(*arr * this->Base::totalSize()) : Base(arr + 1), m_bound(*arr * this->Base::totalSize())
{ {
Expects(0 <= *arr); Expects(0 <= *arr, Bounds);
} }
constexpr BoundsRanges() noexcept : m_bound(0) {} constexpr BoundsRanges() noexcept : m_bound(0) {}
@ -403,7 +403,7 @@ namespace details
constexpr size_type linearize(const T& arr) const constexpr size_type linearize(const T& arr) const
{ {
const size_type index = this->Base::totalSize() * arr[Dim]; const size_type index = this->Base::totalSize() * arr[Dim];
Expects(index < m_bound); Expects(index < m_bound, Bounds);
return index + this->Base::template linearize<T, Dim + 1>(arr); return index + this->Base::template linearize<T, Dim + 1>(arr);
} }
@ -485,7 +485,7 @@ namespace details
// clang-format off // clang-format off
GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute
// clang-format on // clang-format on
Expects(arr[Dim] >= 0 && arr[Dim] < CurrentRange); // Index is out of range Expects(arr[Dim] >= 0 && arr[Dim] < CurrentRange, Bounds); // Index is out of range
// clang-format off // clang-format off
GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute
// clang-format on // clang-format on
@ -680,16 +680,16 @@ public:
constexpr static_bounds(const static_bounds<Ranges...>& other) : m_ranges(other.m_ranges) constexpr static_bounds(const static_bounds<Ranges...>& other) : m_ranges(other.m_ranges)
{ {
Expects((MyRanges::DynamicNum == 0 && details::BoundsRanges<Ranges...>::DynamicNum == 0) || Expects((MyRanges::DynamicNum == 0 && details::BoundsRanges<Ranges...>::DynamicNum == 0) ||
MyRanges::DynamicNum > 0 || other.m_ranges.totalSize() >= m_ranges.totalSize()); MyRanges::DynamicNum > 0 || other.m_ranges.totalSize() >= m_ranges.totalSize(), Bounds);
} }
constexpr static_bounds(std::initializer_list<size_type> il) : m_ranges(il.begin()) constexpr static_bounds(std::initializer_list<size_type> il) : m_ranges(il.begin())
{ {
// Size of the initializer list must match the rank of the array // Size of the initializer list must match the rank of the array
Expects((MyRanges::DynamicNum == 0 && il.size() == 1 && *il.begin() == static_size) || Expects((MyRanges::DynamicNum == 0 && il.size() == 1 && *il.begin() == static_size) ||
MyRanges::DynamicNum == il.size()); MyRanges::DynamicNum == il.size(), Bounds);
// Size of the range must be less than the max element of the size type // Size of the range must be less than the max element of the size type
Expects(m_ranges.totalSize() <= PTRDIFF_MAX); Expects(m_ranges.totalSize() <= PTRDIFF_MAX, Bounds);
} }
constexpr sliced_type slice() const noexcept constexpr sliced_type slice() const noexcept
@ -729,7 +729,7 @@ public:
static_assert(std::is_integral<IntType>::value, static_assert(std::is_integral<IntType>::value,
"Dimension parameter must be supplied as an integral type."); "Dimension parameter must be supplied as an integral type.");
auto real_dim = narrow_cast<std::size_t>(dim); auto real_dim = narrow_cast<std::size_t>(dim);
Expects(real_dim < rank); Expects(real_dim < rank, Bounds);
return m_ranges.elementNum(real_dim); return m_ranges.elementNum(real_dim);
} }
@ -834,7 +834,7 @@ public:
size_type ret = 0; size_type ret = 0;
for (std::size_t i = 0; i < rank; i++) for (std::size_t i = 0; i < rank; i++)
{ {
Expects(idx[i] < m_extents[i]); // index is out of bounds of the array Expects(idx[i] < m_extents[i], Bounds); // index is out of bounds of the array
ret += idx[i] * m_strides[i]; ret += idx[i] * m_strides[i];
} }
return ret; return ret;
@ -960,7 +960,7 @@ public:
} }
// If we're here the preconditions were violated // If we're here the preconditions were violated
// "pre: there exists s such that r == ++s" // "pre: there exists s such that r == ++s"
Expects(false); Expects(false, Bounds);
return *this; return *this;
} }
@ -992,7 +992,7 @@ public:
linear_idx = linear_idx % stride[i]; linear_idx = linear_idx % stride[i];
} }
// index is out of bounds of the array // index is out of bounds of the array
Expects(!less(curr_, index_type{}) && !less(boundary_, curr_)); Expects(!less(curr_, index_type{}) && !less(boundary_, curr_), Bounds);
return *this; return *this;
} }
@ -1132,7 +1132,7 @@ namespace details
BoundsSrc::static_size == dynamic_range || BoundsSrc::static_size == dynamic_range ||
BoundsDest::static_size == BoundsSrc::static_size, BoundsDest::static_size == BoundsSrc::static_size,
"The source bounds must have same size as dest bounds"); "The source bounds must have same size as dest bounds");
Expects(src.size() == dest.size()); Expects(src.size() == dest.size(), Bounds);
} }
} // namespace details } // namespace details
@ -1210,13 +1210,13 @@ namespace details
template <typename BoundsType> template <typename BoundsType>
BoundsType newBoundsHelperImpl(std::ptrdiff_t totalSize, std::true_type) // dynamic size BoundsType newBoundsHelperImpl(std::ptrdiff_t totalSize, std::true_type) // dynamic size
{ {
Expects(totalSize >= 0 && totalSize <= PTRDIFF_MAX); Expects(totalSize >= 0 && totalSize <= PTRDIFF_MAX, Bounds);
return BoundsType{totalSize}; return BoundsType{totalSize};
} }
template <typename BoundsType> template <typename BoundsType>
BoundsType newBoundsHelperImpl(std::ptrdiff_t totalSize, std::false_type) // static size BoundsType newBoundsHelperImpl(std::ptrdiff_t totalSize, std::false_type) // static size
{ {
Expects(BoundsType::static_size <= totalSize); Expects(BoundsType::static_size <= totalSize, Bounds);
return {}; return {};
} }
template <typename BoundsType> template <typename BoundsType>
@ -1345,7 +1345,7 @@ public:
(bounds_type::dynamic_rank == 0 && bounds_type::static_size == 0), (bounds_type::dynamic_rank == 0 && bounds_type::static_size == 0),
"nullptr_t construction of multi_span<T> only possible " "nullptr_t construction of multi_span<T> only possible "
"for dynamic or fixed, zero-length spans."); "for dynamic or fixed, zero-length spans.");
Expects(size == 0); Expects(size == 0, Bounds);
} }
// construct from a single element // construct from a single element
@ -1373,7 +1373,7 @@ public:
// construct from pointer + length - multidimensional // construct from pointer + length - multidimensional
constexpr multi_span(pointer data, bounds_type bounds) : data_(data), bounds_(std::move(bounds)) constexpr multi_span(pointer data, bounds_type bounds) : data_(data), bounds_(std::move(bounds))
{ {
Expects((bounds_.size() > 0 && data != nullptr) || bounds_.size() == 0); Expects((bounds_.size() > 0 && data != nullptr) || bounds_.size() == 0, Bounds);
} }
// construct from begin,end pointer pair // construct from begin,end pointer pair
@ -1384,7 +1384,7 @@ public:
: multi_span(begin, : multi_span(begin,
details::newBoundsHelper<bounds_type>(static_cast<pointer>(end) - begin)) details::newBoundsHelper<bounds_type>(static_cast<pointer>(end) - begin))
{ {
Expects(begin != nullptr && end != nullptr && begin <= static_cast<pointer>(end)); Expects(begin != nullptr && end != nullptr && begin <= static_cast<pointer>(end), Bounds);
} }
// construct from n-dimensions static array // construct from n-dimensions static array
@ -1488,14 +1488,14 @@ public:
Count <= bounds_type::static_size, Count <= bounds_type::static_size,
"Count is out of bounds."); "Count is out of bounds.");
Expects(bounds_type::static_size != dynamic_range || Count <= this->size()); Expects(bounds_type::static_size != dynamic_range || Count <= this->size(), Bounds);
return {this->data(), Count}; return {this->data(), Count};
} }
// first() - extract the first count elements into a new multi_span // first() - extract the first count elements into a new multi_span
constexpr multi_span<ValueType, dynamic_range> first(size_type count) const constexpr multi_span<ValueType, dynamic_range> first(size_type count) const
{ {
Expects(count >= 0 && count <= this->size()); Expects(count >= 0 && count <= this->size(), Bounds);
return {this->data(), count}; return {this->data(), count};
} }
@ -1508,14 +1508,14 @@ public:
Count <= bounds_type::static_size, Count <= bounds_type::static_size,
"Count is out of bounds."); "Count is out of bounds.");
Expects(bounds_type::static_size != dynamic_range || Count <= this->size()); Expects(bounds_type::static_size != dynamic_range || Count <= this->size(), Bounds);
return {this->data() + this->size() - Count, Count}; return {this->data() + this->size() - Count, Count};
} }
// last() - extract the last count elements into a new multi_span // last() - extract the last count elements into a new multi_span
constexpr multi_span<ValueType, dynamic_range> last(size_type count) const constexpr multi_span<ValueType, dynamic_range> last(size_type count) const
{ {
Expects(count >= 0 && count <= this->size()); Expects(count >= 0 && count <= this->size(), Bounds);
return {this->data() + this->size() - count, count}; return {this->data() + this->size() - count, count};
} }
@ -1531,7 +1531,7 @@ public:
"You must describe a sub-range within bounds of the multi_span."); "You must describe a sub-range within bounds of the multi_span.");
Expects(bounds_type::static_size != dynamic_range || Expects(bounds_type::static_size != dynamic_range ||
(Offset <= this->size() && Count <= this->size() - Offset)); (Offset <= this->size() && Count <= this->size() - Offset), Bounds);
return {this->data() + Offset, Count}; return {this->data() + Offset, Count};
} }
@ -1541,7 +1541,7 @@ public:
size_type count = dynamic_range) const size_type count = dynamic_range) const
{ {
Expects((offset >= 0 && offset <= this->size()) && Expects((offset >= 0 && offset <= this->size()) &&
(count == dynamic_range || (count <= this->size() - offset))); (count == dynamic_range || (count <= this->size() - offset)), Bounds);
return {this->data() + offset, count == dynamic_range ? this->length() - offset : count}; return {this->data() + offset, count == dynamic_range ? this->length() - offset : count};
} }
@ -1619,11 +1619,11 @@ public:
// clang-format on // clang-format on
constexpr Ret operator[](size_type idx) const constexpr Ret operator[](size_type idx) const
{ {
Expects(idx >= 0 && idx < bounds_.size()); // index is out of bounds of the array Expects(idx >= 0 && idx < bounds_.size(), Bounds); // index is out of bounds of the array
const size_type ridx = idx * bounds_.stride(); const size_type ridx = idx * bounds_.stride();
// index is out of bounds of the underlying data // index is out of bounds of the underlying data
Expects(ridx < bounds_.total_size()); Expects(ridx < bounds_.total_size(), Bounds);
return Ret{data_ + ridx, bounds_.slice()}; return Ret{data_ + ridx, bounds_.slice()};
} }
@ -1771,7 +1771,7 @@ constexpr auto as_multi_span(multi_span<const byte, Dimensions...> s) -> multi_s
"Target type must be a trivial type and its size must match the byte array size"); "Target type must be a trivial type and its size must match the byte array size");
Expects((s.size_bytes() % narrow_cast<std::ptrdiff_t>(sizeof(U))) == 0 && Expects((s.size_bytes() % narrow_cast<std::ptrdiff_t>(sizeof(U))) == 0 &&
(s.size_bytes() / narrow_cast<std::ptrdiff_t>(sizeof(U))) < PTRDIFF_MAX); (s.size_bytes() / narrow_cast<std::ptrdiff_t>(sizeof(U))) < PTRDIFF_MAX, Bounds);
return {reinterpret_cast<const U*>(s.data()), return {reinterpret_cast<const U*>(s.data()),
s.size_bytes() / narrow_cast<std::ptrdiff_t>(sizeof(U))}; s.size_bytes() / narrow_cast<std::ptrdiff_t>(sizeof(U))};
} }
@ -1795,7 +1795,7 @@ constexpr auto as_multi_span(multi_span<byte, Dimensions...> s)
ByteSpan::bounds_type::static_size % sizeof(U) == 0), ByteSpan::bounds_type::static_size % sizeof(U) == 0),
"Target type must be a trivial type and its size must match the byte array size"); "Target type must be a trivial type and its size must match the byte array size");
Expects((s.size_bytes() % sizeof(U)) == 0); Expects((s.size_bytes() % sizeof(U)) == 0, Bounds);
return {reinterpret_cast<U*>(s.data()), return {reinterpret_cast<U*>(s.data()),
s.size_bytes() / narrow_cast<std::ptrdiff_t>(sizeof(U))}; s.size_bytes() / narrow_cast<std::ptrdiff_t>(sizeof(U))};
} }
@ -1848,7 +1848,7 @@ constexpr auto as_multi_span(Cont& arr) -> std::enable_if_t<
!details::is_multi_span<std::decay_t<Cont>>::value, !details::is_multi_span<std::decay_t<Cont>>::value,
multi_span<std::remove_reference_t<decltype(arr.size(), *arr.data())>, dynamic_range>> multi_span<std::remove_reference_t<decltype(arr.size(), *arr.data())>, dynamic_range>>
{ {
Expects(arr.size() < PTRDIFF_MAX); Expects(arr.size() < PTRDIFF_MAX, Bounds);
return {arr.data(), narrow_cast<std::ptrdiff_t>(arr.size())}; return {arr.data(), narrow_cast<std::ptrdiff_t>(arr.size())};
} }
@ -1865,7 +1865,7 @@ GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute
constexpr auto as_multi_span(std::basic_string<CharT, Traits, Allocator>& str) constexpr auto as_multi_span(std::basic_string<CharT, Traits, Allocator>& str)
-> multi_span<CharT, dynamic_range> -> multi_span<CharT, dynamic_range>
{ {
Expects(str.size() < PTRDIFF_MAX); Expects(str.size() < PTRDIFF_MAX, Bounds);
return {&str[0], narrow_cast<std::ptrdiff_t>(str.size())}; return {&str[0], narrow_cast<std::ptrdiff_t>(str.size())};
} }
@ -1905,9 +1905,9 @@ public:
constexpr strided_span(pointer ptr, size_type size, bounds_type bounds) constexpr strided_span(pointer ptr, size_type size, bounds_type bounds)
: data_(ptr), bounds_(std::move(bounds)) : data_(ptr), bounds_(std::move(bounds))
{ {
Expects((bounds_.size() > 0 && ptr != nullptr) || bounds_.size() == 0); Expects((bounds_.size() > 0 && ptr != nullptr) || bounds_.size() == 0, Bounds);
// Bounds cross data boundaries // Bounds cross data boundaries
Expects(this->bounds().total_size() <= size); Expects(this->bounds().total_size() <= size, Bounds);
// clang-format off // clang-format off
GSL_SUPPRESS(type.4) // NO-FORMAT: attribute // TODO: false positive GSL_SUPPRESS(type.4) // NO-FORMAT: attribute // TODO: false positive
// clang-format on // clang-format on
@ -1980,11 +1980,11 @@ public:
// clang-format on // clang-format on
constexpr Ret operator[](size_type idx) const constexpr Ret operator[](size_type idx) const
{ {
Expects(idx < bounds_.size()); // index is out of bounds of the array Expects(idx < bounds_.size(), Bounds); // index is out of bounds of the array
const size_type ridx = idx * bounds_.stride(); const size_type ridx = idx * bounds_.stride();
// index is out of bounds of the underlying data // index is out of bounds of the underlying data
Expects(ridx < bounds_.total_size()); Expects(ridx < bounds_.total_size(), Bounds);
return {data_ + ridx, bounds_.slice().total_size(), bounds_.slice()}; return {data_ + ridx, bounds_.slice().total_size(), bounds_.slice()};
} }
@ -2084,7 +2084,7 @@ private:
// clang-format off // clang-format off
GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute
// clang-format on // clang-format on
Expects(extent[Rank - 1] >= d && (extent[Rank - 1] % d == 0)); Expects(extent[Rank - 1] >= d && (extent[Rank - 1] % d == 0), Bounds);
index_type ret = extent; index_type ret = extent;
ret[Rank - 1] /= d; ret[Rank - 1] /= d;
@ -2099,7 +2099,7 @@ private:
// clang-format off // clang-format off
GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute
// clang-format on // clang-format on
Expects(strides[Rank - 1] == 1); Expects(strides[Rank - 1] == 1, Bounds);
return strides; return strides;
} }
@ -2111,15 +2111,15 @@ private:
static index_type resize_stride(const index_type& strides, std::ptrdiff_t d) static index_type resize_stride(const index_type& strides, std::ptrdiff_t d)
{ {
// Only strided arrays with regular strides can be resized // Only strided arrays with regular strides can be resized
Expects(strides[Rank - 1] == 1); Expects(strides[Rank - 1] == 1, Bounds);
// The strides must have contiguous chunks of // The strides must have contiguous chunks of
// memory that can contain a multiple of new type elements // memory that can contain a multiple of new type elements
Expects(strides[Rank - 2] >= d && (strides[Rank - 2] % d == 0)); Expects(strides[Rank - 2] >= d && (strides[Rank - 2] % d == 0), Bounds);
for (std::size_t i = Rank - 1; i > 0; --i) for (std::size_t i = Rank - 1; i > 0; --i)
{ {
// Only strided arrays with regular strides can be resized // Only strided arrays with regular strides can be resized
Expects((strides[i - 1] >= strides[i]) && (strides[i - 1] % strides[i] == 0)); Expects((strides[i - 1] >= strides[i]) && (strides[i - 1] % strides[i] == 0), Bounds);
} }
index_type ret = strides / d; index_type ret = strides / d;
@ -2152,7 +2152,7 @@ private:
void validateThis() const void validateThis() const
{ {
// iterator is out of range of the array // iterator is out of range of the array
Expects(data_ >= m_validator->data_ && data_ < m_validator->data_ + m_validator->size()); Expects(data_ >= m_validator->data_ && data_ < m_validator->data_ + m_validator->size(), Bounds);
} }
// clang-format off // clang-format off
@ -2223,13 +2223,13 @@ public:
contiguous_span_iterator& operator-=(difference_type n) { return *this += -n; } contiguous_span_iterator& operator-=(difference_type n) { return *this += -n; }
difference_type operator-(const contiguous_span_iterator& rhs) const difference_type operator-(const contiguous_span_iterator& rhs) const
{ {
Expects(m_validator == rhs.m_validator); Expects(m_validator == rhs.m_validator, Bounds);
return data_ - rhs.data_; return data_ - rhs.data_;
} }
reference operator[](difference_type n) const { return *(*this + n); } reference operator[](difference_type n) const { return *(*this + n); }
bool operator==(const contiguous_span_iterator& rhs) const bool operator==(const contiguous_span_iterator& rhs) const
{ {
Expects(m_validator == rhs.m_validator); Expects(m_validator == rhs.m_validator, Bounds);
return data_ == rhs.data_; return data_ == rhs.data_;
} }
@ -2237,7 +2237,7 @@ public:
bool operator<(const contiguous_span_iterator& rhs) const bool operator<(const contiguous_span_iterator& rhs) const
{ {
Expects(m_validator == rhs.m_validator); Expects(m_validator == rhs.m_validator, Bounds);
return data_ < rhs.data_; return data_ < rhs.data_;
} }
@ -2323,7 +2323,7 @@ public:
general_span_iterator& operator-=(difference_type n) noexcept { return *this += -n; } general_span_iterator& operator-=(difference_type n) noexcept { return *this += -n; }
difference_type operator-(const general_span_iterator& rhs) const difference_type operator-(const general_span_iterator& rhs) const
{ {
Expects(m_container == rhs.m_container); Expects(m_container == rhs.m_container, Bounds);
return m_itr - rhs.m_itr; return m_itr - rhs.m_itr;
} }
@ -2334,13 +2334,13 @@ public:
bool operator==(const general_span_iterator& rhs) const bool operator==(const general_span_iterator& rhs) const
{ {
Expects(m_container == rhs.m_container); Expects(m_container == rhs.m_container, Bounds);
return m_itr == rhs.m_itr; return m_itr == rhs.m_itr;
} }
bool operator!=(const general_span_iterator& rhs) const { return !(*this == rhs); } bool operator!=(const general_span_iterator& rhs) const { return !(*this == rhs); }
bool operator<(const general_span_iterator& rhs) const bool operator<(const general_span_iterator& rhs) const
{ {
Expects(m_container == rhs.m_container); Expects(m_container == rhs.m_container, Bounds);
return m_itr < rhs.m_itr; return m_itr < rhs.m_itr;
} }
bool operator<=(const general_span_iterator& rhs) const { return !(rhs < *this); } bool operator<=(const general_span_iterator& rhs) const { return !(rhs < *this); }

View File

@ -16,7 +16,7 @@
#ifndef GSL_NARROW_H #ifndef GSL_NARROW_H
#define GSL_NARROW_H #define GSL_NARROW_H
#include <gsl/assert> // for Expects #include <gsl/assert> // for contracts
#include <gsl/util> // for narrow_cast #include <gsl/util> // for narrow_cast
namespace gsl namespace gsl
{ {

View File

@ -17,7 +17,7 @@
#ifndef GSL_POINTERS_H #ifndef GSL_POINTERS_H
#define GSL_POINTERS_H #define GSL_POINTERS_H
#include <gsl/assert> // for Ensures, Expects #include <gsl/assert> // for contracts
#include <algorithm> // for forward #include <algorithm> // for forward
#include <cstddef> // for ptrdiff_t, nullptr_t, size_t #include <cstddef> // for ptrdiff_t, nullptr_t, size_t
@ -74,13 +74,13 @@ public:
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>> template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
constexpr not_null(U&& u) : ptr_(std::forward<U>(u)) constexpr not_null(U&& u) : ptr_(std::forward<U>(u))
{ {
Expects(ptr_ != nullptr); Expects(ptr_ != nullptr, Null);
} }
template <typename = std::enable_if_t<!std::is_same<std::nullptr_t, T>::value>> template <typename = std::enable_if_t<!std::is_same<std::nullptr_t, T>::value>>
constexpr not_null(T u) : ptr_(std::move(u)) constexpr not_null(T u) : ptr_(std::move(u))
{ {
Expects(ptr_ != nullptr); Expects(ptr_ != nullptr, Null);
} }
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>> template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
@ -91,7 +91,7 @@ public:
not_null& operator=(const not_null& other) = default; not_null& operator=(const not_null& other) = default;
constexpr std::conditional_t<std::is_copy_constructible<T>::value, T, const T&> get() const constexpr std::conditional_t<std::is_copy_constructible<T>::value, T, const T&> get() const
{ {
Ensures(ptr_ != nullptr); Ensures(ptr_ != nullptr, Null);
return ptr_; return ptr_;
} }

View File

@ -17,7 +17,7 @@
#ifndef GSL_SPAN_H #ifndef GSL_SPAN_H
#define GSL_SPAN_H #define GSL_SPAN_H
#include <gsl/assert> // for Expects #include <gsl/assert> // for contracts
#include <gsl/byte> // for byte #include <gsl/byte> // for byte
#include <gsl/util> // for narrow_cast #include <gsl/util> // for narrow_cast
@ -29,7 +29,7 @@
#if defined(_MSC_VER) && !defined(__clang__) #if defined(_MSC_VER) && !defined(__clang__)
#pragma warning(push) #pragma warning(push)
// turn off some warnings that are noisy about our Expects statements // turn off some warnings that are noisy about our contract checks
#pragma warning(disable : 4127) // conditional expression is constant #pragma warning(disable : 4127) // conditional expression is constant
#pragma warning( \ #pragma warning( \
disable : 4146) // unary minus operator applied to unsigned type, result still unsigned disable : 4146) // unary minus operator applied to unsigned type, result still unsigned
@ -137,21 +137,21 @@ namespace details
constexpr reference operator*() const noexcept constexpr reference operator*() const noexcept
{ {
Expects(begin_ && end_); Expects(begin_ && end_, Bounds);
Expects(begin_ <= current_ && current_ < end_); Expects(begin_ <= current_ && current_ < end_, Bounds);
return *current_; return *current_;
} }
constexpr pointer operator->() const noexcept constexpr pointer operator->() const noexcept
{ {
Expects(begin_ && end_); Expects(begin_ && end_, Bounds);
Expects(begin_ <= current_ && current_ < end_); Expects(begin_ <= current_ && current_ < end_, Bounds);
return current_; return current_;
} }
constexpr span_iterator& operator++() noexcept constexpr span_iterator& operator++() noexcept
{ {
Expects(begin_ && current_ && end_); Expects(begin_ && current_ && end_, Bounds);
Expects(current_ < end_); Expects(current_ < end_, Bounds);
// clang-format off // clang-format off
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
// clang-format on // clang-format on
@ -168,8 +168,8 @@ namespace details
constexpr span_iterator& operator--() noexcept constexpr span_iterator& operator--() noexcept
{ {
Expects(begin_ && end_); Expects(begin_ && end_, Bounds);
Expects(begin_ < current_); Expects(begin_ < current_, Bounds);
--current_; --current_;
return *this; return *this;
} }
@ -183,9 +183,9 @@ namespace details
constexpr span_iterator& operator+=(const difference_type n) noexcept constexpr span_iterator& operator+=(const difference_type n) noexcept
{ {
if (n != 0) Expects(begin_ && current_ && end_); if (n != 0) Expects(begin_ && current_ && end_, Bounds);
if (n > 0) Expects(end_ - current_ >= n); if (n > 0) Expects(end_ - current_ >= n, Bounds);
if (n < 0) Expects(current_ - begin_ >= -n); if (n < 0) Expects(current_ - begin_ >= -n, Bounds);
// clang-format off // clang-format off
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
// clang-format on // clang-format on
@ -208,9 +208,9 @@ namespace details
constexpr span_iterator& operator-=(const difference_type n) noexcept constexpr span_iterator& operator-=(const difference_type n) noexcept
{ {
if (n != 0) Expects(begin_ && current_ && end_); if (n != 0) Expects(begin_ && current_ && end_, Bounds);
if (n > 0) Expects(current_ - begin_ >= n); if (n > 0) Expects(current_ - begin_ >= n, Bounds);
if (n < 0) Expects(end_ - current_ >= -n); if (n < 0) Expects(end_ - current_ >= -n, Bounds);
current_ -= n; current_ -= n;
return *this; return *this;
} }
@ -227,7 +227,7 @@ namespace details
std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0> std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
constexpr difference_type operator-(const span_iterator<Type2>& rhs) const noexcept constexpr difference_type operator-(const span_iterator<Type2>& rhs) const noexcept
{ {
Expects(begin_ == rhs.begin_ && end_ == rhs.end_); Expects(begin_ == rhs.begin_ && end_ == rhs.end_, Bounds);
return current_ - rhs.current_; return current_ - rhs.current_;
} }
@ -241,7 +241,7 @@ namespace details
std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0> std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
constexpr bool operator==(const span_iterator<Type2>& rhs) const noexcept constexpr bool operator==(const span_iterator<Type2>& rhs) const noexcept
{ {
Expects(begin_ == rhs.begin_ && end_ == rhs.end_); Expects(begin_ == rhs.begin_ && end_ == rhs.end_, Bounds);
return current_ == rhs.current_; return current_ == rhs.current_;
} }
@ -258,7 +258,7 @@ namespace details
std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0> std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
constexpr bool operator<(const span_iterator<Type2>& rhs) const noexcept constexpr bool operator<(const span_iterator<Type2>& rhs) const noexcept
{ {
Expects(begin_ == rhs.begin_ && end_ == rhs.end_); Expects(begin_ == rhs.begin_ && end_ == rhs.end_, Bounds);
return current_ < rhs.current_; return current_ < rhs.current_;
} }
@ -294,14 +294,14 @@ namespace details
{ // test that [lhs, rhs) forms a valid range inside an STL algorithm { // test that [lhs, rhs) forms a valid range inside an STL algorithm
Expects(lhs.begin_ == rhs.begin_ // range spans have to match Expects(lhs.begin_ == rhs.begin_ // range spans have to match
&& lhs.end_ == rhs.end_ && && lhs.end_ == rhs.end_ &&
lhs.current_ <= rhs.current_); // range must not be transposed lhs.current_ <= rhs.current_, Bounds); // range must not be transposed
} }
constexpr void _Verify_offset(const difference_type n) const noexcept constexpr void _Verify_offset(const difference_type n) const noexcept
{ // test that *this + n is within the range of this call { // test that *this + n is within the range of this call
if (n != 0) Expects(begin_ && current_ && end_); if (n != 0) Expects(begin_ && current_ && end_, Bounds);
if (n > 0) Expects(end_ - current_ >= n); if (n > 0) Expects(end_ - current_ >= n, Bounds);
if (n < 0) Expects(current_ - begin_ >= -n); if (n < 0) Expects(current_ - begin_ >= -n, Bounds);
} }
// clang-format off // clang-format off
@ -346,7 +346,7 @@ namespace details
constexpr explicit extent_type(extent_type<dynamic_extent>); constexpr explicit extent_type(extent_type<dynamic_extent>);
constexpr explicit extent_type(size_type size) { Expects(size == Ext); } constexpr explicit extent_type(size_type size) { Expects(size == Ext, Bounds); }
constexpr size_type size() const noexcept { return Ext; } constexpr size_type size() const noexcept { return Ext; }
@ -370,7 +370,7 @@ namespace details
constexpr explicit extent_type(size_type size) : size_(size) constexpr explicit extent_type(size_type size) : size_(size)
{ {
Expects(size != dynamic_extent); Expects(size != dynamic_extent, Bounds);
} }
constexpr size_type size() const noexcept { return size_; } constexpr size_type size() const noexcept { return size_; }
@ -382,7 +382,7 @@ namespace details
template <std::size_t Ext> template <std::size_t Ext>
constexpr extent_type<Ext>::extent_type(extent_type<dynamic_extent> ext) constexpr extent_type<Ext>::extent_type(extent_type<dynamic_extent> ext)
{ {
Expects(ext.size() == Ext); Expects(ext.size() == Ext, Bounds);
} }
template <class ElementType, std::size_t Extent, std::size_t Offset, std::size_t Count> template <class ElementType, std::size_t Extent, std::size_t Offset, std::size_t Count>
@ -431,7 +431,7 @@ public:
template <std::size_t MyExtent = Extent, std::enable_if_t<MyExtent != dynamic_extent, int> = 0> template <std::size_t MyExtent = Extent, std::enable_if_t<MyExtent != dynamic_extent, int> = 0>
constexpr explicit span(pointer ptr, size_type count) noexcept : storage_(ptr, count) constexpr explicit span(pointer ptr, size_type count) noexcept : storage_(ptr, count)
{ {
Expects(count == Extent); Expects(count == Extent, Bounds);
} }
template <std::size_t MyExtent = Extent, std::enable_if_t<MyExtent == dynamic_extent, int> = 0> template <std::size_t MyExtent = Extent, std::enable_if_t<MyExtent == dynamic_extent, int> = 0>
@ -442,7 +442,7 @@ public:
constexpr explicit span(pointer firstElem, pointer lastElem) noexcept constexpr explicit span(pointer firstElem, pointer lastElem) noexcept
: storage_(firstElem, narrow_cast<std::size_t>(lastElem - firstElem)) : storage_(firstElem, narrow_cast<std::size_t>(lastElem - firstElem))
{ {
Expects(lastElem - firstElem == static_cast<difference_type>(Extent)); Expects(lastElem - firstElem == static_cast<difference_type>(Extent), Bounds);
} }
template <std::size_t MyExtent = Extent, std::enable_if_t<MyExtent == dynamic_extent, int> = 0> template <std::size_t MyExtent = Extent, std::enable_if_t<MyExtent == dynamic_extent, int> = 0>
@ -553,7 +553,7 @@ public:
template <std::size_t Count> template <std::size_t Count>
constexpr span<element_type, Count> first() const noexcept constexpr span<element_type, Count> first() const noexcept
{ {
Expects(Count <= size()); Expects(Count <= size(), Bounds);
return span<element_type, Count>{data(), Count}; return span<element_type, Count>{data(), Count};
} }
@ -563,7 +563,7 @@ public:
// clang-format on // clang-format on
constexpr span<element_type, Count> last() const noexcept constexpr span<element_type, Count> last() const noexcept
{ {
Expects(Count <= size()); Expects(Count <= size(), Bounds);
return span<element_type, Count>{data() + (size() - Count), Count}; return span<element_type, Count>{data() + (size() - Count), Count};
} }
@ -574,7 +574,7 @@ public:
constexpr auto subspan() const noexcept -> constexpr auto subspan() const noexcept ->
typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type
{ {
Expects((size() >= Offset) && (Count == dynamic_extent || (Count <= size() - Offset))); Expects((size() >= Offset) && (Count == dynamic_extent || (Count <= size() - Offset)), Bounds);
using type = using type =
typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type; typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type;
return type{data() + Offset, Count == dynamic_extent ? size() - Offset : Count}; return type{data() + Offset, Count == dynamic_extent ? size() - Offset : Count};
@ -582,13 +582,13 @@ public:
constexpr span<element_type, dynamic_extent> first(size_type count) const noexcept constexpr span<element_type, dynamic_extent> first(size_type count) const noexcept
{ {
Expects(count <= size()); Expects(count <= size(), Bounds);
return {data(), count}; return {data(), count};
} }
constexpr span<element_type, dynamic_extent> last(size_type count) const noexcept constexpr span<element_type, dynamic_extent> last(size_type count) const noexcept
{ {
Expects(count <= size()); Expects(count <= size(), Bounds);
return make_subspan(size() - count, dynamic_extent, subspan_selector<Extent>{}); return make_subspan(size() - count, dynamic_extent, subspan_selector<Extent>{});
} }
@ -603,7 +603,7 @@ public:
constexpr size_type size_bytes() const noexcept constexpr size_type size_bytes() const noexcept
{ {
Expects(size() < dynamic_extent / sizeof(element_type)); Expects(size() < dynamic_extent / sizeof(element_type), Bounds);
return size() * sizeof(element_type); return size() * sizeof(element_type);
} }
@ -615,19 +615,19 @@ public:
// clang-format on // clang-format on
constexpr reference operator[](size_type idx) const noexcept constexpr reference operator[](size_type idx) const noexcept
{ {
Expects(idx < size()); Expects(idx < size(), Bounds);
return data()[idx]; return data()[idx];
} }
constexpr reference front() const noexcept constexpr reference front() const noexcept
{ {
Expects(size() > 0); Expects(size() > 0, Bounds);
return data()[0]; return data()[0];
} }
constexpr reference back() const noexcept constexpr reference back() const noexcept
{ {
Expects(size() > 0); Expects(size() > 0, Bounds);
return data()[size() - 1]; return data()[size() - 1];
} }
@ -688,14 +688,14 @@ private:
constexpr storage_type(KnownNotNull data, OtherExtentType ext) constexpr storage_type(KnownNotNull data, OtherExtentType ext)
: ExtentType(ext), data_(data.p) : ExtentType(ext), data_(data.p)
{ {
Expects(ExtentType::size() != dynamic_extent); Expects(ExtentType::size() != dynamic_extent, Bounds);
} }
template <class OtherExtentType> template <class OtherExtentType>
constexpr storage_type(pointer data, OtherExtentType ext) : ExtentType(ext), data_(data) constexpr storage_type(pointer data, OtherExtentType ext) : ExtentType(ext), data_(data)
{ {
Expects(ExtentType::size() != dynamic_extent); Expects(ExtentType::size() != dynamic_extent, Bounds);
Expects(data || ExtentType::size() == 0); Expects(data || ExtentType::size() == 0, Bounds);
} }
constexpr pointer data() const noexcept { return data_; } constexpr pointer data() const noexcept { return data_; }
@ -729,11 +729,11 @@ private:
constexpr span<element_type, dynamic_extent> constexpr span<element_type, dynamic_extent>
make_subspan(size_type offset, size_type count, subspan_selector<dynamic_extent>) const noexcept make_subspan(size_type offset, size_type count, subspan_selector<dynamic_extent>) const noexcept
{ {
Expects(size() >= offset); Expects(size() >= offset, Bounds);
if (count == dynamic_extent) { return {KnownNotNull{data() + offset}, size() - offset}; } if (count == dynamic_extent) { return {KnownNotNull{data() + offset}, size() - offset}; }
Expects(size() - offset >= count); Expects(size() - offset >= count, Bounds);
return {KnownNotNull{data() + offset}, count}; return {KnownNotNull{data() + offset}, count};
} }
}; };

View File

@ -124,7 +124,7 @@ template <class ElementType, std::size_t Extent>
constexpr ElementType& at(span<ElementType, Extent> s, index i) constexpr ElementType& at(span<ElementType, Extent> s, index i)
{ {
// No bounds checking here because it is done in span::operator[] called below // No bounds checking here because it is done in span::operator[] called below
Ensures(i >= 0); Ensures(i >= 0, Bounds);
return s[narrow_cast<std::size_t>(i)]; return s[narrow_cast<std::size_t>(i)];
} }

View File

@ -17,7 +17,7 @@
#ifndef GSL_STRING_SPAN_H #ifndef GSL_STRING_SPAN_H
#define GSL_STRING_SPAN_H #define GSL_STRING_SPAN_H
#include <gsl/assert> // for Ensures, Expects #include <gsl/assert> // for contracts
#include <gsl/span_ext> // for operator!=, operator==, dynamic_extent #include <gsl/span_ext> // for operator!=, operator==, dynamic_extent
#include <gsl/util> // for narrow_cast #include <gsl/util> // for narrow_cast
@ -114,19 +114,19 @@ template <typename T, const T Sentinel>
"isocpp/CppCoreGuidelines PR#1680")]] constexpr span<T, dynamic_extent> "isocpp/CppCoreGuidelines PR#1680")]] constexpr span<T, dynamic_extent>
ensure_sentinel(T* seq, std::size_t max = static_cast<std::size_t>(-1)) ensure_sentinel(T* seq, std::size_t max = static_cast<std::size_t>(-1))
{ {
Ensures(seq != nullptr); Ensures(seq != nullptr, Null);
// clang-format off // clang-format off
GSL_SUPPRESS(f.23) // TODO: false positive // TODO: suppress does not work GSL_SUPPRESS(f.23) // TODO: false positive // TODO: suppress does not work
// clang-format on // clang-format on
auto cur = seq; auto cur = seq;
Ensures(cur != nullptr); // workaround for removing the warning Ensures(cur != nullptr, Null); // workaround for removing the warning
// clang-format off // clang-format off
GSL_SUPPRESS(bounds.1) // TODO: suppress does not work GSL_SUPPRESS(bounds.1) // TODO: suppress does not work
// clang-format on // clang-format on
while (static_cast<std::size_t>(cur - seq) < max && *cur != Sentinel) ++cur; while (static_cast<std::size_t>(cur - seq) < max && *cur != Sentinel) ++cur;
Ensures(*cur == Sentinel); Ensures(*cur == Sentinel, Bounds);
return {seq, static_cast<std::size_t>(cur - seq)}; return {seq, static_cast<std::size_t>(cur - seq)};
} }
@ -437,8 +437,8 @@ public:
constexpr basic_zstring_span(impl_type s) : span_(s) constexpr basic_zstring_span(impl_type s) : span_(s)
{ {
// expects a zero-terminated span // expects a zero-terminated span
Expects(s.size() > 0); Expects(s.size() > 0, Bounds);
Expects(s[s.size() - 1] == value_type{}); Expects(s[s.size() - 1] == value_type{}, Bounds);
} }
// copy // copy

View File

@ -17,7 +17,7 @@
#ifndef GSL_UTIL_H #ifndef GSL_UTIL_H
#define GSL_UTIL_H #define GSL_UTIL_H
#include <gsl/assert> // for Expects #include <gsl/assert> // for contracts
#include <array> #include <array>
#include <cstddef> // for ptrdiff_t, size_t #include <cstddef> // for ptrdiff_t, size_t
@ -108,7 +108,7 @@ GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute
// clang-format on // clang-format on
constexpr T& at(T (&arr)[N], const index i) constexpr T& at(T (&arr)[N], const index i)
{ {
Expects(i >= 0 && i < narrow_cast<index>(N)); Expects(i >= 0 && i < narrow_cast<index>(N), Bounds);
return arr[narrow_cast<std::size_t>(i)]; return arr[narrow_cast<std::size_t>(i)];
} }
@ -119,7 +119,7 @@ GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute
// clang-format on // clang-format on
constexpr auto at(Cont& cont, const index i) -> decltype(cont[cont.size()]) constexpr auto at(Cont& cont, const index i) -> decltype(cont[cont.size()])
{ {
Expects(i >= 0 && i < narrow_cast<index>(cont.size())); Expects(i >= 0 && i < narrow_cast<index>(cont.size()), Bounds);
using size_type = decltype(cont.size()); using size_type = decltype(cont.size());
return cont[narrow_cast<size_type>(i)]; return cont[narrow_cast<size_type>(i)];
} }
@ -130,7 +130,7 @@ GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
// clang-format on // clang-format on
constexpr T at(const std::initializer_list<T> cont, const index i) constexpr T at(const std::initializer_list<T> cont, const index i)
{ {
Expects(i >= 0 && i < narrow_cast<index>(cont.size())); Expects(i >= 0 && i < narrow_cast<index>(cont.size()), Bounds);
return *(cont.begin() + i); return *(cont.begin() + i);
} }

View File

@ -15,7 +15,7 @@
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <gsl/assert> // for fail_fast (ptr only), Ensures, Expects #include <gsl/assert> // for fail_fast (ptr only), contracts
using namespace gsl; using namespace gsl;
@ -25,14 +25,14 @@ static constexpr char deathstring[] = "Expected Death";
int f(int i) int f(int i)
{ {
Expects(i > 0 && i < 10); Expects(i > 0 && i < 10, Testing);
return i; return i;
} }
int g(int i) int g(int i)
{ {
i++; i++;
Ensures(i > 0 && i < 10); Ensures(i > 0 && i < 10, Testing);
return i; return i;
} }
} // namespace } // namespace

View File

@ -16,7 +16,7 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <gsl/assert> // for Expects, fail_fast (ptr only) #include <gsl/assert> // for contracts, fail_fast (ptr only)
#include <gsl/pointers> // for owner #include <gsl/pointers> // for owner
#include <gsl/span> // for span, dynamic_extent #include <gsl/span> // for span, dynamic_extent
#include <gsl/string_span> // for basic_string_span, operator==, ensure_z #include <gsl/string_span> // for basic_string_span, operator==, ensure_z
@ -82,7 +82,7 @@ void use(basic_string_span<T, gsl::dynamic_extent>)
czstring_span<> CreateTempName(string_span<> span) czstring_span<> CreateTempName(string_span<> span)
{ {
Expects(span.size() > 1); Expects(span.size() > 1, Testing);
std::size_t last = 0; std::size_t last = 0;
if (span.size() > 4) { if (span.size() > 4) {
@ -99,7 +99,7 @@ czstring_span<> CreateTempName(string_span<> span)
cwzstring_span<> CreateTempNameW(wstring_span<> span) cwzstring_span<> CreateTempNameW(wstring_span<> span)
{ {
Expects(span.size() > 1); Expects(span.size() > 1, Testing);
std::size_t last = 0; std::size_t last = 0;
if (span.size() > 4) { if (span.size() > 4) {
@ -116,7 +116,7 @@ cwzstring_span<> CreateTempNameW(wstring_span<> span)
cu16zstring_span<> CreateTempNameU16(u16string_span<> span) cu16zstring_span<> CreateTempNameU16(u16string_span<> span)
{ {
Expects(span.size() > 1); Expects(span.size() > 1, Testing);
std::size_t last = 0; std::size_t last = 0;
if (span.size() > 4) { if (span.size() > 4) {
@ -133,7 +133,7 @@ cu16zstring_span<> CreateTempNameU16(u16string_span<> span)
cu32zstring_span<> CreateTempNameU32(u32string_span<> span) cu32zstring_span<> CreateTempNameU32(u32string_span<> span)
{ {
Expects(span.size() > 1); Expects(span.size() > 1, Testing);
std::size_t last = 0; std::size_t last = 0;
if (span.size() > 4) { if (span.size() > 4) {