|
1 | | -// Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. |
| 1 | +// Copyright (C) 2018-2026 - DevSH Graphics Programming Sp. z O.O. |
2 | 2 | // This file is part of the "Nabla Engine". |
3 | 3 | // For conditions of distribution and use, see copyright notice in nabla.h |
| 4 | +#ifndef _NBL_CORE_ADDRESS_ALLOCATOR_BASE_H_INCLUDED_ |
| 5 | +#define _NBL_CORE_ADDRESS_ALLOCATOR_BASE_H_INCLUDED_ |
4 | 6 |
|
5 | | -#ifndef __NBL_CORE_ADDRESS_ALLOCATOR_BASE_H_INCLUDED__ |
6 | | -#define __NBL_CORE_ADDRESS_ALLOCATOR_BASE_H_INCLUDED__ |
7 | 7 |
|
8 | 8 | #include "nbl/core/memory/memory.h" |
9 | 9 | #include "nbl/core/alloc/address_allocator_traits.h" |
10 | 10 |
|
11 | | -namespace nbl |
12 | | -{ |
13 | | -namespace core |
| 11 | + |
| 12 | +namespace nbl::core |
14 | 13 | { |
15 | 14 |
|
16 | | - #define _NBL_DECLARE_ADDRESS_ALLOCATOR_TYPEDEFS(SIZE_TYPE) \ |
17 | | - using size_type = SIZE_TYPE;\ |
18 | | - using difference_type = typename std::make_signed<size_type>::type;\ |
19 | | - using ubyte_pointer = uint8_t*;\ |
20 | | - static constexpr size_type invalid_address = nbl::core::address_type_traits<size_type>::invalid_address |
21 | | - |
22 | | - template<typename CRTP, typename _size_type> |
23 | | - class AddressAllocatorBase |
24 | | - { |
25 | | - public: |
26 | | - _NBL_DECLARE_ADDRESS_ALLOCATOR_TYPEDEFS(_size_type); |
27 | | - |
28 | | - AddressAllocatorBase() { invalidate(); } |
29 | | - |
30 | | - inline _size_type max_alignment() const noexcept |
31 | | - { |
32 | | - return maxRequestableAlignment; |
33 | | - } |
34 | | - |
35 | | - inline _size_type get_align_offset() const noexcept |
36 | | - { |
37 | | - return alignOffset; |
38 | | - } |
39 | | - |
40 | | - inline _size_type get_combined_offset() const noexcept |
41 | | - { |
42 | | - return combinedOffset; |
43 | | - } |
44 | | - |
45 | | - // usage: for resizeable allocators built on top of non-resizeable ones (that resize via the CRTP constructor) |
46 | | - // we usually call this before attempting to create the memory for the resized allocator, |
47 | | - // so we don't know exactly what the addressOffset or alignOffset will be |
48 | | - inline _size_type safe_shrink_size(_size_type sizeBound, _size_type newBuffAlignmentWeCanGuarantee=1u) const noexcept |
49 | | - { |
50 | | - if (newBuffAlignmentWeCanGuarantee<maxRequestableAlignment) |
51 | | - return sizeBound+maxRequestableAlignment-newBuffAlignmentWeCanGuarantee; |
52 | | - else if (sizeBound) |
53 | | - return sizeBound; |
54 | | - else |
55 | | - return std::max(maxRequestableAlignment,newBuffAlignmentWeCanGuarantee); |
56 | | - } |
57 | | - protected: |
58 | | - virtual ~AddressAllocatorBase() {} |
59 | | - |
60 | | - AddressAllocatorBase(void* reservedSpc, _size_type addressOffsetToApply, _size_type alignOffsetNeeded, _size_type maxAllocatableAlignment) : |
61 | | - reservedSpace(reservedSpc), addressOffset(addressOffsetToApply), alignOffset(alignOffsetNeeded), |
62 | | - maxRequestableAlignment(maxAllocatableAlignment), combinedOffset(addressOffset+alignOffset) |
63 | | - { |
64 | | - #ifdef _NBL_DEBUG |
65 | | - // pointer to reserved memory has to be aligned to SIMD types! |
66 | | - assert((reinterpret_cast<size_t>(reservedSpace)&(_NBL_SIMD_ALIGNMENT-1u))==0ull); |
67 | | - assert(maxAllocatableAlignment); |
68 | | - assert(core::isPoT(maxRequestableAlignment)); // this is not a proper alignment value |
69 | | - #endif // _NBL_DEBUG |
70 | | - } |
71 | | - AddressAllocatorBase(CRTP&& other, void* newReservedSpc) |
72 | | - { |
73 | | - operator=(std::move(other)); |
74 | | - reservedSpace = newReservedSpc; |
75 | | - #ifdef _NBL_DEBUG |
76 | | - // reserved space has to be aligned at least to SIMD |
77 | | - assert((reinterpret_cast<size_t>(reservedSpace)&(_NBL_SIMD_ALIGNMENT-1u))==0ull); |
78 | | - #endif // _NBL_DEBUG |
79 | | - } |
80 | | - AddressAllocatorBase(CRTP&& other, void* newReservedSpc, _size_type newAddressOffset, _size_type newAlignOffset) : |
81 | | - AddressAllocatorBase(std::move(other),newReservedSpc) |
82 | | - { |
83 | | - addressOffset = newAddressOffset; |
84 | | - alignOffset = newAlignOffset; |
85 | | - combinedOffset = addressOffset+alignOffset; |
86 | | - } |
87 | | - AddressAllocatorBase(const CRTP& other, void* newReservedSpc) : |
88 | | - reservedSpace(newReservedSpc), addressOffset(other.addressOffset), alignOffset(other.alignOffset), |
89 | | - maxRequestableAlignment(other.maxRequestableAlignment), combinedOffset(other.combinedOffset) |
90 | | - { |
91 | | - #ifdef _NBL_DEBUG |
92 | | - // reserved space has to be aligned at least to SIMD |
93 | | - assert((reinterpret_cast<size_t>(reservedSpace)&(_NBL_SIMD_ALIGNMENT-1u))==0ull); |
94 | | - #endif // _NBL_DEBUG |
95 | | - } |
96 | | - AddressAllocatorBase(const CRTP& other, void* newReservedSpc, _size_type newAddressOffset, _size_type newAlignOffset) : |
97 | | - AddressAllocatorBase(other, newReservedSpc) |
98 | | - { |
99 | | - addressOffset = newAddressOffset; |
100 | | - alignOffset = newAlignOffset; |
101 | | - combinedOffset = addressOffset+alignOffset; |
102 | | - } |
103 | | - |
104 | | - inline bool checkResize(_size_type newBuffSz, _size_type newAlignOffset) |
105 | | - { |
106 | | - // cannot reallocate the data into smaller storage than is necessary |
107 | | - if (newBuffSz<safe_shrink_size(0u,maxRequestableAlignment)) return false; |
108 | | - // need enough space for the new alignment |
109 | | - if (newAlignOffset>newBuffSz) return false; |
110 | | - |
111 | | - return true; |
112 | | - } |
113 | | - |
114 | | - inline _size_type getAddressOffset() const noexcept {return addressOffset;} |
115 | | - |
116 | | - inline const void* getReservedSpacePtr() const noexcept {return reservedSpace;} |
117 | | - |
118 | | - AddressAllocatorBase& operator=(AddressAllocatorBase&& other) |
119 | | - { |
120 | | - reservedSpace = other.reservedSpace; |
121 | | - addressOffset = other.addressOffset; |
122 | | - alignOffset = other.alignOffset; |
123 | | - maxRequestableAlignment = other.maxRequestableAlignment; |
124 | | - combinedOffset = other.combinedOffset; |
125 | | - other.invalidate(); |
126 | | - return *this; |
127 | | - } |
128 | | - |
129 | | - void invalidate() |
130 | | - { |
131 | | - reservedSpace = nullptr; |
132 | | - addressOffset = invalid_address; |
133 | | - alignOffset = invalid_address; |
134 | | - maxRequestableAlignment = invalid_address; |
135 | | - combinedOffset = invalid_address; |
136 | | - } |
137 | | - |
138 | | - // pointer to allocator specific state-keeping data, please note that irrBaW address allocators were designed to allocate memory they can't actually access |
139 | | - void* reservedSpace; |
140 | | - // automatic offset to be added to generated addresses |
141 | | - _size_type addressOffset; |
142 | | - // the positive offset that would have to be applied to `addressOffset` to make it `maxRequestableAlignment`-aligned to some unknown value |
143 | | - _size_type alignOffset; |
144 | | - // this cannot be deduced from the `addressOffset` , so we let the user specify it |
145 | | - _size_type maxRequestableAlignment; |
146 | | - |
147 | | - //internal usage |
148 | | - _size_type combinedOffset; |
149 | | - }; |
| 15 | +#define _NBL_DECLARE_ADDRESS_ALLOCATOR_TYPEDEFS(SIZE_TYPE) \ |
| 16 | + using size_type = SIZE_TYPE;\ |
| 17 | + using difference_type = typename std::make_signed<size_type>::type;\ |
| 18 | + using ubyte_pointer = uint8_t*;\ |
| 19 | + static constexpr size_type invalid_address = nbl::core::address_type_traits<size_type>::invalid_address |
150 | 20 |
|
151 | | -} |
152 | | -} |
| 21 | +template<typename CRTP, typename _size_type> |
| 22 | +class AddressAllocatorBase |
| 23 | +{ |
| 24 | + public: |
| 25 | + _NBL_DECLARE_ADDRESS_ALLOCATOR_TYPEDEFS(_size_type); |
| 26 | + |
| 27 | + AddressAllocatorBase() { invalidate(); } |
| 28 | + |
| 29 | + inline _size_type max_alignment() const noexcept |
| 30 | + { |
| 31 | + return maxRequestableAlignment; |
| 32 | + } |
| 33 | + |
| 34 | + inline _size_type get_align_offset() const noexcept |
| 35 | + { |
| 36 | + return alignOffset; |
| 37 | + } |
| 38 | + |
| 39 | + inline _size_type get_combined_offset() const noexcept |
| 40 | + { |
| 41 | + return combinedOffset; |
| 42 | + } |
| 43 | + |
| 44 | + // usage: for resizeable allocators built on top of non-resizeable ones (that resize via the CRTP constructor) |
| 45 | + // we usually call this before attempting to create the memory for the resized allocator, |
| 46 | + // so we don't know exactly what the addressOffset or alignOffset will be |
| 47 | + inline _size_type safe_shrink_size(_size_type sizeBound, _size_type newBuffAlignmentWeCanGuarantee=1u) const noexcept |
| 48 | + { |
| 49 | + if (newBuffAlignmentWeCanGuarantee<maxRequestableAlignment) |
| 50 | + return sizeBound+maxRequestableAlignment-newBuffAlignmentWeCanGuarantee; |
| 51 | + else if (sizeBound) |
| 52 | + return sizeBound; |
| 53 | + else |
| 54 | + return std::max(maxRequestableAlignment,newBuffAlignmentWeCanGuarantee); |
| 55 | + } |
| 56 | + protected: |
| 57 | + virtual ~AddressAllocatorBase() {} |
| 58 | + |
| 59 | + inline AddressAllocatorBase(void* reservedSpc, _size_type addressOffsetToApply, _size_type alignOffsetNeeded, _size_type maxAllocatableAlignment) : |
| 60 | + reservedSpace(reservedSpc), addressOffset(addressOffsetToApply), alignOffset(alignOffsetNeeded), |
| 61 | + maxRequestableAlignment(maxAllocatableAlignment), combinedOffset(addressOffset+alignOffset) |
| 62 | + { |
| 63 | + #ifdef _NBL_DEBUG |
| 64 | + // pointer to reserved memory has to be aligned to SIMD types! |
| 65 | + assert((reinterpret_cast<size_t>(reservedSpace)&(_NBL_SIMD_ALIGNMENT-1u))==0ull); |
| 66 | + assert(maxAllocatableAlignment); |
| 67 | + assert(core::isPoT(maxRequestableAlignment)); // this is not a proper alignment value |
| 68 | + #endif // _NBL_DEBUG |
| 69 | + } |
| 70 | + inline AddressAllocatorBase(CRTP&& other, void* newReservedSpc) |
| 71 | + { |
| 72 | + operator=(std::move(other)); |
| 73 | + reservedSpace = newReservedSpc; |
| 74 | + #ifdef _NBL_DEBUG |
| 75 | + // reserved space has to be aligned at least to SIMD |
| 76 | + assert((reinterpret_cast<size_t>(reservedSpace)&(_NBL_SIMD_ALIGNMENT-1u))==0ull); |
| 77 | + #endif // _NBL_DEBUG |
| 78 | + } |
| 79 | + // TODO: list of extra parameter types for move and copy ctors, and utilities to static assert them |
| 80 | + // NOTE: there's only one move ctor, so maybe all the base classes shouldn't perfectly forward it anymore? |
| 81 | + inline AddressAllocatorBase(CRTP&& other, void* newReservedSpc, _size_type newAddressOffset, _size_type newAlignOffset) : |
| 82 | + AddressAllocatorBase(std::move(other),newReservedSpc) |
| 83 | + { |
| 84 | + addressOffset = newAddressOffset; |
| 85 | + alignOffset = newAlignOffset; |
| 86 | + combinedOffset = addressOffset+alignOffset; |
| 87 | + } |
| 88 | + inline AddressAllocatorBase(const CRTP& other, void* newReservedSpc) : |
| 89 | + reservedSpace(newReservedSpc), addressOffset(other.addressOffset), alignOffset(other.alignOffset), |
| 90 | + maxRequestableAlignment(other.maxRequestableAlignment), combinedOffset(other.combinedOffset) |
| 91 | + { |
| 92 | + #ifdef _NBL_DEBUG |
| 93 | + // reserved space has to be aligned at least to SIMD |
| 94 | + assert((reinterpret_cast<size_t>(reservedSpace)&(_NBL_SIMD_ALIGNMENT-1u))==0ull); |
| 95 | + #endif // _NBL_DEBUG |
| 96 | + } |
| 97 | + inline AddressAllocatorBase(const CRTP& other, void* newReservedSpc, _size_type newAddressOffset, _size_type newAlignOffset) : |
| 98 | + AddressAllocatorBase(other, newReservedSpc) |
| 99 | + { |
| 100 | + addressOffset = newAddressOffset; |
| 101 | + alignOffset = newAlignOffset; |
| 102 | + combinedOffset = addressOffset+alignOffset; |
| 103 | + } |
| 104 | + |
| 105 | + inline bool checkResize(_size_type newBuffSz, _size_type newAlignOffset) |
| 106 | + { |
| 107 | + // cannot reallocate the data into smaller storage than is necessary |
| 108 | + if (newBuffSz<safe_shrink_size(0u,maxRequestableAlignment)) return false; |
| 109 | + // need enough space for the new alignment |
| 110 | + if (newAlignOffset>newBuffSz) return false; |
| 111 | + |
| 112 | + return true; |
| 113 | + } |
| 114 | + |
| 115 | + inline _size_type getAddressOffset() const noexcept {return addressOffset;} |
| 116 | + |
| 117 | + inline const void* getReservedSpacePtr() const noexcept {return reservedSpace;} |
| 118 | + |
| 119 | + inline AddressAllocatorBase& operator=(AddressAllocatorBase&& other) |
| 120 | + { |
| 121 | + reservedSpace = other.reservedSpace; |
| 122 | + addressOffset = other.addressOffset; |
| 123 | + alignOffset = other.alignOffset; |
| 124 | + maxRequestableAlignment = other.maxRequestableAlignment; |
| 125 | + combinedOffset = other.combinedOffset; |
| 126 | + other.invalidate(); |
| 127 | + return *this; |
| 128 | + } |
| 129 | + |
| 130 | + inline void invalidate() |
| 131 | + { |
| 132 | + reservedSpace = nullptr; |
| 133 | + addressOffset = invalid_address; |
| 134 | + alignOffset = invalid_address; |
| 135 | + maxRequestableAlignment = invalid_address; |
| 136 | + combinedOffset = invalid_address; |
| 137 | + } |
| 138 | + |
| 139 | + // pointer to allocator specific state-keeping data, please note that irrBaW address allocators were designed to allocate memory they can't actually access |
| 140 | + void* reservedSpace; |
| 141 | + // automatic offset to be added to generated addresses |
| 142 | + _size_type addressOffset; |
| 143 | + // the positive offset that would have to be applied to `addressOffset` to make it `maxRequestableAlignment`-aligned to some unknown value |
| 144 | + _size_type alignOffset; |
| 145 | + // this cannot be deduced from the `addressOffset` , so we let the user specify it |
| 146 | + _size_type maxRequestableAlignment; |
| 147 | + |
| 148 | + //internal usage |
| 149 | + _size_type combinedOffset; |
| 150 | +}; |
153 | 151 |
|
| 152 | +} |
154 | 153 | #endif |
155 | 154 |
|
0 commit comments