Skip to content

Commit 8bdc6c8

Browse files
committed
First commit
1 parent f4b2626 commit 8bdc6c8

File tree

4 files changed

+442
-260
lines changed

4 files changed

+442
-260
lines changed

include/nbl/core/containers/FixedCapacityDoublyLinkedList.h

Lines changed: 15 additions & 260 deletions
Original file line numberDiff line numberDiff line change
@@ -6,281 +6,36 @@
66
#define __NBL_CORE_FIXED_CAPACITY_DOUBLY_LINKED_LIST_H_INCLUDED__
77

88

9-
#include "nbl/core/alloc/PoolAddressAllocator.h"
10-
#include "nbl/core/decl/Types.h"
11-
12-
#include <functional>
9+
#include "nbl/core/containers/lists/DoublyLinkedListBase.h"
1310

1411
namespace nbl
1512
{
1613
namespace core
1714
{
1815

19-
namespace impl
20-
{
21-
class FixedCapacityDoublyLinkedListBase
22-
{
23-
public:
24-
_NBL_STATIC_INLINE_CONSTEXPR uint32_t invalid_iterator = PoolAddressAllocator<uint32_t>::invalid_address;
25-
protected:
26-
27-
FixedCapacityDoublyLinkedListBase() = default;
28-
29-
template<typename T>
30-
FixedCapacityDoublyLinkedListBase(const uint32_t capacity, void*& _reservedSpace, T*& _array)
31-
{
32-
const auto firstPart = core::alignUp(PoolAddressAllocator<uint32_t>::reserved_size(1u,capacity,1u),alignof(T));
33-
_reservedSpace = _NBL_ALIGNED_MALLOC(firstPart+capacity*sizeof(T),alignof(T));
34-
_array = reinterpret_cast<T*>(reinterpret_cast<uint8_t*>(_reservedSpace)+firstPart);
35-
}
36-
};
37-
}
38-
39-
//Struct for use in a doubly linked list. Stores data and pointers to next and previous elements the list, or invalid iterator if it is first/last
4016
template<typename Value>
41-
struct alignas(void*) SDoublyLinkedNode
17+
class FixedCapacityDoublyLinkedList : public DoublyLinkedListBase<Value>
4218
{
43-
_NBL_STATIC_INLINE_CONSTEXPR uint32_t invalid_iterator = impl::FixedCapacityDoublyLinkedListBase::invalid_iterator;
19+
public:
20+
using base_t = DoublyLinkedListBase<Value>;
21+
using disposal_func_t = typename base_t::disposal_func_t;
4422

45-
Value data;
46-
uint32_t prev;
47-
uint32_t next;
48-
49-
SDoublyLinkedNode() {}
50-
SDoublyLinkedNode(const Value& val) : data(val)
51-
{
52-
prev = invalid_iterator;
53-
next = invalid_iterator;
54-
}
55-
SDoublyLinkedNode(Value&& val) : data(std::move(val))
56-
{
57-
prev = invalid_iterator;
58-
next = invalid_iterator;
59-
}
60-
SDoublyLinkedNode(SDoublyLinkedNode<Value>&& other) : data(std::move(other.data)), prev(std::move(other.prev)), next(std::move(other.next))
61-
{}
62-
63-
~SDoublyLinkedNode()
23+
//Constructor, capacity determines the amount of allocated space
24+
FixedCapacityDoublyLinkedList(const uint32_t capacity, disposal_func_t&& dispose_f = disposal_func_t()) : base_t(capacity, std::move(dispose_f))
6425
{}
6526

66-
SDoublyLinkedNode<Value>& operator=(const SDoublyLinkedNode<Value>& other)
67-
{
68-
this->data = other.data;
69-
this->prev = other.prev;
70-
this->next = other.next;
71-
return *this;
72-
}
73-
74-
SDoublyLinkedNode<Value>& operator=(SDoublyLinkedNode<Value>&& other)
75-
{
76-
this->data = std::move(other.data);
77-
this->prev = std::move(other.prev);
78-
this->next = std::move(other.next);
79-
return *this;
80-
}
81-
};
82-
83-
template<typename Value>
84-
class FixedCapacityDoublyLinkedList : private impl::FixedCapacityDoublyLinkedListBase
85-
{
86-
public:
87-
using AddressAllocator = PoolAddressAllocator<uint32_t>;
88-
_NBL_STATIC_INLINE_CONSTEXPR uint32_t invalid_iterator = impl::FixedCapacityDoublyLinkedListBase::invalid_iterator;
89-
90-
using disposal_func_t = std::function<void(Value&)>;
91-
92-
using node_t = SDoublyLinkedNode<Value>;
93-
94-
// get the fixed capacity
95-
inline uint32_t getCapacity() const { return cap; }
27+
FixedCapacityDoublyLinkedList() = default;
9628

97-
//get node at iterator
98-
inline node_t* get(const uint32_t address)
99-
{
100-
return (m_array + address);
101-
}
102-
inline const node_t* get(const uint32_t address) const
103-
{
104-
return (m_array + address);
105-
}
29+
FixedCapacityDoublyLinkedList(const FixedCapacityDoublyLinkedList& other) = delete;
10630

107-
//remove the last element in the list
108-
inline void popBack()
109-
{
110-
if (m_back == invalid_iterator)
111-
return;
31+
FixedCapacityDoublyLinkedList& operator=(const FixedCapacityDoublyLinkedList& other) = delete;
11232

113-
auto backNode = getBack();
114-
if (backNode->prev != invalid_iterator)
115-
get(backNode->prev)->next = invalid_iterator;
116-
uint32_t temp = m_back;
117-
m_back = backNode->prev;
118-
common_delete(temp);
119-
}
120-
121-
//add new item to the list. This function does not make space to store the new node. in case the list is full, popBack() needs to be called beforehand
122-
inline void pushFront(Value&& val)
123-
{
124-
insertAt(reserveAddress(), std::move(val));
125-
}
126-
127-
template <typename... Args>
128-
inline void emplaceFront(Args&&... args)
129-
{
130-
insertAt(reserveAddress(), Value(std::forward<Args>(args)...));
131-
}
132-
133-
//get node ptr of the first item in the list
134-
inline node_t* getBegin() { return m_array + m_begin; }
135-
inline const node_t* getBegin() const { return m_array + m_begin; }
136-
137-
//get node ptr of the last item in the list
138-
inline node_t* getBack() { return m_array + m_back; }
139-
inline const node_t* getBack() const { return m_array + m_back; }
140-
141-
//get index/iterator of the first element
142-
inline uint32_t getFirstAddress() const { return m_begin; }
143-
144-
//get index/iterator of the last element
145-
inline uint32_t getLastAddress() const { return m_back; }
146-
147-
//remove a node at nodeAddr from the list
148-
inline void erase(const uint32_t nodeAddr)
149-
{
150-
assert(nodeAddr != invalid_iterator);
151-
assert(nodeAddr < cap);
152-
node_t* node = get(nodeAddr);
153-
154-
if (m_back == nodeAddr)
155-
m_back = node->prev;
156-
if (m_begin == nodeAddr)
157-
m_begin = node->next;
158-
159-
common_detach(node);
160-
common_delete(nodeAddr);
161-
}
162-
163-
//move a node at nodeAddr to the front of the list
164-
inline void moveToFront(const uint32_t nodeAddr)
165-
{
166-
if (m_begin == nodeAddr || nodeAddr == invalid_iterator)
167-
return;
168-
169-
getBegin()->prev = nodeAddr;
170-
171-
auto node = get(nodeAddr);
172-
173-
if (m_back == nodeAddr)
174-
m_back = node->prev;
175-
176-
common_detach(node);
177-
node->next = m_begin;
178-
node->prev = invalid_iterator;
179-
m_begin = nodeAddr;
180-
}
181-
182-
//Constructor, capacity determines the amount of allocated space
183-
FixedCapacityDoublyLinkedList(const uint32_t capacity, disposal_func_t&& dispose_f = disposal_func_t()) :
184-
FixedCapacityDoublyLinkedListBase(capacity,m_reservedSpace,m_array),
185-
m_dispose_f(std::move(dispose_f))
186-
{
187-
addressAllocator = std::unique_ptr<AddressAllocator>(new AddressAllocator(m_reservedSpace, 0u, 0u, 1u, capacity, 1u));
188-
cap = capacity;
189-
m_back = invalid_iterator;
190-
m_begin = invalid_iterator;
191-
}
192-
193-
FixedCapacityDoublyLinkedList() = default;
194-
195-
FixedCapacityDoublyLinkedList(const FixedCapacityDoublyLinkedList& other) = delete;
196-
197-
FixedCapacityDoublyLinkedList& operator=(const FixedCapacityDoublyLinkedList& other) = delete;
198-
199-
FixedCapacityDoublyLinkedList& operator=(FixedCapacityDoublyLinkedList&& other)
200-
{
201-
addressAllocator = std::move(other.addressAllocator);
202-
m_reservedSpace = std::move(other.m_reservedSpace);
203-
m_array = std::move(other.m_array);
204-
m_dispose_f = std::move(other.m_dispose_f);
205-
cap = other.cap;
206-
m_back = other.m_back;
207-
m_begin = other.m_begin;
208-
209-
// Nullify other
210-
other.addressAllocator = nullptr;
211-
other.m_reservedSpace = nullptr;
212-
other.m_array = nullptr;
213-
other.cap = 0u;
214-
other.m_back = 0u;
215-
other.m_begin = 0u;
216-
return *this;
217-
}
218-
219-
~FixedCapacityDoublyLinkedList()
220-
{
221-
if (m_dispose_f && m_begin != invalid_iterator)
222-
{
223-
auto* begin = getBegin();
224-
auto* back = getBack();
225-
do
226-
{
227-
m_dispose_f(begin->data);
228-
begin = get(begin->next);
229-
} while (begin != back);
230-
}
231-
_NBL_ALIGNED_FREE(m_reservedSpace);
232-
}
233-
234-
235-
private:
236-
std::unique_ptr<AddressAllocator> addressAllocator;
237-
void* m_reservedSpace;
238-
node_t* m_array;
239-
240-
uint32_t cap;
241-
uint32_t m_back;
242-
uint32_t m_begin;
243-
244-
disposal_func_t m_dispose_f;
245-
246-
//allocate and get the address of the next free node
247-
inline uint32_t reserveAddress()
248-
{
249-
uint32_t addr = addressAllocator->alloc_addr(1u, 1u);
250-
return addr;
251-
}
252-
253-
//create a new node which stores data at already allocated address,
254-
inline void insertAt(uint32_t addr, Value&& val)
255-
{
256-
assert(addr < cap);
257-
assert(addr != invalid_iterator);
258-
SDoublyLinkedNode<Value>* n = new(m_array + addr) SDoublyLinkedNode<Value>(std::move(val));
259-
n->prev = invalid_iterator;
260-
n->next = m_begin;
261-
262-
if (m_begin != invalid_iterator)
263-
getBegin()->prev = addr;
264-
if (m_back == invalid_iterator)
265-
m_back = addr;
266-
m_begin = addr;
267-
}
268-
269-
inline void common_delete(uint32_t address)
270-
{
271-
if (m_dispose_f)
272-
m_dispose_f(get(address)->data);
273-
get(address)->~node_t();
274-
addressAllocator->free_addr(address, 1u);
275-
}
33+
FixedCapacityDoublyLinkedList& operator=(FixedCapacityDoublyLinkedList&& other)
34+
{
35+
base_t::operator=(other);
36+
}
27637

277-
inline void common_detach(node_t* node)
278-
{
279-
if (node->next != invalid_iterator)
280-
get(node->next)->prev = node->prev;
281-
if (node->prev != invalid_iterator)
282-
get(node->prev)->next = node->next;
283-
}
38+
~FixedCapacityDoublyLinkedList() = default;
28439
};
28540

28641

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O.
2+
// This file is part of the "Nabla Engine".
3+
// For conditions of distribution and use, see copyright notice in nabla.h
4+
5+
#ifndef __NBL_CORE_GROWABLE_DOUBLY_LINKED_LIST_H_INCLUDED__
6+
#define __NBL_CORE_GROWABLE_DOUBLY_LINKED_LIST_H_INCLUDED__
7+
8+
9+
#include "nbl/core/containers/lists/DoublyLinkedListBase.h"
10+
11+
namespace nbl
12+
{
13+
namespace core
14+
{
15+
16+
template<typename Value>
17+
class GrowableDoublyLinkedList : public DoublyLinkedListBase<Value>
18+
{
19+
public:
20+
using base_t = DoublyLinkedListBase<Value>;
21+
using value_t = Value;
22+
using node_t = typename base_t::node_t;
23+
using address_allocator_t = typename base_t::address_allocator_t;
24+
using disposal_func_t = typename base_t::disposal_func_t;
25+
26+
//Constructor, capacity determines the amount of allocated space
27+
GrowableDoublyLinkedList(const uint32_t capacity, disposal_func_t&& dispose_f = disposal_func_t()) : base_t(capacity, std::move(dispose_f))
28+
{}
29+
30+
GrowableDoublyLinkedList() = default;
31+
32+
GrowableDoublyLinkedList(const GrowableDoublyLinkedList& other) = delete;
33+
34+
GrowableDoublyLinkedList& operator=(const GrowableDoublyLinkedList& other) = delete;
35+
36+
GrowableDoublyLinkedList& operator=(GrowableDoublyLinkedList&& other)
37+
{
38+
base_t::operator=(other);
39+
}
40+
41+
~GrowableDoublyLinkedList() = default;
42+
43+
inline void grow(uint32_t newCapacity)
44+
{
45+
const auto firstPart = core::alignUp(address_allocator_t::reserved_size(1u, newCapacity, 1u), alignof(node_t));
46+
void* newReservedSpace = _NBL_ALIGNED_MALLOC(firstPart + newCapacity * sizeof(node_t), alignof(node_t));
47+
node_t* newArray = reinterpret_cast<node_t*>(reinterpret_cast<uint8_t*>(newReservedSpace) + firstPart);
48+
49+
memcpy(reinterpret_cast<void*>(newArray), reinterpret_cast<void*>(this->m_array), m_cap * sizeof(node_t));
50+
51+
//this->m_addressAllocator = std::unique_ptr<address_allocator_t>(new address_allocator_t(newCapacity, std::move(this->m_addressAllocator)));
52+
this->m_cap = capacity;
53+
this->m_back = invalid_iterator;
54+
this->m_begin = invalid_iterator;
55+
}
56+
};
57+
58+
59+
}
60+
}
61+
62+
63+
#endif

0 commit comments

Comments
 (0)