yum-mirror/slang

Making it easier to work with shaders

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

Ellie Hermaszewskaformatf65d756bf

master
6.9 KiB274 linesraw
1#ifndef SLANG_CORE_CHUNKED_LIST_H
2#define SLANG_CORE_CHUNKED_LIST_H
3
4#include "slang-allocator.h"
5#include "slang-array-view.h"
6#include "slang-math.h"
7#include "slang.h"
8
9namespace Slang
10{
11// Items stored in a ChunkedList are guaranteed to have fixed address.
12template<typename T, uint32_t defaultChunkSize = 16, typename TAllocator = StandardAllocator>
13class ChunkedList
14{
15private:
16    TAllocator allocator;
17
18    struct Chunk
19    {
20        uint32_t size = 0;
21        uint32_t capacity = defaultChunkSize;
22        Chunk* next = nullptr;
23        T* begin() { return reinterpret_cast<T*>(this + 1); }
24        T* end() { return begin() + size; }
25    };
26
27    struct FirstChunk : public Chunk
28    {
29        T elements[defaultChunkSize];
30    };
31
32    Chunk* allocateChunk(uint32_t size)
33    {
34        auto resultChunk = (Chunk*)allocator.allocate(sizeof(Chunk) + size * sizeof(T));
35        resultChunk->capacity = size;
36        resultChunk->size = 0;
37        resultChunk->next = nullptr;
38        auto firstItem = resultChunk->begin();
39        if (!std::is_trivially_constructible_v<T>)
40        {
41            for (uint32_t i = 0; i < size; i++)
42                new (firstItem + i) T();
43        }
44        return resultChunk;
45    }
46    void freeChunk(Chunk* chunk)
47    {
48        if (!std::is_trivially_destructible_v<T>)
49        {
50            for (uint32_t i = 0; i < chunk->capacity; i++)
51                chunk->begin()[i].~T();
52        }
53        allocator.deallocate(chunk);
54    }
55
56public:
57    typedef ChunkedList<T, defaultChunkSize, TAllocator> ThisType;
58    ChunkedList()
59        : m_lastChunk(&m_firstChunk), m_count(0)
60    {
61    }
62    template<typename... Args>
63    ChunkedList(const T& val, Args... args)
64    {
65        _init(val, args...);
66    }
67    ChunkedList(const ThisType& list)
68        : m_lastChunk(&m_firstChunk), m_count(0)
69    {
70        this->operator=(list);
71    }
72    ChunkedList(ThisType&& list)
73        : m_lastChunk(&m_firstChunk), m_count(0)
74    {
75        this->operator=(static_cast<ThisType&&>(list));
76    }
77    ~ChunkedList() { _deallocateBuffer(); }
78    template<int _otherShortListSize, typename TOtherAllocator>
79    ThisType& operator=(const ChunkedList<T, _otherShortListSize, TOtherAllocator>& list)
80    {
81        clearAndDeallocate();
82        addRange(list);
83        return *this;
84    }
85
86    ThisType& operator=(const ThisType& other)
87    {
88        clearAndDeallocate();
89        addRange(other);
90        return *this;
91    }
92
93    ThisType& operator=(ThisType&& list)
94    {
95        // Could just do a swap here, and memory would be freed on rhs dtor
96        _deallocateBuffer();
97        m_count = list.m_count;
98        m_firstChunk = _Move(list.m_firstChunk);
99        m_lastChunk = list.m_lastChunk;
100        list.m_count = 0;
101        list.m_firstChunk.next = nullptr;
102        list.m_lastChunk = &list.m_firstChunk;
103        list.m_firstChunk.size = 0;
104        return *this;
105    }
106
107    struct Iterator
108    {
109        Chunk* chunk = nullptr;
110        Index index = -1;
111        Iterator& operator++()
112        {
113            ++index;
114            if (index == chunk->size)
115            {
116                index = 0;
117                chunk = chunk->next;
118            }
119            return *this;
120        }
121        Iterator operator++(int)
122        {
123            Iterator rs = *this;
124            operator++();
125            return rs;
126        }
127        T* operator->()
128        {
129            SLANG_ASSERT(chunk);
130            return chunk->begin() + index;
131        }
132        T& operator*()
133        {
134            SLANG_ASSERT(chunk);
135            return chunk->begin()[index];
136        }
137        bool operator==(Iterator other) { return chunk == other.chunk && index == other.index; }
138        bool operator!=(Iterator other) { return index != other.index || chunk != other.chunk; }
139    };
140
141    Iterator begin()
142    {
143        Iterator rs;
144        rs.chunk = &m_firstChunk;
145        rs.index = 0;
146        return rs;
147    }
148    Iterator end()
149    {
150        Iterator rs;
151        rs.chunk = nullptr;
152        rs.index = 0;
153        return rs;
154    }
155
156    Chunk* _maybeReserveForAdd(uint32_t chunkSize)
157    {
158        if (m_lastChunk->capacity - m_lastChunk->size < chunkSize)
159        {
160            auto chunk = allocateChunk(Math::Max(defaultChunkSize, chunkSize));
161            m_lastChunk->next = chunk;
162            m_lastChunk = chunk;
163            return chunk;
164        }
165        return m_lastChunk;
166    }
167
168    T* add(T&& obj)
169    {
170        auto chunk = _maybeReserveForAdd(1);
171        auto result = chunk->begin() + chunk->size;
172        chunk->begin()[chunk->size] = static_cast<T&&>(obj);
173        chunk->size++;
174        m_count++;
175        return result;
176    }
177
178    T* add(const T& obj)
179    {
180        auto chunk = _maybeReserveForAdd(1);
181        auto result = chunk->begin() + chunk->size;
182        chunk->begin()[chunk->size] = obj;
183        chunk->size++;
184        m_count++;
185        return result;
186    }
187
188    Index getCount() const { return m_count; }
189
190    T* addRange(const T* vals, Index n)
191    {
192        Chunk* chunk = _maybeReserveForAdd((uint32_t)n);
193        auto result = chunk->begin() + chunk->size;
194        for (Index i = 0; i < n; i++)
195        {
196            chunk->begin()[chunk->size + i] = vals[i];
197        }
198        chunk->size += (uint32_t)n;
199        m_count += n;
200        return result;
201    }
202
203    T* addRange(ArrayView<T> list) { return addRange(list.m_buffer, list.m_count); }
204
205    T* reserveRange(uint32_t size)
206    {
207        Chunk* chunk = _maybeReserveForAdd((uint32_t)size);
208        auto result = chunk->begin() + chunk->size;
209        chunk->size += size;
210        m_count += size;
211        return result;
212    }
213
214    template<typename TContainer>
215    T* addRange(const TContainer& list)
216    {
217        Chunk* chunk = _maybeReserveForAdd((uint32_t)list.getCount());
218        auto result = chunk->begin() + chunk->size;
219        for (auto& obj : list)
220        {
221            chunk->begin()[chunk->size] = obj;
222            chunk->size++;
223            m_count++;
224        }
225        return result;
226    }
227
228    void clearAndDeallocate()
229    {
230        _deallocateBuffer();
231        m_count = 0;
232        for (auto& item : m_firstChunk.elements)
233            item = T();
234    }
235
236private:
237    Index m_count = 0; ///< The amount of elements
238    FirstChunk m_firstChunk;
239    Chunk* m_lastChunk = &m_firstChunk;
240
241    void _deallocateBuffer()
242    {
243        auto chunk = m_firstChunk.next;
244        while (chunk)
245        {
246            auto nextChunk = chunk->next;
247            freeChunk(chunk);
248            chunk = nextChunk;
249        }
250        m_firstChunk.next = 0;
251        m_firstChunk.size = 0;
252        m_lastChunk = &m_firstChunk;
253    }
254    static inline T* _allocate(Index count)
255    {
256        return AllocateMethod<T, TAllocator>::allocateArray(count);
257    }
258    static inline void _free(T* ptr, Index count)
259    {
260        return AllocateMethod<T, TAllocator>::deallocateArray(ptr, count);
261    }
262
263    template<typename... Args>
264    void _init(const T& val, Args... args)
265    {
266        add(val);
267        _init(args...);
268    }
269
270    void _init() {}
271};
272} // namespace Slang
273
274#endif