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>&amp;&amp;</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