#pragma once #include /** * @brief Generator-macro for creating instant tri-bools, a boolean-like type * that has a "True" state, a "False" state, and a "Maybe"/"Indeterminate" * state. {@see boost::tribool} for an example of this functionality. * * TriBool types obey the following rules of behavior (with T := True, * F := False, M := Maybe): * * Unary operators operate as follows: * | op \ in | T | F | M | * |---------|---|---|---| * | bool() | T | F | T | * | ! | F | T | M | * |---------|---|---|---| * * AND operates as follows: * | | T | F | M | * |---|---|---|---| * | T | T | F | T | * | F | F | F | F | * | M | T | F | M | * |---|---|---|---| * * OR operates as follows: * | | T | F | M | * |---|---|---|---| * | T | T | T | T | * | F | T | F | M | * | M | T | M | M | * |---|---|---|---| * * @param TypeName the name of the class being declared * @param True the name of the truthy enumeration * @param False the name of the falsy enumeration * @param Maybe the name of the indeterminate enumeration */ #define JVALIDATE_TRIBOOL_TYPE(TypeName, True, False, Maybe) \ class TypeName { \ public: \ enum Enum { True, False, Maybe }; \ \ private: \ Enum state_; \ \ public: \ /* Translate a boolean into a tribool value, will never be Maybe */ \ constexpr TypeName(bool state) : state_(state ? True : False) {} \ constexpr TypeName(Enum state) : state_(state) {} \ \ /* Convert to enum for use in switch() statements */ \ constexpr Enum operator*() const { return state_; } \ /* Convert to bool for use in if()/while() statements, requires static_cast otherwise */ \ constexpr explicit operator bool() const { return state_ != False; } \ \ /* Inverts the tribool's value if it is already a concrete boolean type */ \ friend constexpr TypeName operator!(TypeName val) { \ if (val.state_ == Maybe) { \ return Maybe; \ } \ return val.state_ == False ? True : False; \ } \ \ /* Combines two tribools as if performing boolean-OR */ \ friend constexpr TypeName operator|(TypeName lhs, TypeName rhs) { \ if (lhs.state_ == True || rhs.state_ == True) { \ return True; \ } \ if (lhs.state_ == Maybe || rhs.state_ == Maybe) { \ return Maybe; \ } \ return False; \ } \ \ /* Combines two tribools as if performing boolean-AND */ \ friend constexpr TypeName operator&(TypeName lhs, TypeName rhs) { \ if (lhs.state_ == False || rhs.state_ == False) { \ return False; \ } \ if (lhs.state_ == Maybe && rhs.state_ == Maybe) { \ return Maybe; \ } \ return True; \ } \ \ constexpr TypeName & operator&=(TypeName rhs) { return *this = *this & rhs; } \ constexpr TypeName & operator|=(TypeName rhs) { return *this = *this | rhs; } \ \ friend constexpr auto operator==(TypeName lhs, TypeName::Enum rhs) { \ return static_cast(lhs.state_) == static_cast(rhs); \ } \ friend constexpr auto operator!=(TypeName lhs, TypeName::Enum rhs) { \ return static_cast(lhs.state_) != static_cast(rhs); \ } \ friend constexpr auto operator<=>(TypeName lhs, TypeName rhs) { \ return static_cast(lhs.state_) <=> static_cast(rhs.state_); \ } \ }