From 7e0943d20d3082b4f350a7e0c3088d2388e934de Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 May 2025 11:52:47 -0600 Subject: [PATCH] Add constexpr to not_null comparison operators (#1208) * Initial plan for issue * Add test and plan to make not_null comparison functions constexpr Co-authored-by: carsonRadtke <10507970+carsonRadtke@users.noreply.github.com> * Add constexpr to not_null comparison operators Co-authored-by: carsonRadtke <10507970+carsonRadtke@users.noreply.github.com> * Fix copyright year in constexpr_notnull_tests.cpp Co-authored-by: carsonRadtke <10507970+carsonRadtke@users.noreply.github.com> * Fix constexpr tests for better compiler compatibility Co-authored-by: carsonRadtke <10507970+carsonRadtke@users.noreply.github.com> * Remove build artifacts and update .gitignore Co-authored-by: carsonRadtke <10507970+carsonRadtke@users.noreply.github.com> * Fix constexpr tests to be compatible with more compilers Co-authored-by: carsonRadtke <10507970+carsonRadtke@users.noreply.github.com> * copilot: Provide more project context for the Copilot coding agent (#1207) * copilot: create .github/copilot-instructions.md This file provides additional context and instructions to GitHub Copilot so it can better understand the codebase and coding conventions. More can be found about this file at the following links: - [Best practices for using Copilot to work on tasks](https://docs.github.com/en/enterprise-cloud@latest/copilot/using-github-copilot/using-copilot-coding-agent-to-work-on-tasks/best-practices-for-using-copilot-to-work-on-taskshttps://docs.github.com/en/enterprise-cloud@latest/copilot/using-github-copilot/using-copilot-coding-agent-to-work-on-tasks/best-practices-for-using-copilot-to-work-on-tasks) - [Adding repository custom instructions for GitHub Copilot](https://docs.github.com/en/enterprise-cloud@latest/copilot/customizing-copilot/adding-repository-custom-instructions-for-github-copilot?tool=webuihttps://docs.github.com/en/enterprise-cloud@latest/copilot/customizing-copilot/adding-repository-custom-instructions-for-github-copilot) * copilot: add copilot-setup-steps.yml This new workflow is done when copilot loads into an environment and enables copilot to be sure it has the proper dependencies before working on changes. Also included in the change are explicit instructions on what to do before reporting back "done". * Initial plan for issue * Rebase onto main and verify changes meet project guidelines Co-authored-by: carsonRadtke <10507970+carsonRadtke@users.noreply.github.com> * Update .gitignore to exclude build-cxx* directories Co-authored-by: carsonRadtke <10507970+carsonRadtke@users.noreply.github.com> * Fix newline at end of constexpr_notnull_tests.cpp and update .gitignore Co-authored-by: carsonRadtke <10507970+carsonRadtke@users.noreply.github.com> * Remove C++14 feature check that is redundant since C++14 is the minimum supported standard Co-authored-by: carsonRadtke <10507970+carsonRadtke@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: carsonRadtke <10507970+carsonRadtke@users.noreply.github.com> Co-authored-by: Carson Radtke --- .gitignore | 2 +- include/gsl/pointers | 12 ++--- tests/CMakeLists.txt | 1 + tests/constexpr_notnull_tests.cpp | 74 +++++++++++++++++++++++++++++++ 4 files changed, 82 insertions(+), 7 deletions(-) create mode 100644 tests/constexpr_notnull_tests.cpp 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)); +} +