1818
1919namespace 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