6 #ifndef XENIUM_MARKED_PTR_HPP
7 #define XENIUM_MARKED_PTR_HPP
9 #include <xenium/utils.hpp>
15 #ifndef XENIUM_MAX_UPPER_MARK_BITS
16 #define XENIUM_MAX_UPPER_MARK_BITS 16
22 #pragma warning(disable : 4127) // conditional expression is constant
23 #pragma warning(disable : 4293) // shift count negative or too big
40 template <
class T, u
intptr_t MarkBits, u
intptr_t MaxUpperMarkBits = XENIUM_MAX_UPPER_MARK_BITS>
42 static_assert(MarkBits > 0,
"should never happen - compiler should pick the specilization for zero MarkBits!");
43 static constexpr uintptr_t pointer_bits =
sizeof(T*) * 8 - MarkBits;
44 static constexpr uintptr_t MarkMask = (
static_cast<uintptr_t
>(1) << MarkBits) - 1;
46 static constexpr uintptr_t lower_mark_bits = MarkBits < MaxUpperMarkBits ? 0 : MarkBits - MaxUpperMarkBits;
47 static constexpr uintptr_t upper_mark_bits = MarkBits - lower_mark_bits;
48 static constexpr uintptr_t pointer_mask = ((
static_cast<uintptr_t
>(1) << pointer_bits) - 1) << lower_mark_bits;
51 static constexpr uintptr_t number_of_mark_bits = MarkBits;
52 static_assert(MarkBits <= 32,
"MarkBits must not be greater than 32.");
53 static_assert(
sizeof(T*) == 8,
"marked_ptr requires 64bit pointers.");
65 void reset() noexcept { _ptr =
nullptr; }
70 [[nodiscard]] uintptr_t
mark() const noexcept {
71 return utils::rotate<lower_mark_bits>::right(
reinterpret_cast<uintptr_t
>(_ptr)) >> pointer_bits;
77 [[nodiscard]] T*
get() const noexcept {
78 auto ip =
reinterpret_cast<uintptr_t
>(_ptr);
79 if constexpr (number_of_mark_bits != 0) {
82 return reinterpret_cast<T*
>(ip);
88 explicit operator bool() const noexcept {
return _ptr !=
nullptr; }
100 inline friend bool operator==(
const marked_ptr& l,
const marked_ptr& r) {
return l._ptr == r._ptr; }
101 inline friend bool operator!=(
const marked_ptr& l,
const marked_ptr& r) {
return l._ptr != r._ptr; }
104 T* make_ptr(T* p, uintptr_t
mark) noexcept {
105 assert((
reinterpret_cast<uintptr_t
>(p) & ~pointer_mask) == 0 &&
106 "bits reserved for masking are occupied by the pointer");
108 auto ip =
reinterpret_cast<uintptr_t
>(p);
109 if constexpr (number_of_mark_bits == 0) {
113 mark = utils::rotate<lower_mark_bits>::left(
mark << pointer_bits);
114 return reinterpret_cast<T*
>(ip |
mark);
122 enum Masking { MarkMask_ = MarkMask };
127 template <
class T, u
intptr_t MaxUpperMarkBits>
128 class marked_ptr<T, 0, MaxUpperMarkBits> {
130 static constexpr uintptr_t number_of_mark_bits = 0;
135 marked_ptr(T* p =
nullptr) noexcept { _ptr = p; }
140 void reset() noexcept { _ptr =
nullptr; }
145 [[nodiscard]] uintptr_t
mark() const noexcept {
return 0; }
150 [[nodiscard]] T*
get() const noexcept {
return _ptr; }
155 explicit operator bool() const noexcept {
return _ptr !=
nullptr; }
167 inline friend bool operator==(
const marked_ptr& l,
const marked_ptr& r) {
return l._ptr == r._ptr; }
168 inline friend bool operator!=(
const marked_ptr& l,
const marked_ptr& r) {
return l._ptr != r._ptr; }