siplasplas
A library for C++ reflection and introspection
memory_manip.hpp
1 #ifndef SIPLASPLAS_UTILITY_MEMORY_MANIP_HPP
2 #define SIPLASPLAS_UTILITY_MEMORY_MANIP_HPP
3 
4 #include <memory>
5 #include <cstdint>
6 #include <climits>
7 #include <siplasplas/utility/export.hpp>
8 
15 namespace cpp
16 {
17  namespace detail
18  {
29  SIPLASPLAS_UTILITY_EXPORT char* aligned_ptr(char* pointer, std::size_t alignment);
30 
41  SIPLASPLAS_UTILITY_EXPORT void* aligned_ptr(void* pointer, std::size_t alignment);
42 
53  SIPLASPLAS_UTILITY_EXPORT const char* aligned_ptr(const char* pointer, std::size_t alignment);
54 
65  SIPLASPLAS_UTILITY_EXPORT const void* aligned_ptr(const void* pointer, std::size_t alignment);
66 
67 
77  SIPLASPLAS_UTILITY_EXPORT bool is_aligned(char* pointer, std::size_t alignment);
78 
88  SIPLASPLAS_UTILITY_EXPORT bool is_aligned(void* pointer, std::size_t alignment);
89 
99  SIPLASPLAS_UTILITY_EXPORT bool is_aligned(const char* pointer, std::size_t alignment);
100 
110  SIPLASPLAS_UTILITY_EXPORT bool is_aligned(const void* pointer, std::size_t alignment);
111 
122  SIPLASPLAS_UTILITY_EXPORT std::uintptr_t missalignment(const char* address, std::size_t alignment);
123 
134  SIPLASPLAS_UTILITY_EXPORT std::uintptr_t missalignment(const void* address, std::size_t alignment);
135 
146  SIPLASPLAS_UTILITY_EXPORT std::uintptr_t missalignment(char* address, std::size_t alignment);
147 
158  SIPLASPLAS_UTILITY_EXPORT std::uintptr_t missalignment(void* address, std::size_t alignment);
159 
176  template<typename T, typename U>
177  T* tagPointer(T* pointer, U data)
178  {
179  static_assert(sizeof(nullptr) * CHAR_BIT == 64, "Tagging pointers is only supported in architectures with 64 bit virtual addresses");
180 
181  return reinterpret_cast<T*>(static_cast<std::uintptr_t>(data) << 48 | (reinterpret_cast<std::uintptr_t>(pointer) & 0x0000FFFFFFFFFFFF));
182  }
183 
199  template<typename R, typename U, typename... Args>
200  auto tagPointer(R(*pointer)(Args...), U data) -> decltype(pointer)
201  {
202  static_assert(sizeof(nullptr) * CHAR_BIT == 64, "Tagging pointers is only supported in architectures with 64 bit virtual addresses");
203 
204  return reinterpret_cast<R(*)(Args...)>(data << 48 | (reinterpret_cast<std::uintptr_t>(pointer) & 0x0000FFFFFFFFFFFF));
205  }
206 
219  template<typename T>
220  T* untagPointer(T* pointer)
221  {
222  static_assert(sizeof(nullptr) * CHAR_BIT == 64, "Tagging pointers is only supported in architectures with 64 bit virtual addresses");
223 
224  return reinterpret_cast<T*>(reinterpret_cast<std::uintptr_t>(pointer) & 0x0000FFFFFFFFFFFF);
225  }
226 
239  template<typename R, typename... Args>
240  auto untagPointer(R(*pointer)(Args...)) -> decltype(pointer)
241  {
242  static_assert(sizeof(nullptr) * CHAR_BIT == 64, "Tagging pointers is only supported in architectures with 64 bit virtual addresses");
243 
244  return reinterpret_cast<R(*)(Args...)>(reinterpret_cast<std::uintptr_t>(pointer) & 0x0000FFFFFFFFFFFF);
245  }
246 
259  template<typename T>
260  std::uint16_t readTaggedPointer(T* pointer)
261  {
262  static_assert(sizeof(nullptr) * CHAR_BIT == 64, "Tagging pointers is only supported in architectures with 64 bit virtual addresses");
263 
264  return reinterpret_cast<std::uintptr_t>(pointer) >> 48;
265  }
266 
279  template<typename R, typename... Args>
280  std::uint16_t readTaggedPointer(R(*pointer)(Args...))
281  {
282  static_assert(sizeof(nullptr) * CHAR_BIT == 64, "Tagging pointers is only supported in architectures with 64 bit virtual addresses");
283 
284  return reinterpret_cast<std::uintptr_t>(pointer) >> 48;
285  }
286 
287 #ifndef SIPLASPLAS_UTILITY_ALIGNEDMALLOC_ALIGNOFFSET_BITS
288 
308  using AlignedMallocAlingOffset = std::uint8_t;
309 #else
310  using AlignedMallocAlingOffset = SIPLASPLAS_PP_CAT(
311  SIPLASPLAS_PP_CAT(std::uint,SIPLASPLAS_UTILITY_ALIGNEDMALLOC_ALIGNOFFSET_BITS),
312  _t
313  );
314 #endif
315 
332  SIPLASPLAS_UTILITY_EXPORT void* aligned_malloc(std::size_t size, std::size_t alignment, std::size_t offset = 0);
333 
349  SIPLASPLAS_UTILITY_EXPORT void* aligned_malloc_block(void* pointer, std::size_t offset = 0);
350 
359  SIPLASPLAS_UTILITY_EXPORT void aligned_free(void* pointer, std::size_t offset = 0);
360 
361  template<typename T>
362  void write_at(char* pointer, const T& value, std::intptr_t offset = 0)
363  {
364  *(reinterpret_cast<T*>(pointer) + offset) = value;
365  }
366 
367  template<typename T>
368  void write_at(void* pointer, const T& value, std::intptr_t offset = 0)
369  {
370  write_at(reinterpret_cast<char*>(pointer), value, offset);
371  }
372 
373  template<typename T>
374  T read_at(const char* pointer, std::intptr_t offset = 0)
375  {
376  return *(reinterpret_cast<const T*>(pointer + offset));
377  }
378 
379  template<typename T>
380  T read_at(const void* pointer, std::intptr_t offset = 0)
381  {
382  return read_at<T>(reinterpret_cast<const char*>(pointer), offset);
383  }
384 
385  template<typename T>
386  void write_before(char* pointer, const T& value)
387  {
388  write_at(pointer, value, -sizeof(T));
389  }
390 
391  template<typename T>
392  void write_before(void* pointer, const T& value)
393  {
394  write_before(reinterpret_cast<char*>(pointer), value);
395  }
396 
397  template<typename T>
398  T read_before(const char* pointer)
399  {
400  return read_at<T>(pointer, - sizeof(T));
401  }
402 
403  template<typename T>
404  T read_before(const void* pointer)
405  {
406  return read_before<T>(reinterpret_cast<const char*>(pointer));
407  }
408 
409  template<typename T>
410  class RawReaderWriter
411  {
412  public:
413  RawReaderWriter(void* at) :
414  _at{reinterpret_cast<char*>(at)}
415  {}
416 
417  T get() const
418  {
419  return detail::read_at<T>(_at);
420  }
421 
422  operator T() const
423  {
424  return get();
425  }
426 
427  T operator=(T value)
428  {
429  detail::write_at(_at, value);
430  return value;
431  }
432  private:
433  char* _at;
434  };
435  }
436 }
437 
438 #endif // SIPLASPLAS_UTILITY_MEMORY_MANIP_HPP
439 
SIPLASPLAS_UTILITY_EXPORT const void * aligned_ptr(const void *pointer, std::size_t alignment)
Returns an address aligned to an specific boundary.
SIPLASPLAS_UTILITY_EXPORT void * aligned_malloc(std::size_t size, std::size_t alignment, std::size_t offset=0)
Allocates a block of memory of memory aligned to an specific boundary.
auto untagPointer(R(*pointer)(Args...)) -> decltype(pointer)
Untags a pointer.
Definition: memory_manip.hpp:240
Definition: canary_allocator.hpp:7
std::uint8_t AlignedMallocAlingOffset
Type used to store the offset between the aligned pointer returned by aligned_malloc() and the beginn...
Definition: memory_manip.hpp:308
std::uint16_t readTaggedPointer(R(*pointer)(Args...))
Reads the data stored in a tagged pointer.
Definition: memory_manip.hpp:280
SIPLASPLAS_UTILITY_EXPORT std::uintptr_t missalignment(void *address, std::size_t alignment)
Returns the distance between a memory address and the next address aligned to the given boundary...
SIPLASPLAS_UTILITY_EXPORT bool is_aligned(const void *pointer, std::size_t alignment)
Checks if an address is aligned to a given boundary.
SIPLASPLAS_UTILITY_EXPORT void * aligned_malloc_block(void *pointer, std::size_t offset=0)
Returns a pointer to the full block allocated by cpp::aligned_malloc()
auto tagPointer(R(*pointer)(Args...), U data) -> decltype(pointer)
Tags a pointer with the specified data.
Definition: memory_manip.hpp:200
SIPLASPLAS_UTILITY_EXPORT void aligned_free(void *pointer, std::size_t offset=0)
Deallocates a block allocated by cpp::aligned_malloc()