memory_manager_internal.h (6126B)
1 // Copyright (c) the JPEG XL Project Authors. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file. 5 6 #ifndef LIB_JXL_MEMORY_MANAGER_INTERNAL_H_ 7 #define LIB_JXL_MEMORY_MANAGER_INTERNAL_H_ 8 9 // Memory allocator with support for alignment + misalignment. 10 11 #include <jxl/memory_manager.h> 12 13 #include <cstddef> 14 #include <memory> 15 #include <utility> 16 17 #include "lib/jxl/base/compiler_specific.h" 18 #include "lib/jxl/base/status.h" 19 20 namespace jxl { 21 22 namespace memory_manager_internal { 23 24 // To avoid RFOs, match L2 fill size (pairs of lines); 2 x cache line size. 25 static constexpr size_t kAlignment = 2 * 64; 26 static_assert((kAlignment & (kAlignment - 1)) == 0, 27 "kAlignment must be a power of 2"); 28 29 // Minimum multiple for which cache set conflicts and/or loads blocked by 30 // preceding stores can occur. 31 static constexpr size_t kNumAlignmentGroups = 16; 32 static constexpr size_t kAlias = kNumAlignmentGroups * kAlignment; 33 static_assert((kNumAlignmentGroups & (kNumAlignmentGroups - 1)) == 0, 34 "kNumAlignmentGroups must be a power of 2"); 35 36 } // namespace memory_manager_internal 37 38 // Initializes the memory manager instance with the passed one. The 39 // MemoryManager passed in |memory_manager| may be NULL or contain NULL 40 // functions which will be initialized with the default ones. If either alloc 41 // or free are NULL, then both must be NULL, otherwise this function returns an 42 // error. 43 Status MemoryManagerInit(JxlMemoryManager* self, 44 const JxlMemoryManager* memory_manager); 45 46 void* MemoryManagerAlloc(const JxlMemoryManager* memory_manager, size_t size); 47 void MemoryManagerFree(const JxlMemoryManager* memory_manager, void* address); 48 49 // Helper class to be used as a deleter in a unique_ptr<T> call. 50 class MemoryManagerDeleteHelper { 51 public: 52 explicit MemoryManagerDeleteHelper(const JxlMemoryManager* memory_manager) 53 : memory_manager_(memory_manager) {} 54 55 // Delete and free the passed pointer using the memory_manager. 56 template <typename T> 57 void operator()(T* address) const { 58 if (!address) { 59 return; 60 } 61 address->~T(); 62 return memory_manager_->free(memory_manager_->opaque, address); 63 } 64 65 private: 66 const JxlMemoryManager* memory_manager_; 67 }; 68 69 template <typename T> 70 using MemoryManagerUniquePtr = std::unique_ptr<T, MemoryManagerDeleteHelper>; 71 72 // Creates a new object T allocating it with the memory allocator into a 73 // unique_ptr. 74 template <typename T, typename... Args> 75 JXL_INLINE MemoryManagerUniquePtr<T> MemoryManagerMakeUnique( 76 const JxlMemoryManager* memory_manager, Args&&... args) { 77 T* mem = 78 static_cast<T*>(memory_manager->alloc(memory_manager->opaque, sizeof(T))); 79 if (!mem) { 80 // Allocation error case. 81 return MemoryManagerUniquePtr<T>(nullptr, 82 MemoryManagerDeleteHelper(memory_manager)); 83 } 84 return MemoryManagerUniquePtr<T>(new (mem) T(std::forward<Args>(args)...), 85 MemoryManagerDeleteHelper(memory_manager)); 86 } 87 88 // Returns recommended distance in bytes between the start of two consecutive 89 // rows. 90 size_t BytesPerRow(size_t xsize, size_t sizeof_t); 91 92 class AlignedMemory { 93 public: 94 AlignedMemory() 95 : allocation_(nullptr), memory_manager_(nullptr), address_(nullptr) {} 96 97 // Copy disallowed. 98 AlignedMemory(const AlignedMemory& other) = delete; 99 AlignedMemory& operator=(const AlignedMemory& other) = delete; 100 101 // Custom move. 102 AlignedMemory(AlignedMemory&& other) noexcept; 103 AlignedMemory& operator=(AlignedMemory&& other) noexcept; 104 105 ~AlignedMemory(); 106 107 static StatusOr<AlignedMemory> Create(JxlMemoryManager* memory_manager, 108 size_t size, size_t pre_padding = 0); 109 110 explicit operator bool() const noexcept { return (address_ != nullptr); } 111 112 template <typename T> 113 T* address() const { 114 return reinterpret_cast<T*>(address_); 115 } 116 JxlMemoryManager* memory_manager() const { return memory_manager_; } 117 118 // TODO(eustas): we can offer "actually accessible" size; it is 0-2KiB bigger 119 // than requested size, due to generous alignment; 120 // might be useful for resizeable containers (e.g. PaddedBytes) 121 122 private: 123 AlignedMemory(JxlMemoryManager* memory_manager, void* allocation, 124 size_t pre_padding); 125 126 void* allocation_; 127 JxlMemoryManager* memory_manager_; 128 void* address_; 129 }; 130 131 template <typename T> 132 class AlignedArray { 133 public: 134 AlignedArray() : size_(0) {} 135 136 static StatusOr<AlignedArray> Create(JxlMemoryManager* memory_manager, 137 size_t size) { 138 size_t storage_size = size * sizeof(T); 139 JXL_ASSIGN_OR_RETURN(AlignedMemory storage, 140 AlignedMemory::Create(memory_manager, storage_size)); 141 T* items = storage.address<T>(); 142 for (size_t i = 0; i < size; ++i) { 143 new (items + i) T(); 144 } 145 return AlignedArray<T>(std::move(storage), size); 146 } 147 148 // Copy disallowed. 149 AlignedArray(const AlignedArray& other) = delete; 150 AlignedArray& operator=(const AlignedArray& other) = delete; 151 152 // Custom move. 153 AlignedArray(AlignedArray&& other) noexcept { 154 size_ = other.size_; 155 storage_ = std::move(other.storage_); 156 other.size_ = 0; 157 } 158 159 AlignedArray& operator=(AlignedArray&& other) noexcept { 160 if (this == &other) return *this; 161 size_ = other.size_; 162 storage_ = std::move(other.storage_); 163 other.size_ = 0; 164 return *this; 165 } 166 167 ~AlignedArray() { 168 if (!size_) return; 169 T* items = storage_.address<T>(); 170 for (size_t i = 0; i < size_; ++i) { 171 items[i].~T(); 172 } 173 } 174 175 T& operator[](const size_t i) { 176 JXL_DASSERT(i < size_); 177 return *(storage_.address<T>() + i); 178 } 179 const T& operator[](const size_t i) const { 180 JXL_DASSERT(i < size_); 181 return *(storage_.address<T>() + i); 182 } 183 184 private: 185 explicit AlignedArray(AlignedMemory&& storage, size_t size) 186 : size_(size), storage_(std::move(storage)) {} 187 size_t size_; 188 AlignedMemory storage_; 189 }; 190 191 } // namespace jxl 192 193 #endif // LIB_JXL_MEMORY_MANAGER_INTERNAL_H_