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)
23#pragma warning(disable: 4293)
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 uintptr_t
mark() const noexcept {
71 return utils::rotate<lower_mark_bits>::right(
reinterpret_cast<uintptr_t
>(ptr)) >> pointer_bits;
77 T*
get() const noexcept {
78 auto ip =
reinterpret_cast<uintptr_t
>(ptr);
79 if constexpr(number_of_mark_bits != 0)
81 return reinterpret_cast<T*
>(ip);
87 explicit operator bool() const noexcept {
return ptr !=
nullptr; }
99 inline friend bool operator==(
const marked_ptr& l,
const marked_ptr& r) {
return l.ptr == r.ptr; }
100 inline friend bool operator!=(
const marked_ptr& l,
const marked_ptr& r) {
return l.ptr != r.ptr; }
103 T* make_ptr(T* p, uintptr_t
mark)
noexcept {
104 assert((
reinterpret_cast<uintptr_t
>(p) & ~pointer_mask) == 0 &&
105 "bits reserved for masking are occupied by the pointer");
107 uintptr_t ip =
reinterpret_cast<uintptr_t
>(p);
108 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;
142 void reset() noexcept { ptr =
nullptr; }
147 uintptr_t
mark() const noexcept {
return 0; }
152 T*
get() const noexcept {
return ptr; }
157 explicit operator bool() const noexcept {
return ptr !=
nullptr; }
169 inline friend bool operator==(
const marked_ptr& l,
const marked_ptr& r) {
return l.ptr == r.ptr; }
170 inline friend bool operator!=(
const marked_ptr& l,
const marked_ptr& r) {
return l.ptr != r.ptr; }
A pointer with an embedded mark/tag value.
Definition: marked_ptr.hpp:41
T * get() const noexcept
Get underlying pointer (with mark bits stripped off).
Definition: marked_ptr.hpp:77
T & operator*() const noexcept
Get reference to target of pointer.
Definition: marked_ptr.hpp:97
marked_ptr(T *p=nullptr, uintptr_t mark=0) noexcept
Construct a marked ptr with an optional mark value.
Definition: marked_ptr.hpp:60
uintptr_t mark() const noexcept
Get the mark value.
Definition: marked_ptr.hpp:70
T * operator->() const noexcept
Get pointer with mark bits stripped off.
Definition: marked_ptr.hpp:92
void reset() noexcept
Reset the pointer to nullptr and the mark to 0.
Definition: marked_ptr.hpp:65