diff --git a/.gitmodules b/.gitmodules index d9229ae..b198402 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "tests/unittest-cpp"] path = tests/unittest-cpp - url = https://github.com/Microsoft/unittest-cpp.git + url = https://github.com/unittest-cpp/unittest-cpp.git diff --git a/include/gsl/gsl b/include/gsl/gsl index 7ef7742..63c9e7b 100644 --- a/include/gsl/gsl +++ b/include/gsl/gsl @@ -118,6 +118,42 @@ std::ostream& operator<<(std::ostream& os, const not_null& val) return os; } +template +auto operator==(const not_null& lhs, const not_null& rhs) -> decltype(lhs.get() == rhs.get()) +{ + return lhs.get() == rhs.get(); +} + +template +auto operator!=(const not_null& lhs, const not_null& rhs) -> decltype(lhs.get() != rhs.get()) +{ + return lhs.get() != rhs.get(); +} + +template +auto operator<(const not_null& lhs, const not_null& rhs) -> decltype(lhs.get() < rhs.get()) +{ + return lhs.get() < rhs.get(); +} + +template +auto operator<=(const not_null& lhs, const not_null& rhs) -> decltype(lhs.get() <= rhs.get()) +{ + return lhs.get() <= rhs.get(); +} + +template +auto operator>(const not_null& lhs, const not_null& rhs) -> decltype(lhs.get() > rhs.get()) +{ + return lhs.get() > rhs.get(); +} + +template +auto operator>=(const not_null& lhs, const not_null& rhs) -> decltype(lhs.get() >= rhs.get()) +{ + return lhs.get() >= rhs.get(); +} + // more unwanted operators template std::ptrdiff_t operator-(const not_null&, const not_null&) = delete; diff --git a/include/gsl/span b/include/gsl/span index 957c9e6..3a8d31d 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -133,7 +133,7 @@ namespace details using element_type_ = typename Span::element_type; public: using iterator_category = std::random_access_iterator_tag; - using value_type = std::remove_const_t; + using value_type = std::remove_cv_t; using difference_type = typename Span::index_type; using reference = @@ -337,6 +337,7 @@ class span public: // constants and types using element_type = ElementType; + using value_type = std::remove_cv_t; using index_type = std::ptrdiff_t; using pointer = element_type*; using reference = element_type&; @@ -346,6 +347,8 @@ public: using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; + using size_type = index_type; + constexpr static const index_type extent = Extent; // [span.cons], span constructors, copy, assignment, and destructor diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2ed2170..be9e65c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -18,15 +18,15 @@ add_definitions(-DGSL_THROW_ON_CONTRACT_VIOLATION) if(MSVC) # has the support we need # remove unnecessary warnings about unchecked iterators add_definitions(-D_SCL_SECURE_NO_WARNINGS) - add_compile_options(/EHsc /W4) + add_compile_options(/EHsc /W4 /WX) else() include(CheckCXXCompilerFlag) CHECK_CXX_COMPILER_FLAG("-std=c++14" COMPILER_SUPPORTS_CXX14) CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11) if(COMPILER_SUPPORTS_CXX14) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -fno-strict-aliasing -std=c++14 -O3 -Wall -Wextra -Wpedantic -Wno-missing-braces -Wconversion -Wsign-conversion -Wctor-dtor-privacy -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Woverloaded-virtual") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -fno-strict-aliasing -std=c++14 -Wall -Wextra -Wpedantic -Wno-missing-braces -Wconversion -Wsign-conversion -Wctor-dtor-privacy -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Woverloaded-virtual") elseif(COMPILER_SUPPORTS_CXX11) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -fno-strict-aliasing -std=c++11 -O3 -Wall -Wextra -Wpedantic -Wno-missing-braces -Wconversion -Wsign-conversion -Wctor-dtor-privacy -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Woverloaded-virtual") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -fno-strict-aliasing -std=c++11 -Wall -Wextra -Wpedantic -Wno-missing-braces -Wconversion -Wsign-conversion -Wctor-dtor-privacy -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Woverloaded-virtual") else() message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.") endif() diff --git a/tests/at_tests.cpp b/tests/at_tests.cpp index 79f8ddd..db89c34 100644 --- a/tests/at_tests.cpp +++ b/tests/at_tests.cpp @@ -45,8 +45,8 @@ SUITE(at_tests) const std::array& c_a = a; for (int i = 0; i < 4; ++i) { - CHECK(&gsl::at(a, i) == &a[i]); - CHECK(&gsl::at(c_a, i) == &a[i]); + CHECK(&gsl::at(a, i) == &a[static_cast(i)]); + CHECK(&gsl::at(c_a, i) == &a[static_cast(i)]); } CHECK_THROW(gsl::at(a, -1), fail_fast); @@ -61,8 +61,8 @@ SUITE(at_tests) const std::vector& c_a = a; for (int i = 0; i < 4; ++i) { - CHECK(&gsl::at(a, i) == &a[i]); - CHECK(&gsl::at(c_a, i) == &a[i]); + CHECK(&gsl::at(a, i) == &a[static_cast(i)]); + CHECK(&gsl::at(c_a, i) == &a[static_cast(i)]); } CHECK_THROW(gsl::at(a, -1), fail_fast); @@ -87,7 +87,7 @@ SUITE(at_tests) } } -#if !defined(_MSC_VER) || (defined(__clang__) || _MSC_VER >= 1910) +#if !defined(_MSC_VER) || defined(__clang__) || _MSC_VER >= 1910 static constexpr bool test_constexpr() { int a1[4] = { 1, 2, 3, 4 }; @@ -98,7 +98,9 @@ static constexpr bool test_constexpr() for (int i = 0; i < 4; ++i) { if (&gsl::at(a1, i) != &a1[i]) return false; if (&gsl::at(c_a1, i) != &a1[i]) return false; - if (&gsl::at(c_a2, i) != &c_a2[i]) return false; + // requires C++17: + // if (&gsl::at(a2, i) != &a2[static_cast(i)]) return false; + if (&gsl::at(c_a2, i) != &c_a2[static_cast(i)]) return false; if (gsl::at({1,2,3,4}, i) != i+1) return false; } diff --git a/tests/notnull_tests.cpp b/tests/notnull_tests.cpp index 201b797..1c2b50e 100644 --- a/tests/notnull_tests.cpp +++ b/tests/notnull_tests.cpp @@ -17,6 +17,8 @@ #include #include #include +#include +#include using namespace gsl; @@ -33,6 +35,54 @@ struct RefCounted T* p_; }; +// user defined smart pointer with comparison operators returning non bool value +template +struct CustomPtr +{ + CustomPtr(T* p) : p_(p) {} + operator T*() { return p_; } + bool operator !=(std::nullptr_t)const { return p_ != nullptr; } + T* p_ = nullptr; +}; + +template +std::string operator==(CustomPtr const& lhs, CustomPtr const& rhs) +{ + return reinterpret_cast(lhs.p_) == reinterpret_cast(rhs.p_) ? "true" : "false"; +} + +template +std::string operator!=(CustomPtr const& lhs, CustomPtr const& rhs) +{ + return reinterpret_cast(lhs.p_) != reinterpret_cast(rhs.p_) ? "true" : "false"; +} + +template +std::string operator<(CustomPtr const& lhs, CustomPtr const& rhs) +{ + return reinterpret_cast(lhs.p_) < reinterpret_cast(rhs.p_) ? "true" : "false"; +} + +template +std::string operator>(CustomPtr const& lhs, CustomPtr const& rhs) +{ + return reinterpret_cast(lhs.p_) > reinterpret_cast(rhs.p_) ? "true" : "false"; +} + +template +std::string operator<=(CustomPtr const& lhs, CustomPtr const& rhs) +{ + return reinterpret_cast(lhs.p_) <= reinterpret_cast(rhs.p_) ? "true" : "false"; +} + +template +std::string operator>=(CustomPtr const& lhs, CustomPtr const& rhs) +{ + return reinterpret_cast(lhs.p_) >= reinterpret_cast(rhs.p_) ? "true" : "false"; +} + + + SUITE(NotNullTests) { @@ -95,6 +145,101 @@ SUITE(NotNullTests) int* q = nullptr; CHECK_THROW(p = q, fail_fast); } + + TEST(TestNotNullRawPointerComparison) + { + int ints[2] = {42, 43}; + int* p1 = &ints[0]; + const int* p2 = &ints[1]; + + using NotNull1 = not_null; + using NotNull2 = not_null; + + CHECK((NotNull1(p1) == NotNull1(p1)) == true); + CHECK((NotNull1(p1) == NotNull2(p2)) == false); + + CHECK((NotNull1(p1) != NotNull1(p1)) == false); + CHECK((NotNull1(p1) != NotNull2(p2)) == true); + + CHECK((NotNull1(p1) < NotNull1(p1)) == false); + CHECK((NotNull1(p1) < NotNull2(p2)) == (p1 < p2)); + CHECK((NotNull2(p2) < NotNull1(p1)) == (p2 < p1)); + + CHECK((NotNull1(p1) > NotNull1(p1)) == false); + CHECK((NotNull1(p1) > NotNull2(p2)) == (p1 > p2)); + CHECK((NotNull2(p2) > NotNull1(p1)) == (p2 > p1)); + + CHECK((NotNull1(p1) <= NotNull1(p1)) == true); + CHECK((NotNull1(p1) <= NotNull2(p2)) == (p1 <= p2)); + CHECK((NotNull2(p2) <= NotNull1(p1)) == (p2 <= p1)); + + CHECK((NotNull1(p1) >= NotNull1(p1)) == true); + CHECK((NotNull1(p1) >= NotNull2(p2)) == (p1 >= p2)); + CHECK((NotNull2(p2) >= NotNull1(p1)) == (p2 >= p1)); + } + + TEST(TestNotNullSharedPtrComparison) + { + auto sp1 = std::make_shared(42); + auto sp2 = std::make_shared(43); + + using NotNullSp1 = not_null; + using NotNullSp2 = not_null; + + CHECK((NotNullSp1(sp1) == NotNullSp1(sp1)) == true); + CHECK((NotNullSp1(sp1) == NotNullSp2(sp2)) == false); + + CHECK((NotNullSp1(sp1) != NotNullSp1(sp1)) == false); + CHECK((NotNullSp1(sp1) != NotNullSp2(sp2)) == true); + + CHECK((NotNullSp1(sp1) < NotNullSp1(sp1)) == false); + CHECK((NotNullSp1(sp1) < NotNullSp2(sp2)) == (sp1 < sp2)); + CHECK((NotNullSp2(sp2) < NotNullSp1(sp1)) == (sp2 < sp1)); + + CHECK((NotNullSp1(sp1) > NotNullSp1(sp1)) == false); + CHECK((NotNullSp1(sp1) > NotNullSp2(sp2)) == (sp1 > sp2)); + CHECK((NotNullSp2(sp2) > NotNullSp1(sp1)) == (sp2 > sp1)); + + CHECK((NotNullSp1(sp1) <= NotNullSp1(sp1)) == true); + CHECK((NotNullSp1(sp1) <= NotNullSp2(sp2)) == (sp1 <= sp2)); + CHECK((NotNullSp2(sp2) <= NotNullSp1(sp1)) == (sp2 <= sp1)); + + CHECK((NotNullSp1(sp1) >= NotNullSp1(sp1)) == true); + CHECK((NotNullSp1(sp1) >= NotNullSp2(sp2)) == (sp1 >= sp2)); + CHECK((NotNullSp2(sp2) >= NotNullSp1(sp1)) == (sp2 >= sp1)); + } + + TEST(TestNotNullCustomPtrComparison) + { + int ints[2] = { 42, 43 }; + CustomPtr p1(&ints[0]); + CustomPtr p2(&ints[1]); + + using NotNull1 = not_null; + using NotNull2 = not_null; + + CHECK((NotNull1(p1) == NotNull1(p1)) == "true"); + CHECK((NotNull1(p1) == NotNull2(p2)) == "false"); + + CHECK((NotNull1(p1) != NotNull1(p1)) == "false"); + CHECK((NotNull1(p1) != NotNull2(p2)) == "true"); + + CHECK((NotNull1(p1) < NotNull1(p1)) == "false"); + CHECK((NotNull1(p1) < NotNull2(p2)) == (p1 < p2)); + CHECK((NotNull2(p2) < NotNull1(p1)) == (p2 < p1)); + + CHECK((NotNull1(p1) > NotNull1(p1)) == "false"); + CHECK((NotNull1(p1) > NotNull2(p2)) == (p1 > p2)); + CHECK((NotNull2(p2) > NotNull1(p1)) == (p2 > p1)); + + CHECK((NotNull1(p1) <= NotNull1(p1)) == "true"); + CHECK((NotNull1(p1) <= NotNull2(p2)) == (p1 <= p2)); + CHECK((NotNull2(p2) <= NotNull1(p1)) == (p2 <= p1)); + + CHECK((NotNull1(p1) >= NotNull1(p1)) == "true"); + CHECK((NotNull1(p1) >= NotNull2(p2)) == (p1 >= p2)); + CHECK((NotNull2(p2) >= NotNull1(p1)) == (p2 >= p1)); + } } int main(int, const char *[]) diff --git a/tests/unittest-cpp b/tests/unittest-cpp index dc6b908..c331bb0 160000 --- a/tests/unittest-cpp +++ b/tests/unittest-cpp @@ -1 +1 @@ -Subproject commit dc6b90838014ab985bf3cd74ac17ad9d00e1fbcb +Subproject commit c331bb0deaaf92659a31887c029ee34cac2ab19e