all: assorted cleanups and updates

Changes include:
  - add a bunch of "noexcept", mostly to operators and forceinline
  - use "uchar"
  - use "charptr"
  - rename options_t to Options
  - add ptr_check_no_overlap()
  - rewrite p_exe.cpp, NFCI
  - clang-format help.cpp
  - spelling fixes
This commit is contained in:
Markus F.X.J. Oberhumer
2023-03-15 00:19:55 +01:00
parent 127fd095e7
commit a627648249
65 changed files with 1492 additions and 1138 deletions
+5 -5
View File
@@ -74,7 +74,7 @@ MemBuffer::MemBuffer(upx_uint64_t bytes) {
debug_set(debug.last_return_address_alloc, upx_return_address());
}
MemBuffer::~MemBuffer() { this->dealloc(); }
MemBuffer::~MemBuffer() noexcept { this->dealloc(); }
// similar to BoundedPtr, except checks only at creation
// skip == offset, take == size_in_bytes
@@ -215,19 +215,19 @@ void MemBuffer::alloc(upx_uint64_t bytes) {
set_ne32(p + size_in_bytes + 4, stats.global_alloc_counter);
}
ptr = (pointer) (void *) p;
#if !defined(__SANITIZE_ADDRESS__) && 0
fill(0, size_in_bytes, (rand() & 0xff) | 1); // debug
#if DEBUG
memset(ptr, 0xff, size_in_bytes);
(void) VALGRIND_MAKE_MEM_UNDEFINED(ptr, size_in_bytes);
#endif
stats.global_alloc_counter += 1;
stats.global_total_bytes += size_in_bytes;
stats.global_total_active_bytes += size_in_bytes;
#if DEBUG
#if DEBUG || 1
checkState();
#endif
}
void MemBuffer::dealloc() {
void MemBuffer::dealloc() noexcept {
if (ptr != nullptr) {
debug_set(debug.last_return_address_dealloc, upx_return_address());
checkState();
+7 -6
View File
@@ -46,11 +46,12 @@ protected:
size_type size_in_bytes;
public:
MemBufferBase() : ptr(nullptr), size_in_bytes(0) {}
MemBufferBase() noexcept : ptr(nullptr), size_in_bytes(0) {}
inline ~MemBufferBase() noexcept {}
// NOTE: implicit conversion to underlying pointer
// HINT: for fully bound-checked pointer use XSPAN_S from xspan.h
operator pointer() const { return ptr; }
operator pointer() const noexcept { return ptr; }
// membuffer + n -> pointer
template <class U>
@@ -66,8 +67,8 @@ private:
DELETED_FUNCTION;
public: // raw access
pointer raw_ptr() const { return ptr; }
size_type raw_size_in_bytes() const { return size_in_bytes; }
pointer raw_ptr() const noexcept { return ptr; }
size_type raw_size_in_bytes() const noexcept { return size_in_bytes; }
pointer raw_bytes(size_t bytes) const {
if (bytes > 0) {
@@ -84,7 +85,7 @@ class MemBuffer final : public MemBufferBase<byte> {
public:
MemBuffer() : MemBufferBase<byte>() {}
explicit MemBuffer(upx_uint64_t bytes);
~MemBuffer();
~MemBuffer() noexcept;
static unsigned getSizeForCompression(unsigned uncompressed_size, unsigned extra = 0);
static unsigned getSizeForDecompression(unsigned uncompressed_size, unsigned extra = 0);
@@ -93,7 +94,7 @@ public:
void allocForCompression(unsigned uncompressed_size, unsigned extra = 0);
void allocForDecompression(unsigned uncompressed_size, unsigned extra = 0);
void dealloc();
void dealloc() noexcept;
void checkState() const;
unsigned getSize() const { return size_in_bytes; }
+9 -6
View File
@@ -35,9 +35,11 @@
// 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 && !std_is_bounded_array<T>::value, T>::type
raw_bytes(T ptr, size_t size_in_bytes) {
inline typename std::enable_if<std::is_pointer<T>::value && !upx_std_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
raw_bytes(T ptr, size_t size_in_bytes) {
if (size_in_bytes > 0) {
if very_unlikely (ptr == nullptr)
throwCantPack("raw_bytes unexpected NULL ptr");
@@ -50,9 +52,10 @@ inline
// 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 && !std_is_bounded_array<T>::value, T>::type
raw_index_bytes(T ptr, size_t index, size_t size_in_bytes) {
inline typename std::enable_if<std::is_pointer<T>::value && !upx_std_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) {
typedef typename std::remove_pointer<T>::type element_type;
if very_unlikely (ptr == nullptr)
throwCantPack("raw_index_bytes unexpected NULL ptr");
+10 -10
View File
@@ -60,30 +60,30 @@ upx_rsize_t upx_safe_strlen(const char *);
#define vsnprintf upx_safe_vsnprintf
/*************************************************************************
// some unsigned char string support functions to avoid casts
// some uchar string support functions to avoid casts
**************************************************************************/
inline unsigned char *strcpy(unsigned char *s1, const unsigned char *s2) {
return (unsigned char *) strcpy((char *) s1, (const char *) s2);
forceinline uchar *strcpy(uchar *s1, const uchar *s2) {
return (uchar *) strcpy((char *) s1, (const char *) s2);
}
inline int strcmp(const unsigned char *s1, const char *s2) { return strcmp((const char *) s1, s2); }
inline int strcmp(const char *s1, const unsigned char *s2) { return strcmp(s1, (const char *) s2); }
inline int strcmp(const unsigned char *s1, const unsigned char *s2) {
forceinline int strcmp(const uchar *s1, const char *s2) { return strcmp((const char *) s1, s2); }
forceinline int strcmp(const char *s1, const uchar *s2) { return strcmp(s1, (const char *) s2); }
forceinline int strcmp(const uchar *s1, const uchar *s2) {
return strcmp((const char *) s1, (const char *) s2);
}
inline int strcasecmp(const unsigned char *s1, const char *s2) {
forceinline int strcasecmp(const uchar *s1, const char *s2) {
return strcasecmp((const char *) s1, s2);
}
inline int strcasecmp(const char *s1, const unsigned char *s2) {
forceinline int strcasecmp(const char *s1, const uchar *s2) {
return strcasecmp(s1, (const char *) s2);
}
inline int strcasecmp(const unsigned char *s1, const unsigned char *s2) {
forceinline int strcasecmp(const uchar *s1, const uchar *s2) {
return strcasecmp((const char *) s1, (const char *) s2);
}
inline upx_rsize_t upx_safe_strlen(const unsigned char *s) {
forceinline upx_rsize_t upx_safe_strlen(const uchar *s) {
return upx_safe_strlen((const char *) s);
}
+166 -6
View File
@@ -101,6 +101,10 @@ TEST_CASE("mem_size") {
CHECK_THROWS(mem_size(1, 0x30000000, 0x30000000, 0x30000000));
}
/*************************************************************************
// ptr util
**************************************************************************/
int ptr_diff_bytes(const void *a, const void *b) {
if very_unlikely (a == nullptr) {
throwCantPack("ptr_diff_bytes null 1; take care");
@@ -108,13 +112,13 @@ int ptr_diff_bytes(const void *a, const void *b) {
if very_unlikely (b == nullptr) {
throwCantPack("ptr_diff_bytes null 2; take care");
}
ptrdiff_t d = (const char *) a - (const char *) b;
ptrdiff_t d = (const charptr) a - (const charptr) b;
if (a >= b) {
if very_unlikely (!mem_size_valid_bytes(d))
throwCantPack("ptr_diff_bytes 1; take care");
throwCantPack("ptr_diff_bytes-1; take care");
} else {
if very_unlikely (!mem_size_valid_bytes(-d))
throwCantPack("ptr_diff_bytes 2; take care");
throwCantPack("ptr_diff_bytes-2; take care");
}
return ACC_ICONV(int, d);
}
@@ -127,7 +131,7 @@ unsigned ptr_udiff_bytes(const void *a, const void *b) {
}
TEST_CASE("ptr_diff") {
char buf[4] = {0, 1, 2, 3};
byte buf[4] = {0, 1, 2, 3};
CHECK_THROWS(ptr_diff_bytes(nullptr, buf));
CHECK_THROWS(ptr_diff_bytes(buf, nullptr));
CHECK(ptr_diff(buf, buf) == 0);
@@ -138,6 +142,108 @@ TEST_CASE("ptr_diff") {
CHECK_THROWS(ptr_udiff(buf, buf + 1));
}
// check that 2 buffers do not overlap; will throw on error
void uintptr_check_no_overlap(upx_uintptr_t a, size_t a_size, upx_uintptr_t b, size_t b_size) {
if very_unlikely (a == 0 || b == 0)
throwCantPack("ptr_check_no_overlap-nullptr");
upx_uintptr_t a_end = a + mem_size(1, a_size);
upx_uintptr_t b_end = b + mem_size(1, b_size);
if very_unlikely (a_end < a || b_end < b) // wrap-around
throwCantPack("ptr_check_no_overlap-overflow");
// same as (!(a >= b_end || b >= a_end))
if (a < b_end && b < a_end)
throwCantPack("ptr_check_no_overlap-ab");
}
// check that 3 buffers do not overlap; will throw on error
void uintptr_check_no_overlap(upx_uintptr_t a, size_t a_size, upx_uintptr_t b, size_t b_size,
upx_uintptr_t c, size_t c_size) {
if very_unlikely (a == 0 || b == 0 || c == 0)
throwCantPack("ptr_check_no_overlap-nullptr");
upx_uintptr_t a_end = a + mem_size(1, a_size);
upx_uintptr_t b_end = b + mem_size(1, b_size);
upx_uintptr_t c_end = c + mem_size(1, c_size);
if very_unlikely (a_end < a || b_end < b || c_end < c) // wrap-around
throwCantPack("ptr_check_no_overlap-overflow");
if (a < b_end && b < a_end)
throwCantPack("ptr_check_no_overlap-ab");
if (a < c_end && c < a_end)
throwCantPack("ptr_check_no_overlap-ac");
if (b < c_end && c < b_end)
throwCantPack("ptr_check_no_overlap-bc");
}
TEST_CASE("ptr_check_no_overlap 2") {
byte p[4] = {};
auto check_nothrow = [&p](int a, int as, int b, int bs) {
CHECK_NOTHROW(ptr_check_no_overlap(p + a, as, p + b, bs)); // ab
CHECK_NOTHROW(ptr_check_no_overlap(p + b, bs, p + a, as)); // ba
};
auto check_throws_ = [&p](int a, int as, int b, int bs) {
CHECK_THROWS(ptr_check_no_overlap(p + a, as, p + b, bs)); // ab
CHECK_THROWS(ptr_check_no_overlap(p + b, bs, p + a, as)); // ba
};
check_throws_(0, 1, 0, 1);
check_nothrow(0, 1, 1, 1);
check_throws_(0, 2, 1, 1);
check_nothrow(0, 2, 2, 1);
// empty buffers at edge
check_nothrow(0, 0, 0, 0);
check_nothrow(0, 0, 0, 1);
check_nothrow(0, 0, 1, 0);
// empty buffer
check_nothrow(0, 4, 0, 0);
check_throws_(0, 4, 1, 0);
check_throws_(0, 4, 2, 0);
check_throws_(0, 4, 3, 0);
check_nothrow(0, 4, 4, 0);
}
TEST_CASE("ptr_check_no_overlap 3") {
byte p[4] = {};
auto check_nothrow = [&p](int a, int as, int b, int bs, int c, int cs) {
CHECK_NOTHROW(ptr_check_no_overlap(p + a, as, p + b, bs, p + c, cs)); // abc
CHECK_NOTHROW(ptr_check_no_overlap(p + a, as, p + c, cs, p + b, bs)); // acb
CHECK_NOTHROW(ptr_check_no_overlap(p + b, bs, p + a, as, p + c, cs)); // bac
CHECK_NOTHROW(ptr_check_no_overlap(p + b, bs, p + c, cs, p + a, as)); // bca
CHECK_NOTHROW(ptr_check_no_overlap(p + c, cs, p + a, as, p + b, bs)); // cab
CHECK_NOTHROW(ptr_check_no_overlap(p + c, cs, p + b, bs, p + a, as)); // cba
};
auto check_throws_ = [&p](int a, int as, int b, int bs, int c, int cs) {
CHECK_THROWS(ptr_check_no_overlap(p + a, as, p + b, bs, p + c, cs)); // abc
CHECK_THROWS(ptr_check_no_overlap(p + a, as, p + c, cs, p + b, bs)); // acb
CHECK_THROWS(ptr_check_no_overlap(p + b, bs, p + a, as, p + c, cs)); // bac
CHECK_THROWS(ptr_check_no_overlap(p + b, bs, p + c, cs, p + a, as)); // bca
CHECK_THROWS(ptr_check_no_overlap(p + c, cs, p + a, as, p + b, bs)); // cab
CHECK_THROWS(ptr_check_no_overlap(p + c, cs, p + b, bs, p + a, as)); // cba
};
check_throws_(0, 1, 0, 1, 1, 1);
check_nothrow(0, 1, 1, 1, 2, 1);
check_throws_(0, 2, 1, 1, 2, 1);
check_nothrow(0, 2, 2, 1, 3, 1);
// empty buffers at edge
check_nothrow(0, 0, 0, 0, 0, 0);
check_nothrow(0, 0, 0, 0, 0, 1);
check_nothrow(0, 0, 0, 1, 1, 1);
check_nothrow(0, 0, 1, 0, 1, 1);
// empty buffer
check_nothrow(0, 4, 0, 0, 0, 0);
check_throws_(0, 4, 1, 0, 0, 0);
check_throws_(0, 4, 2, 0, 0, 0);
check_throws_(0, 4, 3, 0, 0, 0);
check_nothrow(0, 4, 4, 0, 0, 0);
// empty buffer
check_throws_(0, 4, 0, 0, 1, 0);
check_throws_(0, 4, 1, 0, 1, 0);
check_throws_(0, 4, 2, 0, 1, 0);
check_throws_(0, 4, 3, 0, 1, 0);
check_throws_(0, 4, 4, 0, 1, 0);
}
/*************************************************************************
// bele.h
**************************************************************************/
@@ -152,6 +258,60 @@ const BEPolicy be_policy;
const LEPolicy le_policy;
} // namespace N_BELE_RTP
/*************************************************************************
// stdlib
**************************************************************************/
void *upx_calloc(size_t n, size_t element_size) {
size_t bytes = mem_size(element_size, n); // assert size
void *p = malloc(bytes);
if (p != nullptr)
memset(p, 0, bytes);
return p;
}
// extremely simple stable sort: Gnomesort
// WARNING: O(n**2) !!!!!
void upx_stable_sort(void *base, size_t n, size_t element_size,
int(__acc_cdecl_qsort *compare)(const void *, const void *)) {
(void) mem_size(element_size, n); // assert size
for (size_t i = 1; i < n;) {
char *a = (char *) base + element_size * i; // a = &array[i]
if (i == 0 || (compare(a - element_size, a) <= 0)) {
i += 1;
} else {
i -= 1;
// swap elements a[-1] <=> a[0]
// upx_memswap(a - element_size, a, element_size);
size_t j = element_size;
do {
char tmp = *(a - element_size);
*(a - element_size) = *a;
*a++ = tmp;
} while (--j != 0);
}
}
}
TEST_CASE("upx_stable_sort") {
// TODO C++20: use std::next_permutation() to test all permutations
{
unsigned a[] = {0, 1};
upx_stable_sort(a, 2, sizeof(*a), ne32_compare);
CHECK((a[0] == 0 && a[1] == 1));
}
{
unsigned a[] = {1, 0};
upx_stable_sort(a, 2, sizeof(*a), ne32_compare);
CHECK((a[0] == 0 && a[1] == 1));
}
{
unsigned a[] = {2, 1, 0};
upx_stable_sort(a, 3, sizeof(*a), ne32_compare);
CHECK((a[0] == 0 && a[1] == 1 && a[2] == 2));
}
}
/*************************************************************************
// qsort() util
**************************************************************************/
@@ -258,7 +418,7 @@ int __acc_cdecl_qsort le64_compare_signed(const void *e1, const void *e2) {
int find(const void *buf, int blen, const void *what, int wlen) {
// nullptr is explicitly allowed here
if (buf == nullptr || blen <= 0 || what == nullptr || wlen <= 0)
if (buf == nullptr || blen < wlen || what == nullptr || wlen <= 0)
return -1;
const byte *b = (const byte *) buf;
@@ -367,7 +527,7 @@ static const char dir_sep[] = "/\\";
#define fn_is_drive(s) (s[0] && s[1] == ':')
#define fn_is_sep(c) (strchr(dir_sep, c) != nullptr)
#define fn_skip_drive(s) (fn_is_drive(s) ? (s) + 2 : (s))
#define fn_tolower(c) (tolower(((unsigned char) (c))))
#define fn_tolower(c) (tolower(((uchar) (c))))
#else
+45 -3
View File
@@ -40,9 +40,6 @@ inline bool mem_size_valid_bytes(upx_uint64_t bytes) noexcept { return bytes <=
bool mem_size_valid(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1 = 0,
upx_uint64_t extra2 = 0) noexcept;
// "new" with asserted size; will throw on invalid size
#define New(type, n) new type[mem_size_get_n(sizeof(type), n)]
// will throw on invalid size
upx_rsize_t mem_size(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1,
upx_uint64_t extra2 = 0);
@@ -77,6 +74,27 @@ inline void mem_clear(void *p, size_t n) {
memset(p, 0, n);
}
// "new" with asserted size; will throw on invalid size
#if DEBUG
template <class T>
T *NewArray(upx_uint64_t n) {
size_t bytes = mem_size(sizeof(T), n); // assert size
T *array = new T[size_t(n)];
if (array) {
memset(array, 0xff, bytes);
(void) VALGRIND_MAKE_MEM_UNDEFINED(array, bytes);
}
return array;
}
#define New(type, n) (NewArray<type>(n))
#else
#define New(type, n) new type[mem_size_get_n(sizeof(type), n)]
#endif
/*************************************************************************
// ptr util
**************************************************************************/
// ptrdiff_t with nullptr checks and asserted size; will throw on failure
// NOTE: returns size_in_bytes, not number of elements!
int ptr_diff_bytes(const void *a, const void *b);
@@ -94,6 +112,30 @@ ptr_udiff(const T *a, const U *b) {
return ptr_udiff_bytes(a, b);
}
// check that buffers do not overlap; will throw on error
noinline void uintptr_check_no_overlap(upx_uintptr_t a, size_t a_size, upx_uintptr_t b,
size_t b_size);
noinline void uintptr_check_no_overlap(upx_uintptr_t a, size_t a_size, upx_uintptr_t b,
size_t b_size, upx_uintptr_t c, size_t c_size);
forceinline void ptr_check_no_overlap(const void *a, size_t a_size, const void *b, size_t b_size) {
uintptr_check_no_overlap((upx_uintptr_t) a, a_size, (upx_uintptr_t) b, b_size);
}
forceinline void ptr_check_no_overlap(const void *a, size_t a_size, const void *b, size_t b_size,
const void *c, size_t c_size) {
uintptr_check_no_overlap((upx_uintptr_t) a, a_size, (upx_uintptr_t) b, b_size,
(upx_uintptr_t) c, c_size);
}
/*************************************************************************
// stdlib
**************************************************************************/
void *upx_calloc(size_t n, size_t element_size);
void upx_stable_sort(void *base, size_t n, size_t element_size,
int(__acc_cdecl_qsort *compare)(const void *, const void *));
/*************************************************************************
// misc. support functions
**************************************************************************/
+7 -7
View File
@@ -44,28 +44,28 @@ struct XSpanStats {
static XSpanStats xspan_stats;
// HINT: set env-var "UPX_DEBUG_DOCTEST_DISABLE=1" for improved debugging experience
noinline void xspan_fail_nullptr() {
void xspan_fail_nullptr() {
xspan_stats.fail_nullptr += 1;
throwCantPack("xspan unexpected NULL pointer; take care!");
}
noinline void xspan_fail_nullbase() {
void xspan_fail_nullbase() {
xspan_stats.fail_nullbase += 1;
throwCantPack("xspan unexpected NULL base; take care!");
}
noinline void xspan_fail_not_same_base() {
void xspan_fail_not_same_base() {
xspan_stats.fail_not_same_base += 1;
throwCantPack("xspan unexpected base pointer; take care!");
}
noinline void xspan_fail_range_nullptr() {
void xspan_fail_range_nullptr() {
xspan_stats.fail_range_nullptr += 1;
throwCantPack("xspan_check_range: unexpected NULL pointer; take care!");
}
noinline void xspan_fail_range_nullbase() {
void xspan_fail_range_nullbase() {
xspan_stats.fail_range_nullbase += 1;
throwCantPack("xspan_check_range: unexpected NULL base; take care!");
}
noinline void xspan_fail_range_range() {
void xspan_fail_range_range() {
xspan_stats.fail_range_range += 1;
throwCantPack("xspan_check_range: pointer out of range; take care!");
}
@@ -75,7 +75,7 @@ void xspan_check_range(const void *p, const void *base, ptrdiff_t size_in_bytes)
xspan_fail_range_nullptr();
if very_unlikely (base == nullptr)
xspan_fail_range_nullbase();
ptrdiff_t off = (const char *) p - (const char *) base;
ptrdiff_t off = (const charptr) p - (const charptr) base;
if very_unlikely (off < 0 || off > size_in_bytes)
xspan_fail_range_range();
xspan_stats.check_range_counter += 1;
+4 -1
View File
@@ -146,8 +146,11 @@ inline R *xspan_make_helper__(R * /*dummy*/, MemBuffer &first) {
#endif // WITH_XSPAN
#if 1
/*************************************************************************
// nicer names
**************************************************************************/
#if 1
#define SPAN_0 XSPAN_0
#define SPAN_P XSPAN_P
#define SPAN_S XSPAN_S
+2 -2
View File
@@ -52,11 +52,11 @@ void xspan_check_range(const void *p, const void *base, ptrdiff_t size_in_bytes)
// help constructor to distinguish between number of elements and bytes
struct XSpanCount {
explicit XSpanCount(size_t n) : count(n) {}
explicit XSpanCount(size_t n) noexcept : count(n) {}
size_t count; // public
};
struct XSpanSizeInBytes {
explicit XSpanSizeInBytes(size_t bytes) : size_in_bytes(bytes) {}
explicit XSpanSizeInBytes(size_t bytes) noexcept : size_in_bytes(bytes) {}
size_t size_in_bytes; // public
};
+365 -334
View File
@@ -28,165 +28,176 @@
//
**************************************************************************/
public:
typedef T element_type;
typedef typename std::add_lvalue_reference<T>::type reference;
typedef typename std::add_pointer<T>::type pointer;
typedef size_t size_type;
#if CLANG_FORMAT_DUMMY_CLASS
class CSelf {
#endif
// befriend all
template <class>
friend struct PtrOrSpan;
template <class>
friend struct PtrOrSpanOrNull;
template <class>
friend struct Span;
public:
typedef T element_type;
typedef typename std::add_lvalue_reference<T>::type reference;
typedef typename std::add_pointer<T>::type pointer;
typedef size_t size_type;
// befriend all
template <class>
friend struct PtrOrSpan;
template <class>
friend struct PtrOrSpanOrNull;
template <class>
friend struct Span;
#if XSPAN_CONFIG_ENABLE_IMPLICIT_CONVERSION
operator pointer() const { return ptr; }
public:
operator pointer() const noexcept { return ptr; }
#endif
private:
pointer ptr; // current view into (base, base+size_in_bytes) iff base != nullptr
pointer base;
size_type size_in_bytes;
pointer ptr; // current view into (base, base+size_in_bytes) iff base != nullptr
pointer base;
size_type size_in_bytes;
// debug - internal sanity check; also serves as pseudo-documentation
#if DEBUG
noinline void assertInvariants() const {
if __acc_cte (configRequirePtr)
assert(ptr != nullptr);
if __acc_cte (configRequireBase)
assert(base != nullptr);
if __acc_cte ((configRequirePtr || ptr != nullptr) && (configRequireBase || base != nullptr))
xspan_check_range(ptr, base, size_in_bytes);
}
noinline void assertInvariants() const {
if __acc_cte (configRequirePtr)
assert(ptr != nullptr);
if __acc_cte (configRequireBase)
assert(base != nullptr);
if __acc_cte ((configRequirePtr || ptr != nullptr) &&
(configRequireBase || base != nullptr))
xspan_check_range(ptr, base, size_in_bytes);
}
#else
forceinline void assertInvariants() const {}
inline void assertInvariants() const noexcept {}
#endif
static forceinline pointer makeNotNull(pointer p) {
if very_unlikely (p == nullptr)
xspan_fail_nullptr();
return p;
}
// enforce config invariants at constructor time - static functions
static forceinline pointer makePtr(pointer p) {
if __acc_cte (configRequirePtr && p == nullptr)
xspan_fail_nullptr();
return p;
}
static forceinline pointer makeBase(pointer b) {
if __acc_cte (configRequireBase && b == nullptr)
xspan_fail_nullbase();
return b;
}
// inverse logic for ensuring valid pointers from existing objets
forceinline pointer ensurePtr() const {
if __acc_cte (!configRequirePtr && ptr == nullptr)
xspan_fail_nullptr();
return ptr;
}
forceinline pointer ensureBase() const {
if __acc_cte (!configRequireBase && base == nullptr)
xspan_fail_nullbase();
return base;
}
static inline pointer makeNotNull(pointer p) {
if very_unlikely (p == nullptr)
xspan_fail_nullptr();
return p;
}
// enforce config invariants at constructor time - static functions
static inline pointer makePtr(pointer p) {
if __acc_cte (configRequirePtr && p == nullptr)
xspan_fail_nullptr();
return p;
}
static inline pointer makeBase(pointer b) {
if __acc_cte (configRequireBase && b == nullptr)
xspan_fail_nullbase();
return b;
}
// inverse logic for ensuring valid pointers from existing objects
inline pointer ensurePtr() const {
if __acc_cte (!configRequirePtr && ptr == nullptr)
xspan_fail_nullptr();
return ptr;
}
inline pointer ensureBase() const {
if __acc_cte (!configRequireBase && base == nullptr)
xspan_fail_nullbase();
return base;
}
public:
inline ~CSelf() {
#if DEBUG
invalidate();
inline ~CSelf() { invalidate(); }
#else
inline ~CSelf() noexcept {}
#endif
}
noinline void invalidate() {
assertInvariants();
ptr = (pointer) (acc_uintptr_t) 16; // point to non-null invalid address
// ptr = (pointer) (void *) &ptr; // point to self
base = ptr;
size_in_bytes = 0;
assertInvariants();
}
// constructors from pointers
CSelf(pointer first, XSpanCount count)
: ptr(makePtr(first)), base(makeBase(first)), size_in_bytes(xspan_mem_size<T>(count.count)) {
assertInvariants();
}
CSelf(pointer first, XSpanSizeInBytes bytes)
: ptr(makePtr(first)), base(makeBase(first)),
size_in_bytes(xspan_mem_size<char>(bytes.size_in_bytes)) {
assertInvariants();
}
// enable this constructor only if the underlying type is char or void
template <class U>
CSelf(U *first, size_type count, XSPAN_REQUIRES_SIZE_1_A)
: ptr(makePtr(first)), base(makeBase(first)), size_in_bytes(xspan_mem_size<T>(count)) {
assertInvariants();
}
CSelf(pointer first, XSpanCount count, pointer base_)
: ptr(makePtr(first)), base(makeBase(base_)), size_in_bytes(xspan_mem_size<T>(count.count)) {
// check invariants
if __acc_cte ((configRequirePtr || ptr != nullptr) && (configRequireBase || base != nullptr))
xspan_check_range(ptr, base, size_in_bytes);
// double sanity check
assertInvariants();
}
CSelf(pointer first, XSpanSizeInBytes bytes, pointer base_)
: ptr(makePtr(first)), base(makeBase(base_)),
size_in_bytes(xspan_mem_size<char>(bytes.size_in_bytes)) {
// check invariants
if __acc_cte ((configRequirePtr || ptr != nullptr) && (configRequireBase || base != nullptr))
xspan_check_range(ptr, base, size_in_bytes);
// double sanity check
assertInvariants();
}
// enable this constructor only if the underlying type is char or void
template <class U>
CSelf(pointer first, size_type count, U *base_, XSPAN_REQUIRES_SIZE_1_A)
: ptr(makePtr(first)), base(makeBase(base_)), size_in_bytes(xspan_mem_size<T>(count)) {
// check invariants
if __acc_cte ((configRequirePtr || ptr != nullptr) && (configRequireBase || base != nullptr))
xspan_check_range(ptr, base, size_in_bytes);
// double sanity check
assertInvariants();
}
noinline void invalidate() {
assertInvariants();
ptr = (pointer) (upx_uintptr_t) 16; // point to non-null invalid address
// ptr = (pointer) (void *) &ptr; // point to self
base = ptr;
size_in_bytes = 0;
assertInvariants();
}
// constructors from pointers
CSelf(pointer first, XSpanCount count)
: ptr(makePtr(first)), base(makeBase(first)),
size_in_bytes(xspan_mem_size<T>(count.count)) {
assertInvariants();
}
CSelf(pointer first, XSpanSizeInBytes bytes)
: ptr(makePtr(first)), base(makeBase(first)),
size_in_bytes(xspan_mem_size<char>(bytes.size_in_bytes)) {
assertInvariants();
}
// enable this constructor only if the underlying type is char or void
template <class U>
CSelf(U *first, size_type count, XSPAN_REQUIRES_SIZE_1_A)
: ptr(makePtr(first)), base(makeBase(first)), size_in_bytes(xspan_mem_size<T>(count)) {
assertInvariants();
}
CSelf(pointer first, XSpanCount count, pointer base_)
: ptr(makePtr(first)), base(makeBase(base_)),
size_in_bytes(xspan_mem_size<T>(count.count)) {
// check invariants
if __acc_cte ((configRequirePtr || ptr != nullptr) &&
(configRequireBase || base != nullptr))
xspan_check_range(ptr, base, size_in_bytes);
// double sanity check
assertInvariants();
}
CSelf(pointer first, XSpanSizeInBytes bytes, pointer base_)
: ptr(makePtr(first)), base(makeBase(base_)),
size_in_bytes(xspan_mem_size<char>(bytes.size_in_bytes)) {
// check invariants
if __acc_cte ((configRequirePtr || ptr != nullptr) &&
(configRequireBase || base != nullptr))
xspan_check_range(ptr, base, size_in_bytes);
// double sanity check
assertInvariants();
}
// enable this constructor only if the underlying type is char or void
template <class U>
CSelf(pointer first, size_type count, U *base_, XSPAN_REQUIRES_SIZE_1_A)
: ptr(makePtr(first)), base(makeBase(base_)), size_in_bytes(xspan_mem_size<T>(count)) {
// check invariants
if __acc_cte ((configRequirePtr || ptr != nullptr) &&
(configRequireBase || base != nullptr))
xspan_check_range(ptr, base, size_in_bytes);
// double sanity check
assertInvariants();
}
#ifdef UPX_VERSION_HEX
// constructors from MemBuffer
CSelf(MemBuffer &mb)
: CSelf(makeNotNull((pointer) membuffer_get_void_ptr(mb)),
XSpanSizeInBytes(membuffer_get_size(mb))) {}
CSelf(pointer first, MemBuffer &mb)
: CSelf(first, XSpanSizeInBytes(membuffer_get_size(mb)),
makeNotNull((pointer) membuffer_get_void_ptr(mb))) {}
CSelf(std::nullptr_t, MemBuffer &) XSPAN_DELETED_FUNCTION;
// constructors from MemBuffer
CSelf(MemBuffer &mb)
: CSelf(makeNotNull((pointer) membuffer_get_void_ptr(mb)),
XSpanSizeInBytes(membuffer_get_size(mb))) {}
CSelf(pointer first, MemBuffer &mb)
: CSelf(first, XSpanSizeInBytes(membuffer_get_size(mb)),
makeNotNull((pointer) membuffer_get_void_ptr(mb))) {}
CSelf(std::nullptr_t, MemBuffer &) XSPAN_DELETED_FUNCTION;
#endif
// disable constructors from nullptr to catch compile-time misuse
// disable constructors from nullptr to catch compile-time misuse
private:
CSelf(std::nullptr_t, XSpanCount) XSPAN_DELETED_FUNCTION;
CSelf(std::nullptr_t, XSpanCount, std::nullptr_t) XSPAN_DELETED_FUNCTION;
CSelf(const void *, XSpanCount, std::nullptr_t) XSPAN_DELETED_FUNCTION;
CSelf(std::nullptr_t, XSpanSizeInBytes) XSPAN_DELETED_FUNCTION;
CSelf(std::nullptr_t, XSpanSizeInBytes, std::nullptr_t) XSPAN_DELETED_FUNCTION;
CSelf(const void *, XSpanSizeInBytes, std::nullptr_t) XSPAN_DELETED_FUNCTION;
CSelf(std::nullptr_t, size_type) XSPAN_DELETED_FUNCTION;
CSelf(std::nullptr_t, size_type, std::nullptr_t) XSPAN_DELETED_FUNCTION;
CSelf(const void *, size_type, std::nullptr_t) XSPAN_DELETED_FUNCTION;
CSelf(std::nullptr_t, XSpanCount) XSPAN_DELETED_FUNCTION;
CSelf(std::nullptr_t, XSpanCount, std::nullptr_t) XSPAN_DELETED_FUNCTION;
CSelf(const void *, XSpanCount, std::nullptr_t) XSPAN_DELETED_FUNCTION;
CSelf(std::nullptr_t, XSpanSizeInBytes) XSPAN_DELETED_FUNCTION;
CSelf(std::nullptr_t, XSpanSizeInBytes, std::nullptr_t) XSPAN_DELETED_FUNCTION;
CSelf(const void *, XSpanSizeInBytes, std::nullptr_t) XSPAN_DELETED_FUNCTION;
CSelf(std::nullptr_t, size_type) XSPAN_DELETED_FUNCTION;
CSelf(std::nullptr_t, size_type, std::nullptr_t) XSPAN_DELETED_FUNCTION;
CSelf(const void *, size_type, std::nullptr_t) XSPAN_DELETED_FUNCTION;
// unchecked constructor
// unchecked constructor
protected:
enum ModeUnchecked { Unchecked };
CSelf(ModeUnchecked, pointer p, size_type bytes, pointer b)
: ptr(p), base(b), size_in_bytes(bytes) {
assertInvariants();
}
// unchecked assignment
Self &assign(ModeUnchecked, pointer p, size_type bytes, pointer b) {
ptr = p;
base = b;
size_in_bytes = bytes;
assertInvariants();
return *this;
}
enum ModeUnchecked { Unchecked };
CSelf(ModeUnchecked, pointer p, size_type bytes, pointer b)
: ptr(p), base(b), size_in_bytes(bytes) {
assertInvariants();
}
// unchecked assignment
Self &assign(ModeUnchecked, pointer p, size_type bytes, pointer b) {
ptr = p;
base = b;
size_in_bytes = bytes;
assertInvariants();
return *this;
}
#if 0
Self &assign(ModeUnchecked, const Self &other) {
ptr = other.ptr;
@@ -198,230 +209,250 @@ Self &assign(ModeUnchecked, const Self &other) {
#endif
public:
// assignment - here we can rely on invariants enforced at construction time by makePtr/makeBase
// NOTE: *this remains unmodified in case of failure
Self &assign(pointer other) {
assertInvariants();
other = makePtr(other);
if __acc_cte ((configRequirePtr || other != nullptr) && (configRequireBase || base != nullptr))
xspan_check_range(other, base, size_in_bytes);
// ok
ptr = other;
assertInvariants();
return *this;
}
Self &assign(const Self &other) {
assertInvariants();
other.assertInvariants();
if __acc_cte (!configRequireBase && base == nullptr) {
// magic 1: if base is unset, automatically set base/size_in_bytes from other
if __acc_cte ((configRequirePtr || other.ptr != nullptr) &&
(configRequireBase || other.base != nullptr))
xspan_check_range(other.ptr, other.base, other.size_in_bytes);
// ok
ptr = other.ptr;
base = other.base;
size_in_bytes = other.size_in_bytes;
} else {
// magic 2: assert same base (but ignore size_in_bytes !)
if __acc_cte (configRequireBase || other.base != nullptr)
if very_unlikely (base != other.base)
xspan_fail_not_same_base();
if __acc_cte ((configRequirePtr || other.ptr != nullptr) &&
// assignment - here we can rely on invariants enforced at construction time by makePtr/makeBase
// NOTE: *this remains unmodified in case of failure
Self &assign(pointer other) {
assertInvariants();
other = makePtr(other);
if __acc_cte ((configRequirePtr || other != nullptr) &&
(configRequireBase || base != nullptr))
xspan_check_range(other.ptr, base, size_in_bytes);
xspan_check_range(other, base, size_in_bytes);
// ok
ptr = other.ptr;
ptr = other;
assertInvariants();
return *this;
}
Self &assign(const Self &other) {
assertInvariants();
other.assertInvariants();
if __acc_cte (!configRequireBase && base == nullptr) {
// magic 1: if base is unset, automatically set base/size_in_bytes from other
if __acc_cte ((configRequirePtr || other.ptr != nullptr) &&
(configRequireBase || other.base != nullptr))
xspan_check_range(other.ptr, other.base, other.size_in_bytes);
// ok
ptr = other.ptr;
base = other.base;
size_in_bytes = other.size_in_bytes;
} else {
// magic 2: assert same base (but ignore size_in_bytes !)
if __acc_cte (configRequireBase || other.base != nullptr)
if very_unlikely (base != other.base)
xspan_fail_not_same_base();
if __acc_cte ((configRequirePtr || other.ptr != nullptr) &&
(configRequireBase || base != nullptr))
xspan_check_range(other.ptr, base, size_in_bytes);
// ok
ptr = other.ptr;
}
assertInvariants();
return *this;
}
assertInvariants();
return *this;
}
Self &operator=(pointer other) { return assign(other); }
Self &operator=(pointer other) { return assign(other); }
Self &operator=(const Self &other) { return assign(other); }
Self &operator=(const Self &other) { return assign(other); }
// FIXME: this is not called??
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(Self &)
operator=(const CSelf<U> &other) {
// assert(0);
return assign(Self(other));
}
// FIXME: this is not called??
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(Self &)
operator=(const CSelf<U> &other) {
// assert(0);
return assign(Self(other));
}
#ifdef UPX_VERSION_HEX
Self &operator=(MemBuffer &mb) { return assign(Self(mb)); }
Self &operator=(MemBuffer &mb) { return assign(Self(mb)); }
#endif
Self subspan(ptrdiff_t offset, ptrdiff_t count) {
pointer begin = check_add(ptr, offset);
pointer end = check_add(begin, count);
if (begin <= end)
return Self(Unchecked, begin, (end - begin) * sizeof(T), begin);
else
return Self(Unchecked, end, (begin - end) * sizeof(T), end);
}
Self subspan(ptrdiff_t offset, ptrdiff_t count) {
pointer begin = check_add(ptr, offset);
pointer end = check_add(begin, count);
if (begin <= end)
return Self(Unchecked, begin, (end - begin) * sizeof(T), begin);
else
return Self(Unchecked, end, (begin - end) * sizeof(T), end);
}
bool operator==(pointer other) const { return ptr == other; }
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(U *other) const {
return ptr == other;
}
bool operator!=(pointer other) const { return ptr != other; }
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator!=(U *other) const {
return ptr != other;
}
bool operator==(pointer other) const { return ptr == other; }
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(U *other) const {
return ptr == other;
}
bool operator!=(pointer other) const { return ptr != other; }
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator!=(U *other) const {
return ptr != other;
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(const PtrOrSpan<U> &other) const {
return ptr == other.ptr;
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(const PtrOrSpanOrNull<U> &other) const {
return ptr == other.ptr;
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(const Span<U> &other) const {
return ptr == other.ptr;
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(const PtrOrSpan<U> &other) const {
return ptr == other.ptr;
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(const PtrOrSpanOrNull<U> &other) const {
return ptr == other.ptr;
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(const Span<U> &other) const {
return ptr == other.ptr;
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator!=(const PtrOrSpan<U> &other) const {
return !(*this == other);
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator!=(const PtrOrSpanOrNull<U> &other) const {
return !(*this == other);
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator!=(const Span<U> &other) const {
return !(*this == other);
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator!=(const PtrOrSpan<U> &other) const {
return !(*this == other);
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator!=(const PtrOrSpanOrNull<U> &other) const {
return !(*this == other);
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator!=(const Span<U> &other) const {
return !(*this == other);
}
// check for notNull here
bool operator<(std::nullptr_t) const XSPAN_DELETED_FUNCTION;
bool operator<(pointer other) const { return ensurePtr() < makeNotNull(other); }
// check for notNull here
bool operator<(std::nullptr_t) const XSPAN_DELETED_FUNCTION;
bool operator<(pointer other) const { return ensurePtr() < makeNotNull(other); }
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator<(const PtrOrSpan<U> &other) const {
return ensurePtr() < other.ensurePtr();
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator<(const PtrOrSpanOrNull<U> &other) const {
return ensurePtr() < other.ensurePtr();
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator<(const Span<U> &other) const {
return ensurePtr() < other.ensurePtr();
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator<(const PtrOrSpan<U> &other) const {
return ensurePtr() < other.ensurePtr();
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator<(const PtrOrSpanOrNull<U> &other) const {
return ensurePtr() < other.ensurePtr();
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator<(const Span<U> &other) const {
return ensurePtr() < other.ensurePtr();
}
// dereference
reference operator*() const { return *check_deref(ptr); }
// dereference
reference operator*() const { return *check_deref(ptr); }
// array access
reference operator[](ptrdiff_t i) const { return *check_deref(ptr, i); }
// array access
reference operator[](ptrdiff_t i) const { return *check_deref(ptr, i); }
// arrow operator
pointer operator->() const { return check_deref(ptr); }
// arrow operator
pointer operator->() const { return check_deref(ptr); }
Self &operator++() {
ptr = check_add(ptr, 1);
return *this;
}
Self operator++(int) {
Self tmp = *this;
++*this;
return tmp;
}
Self &operator--() {
ptr = check_add(ptr, -1);
return *this;
}
Self operator--(int) {
Self tmp = *this;
--*this;
return tmp;
}
Self &operator++() {
ptr = check_add(ptr, 1);
return *this;
}
Self operator++(int) {
Self tmp = *this;
++*this;
return tmp;
}
Self &operator--() {
ptr = check_add(ptr, -1);
return *this;
}
Self operator--(int) {
Self tmp = *this;
--*this;
return tmp;
}
Self &operator+=(ptrdiff_t n) {
ptr = check_add(ptr, n);
return *this;
}
Self &operator-=(ptrdiff_t n) {
ptr = check_add(ptr, -n);
return *this;
}
Self &operator+=(ptrdiff_t n) {
ptr = check_add(ptr, n);
return *this;
}
Self &operator-=(ptrdiff_t n) {
ptr = check_add(ptr, -n);
return *this;
}
Self operator+(ptrdiff_t n) const {
pointer first = check_add(ptr, n);
return Self(Unchecked, first, size_in_bytes, base);
}
Self operator-(ptrdiff_t n) const {
pointer first = check_add(ptr, -n);
return Self(Unchecked, first, size_in_bytes, base);
}
Self operator+(ptrdiff_t n) const {
pointer first = check_add(ptr, n);
return Self(Unchecked, first, size_in_bytes, base);
}
Self operator-(ptrdiff_t n) const {
pointer first = check_add(ptr, -n);
return Self(Unchecked, first, size_in_bytes, base);
}
private:
pointer check_deref(pointer p) const {
if __acc_cte (!configRequirePtr && p == nullptr)
xspan_fail_nullptr();
if __acc_cte (configRequireBase || base != nullptr)
xspan_check_range(p, base, size_in_bytes - sizeof(T));
assertInvariants();
return p;
}
pointer check_deref(pointer p, ptrdiff_t n) const {
if __acc_cte (!configRequirePtr && p == nullptr)
xspan_fail_nullptr();
xspan_mem_size_assert_ptrdiff<T>(n);
p += n;
if __acc_cte (configRequireBase || base != nullptr)
xspan_check_range(p, base, size_in_bytes - sizeof(T));
assertInvariants();
return p;
}
pointer check_add(pointer p, ptrdiff_t n) const {
if __acc_cte (!configRequirePtr && p == nullptr)
xspan_fail_nullptr();
xspan_mem_size_assert_ptrdiff<T>(n);
p += n;
if __acc_cte (configRequireBase || base != nullptr)
xspan_check_range(p, base, size_in_bytes);
assertInvariants();
return p;
}
pointer check_deref(pointer p) const {
if __acc_cte (!configRequirePtr && p == nullptr)
xspan_fail_nullptr();
if __acc_cte (configRequireBase || base != nullptr)
xspan_check_range(p, base, size_in_bytes - sizeof(T));
assertInvariants();
return p;
}
pointer check_deref(pointer p, ptrdiff_t n) const {
if __acc_cte (!configRequirePtr && p == nullptr)
xspan_fail_nullptr();
xspan_mem_size_assert_ptrdiff<T>(n);
p += n;
if __acc_cte (configRequireBase || base != nullptr)
xspan_check_range(p, base, size_in_bytes - sizeof(T));
assertInvariants();
return p;
}
pointer check_add(pointer p, ptrdiff_t n) const {
if __acc_cte (!configRequirePtr && p == nullptr)
xspan_fail_nullptr();
xspan_mem_size_assert_ptrdiff<T>(n);
p += n;
if __acc_cte (configRequireBase || base != nullptr)
xspan_check_range(p, base, size_in_bytes);
assertInvariants();
return p;
}
// disable taking the address => force passing by reference
// [I'm not too sure about this design decision, but we can always allow it if needed]
Self *operator&() const XSPAN_DELETED_FUNCTION;
// disable taking the address => force passing by reference
// [I'm not too sure about this design decision, but we can always allow it if needed]
Self *operator&() const XSPAN_DELETED_FUNCTION;
public: // raw access
pointer raw_ptr() const { return ptr; }
pointer raw_base() const { return base; }
size_type raw_size_in_bytes() const { return size_in_bytes; }
pointer raw_ptr() const noexcept { return ptr; }
pointer raw_base() const noexcept { return base; }
size_type raw_size_in_bytes() const noexcept { return size_in_bytes; }
pointer raw_bytes(size_t bytes) const {
assertInvariants();
if (bytes > 0) {
if __acc_cte (!configRequirePtr && ptr == nullptr)
xspan_fail_nullptr();
if __acc_cte (configRequireBase || base != nullptr) {
xspan_check_range(ptr, base, size_in_bytes - bytes);
pointer raw_bytes(size_t bytes) const {
assertInvariants();
if (bytes > 0) {
if __acc_cte (!configRequirePtr && ptr == nullptr)
xspan_fail_nullptr();
if __acc_cte (configRequireBase || base != nullptr) {
xspan_check_range(ptr, base, size_in_bytes - bytes);
}
}
return ptr;
}
return ptr;
}
// like C++ std::span
pointer data() const noexcept { return ptr; }
pointer data(size_t bytes) const { return raw_bytes(bytes); } // UPX extra
// size_type size() const { return size_bytes() / sizeof(element_type); } // NOT USED
size_type size_bytes() const {
assertInvariants();
if __acc_cte (!configRequirePtr && ptr == nullptr)
return 0;
if __acc_cte (!configRequireBase && base == nullptr)
return 0;
const charptr begin = (const charptr) ptr;
const charptr end = (const charptr) base + size_in_bytes;
return end - begin;
}
#if CLANG_FORMAT_DUMMY_CLASS
}; // class
#endif
/* vim:set ts=4 sw=4 et: */
+11 -11
View File
@@ -51,25 +51,25 @@ private:
pointer ptr;
// enforce config invariants at constructor time - static functions
static forceinline pointer makePtr(pointer p) { return p; }
// inverse logic for ensuring valid pointers from existing objets
forceinline pointer ensurePtr() const { return ptr; }
static inline pointer makePtr(pointer p) { return p; }
// inverse logic for ensuring valid pointers from existing objects
inline pointer ensurePtr() const { return ptr; }
// debug
forceinline void assertInvariants() const {}
inline void assertInvariants() const noexcept {}
public:
#if XSPAN_CONFIG_ENABLE_IMPLICIT_CONVERSION || 1
operator pointer() const { return ptr; }
operator pointer() const noexcept { return ptr; }
#endif
inline ~CSelf() {
#if DEBUG
invalidate();
inline ~CSelf() { invalidate(); }
#else
inline ~CSelf() noexcept {}
#endif
}
noinline void invalidate() {
assertInvariants();
ptr = (pointer) (acc_uintptr_t) 16; // point to non-null invalid address
ptr = (pointer) (upx_uintptr_t) 16; // point to non-null invalid address
// ptr = (pointer) (void *) &ptr; // point to self
assertInvariants();
}
@@ -116,7 +116,7 @@ public:
return assign(Self(other));
}
// comparision
// comparison
bool operator==(pointer other) const { return ptr == other; }
template <class U>
@@ -187,7 +187,7 @@ private:
forceinline pointer check_add(pointer p, ptrdiff_t n) const { return p + n; }
public: // raw access
pointer raw_ptr() const { return ptr; }
pointer raw_ptr() const noexcept { return ptr; }
pointer raw_bytes(size_t bytes) const {
assertInvariants();