Add and plumb unsafe_{to,from}_uintptr<T> casts

These encapsulate the wildly powerful reinterpret_cast<> operator where one side
is a uintptr_t and the other is a native pointer.  In both cases we require the
pointer type to be explicitly given.
This commit is contained in:
Nathaniel Wesley Filardo
2022-03-17 17:34:26 +00:00
committed by Nathaniel Wesley Filardo
parent 4ad99d7392
commit 26324e8bfc
6 changed files with 45 additions and 21 deletions

View File

@@ -28,8 +28,8 @@ namespace snmalloc
inline U* pointer_offset(T* base, size_t diff)
{
SNMALLOC_ASSERT(base != nullptr); /* Avoid UB */
return reinterpret_cast<U*>(
reinterpret_cast<uintptr_t>(base) + static_cast<uintptr_t>(diff));
return unsafe_from_uintptr<U>(
unsafe_to_uintptr<T>(base) + static_cast<uintptr_t>(diff));
}
template<SNMALLOC_CONCEPT(capptr::ConceptBound) bounds, typename T>
@@ -129,8 +129,8 @@ namespace snmalloc
template<size_t alignment, typename T = void>
inline T* pointer_align_down(void* p)
{
return reinterpret_cast<T*>(
pointer_align_down<alignment>(reinterpret_cast<uintptr_t>(p)));
return unsafe_from_uintptr<T>(
pointer_align_down<alignment>(unsafe_to_uintptr<void>(p)));
}
template<
@@ -164,8 +164,8 @@ namespace snmalloc
#if __has_builtin(__builtin_align_up)
return static_cast<T*>(__builtin_align_up(p, alignment));
#else
return reinterpret_cast<T*>(
bits::align_up(reinterpret_cast<uintptr_t>(p), alignment));
return unsafe_from_uintptr<T>(
bits::align_up(unsafe_to_uintptr<void>(p), alignment));
#endif
}
}
@@ -197,8 +197,8 @@ namespace snmalloc
#if __has_builtin(__builtin_align_down)
return static_cast<T*>(__builtin_align_down(p, alignment));
#else
return reinterpret_cast<T*>(
bits::align_down(reinterpret_cast<uintptr_t>(p), alignment));
return unsafe_from_uintptr<T>(
bits::align_down(unsafe_to_uintptr<void>(p), alignment));
#endif
}
@@ -221,8 +221,8 @@ namespace snmalloc
#if __has_builtin(__builtin_align_up)
return static_cast<T*>(__builtin_align_up(p, alignment));
#else
return reinterpret_cast<T*>(
bits::align_up(reinterpret_cast<uintptr_t>(p), alignment));
return unsafe_from_uintptr<T>(
bits::align_up(unsafe_to_uintptr<void>(p), alignment));
#endif
}

View File

@@ -7,6 +7,30 @@
namespace snmalloc
{
/*
* reinterpret_cast<> is a powerful primitive that, excitingly, does not
* require the programmer to annotate the expected *source* type. We
* therefore wrap its use to interconvert between uintptr_t and pointer types.
*/
/**
* Convert a pointer to a uintptr_t. Template argument inference is
* prohibited.
*/
template<typename T>
SNMALLOC_FAST_PATH_INLINE uintptr_t
unsafe_to_uintptr(std::enable_if_t<true, T>* p)
{
return reinterpret_cast<uintptr_t>(p);
}
/** Convert a uintptr_t to a T*. */
template<typename T>
SNMALLOC_FAST_PATH_INLINE T* unsafe_from_uintptr(uintptr_t p)
{
return reinterpret_cast<T*>(p);
}
/**
* To assist in providing a uniform interface regardless of pointer wrapper,
* we also export intrinsic pointer and atomic pointer aliases, as the postfix
@@ -321,7 +345,7 @@ namespace snmalloc
[[nodiscard]] SNMALLOC_FAST_PATH uintptr_t unsafe_uintptr() const
{
return reinterpret_cast<uintptr_t>(this->unsafe_capptr);
return unsafe_to_uintptr<T>(this->unsafe_capptr);
}
};