Merge pull request #206 from neilmacintosh/dev/neilmac/contracts

Rework contract enforcement macros and use everywhere.
This commit is contained in:
Neil MacIntosh 2015-11-20 17:26:17 -08:00
commit 3dfda0cfde
6 changed files with 174 additions and 145 deletions

View File

@ -1,55 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
//
// This code is licensed under the MIT License (MIT).
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
///////////////////////////////////////////////////////////////////////////////
#pragma once
#ifndef GSL_FAIL_FAST_H
#define GSL_FAIL_FAST_H
#include <exception>
#if defined(GSL_THROWS_FOR_TESTING)
#include <stdexcept>
#endif
namespace gsl
{
//
// Having "fail fast" result in an exception makes unit testing
// the GSL classes that rely upon it much simpler.
//
#if defined(GSL_THROWS_FOR_TESTING)
struct fail_fast : public std::runtime_error
{
fail_fast() : std::runtime_error("") {}
explicit fail_fast(char const* const message) : std::runtime_error(message) {}
};
inline void fail_fast_assert(bool cond) { if (!cond) throw fail_fast(); }
inline void fail_fast_assert(bool cond, const char* const message) { if (!cond) throw fail_fast(message); }
#else
inline void fail_fast_assert(bool cond) { if (!cond) std::terminate(); }
inline void fail_fast_assert(bool cond, const char* const) { if (!cond) std::terminate(); }
#endif // GSL_THROWS_FOR_TESTING
}
#endif // GSL_FAIL_FAST_H

View File

@ -19,6 +19,7 @@
#ifndef GSL_GSL_H
#define GSL_GSL_H
#include "gsl_assert.h" // Ensures/Expects
#include "span.h" // span, strided_span...
#include "string_span.h" // zstring, string_span, zstring_builder...
#include <memory>
@ -27,15 +28,13 @@
// No MSVC does constexpr fully yet
#pragma push_macro("constexpr")
#define constexpr /* nothing */
#define constexpr
// MSVC 2013 workarounds
#if _MSC_VER <= 1800
// noexcept is not understood
#ifndef GSL_THROWS_FOR_TESTING
#define noexcept /* nothing */
#endif
#pragma push_macro("noexcept")
#define noexcept
// turn off some misguided warnings
#pragma warning(push)
@ -45,11 +44,6 @@
#endif // _MSC_VER
// In order to test the library, we need it to throw exceptions that we can catch
#ifdef GSL_THROWS_FOR_TESTING
#define noexcept /* nothing */
#endif // GSL_THROWS_FOR_TESTING
namespace gsl
{
@ -63,12 +57,6 @@ using std::shared_ptr;
template <class T>
using owner = T;
//
// GSL.assert: assertions
//
#define Expects(x) gsl::fail_fast_assert((x))
#define Ensures(x) gsl::fail_fast_assert((x))
//
// GSL.util: utilities
//
@ -110,14 +98,14 @@ T narrow(U u) { T t = narrow_cast<T>(u); if (static_cast<U>(t) != u) throw narro
//
// at() - Bounds-checked way of accessing static arrays, std::array, std::vector
//
template <class T, size_t N>
T& at(T(&arr)[N], size_t index) { fail_fast_assert(index < N); return arr[index]; }
template <class T, size_t N>
T& at(T(&arr)[N], size_t index) { Expects(index < N); return arr[index]; }
template <class T, size_t N>
T& at(std::array<T, N>& arr, size_t index) { fail_fast_assert(index < N); return arr[index]; }
T& at(std::array<T, N>& arr, size_t index) { Expects(index < N); return arr[index]; }
template <class Cont>
typename Cont::value_type& at(Cont& cont, size_t index) { fail_fast_assert(index < cont.size()); return cont[index]; }
typename Cont::value_type& at(Cont& cont, size_t index) { Expects(index < cont.size()); return cont[index]; }
//
@ -181,7 +169,7 @@ private:
// we assume that the compiler can hoist/prove away most of the checks inlined from this function
// if not, we could make them optional via conditional compilation
void ensure_invariant() const { fail_fast_assert(ptr_ != nullptr); }
void ensure_invariant() const { Expects(ptr_ != nullptr); }
// unwanted operators...pointers only point to single objects!
// TODO ensure all arithmetic ops on this type are unavailable
@ -216,18 +204,14 @@ namespace std
#pragma pop_macro("constexpr")
#if _MSC_VER <= 1800
#pragma warning(pop)
#ifndef GSL_THROWS_FOR_TESTING
#undef noexcept
#endif // GSL_THROWS_FOR_TESTING
#pragma pop_macro("noexcept")
#pragma warning(pop)
#endif // _MSC_VER <= 1800
#endif // _MSC_VER
#if defined(GSL_THROWS_FOR_TESTING)
#undef noexcept
#endif // GSL_THROWS_FOR_TESTING
#endif // GSL_GSL_H

78
include/gsl_assert.h Normal file
View File

@ -0,0 +1,78 @@
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
//
// This code is licensed under the MIT License (MIT).
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
///////////////////////////////////////////////////////////////////////////////
#pragma once
#ifndef GSL_CONTRACTS_H
#define GSL_CONTRACTS_H
#include <exception>
//
// There are three configuration options for this GSL implementation's behavior
// when pre/post conditions on the GSL types are violated:
//
// 1. GSL_TERMINATE_ON_CONTRACT_VIOLATION: std::terminate will be called (default)
// 2. GSL_THROW_ON_CONTRACT_VIOLATION: a gsl::fail_fast exception will be thrown
// 3. GSL_UNENFORCED_ON_CONTRACT_VIOLATION: nothing happens
//
#if !(defined(GSL_THROW_ON_CONTRACT_VIOLATION) ^ defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION) ^ defined(GSL_UNENFORCED_ON_CONTRACT_VIOLATION))
#define GSL_TERMINATE_ON_CONTRACT_VIOLATION
#endif
#define GSL_STRINGIFY_DETAIL(x) #x
#define GSL_STRINGIFY(x) GSL_STRINGIFY_DETAIL(x)
//
// GSL.assert: assertions
//
#if defined(GSL_THROW_ON_CONTRACT_VIOLATION)
#include <stdexcept>
namespace gsl
{
struct fail_fast : public std::runtime_error
{
explicit fail_fast(char const* const message) : std::runtime_error(message) {}
};
}
#define Expects(cond) if (!(cond)) \
throw gsl::fail_fast("GSL: Precondition failure at " __FILE__ GSL_STRINGIFY(__LINE__));
#define Ensures(cond) if (!(cond)) \
throw gsl::fail_fast("GSL: Postcondition failure at " __FILE__ GSL_STRINGIFY(__LINE__));
#elif defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION)
#define Expects(cond) if (!(cond)) std::terminate();
#define Ensures(cond) if (!(cond)) std::terminate();
#elif defined(GSL_UNENFORCED_ON_CONTRACT_VIOLATION)
#define Expects(cond)
#define Ensures(cond)
#endif
#endif // GSL_CONTRACTS_H

View File

@ -31,13 +31,18 @@
#include <stdexcept>
#include <type_traits>
#include <utility>
#include "fail_fast.h"
#include <cassert>
#include "gsl_assert.h"
#ifdef _MSC_VER
// turn off some warnings that are noisy about our Expects statements
#pragma warning(push)
#pragma warning(disable: 4127) // conditional expression is constant
// No MSVC does constexpr fully yet
#pragma push_macro("constexpr")
#define constexpr /* nothing */
#define constexpr
// VS 2013 workarounds
#if _MSC_VER <= 1800
@ -46,7 +51,7 @@
#define GSL_MSVC_HAS_VARIADIC_CTOR_BUG
// noexcept is not understood
#ifndef GSL_THROWS_FOR_TESTING
#ifndef GSL_THROWS_ON_CONTRACT_VIOLATION
#pragma push_macro("noexcept")
#define noexcept /* nothing */
#endif
@ -60,8 +65,7 @@
#endif // _MSC_VER
// In order to test the library, we need it to throw exceptions that we can catch
#ifdef GSL_THROWS_FOR_TESTING
#ifdef GSL_THROW_ON_CONTRACT_VIOLATION
#ifdef _MSC_VER
#pragma push_macro("noexcept")
@ -69,7 +73,7 @@
#define noexcept /* nothing */
#endif // GSL_THROWS_FOR_TESTING
#endif // GSL_THROW_ON_CONTRACT_VIOLATION
namespace gsl {
@ -137,14 +141,14 @@ public:
// Preconditions: component_idx < rank
constexpr reference operator[](size_t component_idx)
{
fail_fast_assert(component_idx < Rank, "Component index must be less than rank");
Expects(component_idx < Rank); // Component index must be less than rank
return elems[component_idx];
}
// Preconditions: component_idx < rank
constexpr const_reference operator[](size_t component_idx) const noexcept
{
fail_fast_assert(component_idx < Rank, "Component index must be less than rank");
Expects(component_idx < Rank); // Component index must be less than rank
return elems[component_idx];
}
@ -344,7 +348,7 @@ namespace details
BoundsRanges(const std::ptrdiff_t* const arr) : Base(arr + 1), m_bound(*arr * this->Base::totalSize())
{
fail_fast_assert(0 <= *arr);
Expects(0 <= *arr);
}
BoundsRanges() : m_bound(0) {}
@ -365,7 +369,7 @@ namespace details
size_type linearize(const T& arr) const
{
const size_type index = this->Base::totalSize() * arr[Dim];
fail_fast_assert(index < m_bound);
Expects(index < m_bound);
return index + this->Base::template linearize<T, Dim + 1>(arr);
}
@ -419,8 +423,9 @@ namespace details
template <std::ptrdiff_t OtherRange, std::ptrdiff_t... RestOtherRanges>
BoundsRanges(const BoundsRanges<OtherRange, RestOtherRanges...>&other, bool firstLevel = true) : Base(static_cast<const BoundsRanges<RestOtherRanges...>&>(other), false)
{
fail_fast_assert((firstLevel && totalSize() <= other.totalSize()) || totalSize() == other.totalSize());
{
Expects((firstLevel && totalSize() <= other.totalSize()) || totalSize() == other.totalSize());
(void)firstLevel;
}
template <typename T, size_t Dim = 0>
@ -433,7 +438,7 @@ namespace details
template <typename T, size_t Dim = 0>
size_type linearize(const T& arr) const
{
fail_fast_assert(arr[Dim] < CurrentRange, "Index is out of range");
Expects(arr[Dim] < CurrentRange); // Index is out of range
return this->Base::totalSize() * arr[Dim] + this->Base::template linearize<T, Dim + 1>(arr);
}
@ -584,8 +589,10 @@ public:
constexpr static_bounds(std::initializer_list<size_type> il) : m_ranges((const std::ptrdiff_t*)il.begin())
{
fail_fast_assert((MyRanges::DynamicNum == 0 && il.size() == 1 && *il.begin() == static_size) || MyRanges::DynamicNum == il.size(), "Size of the initializer list must match the rank of the array");
fail_fast_assert(m_ranges.totalSize() <= PTRDIFF_MAX, "Size of the range is larger than the max element of the size type");
// Size of the initializer list must match the rank of the array
Expects((MyRanges::DynamicNum == 0 && il.size() == 1 && *il.begin() == static_size) || MyRanges::DynamicNum == il.size());
// Size of the range must be less than the max element of the size type
Expects(m_ranges.totalSize() <= PTRDIFF_MAX);
}
constexpr static_bounds() = default;
@ -742,7 +749,7 @@ public:
size_type ret = 0;
for (size_t i = 0; i < rank; i++)
{
fail_fast_assert(idx[i] < m_extents[i], "index is out of bounds of the array");
Expects(idx[i] < m_extents[i]); // index is out of bounds of the array
ret += idx[i] * m_strides[i];
}
return ret;
@ -868,7 +875,7 @@ public:
}
// If we're here the preconditions were violated
// "pre: there exists s such that r == ++s"
fail_fast_assert(false);
Expects(false);
return *this;
}
@ -899,7 +906,8 @@ public:
curr[i] = linear_idx / stride[i];
linear_idx = linear_idx % stride[i];
}
fail_fast_assert(!less(curr, index_type{}) && !less(boundary, curr), "index is out of bounds of the array");
//index is out of bounds of the array
Expects(!less(curr, index_type{}) && !less(boundary, curr));
return *this;
}
@ -1038,7 +1046,7 @@ namespace details
static_assert(is_bounds<BoundsSrc>::value && is_bounds<BoundsDest>::value, "The src type and dest type must be bounds");
static_assert(std::is_same<typename BoundsSrc::mapping_type, contiguous_mapping_tag>::value, "The source type must be a contiguous bounds");
static_assert(BoundsDest::static_size == dynamic_range || BoundsSrc::static_size == dynamic_range || BoundsDest::static_size == BoundsSrc::static_size, "The source bounds must have same size as dest bounds");
fail_fast_assert(src.size() == dest.size());
Expects(src.size() == dest.size());
}
@ -1099,13 +1107,13 @@ namespace details
template <typename BoundsType>
BoundsType newBoundsHelperImpl(std::ptrdiff_t totalSize, std::true_type) // dynamic size
{
fail_fast_assert(totalSize <= PTRDIFF_MAX);
Expects(totalSize <= PTRDIFF_MAX);
return BoundsType{totalSize};
}
template <typename BoundsType>
BoundsType newBoundsHelperImpl(std::ptrdiff_t totalSize, std::false_type) // static size
{
fail_fast_assert(BoundsType::static_size == totalSize);
Expects(BoundsType::static_size == totalSize);
return {};
}
template <typename BoundsType>
@ -1192,7 +1200,7 @@ public:
constexpr span(pointer data, bounds_type bounds) noexcept
: m_pdata(data), m_bounds(std::move(bounds))
{
fail_fast_assert((m_bounds.size() > 0 && data != nullptr) || m_bounds.size() == 0);
Expects((m_bounds.size() > 0 && data != nullptr) || m_bounds.size() == 0);
}
constexpr span(pointer ptr, size_type size) noexcept
@ -1206,7 +1214,7 @@ public:
constexpr span(std::nullptr_t, size_type size) noexcept
: span(nullptr, bounds_type{})
{
fail_fast_assert(size == 0);
Expects(size == 0);
}
// default
@ -1236,7 +1244,7 @@ public:
>
constexpr span(T(&arr)[N], size_type size) : span(arr, typename Helper::bounds_type{size})
{
fail_fast_assert(size <= N);
Expects(size <= N);
}
// from std array
@ -1313,7 +1321,7 @@ public:
{
static_assert(std::is_standard_layout<U>::value && (bounds_type::static_size == dynamic_range || bounds_type::static_size % static_cast<size_type>(sizeof(U)) == 0),
"Target type must be standard layout and its size must match the byte array size");
fail_fast_assert((this->bytes() % sizeof(U)) == 0 && (this->bytes() / sizeof(U)) < PTRDIFF_MAX);
Expects((this->bytes() % sizeof(U)) == 0 && (this->bytes() / sizeof(U)) < PTRDIFF_MAX);
return { reinterpret_cast<const U*>(this->data()), this->bytes() / static_cast<size_type>(sizeof(U)) };
}
@ -1322,7 +1330,7 @@ public:
{
static_assert(std::is_standard_layout<U>::value && (bounds_type::static_size == dynamic_range || bounds_type::static_size % static_cast<size_t>(sizeof(U)) == 0),
"Target type must be standard layout and its size must match the byte array size");
fail_fast_assert((this->bytes() % sizeof(U)) == 0);
Expects((this->bytes() % sizeof(U)) == 0);
return { reinterpret_cast<U*>(this->data()), this->bytes() / static_cast<size_type>(sizeof(U)) };
}
@ -1331,13 +1339,13 @@ public:
constexpr span<ValueType, Count> first() const noexcept
{
static_assert(bounds_type::static_size == dynamic_range || Count <= bounds_type::static_size, "Index is out of bound");
fail_fast_assert(bounds_type::static_size != dynamic_range || Count <= this->size()); // ensures we only check condition when needed
Expects(bounds_type::static_size != dynamic_range || Count <= this->size());
return { this->data(), Count };
}
constexpr span<ValueType, dynamic_range> first(size_type count) const noexcept
{
fail_fast_assert(count <= this->size());
Expects(count <= this->size());
return { this->data(), count };
}
@ -1345,13 +1353,13 @@ public:
constexpr span<ValueType, Count> last() const noexcept
{
static_assert(bounds_type::static_size == dynamic_range || Count <= bounds_type::static_size, "Index is out of bound");
fail_fast_assert(bounds_type::static_size != dynamic_range || Count <= this->size());
Expects(bounds_type::static_size != dynamic_range || Count <= this->size());
return { this->data() + this->size() - Count, Count };
}
constexpr span<ValueType, dynamic_range> last(size_type count) const noexcept
{
fail_fast_assert(count <= this->size());
Expects(count <= this->size());
return { this->data() + this->size() - count, count };
}
@ -1359,13 +1367,13 @@ public:
constexpr span<ValueType, Count> sub() const noexcept
{
static_assert(bounds_type::static_size == dynamic_range || ((Offset == 0 || Offset <= bounds_type::static_size) && Offset + Count <= bounds_type::static_size), "Index is out of bound");
fail_fast_assert(bounds_type::static_size != dynamic_range || ((Offset == 0 || Offset <= this->size()) && Offset + Count <= this->size()));
Expects(bounds_type::static_size != dynamic_range || ((Offset == 0 || Offset <= this->size()) && Offset + Count <= this->size()));
return { this->data() + Offset, Count };
}
constexpr span<ValueType, dynamic_range> sub(size_type offset, size_type count = dynamic_range) const noexcept
{
fail_fast_assert((offset == 0 || offset <= this->size()) && (count == dynamic_range || (offset + count) <= this->size()));
Expects((offset == 0 || offset <= this->size()) && (count == dynamic_range || (offset + count) <= this->size()));
return { this->data() + offset, count == dynamic_range ? this->length() - offset : count };
}
@ -1405,10 +1413,11 @@ public:
template <bool Enabled = (rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
constexpr Ret operator[](size_type idx) const noexcept
{
fail_fast_assert(idx < m_bounds.size(), "index is out of bounds of the array");
Expects(idx < m_bounds.size()); // index is out of bounds of the array
const size_type ridx = idx * m_bounds.stride();
fail_fast_assert(ridx < m_bounds.total_size(), "index is out of bounds of the underlying data");
// index is out of bounds of the underlying data
Expects(ridx < m_bounds.total_size());
return Ret{ m_pdata + ridx, m_bounds.slice() };
}
@ -1560,7 +1569,7 @@ template <typename Cont>
constexpr auto as_span(Cont &arr) -> std::enable_if_t<!details::is_span<std::decay_t<Cont>>::value,
span<std::remove_reference_t<decltype(arr.size(), *arr.data())>, dynamic_range>>
{
fail_fast_assert(arr.size() < PTRDIFF_MAX);
Expects(arr.size() < PTRDIFF_MAX);
return {arr.data(), static_cast<std::ptrdiff_t>(arr.size())};
}
@ -1572,7 +1581,7 @@ constexpr auto as_span(Cont &&arr) -> std::enable_if_t<!details::is_span<std::de
template <typename CharT, typename Traits, typename Allocator>
constexpr auto as_span(std::basic_string<CharT, Traits, Allocator> &str) -> span<CharT, dynamic_range>
{
fail_fast_assert(str.size() < PTRDIFF_MAX);
Expects(str.size() < PTRDIFF_MAX);
return {&str[0], static_cast<std::ptrdiff_t>(str.size())};
}
@ -1608,8 +1617,10 @@ public:
constexpr strided_span(pointer ptr, size_type size, bounds_type bounds)
: m_pdata(ptr), m_bounds(std::move(bounds))
{
fail_fast_assert((m_bounds.size() > 0 && ptr != nullptr) || m_bounds.size() == 0);
fail_fast_assert(this->bounds().total_size() <= size, "Bounds cross data boundaries");
Expects((m_bounds.size() > 0 && ptr != nullptr) || m_bounds.size() == 0);
// Bounds cross data boundaries
Expects(this->bounds().total_size() <= size);
(void)size;
}
// from static array of size N
@ -1659,10 +1670,11 @@ public:
template <bool Enabled = (Rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
constexpr Ret operator[](size_type idx) const
{
fail_fast_assert(idx < m_bounds.size(), "index is out of bounds of the array");
Expects(idx < m_bounds.size()); // index is out of bounds of the array
const size_type ridx = idx * m_bounds.stride();
fail_fast_assert(ridx < m_bounds.total_size(), "index is out of bounds of the underlying data");
// index is out of bounds of the underlying data
Expects(ridx < m_bounds.total_size());
return{ m_pdata + ridx, m_bounds.slice().total_size(), m_bounds.slice() };
}
@ -1773,7 +1785,8 @@ public:
private:
static index_type resize_extent(const index_type& extent, std::ptrdiff_t d)
{
fail_fast_assert(extent[Rank - 1] >= d && (extent[Rank-1] % d == 0), "The last dimension of the array needs to contain a multiple of new type elements");
// The last dimension of the array needs to contain a multiple of new type elements
Expects(extent[Rank - 1] >= d && (extent[Rank - 1] % d == 0));
index_type ret = extent;
ret[Rank - 1] /= d;
@ -1784,7 +1797,8 @@ private:
template <bool Enabled = (Rank == 1), typename Dummy = std::enable_if_t<Enabled>>
static index_type resize_stride(const index_type& strides, std::ptrdiff_t , void * = 0)
{
fail_fast_assert(strides[Rank - 1] == 1, "Only strided arrays with regular strides can be resized");
// Only strided arrays with regular strides can be resized
Expects(strides[Rank - 1] == 1);
return strides;
}
@ -1792,12 +1806,16 @@ private:
template <bool Enabled = (Rank > 1), typename Dummy = std::enable_if_t<Enabled>>
static index_type resize_stride(const index_type& strides, std::ptrdiff_t d)
{
fail_fast_assert(strides[Rank - 1] == 1, "Only strided arrays with regular strides can be resized");
fail_fast_assert(strides[Rank - 2] >= d && (strides[Rank - 2] % d == 0), "The strides must have contiguous chunks of memory that can contain a multiple of new type elements");
// Only strided arrays with regular strides can be resized
Expects(strides[Rank - 1] == 1);
// The strides must have contiguous chunks of
// memory that can contain a multiple of new type elements
Expects(strides[Rank - 2] >= d && (strides[Rank - 2] % d == 0));
for (size_t i = Rank - 1; i > 0; --i)
{
fail_fast_assert((strides[i - 1] >= strides[i]) && (strides[i - 1] % strides[i] == 0), "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));
}
index_type ret = strides / d;
@ -1824,7 +1842,9 @@ private:
const Span* m_validator;
void validateThis() const
{
fail_fast_assert(m_pdata >= m_validator->m_pdata && m_pdata < m_validator->m_pdata + m_validator->size(), "iterator is out of range of the array");
// iterator is out of range of the array
Expects(m_pdata >= m_validator->m_pdata &&
m_pdata < m_validator->m_pdata + m_validator->size());
}
contiguous_span_iterator (const Span* container, bool isbegin) :
m_pdata(isbegin ? container->m_pdata : container->m_pdata + container->size()), m_validator(container) {}
@ -1882,7 +1902,7 @@ public:
}
difference_type operator-(const contiguous_span_iterator& rhs) const noexcept
{
fail_fast_assert(m_validator == rhs.m_validator);
Expects(m_validator == rhs.m_validator);
return m_pdata - rhs.m_pdata;
}
reference operator[](difference_type n) const noexcept
@ -1891,7 +1911,7 @@ public:
}
bool operator==(const contiguous_span_iterator& rhs) const noexcept
{
fail_fast_assert(m_validator == rhs.m_validator);
Expects(m_validator == rhs.m_validator);
return m_pdata == rhs.m_pdata;
}
bool operator!=(const contiguous_span_iterator& rhs) const noexcept
@ -1900,7 +1920,7 @@ public:
}
bool operator<(const contiguous_span_iterator& rhs) const noexcept
{
fail_fast_assert(m_validator == rhs.m_validator);
Expects(m_validator == rhs.m_validator);
return m_pdata < rhs.m_pdata;
}
bool operator<=(const contiguous_span_iterator& rhs) const noexcept
@ -1998,7 +2018,7 @@ public:
}
difference_type operator-(const general_span_iterator& rhs) const noexcept
{
fail_fast_assert(m_container == rhs.m_container);
Expects(m_container == rhs.m_container);
return m_itr - rhs.m_itr;
}
value_type operator[](difference_type n) const noexcept
@ -2007,7 +2027,7 @@ public:
}
bool operator==(const general_span_iterator& rhs) const noexcept
{
fail_fast_assert(m_container == rhs.m_container);
Expects(m_container == rhs.m_container);
return m_itr == rhs.m_itr;
}
bool operator !=(const general_span_iterator& rhs) const noexcept
@ -2016,7 +2036,7 @@ public:
}
bool operator<(const general_span_iterator& rhs) const noexcept
{
fail_fast_assert(m_container == rhs.m_container);
Expects(m_container == rhs.m_container);
return m_itr < rhs.m_itr;
}
bool operator<=(const general_span_iterator& rhs) const noexcept
@ -2055,10 +2075,10 @@ general_span_iterator<Span> operator+(typename general_span_iterator<Span>::diff
#if _MSC_VER <= 1800
#pragma warning(pop)
#ifndef GSL_THROWS_FOR_TESTING
#ifndef GSL_THROW_ON_CONTRACT_VIOLATION
#undef noexcept
#pragma pop_macro("noexcept")
#endif // GSL_THROWS_FOR_TESTING
#endif // GSL_THROW_ON_CONTRACT_VIOLATION
#undef GSL_MSVC_HAS_VARIADIC_CTOR_BUG
@ -2066,15 +2086,16 @@ general_span_iterator<Span> operator+(typename general_span_iterator<Span>::diff
#endif // _MSC_VER
#if defined(GSL_THROWS_FOR_TESTING)
#if defined(GSL_THROW_ON_CONTRACT_VIOLATION)
#undef noexcept
#ifdef _MSC_VER
#pragma warning(pop)
#pragma pop_macro("noexcept")
#endif
#endif // GSL_THROWS_FOR_TESTING
#endif // GSL_THROW_ON_CONTRACT_VIOLATION
#endif // GSL_SPAN_H

View File

@ -19,6 +19,7 @@
#ifndef GSL_STRING_SPAN_H
#define GSL_STRING_SPAN_H
#include "gsl_assert.h"
#include "span.h"
#include <cstring>
@ -89,7 +90,7 @@ span<T, dynamic_range> ensure_sentinel(const T* seq, std::ptrdiff_t max = PTRDIF
{
auto cur = seq;
while ((cur - seq) < max && *cur != Sentinel) ++cur;
fail_fast_assert(*cur == Sentinel);
Ensures(*cur == Sentinel);
return{ seq, cur - seq };
}
@ -109,26 +110,26 @@ inline basic_string_span<T, dynamic_range> ensure_z(T* const & sz, std::ptrdiff_
inline basic_string_span<char, dynamic_range> ensure_z(char* const& sz, std::ptrdiff_t max)
{
auto len = strnlen(sz, max);
fail_fast_assert(sz[len] == 0);
Ensures(sz[len] == 0);
return{ sz, static_cast<std::ptrdiff_t>(len) };
}
inline basic_string_span<const char, dynamic_range> ensure_z(const char* const& sz, std::ptrdiff_t max)
{
auto len = strnlen(sz, max);
fail_fast_assert(sz[len] == 0); return{ sz, static_cast<std::ptrdiff_t>(len) };
Ensures(sz[len] == 0); return{ sz, static_cast<std::ptrdiff_t>(len) };
}
inline basic_string_span<wchar_t, dynamic_range> ensure_z(wchar_t* const& sz, std::ptrdiff_t max)
{
auto len = wcsnlen(sz, max);
fail_fast_assert(sz[len] == 0); return{ sz, static_cast<std::ptrdiff_t>(len) };
Ensures(sz[len] == 0); return{ sz, static_cast<std::ptrdiff_t>(len) };
}
inline basic_string_span<const wchar_t, dynamic_range> ensure_z(const wchar_t* const& sz, std::ptrdiff_t max)
{
auto len = wcsnlen(sz, max);
fail_fast_assert(sz[len] == 0); return{ sz, static_cast<std::ptrdiff_t>(len) };
Ensures(sz[len] == 0); return{ sz, static_cast<std::ptrdiff_t>(len) };
}
template<class T, size_t N>

View File

@ -9,7 +9,7 @@ include_directories(
./unittest-cpp
)
add_definitions(-DGSL_THROWS_FOR_TESTING)
add_definitions(-DGSL_THROW_ON_CONTRACT_VIOLATION)
if(MSVC14 OR MSVC12) # has the support we need
# remove unnecessary warnings about unchecked iterators