1 /**
2 * @file svnxx/tristate.hpp
3 * @copyright
4 * ====================================================================
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
20 * under the License.
21 * ====================================================================
22 * @endcopyright
23 */
24
25 #ifndef SVNXX_TRISTATE_HPP
26 #define SVNXX_TRISTATE_HPP
27
28 #include "svn_types_impl.h"
29
30 #include <cstdint>
31
32 #if defined(SVNXX_USE_BOOST) || defined(DOXYGEN)
33 #include <boost/logic/tribool.hpp>
34 #endif
35
36 namespace apache {
37 namespace subversion {
38 namespace svnxx {
39
40 /**
41 * @brief A three-state Boolean-like type.
42 *
43 * @c tristate values represent one of three states:
44 * @li the @e true state (equivalent to Boolean @c true);
45 * @li the @e false state (equivalent to Boolean @c false);
46 * @li the @e unknown state.
47 *
48 * @c tristate constructors, methods and operators are all
49 * compile-time constant expressions and can be used to initialize
50 * other @c constexpr values. And unlike most other types,
51 * comparisons and logical operations between @c tristate values
52 * return a @c tristate, not a @c bool.
53 *
54 * Given a @c tristate value @a t, the state it represents can be
55 * uniquely determined by the following coding pattern:
56 * @code{.cpp}
57 * if (t) {
58 * // t is true
59 * }
60 * else if (!t) {
61 * // t is false
62 * else {
63 * // t is unknown
64 * }
65 * @endcode
66 *
67 * @note Inspired by <tt>boost::tribool</tt>
68 */
69 class tristate
70 {
71 struct impl
72 {
truevalapache::subversion::svnxx::tristate::impl73 void trueval() {};
74 };
75 using safe_bool = void (impl::*)();
76
77 // The default constructor creates the unkonwn state.
tristate()78 constexpr tristate() noexcept
79 : value(unknown_value)
80 {}
81
82 public:
83 /**
84 * @brief Factory method for the @e unknown state.
85 */
unknown()86 static constexpr tristate unknown() noexcept
87 {
88 return tristate(/*unknown_value*/);
89 }
90
91 /**
92 * @brief Constructor for the @e true and @e false states.
93 */
tristate(bool initial_value)94 constexpr tristate(bool initial_value) noexcept
95 : value(initial_value ? true_value : false_value)
96 {}
97
98 /**
99 * @brief Safe conversion to @c bool.
100 * @returns a @e true-like value only when this @c tristate is the
101 * @e true state.
102 */
operator safe_bool() const103 constexpr operator safe_bool() const noexcept
104 {
105 return value == true_value ? &impl::trueval : 0;
106 }
107
108 /**
109 * @brief Logical negation.
110 * @returns the logical negation of a @c tristate, according to
111 * the following table:
112 * <table border=1>
113 * <tr>
114 * <th><center><code>!</code></center></th>
115 * <th></th>
116 * </tr>
117 * <tr>
118 * <th><center><em>false</em></center></th>
119 * <td><center><em>true</em></center></td>
120 * </tr>
121 * <tr>
122 * <th><center><em>true</em></center></th>
123 * <td><center><em>false</em></center></td>
124 * </tr>
125 * <tr>
126 * <th><center><em>unknown</em></center></th>
127 * <td><center><em>unknown</em></center></td>
128 * </tr>
129 * </table>
130 */
operator !() const131 constexpr tristate operator!() const noexcept
132 {
133 return (value == false_value ? tristate(true)
134 : (value == true_value ? tristate(false)
135 : tristate::unknown()));
136 }
137
138 private:
139 // NOTE: Keep these values identical to those in svn_tristate_t!
140 enum : std::uint8_t {
141 false_value = svn_tristate_false,
142 true_value = svn_tristate_true,
143 unknown_value = svn_tristate_unknown
144 } value;
145
146 #if defined(SVNXX_USE_BOOST) || defined(DOXYGEN)
147 public:
148 /**
149 * @brief Conversion from <tt>boost::tribool</tt>.
150 * @returns a @c tribool value equivalent to the @a t.
151 * @note Avalible only if @c SVNXX_USE_BOOST is defined.
152 */
tristate(boost::tribool t)153 constexpr tristate(boost::tribool t) noexcept
154 : value(boost::indeterminate(t) ? unknown_value
155 : (t ? true_value : false_value))
156 {}
157
158 /**
159 * @brief Conversion to <tt>boost::tribool</tt>.
160 * @returns a <tt>boost::tribool</tt> value equivalent to the @c
161 * tristate value.
162 * @note Avalible only if @c SVNXX_USE_BOOST is defined.
163 */
operator boost::tribool() const164 constexpr operator boost::tribool() const noexcept
165 {
166 return (value == true_value ? boost::tribool(true)
167 : (value == false_value ? boost::tribool(false)
168 : boost::tribool(boost::indeterminate)));
169 }
170 #endif
171 };
172
173 /**
174 * @related tristate
175 * @brief Test for the @e unknown @c tristate state.
176 * @returns @c true only if @a t is the @e unknown state.
177 */
unknown(tristate t)178 constexpr inline bool unknown(tristate t) noexcept
179 {
180 return bool(t) == bool(!t);
181 }
182
183 /**
184 * @related tristate
185 * @brief Logical conjunction.
186 * @returns the result of a logical @c AND of two @c tristate
187 * values, according to the following table:
188 * <table border=1>
189 * <tr>
190 * <th><center><code>&&</code></center></th>
191 * <th><center><em>false</em></center></th>
192 * <th><center><em>true</em></center></th>
193 * <th><center><em>unknown</em></center></th>
194 * </tr>
195 * <tr>
196 * <th><center><em>false</em></center></th>
197 * <td><center><em>false</em></center></td>
198 * <td><center><em>false</em></center></td>
199 * <td><center><em>false</em></center></td>
200 * </tr>
201 * <tr>
202 * <th><center><em>true</em></center></th>
203 * <td><center><em>false</em></center></td>
204 * <td><center><em>true</em></center></td>
205 * <td><center><em>unknown</em></center></td>
206 * </tr>
207 * <tr>
208 * <th><center><em>unknown</em></center></th>
209 * <td><center><em>false</em></center></td>
210 * <td><center><em>unknown</em></center></td>
211 * <td><center><em>unknown</em></center></td>
212 * </tr>
213 * </table>
214 */
operator &&(tristate t,tristate u)215 constexpr inline tristate operator&&(tristate t, tristate u) noexcept
216 {
217 return (bool(!t) || bool(!u) ? tristate(false)
218 : (bool(t) && bool(u) ? tristate(true)
219 : tristate::unknown()));
220 }
221
222 /**
223 * @related tristate
224 * @overload
225 */
operator &&(tristate t,bool b)226 constexpr inline tristate operator&&(tristate t, bool b) noexcept
227 {
228 return b ? t : tristate(false);
229 }
230
231 /**
232 * @related tristate
233 * @overload
234 */
operator &&(bool b,tristate t)235 constexpr inline tristate operator&&(bool b, tristate t) noexcept
236 {
237 return b ? t : tristate(false);
238 }
239
240 #if defined(SVNXX_USE_BOOST) || defined(DOXYGEN)
241 /**
242 * @related tristate
243 * @overload
244 * @note Avalible only if @c SVNXX_USE_BOOST is defined.
245 */
operator &&(tristate t,boost::tribool b)246 constexpr inline tristate operator&&(tristate t, boost::tribool b) noexcept
247 {
248 return t && tristate(b);
249 }
250
251 /**
252 * @related tristate
253 * @overload
254 * @note Avalible only if @c SVNXX_USE_BOOST is defined.
255 */
operator &&(boost::tribool b,tristate t)256 constexpr inline tristate operator&&(boost::tribool b, tristate t) noexcept
257 {
258 return tristate(b) && t;
259 }
260 #endif
261
262 /**
263 * @related tristate
264 * @brief Logical disjunction.
265 * @returns the result of a logical @c OR of two @c tristate
266 * values, according to the following table:
267 * <table border=1>
268 * <tr>
269 * <th><center><code>||</code></center></th>
270 * <th><center><em>false</em></center></th>
271 * <th><center><em>true</em></center></th>
272 * <th><center><em>unknown</em></center></th>
273 * </tr>
274 * <tr>
275 * <th><center><em>false</em></center></th>
276 * <td><center><em>false</em></center></td>
277 * <td><center><em>true</em></center></td>
278 * <td><center><em>unknown</em></center></td>
279 * </tr>
280 * <tr>
281 * <th><center><em>true</em></center></th>
282 * <td><center><em>true</em></center></td>
283 * <td><center><em>true</em></center></td>
284 * <td><center><em>true</em></center></td>
285 * </tr>
286 * <tr>
287 * <th><center><em>unknown</em></center></th>
288 * <td><center><em>unknown</em></center></td>
289 * <td><center><em>true</em></center></td>
290 * <td><center><em>unknown</em></center></td>
291 * </tr>
292 * </table>
293 */
operator ||(tristate t,tristate u)294 constexpr inline tristate operator||(tristate t, tristate u) noexcept
295 {
296 return (bool(!t) && bool(!u) ? tristate(false)
297 : (bool(t) || bool(u) ? tristate(true)
298 : tristate::unknown()));
299 }
300
301 /**
302 * @related tristate
303 * @overload
304 */
operator ||(tristate t,bool b)305 constexpr inline tristate operator||(tristate t, bool b) noexcept
306 {
307 return b ? tristate(true) : t;
308 }
309
310 /**
311 * @related tristate
312 * @overload
313 */
operator ||(bool b,tristate t)314 constexpr inline tristate operator||(bool b, tristate t) noexcept
315 {
316 return b ? tristate(true) : t;
317 }
318
319 #if defined(SVNXX_USE_BOOST) || defined(DOXYGEN)
320 /**
321 * @related tristate
322 * @overload
323 * @note Avalible only if @c SVNXX_USE_BOOST is defined.
324 */
operator ||(tristate t,boost::tribool b)325 constexpr inline tristate operator||(tristate t, boost::tribool b) noexcept
326 {
327 return t || tristate(b);
328 }
329
330 /**
331 * @related tristate
332 * @overload
333 * @note Avalible only if @c SVNXX_USE_BOOST is defined.
334 */
operator ||(boost::tribool b,tristate t)335 constexpr inline tristate operator||(boost::tribool b, tristate t) noexcept
336 {
337 return tristate(b) || t;
338 }
339 #endif
340
341 /**
342 * @related tristate
343 * @brief Equality comparison.
344 * @returns the result of comparing two @c tristate values for
345 * equality, according to the following table:
346 * <table border=1>
347 * <tr>
348 * <th><center><code>==</code></center></th>
349 * <th><center><em>false</em></center></th>
350 * <th><center><em>true</em></center></th>
351 * <th><center><em>unknown</em></center></th>
352 * </tr>
353 * <tr>
354 * <th><center><em>false</em></center></th>
355 * <td><center><em>true</em></center></td>
356 * <td><center><em>false</em></center></td>
357 * <td><center><em>unknown</em></center></td>
358 * </tr>
359 * <tr>
360 * <th><center><em>true</em></center></th>
361 * <td><center><em>false</em></center></td>
362 * <td><center><em>true</em></center></td>
363 * <td><center><em>unknown</em></center></td>
364 * </tr>
365 * <tr>
366 * <th><center><em>unknown</em></center></th>
367 * <td><center><em>unknown</em></center></td>
368 * <td><center><em>unknown</em></center></td>
369 * <td><center><em>unknown</em></center></td>
370 * </tr>
371 * </table>
372 */
operator ==(tristate t,tristate u)373 constexpr inline tristate operator==(tristate t, tristate u) noexcept
374 {
375 return (unknown(t) || unknown(u) ? tristate::unknown()
376 : ((t && u) || (!t && !u)));
377 }
378
379 /**
380 * @related tristate
381 * @overload
382 */
operator ==(tristate t,bool b)383 constexpr inline tristate operator==(tristate t, bool b) noexcept
384 {
385 return t == tristate(b);
386 }
387
388 /**
389 * @related tristate
390 * @overload
391 */
operator ==(bool b,tristate t)392 constexpr inline tristate operator==(bool b, tristate t) noexcept
393 {
394 return tristate(b) == t;
395 }
396
397 #if defined(SVNXX_USE_BOOST) || defined(DOXYGEN)
398 /**
399 * @related tristate
400 * @overload
401 * @note Avalible only if @c SVNXX_USE_BOOST is defined.
402 */
operator ==(tristate t,boost::tribool b)403 constexpr inline tristate operator==(tristate t, boost::tribool b) noexcept
404 {
405 return t == tristate(b);
406 }
407
408 /**
409 * @related tristate
410 * @overload
411 * @note Avalible only if @c SVNXX_USE_BOOST is defined.
412 */
operator ==(boost::tribool b,tristate t)413 constexpr inline tristate operator==(boost::tribool b, tristate t) noexcept
414 {
415 return tristate(b) == t;
416 }
417 #endif
418
419 /**
420 * @related tristate
421 * @brief Inquality comparison.
422 * @returns the result of comparing two @c tristate values for
423 * inequality, according to the following table:
424 * <table border=1>
425 * <tr>
426 * <th><center><code>!=</code></center></th>
427 * <th><center><em>false</em></center></th>
428 * <th><center><em>true</em></center></th>
429 * <th><center><em>unknown</em></center></th>
430 * </tr>
431 * <tr>
432 * <th><center><em>false</em></center></th>
433 * <td><center><em>false</em></center></td>
434 * <td><center><em>true</em></center></td>
435 * <td><center><em>unknown</em></center></td>
436 * </tr>
437 * <tr>
438 * <th><center><em>true</em></center></th>
439 * <td><center><em>true</em></center></td>
440 * <td><center><em>false</em></center></td>
441 * <td><center><em>unknown</em></center></td>
442 * </tr>
443 * <tr>
444 * <th><center><em>unknown</em></center></th>
445 * <td><center><em>unknown</em></center></td>
446 * <td><center><em>unknown</em></center></td>
447 * <td><center><em>unknown</em></center></td>
448 * </tr>
449 * </table>
450 */
operator !=(tristate t,tristate u)451 constexpr inline tristate operator!=(tristate t, tristate u) noexcept
452 {
453 return (unknown(t) || unknown(u) ? tristate::unknown()
454 : !((t && u) || (!t && !u)));
455 }
456
457 /**
458 * @related tristate
459 * @overload
460 */
operator !=(tristate t,bool b)461 constexpr inline tristate operator!=(tristate t, bool b) noexcept
462 {
463 return t != tristate(b);
464 }
465
466 /**
467 * @related tristate
468 * @overload
469 */
operator !=(bool b,tristate t)470 constexpr inline tristate operator!=(bool b, tristate t) noexcept
471 {
472 return tristate(b) != t;
473 }
474
475 #if defined(SVNXX_USE_BOOST) || defined(DOXYGEN)
476 /**
477 * @related tristate
478 * @overload
479 * @note Avalible only if @c SVNXX_USE_BOOST is defined.
480 */
operator !=(tristate t,boost::tribool b)481 constexpr inline tristate operator!=(tristate t, boost::tribool b) noexcept
482 {
483 return t != tristate(b);
484 }
485
486 /**
487 * @related tristate
488 * @overload
489 * @note Avalible only if @c SVNXX_USE_BOOST is defined.
490 */
operator !=(boost::tribool b,tristate t)491 constexpr inline tristate operator!=(boost::tribool b, tristate t) noexcept
492 {
493 return tristate(b) != t;
494 }
495 #endif
496
497 } // namespace svnxx
498 } // namespace subversion
499 } // namespace apache
500
501 #endif // SVNXX_TRISTATE_HPP
502