Compare commits

...

28 Commits

Author SHA1 Message Date
Herb Sutter 882720bd73 Changed default to per-TU violation handlers
And removed the feature test macro to instead tgest for a specific C++ version.
2021-01-27 16:36:59 -08:00
Herb Sutter 81c10b8017 normalize is a more accurate name than sanitize 2020-12-22 17:04:07 -08:00
Herb Sutter 0b80ac7d02 gsl/assert cleanup
Removed unnecessary headers
Added missing const
2020-12-19 12:58:31 -08:00
Herb Sutter e269976910 Added inline variable support 2020-12-18 13:16:40 -08:00
Herb Sutter 60beb7a363 Fixed the default
Accidentally flipped on the previous commit
2020-12-18 12:53:36 -08:00
Herb Sutter d5fc4efbf6 Turn off GCC bounds checking for the tests where we intentionally test out of bounds 2020-12-18 12:48:15 -08:00
Herb Sutter 25c0dee6e3 Reinstance the GSL_*_ON_CONTRACT_VIOLATION macros
At least the nonthrowing ones
2020-12-18 12:45:05 -08:00
Herb Sutter e02baff283 Remove minor code duplication 2020-12-18 12:34:07 -08:00
Herb Sutter 71fd73fa04 Make constructor more constinit-friendly 2020-12-18 12:27:33 -08:00
Herb Sutter c78ad8661c Added "vestigial" comments for downlevel feature test workarounds 2020-12-18 12:18:23 -08:00
Herb Sutter 070db845f8 Add -Wno-global-constructors for Clang 2020-12-18 12:10:36 -08:00
Herb Sutter 0c5a66b666 Added workaround for non-constexpr std::exchange 2020-12-18 12:02:42 -08:00
Herb Sutter 248a7cbdce Add feature test for literal constructor in downlevel compilers 2020-12-18 11:56:36 -08:00
Herb Sutter b77eaa87ee Make contract_group a literal type 2020-12-18 11:40:50 -08:00
Herb Sutter 9033021831 Removed stray .exchange 2020-12-18 11:34:25 -08:00
Herb Sutter a45265a75e Handler shouldn't be internally synchronized 2020-12-18 11:30:17 -08:00
Herb Sutter 8bd828744f Remove constexpr again to see what the failures were 2020-12-18 11:25:04 -08:00
Herb Sutter 1c37688ccd Replaced some of the previous workarounds with feature tests
As always with feature tests, they can only be used to aggressively adopt new features even before all compilers we need have the features -- the test lets us write a vestigial workaround for downllevel compilers, to be removed as soon as all compilers support the feature.
2020-12-18 11:20:03 -08:00
Herb Sutter 8dfd03feeb Remove constexpr from contract_group constructor 2020-12-17 13:19:29 -08:00
Herb Sutter d83e9ea05f Add workarounds for Android compiler and constexpr test 2020-12-17 12:11:42 -08:00
Herb Sutter 59f38376b9 Change auto to void to satisfy some compilers about definition ordering 2020-12-17 12:03:59 -08:00
Herb Sutter dd45e5cfbd Went back to old-style declaration for older compilers that don't do C++17 guaranteed copy elision
A concession to older compilers.
2020-12-17 11:58:53 -08:00
Herb Sutter 0cbb9e221d Removed double .load
Require `chandler` to be never null by installing `[]()noexcept{}` as the handler if given a null pointer.
This lets us remove the double test in `assertion`.
2020-12-17 11:36:23 -08:00
Herb Sutter b7548fd1cd Update multi_span
Revert changes in multi_span to avoid a merge conflict, since this file was deleted in a parallel PR
2020-12-17 10:35:34 -08:00
Herb Sutter cbfd8cd734 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.
2020-11-27 17:06:01 -08:00
Herb Sutter c16e4ce59f Replace GSL_CONTRACT_CHECK with contract_group 2020-11-27 16:33:12 -08:00
Herb Sutter b34dc221a1 Remove GSL_ASSUME (unused code)
This is not specified in the C++ Core Guidelines as part of GSL, so it should not be documented or supported with a GSL name. And since we don't use it in the GSL repo either, we should just remove it directly. For more about why assumptions are a dangerous blunt instrument, including that they actively eliminate contracts checks including GSL's `Expects` and `Ensures`, see [P2064](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2064r0.pdf).
2020-11-27 11:10:53 -08:00
Herb Sutter c20a54c8e7 Remove __builtin_expect prediction assistance
In microbenchmarks I tried, using `__builtin_expect` to indicate which branch was likely/unlikely was never faster, and often slower, than just omitting. In GSL, this is used only for `Expects` and `Ensures` which are nearly always true, and all processors have long been great at predicting such branches well.
2020-11-27 11:07:55 -08:00
13 changed files with 123 additions and 103 deletions
+2 -2
View File
@@ -44,8 +44,8 @@ shared_ptr | ☑ | an alias to `std::shared_ptr`
stack_array | ☐ | a stack-allocated array
dyn_array | ☐ | a heap-allocated array
[**3. Assertions**][cg-assertions] | |
Expects | ☑ | a precondition assertion; on failure it terminates
Ensures | ☑ | a postcondition 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 by default if no user-installed handler
[**4. Utilities**][cg-utilities] | |
move_owner | ☐ | a helper function that moves one `owner` to the other
byte | ☑ | either an alias to std::byte or a byte type
+3 -3
View File
@@ -17,7 +17,7 @@
#ifndef 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 <algorithm> // for copy_n
@@ -27,7 +27,7 @@
#ifdef _MSC_VER
#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 : 4996) // unsafe use of std::copy_n
@@ -47,7 +47,7 @@ void copy(span<SrcElementType, SrcExtent> src, span<DestElementType, DestExtent>
(SrcExtent <= DestExtent),
"Source range is longer than target range");
Expects(dest.size() >= src.size());
Expects(dest.size() >= src.size(), Bounds);
// clang-format off
GSL_SUPPRESS(stl.1) // NO-FORMAT: attribute
// clang-format on
+43 -29
View File
@@ -17,6 +17,7 @@
#ifndef GSL_CONTRACTS_H
#define GSL_CONTRACTS_H
//
// Temporary until MSVC STL supports no-exceptions mode.
// Currently terminate is a no-op in this mode, so we add termination behavior back
@@ -57,30 +58,6 @@
#define GSL_STRINGIFY_DETAIL(x) #x
#define GSL_STRINGIFY(x) GSL_STRINGIFY_DETAIL(x)
#if defined(__clang__) || defined(__GNUC__)
#define GSL_LIKELY(x) __builtin_expect(!!(x), 1)
#define GSL_UNLIKELY(x) __builtin_expect(!!(x), 0)
#else
#define GSL_LIKELY(x) (!!(x))
#define GSL_UNLIKELY(x) (!!(x))
#endif // defined(__clang__) || defined(__GNUC__)
//
// GSL_ASSUME(cond)
//
// Tell the optimizer that the predicate cond must hold. It is unspecified
// whether or not cond is actually evaluated.
//
#ifdef _MSC_VER
#define GSL_ASSUME(cond) __assume(cond)
#elif defined(__GNUC__)
#define GSL_ASSUME(cond) ((cond) ? static_cast<void>(0) : __builtin_unreachable())
#else
#define GSL_ASSUME(cond) static_cast<void>((cond) ? 0 : 0)
#endif
//
// GSL.assert: assertions
//
@@ -120,13 +97,50 @@ namespace details
}
} // namespace details
class contract_group {
public:
#if defined __cpp_noexcept_function_type
using handler = void (*)() noexcept;
#else // VESTIGIAL, remove when no longer needed for downlevel compilers
using handler = void (*)();
#endif
constexpr contract_group (handler h = nullptr) : chandler(normalize(h)) { }
constexpr auto set_handler(handler h) -> handler { auto old = chandler; chandler = normalize(h); return old; }
constexpr auto get_handler() const -> handler { return chandler; }
constexpr auto expects (bool b) -> void { assertion(b); }
constexpr auto ensures (bool b) -> void { assertion(b); }
private:
constexpr auto assertion(bool b) -> void { if (!b) chandler(); }
constexpr auto normalize(handler h) -> handler { return h ? h : []()noexcept{}; }
handler chandler;
};
// By default, there is one violation handler per translation unit.
// Defining GSL_GLOBAL_CONTRACT_VIOLATION_HANDLERS and compiling as
// C++17 (or later) opts into using a global violation handler.
#if defined GSL_GLOBAL_CONTRACT_VIOLATION_HANDLERS && __cplusplus >= 201703L
#define GSL_CONTRACT_VIOLATION_GRANULARITY inline
#else
#define GSL_CONTRACT_VIOLATION_GRANULARITY static
#endif
auto GSL_CONTRACT_VIOLATION_GRANULARITY Default = contract_group(
#if defined GSL_UNENFORCED_ON_CONTRACT_VIOLATION
// use default == null handler
#else // if defined GSL_TERMINATE_ON_CONTRACT_VIOLATION
&gsl::details::terminate
#endif
);
auto GSL_CONTRACT_VIOLATION_GRANULARITY Bounds = Default;
auto GSL_CONTRACT_VIOLATION_GRANULARITY Null = Default;
auto GSL_CONTRACT_VIOLATION_GRANULARITY Testing = Default;
} // namespace gsl
#define GSL_CONTRACT_CHECK(type, cond) \
(GSL_LIKELY(cond) ? static_cast<void>(0) : gsl::details::terminate())
#define Expects(cond) GSL_CONTRACT_CHECK("Precondition", cond)
#define Ensures(cond) GSL_CONTRACT_CHECK("Postcondition", cond)
#define Expects(cond, kind) kind.expects(cond)
#define Ensures(cond, kind) kind.ensures(cond)
#if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND) && defined(__clang__)
#pragma clang diagnostic pop
+1 -1
View File
@@ -18,7 +18,7 @@
#define GSL_GSL_H
#include <gsl/algorithm> // copy
#include <gsl/assert> // Ensures/Expects
#include <gsl/assert> // contracts
#include <gsl/byte> // byte
#include <gsl/pointers> // owner, not_null
#include <gsl/multi_span> // multi_span, strided_span...
+1 -1
View File
@@ -16,7 +16,7 @@
#ifndef GSL_NARROW_H
#define GSL_NARROW_H
#include <gsl/assert> // for Expects
#include <gsl/assert> // for contracts
#include <gsl/util> // for narrow_cast
namespace gsl
{
+4 -4
View File
@@ -17,7 +17,7 @@
#ifndef GSL_POINTERS_H
#define GSL_POINTERS_H
#include <gsl/assert> // for Ensures, Expects
#include <gsl/assert> // for contracts
#include <algorithm> // for forward
#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>>
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>>
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>>
@@ -91,7 +91,7 @@ public:
not_null& operator=(const not_null& other) = default;
constexpr std::conditional_t<std::is_copy_constructible<T>::value, T, const T&> get() const
{
Ensures(ptr_ != nullptr);
Ensures(ptr_ != nullptr, Null);
return ptr_;
}
+42 -42
View File
@@ -17,7 +17,7 @@
#ifndef GSL_SPAN_H
#define GSL_SPAN_H
#include <gsl/assert> // for Expects
#include <gsl/assert> // for contracts
#include <gsl/byte> // for byte
#include <gsl/util> // for narrow_cast
@@ -29,7 +29,7 @@
#if defined(_MSC_VER) && !defined(__clang__)
#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 : 4146) // unary minus operator applied to unsigned type, result still unsigned
@@ -137,21 +137,21 @@ namespace details
constexpr reference operator*() const noexcept
{
Expects(begin_ && end_);
Expects(begin_ <= current_ && current_ < end_);
Expects(begin_ && end_, Bounds);
Expects(begin_ <= current_ && current_ < end_, Bounds);
return *current_;
}
constexpr pointer operator->() const noexcept
{
Expects(begin_ && end_);
Expects(begin_ <= current_ && current_ < end_);
Expects(begin_ && end_, Bounds);
Expects(begin_ <= current_ && current_ < end_, Bounds);
return current_;
}
constexpr span_iterator& operator++() noexcept
{
Expects(begin_ && current_ && end_);
Expects(current_ < end_);
Expects(begin_ && current_ && end_, Bounds);
Expects(current_ < end_, Bounds);
// clang-format off
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
// clang-format on
@@ -168,8 +168,8 @@ namespace details
constexpr span_iterator& operator--() noexcept
{
Expects(begin_ && end_);
Expects(begin_ < current_);
Expects(begin_ && end_, Bounds);
Expects(begin_ < current_, Bounds);
--current_;
return *this;
}
@@ -183,9 +183,9 @@ namespace details
constexpr span_iterator& operator+=(const difference_type n) noexcept
{
if (n != 0) Expects(begin_ && current_ && end_);
if (n > 0) Expects(end_ - current_ >= n);
if (n < 0) Expects(current_ - begin_ >= -n);
if (n != 0) Expects(begin_ && current_ && end_, Bounds);
if (n > 0) Expects(end_ - current_ >= n, Bounds);
if (n < 0) Expects(current_ - begin_ >= -n, Bounds);
// clang-format off
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
// clang-format on
@@ -208,9 +208,9 @@ namespace details
constexpr span_iterator& operator-=(const difference_type n) noexcept
{
if (n != 0) Expects(begin_ && current_ && end_);
if (n > 0) Expects(current_ - begin_ >= n);
if (n < 0) Expects(end_ - current_ >= -n);
if (n != 0) Expects(begin_ && current_ && end_, Bounds);
if (n > 0) Expects(current_ - begin_ >= n, Bounds);
if (n < 0) Expects(end_ - current_ >= -n, Bounds);
current_ -= n;
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>
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_;
}
@@ -241,7 +241,7 @@ namespace details
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
{
Expects(begin_ == rhs.begin_ && end_ == rhs.end_);
Expects(begin_ == rhs.begin_ && end_ == rhs.end_, Bounds);
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>
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_;
}
@@ -294,14 +294,14 @@ namespace details
{ // test that [lhs, rhs) forms a valid range inside an STL algorithm
Expects(lhs.begin_ == rhs.begin_ // range spans have to match
&& 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
{ // test that *this + n is within the range of this call
if (n != 0) Expects(begin_ && current_ && end_);
if (n > 0) Expects(end_ - current_ >= n);
if (n < 0) Expects(current_ - begin_ >= -n);
if (n != 0) Expects(begin_ && current_ && end_, Bounds);
if (n > 0) Expects(end_ - current_ >= n, Bounds);
if (n < 0) Expects(current_ - begin_ >= -n, Bounds);
}
// clang-format off
@@ -346,7 +346,7 @@ namespace details
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; }
@@ -370,7 +370,7 @@ namespace details
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_; }
@@ -382,7 +382,7 @@ namespace details
template <std::size_t 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>
@@ -431,7 +431,7 @@ public:
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)
{
Expects(count == Extent);
Expects(count == Extent, Bounds);
}
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
: 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>
@@ -553,7 +553,7 @@ public:
template <std::size_t Count>
constexpr span<element_type, Count> first() const noexcept
{
Expects(Count <= size());
Expects(Count <= size(), Bounds);
return span<element_type, Count>{data(), Count};
}
@@ -563,7 +563,7 @@ public:
// clang-format on
constexpr span<element_type, Count> last() const noexcept
{
Expects(Count <= size());
Expects(Count <= size(), Bounds);
return span<element_type, Count>{data() + (size() - Count), Count};
}
@@ -574,7 +574,7 @@ public:
constexpr auto subspan() const noexcept ->
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 =
typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type;
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
{
Expects(count <= size());
Expects(count <= size(), Bounds);
return {data(), count};
}
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>{});
}
@@ -603,7 +603,7 @@ public:
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);
}
@@ -615,19 +615,19 @@ public:
// clang-format on
constexpr reference operator[](size_type idx) const noexcept
{
Expects(idx < size());
Expects(idx < size(), Bounds);
return data()[idx];
}
constexpr reference front() const noexcept
{
Expects(size() > 0);
Expects(size() > 0, Bounds);
return data()[0];
}
constexpr reference back() const noexcept
{
Expects(size() > 0);
Expects(size() > 0, Bounds);
return data()[size() - 1];
}
@@ -688,14 +688,14 @@ private:
constexpr storage_type(KnownNotNull data, OtherExtentType ext)
: ExtentType(ext), data_(data.p)
{
Expects(ExtentType::size() != dynamic_extent);
Expects(ExtentType::size() != dynamic_extent, Bounds);
}
template <class OtherExtentType>
constexpr storage_type(pointer data, OtherExtentType ext) : ExtentType(ext), data_(data)
{
Expects(ExtentType::size() != dynamic_extent);
Expects(data || ExtentType::size() == 0);
Expects(ExtentType::size() != dynamic_extent, Bounds);
Expects(data || ExtentType::size() == 0, Bounds);
}
constexpr pointer data() const noexcept { return data_; }
@@ -729,11 +729,11 @@ private:
constexpr span<element_type, dynamic_extent>
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}; }
Expects(size() - offset >= count);
Expects(size() - offset >= count, Bounds);
return {KnownNotNull{data() + offset}, count};
}
};
+1 -1
View File
@@ -124,7 +124,7 @@ template <class ElementType, std::size_t Extent>
constexpr ElementType& at(span<ElementType, Extent> s, index i)
{
// 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)];
}
+6 -6
View File
@@ -17,7 +17,7 @@
#ifndef 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/util> // for narrow_cast
@@ -114,19 +114,19 @@ template <typename T, const T Sentinel>
"isocpp/CppCoreGuidelines PR#1680")]] constexpr span<T, dynamic_extent>
ensure_sentinel(T* seq, std::size_t max = static_cast<std::size_t>(-1))
{
Ensures(seq != nullptr);
Ensures(seq != nullptr, Null);
// clang-format off
GSL_SUPPRESS(f.23) // TODO: false positive // TODO: suppress does not work
// clang-format on
auto cur = seq;
Ensures(cur != nullptr); // workaround for removing the warning
Ensures(cur != nullptr, Null); // workaround for removing the warning
// clang-format off
GSL_SUPPRESS(bounds.1) // TODO: suppress does not work
// clang-format on
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)};
}
@@ -437,8 +437,8 @@ public:
constexpr basic_zstring_span(impl_type s) : span_(s)
{
// expects a zero-terminated span
Expects(s.size() > 0);
Expects(s[s.size() - 1] == value_type{});
Expects(s.size() > 0, Bounds);
Expects(s[s.size() - 1] == value_type{}, Bounds);
}
// copy
+4 -4
View File
@@ -17,7 +17,7 @@
#ifndef GSL_UTIL_H
#define GSL_UTIL_H
#include <gsl/assert> // for Expects
#include <gsl/assert> // for contracts
#include <array>
#include <cstddef> // for ptrdiff_t, size_t
@@ -108,7 +108,7 @@ GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute
// clang-format on
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)];
}
@@ -119,7 +119,7 @@ GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute
// clang-format on
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());
return cont[narrow_cast<size_type>(i)];
}
@@ -130,7 +130,7 @@ GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
// clang-format on
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);
}
+8 -2
View File
@@ -78,6 +78,7 @@ if(MSVC) # MSVC or simulating MSVC
-Wno-shift-sign-overflow # GTest gtest-port.h
-Wno-undef # GTest
-Wno-used-but-marked-unused # GTest EXPECT_DEATH
-Wno-global-constructors
$<$<EQUAL:${GSL_CXX_STANDARD},14>: # no support for [[maybe_unused]]
-Wno-unused-member-function
-Wno-unused-variable
@@ -109,6 +110,7 @@ else()
-Wno-unknown-attributes
-Wno-used-but-marked-unused # GTest EXPECT_DEATH
-Wno-weak-vtables
-Wno-global-constructors
$<$<EQUAL:${GSL_CXX_STANDARD},14>: # no support for [[maybe_unused]]
-Wno-unused-member-function
-Wno-unused-variable
@@ -130,7 +132,8 @@ else()
$<$<NOT:$<VERSION_LESS:$<CXX_COMPILER_VERSION>,6>>:
-Wduplicated-cond # duplicated if-else conditions
-Wmisleading-indentation
-Wnull-dereference
-Wno-null-dereference
-Wno-array-bounds
$<$<EQUAL:${GSL_CXX_STANDARD},14>: # no support for [[maybe_unused]]
-Wno-unused-variable
>
@@ -212,6 +215,7 @@ if(MSVC) # MSVC or simulating MSVC
-Wno-c++98-compat-pedantic
-Wno-missing-prototypes
-Wno-unknown-attributes
-Wno-global-constructors
>
)
else()
@@ -234,6 +238,7 @@ else()
-Wno-missing-prototypes
-Wno-unknown-attributes
-Wno-weak-vtables
-Wno-global-constructors
>
$<$<CXX_COMPILER_ID:GNU>:
-Wdouble-promotion # float implicit to double
@@ -242,7 +247,8 @@ else()
$<$<NOT:$<VERSION_LESS:$<CXX_COMPILER_VERSION>,6>>:
-Wduplicated-cond # duplicated if-else conditions
-Wmisleading-indentation
-Wnull-dereference
-Wno-null-dereference
-Wno-array-bounds
>
$<$<NOT:$<VERSION_LESS:$<CXX_COMPILER_VERSION>,7>>:
-Wduplicated-branches # identical if-else branches
+3 -3
View File
@@ -15,7 +15,7 @@
///////////////////////////////////////////////////////////////////////////////
#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;
@@ -25,14 +25,14 @@ static constexpr char deathstring[] = "Expected Death";
int f(int i)
{
Expects(i > 0 && i < 10);
Expects(i > 0 && i < 10, Testing);
return i;
}
int g(int i)
{
i++;
Ensures(i > 0 && i < 10);
Ensures(i > 0 && i < 10, Testing);
return i;
}
} // namespace
+5 -5
View File
@@ -16,7 +16,7 @@
#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/span> // for span, dynamic_extent
#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)
{
Expects(span.size() > 1);
Expects(span.size() > 1, Testing);
std::size_t last = 0;
if (span.size() > 4) {
@@ -99,7 +99,7 @@ czstring_span<> CreateTempName(string_span<> span)
cwzstring_span<> CreateTempNameW(wstring_span<> span)
{
Expects(span.size() > 1);
Expects(span.size() > 1, Testing);
std::size_t last = 0;
if (span.size() > 4) {
@@ -116,7 +116,7 @@ cwzstring_span<> CreateTempNameW(wstring_span<> span)
cu16zstring_span<> CreateTempNameU16(u16string_span<> span)
{
Expects(span.size() > 1);
Expects(span.size() > 1, Testing);
std::size_t last = 0;
if (span.size() > 4) {
@@ -133,7 +133,7 @@ cu16zstring_span<> CreateTempNameU16(u16string_span<> span)
cu32zstring_span<> CreateTempNameU32(u32string_span<> span)
{
Expects(span.size() > 1);
Expects(span.size() > 1, Testing);
std::size_t last = 0;
if (span.size() > 4) {