Skip to content

Commit 3233ed2

Browse files
pull the Handle, ConstHandle and TypedHandle out of templated classes and add std::hashes for them
1 parent 2336075 commit 3233ed2

1 file changed

Lines changed: 70 additions & 40 deletions

File tree

include/nbl/core/alloc/SimpleBlockBasedAllocator.h

Lines changed: 70 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,40 @@
1818

1919
namespace nbl::core
2020
{
21+
22+
template<typename HandleValue, HandleValue _Invalid> requires (std::is_integral_v<HandleValue>&& std::is_unsigned_v<HandleValue>)
23+
struct ConstHandle
24+
{
25+
using value_t = HandleValue;
26+
constexpr static inline value_t Invalid = _Invalid;
27+
28+
explicit inline operator bool() const {return value!=Invalid;}
29+
// God, I love C++20
30+
inline auto operator<=>(const ConstHandle&) const = default;
31+
32+
// LSB is the offset in the block, MSB is the block index
33+
value_t value = Invalid;
34+
};
35+
template<typename _ConstHandle> requires std::is_same_v<ConstHandle<typename _ConstHandle::value_t,_ConstHandle::Invalid>,_ConstHandle>
36+
struct Handle : _ConstHandle
37+
{
38+
using const_type = _ConstHandle;
39+
40+
inline auto operator<=>(const Handle& other) const {return _ConstHandle::operator<=>(other);}
41+
};
42+
43+
template<typename T, typename _Handle> requires std::is_same_v<Handle<typename _Handle::value_t,_Handle::Invalid>,_Handle>
44+
struct TypedHandle final : std::conditional_t<std::is_const_v<T>,typename _Handle::const_type,_Handle>
45+
{
46+
private:
47+
using base_t = std::conditional_t<std::is_const_v<T>,typename _Handle::const_type,_Handle>;
48+
49+
public:
50+
inline auto operator<=>(const _Handle& other) const {return base_t::operator<=>(other);}
51+
inline auto operator<=>(const typename _Handle::const_type& other) const {return base_t::operator<=>(other);}
52+
53+
inline operator TypedHandle<const T,_Handle>() const {return {{.value=base_t::value}};}
54+
};
2155

2256
//! Does not resize memory arenas, therefore once allocations shall not move
2357
//! Needs an address allocator that takes a Block Size after max alignment parameter
@@ -251,40 +285,10 @@ class SimpleBlockBasedAllocator<AddressAllocator,HandleValue> final : protected
251285
using size_type = typename base_t::size_type;
252286

253287
// everything is handed out by index not pointer
254-
struct ConstHandle
255-
{
256-
using value_t = HandleValue;
257-
constexpr static inline value_t Invalid = ~value_t(0);
258-
259-
explicit inline operator bool() const {return value!=Invalid;}
260-
// God, I love C++20
261-
inline auto operator<=>(const ConstHandle&) const = default;
262-
263-
// LSB is the offset in the block, MSB is the block index
264-
value_t value = Invalid;
265-
};
266-
struct Handle : ConstHandle
267-
{
268-
inline auto operator<=>(const Handle& other) const {return ConstHandle::operator<=>(other);}
269-
};
270-
//
271-
template<typename T>
272-
struct TypedHandle final : std::conditional_t<std::is_const_v<T>,ConstHandle,Handle>
273-
{
274-
private:
275-
using base_t = std::conditional_t<std::is_const_v<T>,ConstHandle,Handle>;
276-
277-
public:
278-
inline auto operator<=>(const ConstHandle& other) const {return base_t::operator<=>(other);}
279-
280-
inline operator TypedHandle<const T>() const {return {{.value=ConstHandle::value}};}
281-
};
282-
283-
//
284288
template<typename T>
285289
struct typed_pointer
286290
{
287-
using type = TypedHandle<T>;
291+
using type = TypedHandle<T,Handle<ConstHandle<HandleValue,~HandleValue(0)> > >;
288292
};
289293

290294
struct SCreationParams final
@@ -349,17 +353,15 @@ class SimpleBlockBasedAllocator<AddressAllocator,HandleValue> final : protected
349353
}
350354

351355
//
352-
inline Handle allocate(const size_type bytes, const size_type alignment) noexcept
356+
inline typename typed_pointer<void>::type allocate(const size_type bytes, const size_type alignment) noexcept
353357
{
354-
auto buildHandle = [&](HandleValue blockID, HandleValue addr)->Handle{return {.value=(blockID<<m_blockSizeLog2)|addr};};
355-
//
356358
constexpr auto invalid_address = AddressAllocator::invalid_address;
357359
// TODO: better allocation strategies like tlsf
358360
for (auto& entry : m_blocks)
359361
{
360362
block_t* block = entry.second;
361363
if (const auto addr=block->alloc(bytes,alignment); addr!=invalid_address)
362-
return buildHandle(entry.first,addr);
364+
return {.value=(entry.first<<m_blockSizeLog2)|addr};
363365
}
364366
const auto newID = m_blockIndexAlloc.alloc_addr(1,1);
365367
if (newID!=block_id_alloc_t::invalid_address)
@@ -368,14 +370,14 @@ class SimpleBlockBasedAllocator<AddressAllocator,HandleValue> final : protected
368370
if (const auto addr=block->alloc(bytes,alignment); addr!=invalid_address)
369371
{
370372
m_blocks[newID] = block;
371-
return buildHandle(newID,addr);
373+
return {.value=(newID<<m_blockSizeLog2)|addr};
372374
}
373375
else
374376
base_t::deleteBlock(block);
375377
}
376378
return {};
377379
}
378-
inline void deallocate(const Handle h, const size_type bytes) noexcept
380+
inline void deallocate(const typename typed_pointer<void>::type h, const size_type bytes) noexcept
379381
{
380382
assert(m_blocks.size()>=base_t::m_initBlockCount);
381383
auto found = m_blocks.find(getBlockIndex(h));
@@ -391,10 +393,10 @@ class SimpleBlockBasedAllocator<AddressAllocator,HandleValue> final : protected
391393
}
392394

393395
private:
394-
inline HandleValue getOffsetInBlock(const ConstHandle h) const {return h.value&m_loAddrMask;}
395-
inline block_t* getBlock(const ConstHandle h) const {return m_blocks[getBlockIndex(h)];}
396+
inline HandleValue getOffsetInBlock(const typename typed_pointer<const void>::type h) const {return h.value&m_loAddrMask;}
397+
inline block_t* getBlock(const typename typed_pointer<const void>::type h) const {return m_blocks[getBlockIndex(h)];}
396398

397-
inline HandleValue getBlockIndex(const ConstHandle h) const {return h.value>>m_blockSizeLog2;}
399+
inline HandleValue getBlockIndex(const typename typed_pointer<const void>::type h) const {return h.value>>m_blockSizeLog2;}
398400

399401
// Either flat array, keeps our `deref()` fast, or hash map which isn't bad because lookup up objects from different blocks will trash anyway.
400402
using block_map_t = core::unordered_map<HandleValue,block_t*>;
@@ -474,6 +476,34 @@ class SimpleBlockBasedAllocatorMT final
474476
};
475477
// no aliases
476478

479+
}
480+
481+
namespace std
482+
{
483+
template<typename HandleValue, HandleValue _Invalid>
484+
struct hash<nbl::core::ConstHandle<HandleValue,_Invalid> >
485+
{
486+
inline size_t operator()(const nbl::core::ConstHandle<HandleValue,_Invalid> handle) const
487+
{
488+
return std::hash<HandleValue>()(handle.value);
489+
}
490+
};
491+
template<typename HandleValue, HandleValue _Invalid>
492+
struct hash<nbl::core::Handle<nbl::core::ConstHandle<HandleValue,_Invalid> > >
493+
{
494+
inline size_t operator()(const nbl::core::Handle<nbl::core::ConstHandle<HandleValue,_Invalid> > handle) const
495+
{
496+
return std::hash<HandleValue>()(handle.value);
497+
}
498+
};
499+
template<typename T, typename HandleValue, HandleValue _Invalid>
500+
struct hash<nbl::core::TypedHandle<T,nbl::core::Handle<nbl::core::ConstHandle<HandleValue,_Invalid> > > >
501+
{
502+
inline size_t operator()(const nbl::core::TypedHandle<T,nbl::core::Handle<nbl::core::ConstHandle<HandleValue,_Invalid> > > handle) const
503+
{
504+
return std::hash<HandleValue>()(handle.value);
505+
}
506+
};
477507
}
478508
#endif
479509

0 commit comments

Comments
 (0)