-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
151 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
#pragma once | ||
|
||
#include "../utility/assert.h" | ||
#include "../utility/bits.h" | ||
#include "packed_ptr_fwd.h" | ||
|
||
#include <type_traits> | ||
|
||
namespace ktl | ||
{ | ||
/** | ||
* @brief A packed pointer-like type which takes advantage of any bits that don't get used due to alignment | ||
* @tparam PtrT The pointer type to use | ||
*/ | ||
template<typename PtrT, size_t Bits, size_t Alignment> | ||
class packed_ptr | ||
{ | ||
public: | ||
static constexpr uintmax_t FREE_BITS = detail::log2(Alignment); | ||
|
||
private: | ||
static_assert(Bits <= FREE_BITS, "The number of bits in use cannot surpass the number of free bits"); | ||
|
||
static constexpr uintptr_t INT_MASK = ((1ULL << Bits) - 1); | ||
static constexpr uintptr_t PTR_MASK = ~((1ULL << FREE_BITS) - 1); | ||
|
||
public: | ||
packed_ptr() noexcept : | ||
m_Value(reinterpret_cast<uintptr_t>(nullptr)) {} | ||
|
||
template<typename Int> | ||
explicit packed_ptr(PtrT p, Int value) noexcept : | ||
m_Value((reinterpret_cast<uintptr_t>(p) & PTR_MASK) | (static_cast<uintptr_t>(value) & INT_MASK)) | ||
{ | ||
// Pointer must be correctly aligned | ||
KTL_ASSERT((reinterpret_cast<size_t>(p) & (Alignment - 1)) == 0); | ||
} | ||
|
||
operator bool() const noexcept { return m_Value; } | ||
|
||
PtrT get_ptr() const noexcept { return reinterpret_cast<PtrT>(m_Value & PTR_MASK); } | ||
|
||
template<typename Int> | ||
Int get_int() const noexcept | ||
{ | ||
static_assert(std::is_unsigned_v<Int>, "Packed integer must be unsigned"); | ||
|
||
return static_cast<Int>(m_Value & INT_MASK); | ||
} | ||
|
||
void set_ptr(PtrT p) noexcept | ||
{ | ||
// Pointer must be correctly aligned | ||
KTL_ASSERT((reinterpret_cast<size_t>(p) & (Alignment - 1)) == 0); | ||
|
||
m_Value = (reinterpret_cast<uintptr_t>(p) & PTR_MASK) | (m_Value & INT_MASK); | ||
} | ||
|
||
template<typename Int> | ||
void set_int(Int value) noexcept | ||
{ | ||
static_assert(std::is_unsigned_v<Int>, "Packed integer must be unsigned"); | ||
|
||
m_Value = (m_Value & PTR_MASK) | (static_cast<uintptr_t>(value) & INT_MASK); | ||
} | ||
|
||
private: | ||
uintptr_t m_Value; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
#pragma once | ||
|
||
#include <cstddef> | ||
|
||
namespace ktl | ||
{ | ||
template<typename PtrT, size_t Bits, size_t Alignment = alignof(PtrT)> | ||
class packed_ptr; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
#pragma once | ||
|
||
#include <cstdint> | ||
|
||
namespace ktl::detail | ||
{ | ||
constexpr inline uintmax_t log2(uintmax_t n) | ||
{ | ||
uintmax_t r = 0; | ||
|
||
if (n >> 32) { r += 32U; n >>= 32U; } | ||
if (n >> 16) { r += 16U; n >>= 16U; } | ||
if (n >> 8) { r += 8U; n >>= 8U; } | ||
if (n >> 4) { r += 4U; n >>= 4U; } | ||
if (n >> 2) { r += 2U; n >>= 2U; } | ||
if (n >> 1) { r += 1U; n >>= 1U; } | ||
|
||
return r; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
#include "shared/assert_utility.h" | ||
#include "shared/test.h" | ||
#include "shared/types.h" | ||
|
||
#define KTL_DEBUG_ASSERT | ||
#include "ktl/containers/packed_ptr.h" | ||
|
||
#include <memory> | ||
|
||
// Naming scheme: packed_ptr | ||
// Contains tests that use the ktl::packed_ptr | ||
|
||
namespace ktl::test::packed_ptr | ||
{ | ||
KTL_ADD_TEST(test_packed_ptr_stack) | ||
{ | ||
int t; | ||
int* in_ptr = &t; | ||
uint16_t in_value = 2; | ||
|
||
ktl::packed_ptr<int*, 2, alignof(int)> pack(in_ptr, in_value); | ||
|
||
KTL_TEST_ASSERT(pack); | ||
KTL_TEST_ASSERT(in_ptr == pack.get_ptr()); | ||
KTL_TEST_ASSERT(in_value == pack.get_int<uint16_t>()); | ||
} | ||
|
||
KTL_ADD_TEST(test_packed_ptr_malloc) | ||
{ | ||
std::allocator<double> alloc; | ||
|
||
double* in_ptr = alloc.allocate(1); | ||
uint64_t in_value = 2; | ||
|
||
// Using more than 2 bits may require full x64 support | ||
ktl::packed_ptr<double*, 2> pack; | ||
|
||
pack.set_ptr(in_ptr); | ||
pack.set_int(in_value); | ||
|
||
KTL_TEST_ASSERT(pack); | ||
KTL_TEST_ASSERT(in_ptr == pack.get_ptr()); | ||
KTL_TEST_ASSERT(in_value == pack.get_int<uint64_t>()); | ||
|
||
alloc.deallocate(in_ptr, 1); | ||
} | ||
} |