yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

Ellie Hermaszewskaformatf65d756bf

master
5.4 KiB232 linesraw
1#include "slang-free-list.h"
2
3// #include "list.h"
4
5namespace Slang
6{
7
8FreeList::~FreeList()
9{
10    _deallocateBlocks(m_activeBlocks);
11    _deallocateBlocks(m_freeBlocks);
12}
13
14void FreeList::_init()
15{
16    m_top = nullptr;
17    m_end = nullptr;
18
19    m_activeBlocks = nullptr;
20    m_freeBlocks = nullptr;
21
22    m_freeElements = nullptr;
23
24    m_elementSize = 0;
25    m_alignment = 1;
26    m_blockSize = 0;
27    m_blockAllocationSize = 0;
28}
29
30void FreeList::_init(size_t elementSize, size_t alignment, size_t elemsPerBlock)
31{
32    alignment = (alignment < sizeof(void*)) ? sizeof(void*) : alignment;
33
34    // Alignment must be a power of 2
35    assert(((alignment - 1) & alignment) == 0);
36
37    // The elementSize must at least be at least the same size as the alignment
38    elementSize = (elementSize >= alignment) ? elementSize : alignment;
39    m_blockSize = elementSize * elemsPerBlock;
40    m_elementSize = elementSize;
41    m_alignment = alignment;
42
43    // Calculate the block size need, correcting for alignment
44    const size_t alignedBlockSize = (alignment <= DEFAULT_ALIGNMENT)
45                                        ? _calcAlignedBlockSize(DEFAULT_ALIGNMENT)
46                                        : _calcAlignedBlockSize(alignment);
47
48    // Make the block struct size aligned
49    m_blockAllocationSize = m_blockSize + alignedBlockSize;
50
51    m_top = nullptr;
52    m_end = nullptr;
53
54    m_activeBlocks = nullptr;
55    m_freeBlocks = nullptr; ///< Blocks that there are no allocations in
56
57    m_freeElements = nullptr;
58}
59
60void FreeList::init(size_t elementSize, size_t alignment, size_t elemsPerBlock)
61{
62    _deallocateBlocks(m_activeBlocks);
63    _deallocateBlocks(m_freeBlocks);
64    _init(elementSize, alignment, elemsPerBlock);
65}
66
67void FreeList::swapWith(ThisType& rhs)
68{
69    Swap(m_top, rhs.m_top);
70    Swap(m_end, rhs.m_end);
71
72    Swap(m_activeBlocks, rhs.m_activeBlocks);
73    Swap(m_freeBlocks, rhs.m_freeBlocks);
74
75    Swap(m_freeElements, rhs.m_freeElements);
76
77    Swap(m_elementSize, rhs.m_elementSize);
78    Swap(m_alignment, rhs.m_alignment);
79    Swap(m_blockSize, rhs.m_blockSize);
80    Swap(m_blockAllocationSize, rhs.m_blockAllocationSize);
81}
82
83void FreeList::_deallocateBlocks(Block* block)
84{
85    while (block)
86    {
87        Block* next = block->m_next;
88
89#ifdef SLANG_FREE_LIST_INIT_MEM
90        Memory::set(block, 0xfd, m_blockAllocationSize);
91#endif
92
93        ::free(block); // deallocate(block, m_blockAllocationSize);
94        block = next;
95    }
96}
97
98bool FreeList::isValidAllocation(const void* dataIn) const
99{
100    uint8_t* data = (uint8_t*)dataIn;
101
102    Block* block = m_activeBlocks;
103    while (block)
104    {
105        uint8_t* start = block->m_data;
106        uint8_t* end = start + m_blockSize;
107
108        if (data >= start && data < end)
109        {
110            // Check it's aligned correctly
111            if ((data - start) % m_elementSize)
112            {
113                return false;
114            }
115
116            // Non allocated data is between top and end
117            if (data >= m_top && data < m_end)
118            {
119                return false;
120            }
121
122            // It can't be in the free list
123            Element* ele = m_freeElements;
124            while (ele)
125            {
126                if (ele == (Element*)data)
127                {
128                    return false;
129                }
130
131                ele = ele->m_next;
132            }
133            return true;
134        }
135
136        block = block->m_next;
137    }
138    // It's not in an active block -> it cannot be a valid allocation
139    return false;
140}
141
142void* FreeList::_allocate()
143{
144    Block* block = m_freeBlocks;
145    if (block)
146    {
147        /// Remove from the free blocks
148        m_freeBlocks = block->m_next;
149    }
150    else
151    {
152        // block = (Block*)m_allocator->allocate(m_blockAllocationSize);
153        block = (Block*)::malloc(m_blockAllocationSize);
154        if (!block)
155        {
156            // Allocation failed... doh
157            return nullptr;
158        }
159        // Do the alignment
160        {
161            size_t fix = (size_t(block) + sizeof(Block) + m_alignment - 1) & ~(m_alignment - 1);
162            block->m_data = (uint8_t*)fix;
163        }
164    }
165
166    // Attach to the active blocks
167    block->m_next = m_activeBlocks;
168    m_activeBlocks = block;
169
170    // Set up top and end
171    m_end = block->m_data + m_blockSize;
172
173    // Return the first element
174    uint8_t* element = block->m_data;
175    m_top = element + m_elementSize;
176
177    SLANG_FREE_LIST_INIT_ALLOCATE(element)
178
179    return element;
180}
181
182void FreeList::deallocateAll()
183{
184    Block* block = m_activeBlocks;
185    if (block)
186    {
187        // Find the end block
188        while (block->m_next)
189        {
190#ifdef SLANG_FREE_LIST_INIT_MEM
191            Memory::set(block->m_data, 0xfd, m_blockSize);
192#endif
193            block = block->m_next;
194        }
195        // Attach to the freeblocks
196        block->m_next = m_freeBlocks;
197        // The list is now all freelists
198        m_freeBlocks = m_activeBlocks;
199        // There are no active blocks
200        m_activeBlocks = nullptr;
201    }
202
203    m_top = nullptr;
204    m_end = nullptr;
205}
206
207void FreeList::reset()
208{
209    _deallocateBlocks(m_activeBlocks);
210    _deallocateBlocks(m_freeBlocks);
211
212    m_top = nullptr;
213    m_end = nullptr;
214
215    m_activeBlocks = nullptr;
216    m_freeBlocks = nullptr;
217
218    m_freeElements = nullptr;
219}
220
221
222void FreeList::_initAllocate(void* mem)
223{
224    ::memset(mem, 0xcd, m_elementSize);
225}
226
227void FreeList::_initDeallocate(void* mem)
228{
229    ::memset(mem, 0xfd, m_elementSize);
230}
231
232} // namespace Slang