| 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 |  | 
|---|