mirror of https://github.com/upx/upx.git
src: create util/cxxlib.h
This commit is contained in:
parent
394cd77bec
commit
8975e2a6b5
|
@ -389,6 +389,8 @@ def main():
|
|||
clang_apply_replacements_binary = find_binary(
|
||||
args.clang_apply_replacements_binary, "clang-apply-replacements", build_path
|
||||
)
|
||||
|
||||
if args.fix or (yaml and args.export_fixes):
|
||||
tmpdir = tempfile.mkdtemp()
|
||||
|
||||
# Load the database and extract all files.
|
||||
|
|
|
@ -100,21 +100,6 @@ ACC_COMPILE_TIME_ASSERT_HEADER((std::is_same<unsigned, upx_uint32_t>::value))
|
|||
ACC_COMPILE_TIME_ASSERT_HEADER((std::is_same<long long, upx_int64_t>::value))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((std::is_same<unsigned long long, upx_uint64_t>::value))
|
||||
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((is_same_all_v<int>) )
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((is_same_all_v<int, int>) )
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((is_same_all_v<int, int, int>) )
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((!is_same_all_v<int, char>) )
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((!is_same_all_v<int, char, int>) )
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((!is_same_all_v<int, int, char>) )
|
||||
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((!is_same_any_v<int>) )
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((is_same_any_v<int, int>) )
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((is_same_any_v<int, char, int>) )
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((is_same_any_v<int, int, char>) )
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((!is_same_any_v<int, char>) )
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((!is_same_any_v<int, char, char>) )
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((!is_same_any_v<int, char, long>) )
|
||||
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(no_bswap16(0x04030201) == 0x0201)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(no_bswap32(0x04030201) == 0x04030201)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(no_bswap64(0x0807060504030201ull) == 0x0807060504030201ull)
|
||||
|
@ -128,43 +113,6 @@ ACC_COMPILE_TIME_ASSERT_HEADER(bswap64(bswap64(0xf8f7f6f5f4f3f2f1ull)) ==
|
|||
no_bswap64(0xf8f7f6f5f4f3f2f1ull))
|
||||
#endif
|
||||
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(usizeof(int) == sizeof(int))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(usizeof('a') == sizeof(char))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(usizeof("") == 1)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(usizeof("a") == 2)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(usizeof(0) == sizeof(int))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(usizeof(0L) == sizeof(long))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(usizeof(0LL) == sizeof(long long))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(usizeof(nullptr) == sizeof(void *))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(usizeof(sizeof(0)) == sizeof(size_t))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(usizeof(usizeof(0)) == sizeof(unsigned))
|
||||
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_len("") == 0)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_len("a") == 1)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_len("ab") == 2)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_len("abc") == 3)
|
||||
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_eq("", ""))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_eq("a", ""))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_eq("", "a"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_eq("abc", "abc"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_eq("ab", "abc"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_eq("abc", "ab"))
|
||||
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_lt("", ""))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_lt("a", ""))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_lt("", "a"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_lt("abc", "abc"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_lt("ab", "abc"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_lt("abc", "ab"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_lt("abc", "aba"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_lt("abc", "abz"))
|
||||
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_ne("abc", "abz"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_gt("abc", "abz"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_ge("abc", "abz"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_le("abc", "abz"))
|
||||
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(CHAR_BIT == 8)
|
||||
#if 0 // does not work with MSVC
|
||||
#if '\0' - 1 < 0
|
||||
|
@ -594,20 +542,6 @@ TEST_CASE("assert_noexcept") {
|
|||
assert_noexcept(!ptr3);
|
||||
}
|
||||
|
||||
TEST_CASE("noncopyable") {
|
||||
struct Test : private noncopyable {
|
||||
int v = 1;
|
||||
};
|
||||
Test t = {};
|
||||
CHECK(t.v == 1);
|
||||
#if (ACC_CC_MSC) // MSVC thinks that Test is not std::is_trivially_copyable; true or compiler bug?
|
||||
t.v = 0;
|
||||
#else
|
||||
mem_clear(&t);
|
||||
#endif
|
||||
CHECK(t.v == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("acc_vget") {
|
||||
CHECK_EQ(acc_vget_int(0, 0), 0);
|
||||
CHECK_EQ(acc_vget_long(1, -1), 1);
|
||||
|
|
|
@ -0,0 +1,186 @@
|
|||
/* dt_cxxlib.cpp -- doctest check
|
||||
|
||||
This file is part of the UPX executable compressor.
|
||||
|
||||
Copyright (C) 1996-2023 Markus Franz Xaver Johannes Oberhumer
|
||||
All Rights Reserved.
|
||||
|
||||
UPX and the UCL library are free software; you can redistribute them
|
||||
and/or modify them under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer
|
||||
<markus@oberhumer.com>
|
||||
*/
|
||||
|
||||
#include "../conf.h"
|
||||
|
||||
/*************************************************************************
|
||||
// compile-time checks
|
||||
**************************************************************************/
|
||||
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((upx::is_same_all_v<int>) )
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((upx::is_same_all_v<int, int>) )
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((upx::is_same_all_v<int, int, int>) )
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((!upx::is_same_all_v<int, char>) )
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((!upx::is_same_all_v<int, char, int>) )
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((!upx::is_same_all_v<int, int, char>) )
|
||||
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((!upx::is_same_any_v<int>) )
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((upx::is_same_any_v<int, int>) )
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((upx::is_same_any_v<int, char, int>) )
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((upx::is_same_any_v<int, int, char>) )
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((!upx::is_same_any_v<int, char>) )
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((!upx::is_same_any_v<int, char, char>) )
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((!upx::is_same_any_v<int, char, long>) )
|
||||
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(usizeof(int) == sizeof(int))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(usizeof('a') == sizeof(char))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(usizeof("") == 1)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(usizeof("a") == 2)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(usizeof(0) == sizeof(int))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(usizeof(0L) == sizeof(long))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(usizeof(0LL) == sizeof(long long))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(usizeof(nullptr) == sizeof(void *))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(usizeof(sizeof(0)) == sizeof(size_t))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(usizeof(usizeof(0)) == sizeof(unsigned))
|
||||
|
||||
namespace compile_time = upx::compile_time;
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_len("") == 0)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_len("a") == 1)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_len("ab") == 2)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_len("abc") == 3)
|
||||
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_eq("", ""))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_eq("a", ""))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_eq("", "a"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_eq("abc", "abc"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_eq("ab", "abc"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_eq("abc", "ab"))
|
||||
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_lt("", ""))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_lt("a", ""))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_lt("", "a"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_lt("abc", "abc"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_lt("ab", "abc"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_lt("abc", "ab"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_lt("abc", "aba"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_lt("abc", "abz"))
|
||||
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_ne("abc", "abz"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_gt("abc", "abz"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_ge("abc", "abz"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_le("abc", "abz"))
|
||||
|
||||
/*************************************************************************
|
||||
// util
|
||||
**************************************************************************/
|
||||
|
||||
TEST_CASE("noncopyable") {
|
||||
struct Test : private upx::noncopyable {
|
||||
int v = 1;
|
||||
};
|
||||
Test t = {};
|
||||
CHECK(t.v == 1);
|
||||
#if (ACC_CC_MSC) // MSVC thinks that Test is not std::is_trivially_copyable; true or compiler bug?
|
||||
t.v = 0;
|
||||
#else
|
||||
mem_clear(&t);
|
||||
#endif
|
||||
CHECK(t.v == 0);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
// TriBool
|
||||
**************************************************************************/
|
||||
|
||||
namespace {
|
||||
template <class T>
|
||||
struct TestTriBool {
|
||||
static void test(bool expect_true, int x) 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);
|
||||
static_assert(std::is_standard_layout<T>::value);
|
||||
static_assert(std::is_trivially_copyable<T>::value);
|
||||
static_assert(T(false) == T::False);
|
||||
static_assert(T(true) == T::True);
|
||||
static_assert(T(T::False) == T::False);
|
||||
static_assert(T(T::True) == T::True);
|
||||
static_assert(T(T::Third) == T::Third);
|
||||
constexpr T array[] = {false, true, T::Third};
|
||||
static_assert(array[0].isStrictFalse());
|
||||
static_assert(array[1].isStrictTrue());
|
||||
static_assert(array[2].isThird());
|
||||
T a;
|
||||
CHECK(!a);
|
||||
CHECK(a.isStrictFalse());
|
||||
CHECK(!a.isStrictTrue());
|
||||
CHECK(a.isStrictBool());
|
||||
CHECK(!a.isThird());
|
||||
a = false;
|
||||
CHECK(!a);
|
||||
CHECK(a.isStrictFalse());
|
||||
CHECK(!a.isStrictTrue());
|
||||
CHECK(a.isStrictBool());
|
||||
CHECK(!a.isThird());
|
||||
a = true;
|
||||
CHECK(a);
|
||||
CHECK(!a.isStrictFalse());
|
||||
CHECK(a.isStrictTrue());
|
||||
CHECK(a.isStrictBool());
|
||||
CHECK(!a.isThird());
|
||||
a = T::Third;
|
||||
if (expect_true)
|
||||
CHECK(a);
|
||||
else
|
||||
CHECK(!a);
|
||||
CHECK(!a.isStrictFalse());
|
||||
CHECK(!a.isStrictTrue());
|
||||
CHECK(!a.isStrictBool());
|
||||
CHECK(a.isThird());
|
||||
a = x;
|
||||
if (expect_true)
|
||||
CHECK(a);
|
||||
else
|
||||
CHECK(!a);
|
||||
CHECK(!a.isStrictFalse());
|
||||
CHECK(!a.isStrictTrue());
|
||||
CHECK(!a.isStrictBool());
|
||||
CHECK(a.isThird());
|
||||
mem_clear(&a);
|
||||
CHECK(a.isStrictFalse());
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
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, -1);
|
||||
TestTriBool<TriBool<upx_int64_t> >::test(false, -1);
|
||||
//
|
||||
TestTriBool<TriBool<unsigned, 2> >::test(true, 2);
|
||||
TestTriBool<TriBool<upx_int8_t, 2> >::test(true, 2);
|
||||
TestTriBool<TriBool<upx_uint8_t, 2> >::test(true, 2);
|
||||
TestTriBool<TriBool<upx_int64_t, 2> >::test(true, 2);
|
||||
TestTriBool<TriBool<upx_uint64_t, 2> >::test(true, 2);
|
||||
}
|
||||
|
||||
/* vim:set ts=4 sw=4 et: */
|
114
src/conf.h
114
src/conf.h
|
@ -34,6 +34,9 @@
|
|||
#include "headers.h"
|
||||
#include "version.h"
|
||||
|
||||
// reserve name "upx" for namespace
|
||||
namespace upx {}
|
||||
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(CHAR_BIT == 8)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(sizeof(short) == 2)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(sizeof(int) == 4)
|
||||
|
@ -85,30 +88,12 @@ inline void upx_std_call_once(upx_std_once_flag &flag, NoexceptCallable &&f) {
|
|||
}
|
||||
#endif // WITH_THREADS
|
||||
|
||||
// <type_traits> upx_std_is_bounded_array: same as C++20 std::is_bounded_array
|
||||
template <class T>
|
||||
struct upx_std_is_bounded_array : public std::false_type {};
|
||||
template <class T, size_t N>
|
||||
struct upx_std_is_bounded_array<T[N]> : public std::true_type {};
|
||||
template <class T>
|
||||
inline constexpr bool upx_std_is_bounded_array_v = upx_std_is_bounded_array<T>::value;
|
||||
|
||||
// <type_traits> upx_is_integral is overloaded for BE16 & friends; see bele.h
|
||||
template <class T>
|
||||
struct upx_is_integral : public std::is_integral<T> {};
|
||||
template <class T>
|
||||
inline constexpr bool upx_is_integral_v = upx_is_integral<T>::value;
|
||||
|
||||
// <type_traits> util: is_same_all and is_same_any means std::is_same for multiple types
|
||||
template <class T, class... Ts>
|
||||
struct is_same_all : public std::conjunction<std::is_same<T, Ts>...> {};
|
||||
template <class T, class... Ts>
|
||||
inline constexpr bool is_same_all_v = is_same_all<T, Ts...>::value;
|
||||
template <class T, class... Ts>
|
||||
struct is_same_any : public std::disjunction<std::is_same<T, Ts>...> {};
|
||||
template <class T, class... Ts>
|
||||
inline constexpr bool is_same_any_v = is_same_any<T, Ts...>::value;
|
||||
|
||||
#if (ACC_ARCH_M68K && ACC_OS_TOS && ACC_CC_GNUC) && defined(__MINT__)
|
||||
// horrible hack for broken compiler
|
||||
#define upx_fake_alignas_1 __attribute__((__aligned__(1),__packed__))
|
||||
|
@ -379,13 +364,6 @@ inline const T& UPX_MAX(const T& a, const T& b) { if (a < b) return b; return a;
|
|||
template <class T>
|
||||
inline const T& UPX_MIN(const T& a, const T& b) { if (a < b) return a; return b; }
|
||||
|
||||
template <size_t Size>
|
||||
struct UnsignedSizeOf {
|
||||
static_assert(Size >= 1 && Size <= UPX_RSIZE_MAX_MEM);
|
||||
static constexpr unsigned value = unsigned(Size);
|
||||
};
|
||||
#define usizeof(expr) (UnsignedSizeOf<sizeof(expr)>::value)
|
||||
|
||||
template <class T>
|
||||
inline void mem_clear(T *object) noexcept {
|
||||
static_assert(std::is_class_v<T>); // UPX convention
|
||||
|
@ -427,42 +405,14 @@ noinline void throwAssertFailed(const char *expr, const char *file, int line, co
|
|||
#define assert_noexcept assert
|
||||
#endif
|
||||
|
||||
class noncopyable {
|
||||
protected:
|
||||
inline noncopyable() noexcept {}
|
||||
inline ~noncopyable() noexcept = default;
|
||||
private:
|
||||
noncopyable(const noncopyable &) noexcept DELETED_FUNCTION; // copy constructor
|
||||
noncopyable& operator=(const noncopyable &) noexcept DELETED_FUNCTION; // copy assignment
|
||||
noncopyable(noncopyable &&) noexcept DELETED_FUNCTION; // move constructor
|
||||
noncopyable& operator=(noncopyable &&) noexcept DELETED_FUNCTION; // move assignment
|
||||
};
|
||||
#include "util/cxxlib.h"
|
||||
using upx::is_same_any_v;
|
||||
using upx::noncopyable;
|
||||
using upx::tribool;
|
||||
using upx::OptVar;
|
||||
#define usizeof(expr) (upx::UnsignedSizeOf<sizeof(expr)>::value)
|
||||
|
||||
|
||||
namespace compile_time {
|
||||
constexpr size_t string_len(const char *a) {
|
||||
return *a == '\0' ? 0 : 1 + string_len(a + 1);
|
||||
}
|
||||
constexpr bool string_eq(const char *a, const char *b) {
|
||||
return *a == *b && (*a == '\0' || string_eq(a + 1, b + 1));
|
||||
}
|
||||
constexpr bool string_lt(const char *a, const char *b) {
|
||||
return (uchar)*a < (uchar)*b || (*a != '\0' && *a == *b && string_lt(a + 1, b + 1));
|
||||
}
|
||||
constexpr bool string_ne(const char *a, const char *b) {
|
||||
return !string_eq(a, b);
|
||||
}
|
||||
constexpr bool string_gt(const char *a, const char *b) {
|
||||
return string_lt(b, a);
|
||||
}
|
||||
constexpr bool string_le(const char *a, const char *b) {
|
||||
return !string_lt(b, a);
|
||||
}
|
||||
constexpr bool string_ge(const char *a, const char *b) {
|
||||
return !string_lt(a, b);
|
||||
}
|
||||
} // namespace compile_time
|
||||
|
||||
/*************************************************************************
|
||||
// constants
|
||||
**************************************************************************/
|
||||
|
@ -632,52 +582,6 @@ struct upx_callback_t {
|
|||
// compression - config_t
|
||||
**************************************************************************/
|
||||
|
||||
template <class T, T default_value_, T min_value_, T max_value_>
|
||||
struct OptVar final {
|
||||
static_assert(std::is_integral_v<T>);
|
||||
typedef T value_type;
|
||||
static constexpr T default_value = default_value_;
|
||||
static constexpr T min_value = min_value_;
|
||||
static constexpr T max_value = max_value_;
|
||||
static_assert(min_value <= default_value && default_value <= max_value);
|
||||
|
||||
static void assertValue(const T &v) noexcept {
|
||||
// info: this generates annoying warnings "unsigned >= 0 is always true"
|
||||
//assert_noexcept(v >= min_value);
|
||||
assert_noexcept(v == min_value || v >= min_value + 1);
|
||||
assert_noexcept(v <= max_value);
|
||||
}
|
||||
void assertValue() const noexcept {
|
||||
assertValue(v);
|
||||
}
|
||||
|
||||
OptVar() noexcept : v(default_value), is_set(false) { }
|
||||
OptVar& operator= (const T &other) noexcept {
|
||||
assertValue(other);
|
||||
v = other;
|
||||
is_set = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void reset() noexcept { v = default_value; is_set = false; }
|
||||
operator T () const noexcept { return v; }
|
||||
|
||||
T v;
|
||||
bool is_set;
|
||||
};
|
||||
|
||||
|
||||
// optional assignments
|
||||
template <class T, T a, T b, T c>
|
||||
inline void oassign(OptVar<T,a,b,c> &self, const OptVar<T,a,b,c> &other) noexcept {
|
||||
if (other.is_set) { self.v = other.v; self.is_set = true; }
|
||||
}
|
||||
template <class T, T a, T b, T c>
|
||||
inline void oassign(T &v, const OptVar<T,a,b,c> &other) noexcept {
|
||||
if (other.is_set) { v = other.v; }
|
||||
}
|
||||
|
||||
|
||||
struct lzma_compress_config_t {
|
||||
typedef OptVar<unsigned, 2u, 0u, 4u> pos_bits_t; // pb
|
||||
typedef OptVar<unsigned, 0u, 0u, 4u> lit_pos_bits_t; // lp
|
||||
|
|
|
@ -96,7 +96,7 @@ private:
|
|||
// This class is private to Filter - don't look.
|
||||
**************************************************************************/
|
||||
|
||||
class FilterImpl {
|
||||
class FilterImpl final {
|
||||
friend class Filter;
|
||||
|
||||
private:
|
||||
|
|
|
@ -680,7 +680,7 @@ static int do_option(int optc, const char *arg) {
|
|||
case 632:
|
||||
opt->win32_pe.compress_resources = 1;
|
||||
if (mfx_optarg && mfx_optarg[0]) {
|
||||
int value;
|
||||
int value = 0;
|
||||
getoptvar(&value, 0, 1, arg);
|
||||
opt->win32_pe.compress_resources = bool(value);
|
||||
}
|
||||
|
|
|
@ -163,8 +163,8 @@ struct Options final {
|
|||
struct {
|
||||
int compress_exports;
|
||||
int compress_icons;
|
||||
TriBool<upx_int8_t> compress_resources;
|
||||
TriBool<upx_int8_t> compress_rt[25]; // 25 == RT_LAST
|
||||
upx::TriBool<upx_int8_t> compress_resources;
|
||||
upx::TriBool<upx_int8_t> compress_rt[25]; // 25 == RT_LAST
|
||||
int strip_relocs;
|
||||
const char *keep_resource;
|
||||
} win32_pe;
|
||||
|
|
|
@ -44,8 +44,8 @@ PackerBase::PackerBase(InputFile *f) : fi(f), file_size(f ? f->st.st_size : 0) {
|
|||
Packer::Packer(InputFile *f) : PackerBase(f) { uip = new UiPacker(this); }
|
||||
|
||||
Packer::~Packer() noexcept {
|
||||
owner_delete(uip);
|
||||
owner_delete(linker);
|
||||
upx::owner_delete(uip);
|
||||
upx::owner_delete(linker);
|
||||
assert_noexcept(linker == nullptr);
|
||||
}
|
||||
|
||||
|
@ -778,7 +778,7 @@ static const char *getIdentstr(unsigned *size, int small) {
|
|||
}
|
||||
|
||||
void Packer::initLoader(const void *pdata, int plen, int small, int pextra) {
|
||||
owner_delete(linker);
|
||||
upx::owner_delete(linker);
|
||||
linker = newLinker();
|
||||
assert(bele == linker->bele);
|
||||
linker->init(pdata, plen, pextra);
|
||||
|
|
|
@ -40,8 +40,8 @@
|
|||
#include "p_com.h"
|
||||
#include "p_djgpp2.h"
|
||||
#include "p_exe.h"
|
||||
#include "p_lx_exc.h"
|
||||
#include "p_lx_elf.h"
|
||||
#include "p_lx_exc.h"
|
||||
#include "p_lx_interp.h"
|
||||
#include "p_lx_sh.h"
|
||||
#include "p_mach.h"
|
||||
|
@ -54,8 +54,8 @@
|
|||
#include "p_w32pe_i386.h"
|
||||
#include "p_w64pe_amd64.h"
|
||||
#include "p_w64pe_arm64.h"
|
||||
#include "p_wince_arm.h"
|
||||
#include "p_wcle.h"
|
||||
#include "p_wince_arm.h"
|
||||
|
||||
/*************************************************************************
|
||||
//
|
||||
|
@ -74,7 +74,7 @@ PackMaster::PackMaster(InputFile *f, Options *o) noexcept : fi(f) {
|
|||
}
|
||||
|
||||
PackMaster::~PackMaster() noexcept {
|
||||
owner_delete(packer);
|
||||
upx::owner_delete(packer);
|
||||
// restore global options
|
||||
if (saved_opt != nullptr) {
|
||||
#if WITH_THREADS
|
||||
|
@ -101,7 +101,7 @@ static tribool try_can_pack(PackerBase *pb, void *user) may_throw {
|
|||
f->seek(0, SEEK_SET);
|
||||
return true; // success
|
||||
}
|
||||
if (r.isOther()) // aka "-1"
|
||||
if (r.isThird()) // aka "-1"
|
||||
return r; // canPack() says the format is recognized and we should fail early
|
||||
} catch (const IOException &) {
|
||||
// ignored
|
||||
|
@ -119,7 +119,7 @@ static tribool try_can_unpack(PackerBase *pb, void *user) may_throw {
|
|||
f->seek(0, SEEK_SET);
|
||||
return true; // success
|
||||
}
|
||||
if (r.isOther()) // aka "-1"
|
||||
if (r.isThird()) // aka "-1"
|
||||
return r; // canUnpack() says the format is recognized and we should fail early
|
||||
} catch (const IOException &) {
|
||||
// ignored
|
||||
|
@ -145,7 +145,7 @@ PackerBase *PackMaster::visitAllPackers(visit_func_t func, InputFile *f, const O
|
|||
tribool r = func(pb.get(), user); \
|
||||
if (r) \
|
||||
return pb.release(); /* success */ \
|
||||
if (r.isOther()) \
|
||||
if (r.isThird()) \
|
||||
return nullptr; /* stop and fail early */ \
|
||||
ACC_BLOCK_END
|
||||
|
||||
|
|
|
@ -1795,14 +1795,14 @@ void PeFile::processResources(Resource *res) {
|
|||
return;
|
||||
|
||||
// setup default options for resource compression
|
||||
if (opt->win32_pe.compress_resources.isOther())
|
||||
if (opt->win32_pe.compress_resources.isThird())
|
||||
opt->win32_pe.compress_resources = !isefi;
|
||||
if (!opt->win32_pe.compress_resources) {
|
||||
opt->win32_pe.compress_icons = false;
|
||||
for (int i = 0; i < RT_LAST; i++)
|
||||
opt->win32_pe.compress_rt[i] = false;
|
||||
}
|
||||
if (opt->win32_pe.compress_rt[RT_STRING].isOther()) {
|
||||
if (opt->win32_pe.compress_rt[RT_STRING].isThird()) {
|
||||
// by default, don't compress RT_STRINGs of screensavers (".scr")
|
||||
opt->win32_pe.compress_rt[RT_STRING] = true;
|
||||
if (fn_has_ext(fi->getName(), "scr"))
|
||||
|
|
|
@ -186,7 +186,7 @@ UiPacker::UiPacker(const PackerBase *pb_) : pb(pb_) {
|
|||
UiPacker::~UiPacker() noexcept {
|
||||
cb.reset();
|
||||
// owner
|
||||
owner_delete(s);
|
||||
upx::owner_delete(s);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
|
|
|
@ -0,0 +1,256 @@
|
|||
/* cxxlib.h --
|
||||
|
||||
This file is part of the UPX executable compressor.
|
||||
|
||||
Copyright (C) 1996-2023 Markus Franz Xaver Johannes Oberhumer
|
||||
All Rights Reserved.
|
||||
|
||||
UPX and the UCL library are free software; you can redistribute them
|
||||
and/or modify them under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer
|
||||
<markus@oberhumer.com>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// #include <stddef.h>
|
||||
// #include <type_traits>
|
||||
|
||||
namespace upx {
|
||||
|
||||
/*************************************************************************
|
||||
// type_traits
|
||||
**************************************************************************/
|
||||
|
||||
// <type_traits> is_bounded_array: same as C++20 std::is_bounded_array
|
||||
template <class T>
|
||||
struct is_bounded_array : public std::false_type {};
|
||||
template <class T, size_t N>
|
||||
struct is_bounded_array<T[N]> : public std::true_type {};
|
||||
template <class T>
|
||||
inline constexpr bool is_bounded_array_v = is_bounded_array<T>::value;
|
||||
|
||||
// <type_traits> util: is_same_all and is_same_any means std::is_same for multiple types
|
||||
template <class T, class... Ts>
|
||||
struct is_same_all : public std::conjunction<std::is_same<T, Ts>...> {};
|
||||
template <class T, class... Ts>
|
||||
inline constexpr bool is_same_all_v = is_same_all<T, Ts...>::value;
|
||||
template <class T, class... Ts>
|
||||
struct is_same_any : public std::disjunction<std::is_same<T, Ts>...> {};
|
||||
template <class T, class... Ts>
|
||||
inline constexpr bool is_same_any_v = is_same_any<T, Ts...>::value;
|
||||
|
||||
/*************************************************************************
|
||||
// util
|
||||
**************************************************************************/
|
||||
|
||||
template <size_t Size>
|
||||
struct UnsignedSizeOf {
|
||||
static_assert(Size >= 1 && Size <= UPX_RSIZE_MAX_MEM);
|
||||
static constexpr unsigned value = unsigned(Size);
|
||||
};
|
||||
|
||||
class noncopyable {
|
||||
protected:
|
||||
inline noncopyable() noexcept {}
|
||||
inline ~noncopyable() noexcept = default;
|
||||
private:
|
||||
noncopyable(const noncopyable &) noexcept DELETED_FUNCTION; // copy constructor
|
||||
noncopyable &operator=(const noncopyable &) noexcept DELETED_FUNCTION; // copy assignment
|
||||
noncopyable(noncopyable &&) noexcept DELETED_FUNCTION; // move constructor
|
||||
noncopyable &operator=(noncopyable &&) noexcept DELETED_FUNCTION; // move assignment
|
||||
};
|
||||
|
||||
namespace compile_time {
|
||||
constexpr size_t string_len(const char *a) { return *a == '\0' ? 0 : 1 + string_len(a + 1); }
|
||||
constexpr bool string_eq(const char *a, const char *b) {
|
||||
return *a == *b && (*a == '\0' || string_eq(a + 1, b + 1));
|
||||
}
|
||||
constexpr bool string_lt(const char *a, const char *b) {
|
||||
return (uchar) *a < (uchar) *b || (*a != '\0' && *a == *b && string_lt(a + 1, b + 1));
|
||||
}
|
||||
constexpr bool string_ne(const char *a, const char *b) { return !string_eq(a, b); }
|
||||
constexpr bool string_gt(const char *a, const char *b) { return string_lt(b, a); }
|
||||
constexpr bool string_le(const char *a, const char *b) { return !string_lt(b, a); }
|
||||
constexpr bool string_ge(const char *a, const char *b) { return !string_lt(a, b); }
|
||||
} // namespace compile_time
|
||||
|
||||
/*************************************************************************
|
||||
// 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
|
||||
**************************************************************************/
|
||||
|
||||
template <class T = int, T ThirdValue = -1> // ThirdValue 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 };
|
||||
// constructors
|
||||
forceinline constexpr TriBool() noexcept : value(False) {}
|
||||
forceinline constexpr TriBool(value_type x) noexcept : value(x) {}
|
||||
constexpr TriBool(promoted_type x) noexcept : value(x == 0 ? False : (x == 1 ? True : Third)) {}
|
||||
forceinline ~TriBool() noexcept = default;
|
||||
// access
|
||||
constexpr value_type getValue() const noexcept { return value; }
|
||||
// checks for > 0, so ThirdValue determines if Third is false (the default) or true
|
||||
explicit constexpr operator bool() const noexcept { return value > False; }
|
||||
// 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; }
|
||||
constexpr bool isStrictBool() const noexcept { return value == False || value == True; }
|
||||
constexpr bool isThird() const noexcept { return value != False && value != True; }
|
||||
constexpr bool operator==(TriBool other) const noexcept { return value == other.value; }
|
||||
constexpr bool operator==(value_type other) const noexcept { return value == other; }
|
||||
constexpr bool operator==(promoted_type other) const noexcept { return value == other; }
|
||||
|
||||
// "third" can mean many things, depending on usage context, so provide some alternative names:
|
||||
// constexpr bool isDefault() const noexcept { return isThird(); } // might be misleading
|
||||
constexpr bool isIndeterminate() const noexcept { return isThird(); }
|
||||
constexpr bool isOther() const noexcept { return isThird(); }
|
||||
constexpr bool isUndecided() const noexcept { return isThird(); }
|
||||
// constexpr bool isUnset() const noexcept { return isThird(); } // might be misleading
|
||||
|
||||
// protected:
|
||||
value_type value;
|
||||
};
|
||||
|
||||
typedef TriBool<> tribool;
|
||||
|
||||
/*************************************************************************
|
||||
// OptVar and oassign
|
||||
**************************************************************************/
|
||||
|
||||
template <class T, T default_value_, T min_value_, T max_value_>
|
||||
struct OptVar final {
|
||||
static_assert(std::is_integral_v<T>);
|
||||
typedef T value_type;
|
||||
static constexpr T default_value = default_value_;
|
||||
static constexpr T min_value = min_value_;
|
||||
static constexpr T max_value = max_value_;
|
||||
static_assert(min_value <= default_value && default_value <= max_value);
|
||||
|
||||
static void assertValue(const T &value) noexcept {
|
||||
// info: this generates annoying warnings "unsigned >= 0 is always true"
|
||||
// assert_noexcept(value >= min_value);
|
||||
assert_noexcept(value == min_value || value >= min_value + 1);
|
||||
assert_noexcept(value <= max_value);
|
||||
}
|
||||
void assertValue() const noexcept { assertValue(value); }
|
||||
|
||||
constexpr OptVar() noexcept : value(default_value), is_set(false) {}
|
||||
OptVar &operator=(const T &other) noexcept {
|
||||
assertValue(other);
|
||||
value = other;
|
||||
is_set = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void reset() noexcept {
|
||||
value = default_value;
|
||||
is_set = false;
|
||||
}
|
||||
constexpr operator T() const noexcept { return value; }
|
||||
|
||||
// protected:
|
||||
T value;
|
||||
bool is_set;
|
||||
};
|
||||
|
||||
// optional assignments
|
||||
template <class T, T a, T b, T c>
|
||||
inline void oassign(OptVar<T, a, b, c> &self, const OptVar<T, a, b, c> &other) noexcept {
|
||||
if (other.is_set) {
|
||||
self.value = other.value;
|
||||
self.is_set = true;
|
||||
}
|
||||
}
|
||||
template <class T, T a, T b, T c>
|
||||
inline void oassign(T &v, const OptVar<T, a, b, c> &other) noexcept {
|
||||
if (other.is_set) {
|
||||
v = other.value;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
// OwningPointer(T)
|
||||
// simple pointer type alias to explicitly mark ownership of objects; purely
|
||||
// cosmetic to improve source code readability, no real functionality
|
||||
**************************************************************************/
|
||||
|
||||
#if 0
|
||||
|
||||
// this works
|
||||
#define OwningPointer(T) T *
|
||||
|
||||
#elif !(DEBUG)
|
||||
|
||||
// this also works
|
||||
template <class T>
|
||||
using OwningPointer = T *;
|
||||
#define OwningPointer(T) upx::OwningPointer<T>
|
||||
|
||||
#else
|
||||
|
||||
// also works: a trivial class with just a number of no-ops
|
||||
template <class T>
|
||||
struct OwningPointer final {
|
||||
static_assert(std::is_class_v<T>); // UPX convention
|
||||
typedef typename std::add_lvalue_reference<T>::type reference;
|
||||
typedef typename std::add_lvalue_reference<const T>::type const_reference;
|
||||
typedef typename std::add_pointer<T>::type pointer;
|
||||
typedef typename std::add_pointer<const T>::type const_pointer;
|
||||
pointer ptr;
|
||||
inline OwningPointer(pointer p) noexcept : ptr(p) {}
|
||||
inline operator pointer() noexcept { return ptr; }
|
||||
inline operator const_pointer() const noexcept { return ptr; }
|
||||
inline reference operator*() noexcept { return *ptr; }
|
||||
inline const_reference operator*() const noexcept { return *ptr; }
|
||||
inline pointer operator->() noexcept { return ptr; }
|
||||
inline const_pointer operator->() const noexcept { return ptr; }
|
||||
};
|
||||
// must overload mem_clear()
|
||||
template <class T>
|
||||
inline void mem_clear(OwningPointer<T> object) noexcept {
|
||||
mem_clear((T *) object);
|
||||
}
|
||||
#define OwningPointer(T) upx::OwningPointer<T>
|
||||
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
inline void owner_delete(OwningPointer(T)(&object)) noexcept {
|
||||
static_assert(std::is_class_v<T>); // UPX convention
|
||||
static_assert(std::is_nothrow_destructible_v<T>);
|
||||
if (object != nullptr) {
|
||||
delete (T *) object;
|
||||
object = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// disable some overloads
|
||||
#if defined(__clang__) || __GNUC__ != 7
|
||||
template <class T>
|
||||
inline void owner_delete(T (&array)[]) noexcept DELETED_FUNCTION;
|
||||
#endif
|
||||
template <class T, size_t N>
|
||||
inline void owner_delete(T (&array)[N]) noexcept DELETED_FUNCTION;
|
||||
|
||||
} // namespace upx
|
|
@ -35,7 +35,7 @@
|
|||
|
||||
// default: for any regular pointer, raw_bytes() is just the pointer itself
|
||||
template <class T>
|
||||
inline typename std::enable_if<std::is_pointer<T>::value && !upx_std_is_bounded_array<T>::value &&
|
||||
inline typename std::enable_if<std::is_pointer<T>::value && !upx::is_bounded_array<T>::value &&
|
||||
(upx_is_integral<typename std::remove_pointer<T>::type>::value ||
|
||||
std::is_void<typename std::remove_pointer<T>::type>::value),
|
||||
T>::type
|
||||
|
@ -52,7 +52,7 @@ raw_bytes(T ptr, size_t size_in_bytes) {
|
|||
// default: for any regular pointer, raw_index_bytes() is just "pointer + index"
|
||||
// NOTE: index == number of elements, *NOT* size in bytes!
|
||||
template <class T>
|
||||
inline typename std::enable_if<std::is_pointer<T>::value && !upx_std_is_bounded_array<T>::value &&
|
||||
inline typename std::enable_if<std::is_pointer<T>::value && !upx::is_bounded_array<T>::value &&
|
||||
upx_is_integral<typename std::remove_pointer<T>::type>::value,
|
||||
T>::type
|
||||
raw_index_bytes(T ptr, size_t index, size_t size_in_bytes) {
|
||||
|
|
|
@ -787,66 +787,4 @@ TEST_CASE("get_ratio") {
|
|||
CHECK(get_ratio(2 * UPX_RSIZE_MAX, 1024ull * UPX_RSIZE_MAX) == 9999999);
|
||||
}
|
||||
|
||||
namespace {
|
||||
template <class T>
|
||||
struct TestTriBool {
|
||||
static void test(bool expect_true, int x) noexcept {
|
||||
CHECK(T(false) == T::False);
|
||||
CHECK(T(true) == T::True);
|
||||
CHECK(T(T::Other) == T::Other);
|
||||
T a;
|
||||
CHECK(!a);
|
||||
CHECK(a.isStrictFalse());
|
||||
CHECK(!a.isStrictTrue());
|
||||
CHECK(a.isStrictBool());
|
||||
CHECK(!a.isOther());
|
||||
a = false;
|
||||
CHECK(!a);
|
||||
CHECK(a.isStrictFalse());
|
||||
CHECK(!a.isStrictTrue());
|
||||
CHECK(a.isStrictBool());
|
||||
CHECK(!a.isOther());
|
||||
a = true;
|
||||
CHECK(a);
|
||||
CHECK(!a.isStrictFalse());
|
||||
CHECK(a.isStrictTrue());
|
||||
CHECK(a.isStrictBool());
|
||||
CHECK(!a.isOther());
|
||||
a = T::Other;
|
||||
if (expect_true)
|
||||
CHECK(a);
|
||||
else
|
||||
CHECK(!a);
|
||||
CHECK(!a.isStrictFalse());
|
||||
CHECK(!a.isStrictTrue());
|
||||
CHECK(!a.isStrictBool());
|
||||
CHECK(a.isOther());
|
||||
a = x;
|
||||
if (expect_true)
|
||||
CHECK(a);
|
||||
else
|
||||
CHECK(!a);
|
||||
CHECK(!a.isStrictFalse());
|
||||
CHECK(!a.isStrictTrue());
|
||||
CHECK(!a.isStrictBool());
|
||||
CHECK(a.isOther());
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("TriBool") {
|
||||
static_assert(!tribool(false));
|
||||
static_assert(tribool(true));
|
||||
static_assert(!tribool(tribool::Other));
|
||||
TestTriBool<tribool>::test(false, -1);
|
||||
//
|
||||
TestTriBool<TriBool<upx_int8_t> >::test(false, -1);
|
||||
TestTriBool<TriBool<upx_int64_t> >::test(false, -1);
|
||||
//
|
||||
TestTriBool<TriBool<upx_int8_t, 2> >::test(true, 2);
|
||||
TestTriBool<TriBool<upx_uint8_t, 2> >::test(true, 2);
|
||||
TestTriBool<TriBool<upx_int64_t, 2> >::test(true, 2);
|
||||
TestTriBool<TriBool<upx_uint64_t, 2> >::test(true, 2);
|
||||
}
|
||||
|
||||
/* vim:set ts=4 sw=4 et: */
|
||||
|
|
107
src/util/util.h
107
src/util/util.h
|
@ -130,113 +130,6 @@ void upx_memswap(void *a, void *b, size_t n);
|
|||
void upx_stable_sort(void *array, size_t n, size_t element_size,
|
||||
int (*compare)(const void *, const void *));
|
||||
|
||||
/*************************************************************************
|
||||
// OwningPointer(T)
|
||||
// simple pointer type alias to explicitly mark ownership of objects; purely
|
||||
// cosmetic to improve source code readability, no real functionality
|
||||
**************************************************************************/
|
||||
|
||||
#if 0
|
||||
|
||||
// this works
|
||||
#define OwningPointer(T) T *
|
||||
|
||||
#elif !(DEBUG)
|
||||
|
||||
// this also works
|
||||
template <class T>
|
||||
using OwningPointer = T *;
|
||||
#define OwningPointer(T) OwningPointer<T>
|
||||
|
||||
#else
|
||||
|
||||
// also works: a trivial class with just a number of no-ops
|
||||
template <class T>
|
||||
struct OwningPointer final {
|
||||
static_assert(std::is_class_v<T>); // UPX convention
|
||||
typedef typename std::add_lvalue_reference<T>::type reference;
|
||||
typedef typename std::add_lvalue_reference<const T>::type const_reference;
|
||||
typedef typename std::add_pointer<T>::type pointer;
|
||||
typedef typename std::add_pointer<const T>::type const_pointer;
|
||||
pointer ptr;
|
||||
inline OwningPointer(pointer p) noexcept : ptr(p) {}
|
||||
inline operator pointer() noexcept { return ptr; }
|
||||
inline operator const_pointer() const noexcept { return ptr; }
|
||||
inline reference operator*() noexcept { return *ptr; }
|
||||
inline const_reference operator*() const noexcept { return *ptr; }
|
||||
inline pointer operator->() noexcept { return ptr; }
|
||||
inline const_pointer operator->() const noexcept { return ptr; }
|
||||
};
|
||||
// must overload mem_clear()
|
||||
template <class T>
|
||||
inline void mem_clear(OwningPointer<T> object) noexcept {
|
||||
mem_clear((T *) object);
|
||||
}
|
||||
#define OwningPointer(T) OwningPointer<T>
|
||||
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
inline void owner_delete(OwningPointer(T)(&object)) noexcept {
|
||||
static_assert(std::is_class_v<T>); // UPX convention
|
||||
static_assert(std::is_nothrow_destructible_v<T>);
|
||||
if (object != nullptr) {
|
||||
delete (T *) object;
|
||||
object = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// disable some overloads
|
||||
#if defined(__clang__) || __GNUC__ != 7
|
||||
template <class T>
|
||||
inline void owner_delete(T (&array)[]) noexcept DELETED_FUNCTION;
|
||||
#endif
|
||||
template <class T, size_t N>
|
||||
inline void owner_delete(T (&array)[N]) noexcept DELETED_FUNCTION;
|
||||
|
||||
/*************************************************************************
|
||||
// TriBool - tri-state bool
|
||||
**************************************************************************/
|
||||
|
||||
template <class T = int, T TOther = -1> // an enum with an underlying type and 3 values
|
||||
class TriBool {
|
||||
public:
|
||||
// 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(TOther != 0 && TOther != 1);
|
||||
enum value_type : underlying_type { False = 0, True = 1, Other = TOther };
|
||||
// constructors
|
||||
forceinline constexpr TriBool() noexcept = default;
|
||||
forceinline ~TriBool() noexcept = default;
|
||||
constexpr TriBool(value_type x) noexcept : value(x) {}
|
||||
constexpr TriBool(promoted_type x) noexcept : value(x == 0 ? False : (x == 1 ? True : Other)) {}
|
||||
// access
|
||||
constexpr value_type getValue() const noexcept { return value; }
|
||||
// checks for > 0, so TOther determines if Other is false (the default) or true
|
||||
explicit constexpr operator bool() const noexcept { return value > False; }
|
||||
// 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; }
|
||||
constexpr bool isStrictBool() const noexcept { return value == False || value == True; }
|
||||
constexpr bool isOther() const noexcept { return value != False && value != True; }
|
||||
// "other" can mean many things, depending on usage context, so provide some alternative names:
|
||||
// constexpr bool isDefault() const noexcept { return isOther(); } // might be misleading
|
||||
constexpr bool isIndeterminate() const noexcept { return isOther(); }
|
||||
constexpr bool isUndecided() const noexcept { return isOther(); }
|
||||
// constexpr bool isUnset() const noexcept { return isOther(); } // might be misleading
|
||||
constexpr bool operator==(TriBool other) const noexcept { return value == other.value; }
|
||||
constexpr bool operator==(value_type other) const noexcept { return value == other; }
|
||||
constexpr bool operator==(promoted_type other) const noexcept { return value == other; }
|
||||
protected:
|
||||
// value
|
||||
value_type value = False;
|
||||
};
|
||||
|
||||
typedef TriBool<> tribool;
|
||||
|
||||
/*************************************************************************
|
||||
// misc. support functions
|
||||
**************************************************************************/
|
||||
|
|
Loading…
Reference in New Issue