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; }