| 1 | // Copyright (c) Microsoft Corporation. All rights reserved. |
| 2 | // Licensed under the MIT license. |
| 3 | |
| 4 | #pragma once |
| 5 | |
| 6 | #include <cassert> |
| 7 | #include <cstdint> |
| 8 | #include <functional> |
| 9 | #include <memory> |
| 10 | #include <type_traits> |
| 11 | |
| 12 | #include "alloc.h" |
| 13 | #include "lss_allocator.h" |
| 14 | |
| 15 | #ifdef _WIN32 |
| 16 | #include <intrin.h> |
| 17 | #pragma intrinsic(_BitScanReverse64) |
| 18 | #else |
| 19 | namespace FASTER { |
| 20 | /// Convert GCC's __builtin_clzl() to Microsoft's _BitScanReverse64(). |
| 21 | inline uint8_t _BitScanReverse64(unsigned long* index, uint64_t mask) { |
| 22 | bool found = mask > 0; |
| 23 | *index = 63 - __builtin_clzl(mask); |
| 24 | return found; |
| 25 | } |
| 26 | } |
| 27 | #endif |
| 28 | |
| 29 | /// Wrappers for C++ std::unique_ptr<>. |
| 30 | |
| 31 | namespace FASTER { |
| 32 | namespace core { |
| 33 | |
| 34 | /// Round the specified size up to the next power of 2. |
| 35 | inline size_t next_power_of_two(size_t size) { |
| 36 | assert(size > 0); |
| 37 | // BSR returns the index k of the most-significant 1 bit. So 2^(k+1) > (size - 1) >= 2^k, |
| 38 | // which means 2^(k+1) >= size > 2^k. |
| 39 | unsigned long k; |
| 40 | uint8_t found = _BitScanReverse64(&k, size - 1); |
| 41 | return (uint64_t)1 << (found * (k + 1)); |
| 42 | } |
| 43 | |
| 44 | /// Pad alignment to specified. Declared "constexpr" so that the calculation can be performed at |
| 45 | /// compile time, assuming parameters "size" and "alignment" are known then. |
| 46 | constexpr inline size_t pad_alignment(size_t size, size_t alignment) { |
| 47 | assert(alignment > 0); |
| 48 | // Function implemented only for powers of 2. |
| 49 | assert((alignment & (alignment - 1)) == 0); |
| 50 | size_t max_padding = alignment - 1; |
| 51 | return (size + max_padding) & ~max_padding; |
| 52 | } |
| 53 | |
| 54 | /// Pad alignment to specified type. |
| 55 | template <typename T> |
| 56 | constexpr inline size_t pad_alignment(size_t size) { |
| 57 | return pad_alignment(size, alignof(T)); |
| 58 | } |
| 59 | |
| 60 | /// Defined in C++ 14; copying the definition here for older compilers. |
| 61 | template <typename T> |
| 62 | using remove_const_t = typename std::remove_const<T>::type; |
| 63 | |
| 64 | /// alloc_aligned(): allocate a unique_ptr with a particular alignment. |
| 65 | template <typename T> |
| 66 | void unique_ptr_aligned_deleter(T* p) { |
| 67 | auto q = const_cast<remove_const_t<T>*>(p); |
| 68 | q->~T(); |
| 69 | aligned_free(q); |
| 70 | } |
| 71 | |
| 72 | template <typename T> |
| 73 | struct AlignedDeleter { |
| 74 | void operator()(T* p) const { |
| 75 | unique_ptr_aligned_deleter(p); |
| 76 | } |
| 77 | }; |
| 78 | |
| 79 | template <typename T> |
| 80 | using aligned_unique_ptr_t = std::unique_ptr<T, AlignedDeleter<T>>; |
| 81 | static_assert(sizeof(aligned_unique_ptr_t<void>) == 8, "sizeof(unique_aligned_ptr_t)" ); |
| 82 | |
| 83 | template <typename T> |
| 84 | aligned_unique_ptr_t<T> make_aligned_unique_ptr(T* p) { |
| 85 | return aligned_unique_ptr_t<T>(p, AlignedDeleter<T>()); |
| 86 | } |
| 87 | |
| 88 | template <typename T> |
| 89 | aligned_unique_ptr_t<T> alloc_aligned(size_t alignment, size_t size) { |
| 90 | return make_aligned_unique_ptr<T>(reinterpret_cast<T*>(aligned_alloc(alignment, size))); |
| 91 | } |
| 92 | |
| 93 | /// alloc_context(): allocate a small chunk of memory for a callback context. |
| 94 | template <typename T> |
| 95 | void unique_ptr_context_deleter(T* p) { |
| 96 | auto q = const_cast<remove_const_t<T>*>(p); |
| 97 | q->~T(); |
| 98 | lss_allocator.Free(q); |
| 99 | } |
| 100 | |
| 101 | template <typename T> |
| 102 | struct ContextDeleter { |
| 103 | void operator()(T* p) const { |
| 104 | unique_ptr_context_deleter(p); |
| 105 | } |
| 106 | }; |
| 107 | |
| 108 | template <typename T> |
| 109 | using context_unique_ptr_t = std::unique_ptr<T, ContextDeleter<T>>; |
| 110 | static_assert(sizeof(context_unique_ptr_t<void>) == 8, "sizeof(context_unique_ptr_t)" ); |
| 111 | |
| 112 | template <typename T> |
| 113 | context_unique_ptr_t<T> make_context_unique_ptr(T* p) { |
| 114 | return context_unique_ptr_t<T>(p, ContextDeleter<T>()); |
| 115 | } |
| 116 | |
| 117 | template <typename T> |
| 118 | context_unique_ptr_t<T> alloc_context(uint32_t size) { |
| 119 | return make_context_unique_ptr<T>(reinterpret_cast<T*>(lss_allocator.Allocate(size))); |
| 120 | } |
| 121 | |
| 122 | } |
| 123 | } // namespace FASTER::core |
| 124 | |