From 534bb4c663673740b1e116b7a7275af2067fab98 Mon Sep 17 00:00:00 2001 From: Alexey Malov Date: Thu, 13 Apr 2017 03:34:39 +0300 Subject: [PATCH 1/4] Added support of not_null comparison (#473) * Added support of not_null comparison * The return type of not_null comparison operators is determined using SFINAE #474 * tests for gsl::not_null comparison were added * not_null comparison tests were rewritten to compare pointers to objects located in the same array * not_null comparison was simplified --- include/gsl/gsl | 36 ++++++++++ tests/notnull_tests.cpp | 145 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 181 insertions(+) diff --git a/include/gsl/gsl b/include/gsl/gsl index 26742be..b3dbe33 100644 --- a/include/gsl/gsl +++ b/include/gsl/gsl @@ -117,6 +117,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/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 *[]) From 66cf6896e54d7fec5acf14457499fdb7a409a545 Mon Sep 17 00:00:00 2001 From: Julien Monat Rodier Date: Thu, 13 Apr 2017 10:46:31 -0700 Subject: [PATCH 2/4] Updated submodule reference for unittest-cpp to latest (#483) - updated to latest unittest-cpp --- .gitmodules | 2 +- tests/unittest-cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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/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 From c2f953f2eb7ab501325a7ec5656b400d54b8a345 Mon Sep 17 00:00:00 2001 From: "Maciej T. Nowak" Date: Thu, 13 Apr 2017 22:55:20 +0200 Subject: [PATCH 3/4] Add value_type to span (#425) * Add value_type to span Currently I'm working on project which involves a lot of `span`s and mocking via Google Mock. Unfortunately a lot of standard matchers requires `value_type` type definition inside container which `gsl::span` lacks. This pull request add `value_type` type definition inside `gsl::span` * Strip cv from value_type of span and span_iterator --- include/gsl/span | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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 From c5851a8161938798c5594a66420cb814fea92711 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Mon, 17 Apr 2017 12:26:38 -0700 Subject: [PATCH 4/4] Turn warnings into errors (#488) --- tests/CMakeLists.txt | 6 +++--- tests/at_tests.cpp | 14 ++++++++------ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 40c46d5..b56cc26 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} -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} -fno-strict-aliasing -std=c++14 -Werror -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} -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} -fno-strict-aliasing -std=c++11 -Werror -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; }