upx/src/util/xspan_impl_ptr.h
2022-11-08 23:05:34 +01:00

221 lines
5.9 KiB
C++

/* xspan -- a minimally invasive checked memory smart pointer
This file is part of the UPX executable compressor.
Copyright (C) 1996-2022 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
SPAN_NAMESPACE_BEGIN
/*************************************************************************
// Ptr
**************************************************************************/
template <class T>
struct Ptr {
private:
#define CSelf Ptr
typedef CSelf<T> Self;
public:
// befriend all
template <class>
friend struct CSelf;
typedef T element_type;
typedef typename std::add_lvalue_reference<T>::type reference;
typedef typename std::add_pointer<T>::type pointer;
private:
pointer ptr;
// enforce config invariants at constructor time - static functions
static __acc_forceinline pointer makePtr(pointer p) { return p; }
// inverse logic for ensuring valid pointers from existing objets
__acc_forceinline pointer ensurePtr() const { return ptr; }
// debug
__acc_forceinline void assertInvariants() const {}
public:
#if SPAN_CONFIG_ENABLE_IMPLICIT_CONVERSION || 1
operator pointer() const { return ptr; }
#endif
inline ~CSelf() {}
inline CSelf() { assertInvariants(); }
// constructors from pointers
CSelf(pointer p) : ptr(makePtr(p)) { assertInvariants(); }
template <class U>
CSelf(U *p, SPAN_REQUIRES_CONVERTIBLE_A) : ptr(makePtr(p)) {
assertInvariants();
}
// constructors
CSelf(const Self &other) : ptr(other.ptr) { assertInvariants(); }
template <class U>
CSelf(const CSelf<U> &other, SPAN_REQUIRES_CONVERTIBLE_A) : ptr(other.ptr) {
assertInvariants();
}
Self &assign(const Self &other) {
assertInvariants();
other.assertInvariants();
ptr = other.ptr;
assertInvariants();
return *this;
}
// assignment
Self &operator=(const Self &other) { return assign(other); }
// FIXME: this is not called !!
template <class U>
SPAN_REQUIRES_CONVERTIBLE_R(Self &)
operator=(U *other) {
// assert(0);
return assign(Self(other));
}
// FIXME: this is not called !!
template <class U>
SPAN_REQUIRES_CONVERTIBLE_R(Self &)
operator=(const CSelf<U> &other) {
// assert(0);
return assign(Self(other));
}
// comparision
bool operator==(pointer other) const { return ptr == other; }
template <class U>
SPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(U *other) const {
return ptr == other;
}
template <class U>
SPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(const Ptr<U> &other) const {
return ptr == other.ptr;
}
// dereference
reference operator*() const { return *check_deref(ptr); }
// array access
reference operator[](ptrdiff_t i) const { return *check_deref(ptr, i); }
// 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+=(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 p = check_add(ptr, n);
return Self(p);
}
Self operator-(ptrdiff_t n) const {
pointer p = check_add(ptr, -n);
return Self(p);
}
#ifdef UPX_VERSION_HEX
CSelf(MemBuffer &mb) : ptr((pointer) membuffer_get_void_ptr(mb)) {}
Self &operator=(MemBuffer &mb) { return assign(Self(mb)); }
#endif
private:
__acc_forceinline pointer check_deref(pointer p) const { return p; }
__acc_forceinline pointer check_deref(pointer p, ptrdiff_t n) const { return p + n; }
__acc_forceinline pointer check_add(pointer p, ptrdiff_t n) const { return p + n; }
public: // raw access
pointer raw_ptr() const { return ptr; }
pointer raw_bytes(size_t bytes) const {
assertInvariants();
if (bytes > 0) {
if __acc_cte (ptr == nullptr)
span_fail_nullptr();
}
return ptr;
}
#undef CSelf
};
// raw_bytes overload
template <class T>
inline typename Ptr<T>::pointer raw_bytes(const Ptr<T> &a, size_t size_in_bytes) {
return a.raw_bytes(size_in_bytes);
}
template <class T>
inline typename Ptr<T>::pointer raw_index_bytes(const Ptr<T> &a, size_t index,
size_t size_in_bytes) {
typedef typename Ptr<T>::element_type element_type;
return raw_bytes(a, mem_size(sizeof(element_type), index, size_in_bytes)) + index;
}
/*************************************************************************
//
**************************************************************************/
SPAN_NAMESPACE_END
#if 1
#define C SPAN_NS(Ptr)
#include "xspan_fwd.h"
#undef C
#endif
/* vim:set ts=4 sw=4 et: */