1193323Sed//===- llvm/Support/PointerLikeTypeTraits.h - Pointer Traits ----*- C++ -*-===// 2193323Sed// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6193323Sed// 7193323Sed//===----------------------------------------------------------------------===// 8193323Sed// 9193323Sed// This file defines the PointerLikeTypeTraits class. This allows data 10193323Sed// structures to reason about pointers and other things that are pointer sized. 11193323Sed// 12193323Sed//===----------------------------------------------------------------------===// 13193323Sed 14193323Sed#ifndef LLVM_SUPPORT_POINTERLIKETYPETRAITS_H 15193323Sed#define LLVM_SUPPORT_POINTERLIKETYPETRAITS_H 16193323Sed 17218893Sdim#include "llvm/Support/DataTypes.h" 18341825Sdim#include <assert.h> 19314564Sdim#include <type_traits> 20193323Sed 21193323Sednamespace llvm { 22296417Sdim 23296417Sdim/// A traits type that is used to handle pointer types and things that are just 24296417Sdim/// wrappers for pointers as a uniform entity. 25327952Sdimtemplate <typename T> struct PointerLikeTypeTraits; 26193323Sed 27296417Sdimnamespace detail { 28296417Sdim/// A tiny meta function to compute the log2 of a compile time constant. 29296417Sdimtemplate <size_t N> 30296417Sdimstruct ConstantLog2 31296417Sdim : std::integral_constant<size_t, ConstantLog2<N / 2>::value + 1> {}; 32296417Sdimtemplate <> struct ConstantLog2<1> : std::integral_constant<size_t, 0> {}; 33296417Sdim 34327952Sdim// Provide a trait to check if T is pointer-like. 35327952Sdimtemplate <typename T, typename U = void> struct HasPointerLikeTypeTraits { 36327952Sdim static const bool value = false; 37327952Sdim}; 38327952Sdim 39327952Sdim// sizeof(T) is valid only for a complete T. 40327952Sdimtemplate <typename T> struct HasPointerLikeTypeTraits< 41327952Sdim T, decltype((sizeof(PointerLikeTypeTraits<T>) + sizeof(T)), void())> { 42327952Sdim static const bool value = true; 43327952Sdim}; 44327952Sdim 45327952Sdimtemplate <typename T> struct IsPointerLike { 46327952Sdim static const bool value = HasPointerLikeTypeTraits<T>::value; 47327952Sdim}; 48327952Sdim 49327952Sdimtemplate <typename T> struct IsPointerLike<T *> { 50327952Sdim static const bool value = true; 51327952Sdim}; 52327952Sdim} // namespace detail 53327952Sdim 54193323Sed// Provide PointerLikeTypeTraits for non-cvr pointers. 55327952Sdimtemplate <typename T> struct PointerLikeTypeTraits<T *> { 56296417Sdim static inline void *getAsVoidPointer(T *P) { return P; } 57296417Sdim static inline T *getFromVoidPointer(void *P) { return static_cast<T *>(P); } 58296417Sdim 59314564Sdim enum { NumLowBitsAvailable = detail::ConstantLog2<alignof(T)>::value }; 60296417Sdim}; 61296417Sdim 62327952Sdimtemplate <> struct PointerLikeTypeTraits<void *> { 63296417Sdim static inline void *getAsVoidPointer(void *P) { return P; } 64296417Sdim static inline void *getFromVoidPointer(void *P) { return P; } 65296417Sdim 66296417Sdim /// Note, we assume here that void* is related to raw malloc'ed memory and 67296417Sdim /// that malloc returns objects at least 4-byte aligned. However, this may be 68296417Sdim /// wrong, or pointers may be from something other than malloc. In this case, 69296417Sdim /// you should specify a real typed pointer or avoid this template. 70193323Sed /// 71193323Sed /// All clients should use assertions to do a run-time check to ensure that 72193323Sed /// this is actually true. 73193323Sed enum { NumLowBitsAvailable = 2 }; 74193323Sed}; 75296417Sdim 76321369Sdim// Provide PointerLikeTypeTraits for const things. 77327952Sdimtemplate <typename T> struct PointerLikeTypeTraits<const T> { 78321369Sdim typedef PointerLikeTypeTraits<T> NonConst; 79321369Sdim 80321369Sdim static inline const void *getAsVoidPointer(const T P) { 81321369Sdim return NonConst::getAsVoidPointer(P); 82321369Sdim } 83321369Sdim static inline const T getFromVoidPointer(const void *P) { 84321369Sdim return NonConst::getFromVoidPointer(const_cast<void *>(P)); 85321369Sdim } 86321369Sdim enum { NumLowBitsAvailable = NonConst::NumLowBitsAvailable }; 87321369Sdim}; 88321369Sdim 89193323Sed// Provide PointerLikeTypeTraits for const pointers. 90327952Sdimtemplate <typename T> struct PointerLikeTypeTraits<const T *> { 91296417Sdim typedef PointerLikeTypeTraits<T *> NonConst; 92198090Srdivacky 93296417Sdim static inline const void *getAsVoidPointer(const T *P) { 94296417Sdim return NonConst::getAsVoidPointer(const_cast<T *>(P)); 95198090Srdivacky } 96193323Sed static inline const T *getFromVoidPointer(const void *P) { 97296417Sdim return NonConst::getFromVoidPointer(const_cast<void *>(P)); 98193323Sed } 99198090Srdivacky enum { NumLowBitsAvailable = NonConst::NumLowBitsAvailable }; 100193323Sed}; 101193323Sed 102193323Sed// Provide PointerLikeTypeTraits for uintptr_t. 103327952Sdimtemplate <> struct PointerLikeTypeTraits<uintptr_t> { 104193323Sed static inline void *getAsVoidPointer(uintptr_t P) { 105296417Sdim return reinterpret_cast<void *>(P); 106193323Sed } 107193323Sed static inline uintptr_t getFromVoidPointer(void *P) { 108193323Sed return reinterpret_cast<uintptr_t>(P); 109193323Sed } 110193323Sed // No bits are available! 111193323Sed enum { NumLowBitsAvailable = 0 }; 112193323Sed}; 113296417Sdim 114341825Sdim/// Provide suitable custom traits struct for function pointers. 115341825Sdim/// 116341825Sdim/// Function pointers can't be directly given these traits as functions can't 117341825Sdim/// have their alignment computed with `alignof` and we need different casting. 118341825Sdim/// 119341825Sdim/// To rely on higher alignment for a specialized use, you can provide a 120341825Sdim/// customized form of this template explicitly with higher alignment, and 121341825Sdim/// potentially use alignment attributes on functions to satisfy that. 122341825Sdimtemplate <int Alignment, typename FunctionPointerT> 123341825Sdimstruct FunctionPointerLikeTypeTraits { 124341825Sdim enum { NumLowBitsAvailable = detail::ConstantLog2<Alignment>::value }; 125341825Sdim static inline void *getAsVoidPointer(FunctionPointerT P) { 126341825Sdim assert((reinterpret_cast<uintptr_t>(P) & 127341825Sdim ~((uintptr_t)-1 << NumLowBitsAvailable)) == 0 && 128341825Sdim "Alignment not satisfied for an actual function pointer!"); 129341825Sdim return reinterpret_cast<void *>(P); 130341825Sdim } 131341825Sdim static inline FunctionPointerT getFromVoidPointer(void *P) { 132341825Sdim return reinterpret_cast<FunctionPointerT>(P); 133341825Sdim } 134341825Sdim}; 135341825Sdim 136341825Sdim/// Provide a default specialization for function pointers that assumes 4-byte 137341825Sdim/// alignment. 138341825Sdim/// 139341825Sdim/// We assume here that functions used with this are always at least 4-byte 140341825Sdim/// aligned. This means that, for example, thumb functions won't work or systems 141341825Sdim/// with weird unaligned function pointers won't work. But all practical systems 142341825Sdim/// we support satisfy this requirement. 143341825Sdimtemplate <typename ReturnT, typename... ParamTs> 144341825Sdimstruct PointerLikeTypeTraits<ReturnT (*)(ParamTs...)> 145341825Sdim : FunctionPointerLikeTypeTraits<4, ReturnT (*)(ParamTs...)> {}; 146341825Sdim 147193323Sed} // end namespace llvm 148193323Sed 149193323Sed#endif 150