File indexing completed on 2024-12-01 10:29:04

0001 /* This file is part of the KDE project
0002    Copyright (C) 2004-2012 Jarosław Staniek <staniek@kde.org>
0003 
0004    This program is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU Library General Public
0006    License as published by the Free Software Foundation; either
0007    version 2 of the License, or (at your option) any later version.
0008 
0009    This program is distributed in the hope that it will be useful,
0010    but WITHOUT ANY WARRANTY; without even the implied warranty of
0011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012    Library General Public License for more details.
0013 
0014    You should have received a copy of the GNU Library General Public License
0015    along with this program; see the file COPYING.  If not, write to
0016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017  * Boston, MA 02110-1301, USA.
0018 */
0019 
0020 #ifndef KDB_TRISTATE_H
0021 #define KDB_TRISTATE_H
0022 
0023 #include <QString>
0024 #include <QtDebug>
0025 
0026 enum tristate_cancelled_t {
0027     /**
0028      * @e cancelled value, in most cases usable if there is a need for returning
0029      * @e cancelled value explicitly. Example use:
0030      * @code
0031      * tristate myFunctionThatCanBeCancelled() {
0032      *   doSomething();
0033      *   if (userCancelledOperation())
0034      *     return cancelled; //neither success or failure is returned here
0035      *   return operationSucceeded(); //return success or failure
0036      * }
0037      * @endcode
0038      * Even though ~ operator of tristate class can be used, it is also possible to test:
0039      * @code
0040      * if (cancelled == myFunctionThatCanBeCancelled()) { .... }
0041      * @endcode
0042      */
0043     cancelled,
0044 
0045     /**
0046      * Convenience name, the same as cancelled value.
0047      */
0048     dontKnow = cancelled
0049 };
0050 
0051 /**
0052  * 3-state logical type with three values: @e true, @e false and @e cancelled and convenient operators.
0053  *
0054  * @e cancelled state can be also called @e dontKnow, it behaves as @e null in SQL.
0055  * A main goal of this class is to improve readibility when there's a need
0056  * for storing third, @e cancelled, state, especially in case C++ exceptions are not in use.
0057  * With it, developer can forget about declaring a specific enum type
0058  * having just three values: @e true, @e false, @e cancelled.
0059  *
0060  * Objects of this class can be used with similar convenience as standard bool type:
0061  * - use as return value when 'cancelled'
0062  *   @code
0063  *   tristate doSomething();
0064  *   @endcode
0065  * - convert from bool (1) or to bool (2)
0066  *   @code
0067  *   tristate t = true; //(1)
0068  *   setVisible(t);   //(2)
0069  *   @endcode
0070  * - clear comparisons
0071  *   @code
0072  *   tristate t = doSomething();
0073  *   if (t) doSomethingIfTrue();
0074  *   if (!t) doSomethingIfFalse();
0075  *   if (~t) doSomethingIfCancelled();
0076  *   @endcode
0077  *
0078  * "! ~" can be used as "not cancelled".
0079  *
0080  * With tristate class, developer can also forget about
0081  * it's additional meaning and treat it just as a bool, if the third state
0082  * is irrelevant to the current situation.
0083  *
0084  * Other use for tristate class could be to allow cancellation within
0085  * a callback function or a Qt slot. Example:
0086  * @code
0087  * public Q_SLOTS:
0088  *   void validateData(tristate *result);
0089  * @endcode
0090  * Having the single parameter, signals and slots have still simple look.
0091  * Developers can alter their code (by replacing 'bool *result' with 'tristate *result')
0092  * in case when a possibility of canceling of, say, data provessing needs to be implemented.
0093  * Let's say @e validateData() function uses a QDialog to get some validation from a user.
0094  * While QDialog::Rejected is returned after cancellation of the validation process,
0095  * the information about cancellation needs to be transferred up to a higher level of the program.
0096  * Storing values of type QDialog::DialogCode there could be found as unreadable, and
0097  * casting these to int is not typesafe. With tristate class it's easier to make it obvious that
0098  * cancellation should be taken into account.
0099  */
0100 class tristate
0101 {
0102 public:
0103     /**
0104      * Default constructor, object has @e cancelled value set.
0105      */
0106     inline tristate()
0107             : m_value(Cancelled) {
0108     }
0109 
0110     /**
0111      * Constructor accepting a boolean value.
0112      */
0113     inline tristate(bool boolValue)
0114             : m_value(boolValue ? True : False) {
0115     }
0116 
0117     /**
0118      * Constructor accepting a char value.
0119      * It is converted in the following way:
0120      * - 2 -> cancelled
0121      * - 1 -> true
0122      * - other -> false
0123      */
0124     inline tristate(tristate_cancelled_t)
0125             : m_value(tristate::Cancelled) {
0126     }
0127 
0128     /**
0129      * Casting to bool type with negation: true is only returned
0130      * if the original tristate value is equal to false.
0131      */
0132     inline bool operator!() const {
0133         return m_value == False;
0134     }
0135 
0136     /**
0137      * Special casting to bool type: true is only returned
0138      * if the original tristate value is equal to @e cancelled.
0139      */
0140     inline bool operator~() const {
0141         return m_value == Cancelled;
0142     }
0143 
0144     inline tristate& operator=(tristate tsValue);
0145 
0146     inline tristate& operator=(bool boolValue);
0147 
0148     inline tristate& operator=(tristate_cancelled_t);
0149 
0150     friend inline bool operator==(bool boolValue, tristate tsValue);
0151 
0152     friend inline bool operator==(tristate tsValue, bool boolValue);
0153 
0154     friend inline bool operator!=(bool boolValue, tristate tsValue);
0155 
0156     friend inline bool operator!=(tristate tsValue, bool boolValue);
0157 
0158     friend inline bool operator==(tristate_cancelled_t, tristate tsValue);
0159 
0160     friend inline bool operator==(tristate tsValue, tristate_cancelled_t);
0161 
0162     friend inline bool operator!=(tristate_cancelled_t, tristate tsValue);
0163 
0164     friend inline bool operator!=(tristate tsValue, tristate_cancelled_t);
0165 
0166     friend inline bool operator==(tristate_cancelled_t, bool boolValue);
0167 
0168     friend inline bool operator==(bool boolValue, tristate_cancelled_t);
0169 
0170     friend inline bool operator!=(tristate_cancelled_t, bool boolValue);
0171 
0172     friend inline bool operator!=(bool boolValue, tristate_cancelled_t);
0173 
0174     friend inline QDebug operator<<(QDebug dbg, tristate tsValue);
0175 
0176     /**
0177      * @return text representation of the value: "true", "false" or "cancelled".
0178      */
0179     QString toString() const {
0180         if (m_value == False) {
0181             return QStringLiteral("false");
0182         }
0183         return m_value == True ? QStringLiteral("true") : QStringLiteral("cancelled");
0184     }
0185 
0186 private:
0187     /**
0188      * @internal
0189      * States used internally.
0190      */
0191     enum Value {
0192         False = 0,
0193         True = 1,
0194         Cancelled = 2
0195     };
0196 
0197     /**
0198      * @internal
0199      */
0200     Value m_value;
0201 };
0202 
0203 tristate& tristate::operator=(tristate tsValue)
0204 {
0205     m_value = tsValue.m_value;
0206     return *this;
0207 }
0208 
0209 tristate& tristate::operator=(bool boolValue)
0210 {
0211     m_value = boolValue ? True : False;
0212     return *this;
0213 }
0214 
0215 tristate& tristate::operator=(tristate_cancelled_t)
0216 {
0217     m_value = Cancelled;
0218     return *this;
0219 }
0220 
0221 /**
0222  * Inequality operator comparing a bool value @p boolValue and a tristate value @p tsValue.
0223  *
0224  * @return false if both @p boolValue and @p tsValue are true
0225  *         or if both  @p boolValue and @p tsValue are false.
0226  *         Else, returns true.
0227 */
0228 inline bool operator!=(bool boolValue, tristate tsValue)
0229 {
0230     return !((tsValue.m_value == tristate::True && boolValue)
0231              || (tsValue.m_value == tristate::False && !boolValue));
0232 }
0233 
0234 /**
0235  * Inequality operator comparing a tristate value @p tsValue and a bool value @p boolValue.
0236  * @see bool operator!=(bool boolValue, tristate tsValue)
0237 */
0238 inline bool operator!=(tristate tsValue, bool boolValue)
0239 {
0240     return !((tsValue.m_value == tristate::True && boolValue)
0241              || (tsValue.m_value == tristate::False && !boolValue));
0242 }
0243 
0244 /**
0245   * Equality operator comparing a tristate value @p tsValue and a bool value @p boolValue.
0246   * @return true if
0247   * - both @p tsValue value and @p boolValue are true, or
0248   * - both @p tsValue value and @p boolValue are false
0249   * If the tristate value has value of cancelled, false is returned.
0250   */
0251 inline bool operator==(tristate tsValue, bool boolValue)
0252 {
0253     return (tsValue.m_value == tristate::True && boolValue)
0254            || (tsValue.m_value == tristate::False && !boolValue);
0255 }
0256 
0257 /**
0258   * Equality operator comparing a bool value @p boolValue and a tristate value @p tsValue.
0259   * @return true if both
0260   * - both @p tsValue value and @p boolValue are true, or
0261   * - both @p tsValue value and @p boolValue are false
0262   * If the tristate value has value of cancelled, false is returned.
0263   */
0264 inline bool operator==(bool boolValue, tristate tsValue)
0265 {
0266     return (tsValue.m_value == tristate::True && boolValue)
0267            || (tsValue.m_value == tristate::False && !boolValue);
0268 }
0269 
0270 /**
0271   * Equality operator comparing a cancelled and a tristate value @p tsValue.
0272   * @return true if @p tsValue is equal to cancelled value.
0273   */
0274 inline bool operator==(tristate_cancelled_t, tristate tsValue)
0275 {
0276     return tsValue.m_value == tristate::Cancelled;
0277 }
0278 
0279 /**
0280   * Equality operator comparing a cancelled and a tristate value @p tsValue.
0281   * @return true if @p tsValue is equal to cancelled value.
0282   */
0283 inline bool operator==(tristate tsValue, tristate_cancelled_t)
0284 {
0285     return tsValue.m_value == tristate::Cancelled;
0286 }
0287 
0288 /**
0289   * Equality operator comparing a cancelled and a bool value.
0290   * @return false.
0291   */
0292 inline bool operator==(tristate_cancelled_t, bool)
0293 {
0294     return false;
0295 }
0296 
0297 /**
0298   * Equality operator comparing a cancelled and a bool value.
0299   * @return false.
0300   */
0301 inline bool operator==(bool, tristate_cancelled_t)
0302 {
0303     return false;
0304 }
0305 
0306 /**
0307   * Inequality operator comparing a cancelled and a tristate value @p tsValue.
0308   * @return true if @p tsValue is not equal to cancelled value.
0309   */
0310 inline bool operator!=(tristate_cancelled_t, tristate tsValue)
0311 {
0312     return tsValue.m_value != tristate::Cancelled;
0313 }
0314 
0315 /**
0316   * Equality operator comparing a cancelled and a tristate value @p tsValue.
0317   * @return true if @p tsValue is not equal to cancelled value.
0318   */
0319 inline bool operator!=(tristate tsValue, tristate_cancelled_t)
0320 {
0321     return tsValue.m_value != tristate::Cancelled;
0322 }
0323 
0324 /**
0325   * Equality operator comparing a cancelled and a bool value.
0326   * @return true.
0327   */
0328 inline bool operator!=(tristate_cancelled_t, bool)
0329 {
0330     return true;
0331 }
0332 
0333 /**
0334   * Equality operator comparing a cancelled and a bool value.
0335   * @return true.
0336   */
0337 inline bool operator!=(bool, tristate_cancelled_t)
0338 {
0339     return true;
0340 }
0341 
0342 //! qDebug() stream operator. Writes tristate value to the debug output in a nicely formatted way.
0343 inline QDebug operator<<(QDebug dbg, tristate tsValue)
0344 {
0345     switch (tsValue.m_value) {
0346     case tristate::True: dbg.nospace() << "true"; break;
0347     case tristate::False: dbg.nospace() << "false"; break;
0348     case tristate::Cancelled: dbg.nospace() << "cancelled"; break;
0349     }
0350     return dbg.space();
0351 }
0352 
0353 inline QDebug operator<<(QDebug dbg, tristate_cancelled_t)
0354 {
0355     dbg.nospace() << "cancelled";
0356     return dbg.space();
0357 }
0358 
0359 inline bool operator~(tristate_cancelled_t)
0360 {
0361     return true;
0362 }
0363 
0364 inline bool operator!(tristate_cancelled_t)
0365 {
0366     return false;
0367 }
0368 
0369 #endif