#pragma once #include constexpr std::size_t log2(std::size_t n) { return ((n < 2) ? 0 : 1 + log2(n >> 1)); } template struct PointerPackTraits { // here is a place to embed something like platform specific things // TODO: cover more cases constexpr static int free_bits = log2(alignof(PtrT)); static auto get_ptr(uintptr_t value) { return (PtrT)(value); } }; template > class PtrInt { private: constexpr static int int_shift = PtrTraits::free_bits - IntBits; constexpr static uintptr_t ptr_mask = ~(uintptr_t)(((intptr_t)1 << PtrTraits::free_bits) - 1); constexpr static uintptr_t int_mask = (uintptr_t)(((intptr_t)1 << IntBits) - 1); uintptr_t value{0}; public: PtrInt(PtrT pointer, IntT integer) { set_ptr(pointer); set_int(integer); } auto set_ptr(PtrT pointer) { auto integer = static_cast(get_int()); auto ptr = reinterpret_cast(pointer); value = (ptr_mask & ptr) | (integer << int_shift); } auto set_int(IntT integer) { auto ptr = reinterpret_cast(get_ptr()); auto int_shifted = static_cast(integer << int_shift); value = (int_mask & int_shifted) | ptr; } auto get_ptr() const { return PtrTraits::get_ptr(value & ptr_mask); } auto get_int() const { return (IntT)((value >> int_shift) & int_mask); } };