GCC Code Coverage Report


Directory: include/tts/
File: include/tts/tools/comparators.hpp
Date: 2026-10-14 16:28:14
Exec Total Coverage
Lines: 25 25 100.0%
Functions: 196 196 100.0%
Branches: 5 5 100.0%

Line Branch Exec Source
1 //======================================================================================================================
2 /*
3 TTS - Tiny Test System
4 Copyright : TTS Contributors & Maintainers
5 SPDX-License-Identifier: BSL-1.0
6 */
7 //======================================================================================================================
8 #pragma once
9
10 //======================================================================================================================
11 // Wrappers for comparisons with external setup
12 //======================================================================================================================
13 namespace tts::_
14 {
15 template<typename L, typename R> struct builtin_comparison
16 {
17 914 static constexpr bool equal(L const& l, R const& r)
18 {
19 static_assert(
20 !requires { compare_equal(l, r); },
21 "[TTS] tts::compare_equal is no longer a customization point. "
22 "Specialize tts::comparison<L, R>::equal instead.");
23
24 914 return l == r;
25 }
26
27 631 static constexpr bool less(L const& l, R const& r)
28 {
29 static_assert(
30 !requires { compare_less(l, r); },
31 "[TTS] tts::compare_less is no longer a customization point. "
32 "Specialize tts::comparison<L, R>::less instead.");
33
34
1/1
✓ Branch 1 taken 18 times.
631 return l < r;
35 }
36
37 34 static bool bit_equal(L const& l, R const& r)
38 {
39 static_assert(sizeof(L) == sizeof(R), "Types must have the same size for bitwise comparison");
40
41 34 return std::memcmp(&l, &r, sizeof(L)) == 0;
42 }
43 };
44 }
45
46 namespace tts
47 {
48 //====================================================================================================================
49 /**
50 @defgroup tools-comparison Comparison Utilities
51 @{
52 **/
53 //====================================================================================================================
54
55 //====================================================================================================================
56 /*!
57 @ingroup tools-comparison
58 @brief When two values are equal, when one comes before the other, and when their bits agree
59
60 Specialize this for your own types rather than overloading the free functions: a specialization
61 that does not match is a compilation error, where a misnamed overload used to be ignored in
62 silence.
63
64 The three members are `equal`, `less` and `bit_equal`. Write the ones the type needs and leave
65 the rest out: their defaults are `operator==`, `operator<` and a `memcmp` over the whole
66 object. That last one reads padding, so a type whose storage is wider than the value it
67 carries, such as a SIMD register wider than the lanes it holds, has to write `bit_equal`.
68
69 Both operand types are parameters, in the order they are written, so a comparison between two
70 different types is specialized on the pair rather than on either side of it.
71
72 The `compare_equal` and `compare_less` free functions this replaces are gone. An overload left
73 behind is reported where it would have been used, rather than ignored in silence.
74
75 @tparam L Type of the left-hand operand
76 @tparam R Type of the right-hand operand, the same as L unless stated otherwise
77
78 @groupheader{Example}
79 @snippet doc/comparators.cpp snippet1
80
81 A specialization that answers for `less` as well covers the ordering macros.
82
83 @snippet doc/comparators.cpp snippet2
84
85 A type whose storage is wider than the value it carries answers for `bit_equal`.
86
87 @snippet doc/comparators.cpp snippet3
88 **/
89 //====================================================================================================================
90 template<typename L, typename R = L> struct comparison
91 {
92 };
93
94 //! @}
95 }
96
97 namespace tts::_
98 {
99 // The fallback refuses a member that is there but does not take the operands.
100 struct bit_eq_t
101 {
102 40 template<typename L, typename R> constexpr bool operator()(L const& l, R const& r) const
103 {
104 if constexpr(requires { comparison<L, R>::bit_equal(l, r); })
105 {
106 6 return comparison<L, R>::bit_equal(l, r);
107 }
108 else
109 {
110 static_assert(
111 !requires { comparison<L, R>::bit_equal; },
112 "[TTS] tts::comparison<L, R>::bit_equal does not accept the two operands.");
113
114 34 return builtin_comparison<L, R>::bit_equal(l, r);
115 }
116 }
117 };
118
119 inline constexpr bit_eq_t bit_eq {};
120
121 struct bit_neq_t
122 {
123 13 template<typename L, typename R> constexpr bool operator()(L const& l, R const& r) const
124 {
125 13 return !bit_eq(l, r);
126 }
127 };
128
129 inline constexpr bit_neq_t bit_neq {};
130
131 struct eq_t
132 {
133 948 template<typename L, typename R> constexpr bool operator()(L const& l, R const& r) const
134 {
135 if constexpr(requires { comparison<L, R>::equal(l, r); })
136 {
137 34 return comparison<L, R>::equal(l, r);
138 }
139 else
140 {
141 static_assert(
142 !requires { comparison<L, R>::equal; },
143 "[TTS] tts::comparison<L, R>::equal does not accept the two operands.");
144
145 914 return builtin_comparison<L, R>::equal(l, r);
146 }
147 }
148 };
149
150 inline constexpr eq_t eq {};
151
152 struct neq_t
153 {
154 29 template<typename L, typename R> constexpr bool operator()(L const& l, R const& r) const
155 {
156 29 return !eq(l, r);
157 }
158 };
159
160 inline constexpr neq_t neq {};
161
162 struct lt_t
163 {
164 662 template<typename L, typename R> constexpr bool operator()(L const& l, R const& r) const
165 {
166 if constexpr(requires { comparison<L, R>::less(l, r); })
167 {
168 28 return comparison<L, R>::less(l, r);
169 }
170 else
171 {
172 static_assert(
173 !requires { comparison<L, R>::less; },
174 "[TTS] tts::comparison<L, R>::less does not accept the two operands.");
175
176 634 return builtin_comparison<L, R>::less(l, r);
177 }
178 }
179 };
180
181 inline constexpr lt_t lt {};
182
183 struct le_t
184 {
185 320 template<typename L, typename R> constexpr bool operator()(L const& l, R const& r) const
186 {
187
4/4
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 137 times.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 13 times.
320 return lt(l, r) || eq(l, r);
188 }
189 };
190
191 inline constexpr le_t le {};
192
193 struct gt_t
194 {
195 23 template<typename L, typename R> constexpr bool operator()(L const& l, R const& r) const
196 {
197 23 return !le(l, r);
198 }
199 };
200
201 inline constexpr gt_t gt {};
202
203 struct ge_t
204 {
205 305 template<typename L, typename R> constexpr bool operator()(L const& l, R const& r) const
206 {
207 305 return !lt(l, r);
208 }
209 };
210
211 inline constexpr ge_t ge {};
212 }
213