Skip to content

Commit 7e0943d

Browse files
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 <carsonradtke@microsoft.com>
1 parent 2d343b0 commit 7e0943d

File tree

4 files changed

+82
-7
lines changed

4 files changed

+82
-7
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
CMakeFiles
2-
build
2+
build*/
33
tests/CMakeFiles
44
tests/Debug
55
*.opensdf

include/gsl/pointers

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -173,47 +173,47 @@ std::ostream& operator<<(std::ostream& os, const not_null<T>& val)
173173
#endif // !defined(GSL_NO_IOSTREAMS)
174174

175175
template <class T, class U>
176-
auto operator==(const not_null<T>& lhs,
176+
constexpr auto operator==(const not_null<T>& lhs,
177177
const not_null<U>& rhs) noexcept(noexcept(lhs.get() == rhs.get()))
178178
-> decltype(lhs.get() == rhs.get())
179179
{
180180
return lhs.get() == rhs.get();
181181
}
182182

183183
template <class T, class U>
184-
auto operator!=(const not_null<T>& lhs,
184+
constexpr auto operator!=(const not_null<T>& lhs,
185185
const not_null<U>& rhs) noexcept(noexcept(lhs.get() != rhs.get()))
186186
-> decltype(lhs.get() != rhs.get())
187187
{
188188
return lhs.get() != rhs.get();
189189
}
190190

191191
template <class T, class U>
192-
auto operator<(const not_null<T>& lhs,
192+
constexpr auto operator<(const not_null<T>& lhs,
193193
const not_null<U>& rhs) noexcept(noexcept(std::less<>{}(lhs.get(), rhs.get())))
194194
-> decltype(std::less<>{}(lhs.get(), rhs.get()))
195195
{
196196
return std::less<>{}(lhs.get(), rhs.get());
197197
}
198198

199199
template <class T, class U>
200-
auto operator<=(const not_null<T>& lhs,
200+
constexpr auto operator<=(const not_null<T>& lhs,
201201
const not_null<U>& rhs) noexcept(noexcept(std::less_equal<>{}(lhs.get(), rhs.get())))
202202
-> decltype(std::less_equal<>{}(lhs.get(), rhs.get()))
203203
{
204204
return std::less_equal<>{}(lhs.get(), rhs.get());
205205
}
206206

207207
template <class T, class U>
208-
auto operator>(const not_null<T>& lhs,
208+
constexpr auto operator>(const not_null<T>& lhs,
209209
const not_null<U>& rhs) noexcept(noexcept(std::greater<>{}(lhs.get(), rhs.get())))
210210
-> decltype(std::greater<>{}(lhs.get(), rhs.get()))
211211
{
212212
return std::greater<>{}(lhs.get(), rhs.get());
213213
}
214214

215215
template <class T, class U>
216-
auto operator>=(const not_null<T>& lhs,
216+
constexpr auto operator>=(const not_null<T>& lhs,
217217
const not_null<U>& rhs) noexcept(noexcept(std::greater_equal<>{}(lhs.get(), rhs.get())))
218218
-> decltype(std::greater_equal<>{}(lhs.get(), rhs.get()))
219219
{

tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ add_executable(gsl_tests
204204
assertion_tests.cpp
205205
at_tests.cpp
206206
byte_tests.cpp
207+
constexpr_notnull_tests.cpp
207208
notnull_tests.cpp
208209
owner_tests.cpp
209210
pointers_tests.cpp

tests/constexpr_notnull_tests.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
///////////////////////////////////////////////////////////////////////////////
2+
//
3+
// Copyright (c) 2025 Microsoft Corporation. All rights reserved.
4+
//
5+
// This code is licensed under the MIT License (MIT).
6+
//
7+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
8+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
9+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
10+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
11+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
12+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
13+
// THE SOFTWARE.
14+
//
15+
///////////////////////////////////////////////////////////////////////////////
16+
17+
#include <gsl/pointers> // for not_null
18+
#include <gtest/gtest.h>
19+
20+
#include <type_traits> // for declval
21+
22+
using namespace gsl;
23+
24+
namespace
25+
{
26+
constexpr bool comparison_test(const int* ptr1, const int* ptr2)
27+
{
28+
const not_null<const int*> p1(ptr1);
29+
const not_null<const int*> p1_same(ptr1);
30+
const not_null<const int*> p2(ptr2);
31+
32+
// Testing operator==
33+
const bool eq_result = (p1 == p1_same); // Should be true
34+
const bool neq_result = (p1 != p2); // Should be true
35+
36+
// Testing operator<= and operator>=
37+
const bool le_result = (p1 <= p1_same); // Should be true
38+
const bool ge_result = (p1 >= p1_same); // Should be true
39+
40+
// The exact comparison results will depend on pointer ordering,
41+
// but we can verify that the basic equality checks work as expected
42+
return eq_result && neq_result && le_result && ge_result;
43+
}
44+
45+
constexpr bool workaround_test(const int* ptr1, const int* ptr2)
46+
{
47+
const not_null<const int*> p1(ptr1);
48+
const not_null<const int*> p1_same(ptr1);
49+
const not_null<const int*> p2(ptr2);
50+
51+
// Using .get() to compare
52+
const bool eq_result = (p1.get() == p1_same.get()); // Should be true
53+
const bool neq_result = (p1.get() != p2.get()); // Should be true
54+
55+
return eq_result && neq_result;
56+
}
57+
} // namespace
58+
59+
constexpr int test_value1 = 1;
60+
constexpr int test_value2 = 2;
61+
62+
static_assert(comparison_test(&test_value1, &test_value2), "not_null comparison operators should be constexpr");
63+
static_assert(workaround_test(&test_value1, &test_value2), "not_null .get() comparison workaround should work");
64+
65+
TEST(notnull_constexpr_tests, TestNotNullConstexprComparison)
66+
{
67+
// This test simply verifies that the constexpr functions compile and run
68+
// If we got here, it means the constexpr comparison operators are working
69+
static const int value1 = 1;
70+
static const int value2 = 2;
71+
EXPECT_TRUE(comparison_test(&value1, &value2));
72+
EXPECT_TRUE(workaround_test(&value1, &value2));
73+
}
74+

0 commit comments

Comments
 (0)