diff --git a/.gitignore b/.gitignore index 326971f..4ca21ed 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ CMakeFiles -build +build*/ tests/CMakeFiles tests/Debug *.opensdf diff --git a/include/gsl/pointers b/include/gsl/pointers index 3a5409a..5e69f58 100644 --- a/include/gsl/pointers +++ b/include/gsl/pointers @@ -173,7 +173,7 @@ std::ostream& operator<<(std::ostream& os, const not_null& val) #endif // !defined(GSL_NO_IOSTREAMS) template -auto operator==(const not_null& lhs, +constexpr auto operator==(const not_null& lhs, const not_null& rhs) noexcept(noexcept(lhs.get() == rhs.get())) -> decltype(lhs.get() == rhs.get()) { @@ -181,7 +181,7 @@ auto operator==(const not_null& lhs, } template -auto operator!=(const not_null& lhs, +constexpr auto operator!=(const not_null& lhs, const not_null& rhs) noexcept(noexcept(lhs.get() != rhs.get())) -> decltype(lhs.get() != rhs.get()) { @@ -189,7 +189,7 @@ auto operator!=(const not_null& lhs, } template -auto operator<(const not_null& lhs, +constexpr auto operator<(const not_null& lhs, const not_null& rhs) noexcept(noexcept(std::less<>{}(lhs.get(), rhs.get()))) -> decltype(std::less<>{}(lhs.get(), rhs.get())) { @@ -197,7 +197,7 @@ auto operator<(const not_null& lhs, } template -auto operator<=(const not_null& lhs, +constexpr auto operator<=(const not_null& lhs, const not_null& rhs) noexcept(noexcept(std::less_equal<>{}(lhs.get(), rhs.get()))) -> decltype(std::less_equal<>{}(lhs.get(), rhs.get())) { @@ -205,7 +205,7 @@ auto operator<=(const not_null& lhs, } template -auto operator>(const not_null& lhs, +constexpr auto operator>(const not_null& lhs, const not_null& rhs) noexcept(noexcept(std::greater<>{}(lhs.get(), rhs.get()))) -> decltype(std::greater<>{}(lhs.get(), rhs.get())) { @@ -213,7 +213,7 @@ auto operator>(const not_null& lhs, } template -auto operator>=(const not_null& lhs, +constexpr auto operator>=(const not_null& lhs, const not_null& rhs) noexcept(noexcept(std::greater_equal<>{}(lhs.get(), rhs.get()))) -> decltype(std::greater_equal<>{}(lhs.get(), rhs.get())) { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 1f2bf7a..a8fd30a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -204,6 +204,7 @@ add_executable(gsl_tests assertion_tests.cpp at_tests.cpp byte_tests.cpp + constexpr_notnull_tests.cpp notnull_tests.cpp owner_tests.cpp pointers_tests.cpp diff --git a/tests/constexpr_notnull_tests.cpp b/tests/constexpr_notnull_tests.cpp new file mode 100644 index 0000000..9192f85 --- /dev/null +++ b/tests/constexpr_notnull_tests.cpp @@ -0,0 +1,74 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2025 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +/////////////////////////////////////////////////////////////////////////////// + +#include // for not_null +#include + +#include // for declval + +using namespace gsl; + +namespace +{ +constexpr bool comparison_test(const int* ptr1, const int* ptr2) +{ + const not_null p1(ptr1); + const not_null p1_same(ptr1); + const not_null p2(ptr2); + + // Testing operator== + const bool eq_result = (p1 == p1_same); // Should be true + const bool neq_result = (p1 != p2); // Should be true + + // Testing operator<= and operator>= + const bool le_result = (p1 <= p1_same); // Should be true + const bool ge_result = (p1 >= p1_same); // Should be true + + // The exact comparison results will depend on pointer ordering, + // but we can verify that the basic equality checks work as expected + return eq_result && neq_result && le_result && ge_result; +} + +constexpr bool workaround_test(const int* ptr1, const int* ptr2) +{ + const not_null p1(ptr1); + const not_null p1_same(ptr1); + const not_null p2(ptr2); + + // Using .get() to compare + const bool eq_result = (p1.get() == p1_same.get()); // Should be true + const bool neq_result = (p1.get() != p2.get()); // Should be true + + return eq_result && neq_result; +} +} // namespace + +constexpr int test_value1 = 1; +constexpr int test_value2 = 2; + +static_assert(comparison_test(&test_value1, &test_value2), "not_null comparison operators should be constexpr"); +static_assert(workaround_test(&test_value1, &test_value2), "not_null .get() comparison workaround should work"); + +TEST(notnull_constexpr_tests, TestNotNullConstexprComparison) +{ + // This test simply verifies that the constexpr functions compile and run + // If we got here, it means the constexpr comparison operators are working + static const int value1 = 1; + static const int value2 = 2; + EXPECT_TRUE(comparison_test(&value1, &value2)); + EXPECT_TRUE(workaround_test(&value1, &value2)); +} +