src/util: change TriBool logic to use a bool template parameter

This commit is contained in:
Markus F.X.J. Oberhumer 2023-10-31 12:24:44 +01:00
parent e306085b81
commit e964d4acf3
4 changed files with 31 additions and 30 deletions

View File

@ -155,7 +155,7 @@ TEST_CASE("noncopyable") {
namespace {
template <class T>
struct TestTriBool {
static void test(bool expect_true, int x) noexcept {
static void test(bool expect_true) noexcept {
static_assert(std::is_class<T>::value);
static_assert(std::is_nothrow_default_constructible<T>::value);
static_assert(std::is_nothrow_destructible<T>::value);
@ -171,7 +171,6 @@ struct TestTriBool {
#endif
static_assert(!bool(T(false)));
static_assert(bool(T(true)));
static_assert(bool(T(T::Third)) == (T::Third > T::False));
static_assert(T(false) == T::False);
static_assert(T(true) == T::True);
static_assert(T(T::False) == T::False);
@ -232,7 +231,7 @@ struct TestTriBool {
CHECK(!a.isStrictTrue());
CHECK(!a.isStrictBool());
CHECK(a.isThird());
a = x;
a = 99;
CHECK(a.getValue() == T::Third);
if (expect_true) {
CHECK(a);
@ -255,26 +254,28 @@ struct TestTriBool {
TEST_CASE("TriBool") {
using upx::TriBool, upx::tribool;
//
static_assert(!tribool(false));
static_assert(tribool(true));
static_assert(!tribool(tribool::Third));
TestTriBool<tribool>::test(false, -1);
//
TestTriBool<TriBool<upx_int8_t> >::test(false, -99990);
TestTriBool<TriBool<upx_int16_t> >::test(false, -99991);
TestTriBool<TriBool<upx_int32_t> >::test(false, -99992);
TestTriBool<TriBool<upx_int64_t> >::test(false, -99993);
//
TestTriBool<TriBool<unsigned, 2> >::test(true, 99);
TestTriBool<TriBool<upx_int8_t, 2> >::test(true, 99990);
TestTriBool<TriBool<upx_uint8_t, 2> >::test(true, 99991);
TestTriBool<TriBool<upx_int16_t, 2> >::test(true, 99992);
TestTriBool<TriBool<upx_uint16_t, 2> >::test(true, 99993);
TestTriBool<TriBool<upx_int32_t, 2> >::test(true, 99994);
TestTriBool<TriBool<upx_uint32_t, 2> >::test(true, 99995);
TestTriBool<TriBool<upx_int64_t, 2> >::test(true, 99996);
TestTriBool<TriBool<upx_uint64_t, 2> >::test(true, 99997);
TestTriBool<tribool>::test(false);
#if DEBUG || 1
TestTriBool<TriBool<upx_int8_t> >::test(false);
TestTriBool<TriBool<upx_uint8_t> >::test(false);
TestTriBool<TriBool<upx_int16_t> >::test(false);
TestTriBool<TriBool<upx_uint16_t> >::test(false);
TestTriBool<TriBool<upx_int32_t> >::test(false);
TestTriBool<TriBool<upx_uint32_t> >::test(false);
TestTriBool<TriBool<upx_int64_t> >::test(false);
TestTriBool<TriBool<upx_uint64_t> >::test(false);
TestTriBool<TriBool<upx_int8_t, true> >::test(true);
TestTriBool<TriBool<upx_uint8_t, true> >::test(true);
TestTriBool<TriBool<upx_int16_t, true> >::test(true);
TestTriBool<TriBool<upx_uint16_t, true> >::test(true);
TestTriBool<TriBool<upx_int32_t, true> >::test(true);
TestTriBool<TriBool<upx_uint32_t, true> >::test(true);
TestTriBool<TriBool<upx_int64_t, true> >::test(true);
TestTriBool<TriBool<upx_uint64_t, true> >::test(true);
#endif
}
/* vim:set ts=4 sw=4 et: */

View File

@ -170,8 +170,8 @@ struct Options final {
struct {
int compress_exports;
int compress_icons;
upx::TriBool<upx_int8_t, 2> compress_resources;
upx::TriBool<upx_int8_t, 2> compress_rt[25]; // 25 == RT_LAST
upx::TriBool<upx_int8_t, true> compress_resources;
upx::TriBool<upx_int8_t, true> compress_rt[25]; // 25 == RT_LAST
int strip_relocs;
const char *keep_resource;
} win32_pe;

View File

@ -2974,8 +2974,7 @@ tribool PackLinuxElf64::canUnpack() // bool, except -1: format known, but not pa
return false;
}
tribool
PackLinuxElf64::canPack()
tribool PackLinuxElf64::canPack()
{
union {
unsigned char buf[MAX_ELF_HDR_64];

View File

@ -109,23 +109,23 @@ constexpr bool string_ge(const char *a, const char *b) { return !string_lt(a, b)
/*************************************************************************
// TriBool - tri-state bool
// an enum with an underlying type and 3 values
// bool() checks for > 0, so ThirdValue determines if Third is false or true
// IsThirdTrue determines if Third is false or true
**************************************************************************/
template <class T = int, T ThirdValue = -1> // ThirdValue is false by default
template <class T = int, bool IsThirdTrue = false> // Third is false by default
struct TriBool final {
// types
typedef T underlying_type;
static_assert(std::is_integral_v<underlying_type>);
typedef decltype(T(0) + T(0)) promoted_type;
static_assert(std::is_integral_v<promoted_type>);
static_assert(ThirdValue != 0 && ThirdValue != 1);
enum value_type : underlying_type { False = 0, True = 1, Third = ThirdValue };
enum value_type : underlying_type { False = 0, True = 1, Third = 2 };
static_assert(sizeof(value_type) == sizeof(underlying_type));
static_assert(sizeof(underlying_type) <= sizeof(promoted_type));
// constructors
forceinline constexpr TriBool() noexcept {}
forceinline constexpr TriBool(value_type x) noexcept : value(x) {}
// permissive, converts all other values to Third!!
constexpr TriBool(promoted_type x) noexcept : value(x == 0 ? False : (x == 1 ? True : Third)) {}
#if __cplusplus >= 202002L
forceinline constexpr ~TriBool() noexcept = default;
@ -133,8 +133,9 @@ struct TriBool final {
forceinline ~TriBool() noexcept = default;
#endif
// explicit conversion to bool
// checks for > 0, so ThirdValue determines if Third is false (the default) or true
explicit constexpr operator bool() const noexcept { return value > False; }
explicit constexpr operator bool() const noexcept {
return IsThirdTrue ? (value != False) : (value == True);
}
// query; this is NOT the same as operator bool()
constexpr bool isStrictFalse() const noexcept { return value == False; }
constexpr bool isStrictTrue() const noexcept { return value == True; }