library of assembled shared sources |
http://lass.cocamware.com |
00001 /** @file 00002 * @author Bram de Greve (bramz@users.sourceforge.net) 00003 * @author Tom De Muer (tomdemuer@users.sourceforge.net) 00004 * 00005 * *** BEGIN LICENSE INFORMATION *** 00006 * 00007 * The contents of this file are subject to the Common Public Attribution License 00008 * Version 1.0 (the "License"); you may not use this file except in compliance with 00009 * the License. You may obtain a copy of the License at 00010 * http://lass.sourceforge.net/cpal-license. The License is based on the 00011 * Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover 00012 * use of software over a computer network and provide for limited attribution for 00013 * the Original Developer. In addition, Exhibit A has been modified to be consistent 00014 * with Exhibit B. 00015 * 00016 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT 00017 * WARRANTY OF ANY KIND, either express or implied. See the License for the specific 00018 * language governing rights and limitations under the License. 00019 * 00020 * The Original Code is LASS - Library of Assembled Shared Sources. 00021 * 00022 * The Initial Developer of the Original Code is Bram de Greve and Tom De Muer. 00023 * The Original Developer is the Initial Developer. 00024 * 00025 * All portions of the code written by the Initial Developer are: 00026 * Copyright (C) 2004-2007 the Initial Developer. 00027 * All Rights Reserved. 00028 * 00029 * Contributor(s): 00030 * 00031 * Alternatively, the contents of this file may be used under the terms of the 00032 * GNU General Public License Version 2 or later (the GPL), in which case the 00033 * provisions of GPL are applicable instead of those above. If you wish to allow use 00034 * of your version of this file only under the terms of the GPL and not to allow 00035 * others to use your version of this file under the CPAL, indicate your decision by 00036 * deleting the provisions above and replace them with the notice and other 00037 * provisions required by the GPL License. If you do not delete the provisions above, 00038 * a recipient may use your version of this file under either the CPAL or the GPL. 00039 * 00040 * *** END LICENSE INFORMATION *** 00041 */ 00042 00043 00044 00045 /** @class lass::num::TriBool 00046 * @brief a three-state boolean value with { true, false and lass::num::unknown } 00047 * @author Bram de Greve [BdG] 00048 * 00049 * Inspired by Boost three-state boolean logic library 'boost::tribool' by Doug Gregor 00050 * (gregod@cs.rpi.edu). 00051 * 00052 * Booleans are great to express binary states, to express if something is true or false. But they 00053 * lack the concept of @e Not-A-Number (@c NaN). Indeed, with traditional booleans, there's no way 00054 * to express that you don't know, that the boolean value is invalid. That's when this TriBool 00055 * comes into action. TriBool adds one extra state to the traditional @c true and @c false: 00056 * @c unknown. As said, this @c unknown acts like the @c NaN for floating point values and behaves 00057 * much the same way (though not @e entirely the same!). 00058 * 00059 * @section behaviour_unknown behaviour of unknown 00060 * 00061 * The first thing to know is that the value @c unknown can not come into existance as long as all 00062 * your operands are in a known state (@c true or @c false). You have to inject an @c unknown 00063 * value yourself, and this section merely describes how it will flow through your code. 00064 * 00065 * @b rule: <i>In TriBool unary expressions, if the argument is @c unknown, then the result will 00066 * yield @c unknown too.</i>. 00067 * 00068 * Check out @c operator! Indeed, if @c a is @c unknown, then @c !a is @c unknown too. 00069 * 00070 * @b rule: <i>In TriBool binary expressions, if at least one of the operands is @c unknown, then 00071 * the result yields @c unknown, @b except if one of the operands is known (@c true or 00072 * @c false) and provides enough information to result in a known state.</i> 00073 * 00074 * The first part is obvious. In an expression @c a @c == @c b , if one of the operands is 00075 * @c unknown, we can not possible know if @c a and @c b are equal or not. It will yield 00076 * @c unknown. However, there are two situations in which a binary expression with an unknown 00077 * operands still results in a known state. These are: 00078 * 00079 * - @c false @c && @c unknown yields @c false. Indeed, for an AND operation to yield @c true, 00080 * @e both operands must be @c true. Since we know at least one of them is @c false, we can know 00081 * for sure the result is @c false too. 00082 * - @c true @c || @c unknown yields @c true. Indeed, for an OR operation to yield @c true, 00083 * at @e least one of the operands must be @c true. Since we know the left operand is @c true 00084 * we know for sure we have at least one operand that is true, hence the result is @c true. 00085 * 00086 * Since AND and OR are commutative, this is also valid for @c unknown @c && @c false and 00087 * @c unknown @c || @c true . In all other cases, a binary expression with at least one @c unknown 00088 * operand will yield @c unknown. 00089 * 00090 * @note we said @c unknown behaves much like @c NaN, but that's not really true. If you 00091 * compare two operands that are @c NaN, you'll get @c false as result (a known state), 00092 * where as if both operands are @c unknown, it will not result @c false but @c unknown! 00093 * 00094 * @note in contrary to traditional boolean logic, @c a!=b @c || @c a==b does not always yield 00095 * @c true! It will be @c unknown if one of the operands is unknown. 00096 * 00097 * @section if_consequences consequences on if/else 00098 * 00099 * Care must be taken when TriBool variables are used in boolean context like @c if/else statements 00100 * (and @c for and @c while loops ...). For instance, the following examples are not equivalent 00101 * (as they would be for plain old boolean logic). Notice what happens if @c a is unknown! 00102 * 00103 * @code 00104 * TriBool a; 00105 * 00106 * if (a) 00107 * { 00108 * foo(); // called if a is true. 00109 * } 00110 * else 00111 * { 00112 * bar(); // called if a is false OR unknown. 00113 * } 00114 * 00115 * if (!a) 00116 * { 00117 * bar(); // called if a is false 00118 * } 00119 * else 00120 * { 00121 * foo(); // called if a is true OR unknown. 00122 * } 00123 * @endcode 00124 * 00125 * The discrepancy is due to the fact there isn't an unambigious way to reduce the three states 00126 * of a TriBool to the two states of the @c if/else statement, or the traditional boolean logic. 00127 * In the former, the @c if block tests if @c a is @c true and the @c else block gets the other 00128 * two states. In the latter, the @c if block tests if @c a is @c false and again the @c else 00129 * block gets the other two states. So, in any case, if @c a is unknown, you'll end up in the 00130 * @c else block. 00131 * 00132 * @note as you might notice, there's no conversion operator to @c bool. That's because of the 00133 * ambigious mapping from TriBool to @c bool as described above. But then how does 00134 * @c if @c (a) works? If does need a boolean value, doesn't it? The trick is in the 00135 * @c operator @c SafeBool(). It will return a non-NULL pointer if and only if the TriBool 00136 * is @c true, what invokes the @c if block. If the TriBool is @c false or @c unknown, then 00137 * a NULL pointer is returned instead and the @c else block is called. 00138 * 00139 * If you want to test for the three different cases in an @c if/else construction, your code will 00140 * typically look like the following: 00141 * 00142 * @code 00143 * if (a) 00144 * { 00145 * foo(); // called if a is true 00146 * } 00147 * else if (!a) 00148 * { 00149 * bar(); // called if a is false 00150 * } 00151 * else 00152 * { 00153 * fun(); // called if a is unknown 00154 * } 00155 * @endcode 00156 * 00157 * This is equivalent to: 00158 * 00159 * @code 00160 * switch (a.state()) 00161 * { 00162 * case TriBool::sTrue: 00163 * foo(); 00164 * break; 00165 * case TriBool::sFalse: 00166 * bar(); 00167 * break; 00168 * default: 00169 * LASS_ASSERT(a.state() == TriBool::sUnknown); 00170 * fun(); 00171 * break; 00172 * } 00173 * @endcode 00174 * 00175 * @warning a common mistake is to test if a TriBool @c a is in a unknown state by comparing it to 00176 * the constant @c unknown. You might expect it to yield @c true if @c a is indeed, 00177 * unknown, but it will always return @c unknown instead. After all, it cannot know if 00178 * both sides are equal, since at least one is unknown (@c unknown itself). To test if 00179 * @c a TriBool is indeed unknown, you have to use the method @c TriBool::isUnknown(). 00180 * 00181 * @code 00182 * TriBool a; 00183 * 00184 * if (a == unknown) 00185 * { 00186 * // BAD! unreachable code, the test will never yield true. 00187 * } 00188 * 00189 * if (a.isUnknown()) 00190 * { 00191 * // GOOD! this code will be reached if the state of a is unknown. 00192 * } 00193 * @endcode 00194 */ 00195 00196 #ifndef LASS_GUARDIAN_OF_INCLUSION_NUM_TRI_BOOL_H 00197 #define LASS_GUARDIAN_OF_INCLUSION_NUM_TRI_BOOL_H 00198 00199 #include "num_common.h" 00200 #include "safe_bool.h" 00201 00202 namespace lass 00203 { 00204 namespace num 00205 { 00206 00207 class LASS_DLL TriBool 00208 { 00209 public: 00210 00211 enum State 00212 { 00213 sFalse, 00214 sTrue, 00215 sUnknown 00216 }; 00217 00218 TriBool(State iState = sUnknown); 00219 TriBool(bool iBool); 00220 00221 const State state() const; 00222 State& state(); 00223 00224 TriBool operator!() const; 00225 operator SafeBool() const; 00226 00227 bool isTrue() const; 00228 bool isFalse() const; 00229 bool isUnknown() const; 00230 00231 private: 00232 00233 State state_; 00234 }; 00235 00236 LASS_DLL TriBool LASS_CALL operator==(TriBool iA, TriBool iB); 00237 LASS_DLL TriBool LASS_CALL operator!=(TriBool iA, TriBool iB); 00238 LASS_DLL TriBool LASS_CALL operator&&(TriBool iA, TriBool iB); 00239 LASS_DLL TriBool LASS_CALL operator||(TriBool iA, TriBool iB); 00240 00241 LASS_DLL std::ostream& LASS_CALL operator<<(std::ostream& ioS, TriBool iB); 00242 00243 00244 00245 /** constant to be used as new keyword like @c true and @c false 00246 * @relates TriBool 00247 */ 00248 const TriBool unknown(TriBool::sUnknown); 00249 00250 } 00251 00252 } 00253 00254 #endif 00255 00256 // EOF
Generated on Mon Nov 10 14:21:40 2008 for Library of Assembled Shared Sources by 1.5.7.1 |