gsl::at behavior change regarding gsl::span (#985)

* move span specialization of 'at' to <gsl/span> and update the parameter to be taken by reference

* undid previous changes and acted upon decisions made in maintainer sync. Fixed tests failing in /kernel mode

* ran clang-format on the include folder

* ran clang-format on the test folder

Co-authored-by: Jordan Maples <jordan.maples@microsoft.com>
This commit is contained in:
Jordan Maples [MSFT] 2021-05-20 18:18:08 -07:00 committed by GitHub
parent c1cbb41b42
commit b26f6d5ec7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 1304 additions and 1175 deletions

View File

@ -22,6 +22,7 @@
// Currently terminate is a no-op in this mode, so we add termination behavior back // Currently terminate is a no-op in this mode, so we add termination behavior back
// //
#if defined(_MSC_VER) && (defined(_KERNEL_MODE) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS)) #if defined(_MSC_VER) && (defined(_KERNEL_MODE) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS))
#define GSL_KERNEL_MODE
#define GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND #define GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND
#include <intrin.h> #include <intrin.h>

View File

@ -1,3 +1,4 @@
#pragma once #pragma once
#pragma message("This header will soon be removed. Use <gsl/algorithm> instead of <gsl/gsl_algorithm>") #pragma message( \
"This header will soon be removed. Use <gsl/algorithm> instead of <gsl/gsl_algorithm>")
#include <gsl/algorithm> #include <gsl/algorithm>

View File

@ -30,7 +30,7 @@ template <class T, class U>
// clang-format off // clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // TODO: MSVC /analyze does not recognise noexcept(false) GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // TODO: MSVC /analyze does not recognise noexcept(false)
// clang-format on // clang-format on
constexpr T narrow(U u) noexcept(false) constexpr T narrow(U u) noexcept(false)
{ {
constexpr const bool is_different_signedness = constexpr const bool is_different_signedness =

View File

@ -34,12 +34,19 @@ namespace gsl
namespace details namespace details
{ {
template<typename T, typename = void> template <typename T, typename = void>
struct is_comparable_to_nullptr : std::false_type {}; struct is_comparable_to_nullptr : std::false_type
{
};
template <typename T> template <typename T>
struct is_comparable_to_nullptr<T, std::enable_if_t<std::is_convertible<decltype(std::declval<T>() != nullptr), bool>::value>> : std::true_type {}; struct is_comparable_to_nullptr<
} // namespace details T,
std::enable_if_t<std::is_convertible<decltype(std::declval<T>() != nullptr), bool>::value>>
: std::true_type
{
};
} // namespace details
// //
// GSL.owner: ownership pointers // GSL.owner: ownership pointers

View File

@ -21,10 +21,11 @@
#include <gsl/byte> // for byte #include <gsl/byte> // for byte
#include <gsl/util> // for narrow_cast #include <gsl/util> // for narrow_cast
#include <array> // for array #include <array> // for array
#include <cstddef> // for ptrdiff_t, size_t, nullptr_t #include <cstddef> // for ptrdiff_t, size_t, nullptr_t
#include <iterator> // for reverse_iterator, distance, random_access_... #include <gsl/span_ext> // for span specialization of gsl::at and other span-related extensions
#include <type_traits> // for enable_if_t, declval, is_convertible, inte... #include <iterator> // for reverse_iterator, distance, random_access_...
#include <type_traits> // for enable_if_t, declval, is_convertible, inte...
#if defined(_MSC_VER) && !defined(__clang__) #if defined(_MSC_VER) && !defined(__clang__)
#pragma warning(push) #pragma warning(push)
@ -60,12 +61,6 @@
namespace gsl namespace gsl
{ {
// [views.constants], constants
constexpr const std::size_t dynamic_extent = narrow_cast<std::size_t>(-1);
template <class ElementType, std::size_t Extent = dynamic_extent>
class span;
// implementation details // implementation details
namespace details namespace details
{ {

View File

@ -27,16 +27,29 @@
// //
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#include <gsl/span> // for span #include <gsl/assert> // GSL_KERNEL_MODE
#include <gsl/util> // for narrow_cast, narrow #include <gsl/util> // for narrow_cast, narrow
#include <algorithm> // for lexicographical_compare #include <cstddef> // for ptrdiff_t, size_t
#include <cstddef> // for ptrdiff_t, size_t
#include <utility> #include <utility>
#ifndef GSL_KERNEL_MODE
#include <algorithm> // for lexicographical_compare
#endif // GSL_KERNEL_MODE
namespace gsl namespace gsl
{ {
// [span.views.constants], constants
constexpr const std::size_t dynamic_extent = narrow_cast<std::size_t>(-1);
template <class ElementType, std::size_t Extent = dynamic_extent>
class span;
// std::equal and std::lexicographical_compare are not /kernel compatible
// so all comparison operators must be removed for kernel mode.
#ifndef GSL_KERNEL_MODE
// [span.comparison], span comparison operators // [span.comparison], span comparison operators
template <class ElementType, std::size_t FirstExtent, std::size_t SecondExtent> template <class ElementType, std::size_t FirstExtent, std::size_t SecondExtent>
constexpr bool operator==(span<ElementType, FirstExtent> l, span<ElementType, SecondExtent> r) constexpr bool operator==(span<ElementType, FirstExtent> l, span<ElementType, SecondExtent> r)
@ -74,6 +87,8 @@ constexpr bool operator>=(span<ElementType, Extent> l, span<ElementType, Extent>
return !(l < r); return !(l < r);
} }
#endif // GSL_KERNEL_MODE
// //
// make_span() - Utility functions for creating spans // make_span() - Utility functions for creating spans
// //

View File

@ -25,6 +25,10 @@
#include <type_traits> // for is_signed, integral_constant #include <type_traits> // for is_signed, integral_constant
#include <utility> // for exchange, forward #include <utility> // for exchange, forward
#if defined(__cplusplus) && __cplusplus >= 202002L
#include <span>
#endif // __cplusplus >= 202002L
#if defined(_MSC_VER) && !defined(__clang__) #if defined(_MSC_VER) && !defined(__clang__)
#pragma warning(push) #pragma warning(push)
@ -92,8 +96,8 @@ finally(F&& f) noexcept
template <class T, class U> template <class T, class U>
// clang-format off // clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on // clang-format on
constexpr T narrow_cast(U&& u) noexcept constexpr T narrow_cast(U&& u) noexcept
{ {
return static_cast<T>(std::forward<U>(u)); return static_cast<T>(std::forward<U>(u));
} }
@ -105,7 +109,7 @@ template <class T, std::size_t N>
// clang-format off // clang-format off
GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute
GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute 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));
@ -116,7 +120,7 @@ template <class Cont>
// clang-format off // clang-format off
GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute
GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute 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()));
@ -127,13 +131,21 @@ GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute
template <class T> template <class T>
// 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
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()));
return *(cont.begin() + i); return *(cont.begin() + i);
} }
#if defined(__cplusplus) && __cplusplus >= 202002L
template <class T, size_t extent = std::dynamic_extent>
constexpr auto at(std::span<T, extent> sp, const index i)
{
Expects(i >= 0 && i < narrow_cast<i>(sp.size()));
return sp[i];
}
#endif // __cplusplus >= 202002L
} // namespace gsl } // namespace gsl
#if defined(_MSC_VER) && !defined(__clang__) #if defined(_MSC_VER) && !defined(__clang__)

View File

@ -14,16 +14,13 @@
// //
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#include <gtest/gtest.h> #include <array> // for array
#include <cstddef> // for size_t
#include <gsl/algorithm> // for copy #include <gsl/algorithm> // for copy
#include <gsl/span> // for span #include <gsl/span> // for span
#include <array> // for array #include <gtest/gtest.h>
#include <cstddef> // for size_t
namespace #include "deathTestCommon.h"
{
static constexpr char deathstring[] = "Expected Death";
}
namespace gsl namespace gsl
{ {
@ -204,10 +201,11 @@ TEST(algorithm_tests, incompatible_type)
TEST(algorithm_tests, small_destination_span) TEST(algorithm_tests, small_destination_span)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. small_destination_span"; std::cerr << "Expected Death. small_destination_span";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
std::array<int, 12> src{1, 2, 3, 4}; std::array<int, 12> src{1, 2, 3, 4};
std::array<int, 4> dst{}; std::array<int, 4> dst{};
@ -217,9 +215,9 @@ TEST(algorithm_tests, small_destination_span)
const span<int> dst_span_dyn(dst); const span<int> dst_span_dyn(dst);
const span<int, 4> dst_span_static(dst); const span<int, 4> dst_span_static(dst);
EXPECT_DEATH(copy(src_span_dyn, dst_span_dyn), deathstring); EXPECT_DEATH(copy(src_span_dyn, dst_span_dyn), expected);
EXPECT_DEATH(copy(src_span_dyn, dst_span_static), deathstring); EXPECT_DEATH(copy(src_span_dyn, dst_span_static), expected);
EXPECT_DEATH(copy(src_span_static, dst_span_dyn), deathstring); EXPECT_DEATH(copy(src_span_static, dst_span_dyn), expected);
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
copy(src_span_static, dst_span_static); copy(src_span_static, dst_span_static);

View File

@ -14,14 +14,14 @@
// //
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#include <gtest/gtest.h> #include "deathTestCommon.h"
#include <gsl/assert> // for fail_fast (ptr only), Ensures, Expects #include <gsl/assert> // for fail_fast (ptr only), Ensures, Expects
#include <gtest/gtest.h>
using namespace gsl; using namespace gsl;
namespace namespace
{ {
static constexpr char deathstring[] = "Expected Death";
int f(int i) int f(int i)
{ {
@ -39,23 +39,22 @@ int g(int i)
TEST(assertion_tests, expects) TEST(assertion_tests, expects)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. expects"; std::cerr << "Expected Death. expects";
std::abort(); std::abort();
}); });
EXPECT_TRUE(f(2) == 2); EXPECT_TRUE(f(2) == 2);
EXPECT_DEATH(f(10), deathstring); EXPECT_DEATH(f(10), GetExpectedDeathString(terminateHandler));
} }
TEST(assertion_tests, ensures) TEST(assertion_tests, ensures)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. ensures"; std::cerr << "Expected Death. ensures";
std::abort(); std::abort();
}); });
EXPECT_TRUE(g(2) == 3); EXPECT_TRUE(g(2) == 3);
EXPECT_DEATH(g(9), deathstring); EXPECT_DEATH(g(9), GetExpectedDeathString(terminateHandler));
} }

View File

@ -22,31 +22,33 @@
#include <cstddef> // for size_t #include <cstddef> // for size_t
#include <initializer_list> // for initializer_list #include <initializer_list> // for initializer_list
#include <vector> // for vector #include <vector> // for vector
#if defined(__cplusplus) && __cplusplus >= 202002L
#include <span>
#endif // __cplusplus >= 202002L
namespace #include "deathTestCommon.h"
{
static constexpr char deathstring[] = "Expected Death";
}
TEST(at_tests, static_array) TEST(at_tests, static_array)
{ {
int a[4] = {1, 2, 3, 4}; int a[4] = {1, 2, 3, 4};
const int(&c_a)[4] = a; const int(&c_a)[4] = a;
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i)
{
EXPECT_TRUE(&gsl::at(a, i) == &a[i]); EXPECT_TRUE(&gsl::at(a, i) == &a[i]);
EXPECT_TRUE(&gsl::at(c_a, i) == &a[i]); EXPECT_TRUE(&gsl::at(c_a, i) == &a[i]);
} }
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. static_array"; std::cerr << "Expected Death. static_array";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
EXPECT_DEATH(gsl::at(a, -1), deathstring); EXPECT_DEATH(gsl::at(a, -1), expected);
EXPECT_DEATH(gsl::at(a, 4), deathstring); EXPECT_DEATH(gsl::at(a, 4), expected);
EXPECT_DEATH(gsl::at(c_a, -1), deathstring); EXPECT_DEATH(gsl::at(c_a, -1), expected);
EXPECT_DEATH(gsl::at(c_a, 4), deathstring); EXPECT_DEATH(gsl::at(c_a, 4), expected);
} }
TEST(at_tests, std_array) TEST(at_tests, std_array)
@ -54,20 +56,22 @@ TEST(at_tests, std_array)
std::array<int, 4> a = {1, 2, 3, 4}; std::array<int, 4> a = {1, 2, 3, 4};
const std::array<int, 4>& c_a = a; const std::array<int, 4>& c_a = a;
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i)
{
EXPECT_TRUE(&gsl::at(a, i) == &a[static_cast<std::size_t>(i)]); EXPECT_TRUE(&gsl::at(a, i) == &a[static_cast<std::size_t>(i)]);
EXPECT_TRUE(&gsl::at(c_a, i) == &a[static_cast<std::size_t>(i)]); EXPECT_TRUE(&gsl::at(c_a, i) == &a[static_cast<std::size_t>(i)]);
} }
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. std_array"; std::cerr << "Expected Death. std_array";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
EXPECT_DEATH(gsl::at(a, -1), deathstring); EXPECT_DEATH(gsl::at(a, -1), expected);
EXPECT_DEATH(gsl::at(a, 4), deathstring); EXPECT_DEATH(gsl::at(a, 4), expected);
EXPECT_DEATH(gsl::at(c_a, -1), deathstring); EXPECT_DEATH(gsl::at(c_a, -1), expected);
EXPECT_DEATH(gsl::at(c_a, 4), deathstring); EXPECT_DEATH(gsl::at(c_a, 4), expected);
} }
TEST(at_tests, std_vector) TEST(at_tests, std_vector)
@ -75,42 +79,68 @@ TEST(at_tests, std_vector)
std::vector<int> a = {1, 2, 3, 4}; std::vector<int> a = {1, 2, 3, 4};
const std::vector<int>& c_a = a; const std::vector<int>& c_a = a;
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i)
{
EXPECT_TRUE(&gsl::at(a, i) == &a[static_cast<std::size_t>(i)]); EXPECT_TRUE(&gsl::at(a, i) == &a[static_cast<std::size_t>(i)]);
EXPECT_TRUE(&gsl::at(c_a, i) == &a[static_cast<std::size_t>(i)]); EXPECT_TRUE(&gsl::at(c_a, i) == &a[static_cast<std::size_t>(i)]);
} }
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. std_vector"; std::cerr << "Expected Death. std_vector";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
EXPECT_DEATH(gsl::at(a, -1), deathstring); EXPECT_DEATH(gsl::at(a, -1), expected);
EXPECT_DEATH(gsl::at(a, 4), deathstring); EXPECT_DEATH(gsl::at(a, 4), expected);
EXPECT_DEATH(gsl::at(c_a, -1), deathstring); EXPECT_DEATH(gsl::at(c_a, -1), expected);
EXPECT_DEATH(gsl::at(c_a, 4), deathstring); EXPECT_DEATH(gsl::at(c_a, 4), expected);
} }
TEST(at_tests, InitializerList) TEST(at_tests, InitializerList)
{ {
const std::initializer_list<int> a = {1, 2, 3, 4}; const std::initializer_list<int> a = {1, 2, 3, 4};
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i)
{
EXPECT_TRUE(gsl::at(a, i) == i + 1); EXPECT_TRUE(gsl::at(a, i) == i + 1);
EXPECT_TRUE(gsl::at({1, 2, 3, 4}, i) == i + 1); EXPECT_TRUE(gsl::at({1, 2, 3, 4}, i) == i + 1);
} }
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. InitializerList"; std::cerr << "Expected Death. InitializerList";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
EXPECT_DEATH(gsl::at(a, -1), deathstring); EXPECT_DEATH(gsl::at(a, -1), expected);
EXPECT_DEATH(gsl::at(a, 4), deathstring); EXPECT_DEATH(gsl::at(a, 4), expected);
EXPECT_DEATH(gsl::at({1, 2, 3, 4}, -1), deathstring); EXPECT_DEATH(gsl::at({1, 2, 3, 4}, -1), expected);
EXPECT_DEATH(gsl::at({1, 2, 3, 4}, 4), deathstring); EXPECT_DEATH(gsl::at({1, 2, 3, 4}, 4), expected);
} }
#if defined(__cplusplus) && __cplusplus >= 202002L
TEST(at_tests, std_span)
{
std::vector<int> vec{1, 2, 3, 4, 5};
std::span sp{vec};
std::vector<int> cvec{1, 2, 3, 4, 5};
std::span csp{cvec};
for (size_t i = 0, i < vec.size(); ++i)
{
EXPECT_TRUE(&gsl::at(sp, i) == &vec[i]);
EXPECT_TRUE(&gsl::at(csp, i) == &cvec[i]);
}
EXPECT_DEATH(gsl::at(sp, -1), expected);
EXPECT_DEATH(gsl::at(sp, sp.size()), expected);
EXPECT_DEATH(gsl::at(csp, -1), expected);
EXPECT_DEATH(gsl::at(csp, sp.size()), expected);
}
#endif // __cplusplus >= 202002L
#if !defined(_MSC_VER) || defined(__clang__) || _MSC_VER >= 1910 #if !defined(_MSC_VER) || defined(__clang__) || _MSC_VER >= 1910
static constexpr bool test_constexpr() static constexpr bool test_constexpr()
{ {
@ -119,7 +149,8 @@ static constexpr bool test_constexpr()
std::array<int, 4> a2 = {1, 2, 3, 4}; std::array<int, 4> a2 = {1, 2, 3, 4};
const std::array<int, 4>& c_a2 = a2; const std::array<int, 4>& c_a2 = a2;
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i)
{
if (&gsl::at(a1, i) != &a1[i]) return false; if (&gsl::at(a1, i) != &a1[i]) return false;
if (&gsl::at(c_a1, i) != &a1[i]) return false; if (&gsl::at(c_a1, i) != &a1[i]) return false;
// requires C++17: // requires C++17:

View File

@ -37,7 +37,9 @@ TEST(byte_tests, construction)
EXPECT_TRUE(static_cast<unsigned char>(b) == 4); EXPECT_TRUE(static_cast<unsigned char>(b) == 4);
} }
// clang-format off
GSL_SUPPRESS(es.49) GSL_SUPPRESS(es.49)
// clang-format on
{ {
const byte b = byte(12); const byte b = byte(12);
EXPECT_TRUE(static_cast<unsigned char>(b) == 12); EXPECT_TRUE(static_cast<unsigned char>(b) == 12);
@ -55,7 +57,7 @@ TEST(byte_tests, construction)
#if defined(__cplusplus) && (__cplusplus >= 201703L) #if defined(__cplusplus) && (__cplusplus >= 201703L)
{ {
const byte b { 14 }; const byte b{14};
EXPECT_TRUE(static_cast<unsigned char>(b) == 14); EXPECT_TRUE(static_cast<unsigned char>(b) == 14);
} }
#endif #endif
@ -122,7 +124,7 @@ TEST(byte_tests, aliasing)
EXPECT_TRUE(res == i); EXPECT_TRUE(res == i);
} }
} } // namespace
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
copy(src_span_static, dst_span_static); copy(src_span_static, dst_span_static);

11
tests/deathTestCommon.h Normal file
View File

@ -0,0 +1,11 @@
#pragma once
#include <gsl/assert>
constexpr char deathstring[] = "Expected Death";
constexpr char failed_set_terminate_deathstring[] = ".*";
// This prevents a failed call to set_terminate from failing the test suite.
constexpr const char* GetExpectedDeathString(std::terminate_handler handle)
{
return handle ? deathstring : failed_set_terminate_deathstring;
}

View File

@ -25,13 +25,9 @@
#include <string> // for basic_string, operator==, string, operator<< #include <string> // for basic_string, operator==, string, operator<<
#include <typeinfo> // for type_info #include <typeinfo> // for type_info
#include "deathTestCommon.h"
using namespace gsl; using namespace gsl;
namespace
{
constexpr char deathstring[] = "Expected Death";
} // namespace
struct MyBase struct MyBase
{ {
}; };
@ -64,7 +60,9 @@ struct CustomPtr
template <typename T, typename U> template <typename T, typename U>
std::string operator==(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) std::string operator==(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
{ {
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on
return reinterpret_cast<const void*>(lhs.p_) == reinterpret_cast<const void*>(rhs.p_) ? "true" return reinterpret_cast<const void*>(lhs.p_) == reinterpret_cast<const void*>(rhs.p_) ? "true"
: "false"; : "false";
} }
@ -72,7 +70,9 @@ std::string operator==(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
template <typename T, typename U> template <typename T, typename U>
std::string operator!=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) std::string operator!=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
{ {
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on
return reinterpret_cast<const void*>(lhs.p_) != reinterpret_cast<const void*>(rhs.p_) ? "true" return reinterpret_cast<const void*>(lhs.p_) != reinterpret_cast<const void*>(rhs.p_) ? "true"
: "false"; : "false";
} }
@ -80,7 +80,9 @@ std::string operator!=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
template <typename T, typename U> template <typename T, typename U>
std::string operator<(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) std::string operator<(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
{ {
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on
return reinterpret_cast<const void*>(lhs.p_) < reinterpret_cast<const void*>(rhs.p_) ? "true" return reinterpret_cast<const void*>(lhs.p_) < reinterpret_cast<const void*>(rhs.p_) ? "true"
: "false"; : "false";
} }
@ -88,7 +90,9 @@ std::string operator<(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
template <typename T, typename U> template <typename T, typename U>
std::string operator>(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) std::string operator>(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
{ {
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on
return reinterpret_cast<const void*>(lhs.p_) > reinterpret_cast<const void*>(rhs.p_) ? "true" return reinterpret_cast<const void*>(lhs.p_) > reinterpret_cast<const void*>(rhs.p_) ? "true"
: "false"; : "false";
} }
@ -96,7 +100,9 @@ std::string operator>(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
template <typename T, typename U> template <typename T, typename U>
std::string operator<=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) std::string operator<=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
{ {
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on
return reinterpret_cast<const void*>(lhs.p_) <= reinterpret_cast<const void*>(rhs.p_) ? "true" return reinterpret_cast<const void*>(lhs.p_) <= reinterpret_cast<const void*>(rhs.p_) ? "true"
: "false"; : "false";
} }
@ -104,7 +110,9 @@ std::string operator<=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
template <typename T, typename U> template <typename T, typename U>
std::string operator>=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) std::string operator>=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
{ {
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on
return reinterpret_cast<const void*>(lhs.p_) >= reinterpret_cast<const void*>(rhs.p_) ? "true" return reinterpret_cast<const void*>(lhs.p_) >= reinterpret_cast<const void*>(rhs.p_) ? "true"
: "false"; : "false";
} }
@ -120,9 +128,13 @@ struct NonCopyableNonMovable
namespace namespace
{ {
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute // clang-format off
GSL_SUPPRESS(f .4) // NO-FORMAT: attribute
// clang-format on
bool helper(not_null<int*> p) { return *p == 12; } bool helper(not_null<int*> p) { return *p == 12; }
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute // clang-format off
GSL_SUPPRESS(f .4) // NO-FORMAT: attribute
// clang-format on
bool helper_const(not_null<const int*> p) { return *p == 12; } bool helper_const(not_null<const int*> p) { return *p == 12; }
int* return_pointer() { return nullptr; } int* return_pointer() { return nullptr; }
@ -145,10 +157,12 @@ TEST(notnull_tests, TestNotNullConstructors)
#endif #endif
} }
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. TestNotNullConstructors"; std::cerr << "Expected Death. TestNotNullConstructors";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
{ {
// from shared pointer // from shared pointer
int i = 12; int i = 12;
@ -160,7 +174,7 @@ TEST(notnull_tests, TestNotNullConstructors)
std::make_shared<int>(10)); // shared_ptr<int> is nullptr assignable std::make_shared<int>(10)); // shared_ptr<int> is nullptr assignable
int* pi = nullptr; int* pi = nullptr;
EXPECT_DEATH((not_null<decltype(pi)>(pi)), deathstring); EXPECT_DEATH((not_null<decltype(pi)>(pi)), expected);
} }
{ {
@ -217,8 +231,8 @@ TEST(notnull_tests, TestNotNullConstructors)
{ {
// from returned pointer // from returned pointer
EXPECT_DEATH(helper(return_pointer()), deathstring); EXPECT_DEATH(helper(return_pointer()), expected);
EXPECT_DEATH(helper_const(return_pointer()), deathstring); EXPECT_DEATH(helper_const(return_pointer()), expected);
} }
} }
@ -278,17 +292,18 @@ TEST(notnull_tests, TestNotNullCasting)
TEST(notnull_tests, TestNotNullAssignment) TEST(notnull_tests, TestNotNullAssignment)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. TestNotNullAssignmentd"; std::cerr << "Expected Death. TestNotNullAssignmentd";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
int i = 12; int i = 12;
not_null<int*> p(&i); not_null<int*> p(&i);
EXPECT_TRUE(helper(p)); EXPECT_TRUE(helper(p));
int* q = nullptr; int* q = nullptr;
EXPECT_DEATH(p = not_null<int*>(q), deathstring); EXPECT_DEATH(p = not_null<int*>(q), expected);
} }
TEST(notnull_tests, TestNotNullRawPointerComparison) TEST(notnull_tests, TestNotNullRawPointerComparison)
@ -437,17 +452,18 @@ TEST(notnull_tests, TestNotNullConstructorTypeDeduction)
EXPECT_TRUE(*x == 42); EXPECT_TRUE(*x == 42);
} }
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. TestNotNullConstructorTypeDeduction"; std::cerr << "Expected Death. TestNotNullConstructorTypeDeduction";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
{ {
auto workaround_macro = []() { auto workaround_macro = []() {
int* p1 = nullptr; int* p1 = nullptr;
const not_null x{p1}; const not_null x{p1};
}; };
EXPECT_DEATH(workaround_macro(), deathstring); EXPECT_DEATH(workaround_macro(), expected);
} }
{ {
@ -455,14 +471,14 @@ TEST(notnull_tests, TestNotNullConstructorTypeDeduction)
const int* p1 = nullptr; const int* p1 = nullptr;
const not_null x{p1}; const not_null x{p1};
}; };
EXPECT_DEATH(workaround_macro(), deathstring); EXPECT_DEATH(workaround_macro(), expected);
} }
{ {
int* p = nullptr; int* p = nullptr;
EXPECT_DEATH(helper(not_null{p}), deathstring); EXPECT_DEATH(helper(not_null{p}), expected);
EXPECT_DEATH(helper_const(not_null{p}), deathstring); EXPECT_DEATH(helper_const(not_null{p}), expected);
} }
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
@ -498,10 +514,11 @@ TEST(notnull_tests, TestMakeNotNull)
EXPECT_TRUE(*x == 42); EXPECT_TRUE(*x == 42);
} }
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. TestMakeNotNull"; std::cerr << "Expected Death. TestMakeNotNull";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
{ {
const auto workaround_macro = []() { const auto workaround_macro = []() {
@ -509,7 +526,7 @@ TEST(notnull_tests, TestMakeNotNull)
const auto x = make_not_null(p1); const auto x = make_not_null(p1);
EXPECT_TRUE(*x == 42); EXPECT_TRUE(*x == 42);
}; };
EXPECT_DEATH(workaround_macro(), deathstring); EXPECT_DEATH(workaround_macro(), expected);
} }
{ {
@ -518,21 +535,21 @@ TEST(notnull_tests, TestMakeNotNull)
const auto x = make_not_null(p1); const auto x = make_not_null(p1);
EXPECT_TRUE(*x == 42); EXPECT_TRUE(*x == 42);
}; };
EXPECT_DEATH(workaround_macro(), deathstring); EXPECT_DEATH(workaround_macro(), expected);
} }
{ {
int* p = nullptr; int* p = nullptr;
EXPECT_DEATH(helper(make_not_null(p)), deathstring); EXPECT_DEATH(helper(make_not_null(p)), expected);
EXPECT_DEATH(helper_const(make_not_null(p)), deathstring); EXPECT_DEATH(helper_const(make_not_null(p)), expected);
} }
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
{ {
EXPECT_DEATH(make_not_null(nullptr), deathstring); EXPECT_DEATH(make_not_null(nullptr), expected);
EXPECT_DEATH(helper(make_not_null(nullptr)), deathstring); EXPECT_DEATH(helper(make_not_null(nullptr)), expected);
EXPECT_DEATH(helper_const(make_not_null(nullptr)), deathstring); EXPECT_DEATH(helper_const(make_not_null(nullptr)), expected);
} }
#endif #endif
} }

View File

@ -20,7 +20,7 @@
using namespace gsl; using namespace gsl;
GSL_SUPPRESS(f.23) // NO-FORMAT: attribute GSL_SUPPRESS(f .23) // NO-FORMAT: attribute
void f(int* i) { *i += 1; } void f(int* i) { *i += 1; }
TEST(owner_tests, basic_test) TEST(owner_tests, basic_test)
@ -34,10 +34,10 @@ TEST(owner_tests, basic_test)
TEST(owner_tests, check_pointer_constraint) TEST(owner_tests, check_pointer_constraint)
{ {
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
{ {
owner<int> integerTest = 10; owner<int> integerTest = 10;
owner<std::shared_ptr<int>> sharedPtrTest(new int(10)); owner<std::shared_ptr<int>> sharedPtrTest(new int(10));
} }
#endif #endif
} }

View File

@ -17,7 +17,7 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <gsl/byte> // for byte #include <gsl/byte> // for byte
#include <gsl/span> // for span, span_iterator, operator==, operator!= #include <gsl/span> // for span, span_iterator, operator==, operator!=
#include <array> // for array #include <array> // for array
#include <cstddef> // for ptrdiff_t #include <cstddef> // for ptrdiff_t

View File

@ -16,27 +16,26 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <gsl/span> // for span and span_ext
#include <gsl/util> // for narrow_cast, at #include <gsl/util> // for narrow_cast, at
#include <gsl/span_ext> // for operator==, operator!=, make_span
#include <array> // for array #include <array> // for array
#include <iostream> // for cerr #include <iostream> // for cerr
#include <vector> // for vector #include <vector> // for vector
using namespace std; using namespace std;
using namespace gsl; using namespace gsl;
namespace #include "deathTestCommon.h"
{
static constexpr char deathstring[] = "Expected Death";
} // namespace
TEST(span_ext_test, make_span_from_pointer_length_constructor) TEST(span_ext_test, make_span_from_pointer_length_constructor)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. from_pointer_length_constructor"; std::cerr << "Expected Death. from_pointer_length_constructor";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
int arr[4] = {1, 2, 3, 4}; int arr[4] = {1, 2, 3, 4};
{ {
@ -57,7 +56,7 @@ TEST(span_ext_test, make_span_from_pointer_length_constructor)
{ {
int* p = nullptr; int* p = nullptr;
auto workaround_macro = [=]() { make_span(p, 2); }; auto workaround_macro = [=]() { make_span(p, 2); };
EXPECT_DEATH(workaround_macro(), deathstring); EXPECT_DEATH(workaround_macro(), expected);
} }
} }
@ -88,273 +87,275 @@ TEST(span_ext_test, make_span_from_pointer_pointer_construction)
} }
TEST(span_ext_test, make_span_from_array_constructor) TEST(span_ext_test, make_span_from_array_constructor)
{ {
int arr[5] = {1, 2, 3, 4, 5}; int arr[5] = {1, 2, 3, 4, 5};
int arr2d[2][3] = {1, 2, 3, 4, 5, 6}; int arr2d[2][3] = {1, 2, 3, 4, 5, 6};
int arr3d[2][3][2] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; int arr3d[2][3][2] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
{ {
const auto s = make_span(arr); const auto s = make_span(arr);
EXPECT_TRUE(s.size() == 5); EXPECT_TRUE(s.size() == 5);
EXPECT_TRUE(s.data() == std::addressof(arr[0])); EXPECT_TRUE(s.data() == std::addressof(arr[0]));
} }
{ {
const auto s = make_span(std::addressof(arr2d[0]), 1); const auto s = make_span(std::addressof(arr2d[0]), 1);
EXPECT_TRUE(s.size() == 1); EXPECT_TRUE(s.size() == 1);
EXPECT_TRUE(s.data() == std::addressof(arr2d[0])); EXPECT_TRUE(s.data() == std::addressof(arr2d[0]));
} }
{ {
const auto s = make_span(std::addressof(arr3d[0]), 1); const auto s = make_span(std::addressof(arr3d[0]), 1);
EXPECT_TRUE(s.size() == 1); EXPECT_TRUE(s.size() == 1);
EXPECT_TRUE(s.data() == std::addressof(arr3d[0])); EXPECT_TRUE(s.data() == std::addressof(arr3d[0]));
} }
} }
TEST(span_ext_test, make_span_from_dynamic_array_constructor) TEST(span_ext_test, make_span_from_dynamic_array_constructor)
{ {
double(*arr)[3][4] = new double[100][3][4]; double(*arr)[3][4] = new double[100][3][4];
{ {
auto s = make_span(&arr[0][0][0], 10); auto s = make_span(&arr[0][0][0], 10);
EXPECT_TRUE(s.size() == 10); EXPECT_TRUE(s.size() == 10);
EXPECT_TRUE(s.data() == &arr[0][0][0]); EXPECT_TRUE(s.data() == &arr[0][0][0]);
} }
delete[] arr; delete[] arr;
} }
TEST(span_ext_test, make_span_from_std_array_constructor) TEST(span_ext_test, make_span_from_std_array_constructor)
{ {
std::array<int, 4> arr = {1, 2, 3, 4}; std::array<int, 4> arr = {1, 2, 3, 4};
{ {
auto s = make_span(arr); auto s = make_span(arr);
EXPECT_TRUE(s.size() == arr.size()); EXPECT_TRUE(s.size() == arr.size());
EXPECT_TRUE(s.data() == arr.data()); EXPECT_TRUE(s.data() == arr.data());
} }
// This test checks for the bug found in gcc 6.1, 6.2, 6.3, 6.4, 6.5 7.1, 7.2, 7.3 - issue #590 // This test checks for the bug found in gcc 6.1, 6.2, 6.3, 6.4, 6.5 7.1, 7.2, 7.3 - issue #590
{ {
span<int> s1 = make_span(arr); span<int> s1 = make_span(arr);
static span<int> s2; static span<int> s2;
s2 = s1; s2 = s1;
#if defined(__GNUC__) && __GNUC__ == 6 && (__GNUC_MINOR__ == 4 || __GNUC_MINOR__ == 5) && \ #if defined(__GNUC__) && __GNUC__ == 6 && (__GNUC_MINOR__ == 4 || __GNUC_MINOR__ == 5) && \
__GNUC_PATCHLEVEL__ == 0 && defined(__OPTIMIZE__) __GNUC_PATCHLEVEL__ == 0 && defined(__OPTIMIZE__)
// Known to be broken in gcc 6.4 and 6.5 with optimizations // Known to be broken in gcc 6.4 and 6.5 with optimizations
// Issue in gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83116 // Issue in gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83116
EXPECT_TRUE(s1.size() == 4); EXPECT_TRUE(s1.size() == 4);
EXPECT_TRUE(s2.size() == 0); EXPECT_TRUE(s2.size() == 0);
#else #else
EXPECT_TRUE(s1.size() == s2.size()); EXPECT_TRUE(s1.size() == s2.size());
#endif #endif
} }
} }
TEST(span_ext_test, make_span_from_const_std_array_constructor) TEST(span_ext_test, make_span_from_const_std_array_constructor)
{ {
const std::array<int, 4> arr = {1, 2, 3, 4}; const std::array<int, 4> arr = {1, 2, 3, 4};
{ {
auto s = make_span(arr); auto s = make_span(arr);
EXPECT_TRUE(s.size() == arr.size()); EXPECT_TRUE(s.size() == arr.size());
EXPECT_TRUE(s.data() == arr.data()); EXPECT_TRUE(s.data() == arr.data());
} }
} }
TEST(span_ext_test, make_span_from_std_array_const_constructor) TEST(span_ext_test, make_span_from_std_array_const_constructor)
{ {
std::array<const int, 4> arr = {1, 2, 3, 4}; std::array<const int, 4> arr = {1, 2, 3, 4};
{ {
auto s = make_span(arr); auto s = make_span(arr);
EXPECT_TRUE(s.size() == arr.size()); EXPECT_TRUE(s.size() == arr.size());
EXPECT_TRUE(s.data() == arr.data()); EXPECT_TRUE(s.data() == arr.data());
} }
} }
TEST(span_ext_test, make_span_from_container_constructor) TEST(span_ext_test, make_span_from_container_constructor)
{ {
std::vector<int> v = {1, 2, 3}; std::vector<int> v = {1, 2, 3};
const std::vector<int> cv = v; const std::vector<int> cv = v;
{ {
auto s = make_span(v); auto s = make_span(v);
EXPECT_TRUE(s.size() == v.size()); EXPECT_TRUE(s.size() == v.size());
EXPECT_TRUE(s.data() == v.data()); EXPECT_TRUE(s.data() == v.data());
auto cs = make_span(cv); auto cs = make_span(cv);
EXPECT_TRUE(cs.size() == cv.size()); EXPECT_TRUE(cs.size() == cv.size());
EXPECT_TRUE(cs.data() == cv.data()); EXPECT_TRUE(cs.data() == cv.data());
} }
} }
TEST(span_test, interop_with_gsl_at) TEST(span_test, interop_with_gsl_at)
{ {
int arr[5] = {1, 2, 3, 4, 5}; int arr[5] = {1, 2, 3, 4, 5};
span<int> s{arr}; span<int> s{arr};
EXPECT_TRUE(at(s, 0) == 1); EXPECT_TRUE(at(s, 0) == 1);
EXPECT_TRUE(at(s, 1) == 2); EXPECT_TRUE(at(s, 1) == 2);
} }
TEST(span_ext_test, iterator_free_functions) TEST(span_ext_test, iterator_free_functions)
{ {
int a[] = {1, 2, 3, 4}; int a[] = {1, 2, 3, 4};
span<int> s{a}; span<int> s{a};
EXPECT_TRUE((std::is_same<decltype(s.begin()), decltype(begin(s))>::value)); EXPECT_TRUE((std::is_same<decltype(s.begin()), decltype(begin(s))>::value));
EXPECT_TRUE((std::is_same<decltype(s.end()), decltype(end(s))>::value)); EXPECT_TRUE((std::is_same<decltype(s.end()), decltype(end(s))>::value));
EXPECT_TRUE((std::is_same<decltype(std::cbegin(s)), decltype(cbegin(s))>::value)); EXPECT_TRUE((std::is_same<decltype(std::cbegin(s)), decltype(cbegin(s))>::value));
EXPECT_TRUE((std::is_same<decltype(std::cend(s)), decltype(cend(s))>::value)); EXPECT_TRUE((std::is_same<decltype(std::cend(s)), decltype(cend(s))>::value));
EXPECT_TRUE((std::is_same<decltype(s.rbegin()), decltype(rbegin(s))>::value)); EXPECT_TRUE((std::is_same<decltype(s.rbegin()), decltype(rbegin(s))>::value));
EXPECT_TRUE((std::is_same<decltype(s.rend()), decltype(rend(s))>::value)); EXPECT_TRUE((std::is_same<decltype(s.rend()), decltype(rend(s))>::value));
EXPECT_TRUE((std::is_same<decltype(std::crbegin(s)), decltype(crbegin(s))>::value)); EXPECT_TRUE((std::is_same<decltype(std::crbegin(s)), decltype(crbegin(s))>::value));
EXPECT_TRUE((std::is_same<decltype(std::crend(s)), decltype(crend(s))>::value)); EXPECT_TRUE((std::is_same<decltype(std::crend(s)), decltype(crend(s))>::value));
EXPECT_TRUE(s.begin() == begin(s)); EXPECT_TRUE(s.begin() == begin(s));
EXPECT_TRUE(s.end() == end(s)); EXPECT_TRUE(s.end() == end(s));
EXPECT_TRUE(s.rbegin() == rbegin(s)); EXPECT_TRUE(s.rbegin() == rbegin(s));
EXPECT_TRUE(s.rend() == rend(s)); EXPECT_TRUE(s.rend() == rend(s));
EXPECT_TRUE(s.begin() == cbegin(s)); EXPECT_TRUE(s.begin() == cbegin(s));
EXPECT_TRUE(s.end() == cend(s)); EXPECT_TRUE(s.end() == cend(s));
EXPECT_TRUE(s.rbegin() == crbegin(s)); EXPECT_TRUE(s.rbegin() == crbegin(s));
EXPECT_TRUE(s.rend() == crend(s)); EXPECT_TRUE(s.rend() == crend(s));
} }
TEST(span_ext_test, ssize_free_function) TEST(span_ext_test, ssize_free_function)
{ {
int a[] = {1, 2, 3, 4}; int a[] = {1, 2, 3, 4};
span<int> s{a}; span<int> s{a};
EXPECT_FALSE((std::is_same<decltype(s.size()), decltype(ssize(s))>::value)); EXPECT_FALSE((std::is_same<decltype(s.size()), decltype(ssize(s))>::value));
EXPECT_TRUE(s.size() == static_cast<std::size_t>(ssize(s))); EXPECT_TRUE(s.size() == static_cast<std::size_t>(ssize(s)));
} }
TEST(span_ext_test, comparison_operators) #ifndef GSL_KERNEL_MODE
{ TEST(span_ext_test, comparison_operators)
{ {
span<int> s1; {
span<int> s2; span<int> s1;
EXPECT_TRUE(s1 == s2); span<int> s2;
EXPECT_FALSE(s1 != s2); EXPECT_TRUE(s1 == s2);
EXPECT_FALSE(s1 < s2); EXPECT_FALSE(s1 != s2);
EXPECT_TRUE(s1 <= s2); EXPECT_FALSE(s1 < s2);
EXPECT_FALSE(s1 > s2); EXPECT_TRUE(s1 <= s2);
EXPECT_TRUE(s1 >= s2); EXPECT_FALSE(s1 > s2);
EXPECT_TRUE(s2 == s1); EXPECT_TRUE(s1 >= s2);
EXPECT_FALSE(s2 != s1); EXPECT_TRUE(s2 == s1);
EXPECT_FALSE(s2 != s1); EXPECT_FALSE(s2 != s1);
EXPECT_TRUE(s2 <= s1); EXPECT_FALSE(s2 != s1);
EXPECT_FALSE(s2 > s1); EXPECT_TRUE(s2 <= s1);
EXPECT_TRUE(s2 >= s1); EXPECT_FALSE(s2 > s1);
} EXPECT_TRUE(s2 >= s1);
}
{ {
int arr[] = {2, 1}; int arr[] = {2, 1};
span<int> s1 = arr; span<int> s1 = arr;
span<int> s2 = arr; span<int> s2 = arr;
EXPECT_TRUE(s1 == s2); EXPECT_TRUE(s1 == s2);
EXPECT_FALSE(s1 != s2); EXPECT_FALSE(s1 != s2);
EXPECT_FALSE(s1 < s2); EXPECT_FALSE(s1 < s2);
EXPECT_TRUE(s1 <= s2); EXPECT_TRUE(s1 <= s2);
EXPECT_FALSE(s1 > s2); EXPECT_FALSE(s1 > s2);
EXPECT_TRUE(s1 >= s2); EXPECT_TRUE(s1 >= s2);
EXPECT_TRUE(s2 == s1); EXPECT_TRUE(s2 == s1);
EXPECT_FALSE(s2 != s1); EXPECT_FALSE(s2 != s1);
EXPECT_FALSE(s2 < s1); EXPECT_FALSE(s2 < s1);
EXPECT_TRUE(s2 <= s1); EXPECT_TRUE(s2 <= s1);
EXPECT_FALSE(s2 > s1); EXPECT_FALSE(s2 > s1);
EXPECT_TRUE(s2 >= s1); EXPECT_TRUE(s2 >= s1);
} }
{ {
int arr[] = {2, 1}; // bigger int arr[] = {2, 1}; // bigger
span<int> s1; span<int> s1;
span<int> s2 = arr; span<int> s2 = arr;
EXPECT_TRUE(s1 != s2); EXPECT_TRUE(s1 != s2);
EXPECT_TRUE(s2 != s1); EXPECT_TRUE(s2 != s1);
EXPECT_FALSE(s1 == s2); EXPECT_FALSE(s1 == s2);
EXPECT_FALSE(s2 == s1); EXPECT_FALSE(s2 == s1);
EXPECT_TRUE(s1 < s2); EXPECT_TRUE(s1 < s2);
EXPECT_FALSE(s2 < s1); EXPECT_FALSE(s2 < s1);
EXPECT_TRUE(s1 <= s2); EXPECT_TRUE(s1 <= s2);
EXPECT_FALSE(s2 <= s1); EXPECT_FALSE(s2 <= s1);
EXPECT_TRUE(s2 > s1); EXPECT_TRUE(s2 > s1);
EXPECT_FALSE(s1 > s2); EXPECT_FALSE(s1 > s2);
EXPECT_TRUE(s2 >= s1); EXPECT_TRUE(s2 >= s1);
EXPECT_FALSE(s1 >= s2); EXPECT_FALSE(s1 >= s2);
} }
{ {
int arr1[] = {1, 2}; int arr1[] = {1, 2};
int arr2[] = {1, 2}; int arr2[] = {1, 2};
span<int> s1 = arr1; span<int> s1 = arr1;
span<int> s2 = arr2; span<int> s2 = arr2;
EXPECT_TRUE(s1 == s2); EXPECT_TRUE(s1 == s2);
EXPECT_FALSE(s1 != s2); EXPECT_FALSE(s1 != s2);
EXPECT_FALSE(s1 < s2); EXPECT_FALSE(s1 < s2);
EXPECT_TRUE(s1 <= s2); EXPECT_TRUE(s1 <= s2);
EXPECT_FALSE(s1 > s2); EXPECT_FALSE(s1 > s2);
EXPECT_TRUE(s1 >= s2); EXPECT_TRUE(s1 >= s2);
EXPECT_TRUE(s2 == s1); EXPECT_TRUE(s2 == s1);
EXPECT_FALSE(s2 != s1); EXPECT_FALSE(s2 != s1);
EXPECT_FALSE(s2 < s1); EXPECT_FALSE(s2 < s1);
EXPECT_TRUE(s2 <= s1); EXPECT_TRUE(s2 <= s1);
EXPECT_FALSE(s2 > s1); EXPECT_FALSE(s2 > s1);
EXPECT_TRUE(s2 >= s1); EXPECT_TRUE(s2 >= s1);
} }
{ {
int arr[] = {1, 2, 3}; int arr[] = {1, 2, 3};
span<int> s1 = {&arr[0], 2}; // shorter span<int> s1 = {&arr[0], 2}; // shorter
span<int> s2 = arr; // longer span<int> s2 = arr; // longer
EXPECT_TRUE(s1 != s2); EXPECT_TRUE(s1 != s2);
EXPECT_TRUE(s2 != s1); EXPECT_TRUE(s2 != s1);
EXPECT_FALSE(s1 == s2); EXPECT_FALSE(s1 == s2);
EXPECT_FALSE(s2 == s1); EXPECT_FALSE(s2 == s1);
EXPECT_TRUE(s1 < s2); EXPECT_TRUE(s1 < s2);
EXPECT_FALSE(s2 < s1); EXPECT_FALSE(s2 < s1);
EXPECT_TRUE(s1 <= s2); EXPECT_TRUE(s1 <= s2);
EXPECT_FALSE(s2 <= s1); EXPECT_FALSE(s2 <= s1);
EXPECT_TRUE(s2 > s1); EXPECT_TRUE(s2 > s1);
EXPECT_FALSE(s1 > s2); EXPECT_FALSE(s1 > s2);
EXPECT_TRUE(s2 >= s1); EXPECT_TRUE(s2 >= s1);
EXPECT_FALSE(s1 >= s2); EXPECT_FALSE(s1 >= s2);
} }
{ {
int arr1[] = {1, 2}; // smaller int arr1[] = {1, 2}; // smaller
int arr2[] = {2, 1}; // bigger int arr2[] = {2, 1}; // bigger
span<int> s1 = arr1; span<int> s1 = arr1;
span<int> s2 = arr2; span<int> s2 = arr2;
EXPECT_TRUE(s1 != s2); EXPECT_TRUE(s1 != s2);
EXPECT_TRUE(s2 != s1); EXPECT_TRUE(s2 != s1);
EXPECT_FALSE(s1 == s2); EXPECT_FALSE(s1 == s2);
EXPECT_FALSE(s2 == s1); EXPECT_FALSE(s2 == s1);
EXPECT_TRUE(s1 < s2); EXPECT_TRUE(s1 < s2);
EXPECT_FALSE(s2 < s1); EXPECT_FALSE(s2 < s1);
EXPECT_TRUE(s1 <= s2); EXPECT_TRUE(s1 <= s2);
EXPECT_FALSE(s2 <= s1); EXPECT_FALSE(s2 <= s1);
EXPECT_TRUE(s2 > s1); EXPECT_TRUE(s2 > s1);
EXPECT_FALSE(s1 > s2); EXPECT_FALSE(s1 > s2);
EXPECT_TRUE(s2 >= s1); EXPECT_TRUE(s2 >= s1);
EXPECT_FALSE(s1 >= s2); EXPECT_FALSE(s1 >= s2);
} }
} }
#endif // GSL_KERNEL_MODE

File diff suppressed because it is too large Load Diff

View File

@ -14,23 +14,33 @@
// //
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#include <gsl/pointers> // for not_null, operator<, operator<=, operator>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <gsl/pointers> // for not_null, operator<, operator<=, operator>
#include "deathTestCommon.h"
using namespace gsl; using namespace gsl;
namespace namespace
{ {
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute // clang-format off
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
// clang-format on
bool helper(not_null<int*> p) { return *p == 12; } bool helper(not_null<int*> p) { return *p == 12; }
// clang-format off
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
// clang-format on
bool helper_const(not_null<const int*> p) { return *p == 12; } bool helper_const(not_null<const int*> p) { return *p == 12; }
// clang-format off
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
// clang-format on
bool strict_helper(strict_not_null<int*> p) { return *p == 12; } bool strict_helper(strict_not_null<int*> p) { return *p == 12; }
// clang-format off
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
// clang-format on
bool strict_helper_const(strict_not_null<const int*> p) { return *p == 12; } bool strict_helper_const(strict_not_null<const int*> p) { return *p == 12; }
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
@ -123,17 +133,14 @@ TEST(strict_notnull_tests, TestStrictNotNull)
} }
#if defined(__cplusplus) && (__cplusplus >= 201703L) #if defined(__cplusplus) && (__cplusplus >= 201703L)
namespace
{
static constexpr char deathstring[] = "Expected Death";
}
TEST(strict_notnull_tests, TestStrictNotNullConstructorTypeDeduction) TEST(strict_notnull_tests, TestStrictNotNullConstructorTypeDeduction)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. TestStrictNotNullConstructorTypeDeduction"; std::cerr << "Expected Death. TestStrictNotNullConstructorTypeDeduction";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
{ {
int i = 42; int i = 42;
@ -161,7 +168,7 @@ TEST(strict_notnull_tests, TestStrictNotNullConstructorTypeDeduction)
int* p1 = nullptr; int* p1 = nullptr;
const strict_not_null x{p1}; const strict_not_null x{p1};
}; };
EXPECT_DEATH(workaround_macro(), deathstring); EXPECT_DEATH(workaround_macro(), expected);
} }
{ {
@ -169,14 +176,14 @@ TEST(strict_notnull_tests, TestStrictNotNullConstructorTypeDeduction)
const int* p1 = nullptr; const int* p1 = nullptr;
const strict_not_null x{p1}; const strict_not_null x{p1};
}; };
EXPECT_DEATH(workaround_macro(), deathstring); EXPECT_DEATH(workaround_macro(), expected);
} }
{ {
int* p = nullptr; int* p = nullptr;
EXPECT_DEATH(helper(strict_not_null{p}), deathstring); EXPECT_DEATH(helper(strict_not_null{p}), expected);
EXPECT_DEATH(helper_const(strict_not_null{p}), deathstring); EXPECT_DEATH(helper_const(strict_not_null{p}), expected);
} }
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS

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 Expects, 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
@ -28,13 +28,11 @@
#include <type_traits> // for remove_reference<>::type #include <type_traits> // for remove_reference<>::type
#include <vector> // for vector, allocator #include <vector> // for vector, allocator
#include "deathTestCommon.h"
using namespace std; using namespace std;
using namespace gsl; using namespace gsl;
namespace
{
static constexpr char deathstring[] = "Expected Death";
}
// Generic string functions // Generic string functions
namespace generic namespace generic
@ -76,8 +74,7 @@ T create()
template <class T> template <class T>
void use(basic_string_span<T, gsl::dynamic_extent>) void use(basic_string_span<T, gsl::dynamic_extent>)
{ {}
}
#endif #endif
czstring_span<> CreateTempName(string_span<> span) czstring_span<> CreateTempName(string_span<> span)
@ -85,7 +82,8 @@ czstring_span<> CreateTempName(string_span<> span)
Expects(span.size() > 1); Expects(span.size() > 1);
std::size_t last = 0; std::size_t last = 0;
if (span.size() > 4) { if (span.size() > 4)
{
span[0] = 't'; span[0] = 't';
span[1] = 'm'; span[1] = 'm';
span[2] = 'p'; span[2] = 'p';
@ -102,7 +100,8 @@ cwzstring_span<> CreateTempNameW(wstring_span<> span)
Expects(span.size() > 1); Expects(span.size() > 1);
std::size_t last = 0; std::size_t last = 0;
if (span.size() > 4) { if (span.size() > 4)
{
span[0] = L't'; span[0] = L't';
span[1] = L'm'; span[1] = L'm';
span[2] = L'p'; span[2] = L'p';
@ -119,7 +118,8 @@ cu16zstring_span<> CreateTempNameU16(u16string_span<> span)
Expects(span.size() > 1); Expects(span.size() > 1);
std::size_t last = 0; std::size_t last = 0;
if (span.size() > 4) { if (span.size() > 4)
{
span[0] = u't'; span[0] = u't';
span[1] = u'm'; span[1] = u'm';
span[2] = u'p'; span[2] = u'p';
@ -136,7 +136,8 @@ cu32zstring_span<> CreateTempNameU32(u32string_span<> span)
Expects(span.size() > 1); Expects(span.size() > 1);
std::size_t last = 0; std::size_t last = 0;
if (span.size() > 4) { if (span.size() > 4)
{
span[0] = U't'; span[0] = U't';
span[1] = U'm'; span[1] = U'm';
span[2] = U'p'; span[2] = U'p';
@ -950,10 +951,11 @@ TEST(string_span_tests, Conversion)
TEST(string_span_tests, zstring) TEST(string_span_tests, zstring)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. zstring"; std::cerr << "Expected Death. zstring";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
// create zspan from zero terminated string // create zspan from zero terminated string
{ {
@ -973,7 +975,7 @@ TEST(string_span_tests, zstring)
buf[0] = 'a'; buf[0] = 'a';
auto workaround_macro = [&]() { const zstring_span<> zspan({buf, 1}); }; auto workaround_macro = [&]() { const zstring_span<> zspan({buf, 1}); };
EXPECT_DEATH(workaround_macro(), deathstring); EXPECT_DEATH(workaround_macro(), expected);
} }
// usage scenario: create zero-terminated temp file name and pass to a legacy API // usage scenario: create zero-terminated temp file name and pass to a legacy API
@ -981,7 +983,8 @@ TEST(string_span_tests, zstring)
char buf[10]; char buf[10];
auto name = CreateTempName({buf, 10}); auto name = CreateTempName({buf, 10});
if (!name.empty()) { if (!name.empty())
{
czstring<> str = name.assume_z(); czstring<> str = name.assume_z();
EXPECT_TRUE(generic::strlen(str) == 3); EXPECT_TRUE(generic::strlen(str) == 3);
EXPECT_TRUE(*(str + 3) == '\0'); EXPECT_TRUE(*(str + 3) == '\0');
@ -991,10 +994,11 @@ TEST(string_span_tests, zstring)
TEST(string_span_tests, wzstring) TEST(string_span_tests, wzstring)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. wzstring"; std::cerr << "Expected Death. wzstring";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
// create zspan from zero terminated string // create zspan from zero terminated string
{ {
@ -1014,7 +1018,7 @@ TEST(string_span_tests, wzstring)
buf[0] = L'a'; buf[0] = L'a';
const auto workaround_macro = [&]() { const wzstring_span<> zspan({buf, 1}); }; const auto workaround_macro = [&]() { const wzstring_span<> zspan({buf, 1}); };
EXPECT_DEATH(workaround_macro(), deathstring); EXPECT_DEATH(workaround_macro(), expected);
} }
// usage scenario: create zero-terminated temp file name and pass to a legacy API // usage scenario: create zero-terminated temp file name and pass to a legacy API
@ -1022,7 +1026,8 @@ TEST(string_span_tests, wzstring)
wchar_t buf[10]; wchar_t buf[10];
const auto name = CreateTempNameW({buf, 10}); const auto name = CreateTempNameW({buf, 10});
if (!name.empty()) { if (!name.empty())
{
cwzstring<> str = name.assume_z(); cwzstring<> str = name.assume_z();
EXPECT_TRUE(generic::strnlen(str, 10) == 3); EXPECT_TRUE(generic::strnlen(str, 10) == 3);
EXPECT_TRUE(*(str + 3) == L'\0'); EXPECT_TRUE(*(str + 3) == L'\0');
@ -1032,10 +1037,11 @@ TEST(string_span_tests, wzstring)
TEST(string_span_tests, u16zstring) TEST(string_span_tests, u16zstring)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. u16zstring"; std::cerr << "Expected Death. u16zstring";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
// create zspan from zero terminated string // create zspan from zero terminated string
{ {
@ -1055,7 +1061,7 @@ TEST(string_span_tests, u16zstring)
buf[0] = u'a'; buf[0] = u'a';
const auto workaround_macro = [&]() { const u16zstring_span<> zspan({buf, 1}); }; const auto workaround_macro = [&]() { const u16zstring_span<> zspan({buf, 1}); };
EXPECT_DEATH(workaround_macro(), deathstring); EXPECT_DEATH(workaround_macro(), expected);
} }
// usage scenario: create zero-terminated temp file name and pass to a legacy API // usage scenario: create zero-terminated temp file name and pass to a legacy API
@ -1063,7 +1069,8 @@ TEST(string_span_tests, u16zstring)
char16_t buf[10]; char16_t buf[10];
const auto name = CreateTempNameU16({buf, 10}); const auto name = CreateTempNameU16({buf, 10});
if (!name.empty()) { if (!name.empty())
{
cu16zstring<> str = name.assume_z(); cu16zstring<> str = name.assume_z();
EXPECT_TRUE(generic::strnlen(str, 10) == 3); EXPECT_TRUE(generic::strnlen(str, 10) == 3);
EXPECT_TRUE(*(str + 3) == L'\0'); EXPECT_TRUE(*(str + 3) == L'\0');
@ -1073,10 +1080,11 @@ TEST(string_span_tests, u16zstring)
TEST(string_span_tests, u32zstring) TEST(string_span_tests, u32zstring)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. u31zstring"; std::cerr << "Expected Death. u31zstring";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
// create zspan from zero terminated string // create zspan from zero terminated string
{ {
@ -1096,7 +1104,7 @@ TEST(string_span_tests, u32zstring)
buf[0] = u'a'; buf[0] = u'a';
const auto workaround_macro = [&]() { const u32zstring_span<> zspan({buf, 1}); }; const auto workaround_macro = [&]() { const u32zstring_span<> zspan({buf, 1}); };
EXPECT_DEATH(workaround_macro(), deathstring); EXPECT_DEATH(workaround_macro(), expected);
} }
// usage scenario: create zero-terminated temp file name and pass to a legacy API // usage scenario: create zero-terminated temp file name and pass to a legacy API
@ -1104,7 +1112,8 @@ TEST(string_span_tests, u32zstring)
char32_t buf[10]; char32_t buf[10];
const auto name = CreateTempNameU32({buf, 10}); const auto name = CreateTempNameU32({buf, 10});
if (!name.empty()) { if (!name.empty())
{
cu32zstring<> str = name.assume_z(); cu32zstring<> str = name.assume_z();
EXPECT_TRUE(generic::strnlen(str, 10) == 3); EXPECT_TRUE(generic::strnlen(str, 10) == 3);
EXPECT_TRUE(*(str + 3) == L'\0'); EXPECT_TRUE(*(str + 3) == L'\0');

View File

@ -16,14 +16,14 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <gsl/util> // finally, narrow_cast
#include <gsl/narrow> // for narrow, narrowing_error
#include <algorithm> // for move #include <algorithm> // for move
#include <cstddef> // for std::ptrdiff_t
#include <functional> // for reference_wrapper, _Bind_helper<>::type #include <functional> // for reference_wrapper, _Bind_helper<>::type
#include <gsl/narrow> // for narrow, narrowing_error
#include <gsl/util> // finally, narrow_cast
#include <limits> // for numeric_limits #include <limits> // for numeric_limits
#include <stdint.h> // for uint32_t, int32_t #include <stdint.h> // for uint32_t, int32_t
#include <type_traits> // for is_same #include <type_traits> // for is_same
#include <cstddef> // for std::ptrdiff_t
using namespace gsl; using namespace gsl;
@ -32,8 +32,7 @@ namespace
void f(int& i) { i += 1; } void f(int& i) { i += 1; }
static int j = 0; static int j = 0;
void g() { j += 1; } void g() { j += 1; }
} } // namespace
TEST(utils_tests, sanity_check_for_gsl_index_typedef) TEST(utils_tests, sanity_check_for_gsl_index_typedef)
{ {
@ -123,6 +122,7 @@ TEST(utils_tests, narrow_cast)
EXPECT_TRUE(uc == 44); EXPECT_TRUE(uc == 44);
} }
#ifndef GSL_KERNEL_MODE
TEST(utils_tests, narrow) TEST(utils_tests, narrow)
{ {
int n = 120; int n = 120;
@ -145,3 +145,4 @@ TEST(utils_tests, narrow)
n = -42; n = -42;
EXPECT_THROW(narrow<unsigned>(n), narrowing_error); EXPECT_THROW(narrow<unsigned>(n), narrowing_error);
} }
#endif // GSL_KERNEL_MODE