Skip to content

Commit dea34a1

Browse files
committed
Merge branch 'dtm' of github.com:Devsh-Graphics-Programming/Nabla into dtm
2 parents b6534f5 + 716aaf2 commit dea34a1

File tree

2 files changed

+115
-49
lines changed

2 files changed

+115
-49
lines changed

include/nbl/core/containers/DoublyLinkedList.h

Lines changed: 71 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,14 @@ template<typename Value, class allocator = core::allocator<SDoublyLinkedNode<Val
6969
class DoublyLinkedList
7070
{
7171
public:
72+
template <bool Mutable>
7273
class Iterator;
74+
template <bool Mutable>
7375
friend class Iterator;
7476

77+
using iterator = Iterator<true>;
78+
using const_iterator = Iterator<false>;
79+
7580
using allocator_t = allocator;
7681
using allocator_traits_t = std::allocator_traits<allocator_t>;
7782
using address_allocator_t = PoolAddressAllocator<uint32_t>;
@@ -236,16 +241,43 @@ class DoublyLinkedList
236241
// Offset the array start by the storage used by the address allocator
237242
m_array = reinterpret_cast<node_t*>(reinterpret_cast<uint8_t*>(m_reservedSpace) + addressAllocatorStorageSize * sizeof(node_t));
238243

239-
m_addressAllocator = address_allocator_t(m_reservedSpace, 0u, 0u, 1u, capacity, 1u);
240244
// If allocation failed, create list with no capacity to indicate creation failed
241245
m_cap = m_reservedSpace ? capacity : 0;
242-
m_back = invalid_iterator;
243-
m_begin = invalid_iterator;
246+
m_addressAllocator = address_allocator_t(m_reservedSpace, 0u, 0u, 1u, m_cap, 1u);
244247
}
245248

246249
DoublyLinkedList() = default;
247250

248-
DoublyLinkedList(const DoublyLinkedList& other) = delete;
251+
// Copy Constructor
252+
explicit DoublyLinkedList(const DoublyLinkedList& other) : m_dispose_f(other.m_dispose_f), m_allocator(other.m_allocator)
253+
{
254+
const size_t addressAllocatorStorageSize = (address_allocator_t::reserved_size(1u, other.m_cap, 1u) + sizeof(node_t) - 1) / sizeof(node_t);
255+
m_currentAllocationSize = addressAllocatorStorageSize + other.m_cap;
256+
m_reservedSpace = reinterpret_cast<void*>(allocator_traits_t::allocate(m_allocator, m_currentAllocationSize));
257+
// If allocation failed, create a list with no capacity
258+
m_cap = m_reservedSpace ? other.m_cap : 0;
259+
if (!m_cap) return; // Allocation failed
260+
// Offset the array start by the storage used by the address allocator
261+
m_array = reinterpret_cast<node_t*>(reinterpret_cast<uint8_t*>(m_reservedSpace) + addressAllocatorStorageSize * sizeof(node_t));
262+
263+
if constexpr (std::is_trivially_copyable_v<Value>)
264+
{
265+
// Create new address allocator by copying state
266+
m_addressAllocator = address_allocator_t(m_cap, other.m_addressAllocator, m_reservedSpace);
267+
// Copy memory over
268+
memcpy(m_array, other.m_array, m_cap * sizeof(node_t));
269+
m_back = other.m_back;
270+
m_begin = other.m_begin;
271+
}
272+
else
273+
{
274+
m_addressAllocator = address_allocator_t(m_reservedSpace, 0u, 0u, 1u, m_cap, 1u);
275+
// Reverse iteration since we push from the front
276+
for (auto it = other.crbegin(); it != other.crend(); it++)
277+
pushFront(value_t(*it));
278+
279+
}
280+
}
249281

250282
DoublyLinkedList& operator=(const DoublyLinkedList& other) = delete;
251283

@@ -277,14 +309,14 @@ class DoublyLinkedList
277309
}
278310

279311
// Iterator stuff
280-
Iterator begin();
281-
Iterator end();
282-
Iterator cbegin() const;
283-
Iterator cend() const;
284-
std::reverse_iterator<Iterator> rbegin();
285-
std::reverse_iterator<Iterator> rend();
286-
std::reverse_iterator<Iterator> crbegin() const;
287-
std::reverse_iterator<Iterator> crend() const;
312+
iterator begin();
313+
iterator end();
314+
const_iterator cbegin() const;
315+
const_iterator cend() const;
316+
std::reverse_iterator<iterator> rbegin();
317+
std::reverse_iterator<iterator> rend();
318+
std::reverse_iterator<const_iterator> crbegin() const;
319+
std::reverse_iterator<const_iterator> crend() const;
288320

289321
private:
290322
//allocate and get the address of the next free node
@@ -352,22 +384,23 @@ class DoublyLinkedList
352384
node_t* m_array;
353385

354386
uint32_t m_cap;
355-
uint32_t m_back;
356-
uint32_t m_begin;
387+
uint32_t m_back = invalid_iterator;
388+
uint32_t m_begin = invalid_iterator;
357389
disposal_func_t m_dispose_f;
358390
};
359391

360392
// ---------------------------------------------------- ITERATOR -----------------------------------------------------------
361393

362394
// Satifies std::bidirectional_iterator
363395
template<typename Value, class allocator>
396+
template<bool Mutable>
364397
class DoublyLinkedList<Value, allocator>::Iterator
365398
{
366-
using iterable_t = DoublyLinkedList<Value, allocator>;
367-
using this_t = iterable_t::Iterator;
368-
friend class iterable_t;
399+
using base_iterable_t = DoublyLinkedList<Value, allocator>;
400+
using iterable_t = std::conditional_t<Mutable, base_iterable_t, const base_iterable_t>;
401+
friend class base_iterable_t;
369402
public:
370-
using value_type = const Value;
403+
using value_type = std::conditional_t<Mutable, Value, const Value>;
371404
using pointer = value_type*;
372405
using reference = value_type&;
373406
using difference_type = int32_t;
@@ -409,68 +442,68 @@ class DoublyLinkedList<Value, allocator>::Iterator
409442
}
410443

411444
//Deref
412-
value_type& operator*() const
445+
reference operator*() const
413446
{
414447
return m_iterable->get(m_current)->data;
415448
}
416449

417-
value_type* operator->() const
450+
pointer operator->() const
418451
{
419452
return & operator*();
420453
}
421454
private:
422-
DoublyLinkedList<Value, allocator>::Iterator(const iterable_t* const iterable, uint32_t idx) : m_iterable(iterable), m_current(idx) {}
455+
Iterator(iterable_t* const iterable, uint32_t idx) : m_iterable(iterable), m_current(idx) {}
423456

424-
const iterable_t* m_iterable;
457+
iterable_t* m_iterable;
425458
uint32_t m_current;
426459
};
427460

428461
template<typename Value, class allocator>
429-
DoublyLinkedList<Value, allocator>::Iterator DoublyLinkedList<Value, allocator>::begin()
462+
DoublyLinkedList<Value, allocator>::iterator DoublyLinkedList<Value, allocator>::begin()
430463
{
431-
return Iterator(this, m_begin);
464+
return iterator(this, m_begin);
432465
}
433466

434467
template<typename Value, class allocator>
435-
DoublyLinkedList<Value, allocator>::Iterator DoublyLinkedList<Value, allocator>::cbegin() const
468+
DoublyLinkedList<Value, allocator>::const_iterator DoublyLinkedList<Value, allocator>::cbegin() const
436469
{
437-
return Iterator(this, m_begin);
470+
return const_iterator(this, m_begin);
438471
}
439472

440473
template<typename Value, class allocator>
441-
DoublyLinkedList<Value, allocator>::Iterator DoublyLinkedList<Value, allocator>::end()
474+
DoublyLinkedList<Value, allocator>::iterator DoublyLinkedList<Value, allocator>::end()
442475
{
443-
return Iterator(this, invalid_iterator);
476+
return iterator(this, invalid_iterator);
444477
}
445478

446479
template<typename Value, class allocator>
447-
DoublyLinkedList<Value, allocator>::Iterator DoublyLinkedList<Value, allocator>::cend() const
480+
DoublyLinkedList<Value, allocator>::const_iterator DoublyLinkedList<Value, allocator>::cend() const
448481
{
449-
return Iterator(this, invalid_iterator);
482+
return const_iterator(this, invalid_iterator);
450483
}
451484

452485
template<typename Value, class allocator>
453-
std::reverse_iterator<typename DoublyLinkedList<Value, allocator>::Iterator> DoublyLinkedList<Value, allocator>::rbegin()
486+
std::reverse_iterator<typename DoublyLinkedList<Value, allocator>::iterator> DoublyLinkedList<Value, allocator>::rbegin()
454487
{
455-
return std::reverse_iterator<Iterator>(Iterator(this, invalid_iterator));
488+
return std::reverse_iterator<iterator>(iterator(this, invalid_iterator));
456489
}
457490

458491
template<typename Value, class allocator>
459-
std::reverse_iterator<typename DoublyLinkedList<Value, allocator>::Iterator> DoublyLinkedList<Value, allocator>::crbegin() const
492+
std::reverse_iterator<typename DoublyLinkedList<Value, allocator>::const_iterator> DoublyLinkedList<Value, allocator>::crbegin() const
460493
{
461-
return std::reverse_iterator<Iterator>(Iterator(this, invalid_iterator));
494+
return std::reverse_iterator<const_iterator>(const_iterator(this, invalid_iterator));
462495
}
463496

464497
template<typename Value, class allocator>
465-
std::reverse_iterator<typename DoublyLinkedList<Value, allocator>::Iterator> DoublyLinkedList<Value, allocator>::rend()
498+
std::reverse_iterator<typename DoublyLinkedList<Value, allocator>::iterator> DoublyLinkedList<Value, allocator>::rend()
466499
{
467-
return std::reverse_iterator<Iterator>(Iterator(this, m_begin));
500+
return std::reverse_iterator<iterator>(iterator(this, m_begin));
468501
}
469502

470503
template<typename Value, class allocator>
471-
std::reverse_iterator<typename DoublyLinkedList<Value, allocator>::Iterator> DoublyLinkedList<Value, allocator>::crend() const
504+
std::reverse_iterator<typename DoublyLinkedList<Value, allocator>::const_iterator> DoublyLinkedList<Value, allocator>::crend() const
472505
{
473-
return std::reverse_iterator<Iterator>(Iterator(this, m_begin));
506+
return std::reverse_iterator<const_iterator>(const_iterator(this, m_begin));
474507
}
475508

476509
} //namespace core

include/nbl/core/containers/LRUCache.h

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ class LRUCacheBase
3838
LRUCacheBase(const uint32_t capacity, MapHash&& _hash, MapEquals&& _equals, disposal_func_t&& df) : m_list(capacity, std::move(df)), m_hash(std::move(_hash)), m_equals(std::move(_equals)), searchedKey(nullptr)
3939
{ }
4040

41+
LRUCacheBase(const LRUCacheBase& other) : m_list(other.m_list), m_hash(other.m_hash), m_equals(other.m_equals), searchedKey(nullptr) {}
42+
4143
public:
4244
inline const Key& getReference(const uint32_t nodeAddr) const
4345
{
@@ -221,6 +223,19 @@ class [[deprecated]] LRUCache : protected impl::LRUCacheBase<Key,Value,MapHash,M
221223
unordered_set<uint32_t,WrapHash,WrapEquals> m_shortcut_map;
222224
};
223225

226+
namespace impl
227+
{
228+
template<typename EvictionCallback, typename Value>
229+
concept LRUCacheValueEvictionCallback = std::invocable<EvictionCallback, const Value&>;
230+
231+
template<typename EvictionCallback, typename Key, typename Value>
232+
concept LRUCacheKeyValueEvictionCallback = std::invocable<EvictionCallback, const Key&, const Value&>;
233+
234+
template<typename EvictionCallback, typename Key, typename Value>
235+
concept LRUCacheInsertEvictionCallback = LRUCacheValueEvictionCallback<EvictionCallback, Value>
236+
|| LRUCacheKeyValueEvictionCallback<EvictionCallback, Key, Value>;
237+
} //namespace impl
238+
224239
// Key-Value Least Recently Used cache
225240
// Capacity can be increased at user's will
226241
// When the cache is full inserting will remove the least used entry
@@ -278,7 +293,8 @@ class ResizableLRUCache : protected impl::LRUCacheBase<Key, Value, MapHash, MapE
278293

279294
public:
280295
// Keep it simple
281-
using Iterator = list_t::Iterator;
296+
using iterator = typename list_t::iterator;
297+
using const_iterator = typename list_t::const_iterator;
282298

283299
using disposal_func_t = typename base_t::disposal_func_t;
284300
using assoc_t = typename base_t::list_value_t;
@@ -292,6 +308,15 @@ class ResizableLRUCache : protected impl::LRUCacheBase<Key, Value, MapHash, MapE
292308
}
293309
ResizableLRUCache() = delete;
294310

311+
// It's not possible to copy the unordered_set memory-wise and just change hashing and KeyEquals functions unfortunately
312+
// (in the general case that wouldn't make sense but it does here due to the way the wrappers work)
313+
// Anyway, we must iterate over the old cache and copy the map over
314+
explicit ResizableLRUCache(const ResizableLRUCache& other) : base_t(other), m_capacity(other.m_capacity),
315+
m_shortcut_map(other.m_shortcut_map.cbegin(), other.m_shortcut_map.cend(), other.m_capacity >> 2, WrapHash{this}, WrapEquals{this})
316+
{
317+
m_shortcut_map.reserve(m_capacity);
318+
}
319+
295320
inline void print(core::smart_refctd_ptr<system::ILogger> logger)
296321
{
297322
logger->log("Printing LRU cache contents");
@@ -326,7 +351,7 @@ class ResizableLRUCache : protected impl::LRUCacheBase<Key, Value, MapHash, MapE
326351
return stringStream.str();
327352
}
328353

329-
template<typename K, typename V, std::invocable<const Value&> EvictionCallback> requires std::is_constructible_v<Value, V> // && (std::is_same_v<Value,V> || std::is_assignable_v<Value,V>) // is_assignable_v<int, int&> returns false :(
354+
template<typename K, typename V, typename EvictionCallback> requires std::is_constructible_v<Value, V> && impl::LRUCacheInsertEvictionCallback<EvictionCallback, Key, Value>// && (std::is_same_v<Value,V> || std::is_assignable_v<Value,V>) // is_assignable_v<int, int&> returns false :(
330355
inline Value* insert(K&& k, V&& v, EvictionCallback&& evictCallback)
331356
{
332357
bool success;
@@ -342,7 +367,15 @@ class ResizableLRUCache : protected impl::LRUCacheBase<Key, Value, MapHash, MapE
342367
const bool overflow = size() >= base_t::m_list.getCapacity();
343368
if (overflow)
344369
{
345-
evictCallback(base_t::m_list.getBack()->data.second);
370+
if constexpr (impl::LRUCacheValueEvictionCallback<EvictionCallback, Value>)
371+
{
372+
evictCallback(base_t::m_list.getBack()->data.second);
373+
}
374+
// LRUCacheKeyValueEvictionCallback
375+
else
376+
{
377+
evictCallback(base_t::m_list.getBack()->data.first, base_t::m_list.getBack()->data.second);
378+
}
346379
m_shortcut_map.erase(base_t::m_list.getLastAddress());
347380
base_t::m_list.popBack();
348381
}
@@ -446,14 +479,14 @@ class ResizableLRUCache : protected impl::LRUCacheBase<Key, Value, MapHash, MapE
446479

447480
// Iterator stuff
448481
// Normal iterator order is MRU -> LRU
449-
Iterator begin() { return base_t::m_list.begin(); }
450-
Iterator end() { return base_t::m_list.end(); }
451-
Iterator cbegin() const { return base_t::m_list.cbegin(); }
452-
Iterator cend() const { return base_t::m_list.cend(); }
453-
std::reverse_iterator<Iterator> rbegin() { return base_t::m_list.rbegin(); }
454-
std::reverse_iterator<Iterator> rend() { return base_t::m_list.rend(); }
455-
std::reverse_iterator<Iterator> crbegin() const { return base_t::m_list.crbegin(); }
456-
std::reverse_iterator<Iterator> crend() const { return base_t::m_list.crend(); }
482+
iterator begin() { return base_t::m_list.begin(); }
483+
iterator end() { return base_t::m_list.end(); }
484+
const_iterator cbegin() const { return base_t::m_list.cbegin(); }
485+
const_iterator cend() const { return base_t::m_list.cend(); }
486+
std::reverse_iterator<iterator> rbegin() { return base_t::m_list.rbegin(); }
487+
std::reverse_iterator<iterator> rend() { return base_t::m_list.rend(); }
488+
std::reverse_iterator<const_iterator> crbegin() const { return base_t::m_list.crbegin(); }
489+
std::reverse_iterator<const_iterator> crend() const { return base_t::m_list.crend(); }
457490

458491
protected:
459492
unordered_set<uint32_t, WrapHash, WrapEquals> m_shortcut_map;

0 commit comments

Comments
 (0)