tribool.h 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. #pragma once
  2. #include <compare>
  3. /**
  4. * @brief Generator-macro for creating instant tri-bools, a boolean-like type
  5. * that has a "True" state, a "False" state, and a "Maybe"/"Indeterminate"
  6. * state. {@see boost::tribool} for an example of this functionality.
  7. *
  8. * TriBool types obey the following rules of behavior (with T := True,
  9. * F := False, M := Maybe):
  10. *
  11. * Unary operators operate as follows:
  12. * | op \ in | T | F | M |
  13. * |---------|---|---|---|
  14. * | bool() | T | F | T |
  15. * | ! | F | T | M |
  16. * |---------|---|---|---|
  17. *
  18. * AND operates as follows:
  19. * | | T | F | M |
  20. * |---|---|---|---|
  21. * | T | T | F | T |
  22. * | F | F | F | F |
  23. * | M | T | F | M |
  24. * |---|---|---|---|
  25. *
  26. * OR operates as follows:
  27. * | | T | F | M |
  28. * |---|---|---|---|
  29. * | T | T | T | T |
  30. * | F | T | F | M |
  31. * | M | T | M | M |
  32. * |---|---|---|---|
  33. *
  34. * @param TypeName the name of the class being declared
  35. * @param True the name of the truthy enumeration
  36. * @param False the name of the falsy enumeration
  37. * @param Maybe the name of the indeterminate enumeration
  38. */
  39. #define JVALIDATE_TRIBOOL_TYPE(TypeName, True, False, Maybe) \
  40. class TypeName { \
  41. public: \
  42. enum Enum { True, False, Maybe }; \
  43. \
  44. private: \
  45. Enum state_; \
  46. \
  47. public: \
  48. /* Translate a boolean into a tribool value, will never be Maybe */ \
  49. constexpr TypeName(bool state) : state_(state ? True : False) {} \
  50. constexpr TypeName(Enum state) : state_(state) {} \
  51. \
  52. /* Convert to enum for use in switch() statements */ \
  53. constexpr Enum operator*() const { return state_; } \
  54. /* Convert to bool for use in if()/while() statements, requires static_cast otherwise */ \
  55. constexpr explicit operator bool() const { return state_ != False; } \
  56. \
  57. /* Inverts the tribool's value if it is already a concrete boolean type */ \
  58. friend constexpr TypeName operator!(TypeName val) { \
  59. if (val.state_ == Maybe) { \
  60. return Maybe; \
  61. } \
  62. return val.state_ == False ? True : False; \
  63. } \
  64. \
  65. /* Combines two tribools as if performing boolean-OR */ \
  66. friend constexpr TypeName operator|(TypeName lhs, TypeName rhs) { \
  67. if (lhs.state_ == True || rhs.state_ == True) { \
  68. return True; \
  69. } \
  70. if (lhs.state_ == Maybe || rhs.state_ == Maybe) { \
  71. return Maybe; \
  72. } \
  73. return False; \
  74. } \
  75. \
  76. /* Combines two tribools as if performing boolean-AND */ \
  77. friend constexpr TypeName operator&(TypeName lhs, TypeName rhs) { \
  78. if (lhs.state_ == False || rhs.state_ == False) { \
  79. return False; \
  80. } \
  81. if (lhs.state_ == Maybe && rhs.state_ == Maybe) { \
  82. return Maybe; \
  83. } \
  84. return True; \
  85. } \
  86. \
  87. constexpr TypeName & operator&=(TypeName rhs) { return *this = *this & rhs; } \
  88. constexpr TypeName & operator|=(TypeName rhs) { return *this = *this | rhs; } \
  89. \
  90. friend constexpr auto operator==(TypeName lhs, TypeName::Enum rhs) { \
  91. return static_cast<int>(lhs.state_) == static_cast<int>(rhs); \
  92. } \
  93. friend constexpr auto operator!=(TypeName lhs, TypeName::Enum rhs) { \
  94. return static_cast<int>(lhs.state_) != static_cast<int>(rhs); \
  95. } \
  96. friend constexpr auto operator<=>(TypeName lhs, TypeName rhs) { \
  97. return static_cast<int>(lhs.state_) <=> static_cast<int>(rhs.state_); \
  98. } \
  99. }