KTL
Loading...
Searching...
No Matches
packed_ptr.h
Go to the documentation of this file.
1#pragma once
2
3#include "../utility/assert.h"
4#include "../utility/bits.h"
5#include "packed_ptr_fwd.h"
6
7#include <type_traits>
8
9namespace ktl
10{
16 template<typename PtrT, typename IntT, IntT Min, IntT Max, size_t Alignment>
18 {
19 public:
20 using ptr_type = PtrT;
22
23 static constexpr uintmax_t UsedBits = detail::bits_in_range(static_cast<int64_t>(Min), static_cast<int64_t>(Max));
24 static constexpr uintmax_t FreeBits = detail::log2(Alignment);
25
26 private:
27 static_assert(!std::is_const_v<PtrT>, "Pointer type cannot be const");
28 static_assert(!std::is_const_v<IntT>, "Integer type cannot be const");
29 static_assert(std::is_pointer_v<PtrT>, "Type must be a pointer");
30 static_assert(UsedBits <= FreeBits, "The number of bits in use cannot surpass the number of free bits");
31 static_assert(std::is_integral_v<IntT> || std::is_enum_v<IntT>, "The packed type must be an integer, bool or enum");
32
33 static constexpr uintptr_t INT_MASK = (1ULL << UsedBits) - 1ULL;
34 static constexpr uintptr_t PTR_MASK = ~((1ULL << FreeBits) - 1ULL);
35 static constexpr uintptr_t SIGNED_INT_MIN = 1ULL << (UsedBits - 1ULL);
36
37 public:
38 packed_ptr() noexcept :
39 m_Value(reinterpret_cast<uintptr_t>(nullptr)) {}
40
41 packed_ptr(PtrT p, IntT value) noexcept :
42 m_Value(from_ptr(p) | from_int(value))
43 {
44 // Pointer must be correctly aligned
45 KTL_ASSERT((reinterpret_cast<size_t>(p) & (Alignment - 1)) == 0);
46
47 // Integer must be between min and max
48 KTL_ASSERT(value >= Min && value <= Max);
49 }
50
51 packed_ptr(PtrT p) noexcept :
52 m_Value(from_ptr(p))
53 {
54 // Pointer must be correctly aligned
55 KTL_ASSERT((reinterpret_cast<size_t>(p) & (Alignment - 1)) == 0);
56 }
57
58 packed_ptr(IntT value) noexcept :
59 m_Value(from_int(value))
60 {
61 // Integer must be between min and max
62 KTL_ASSERT(value >= Min && value <= Max);
63 }
64
65#ifndef KTL_EXPLICIT_POINTER
66 packed_ptr& operator=(PtrT p) noexcept
67 {
68 set_ptr(p);
69 return *this;
70 }
71
72 packed_ptr& operator=(IntT value) noexcept
73 {
74 set_int(value);
75 return *this;
76 }
77
78 friend bool operator==(packed_ptr pack, PtrT p) noexcept { return pack.get_ptr() == p; }
79
80 friend bool operator==(packed_ptr pack, IntT n) noexcept { return pack.get_int() == n; }
81
82 friend bool operator==(PtrT p, packed_ptr pack) noexcept { return pack.get_ptr() == p; }
83
84 friend bool operator==(IntT n, packed_ptr pack) noexcept { return pack.get_int() == n; }
85
86 template<typename Y = IntT, typename = std::enable_if_t<!std::is_same_v<Y, bool>, Y>>
87 operator ptr_type() const noexcept { return get_ptr(); }
88
89 template<typename Y = IntT, typename = std::enable_if_t<!std::is_same_v<Y, bool>, Y>>
90 operator IntT() const noexcept { return get_int(); }
91
92 explicit operator bool() const noexcept { return get_ptr(); }
93#endif // KTL_EXPLICIT_POINTER
94
95 ptr_type operator->() const noexcept { return get_ptr(); }
96
97 decltype(*std::declval<PtrT>()) operator*() const noexcept { return *get_ptr(); }
98
99 template<typename... Ts>
100 decltype(auto) operator()(Ts&&... args) const noexcept { return get_ptr()(std::forward<Ts>(args) ...); }
101
102 ptr_type get_ptr() const noexcept { return to_ptr(m_Value); }
103
104 IntT get_int() const noexcept { return to_int(m_Value); }
105
106 void set_ptr(PtrT p) noexcept
107 {
108 // Pointer must be correctly aligned
109 KTL_ASSERT((reinterpret_cast<size_t>(p) & (Alignment - 1)) == 0);
110
111 m_Value = from_ptr(p) | (m_Value & INT_MASK);
112 }
113
114 void set_int(IntT value) noexcept
115 {
116 // Integer must be between min and max
117 KTL_ASSERT(value >= Min && value <= Max);
118
119 m_Value = (m_Value & PTR_MASK) | from_int(value);
120 }
121
122 private:
123 ptr_type to_ptr(uintptr_t value) const noexcept
124 {
125 return reinterpret_cast<ptr_type>(value & PTR_MASK);
126 }
127
128 uintptr_t from_ptr(PtrT value) const noexcept
129 {
130 return reinterpret_cast<uintptr_t>(value) & PTR_MASK;
131 }
132
133 IntT to_int(uintptr_t value) const noexcept
134 {
135 return static_cast<IntT>(static_cast<int_type>(value & INT_MASK) + static_cast<int_type>(Min));
136 }
137
138 uintptr_t from_int(IntT value) const noexcept
139 {
140 return static_cast<uintptr_t>(static_cast<int_type>(value) - static_cast<int_type>(Min)) & INT_MASK;
141 }
142
143 private:
144 uintptr_t m_Value;
145 };
146}
#define KTL_ASSERT(x)
Definition assert.h:17
A packed pointer-like type which takes advantage of any bits that don't get used due to alignment.
Definition packed_ptr.h:18
ptr_type get_ptr() const noexcept
Definition packed_ptr.h:102
IntT get_int() const noexcept
Definition packed_ptr.h:104
friend bool operator==(IntT n, packed_ptr pack) noexcept
Definition packed_ptr.h:84
friend bool operator==(packed_ptr pack, PtrT p) noexcept
Definition packed_ptr.h:78
packed_ptr(PtrT p, IntT value) noexcept
Definition packed_ptr.h:41
static constexpr uintmax_t UsedBits
Definition packed_ptr.h:23
static constexpr uintmax_t FreeBits
Definition packed_ptr.h:24
packed_ptr(PtrT p) noexcept
Definition packed_ptr.h:51
PtrT ptr_type
Definition packed_ptr.h:20
friend bool operator==(packed_ptr pack, IntT n) noexcept
Definition packed_ptr.h:80
packed_ptr() noexcept
Definition packed_ptr.h:38
friend bool operator==(PtrT p, packed_ptr pack) noexcept
Definition packed_ptr.h:82
void set_int(IntT value) noexcept
Definition packed_ptr.h:114
packed_ptr(IntT value) noexcept
Definition packed_ptr.h:58
void set_ptr(PtrT p) noexcept
Definition packed_ptr.h:106
packed_ptr & operator=(PtrT p) noexcept
Definition packed_ptr.h:66
detail::underlying_type_t< IntT > int_type
Definition packed_ptr.h:21
packed_ptr & operator=(IntT value) noexcept
Definition packed_ptr.h:72
ptr_type operator->() const noexcept
Definition packed_ptr.h:95
typename underlying_type< T >::type underlying_type_t
Definition packed_ptr_fwd.h:62
constexpr uintmax_t bits_in_range(intmax_t min, intmax_t max) noexcept
Definition bits.h:35
constexpr uintmax_t log2(uintmax_t n) noexcept
Definition bits.h:7
Definition cascading.h:16