2024-04-18 22:59:11 +10:00
# pragma once
# include "dqn.h"
2024-03-25 16:11:57 +11:00
/*
2024-01-31 23:49:23 +11:00
////////////////////////////////////////////////////////////////////////////////////////////////////
//
/ / $ $ $ $ $ $ \ $ $ $ $ $ $ \ $ $ \ $ $ \ $ $ $ $ $ $ $ $ \ $ $ $ $ $ $ \ $ $ $ $ $ $ \ $ $ \ $ $ \ $ $ $ $ $ $ $ $ \ $ $ $ $ $ $ $ \ $ $ $ $ $ $ \
/ / $ $ __ $ $ \ $ $ __ $ $ \ $ $ $ \ $ $ | \ __ $ $ __ | $ $ __ $ $ \ \ _ $ $ _ | $ $ $ \ $ $ | $ $ _____ | $ $ __ $ $ \ $ $ __ $ $ \
// $$ / \__|$$ / $$ |$$$$\ $$ | $$ | $$ / $$ | $$ | $$$$\ $$ |$$ | $$ | $$ |$$ / \__|
/ / $ $ | $ $ | $ $ | $ $ $ $ \ $ $ | $ $ | $ $ $ $ $ $ $ $ | $ $ | $ $ $ $ \ $ $ | $ $ $ $ $ \ $ $ $ $ $ $ $ | \ $ $ $ $ $ $ \
/ / $ $ | $ $ | $ $ | $ $ \ $ $ $ $ | $ $ | $ $ __ $ $ | $ $ | $ $ \ $ $ $ $ | $ $ __ | $ $ __ $ $ < \ ____ $ $ \
// $$ | $$\ $$ | $$ |$$ |\$$$ | $$ | $$ | $$ | $$ | $$ |\$$$ |$$ | $$ | $$ |$$\ $$ |
// \$$$$$$ | $$$$$$ |$$ | \$$ | $$ | $$ | $$ |$$$$$$\ $$ | \$$ |$$$$$$$$\ $$ | $$ |\$$$$$$ |
// \______/ \______/ \__| \__| \__| \__| \__|\______|\__| \__|\________|\__| \__| \______/
//
// dqn_containers.cpp
//
////////////////////////////////////////////////////////////////////////////////////////////////////
2024-03-25 16:11:57 +11:00
*/
2024-01-31 23:49:23 +11:00
2025-02-14 00:27:42 +11:00
// NOTE: [$CARR] DN_CArray ////////////////////////////////////////////////////////////////////////
template < typename T > DN_ArrayEraseResult DN_CArray_EraseRange ( T * data , DN_USize * size , DN_USize begin_index , DN_ISize count , DN_ArrayErase erase )
2024-01-31 23:49:23 +11:00
{
2025-02-14 00:27:42 +11:00
DN_ArrayEraseResult result = { } ;
if ( ! data | | ! size | | * size = = 0 | | count = = 0 )
return result ;
DN_ASSERTF ( count ! = - 1 , " There's a bug with negative element erases, see the DN_VArray section in dn_docs.cpp " ) ;
// NOTE: Caculate the end index of the erase range
DN_ISize abs_count = DN_ABS ( count ) ;
DN_USize end_index = 0 ;
if ( count < 0 ) {
end_index = begin_index - ( abs_count - 1 ) ;
if ( end_index > begin_index )
end_index = 0 ;
} else {
end_index = begin_index + ( abs_count - 1 ) ;
if ( end_index < begin_index )
end_index = ( * size ) - 1 ;
}
// NOTE: Ensure begin_index < one_past_end_index
if ( end_index < begin_index ) {
DN_USize tmp = begin_index ;
begin_index = end_index ;
end_index = tmp ;
}
// NOTE: Ensure indexes are within valid bounds
begin_index = DN_MIN ( begin_index , * size ) ;
end_index = DN_MIN ( end_index , * size - 1 ) ;
// NOTE: Erase the items in the range [begin_index, one_past_end_index)
DN_USize one_past_end_index = end_index + 1 ;
DN_USize erase_count = one_past_end_index - begin_index ;
if ( erase_count ) {
T * end = data + * size ;
T * dest = data + begin_index ;
if ( erase = = DN_ArrayErase_Stable ) {
T * src = dest + erase_count ;
DN_MEMMOVE ( dest , src , ( end - src ) * sizeof ( T ) ) ;
} else {
T * src = end - erase_count ;
DN_MEMCPY ( dest , src , ( end - src ) * sizeof ( T ) ) ;
}
* size - = erase_count ;
}
result . items_erased = erase_count ;
result . it_index = begin_index ;
return result ;
}
template < typename T > T * DN_CArray_MakeArray ( T * data , DN_USize * size , DN_USize max , DN_USize count , DN_ZeroMem zero_mem )
{
if ( ! data | | ! size | | count = = 0 )
return nullptr ;
if ( ! DN_CHECKF ( ( * size + count ) < = max , " Array is out of space (user requested +%zu items, array has %zu/%zu items) " , count , * size , max ) )
return nullptr ;
// TODO: Use placement new? Why doesn't this work?
T * result = data + * size ;
* size + = count ;
if ( zero_mem = = DN_ZeroMem_Yes )
DN_MEMSET ( result , 0 , sizeof ( * result ) * count ) ;
return result ;
}
template < typename T > T * DN_CArray_InsertArray ( T * data , DN_USize * size , DN_USize max , DN_USize index , T const * items , DN_USize count )
{
T * result = nullptr ;
if ( ! data | | ! size | | ! items | | count < = 0 | | ( ( * size + count ) > max ) )
return result ;
DN_USize clamped_index = DN_MIN ( index , * size ) ;
if ( clamped_index ! = * size ) {
char const * src = DN_CAST ( char * ) ( data + clamped_index ) ;
char const * dest = DN_CAST ( char * ) ( data + ( clamped_index + count ) ) ;
char const * end = DN_CAST ( char * ) ( data + ( * size ) ) ;
DN_USize bytes_to_move = end - src ;
DN_MEMMOVE ( DN_CAST ( void * ) dest , src , bytes_to_move ) ;
}
result = data + clamped_index ;
DN_MEMCPY ( result , items , sizeof ( T ) * count ) ;
* size + = count ;
return result ;
}
template < typename T > T DN_CArray_PopFront ( T * data , DN_USize * size , DN_USize count )
{
T result = { } ;
if ( ! data | | ! size | | * size < = 0 )
return result ;
result = data [ 0 ] ;
DN_USize pop_count = DN_MIN ( count , * size ) ;
DN_MEMMOVE ( data , data + pop_count , ( * size - pop_count ) * sizeof ( T ) ) ;
* size - = pop_count ;
return result ;
}
template < typename T > T DN_CArray_PopBack ( T * data , DN_USize * size , DN_USize count )
{
T result = { } ;
if ( ! data | | ! size | | * size < = 0 )
return result ;
DN_USize pop_count = DN_MIN ( count , * size ) ;
result = data [ ( * size - 1 ) ] ;
* size - = pop_count ;
return result ;
}
template < typename T > DN_ArrayFindResult < T > DN_CArray_Find ( T * data , DN_USize size , T const & value )
{
DN_ArrayFindResult < T > result = { } ;
if ( ! data | | size < = 0 )
return result ;
for ( DN_USize index = 0 ; ! result . data & & index < size ; index + + ) {
T * item = data + index ;
if ( * item = = value ) {
result . data = item ;
result . index = index ;
}
}
return result ;
}
# if !defined(DN_NO_VARRAY)
// NOTE: [$VARR] DN_VArray ////////////////////////////////////////////////////////////////////////
template < typename T > DN_VArray < T > DN_VArray_InitByteSize ( DN_USize byte_size )
{
DN_VArray < T > result = { } ;
result . data = DN_CAST ( T * ) DN_OS_MemReserve ( byte_size , DN_OSMemCommit_No , DN_OSMemPage_ReadWrite ) ;
if ( result . data )
result . max = byte_size / sizeof ( T ) ;
return result ;
}
template < typename T > DN_VArray < T > DN_VArray_Init ( DN_USize max )
{
DN_VArray < T > result = DN_VArray_InitByteSize < T > ( max * sizeof ( T ) ) ;
DN_ASSERT ( result . max > = max ) ;
return result ;
}
template < typename T > DN_VArray < T > DN_VArray_InitSlice ( DN_Slice < T > slice , DN_USize max )
{
DN_USize real_max = DN_MAX ( slice . size , max ) ;
DN_VArray < T > result = DN_VArray_Init < T > ( real_max ) ;
if ( DN_VArray_IsValid ( & result ) )
DN_VArray_AddArray ( & result , slice . data , slice . size ) ;
return result ;
}
template < typename T , DN_USize N > DN_VArray < T > DN_VArray_InitCArray ( T const ( & items ) [ N ] , DN_USize max )
{
DN_USize real_max = DN_MAX ( N , max ) ;
DN_VArray < T > result = DN_VArray_InitSlice ( DN_Slice_Init ( items , N ) , real_max ) ;
return result ;
}
template < typename T > void DN_VArray_Deinit ( DN_VArray < T > * array )
{
DN_OS_MemRelease ( array - > data , array - > max * sizeof ( T ) ) ;
* array = { } ;
}
template < typename T > bool DN_VArray_IsValid ( DN_VArray < T > const * array )
{
bool result = array - > data & & array - > size < = array - > max ;
return result ;
}
template < typename T > DN_Slice < T > DN_VArray_Slice ( DN_VArray < T > const * array )
{
DN_Slice < T > result = { } ;
if ( array )
result = DN_Slice_Init < T > ( array - > data , array - > size ) ;
return result ;
}
template < typename T > T * DN_VArray_AddArray ( DN_VArray < T > * array , T const * items , DN_USize count )
{
T * result = DN_VArray_MakeArray ( array , count , DN_ZeroMem_No ) ;
if ( result )
DN_MEMCPY ( result , items , count * sizeof ( T ) ) ;
return result ;
}
template < typename T , DN_USize N > T * DN_VArray_AddCArray ( DN_VArray < T > * array , T const ( & items ) [ N ] )
{
T * result = DN_VArray_AddArray ( array , items , N ) ;
return result ;
}
template < typename T > T * DN_VArray_Add ( DN_VArray < T > * array , T const & item )
{
T * result = DN_VArray_AddArray ( array , & item , 1 ) ;
return result ;
}
template < typename T > T * DN_VArray_MakeArray ( DN_VArray < T > * array , DN_USize count , DN_ZeroMem zero_mem )
{
if ( ! DN_VArray_IsValid ( array ) )
return nullptr ;
if ( ! DN_CHECKF ( ( array - > size + count ) < array - > max , " Array is out of space (user requested +%zu items, array has %zu/%zu items) " , count , array - > size , array - > max ) )
return nullptr ;
if ( ! DN_VArray_Reserve ( array , count ) )
return nullptr ;
// TODO: Use placement new
T * result = array - > data + array - > size ;
array - > size + = count ;
if ( zero_mem = = DN_ZeroMem_Yes )
DN_MEMSET ( result , 0 , count * sizeof ( T ) ) ;
return result ;
}
template < typename T > T * DN_VArray_Make ( DN_VArray < T > * array , DN_ZeroMem zero_mem )
{
T * result = DN_VArray_MakeArray ( array , 1 , zero_mem ) ;
return result ;
}
template < typename T > T * DN_VArray_InsertArray ( DN_VArray < T > * array , DN_USize index , T const * items , DN_USize count )
{
T * result = nullptr ;
if ( ! DN_VArray_IsValid ( array ) )
return result ;
if ( DN_VArray_Reserve ( array , array - > size + count ) )
result = DN_CArray_InsertArray ( array - > data , & array - > size , array - > max , index , items , count ) ;
return result ;
}
template < typename T , DN_USize N > T * DN_VArray_InsertCArray ( DN_VArray < T > * array , DN_USize index , T const ( & items ) [ N ] )
{
T * result = DN_VArray_InsertArray ( array , index , items , N ) ;
return result ;
}
template < typename T > T * DN_VArray_Insert ( DN_VArray < T > * array , DN_USize index , T const & item )
{
T * result = DN_VArray_InsertArray ( array , index , & item , 1 ) ;
return result ;
}
template < typename T > T * DN_VArray_PopFront ( DN_VArray < T > * array , DN_USize count )
{
T * result = DN_CArray_PopFront ( array - > data , & array - > size , count ) ;
return result ;
}
template < typename T > T * DN_VArray_PopBack ( DN_VArray < T > * array , DN_USize count )
{
T * result = DN_CArray_PopBack ( array - > data , & array - > size , count ) ;
return result ;
}
template < typename T > DN_ArrayEraseResult DN_VArray_EraseRange ( DN_VArray < T > * array , DN_USize begin_index , DN_ISize count , DN_ArrayErase erase )
{
DN_ArrayEraseResult result = { } ;
if ( ! DN_VArray_IsValid ( array ) )
return result ;
result = DN_CArray_EraseRange < T > ( array - > data , & array - > size , begin_index , count , erase ) ;
return result ;
}
template < typename T > void DN_VArray_Clear ( DN_VArray < T > * array , DN_ZeroMem zero_mem )
{
if ( array ) {
if ( zero_mem = = DN_ZeroMem_Yes )
DN_MEMSET ( array - > data , 0 , array - > size * sizeof ( T ) ) ;
array - > size = 0 ;
}
}
template < typename T > bool DN_VArray_Reserve ( DN_VArray < T > * array , DN_USize count )
{
if ( ! DN_VArray_IsValid ( array ) | | count = = 0 )
return false ;
DN_USize real_commit = ( array - > size + count ) * sizeof ( T ) ;
DN_USize aligned_commit = DN_AlignUpPowerOfTwo ( real_commit , g_dn_core - > os_page_size ) ;
if ( array - > commit > = aligned_commit )
return true ;
bool result = DN_OS_MemCommit ( array - > data , aligned_commit , DN_OSMemPage_ReadWrite ) ;
array - > commit = aligned_commit ;
return result ;
}
# endif // !defined(DN_NO_VARRAY)
# if !defined(DN_NO_SARRAY)
// NOTE: [$SARR] DN_SArray ////////////////////////////////////////////////////////////////////////
template < typename T > DN_SArray < T > DN_SArray_Init ( DN_Arena * arena , DN_USize size , DN_ZeroMem zero_mem )
{
DN_SArray < T > result = { } ;
if ( ! arena | | ! size )
return result ;
result . data = DN_Arena_NewArray ( arena , T , size , zero_mem ) ;
if ( result . data )
result . max = size ;
return result ;
}
template < typename T > DN_SArray < T > DN_SArray_InitSlice ( DN_Arena * arena , DN_Slice < T > slice , DN_USize size , DN_ZeroMem zero_mem )
{
DN_USize max = DN_MAX ( slice . size , size ) ;
DN_SArray < T > result = DN_SArray_Init < T > ( arena , max , DN_ZeroMem_No ) ;
if ( DN_SArray_IsValid ( & result ) ) {
DN_SArray_AddArray ( & result , slice . data , slice . size ) ;
if ( zero_mem = = DN_ZeroMem_Yes )
DN_MEMSET ( result . data + result . size , 0 , ( result . max - result . size ) * sizeof ( T ) ) ;
}
return result ;
}
template < typename T , size_t N > DN_SArray < T > DN_SArray_InitCArray ( DN_Arena * arena , T const ( & array ) [ N ] , DN_USize size , DN_ZeroMem zero_mem )
{
DN_SArray < T > result = DN_SArray_InitSlice ( arena , DN_Slice_Init ( DN_CAST ( T * ) array , N ) , size , zero_mem ) ;
return result ;
}
template < typename T > DN_SArray < T > DN_SArray_InitBuffer ( T * buffer , DN_USize size )
{
DN_SArray < T > result = { } ;
result . data = buffer ;
result . max = size ;
return result ;
}
template < typename T > bool DN_SArray_IsValid ( DN_SArray < T > const * array )
{
bool result = array & & array - > data & & array - > size < = array - > max ;
return result ;
}
template < typename T > DN_Slice < T > DN_SArray_Slice ( DN_SArray < T > const * array )
{
DN_Slice < T > result = { } ;
if ( array )
result = DN_Slice_Init < T > ( DN_CAST ( T * ) array - > data , array - > size ) ;
return result ;
}
template < typename T > T * DN_SArray_MakeArray ( DN_SArray < T > * array , DN_USize count , DN_ZeroMem zero_mem )
{
if ( ! DN_SArray_IsValid ( array ) )
return nullptr ;
T * result = DN_CArray_MakeArray ( array - > data , & array - > size , array - > max , count , zero_mem ) ;
return result ;
}
template < typename T > T * DN_SArray_Make ( DN_SArray < T > * array , DN_ZeroMem zero_mem )
{
T * result = DN_SArray_MakeArray ( array , 1 , zero_mem ) ;
return result ;
}
template < typename T > T * DN_SArray_AddArray ( DN_SArray < T > * array , T const * items , DN_USize count )
{
T * result = DN_SArray_MakeArray ( array , count , DN_ZeroMem_No ) ;
if ( result )
DN_MEMCPY ( result , items , count * sizeof ( T ) ) ;
return result ;
}
template < typename T , DN_USize N > T * DN_SArray_AddCArray ( DN_SArray < T > * array , T const ( & items ) [ N ] )
{
T * result = DN_SArray_AddArray ( array , items , N ) ;
return result ;
}
template < typename T > T * DN_SArray_Add ( DN_SArray < T > * array , T const & item )
{
T * result = DN_SArray_AddArray ( array , & item , 1 ) ;
return result ;
}
template < typename T > T * DN_SArray_InsertArray ( DN_SArray < T > * array , DN_USize index , T const * items , DN_USize count )
{
T * result = nullptr ;
if ( ! DN_SArray_IsValid ( array ) )
return result ;
result = DN_CArray_InsertArray ( array - > data , & array - > size , array - > max , index , items , count ) ;
return result ;
}
template < typename T , DN_USize N > T * DN_SArray_InsertCArray ( DN_SArray < T > * array , DN_USize index , T const ( & items ) [ N ] )
{
T * result = DN_SArray_InsertArray ( array , index , items , N ) ;
return result ;
}
template < typename T > T * DN_SArray_Insert ( DN_SArray < T > * array , DN_USize index , T const & item )
{
T * result = DN_SArray_InsertArray ( array , index , & item , 1 ) ;
return result ;
}
template < typename T > T DN_SArray_PopFront ( DN_SArray < T > * array , DN_USize count )
{
T result = DN_CArray_PopFront ( array - > data , & array - > size , count ) ;
return result ;
}
template < typename T > T DN_SArray_PopBack ( DN_SArray < T > * array , DN_USize count )
{
T result = DN_CArray_PopBack ( array - > data , & array - > size , count ) ;
return result ;
}
template < typename T > DN_ArrayEraseResult DN_SArray_EraseRange ( DN_SArray < T > * array , DN_USize begin_index , DN_ISize count , DN_ArrayErase erase )
{
DN_ArrayEraseResult result = { } ;
if ( ! DN_SArray_IsValid ( array ) | | array - > size = = 0 | | count = = 0 )
return result ;
result = DN_CArray_EraseRange ( array - > data , & array - > size , begin_index , count , erase ) ;
return result ;
}
template < typename T > void DN_SArray_Clear ( DN_SArray < T > * array )
{
if ( array )
array - > size = 0 ;
}
# endif // !defined(DN_NO_SARRAY)
# if !defined(DN_NO_FARRAY)
// NOTE: [$FARR] DN_FArray ////////////////////////////////////////////////////////////////////////
template < typename T , DN_USize N > DN_FArray < T , N > DN_FArray_Init ( T const * array , DN_USize count )
{
DN_FArray < T , N > result = { } ;
bool added = DN_FArray_AddArray ( & result , array , count ) ;
DN_ASSERT ( added ) ;
return result ;
}
template < typename T , DN_USize N > DN_FArray < T , N > DN_FArray_InitSlice ( DN_Slice < T > slice )
{
DN_FArray < T , N > result = DN_FArray_Init ( slice . data , slice . size ) ;
return result ;
}
template < typename T , DN_USize N , DN_USize K > DN_FArray < T , N > DN_FArray_InitCArray ( T const ( & items ) [ K ] )
{
DN_FArray < T , N > result = DN_FArray_Init < T , N > ( items , K ) ;
return result ;
}
template < typename T , DN_USize N > bool DN_FArray_IsValid ( DN_FArray < T , N > const * array )
{
bool result = array & & array - > size < = DN_ARRAY_UCOUNT ( array - > data ) ;
return result ;
}
template < typename T , DN_USize N > DN_Slice < T > DN_FArray_Slice ( DN_FArray < T , N > const * array )
{
DN_Slice < T > result = { } ;
if ( array )
result = DN_Slice_Init < T > ( DN_CAST ( T * ) array - > data , array - > size ) ;
return result ;
}
template < typename T , DN_USize N > T * DN_FArray_AddArray ( DN_FArray < T , N > * array , T const * items , DN_USize count )
{
T * result = DN_FArray_MakeArray ( array , count , DN_ZeroMem_No ) ;
if ( result )
DN_MEMCPY ( result , items , count * sizeof ( T ) ) ;
return result ;
}
template < typename T , DN_USize N , DN_USize K > T * DN_FArray_AddCArray ( DN_FArray < T , N > * array , T const ( & items ) [ K ] )
{
T * result = DN_FArray_MakeArray ( array , K , DN_ZeroMem_No ) ;
if ( result )
DN_MEMCPY ( result , items , K * sizeof ( T ) ) ;
return result ;
}
template < typename T , DN_USize N > T * DN_FArray_Add ( DN_FArray < T , N > * array , T const & item )
{
T * result = DN_FArray_AddArray ( array , & item , 1 ) ;
return result ;
}
template < typename T , DN_USize N > T * DN_FArray_MakeArray ( DN_FArray < T , N > * array , DN_USize count , DN_ZeroMem zero_mem )
{
if ( ! DN_FArray_IsValid ( array ) )
return nullptr ;
T * result = DN_CArray_MakeArray ( array - > data , & array - > size , N , count , zero_mem ) ;
return result ;
}
template < typename T , DN_USize N > T * DN_FArray_Make ( DN_FArray < T , N > * array , DN_ZeroMem zero_mem )
{
T * result = DN_FArray_MakeArray ( array , 1 , zero_mem ) ;
return result ;
}
template < typename T , DN_USize N > T * DN_FArray_InsertArray ( DN_FArray < T , N > * array , DN_USize index , T const * items , DN_USize count )
{
T * result = nullptr ;
if ( ! DN_FArray_IsValid ( array ) )
return result ;
result = DN_CArray_InsertArray ( array - > data , & array - > size , N , index , items , count ) ;
return result ;
}
template < typename T , DN_USize N , DN_USize K > T * DN_FArray_InsertCArray ( DN_FArray < T , N > * array , DN_USize index , T const ( & items ) [ K ] )
{
T * result = DN_FArray_InsertArray ( array , index , items , K ) ;
return result ;
}
template < typename T , DN_USize N > T * DN_FArray_Insert ( DN_FArray < T , N > * array , DN_USize index , T const & item )
{
T * result = DN_FArray_InsertArray ( array , index , & item , 1 ) ;
return result ;
}
template < typename T , DN_USize N > T DN_FArray_PopFront ( DN_FArray < T , N > * array , DN_USize count )
{
T result = DN_CArray_PopFront ( array - > data , & array - > size , count ) ;
return result ;
}
template < typename T , DN_USize N > T DN_FArray_PopBack ( DN_FArray < T , N > * array , DN_USize count )
{
T result = DN_CArray_PopBack ( array - > data , & array - > size , count ) ;
return result ;
}
template < typename T , DN_USize N > DN_ArrayFindResult < T > DN_FArray_Find ( DN_FArray < T , N > * array , T const & find )
{
DN_ArrayFindResult < T > result = DN_CArray_Find < T > ( array - > data , array - > size , find ) ;
return result ;
}
template < typename T , DN_USize N > DN_ArrayEraseResult DN_FArray_EraseRange ( DN_FArray < T , N > * array , DN_USize begin_index , DN_ISize count , DN_ArrayErase erase )
{
DN_ArrayEraseResult result = { } ;
if ( ! DN_FArray_IsValid ( array ) | | array - > size = = 0 | | count = = 0 )
return result ;
result = DN_CArray_EraseRange ( array - > data , & array - > size , begin_index , count , erase ) ;
return result ;
}
template < typename T , DN_USize N > void DN_FArray_Clear ( DN_FArray < T , N > * array )
{
if ( array )
array - > size = 0 ;
}
# endif // !defined(DN_NO_FARRAY)
# if !defined(DN_NO_SLICE)
template < typename T > DN_Slice < T > DN_Slice_Init ( T * const data , DN_USize size )
{
DN_Slice < T > result = { } ;
if ( data ) {
result . data = data ;
result . size = size ;
}
return result ;
}
template < typename T , DN_USize N > DN_Slice < T > DN_Slice_InitCArray ( DN_Arena * arena , T const ( & array ) [ N ] )
{
DN_Slice < T > result = DN_Slice_Alloc < T > ( arena , N , DN_ZeroMem_No ) ;
if ( result . data )
DN_MEMCPY ( result . data , array , sizeof ( T ) * N ) ;
return result ;
}
template < typename T > DN_Slice < T > DN_Slice_CopyPtr ( DN_Arena * arena , T * const data , DN_USize size )
{
T * copy = DN_Arena_NewArrayCopy ( arena , T , data , size ) ;
DN_Slice < T > result = DN_Slice_Init ( copy , copy ? size : 0 ) ;
return result ;
}
template < typename T > DN_Slice < T > DN_Slice_Copy ( DN_Arena * arena , DN_Slice < T > slice )
{
DN_Slice < T > result = DN_Slice_CopyPtr ( arena , slice . data , slice . size ) ;
return result ;
}
template < typename T > DN_Slice < T > DN_Slice_Alloc ( DN_Arena * arena , DN_USize size , DN_ZeroMem zero_mem )
{
DN_Slice < T > result = { } ;
if ( ! arena | | size = = 0 )
return result ;
result . data = DN_Arena_NewArray ( arena , T , size , zero_mem ) ;
if ( result . data )
result . size = size ;
return result ;
}
# endif // !defined(DN_NO_SLICE)
# if !defined(DN_NO_DSMAP)
// NOTE: [$DMAP] DN_DSMap /////////////////////////////////////////////////////////////////////////
DN_U32 const DN_DS_MAP_DEFAULT_HASH_SEED = 0x8a1ced49 ;
DN_U32 const DN_DS_MAP_SENTINEL_SLOT = 0 ;
template < typename T > DN_DSMap < T > DN_DSMap_Init ( DN_Arena * arena , DN_U32 size , DN_DSMapFlags flags )
{
DN_DSMap < T > result = { } ;
if ( ! DN_CHECKF ( DN_IsPowerOfTwo ( size ) , " Power-of-two size required, given size was '%u' " , size ) )
return result ;
if ( size < = 0 )
return result ;
if ( ! DN_CHECK ( arena ) )
return result ;
result . arena = arena ;
result . pool = DN_Pool_Init ( arena , DN_POOL_DEFAULT_ALIGN ) ;
result . hash_to_slot = DN_Arena_NewArray ( result . arena , DN_U32 , size , DN_ZeroMem_Yes ) ;
result . slots = DN_Arena_NewArray ( result . arena , DN_DSMapSlot < T > , size , DN_ZeroMem_Yes ) ;
result . occupied = 1 ; // For sentinel
result . size = size ;
result . initial_size = size ;
result . flags = flags ;
DN_ASSERTF ( result . hash_to_slot & & result . slots , " We pre-allocated a block of memory sufficient in size for the 2 arrays. Maybe the pointers needed extra space because of natural alignment? " ) ;
return result ;
}
template < typename T >
void DN_DSMap_Deinit ( DN_DSMap < T > * map , DN_ZeroMem zero_mem )
{
if ( ! map )
return ;
// TODO(doyle): Use zero_mem
( void ) zero_mem ;
DN_Arena_Deinit ( map - > arena ) ;
* map = { } ;
}
template < typename T >
bool DN_DSMap_IsValid ( DN_DSMap < T > const * map )
{
bool result = map & &
map - > arena & &
map - > hash_to_slot & & // Hash to slot mapping array must be allocated
map - > slots & & // Slots array must be allocated
( map - > size & ( map - > size - 1 ) ) = = 0 & & // Must be power of two size
map - > occupied > = 1 ; // DN_DS_MAP_SENTINEL_SLOT takes up one slot
return result ;
}
template < typename T >
DN_U32 DN_DSMap_Hash ( DN_DSMap < T > const * map , DN_DSMapKey key )
{
DN_U32 result = 0 ;
if ( ! map )
return result ;
if ( key . type = = DN_DSMapKeyType_U64NoHash ) {
result = DN_CAST ( DN_U32 ) key . u64 ;
return result ;
}
if ( key . type = = DN_DSMapKeyType_BufferAsU64NoHash ) {
result = key . hash ;
return result ;
}
DN_U32 seed = map - > hash_seed ? map - > hash_seed : DN_DS_MAP_DEFAULT_HASH_SEED ;
if ( map - > hash_function ) {
map - > hash_function ( key , seed ) ;
} else {
// NOTE: Courtesy of Demetri Spanos (which this hash table was inspired
// from), the following is a hashing function snippet provided for
// reliable, quick and simple quality hashing functions for hash table
// use.
// Source: https://github.com/demetri/scribbles/blob/c475464756c104c91bab83ed4e14badefef12ab5/hashing/ub_aware_hash_functions.c
char const * key_ptr = nullptr ;
DN_U32 len = 0 ;
DN_U32 h = seed ;
switch ( key . type ) {
case DN_DSMapKeyType_BufferAsU64NoHash : /*FALLTHRU*/
case DN_DSMapKeyType_U64NoHash : DN_INVALID_CODE_PATH ; /*FALLTHRU*/
case DN_DSMapKeyType_Invalid : break ;
case DN_DSMapKeyType_Buffer :
key_ptr = DN_CAST ( char const * ) key . buffer_data ;
len = key . buffer_size ;
break ;
case DN_DSMapKeyType_U64 :
key_ptr = DN_CAST ( char const * ) & key . u64 ;
len = sizeof ( key . u64 ) ;
break ;
}
// Murmur3 32-bit without UB unaligned accesses
// DN_U32 mur3_32_no_UB(const void *key, int len, DN_U32 h)
// main body, work on 32-bit blocks at a time
for ( DN_U32 i = 0 ; i < len / 4 ; i + + ) {
DN_U32 k ;
memcpy ( & k , & key_ptr [ i * 4 ] , sizeof ( k ) ) ;
k * = 0xcc9e2d51 ;
k = ( ( k < < 15 ) | ( k > > 17 ) ) * 0x1b873593 ;
h = ( ( ( h ^ k ) < < 13 ) | ( ( h ^ k ) > > 19 ) ) * 5 + 0xe6546b64 ;
}
// load/mix up to 3 remaining tail bytes into a tail block
DN_U32 t = 0 ;
uint8_t * tail = ( ( uint8_t * ) key_ptr ) + 4 * ( len / 4 ) ;
switch ( len & 3 ) {
case 3 : t ^ = tail [ 2 ] < < 16 ;
case 2 : t ^ = tail [ 1 ] < < 8 ;
case 1 : {
t ^ = tail [ 0 ] < < 0 ;
h ^ = ( ( 0xcc9e2d51 * t < < 15 ) | ( 0xcc9e2d51 * t > > 17 ) ) * 0x1b873593 ;
}
}
// finalization mix, including key length
h = ( ( h ^ len ) ^ ( ( h ^ len ) > > 16 ) ) * 0x85ebca6b ;
h = ( h ^ ( h > > 13 ) ) * 0xc2b2ae35 ;
result = h ^ ( h > > 16 ) ;
}
return result ;
}
template < typename T >
DN_U32 DN_DSMap_HashToSlotIndex ( DN_DSMap < T > const * map , DN_DSMapKey key )
{
DN_ASSERT ( key . type ! = DN_DSMapKeyType_Invalid ) ;
DN_U32 result = DN_DS_MAP_SENTINEL_SLOT ;
if ( ! DN_DSMap_IsValid ( map ) )
return result ;
result = key . hash & ( map - > size - 1 ) ;
for ( ; ; ) {
if ( result = = DN_DS_MAP_SENTINEL_SLOT ) // Sentinel is reserved
result + + ;
if ( map - > hash_to_slot [ result ] = = DN_DS_MAP_SENTINEL_SLOT ) // Slot is vacant, can use
return result ;
DN_DSMapSlot < T > * slot = map - > slots + map - > hash_to_slot [ result ] ;
if ( slot - > key . type = = DN_DSMapKeyType_Invalid | | ( slot - > key . hash = = key . hash & & slot - > key = = key ) )
return result ;
result = ( result + 1 ) & ( map - > size - 1 ) ;
}
}
template < typename T >
DN_DSMapResult < T > DN_DSMap_Find ( DN_DSMap < T > const * map , DN_DSMapKey key )
{
DN_DSMapResult < T > result = { } ;
if ( DN_DSMap_IsValid ( map ) ) {
DN_U32 index = DN_DSMap_HashToSlotIndex ( map , key ) ;
if ( index ! = DN_DS_MAP_SENTINEL_SLOT & & map - > hash_to_slot [ index ] = = DN_DS_MAP_SENTINEL_SLOT ) {
result . slot = map - > slots ; // NOTE: Set to sentinel value
} else {
result . slot = map - > slots + map - > hash_to_slot [ index ] ;
result . found = true ;
}
result . value = & result . slot - > value ;
}
return result ;
}
template < typename T >
DN_DSMapResult < T > DN_DSMap_Make ( DN_DSMap < T > * map , DN_DSMapKey key )
{
DN_DSMapResult < T > result = { } ;
if ( ! DN_DSMap_IsValid ( map ) )
return result ;
DN_U32 index = DN_DSMap_HashToSlotIndex ( map , key ) ;
if ( map - > hash_to_slot [ index ] = = DN_DS_MAP_SENTINEL_SLOT ) {
// NOTE: Create the slot
if ( index ! = DN_DS_MAP_SENTINEL_SLOT )
map - > hash_to_slot [ index ] = map - > occupied + + ;
// NOTE: Check if resize is required
bool map_is_75pct_full = ( map - > occupied * 4 ) > ( map - > size * 3 ) ;
if ( map_is_75pct_full ) {
if ( ! DN_DSMap_Resize ( map , map - > size * 2 ) )
return result ;
result = DN_DSMap_Make ( map , key ) ;
} else {
result . slot = map - > slots + map - > hash_to_slot [ index ] ;
result . slot - > key = key ; // NOTE: Assign key to new slot
if ( ( key . type = = DN_DSMapKeyType_Buffer | |
key . type = = DN_DSMapKeyType_BufferAsU64NoHash ) & &
! key . no_copy_buffer ) {
result . slot - > key . buffer_data = DN_Pool_NewArrayCopy ( & map - > pool , char , key . buffer_data , key . buffer_size ) ;
}
}
} else {
result . slot = map - > slots + map - > hash_to_slot [ index ] ;
result . found = true ;
}
result . value = & result . slot - > value ;
DN_ASSERT ( result . slot - > key . type ! = DN_DSMapKeyType_Invalid ) ;
return result ;
}
template < typename T >
DN_DSMapResult < T > DN_DSMap_Set ( DN_DSMap < T > * map , DN_DSMapKey key , T const & value )
{
DN_DSMapResult < T > result = { } ;
if ( ! DN_DSMap_IsValid ( map ) )
return result ;
result = DN_DSMap_Make ( map , key ) ;
result . slot - > value = value ;
return result ;
}
template < typename T >
DN_DSMapResult < T > DN_DSMap_FindKeyU64 ( DN_DSMap < T > const * map , DN_U64 key )
{
DN_DSMapKey map_key = DN_DSMap_KeyU64 ( map , key ) ;
DN_DSMapResult < T > result = DN_DSMap_Find ( map , map_key ) ;
return result ;
}
template < typename T >
DN_DSMapResult < T > DN_DSMap_MakeKeyU64 ( DN_DSMap < T > * map , DN_U64 key )
{
DN_DSMapKey map_key = DN_DSMap_KeyU64 ( map , key ) ;
DN_DSMapResult < T > result = DN_DSMap_Make ( map , map_key ) ;
return result ;
}
template < typename T >
DN_DSMapResult < T > DN_DSMap_SetKeyU64 ( DN_DSMap < T > * map , DN_U64 key , T const & value )
{
DN_DSMapKey map_key = DN_DSMap_KeyU64 ( map , key ) ;
DN_DSMapResult < T > result = DN_DSMap_Set ( map , map_key , value ) ;
return result ;
}
template < typename T >
DN_DSMapResult < T > DN_DSMap_FindKeyStr8 ( DN_DSMap < T > const * map , DN_Str8 key )
{
DN_DSMapKey map_key = DN_DSMap_KeyStr8 ( map , key ) ;
DN_DSMapResult < T > result = DN_DSMap_Find ( map , map_key ) ;
return result ;
}
template < typename T >
DN_DSMapResult < T > DN_DSMap_MakeKeyStr8 ( DN_DSMap < T > * map , DN_Str8 key )
{
DN_DSMapKey map_key = DN_DSMap_KeyStr8 ( map , key ) ;
DN_DSMapResult < T > result = DN_DSMap_Make ( map , map_key ) ;
return result ;
}
template < typename T >
DN_DSMapResult < T > DN_DSMap_SetKeyStr8 ( DN_DSMap < T > * map , DN_Str8 key , T const & value )
{
DN_DSMapKey map_key = DN_DSMap_KeyStr8 ( map , key ) ;
DN_DSMapResult < T > result = DN_DSMap_Set ( map , map_key ) ;
return result ;
}
template < typename T >
bool DN_DSMap_Resize ( DN_DSMap < T > * map , DN_U32 size )
{
if ( ! DN_DSMap_IsValid ( map ) | | size < map - > occupied | | size < map - > initial_size )
return false ;
DN_Arena * prev_arena = map - > arena ;
DN_Arena new_arena = { } ;
new_arena . flags = prev_arena - > flags ;
new_arena . label = prev_arena - > label ;
new_arena . prev = prev_arena - > prev ;
new_arena . next = prev_arena - > next ;
DN_DSMap < T > new_map = DN_DSMap_Init < T > ( & new_arena , size , map - > flags ) ;
if ( ! DN_DSMap_IsValid ( & new_map ) )
return false ;
new_map . initial_size = map - > initial_size ;
for ( DN_U32 old_index = 1 /*Sentinel*/ ; old_index < map - > occupied ; old_index + + ) {
DN_DSMapSlot < T > * old_slot = map - > slots + old_index ;
DN_DSMapKey old_key = old_slot - > key ;
if ( old_key . type = = DN_DSMapKeyType_Invalid )
continue ;
DN_DSMap_Set ( & new_map , old_key , old_slot - > value ) ;
}
if ( ( map - > flags & DN_DSMapFlags_DontFreeArenaOnResize ) = = 0 )
DN_DSMap_Deinit ( map , DN_ZeroMem_No ) ;
* map = new_map ; // Update the map inplace
map - > arena = prev_arena ; // Restore the previous arena pointer, it's been de-init-ed
* map - > arena = new_arena ; // Re-init the old arena with the new data
map - > pool . arena = map - > arena ;
return true ;
}
template < typename T >
bool DN_DSMap_Erase ( DN_DSMap < T > * map , DN_DSMapKey key )
{
if ( ! DN_DSMap_IsValid ( map ) )
return false ;
DN_U32 index = DN_DSMap_HashToSlotIndex ( map , key ) ;
if ( index = = 0 )
return true ;
DN_U32 slot_index = map - > hash_to_slot [ index ] ;
if ( slot_index = = DN_DS_MAP_SENTINEL_SLOT )
return false ;
// NOTE: Mark the slot as unoccupied
map - > hash_to_slot [ index ] = DN_DS_MAP_SENTINEL_SLOT ;
DN_DSMapSlot < T > * slot = map - > slots + slot_index ;
if ( ! slot - > key . no_copy_buffer )
DN_Pool_Dealloc ( & map - > pool , DN_CAST ( void * ) slot - > key . buffer_data ) ;
* slot = { } ; // TODO: Optional?
if ( map - > occupied > 1 /*Sentinel*/ ) {
// NOTE: Repair the hash chain, e.g. rehash all the items after the removed
// element and reposition them if necessary.
for ( DN_U32 probe_index = index ; ; ) {
probe_index = ( probe_index + 1 ) & ( map - > size - 1 ) ;
if ( map - > hash_to_slot [ probe_index ] = = DN_DS_MAP_SENTINEL_SLOT )
break ;
DN_DSMapSlot < T > * probe = map - > slots + map - > hash_to_slot [ probe_index ] ;
DN_U32 new_index = probe - > key . hash & ( map - > size - 1 ) ;
if ( index < = probe_index ) {
if ( index < new_index & & new_index < = probe_index )
continue ;
} else {
if ( index < new_index | | new_index < = probe_index )
continue ;
}
map - > hash_to_slot [ index ] = map - > hash_to_slot [ probe_index ] ;
map - > hash_to_slot [ probe_index ] = DN_DS_MAP_SENTINEL_SLOT ;
index = probe_index ;
}
// NOTE: We have erased a slot from the hash table, this leaves a gap
// in our contiguous array. After repairing the chain, the hash mapping
// is correct.
// We will now fill in the vacant spot that we erased using the last
// element in the slot list.
if ( map - > occupied > = 3 /*Ignoring sentinel, at least 2 other elements to unstable erase*/ ) {
DN_U32 last_index = map - > occupied - 1 ;
if ( last_index ! = slot_index ) {
// NOTE: Copy in last slot to the erase slot
DN_DSMapSlot < T > * last_slot = map - > slots + last_index ;
map - > slots [ slot_index ] = * last_slot ;
// NOTE: Update the hash-to-slot mapping for the value that was copied in
DN_U32 hash_to_slot_index = DN_DSMap_HashToSlotIndex ( map , last_slot - > key ) ;
map - > hash_to_slot [ hash_to_slot_index ] = slot_index ;
* last_slot = { } ; // TODO: Optional?
}
}
}
map - > occupied - - ;
bool map_is_below_25pct_full = ( map - > occupied * 4 ) < ( map - > size * 1 ) ;
if ( map_is_below_25pct_full & & ( map - > size / 2 ) > = map - > initial_size )
DN_DSMap_Resize ( map , map - > size / 2 ) ;
return true ;
}
template < typename T > bool DN_DSMap_EraseKeyU64 ( DN_DSMap < T > * map , DN_U64 key )
{
DN_DSMapKey map_key = DN_DSMap_KeyU64 ( map , key ) ;
bool result = DN_DSMap_Erase ( map , map_key ) ;
return result ;
}
template < typename T > bool DN_DSMap_EraseKeyStr8 ( DN_DSMap < T > * map , DN_Str8 key )
{
DN_DSMapKey map_key = DN_DSMap_KeyStr8 ( map , key ) ;
bool result = DN_DSMap_Erase ( map , map_key ) ;
return result ;
}
template < typename T >
DN_DSMapKey DN_DSMap_KeyBuffer ( DN_DSMap < T > const * map , void const * data , DN_USize size )
{
DN_ASSERT ( size > 0 & & size < = UINT32_MAX ) ;
DN_DSMapKey result = { } ;
result . type = DN_DSMapKeyType_Buffer ;
result . buffer_data = data ;
result . buffer_size = DN_CAST ( DN_U32 ) size ;
result . hash = DN_DSMap_Hash ( map , result ) ;
return result ;
}
template < typename T >
DN_DSMapKey DN_DSMap_KeyBufferAsU64NoHash ( DN_DSMap < T > const * map , void const * data , DN_U32 size )
{
DN_DSMapKey result = { } ;
result . type = DN_DSMapKeyType_BufferAsU64NoHash ;
result . buffer_data = data ;
result . buffer_size = DN_CAST ( DN_U32 ) size ;
DN_ASSERT ( size > = sizeof ( result . hash ) ) ;
DN_MEMCPY ( & result . hash , data , sizeof ( result . hash ) ) ;
return result ;
}
template < typename T > DN_DSMapKey DN_DSMap_KeyU64 ( DN_DSMap < T > const * map , DN_U64 u64 )
{
DN_DSMapKey result = { } ;
result . type = DN_DSMapKeyType_U64 ;
result . u64 = u64 ;
result . hash = DN_DSMap_Hash ( map , result ) ;
return result ;
}
template < typename T > DN_DSMapKey DN_DSMap_KeyStr8 ( DN_DSMap < T > const * map , DN_Str8 string )
{
DN_DSMapKey result = DN_DSMap_KeyBuffer ( map , string . data , string . size ) ;
return result ;
}
# endif // !defined(DN_NO_DSMAP)
# if !defined(DN_NO_LIST)
// NOTE: [$LIST] DN_List //////////////////////////////////////////////////////////////////////////
template < typename T > DN_List < T > DN_List_Init ( DN_USize chunk_size )
{
DN_List < T > result = { } ;
result . chunk_size = chunk_size ;
return result ;
}
template < typename T , size_t N > DN_List < T > DN_List_InitCArray ( DN_Arena * arena , DN_USize chunk_size , T const ( & array ) [ N ] )
{
DN_List < T > result = DN_List_Init < T > ( arena , chunk_size ) ;
DN_FOR_UINDEX ( index , N )
DN_List_Add ( & result , array [ index ] ) ;
return result ;
}
template < typename T > DN_List < T > DN_List_InitSliceCopy ( DN_Arena * arena , DN_USize chunk_size , DN_Slice < T > slice )
{
DN_List < T > result = DN_List_Init < T > ( arena , chunk_size ) ;
DN_FOR_UINDEX ( index , slice . size )
DN_List_Add ( & result , slice . data [ index ] ) ;
return result ;
}
template < typename T > DN_API bool DN_List_AttachTail_ ( DN_List < T > * list , DN_ListChunk < T > * tail )
{
if ( ! tail )
return false ;
if ( list - > tail ) {
list - > tail - > next = tail ;
tail - > prev = list - > tail ;
}
list - > tail = tail ;
if ( ! list - > head )
list - > head = list - > tail ;
return true ;
}
template < typename T > DN_API DN_ListChunk < T > * DN_List_AllocArena_ ( DN_List < T > * list , DN_Arena * arena , DN_USize count )
{
auto * result = DN_Arena_New ( arena , DN_ListChunk < T > , DN_ZeroMem_Yes ) ;
DN_ArenaTempMem tmem = DN_Arena_TempMemBegin ( arena ) ;
if ( ! result )
return nullptr ;
DN_USize items = DN_MAX ( list - > chunk_size , count ) ;
result - > data = DN_Arena_NewArray ( arena , T , items , DN_ZeroMem_Yes ) ;
result - > size = items ;
if ( ! result - > data ) {
DN_Arena_TempMemEnd ( tmem ) ;
result = nullptr ;
}
DN_List_AttachTail_ ( list , result ) ;
return result ;
}
template < typename T > DN_API DN_ListChunk < T > * DN_List_AllocPool_ ( DN_List < T > * list , DN_Pool * pool , DN_USize count )
{
auto * result = DN_Pool_New ( pool , DN_ListChunk < T > ) ;
if ( ! result )
return nullptr ;
DN_USize items = DN_MAX ( list - > chunk_size , count ) ;
result - > data = DN_Pool_NewArray ( pool , T , items ) ;
result - > size = items ;
if ( ! result - > data ) {
DN_Pool_Dealloc ( result ) ;
result = nullptr ;
}
DN_List_AttachTail_ ( list , result ) ;
return result ;
}
template < typename T > DN_API T * DN_List_MakeArena ( DN_List < T > * list , DN_Arena * arena , DN_USize count )
{
if ( list - > chunk_size = = 0 )
list - > chunk_size = 128 ;
if ( ! list - > tail | | ( list - > tail - > count + count ) > list - > tail - > size ) {
if ( ! DN_List_AllocArena_ ( list , arena , count ) )
return nullptr ;
}
T * result = list - > tail - > data + list - > tail - > count ;
list - > tail - > count + = count ;
list - > count + = count ;
return result ;
}
template < typename T > DN_API T * DN_List_MakePool ( DN_List < T > * list , DN_Pool * pool , DN_USize count )
{
if ( list - > chunk_size = = 0 )
list - > chunk_size = 128 ;
if ( ! list - > tail | | ( list - > tail - > count + count ) > list - > tail - > size ) {
if ( ! DN_List_AllocPool_ ( list , pool , count ) )
return nullptr ;
}
T * result = list - > tail - > data + list - > tail - > count ;
list - > tail - > count + = count ;
list - > count + = count ;
return result ;
}
template < typename T > DN_API T * DN_List_AddArena ( DN_List < T > * list , DN_Arena * arena , T const & value )
{
T * result = DN_List_MakeArena ( list , arena , 1 ) ;
* result = value ;
return result ;
}
template < typename T > DN_API T * DN_List_AddPool ( DN_List < T > * list , DN_Pool * pool , T const & value )
{
T * result = DN_List_MakePool ( list , pool , 1 ) ;
* result = value ;
return result ;
}
template < typename T , size_t N > DN_API bool DN_List_AddCArray ( DN_List < T > * list , T const ( & array ) [ N ] )
{
if ( ! list )
return false ;
for ( T const & item : array ) {
if ( ! DN_List_Add ( list , item ) )
return false ;
}
return true ;
}
template < typename T > DN_API void DN_List_AddListArena ( DN_List < T > * list , DN_Arena * arena , DN_List < T > other )
{
if ( ! list )
return ;
// TODO(doyle): Copy chunk by chunk
for ( DN_ListIterator < T > it = { } ; DN_List_Iterate ( & other , & it , 0 /*start_index*/ ) ; )
DN_List_AddArena ( list , arena , * it . data ) ;
}
template < typename T > DN_API void DN_List_AddListPool ( DN_List < T > * list , DN_Pool * pool , DN_List < T > other )
{
if ( ! list )
return ;
// TODO(doyle): Copy chunk by chunk
for ( DN_ListIterator < T > it = { } ; DN_List_Iterate ( & other , & it , 0 /*start_index*/ ) ; )
DN_List_AddPool ( list , pool , * it . data ) ;
}
template < typename T > void DN_List_Clear ( DN_List < T > * list )
{
if ( ! list )
return ;
list - > head = list - > tail = nullptr ;
list - > count = 0 ;
}
template < typename T > DN_API bool DN_List_Iterate ( DN_List < T > * list , DN_ListIterator < T > * it , DN_USize start_index )
{
bool result = false ;
if ( ! list | | ! it | | list - > chunk_size < = 0 )
return result ;
if ( it - > init ) {
it - > index + + ;
} else {
* it = { } ;
if ( start_index = = 0 ) {
it - > chunk = list - > head ;
} else {
DN_List_At ( list , start_index , & it - > chunk ) ;
if ( list - > chunk_size > 0 )
it - > chunk_data_index = start_index % list - > chunk_size ;
}
it - > init = true ;
}
if ( it - > chunk ) {
if ( it - > chunk_data_index > = it - > chunk - > count ) {
it - > chunk = it - > chunk - > next ;
it - > chunk_data_index = 0 ;
}
if ( it - > chunk ) {
it - > data = it - > chunk - > data + it - > chunk_data_index + + ;
result = true ;
}
}
if ( ! it - > chunk )
DN_ASSERT ( result = = false ) ;
return result ;
}
template < typename T > DN_API T * DN_List_At ( DN_List < T > * list , DN_USize index , DN_ListChunk < T > * * at_chunk )
{
if ( ! list | | index > = list - > count | | ! list - > head )
return nullptr ;
// NOTE: Scan forwards to the chunk we need. We don't have random access to chunks
DN_ListChunk < T > * * chunk = & list - > head ;
DN_USize running_index = index ;
for ( ; ( * chunk ) & & running_index > = ( * chunk ) - > size ; chunk = & ( ( * chunk ) - > next ) )
running_index - = ( * chunk ) - > size ;
T * result = nullptr ;
if ( * chunk )
result = ( * chunk ) - > data + running_index ;
if ( result & & at_chunk )
* at_chunk = * chunk ;
return result ;
}
template < typename T > DN_Slice < T > DN_List_ToSliceCopy ( DN_List < T > const * list , DN_Arena * arena )
{
// TODO(doyle): Chunk memcopies is much faster
DN_Slice < T > result = DN_Slice_Alloc < T > ( arena , list - > count , DN_ZeroMem_No ) ;
if ( result . size ) {
DN_USize slice_index = 0 ;
DN_MSVC_WARNING_PUSH
DN_MSVC_WARNING_DISABLE ( 6011 ) // Dereferencing NULL pointer 'x'
for ( DN_ListIterator < T > it = { } ; DN_List_Iterate < T > ( DN_CAST ( DN_List < T > * ) list , & it , 0 ) ; )
result . data [ slice_index + + ] = * it . data ;
DN_MSVC_WARNING_POP
DN_ASSERT ( slice_index = = result . size ) ;
}
return result ;
}
# endif // !defined(DN_NO_LIST)
// NOTE: [$SLIC] DN_Slice /////////////////////////////////////////////////////////////////////////
DN_API DN_Str8 DN_Slice_Str8Render ( DN_Arena * arena , DN_Slice < DN_Str8 > array , DN_Str8 separator )
{
DN_Str8 result = { } ;
2024-01-31 23:49:23 +11:00
if ( ! arena )
return result ;
2025-02-14 00:27:42 +11:00
DN_USize total_size = 0 ;
for ( DN_USize index = 0 ; index < array . size ; index + + ) {
2024-01-31 23:49:23 +11:00
if ( index )
total_size + = separator . size ;
2025-02-14 00:27:42 +11:00
DN_Str8 item = array . data [ index ] ;
2024-01-31 23:49:23 +11:00
total_size + = item . size ;
}
2025-02-14 00:27:42 +11:00
result = DN_Str8_Alloc ( arena , total_size , DN_ZeroMem_No ) ;
2024-01-31 23:49:23 +11:00
if ( result . data ) {
2025-02-14 00:27:42 +11:00
DN_USize write_index = 0 ;
for ( DN_USize index = 0 ; index < array . size ; index + + ) {
2024-01-31 23:49:23 +11:00
if ( index ) {
2025-02-14 00:27:42 +11:00
DN_MEMCPY ( result . data + write_index , separator . data , separator . size ) ;
2024-01-31 23:49:23 +11:00
write_index + = separator . size ;
}
2025-02-14 00:27:42 +11:00
DN_Str8 item = array . data [ index ] ;
DN_MEMCPY ( result . data + write_index , item . data , item . size ) ;
2024-01-31 23:49:23 +11:00
write_index + = item . size ;
}
}
return result ;
}
2025-02-14 00:27:42 +11:00
DN_API DN_Str8 DN_Slice_Str8RenderSpaceSeparated ( DN_Arena * arena , DN_Slice < DN_Str8 > array )
2024-01-31 23:49:23 +11:00
{
2025-02-14 00:27:42 +11:00
DN_Str8 result = DN_Slice_Str8Render ( arena , array , DN_STR8 ( " " ) ) ;
2024-01-31 23:49:23 +11:00
return result ;
}
2025-02-14 00:27:42 +11:00
DN_API DN_Str16 DN_Slice_Str16Render ( DN_Arena * arena , DN_Slice < DN_Str16 > array , DN_Str16 separator )
2024-08-01 13:34:36 +10:00
{
2025-02-14 00:27:42 +11:00
DN_Str16 result = { } ;
2024-08-01 13:34:36 +10:00
if ( ! arena )
return result ;
2025-02-14 00:27:42 +11:00
DN_USize total_size = 0 ;
for ( DN_USize index = 0 ; index < array . size ; index + + ) {
2024-08-01 13:34:36 +10:00
if ( index )
total_size + = separator . size ;
2025-02-14 00:27:42 +11:00
DN_Str16 item = array . data [ index ] ;
2024-08-01 13:34:36 +10:00
total_size + = item . size ;
}
2025-02-14 00:27:42 +11:00
result = { DN_Arena_NewArray ( arena , wchar_t , total_size + 1 , DN_ZeroMem_No ) , total_size } ;
2024-08-01 13:34:36 +10:00
if ( result . data ) {
2025-02-14 00:27:42 +11:00
DN_USize write_index = 0 ;
for ( DN_USize index = 0 ; index < array . size ; index + + ) {
2024-08-01 13:34:36 +10:00
if ( index ) {
2025-02-14 00:27:42 +11:00
DN_MEMCPY ( result . data + write_index , separator . data , separator . size * sizeof ( result . data [ 0 ] ) ) ;
2024-08-01 13:34:36 +10:00
write_index + = separator . size ;
}
2025-02-14 00:27:42 +11:00
DN_Str16 item = array . data [ index ] ;
DN_MEMCPY ( result . data + write_index , item . data , item . size * sizeof ( result . data [ 0 ] ) ) ;
2024-08-01 13:34:36 +10:00
write_index + = item . size ;
}
}
result . data [ total_size ] = 0 ;
return result ;
}
2025-02-14 00:27:42 +11:00
DN_API DN_Str16 DN_Slice_Str16RenderSpaceSeparated ( DN_Arena * arena , DN_Slice < DN_Str16 > array )
2024-08-01 13:34:36 +10:00
{
2025-02-14 00:27:42 +11:00
DN_Str16 result = DN_Slice_Str16Render ( arena , array , DN_STR16 ( L " " ) ) ;
2024-08-01 13:34:36 +10:00
return result ;
}
2025-02-14 00:27:42 +11:00
# if !defined(DN_NO_DSMAP)
// NOTE: [$DMAP] DN_DSMap /////////////////////////////////////////////////////////////////////////
DN_API DN_DSMapKey DN_DSMap_KeyU64NoHash ( DN_U64 u64 )
2023-07-05 00:04:53 +10:00
{
2025-02-14 00:27:42 +11:00
DN_DSMapKey result = { } ;
result . type = DN_DSMapKeyType_U64NoHash ;
2024-08-01 13:34:36 +10:00
result . u64 = u64 ;
2025-02-14 00:27:42 +11:00
result . hash = DN_CAST ( DN_U32 ) u64 ;
2023-07-05 00:04:53 +10:00
return result ;
}
2025-02-14 00:27:42 +11:00
DN_API bool DN_DSMap_KeyEquals ( DN_DSMapKey lhs , DN_DSMapKey rhs )
2023-07-05 00:04:53 +10:00
{
bool result = false ;
if ( lhs . type = = rhs . type & & lhs . hash = = rhs . hash ) {
switch ( lhs . type ) {
2025-02-14 00:27:42 +11:00
case DN_DSMapKeyType_Invalid : result = true ; break ;
case DN_DSMapKeyType_U64NoHash : result = true ; break ;
case DN_DSMapKeyType_U64 : result = lhs . u64 = = rhs . u64 ; break ;
2024-08-01 13:34:36 +10:00
2025-02-14 00:27:42 +11:00
case DN_DSMapKeyType_BufferAsU64NoHash : /*FALLTHRU*/
case DN_DSMapKeyType_Buffer : {
2024-08-01 13:34:36 +10:00
if ( lhs . buffer_size = = rhs . buffer_size )
2025-02-14 00:27:42 +11:00
result = DN_MEMCMP ( lhs . buffer_data , rhs . buffer_data , lhs . buffer_size ) = = 0 ;
2024-08-01 13:34:36 +10:00
} break ;
2023-07-05 00:04:53 +10:00
}
}
return result ;
}
2025-02-14 00:27:42 +11:00
DN_API bool operator = = ( DN_DSMapKey lhs , DN_DSMapKey rhs )
2023-07-05 00:04:53 +10:00
{
2025-02-14 00:27:42 +11:00
bool result = DN_DSMap_KeyEquals ( lhs , rhs ) ;
2023-07-05 00:04:53 +10:00
return result ;
}
2025-02-14 00:27:42 +11:00
# endif // !defined(DN_NO_DSMAP)