2024-04-18 12:59:11 +00:00
# pragma once
# include "dqn.h"
2024-03-25 05:11:57 +00:00
/*
2024-01-31 12:49:23 +00:00
////////////////////////////////////////////////////////////////////////////////////////////////////
//
/ / $ $ $ $ $ $ \ $ $ $ $ $ $ \ $ $ \ $ $ \ $ $ $ $ $ $ $ $ \ $ $ $ $ $ $ \ $ $ $ $ $ $ \ $ $ \ $ $ \ $ $ $ $ $ $ $ $ \ $ $ $ $ $ $ $ \ $ $ $ $ $ $ \
/ / $ $ __ $ $ \ $ $ __ $ $ \ $ $ $ \ $ $ | \ __ $ $ __ | $ $ __ $ $ \ \ _ $ $ _ | $ $ $ \ $ $ | $ $ _____ | $ $ __ $ $ \ $ $ __ $ $ \
// $$ / \__|$$ / $$ |$$$$\ $$ | $$ | $$ / $$ | $$ | $$$$\ $$ |$$ | $$ | $$ |$$ / \__|
/ / $ $ | $ $ | $ $ | $ $ $ $ \ $ $ | $ $ | $ $ $ $ $ $ $ $ | $ $ | $ $ $ $ \ $ $ | $ $ $ $ $ \ $ $ $ $ $ $ $ | \ $ $ $ $ $ $ \
/ / $ $ | $ $ | $ $ | $ $ \ $ $ $ $ | $ $ | $ $ __ $ $ | $ $ | $ $ \ $ $ $ $ | $ $ __ | $ $ __ $ $ < \ ____ $ $ \
// $$ | $$\ $$ | $$ |$$ |\$$$ | $$ | $$ | $$ | $$ | $$ |\$$$ |$$ | $$ | $$ |$$\ $$ |
// \$$$$$$ | $$$$$$ |$$ | \$$ | $$ | $$ | $$ |$$$$$$\ $$ | \$$ |$$$$$$$$\ $$ | $$ |\$$$$$$ |
// \______/ \______/ \__| \__| \__| \__| \__|\______|\__| \__|\________|\__| \__| \______/
//
// dqn_containers.h -- Data structures for storing data (e.g. arrays and hash tables)
//
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// [$CARR] Dqn_CArray -- -- Basic operations on C arrays for VArray/SArray/FArray to reuse
// [$VARR] Dqn_VArray -- DQN_VARRAY -- Array backed by virtual memory arena
// [$SARR] Dqn_SArray -- DQN_SARRAY -- Array that are allocated but cannot resize
// [$FARR] Dqn_FArray -- DQN_FARRAY -- Fixed-size arrays
// [$SLIC] Dqn_Slice -- -- Pointe and length container of data
// [$DMAP] Dqn_DSMap -- DQN_DSMAP -- Hashtable, 70% max load, PoT size, linear probe, chain repair
// [$LIST] Dqn_List -- DQN_LIST -- Chunked linked lists, append only
//
////////////////////////////////////////////////////////////////////////////////////////////////////
2024-03-25 05:11:57 +00:00
*/
2024-01-31 12:49:23 +00:00
// NOTE: [$CARR] Dqn_CArray ////////////////////////////////////////////////////////////////////////
2023-08-31 12:10:47 +00:00
enum Dqn_ArrayErase
{
Dqn_ArrayErase_Unstable ,
Dqn_ArrayErase_Stable ,
} ;
2023-10-24 13:11:48 +00:00
struct Dqn_ArrayEraseResult
{
// The next index your for-index should be set to such that you can continue
// to iterate the remainder of the array, e.g:
//
// for (Dqn_usize index = 0; index < array.size; index++) {
// if (erase)
// index = Dqn_FArray_EraseRange(&array, index, -3, Dqn_ArrayErase_Unstable);
// }
Dqn_usize it_index ;
Dqn_usize items_erased ; // The number of items erased
} ;
2024-01-31 12:49:23 +00:00
template < typename T > struct Dqn_ArrayFindResult
2023-10-24 13:11:48 +00:00
{
T * data ; // Pointer to the value if a match is found, null pointer otherwise
Dqn_usize index ; // Index to the value if a match is found, 0 otherwise
} ;
2023-07-05 12:39:43 +00:00
# if !defined(DQN_NO_VARRAY)
2024-01-31 12:49:23 +00:00
// NOTE: [$VARR] Dqn_VArray ////////////////////////////////////////////////////////////////////////
2023-07-06 11:13:52 +00:00
// TODO(doyle): Add an API for shrinking the array by decomitting pages back to
// the OS.
2023-07-04 14:04:53 +00:00
template < typename T > struct Dqn_VArray
{
2024-01-31 12:49:23 +00:00
Dqn_Arena arena ; // Allocator for the array
T * data ; // Pointer to the start of the array items in the block of memory
Dqn_usize size ; // Number of items currently in the array
Dqn_usize max ; // Maximum number of items this array can store
2023-07-04 14:04:53 +00:00
T * begin ( ) { return data ; }
T * end ( ) { return data + size ; }
T const * begin ( ) const { return data ; }
T const * end ( ) const { return data + size ; }
} ;
# endif // !defined(DQN_NO_VARRAY)
2023-08-31 12:10:47 +00:00
# if !defined(DQN_NO_SARRAY)
2024-01-31 12:49:23 +00:00
// NOTE: [$SARR] Dqn_SArray ////////////////////////////////////////////////////////////////////////
2023-08-31 12:10:47 +00:00
template < typename T > struct Dqn_SArray
{
T * data ; // Pointer to the start of the array items in the block of memory
Dqn_usize size ; // Number of items currently in the array
Dqn_usize max ; // Maximum number of items this array can store
T * begin ( ) { return data ; }
T * end ( ) { return data + size ; }
T const * begin ( ) const { return data ; }
T const * end ( ) const { return data + size ; }
} ;
# endif // !defined(DQN_NO_SARRAY)
# if !defined(DQN_NO_FARRAY)
2024-01-31 12:49:23 +00:00
// NOTE: [$FARR] Dqn_FArray ////////////////////////////////////////////////////////////////////////
2023-08-31 12:10:47 +00:00
template < typename T , Dqn_usize N > struct Dqn_FArray
{
T data [ N ] ; // Pointer to the start of the array items in the block of memory
Dqn_usize size ; // Number of items currently in the array
T * begin ( ) { return data ; }
T * end ( ) { return data + size ; }
T const * begin ( ) const { return data ; }
T const * end ( ) const { return data + size ; }
} ;
2024-01-31 12:49:23 +00:00
template < typename T > using Dqn_FArray8 = Dqn_FArray < T , 8 > ;
template < typename T > using Dqn_FArray16 = Dqn_FArray < T , 16 > ;
template < typename T > using Dqn_FArray32 = Dqn_FArray < T , 32 > ;
template < typename T > using Dqn_FArray64 = Dqn_FArray < T , 64 > ;
2023-08-31 12:10:47 +00:00
# endif // !defined(DQN_NO_FARRAY)
2023-07-04 14:04:53 +00:00
# if !defined(DQN_NO_DSMAP)
2024-01-31 12:49:23 +00:00
// NOTE: [$DMAP] Dqn_DSMap /////////////////////////////////////////////////////////////////////////
2023-07-04 14:04:53 +00:00
enum Dqn_DSMapKeyType
{
2024-08-01 03:34:36 +00:00
// Key | Key Hash | Map Index
2023-07-04 14:04:53 +00:00
Dqn_DSMapKeyType_Invalid ,
2024-08-01 03:34:36 +00:00
Dqn_DSMapKeyType_U64 , // U64 | Hash(U64) | Hash(U64) % map_size
Dqn_DSMapKeyType_U64NoHash , // U64 | U64 | U64 % map_size
Dqn_DSMapKeyType_Buffer , // Buffer | Hash(buffer) | Hash(buffer) % map_size
Dqn_DSMapKeyType_BufferAsU64NoHash , // Buffer | U64(buffer[0:4]) | U64(buffer[0:4]) % map_size
2023-07-04 14:04:53 +00:00
} ;
struct Dqn_DSMapKey
{
Dqn_DSMapKeyType type ;
2024-08-01 03:34:36 +00:00
uint32_t hash ; // Hash to lookup in the map. If it equals, we check that the original key payload matches
void const * buffer_data ;
uint32_t buffer_size ;
uint64_t u64 ;
bool no_copy_buffer ;
2023-07-04 14:04:53 +00:00
} ;
2024-01-31 12:49:23 +00:00
template < typename T >
struct Dqn_DSMapSlot
2023-07-04 14:04:53 +00:00
{
Dqn_DSMapKey key ; ///< Hash table lookup key
T value ; ///< Hash table value
} ;
2024-08-01 03:34:36 +00:00
typedef uint32_t Dqn_DSMapFlags ;
enum Dqn_DSMapFlags_
{
Dqn_DSMapFlags_Nil = 0 ,
Dqn_DSMapFlags_DontFreeArenaOnResize = 1 < < 0 ,
} ;
2023-07-04 14:04:53 +00:00
using Dqn_DSMapHashFunction = uint32_t ( Dqn_DSMapKey key , uint32_t seed ) ;
template < typename T > struct Dqn_DSMap
{
2023-07-06 11:13:52 +00:00
uint32_t * hash_to_slot ; // Mapping from hash to a index in the slots array
Dqn_DSMapSlot < T > * slots ; // Values of the array stored contiguously, non-sorted order
uint32_t size ; // Total capacity of the map and is a power of two
uint32_t occupied ; // Number of slots used in the hash table
2024-01-31 12:49:23 +00:00
Dqn_Arena * arena ; // Backing arena for the hash table
2023-07-06 11:13:52 +00:00
uint32_t initial_size ; // Initial map size, map cannot shrink on erase below this size
Dqn_DSMapHashFunction * hash_function ; // Custom hashing function to use if field is set
uint32_t hash_seed ; // Seed for the hashing function, when 0, DQN_DS_MAP_DEFAULT_HASH_SEED is used
2024-08-01 03:34:36 +00:00
Dqn_DSMapFlags flags ;
2023-07-04 14:04:53 +00:00
} ;
2024-01-31 12:49:23 +00:00
template < typename T > struct Dqn_DSMapResult
2023-10-24 13:11:48 +00:00
{
bool found ;
Dqn_DSMapSlot < T > * slot ;
T * value ;
} ;
2023-07-04 14:04:53 +00:00
# endif // !defined(DQN_NO_DSMAP)
2023-07-05 12:39:43 +00:00
# if !defined(DQN_NO_LIST)
2024-01-31 12:49:23 +00:00
// NOTE: [$LIST] Dqn_List //////////////////////////////////////////////////////////////////////////
2023-07-04 14:04:53 +00:00
template < typename T > struct Dqn_ListChunk
{
T * data ;
Dqn_usize size ;
Dqn_usize count ;
Dqn_ListChunk < T > * next ;
Dqn_ListChunk < T > * prev ;
} ;
template < typename T > struct Dqn_ListIterator
{
2023-07-06 11:13:52 +00:00
Dqn_b32 init ; // True if Dqn_List_Iterate has been called at-least once on this iterator
Dqn_ListChunk < T > * chunk ; // The chunk that the iterator is reading from
Dqn_usize chunk_data_index ; // The index in the chunk the iterator is referencing
2023-10-24 13:11:48 +00:00
Dqn_usize index ; // The index of the item in the list as if it was flat array
2023-07-06 11:13:52 +00:00
T * data ; // Pointer to the data the iterator is referencing. Nullptr if invalid.
2023-07-04 14:04:53 +00:00
} ;
template < typename T > struct Dqn_List
{
Dqn_usize count ; // Cumulative count of all items made across all list chunks
Dqn_usize chunk_size ; // When new ListChunk's are required, the minimum 'data' entries to allocate for that node.
Dqn_ListChunk < T > * head ;
Dqn_ListChunk < T > * tail ;
} ;
2024-01-31 12:49:23 +00:00
# endif // !defined(DQN_NO_LIST)
2023-07-04 14:04:53 +00:00
2024-01-31 12:49:23 +00:00
template < typename T > Dqn_ArrayEraseResult Dqn_CArray_EraseRange ( T * data , Dqn_usize * size , Dqn_usize begin_index , Dqn_isize count , Dqn_ArrayErase erase ) ;
template < typename T > T * Dqn_CArray_MakeArray ( T * data , Dqn_usize * size , Dqn_usize max , Dqn_usize count , Dqn_ZeroMem zero_mem ) ;
template < typename T > T * Dqn_CArray_InsertArray ( T * data , Dqn_usize * size , Dqn_usize max , Dqn_usize index , T const * items , Dqn_usize count ) ;
template < typename T > T Dqn_CArray_PopFront ( T * data , Dqn_usize * size , Dqn_usize count ) ;
template < typename T > T Dqn_CArray_PopBack ( T * data , Dqn_usize * size , Dqn_usize count ) ;
template < typename T > Dqn_ArrayFindResult < T > Dqn_CArray_Find ( T * data , Dqn_usize size , T const & value ) ;
2023-10-24 13:11:48 +00:00
2024-01-31 12:49:23 +00:00
# if !defined(DQN_NO_VARRAY)
template < typename T > Dqn_VArray < T > Dqn_VArray_InitByteSize ( Dqn_usize byte_size , uint8_t arena_flags ) ;
template < typename T > Dqn_VArray < T > Dqn_VArray_Init ( Dqn_usize max , uint8_t arena_flags ) ;
2024-02-01 13:08:31 +00:00
template < typename T > Dqn_VArray < T > Dqn_VArray_InitSlice ( Dqn_Slice < T > slice , Dqn_usize max , uint8_t arena_flags ) ;
template < typename T , Dqn_usize N > Dqn_VArray < T > Dqn_VArray_InitCArray ( T const ( & items ) [ N ] , Dqn_usize max , uint8_t arena_flags ) ;
2024-01-31 12:49:23 +00:00
template < typename T > void Dqn_VArray_Deinit ( Dqn_VArray < T > * array ) ;
template < typename T > bool Dqn_VArray_IsValid ( Dqn_VArray < T > const * array ) ;
2024-02-01 13:08:31 +00:00
template < typename T > Dqn_Slice < T > Dqn_VArray_Slice ( Dqn_VArray < T > const * array ) ;
2024-01-31 12:49:23 +00:00
template < typename T > bool Dqn_VArray_Reserve ( Dqn_VArray < T > * array , Dqn_usize count ) ;
template < typename T > T * Dqn_VArray_AddArray ( Dqn_VArray < T > * array , T const * items , Dqn_usize count ) ;
template < typename T , Dqn_usize N > T * Dqn_VArray_AddCArray ( Dqn_VArray < T > * array , T const ( & items ) [ N ] ) ;
template < typename T > T * Dqn_VArray_Add ( Dqn_VArray < T > * array , T const & item ) ;
# define Dqn_VArray_AddArrayAssert(...) DQN_HARD_ASSERT(Dqn_VArray_AddArray(__VA_ARGS__))
# define Dqn_VArray_AddCArrayAssert(...) DQN_HARD_ASSERT(Dqn_VArray_AddCArray(__VA_ARGS__))
# define Dqn_VArray_AddAssert(...) DQN_HARD_ASSERT(Dqn_VArray_Add(__VA_ARGS__))
template < typename T > T * Dqn_VArray_MakeArray ( Dqn_VArray < T > * array , Dqn_usize count , Dqn_ZeroMem zero_mem ) ;
template < typename T > T * Dqn_VArray_Make ( Dqn_VArray < T > * array , Dqn_ZeroMem zero_mem ) ;
# define Dqn_VArray_MakeArrayAssert(...) DQN_HARD_ASSERT(Dqn_VArray_MakeArray(__VA_ARGS__))
# define Dqn_VArray_MakeAssert(...) DQN_HARD_ASSERT(Dqn_VArray_Make(__VA_ARGS__))
template < typename T > T * Dqn_VArray_InsertArray ( Dqn_VArray < T > * array , Dqn_usize index , T const * items , Dqn_usize count ) ;
template < typename T , Dqn_usize N > T * Dqn_VArray_InsertCArray ( Dqn_VArray < T > * array , Dqn_usize index , T const ( & items ) [ N ] ) ;
template < typename T > T * Dqn_VArray_Insert ( Dqn_VArray < T > * array , Dqn_usize index , T const & item ) ;
# define Dqn_VArray_InsertArrayAssert(...) DQN_HARD_ASSERT(Dqn_VArray_InsertArray(__VA_ARGS__))
# define Dqn_VArray_InsertCArrayAssert(...) DQN_HARD_ASSERT(Dqn_VArray_InsertCArray(__VA_ARGS__))
# define Dqn_VArray_InsertAssert(...) DQN_HARD_ASSERT(Dqn_VArray_Insert(__VA_ARGS__))
template < typename T > T Dqn_VArray_PopFront ( Dqn_VArray < T > * array , Dqn_usize count ) ;
template < typename T > T Dqn_VArray_PopBack ( Dqn_VArray < T > * array , Dqn_usize count ) ;
template < typename T > Dqn_ArrayEraseResult Dqn_VArray_EraseRange ( Dqn_VArray < T > * array , Dqn_usize begin_index , Dqn_isize count , Dqn_ArrayErase erase ) ;
template < typename T > void Dqn_VArray_Clear ( Dqn_VArray < T > * array , Dqn_ZeroMem zero_mem ) ;
# endif // !defined(DQN_NO_VARRAY)
2024-02-01 13:08:31 +00:00
// NOTE: [$SARR] Dqn_SArray ////////////////////////////////////////////////////////////////////////
2024-01-31 12:49:23 +00:00
# if !defined(DQN_NO_SARRAY)
template < typename T > Dqn_SArray < T > Dqn_SArray_Init ( Dqn_Arena * arena , Dqn_usize size , Dqn_ZeroMem zero_mem ) ;
2024-02-01 13:08:31 +00:00
template < typename T > Dqn_SArray < T > Dqn_SArray_InitSlice ( Dqn_Arena * arena , Dqn_Slice < T > slice , Dqn_usize size , Dqn_ZeroMem zero_mem ) ;
2024-02-25 11:37:14 +00:00
template < typename T , size_t N > Dqn_SArray < T > Dqn_SArray_InitCArray ( Dqn_Arena * arena , T const ( & array ) [ N ] , Dqn_usize size , Dqn_ZeroMem ) ;
2024-01-31 12:49:23 +00:00
template < typename T > bool Dqn_SArray_IsValid ( Dqn_SArray < T > const * array ) ;
template < typename T > Dqn_Slice < T > Dqn_SArray_Slice ( Dqn_SArray < T > const * array ) ;
template < typename T > T * Dqn_SArray_AddArray ( Dqn_SArray < T > * array , T const * items , Dqn_usize count ) ;
template < typename T , Dqn_usize N > T * Dqn_SArray_AddCArray ( Dqn_SArray < T > * array , T const ( & items ) [ N ] ) ;
template < typename T > T * Dqn_SArray_Add ( Dqn_SArray < T > * array , T const & item ) ;
# define Dqn_SArray_AddArrayAssert(...) DQN_HARD_ASSERT(Dqn_SArray_AddArray(__VA_ARGS__))
# define Dqn_SArray_AddCArrayAssert(...) DQN_HARD_ASSERT(Dqn_SArray_AddCArray(__VA_ARGS__))
# define Dqn_SArray_AddAssert(...) DQN_HARD_ASSERT(Dqn_SArray_Add(__VA_ARGS__))
template < typename T > T * Dqn_SArray_MakeArray ( Dqn_SArray < T > * array , Dqn_usize count , Dqn_ZeroMem zero_mem ) ;
template < typename T > T * Dqn_SArray_Make ( Dqn_SArray < T > * array , Dqn_ZeroMem zero_mem ) ;
# define Dqn_SArray_MakeArrayAssert(...) DQN_HARD_ASSERT(Dqn_SArray_MakeArray(__VA_ARGS__))
# define Dqn_SArray_MakeAssert(...) DQN_HARD_ASSERT(Dqn_SArray_Make(__VA_ARGS__))
template < typename T > T * Dqn_SArray_InsertArray ( Dqn_SArray < T > * array , Dqn_usize index , T const * items , Dqn_usize count ) ;
template < typename T , Dqn_usize N > T * Dqn_SArray_InsertCArray ( Dqn_SArray < T > * array , Dqn_usize index , T const ( & items ) [ N ] ) ;
template < typename T > T * Dqn_SArray_Insert ( Dqn_SArray < T > * array , Dqn_usize index , T const & item ) ;
# define Dqn_SArray_InsertArrayAssert(...) DQN_HARD_ASSERT(Dqn_SArray_InsertArray(__VA_ARGS__))
# define Dqn_SArray_InsertCArrayAssert(...) DQN_HARD_ASSERT(Dqn_SArray_InsertCArray(__VA_ARGS__))
# define Dqn_SArray_InsertAssert(...) DQN_HARD_ASSERT(Dqn_SArray_Insert(__VA_ARGS__))
template < typename T > T Dqn_SArray_PopFront ( Dqn_SArray < T > * array , Dqn_usize count ) ;
template < typename T > T Dqn_SArray_PopBack ( Dqn_SArray < T > * array , Dqn_usize count ) ;
template < typename T > Dqn_ArrayEraseResult Dqn_SArray_EraseRange ( Dqn_SArray < T > * array , Dqn_usize begin_index , Dqn_isize count , Dqn_ArrayErase erase ) ;
template < typename T > void Dqn_SArray_Clear ( Dqn_SArray < T > * array ) ;
# endif // !defined(DQN_NO_SARRAY)
# if !defined(DQN_NO_FARRAY)
template < typename T , Dqn_usize N > Dqn_FArray < T , N > Dqn_FArray_Init ( T const * array , Dqn_usize count ) ;
2024-08-01 03:34:36 +00:00
# define Dqn_FArray_HasData(array) ((array).data && (array).size)
2024-02-01 13:08:31 +00:00
template < typename T , Dqn_usize N > Dqn_FArray < T , N > Dqn_FArray_InitSlice ( Dqn_Slice < T > slice ) ;
2024-01-31 12:49:23 +00:00
template < typename T , Dqn_usize N , Dqn_usize K > Dqn_FArray < T , N > Dqn_FArray_InitCArray ( T const ( & items ) [ K ] ) ;
template < typename T , Dqn_usize N > bool Dqn_FArray_IsValid ( Dqn_FArray < T , N > const * array ) ;
template < typename T , Dqn_usize N > Dqn_usize Dqn_FArray_Max ( Dqn_FArray < T , N > const * ) { return N ; }
template < typename T , Dqn_usize N > Dqn_Slice < T > Dqn_FArray_Slice ( Dqn_FArray < T , N > const * array ) ;
template < typename T , Dqn_usize N > T * Dqn_FArray_AddArray ( Dqn_FArray < T , N > * array , T const * items , Dqn_usize count ) ;
template < typename T , Dqn_usize N , Dqn_usize K > T * Dqn_FArray_AddCArray ( Dqn_FArray < T , N > * array , T const ( & items ) [ K ] ) ;
template < typename T , Dqn_usize N > T * Dqn_FArray_Add ( Dqn_FArray < T , N > * array , T const & item ) ;
# define Dqn_FArray_AddArrayAssert(...) DQN_HARD_ASSERT(Dqn_FArray_AddArray(__VA_ARGS__))
# define Dqn_FArray_AddCArrayAssert(...) DQN_HARD_ASSERT(Dqn_FArray_AddCArray(__VA_ARGS__))
# define Dqn_FArray_AddAssert(...) DQN_HARD_ASSERT(Dqn_FArray_Add(__VA_ARGS__))
template < typename T , Dqn_usize N > T * Dqn_FArray_MakeArray ( Dqn_FArray < T , N > * array , Dqn_usize count , Dqn_ZeroMem zero_mem ) ;
template < typename T , Dqn_usize N > T * Dqn_FArray_Make ( Dqn_FArray < T , N > * array , Dqn_ZeroMem zero_mem ) ;
# define Dqn_FArray_MakeArrayAssert(...) DQN_HARD_ASSERT(Dqn_FArray_MakeArray(__VA_ARGS__))
# define Dqn_FArray_MakeAssert(...) DQN_HARD_ASSERT(Dqn_FArray_Make(__VA_ARGS__))
template < typename T , Dqn_usize N > T * Dqn_FArray_InsertArray ( Dqn_FArray < T , N > * array , T const & item , Dqn_usize index ) ;
template < typename T , Dqn_usize N , Dqn_usize K > T * Dqn_FArray_InsertCArray ( Dqn_FArray < T , N > * array , Dqn_usize index , T const ( & items ) [ K ] ) ;
template < typename T , Dqn_usize N > T * Dqn_FArray_Insert ( Dqn_FArray < T , N > * array , Dqn_usize index , T const & item ) ;
# define Dqn_FArray_InsertArrayAssert(...) DQN_HARD_ASSERT(Dqn_FArray_InsertArray(__VA_ARGS__))
# define Dqn_FArray_InsertAssert(...) DQN_HARD_ASSERT(Dqn_FArray_Insert(__VA_ARGS__))
template < typename T , Dqn_usize N > T Dqn_FArray_PopFront ( Dqn_FArray < T , N > * array , Dqn_usize count ) ;
template < typename T , Dqn_usize N > T Dqn_FArray_PopBack ( Dqn_FArray < T , N > * array , Dqn_usize count ) ;
template < typename T , Dqn_usize N > Dqn_ArrayFindResult < T > Dqn_FArray_Find ( Dqn_FArray < T , N > * array , T const & find ) ;
template < typename T , Dqn_usize N > Dqn_ArrayEraseResult Dqn_FArray_EraseRange ( Dqn_FArray < T , N > * array , Dqn_usize begin_index , Dqn_isize count , Dqn_ArrayErase erase ) ;
template < typename T , Dqn_usize N > void Dqn_FArray_Clear ( Dqn_FArray < T , N > * array ) ;
# endif // !defined(DQN_NO_FARRAY)
# if !defined(DQN_NO_SLICE)
2024-02-01 13:08:31 +00:00
# define DQN_TO_SLICE(val) Dqn_Slice_Init((val)->data, (val)->size)
2024-01-31 12:49:23 +00:00
template < typename T > Dqn_Slice < T > Dqn_Slice_Init ( T * const data , Dqn_usize size ) ;
template < typename T , Dqn_usize N > Dqn_Slice < T > Dqn_Slice_InitCArray ( Dqn_Arena * arena , T const ( & array ) [ N ] ) ;
2024-04-18 12:59:11 +00:00
template < typename T > Dqn_Slice < T > Dqn_Slice_Copy ( Dqn_Arena * arena , Dqn_Slice < T > slice ) ;
template < typename T > Dqn_Slice < T > Dqn_Slice_CopyPtr ( Dqn_Arena * arena , T * const data , Dqn_usize size ) ;
2024-01-31 12:49:23 +00:00
template < typename T > Dqn_Slice < T > Dqn_Slice_Alloc ( Dqn_Arena * arena , Dqn_usize size , Dqn_ZeroMem zero_mem ) ;
Dqn_Str8 Dqn_Slice_Str8Render ( Dqn_Arena * arena , Dqn_Slice < Dqn_Str8 > array , Dqn_Str8 separator ) ;
Dqn_Str8 Dqn_Slice_Str8RenderSpaceSeparated ( Dqn_Arena * arena , Dqn_Slice < Dqn_Str8 > array ) ;
2024-08-01 03:34:36 +00:00
Dqn_Str16 Dqn_Slice_Str16Render ( Dqn_Arena * arena , Dqn_Slice < Dqn_Str16 > array , Dqn_Str16 separator ) ;
Dqn_Str16 Dqn_Slice_Str16RenderSpaceSeparated ( Dqn_Arena * arena , Dqn_Slice < Dqn_Str16 > array ) ;
2024-01-31 12:49:23 +00:00
# endif // !defined(DQN_NO_SLICE)
# if !defined(DQN_NO_DSMAP)
2024-08-01 03:34:36 +00:00
template < typename T > Dqn_DSMap < T > Dqn_DSMap_Init ( Dqn_Arena * arena , uint32_t size , Dqn_DSMapFlags flags ) ;
2024-01-31 12:49:23 +00:00
template < typename T > void Dqn_DSMap_Deinit ( Dqn_DSMap < T > * map , Dqn_ZeroMem zero_mem ) ;
template < typename T > bool Dqn_DSMap_IsValid ( Dqn_DSMap < T > const * map ) ;
template < typename T > uint32_t Dqn_DSMap_Hash ( Dqn_DSMap < T > const * map , Dqn_DSMapKey key ) ;
template < typename T > uint32_t Dqn_DSMap_HashToSlotIndex ( Dqn_DSMap < T > const * map , Dqn_DSMapKey key ) ;
template < typename T > Dqn_DSMapResult < T > Dqn_DSMap_Find ( Dqn_DSMap < T > const * map , Dqn_DSMapKey key ) ;
template < typename T > Dqn_DSMapResult < T > Dqn_DSMap_Make ( Dqn_DSMap < T > * map , Dqn_DSMapKey key ) ;
template < typename T > Dqn_DSMapResult < T > Dqn_DSMap_Set ( Dqn_DSMap < T > * map , Dqn_DSMapKey key , T const & value ) ;
template < typename T > Dqn_DSMapResult < T > Dqn_DSMap_FindKeyU64 ( Dqn_DSMap < T > const * map , uint64_t key ) ;
template < typename T > Dqn_DSMapResult < T > Dqn_DSMap_MakeKeyU64 ( Dqn_DSMap < T > * map , uint64_t key ) ;
template < typename T > Dqn_DSMapResult < T > Dqn_DSMap_SetKeyU64 ( Dqn_DSMap < T > * map , uint64_t key , T const & value ) ;
template < typename T > Dqn_DSMapResult < T > Dqn_DSMap_FindKeyStr8 ( Dqn_DSMap < T > const * map , Dqn_Str8 key ) ;
template < typename T > Dqn_DSMapResult < T > Dqn_DSMap_MakeKeyStr8 ( Dqn_DSMap < T > * map , Dqn_Str8 key ) ;
template < typename T > Dqn_DSMapResult < T > Dqn_DSMap_SetKeyStr8 ( Dqn_DSMap < T > * map , Dqn_Str8 key , T const & value ) ;
template < typename T > bool Dqn_DSMap_Resize ( Dqn_DSMap < T > * map , uint32_t size ) ;
template < typename T > bool Dqn_DSMap_Erase ( Dqn_DSMap < T > * map , Dqn_DSMapKey key ) ;
template < typename T > Dqn_DSMapKey Dqn_DSMap_KeyBuffer ( Dqn_DSMap < T > const * map , void const * data , uint32_t size ) ;
2024-08-01 03:34:36 +00:00
template < typename T > Dqn_DSMapKey Dqn_DSMap_KeyBufferAsU64NoHash ( Dqn_DSMap < T > const * map , void const * data , uint32_t size ) ;
2024-01-31 12:49:23 +00:00
template < typename T > Dqn_DSMapKey Dqn_DSMap_KeyU64 ( Dqn_DSMap < T > const * map , uint64_t u64 ) ;
template < typename T > Dqn_DSMapKey Dqn_DSMap_KeyStr8 ( Dqn_DSMap < T > const * map , Dqn_Str8 string ) ;
# define Dqn_DSMap_KeyCStr8(map, string) Dqn_DSMap_KeyBuffer(map, string, sizeof((string)) / sizeof((string)[0]) - 1)
DQN_API Dqn_DSMapKey Dqn_DSMap_KeyU64NoHash ( uint64_t u64 ) ;
DQN_API bool Dqn_DSMap_KeyEquals ( Dqn_DSMapKey lhs , Dqn_DSMapKey rhs ) ;
DQN_API bool operator = = ( Dqn_DSMapKey lhs , Dqn_DSMapKey rhs ) ;
# endif // !defined(DQN_NO_DSMAP)
# if !defined(DQN_NO_LIST)
2024-08-01 03:34:36 +00:00
template < typename T > Dqn_List < T > Dqn_List_Init ( Dqn_usize chunk_size ) ;
2024-01-31 12:49:23 +00:00
template < typename T , size_t N > Dqn_List < T > Dqn_List_InitCArray ( Dqn_Arena * arena , Dqn_usize chunk_size , T const ( & array ) [ N ] ) ;
template < typename T > T * Dqn_List_At ( Dqn_List < T > * list , Dqn_usize index , Dqn_ListChunk < T > * at_chunk ) ;
template < typename T > bool Dqn_List_Iterate ( Dqn_List < T > * list , Dqn_ListIterator < T > * it , Dqn_usize start_index ) ;
2024-08-01 03:34:36 +00:00
template < typename T > T * Dqn_List_MakeArena ( Dqn_List < T > * list , Dqn_Arena * arena , Dqn_usize count ) ;
template < typename T > T * Dqn_List_MakePool ( Dqn_List < T > * list , Dqn_ChunkPool * pool , Dqn_usize count ) ;
template < typename T > T * Dqn_List_AddArena ( Dqn_List < T > * list , Dqn_Arena * arena , T const & value ) ;
template < typename T > T * Dqn_List_AddPool ( Dqn_List < T > * list , Dqn_ChunkPool * pool , T const & value ) ;
template < typename T > void Dqn_List_AddListArena ( Dqn_List < T > * list , Dqn_Arena * arena , Dqn_List < T > other ) ;
template < typename T > void Dqn_List_AddListArena ( Dqn_List < T > * list , Dqn_ChunkPool * pool , Dqn_List < T > other ) ;
2024-01-31 12:49:23 +00:00
template < typename T > Dqn_Slice < T > Dqn_List_ToSliceCopy ( Dqn_List < T > const * list , Dqn_Arena * arena ) ;
2023-07-05 12:39:43 +00:00
# endif // !defined(DQN_NO_LIST)
2023-07-04 14:04:53 +00:00
2024-01-31 12:49:23 +00:00
// NOTE: [$CARR] Dqn_CArray ////////////////////////////////////////////////////////////////////////
2023-10-24 13:11:48 +00:00
template < typename T > Dqn_ArrayEraseResult Dqn_CArray_EraseRange ( T * data , Dqn_usize * size , Dqn_usize begin_index , Dqn_isize count , Dqn_ArrayErase erase )
2023-08-31 12:10:47 +00:00
{
2023-10-24 13:11:48 +00:00
Dqn_ArrayEraseResult result = { } ;
2023-08-31 12:10:47 +00:00
if ( ! data | | ! size | | * size = = 0 | | count = = 0 )
return result ;
2024-01-31 12:49:23 +00:00
DQN_ASSERTF ( count ! = - 1 , " There's a bug with negative element erases, see the Dqn_VArray section in dqn_docs.cpp " ) ;
2023-08-31 12:10:47 +00:00
// NOTE: Caculate the end index of the erase range
Dqn_isize abs_count = DQN_ABS ( count ) ;
Dqn_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 ) {
Dqn_usize tmp = begin_index ;
begin_index = end_index ;
end_index = tmp ;
}
// NOTE: Ensure indexes are within valid bounds
begin_index = DQN_MIN ( begin_index , * size ) ;
end_index = DQN_MIN ( end_index , * size - 1 ) ;
// NOTE: Erase the items in the range [begin_index, one_past_end_index)
Dqn_usize one_past_end_index = end_index + 1 ;
Dqn_usize erase_count = one_past_end_index - begin_index ;
if ( erase_count ) {
T * end = data + * size ;
T * dest = data + begin_index ;
if ( erase = = Dqn_ArrayErase_Stable ) {
T * src = dest + erase_count ;
DQN_MEMMOVE ( dest , src , ( end - src ) * sizeof ( T ) ) ;
} else {
T * src = end - erase_count ;
DQN_MEMCPY ( dest , src , ( end - src ) * sizeof ( T ) ) ;
}
* size - = erase_count ;
}
2023-10-24 13:11:48 +00:00
result . items_erased = erase_count ;
result . it_index = begin_index ;
2023-08-31 12:10:47 +00:00
return result ;
}
2023-10-24 13:11:48 +00:00
template < typename T > T * Dqn_CArray_MakeArray ( T * data , Dqn_usize * size , Dqn_usize max , Dqn_usize count , Dqn_ZeroMem zero_mem )
2023-08-31 12:10:47 +00:00
{
if ( ! data | | ! size | | count = = 0 )
return nullptr ;
2024-01-31 12:49:23 +00:00
if ( ! DQN_CHECKF ( ( * size + count ) < = max , " Array is out of space (user requested +%zu items, array has %zu/%zu items) " , count , * size , max ) )
2023-08-31 12:10:47 +00:00
return nullptr ;
// TODO: Use placement new? Why doesn't this work?
T * result = data + * size ;
* size + = count ;
if ( zero_mem = = Dqn_ZeroMem_Yes )
2024-01-31 12:49:23 +00:00
DQN_MEMSET ( result , 0 , sizeof ( * result ) * count ) ;
2023-08-31 12:10:47 +00:00
return result ;
}
2024-01-31 12:49:23 +00:00
template < typename T > T * Dqn_CArray_InsertArray ( T * data , Dqn_usize * size , Dqn_usize max , Dqn_usize index , T const * items , Dqn_usize count )
2023-10-24 13:11:48 +00:00
{
T * result = nullptr ;
if ( ! data | | ! size | | ! items | | count < = 0 | | ( ( * size + count ) > max ) )
return result ;
2024-01-31 12:49:23 +00:00
Dqn_usize clamped_index = DQN_MIN ( index , * size ) ;
2023-10-24 13:11:48 +00:00
if ( clamped_index ! = * size ) {
2024-03-19 12:11:00 +00:00
char const * src = DQN_CAST ( char * ) ( data + clamped_index ) ;
char const * dest = DQN_CAST ( char * ) ( data + ( clamped_index + count ) ) ;
char const * end = DQN_CAST ( char * ) ( data + ( * size ) ) ;
Dqn_usize bytes_to_move = end - src ;
DQN_MEMMOVE ( DQN_CAST ( void * ) dest , src , bytes_to_move ) ;
2023-10-24 13:11:48 +00:00
}
result = data + clamped_index ;
DQN_MEMCPY ( result , items , sizeof ( T ) * count ) ;
* size + = count ;
return result ;
}
template < typename T > T Dqn_CArray_PopFront ( T * data , Dqn_usize * size , Dqn_usize count )
{
T result = { } ;
if ( ! data | | ! size | | * size < = 0 )
return result ;
result = data [ 0 ] ;
Dqn_usize pop_count = DQN_MIN ( count , * size ) ;
DQN_MEMMOVE ( data , data + pop_count , ( * size - pop_count ) * sizeof ( T ) ) ;
* size - = pop_count ;
return result ;
}
template < typename T > T Dqn_CArray_PopBack ( T * data , Dqn_usize * size , Dqn_usize count )
{
T result = { } ;
if ( ! data | | ! size | | * size < = 0 )
return result ;
Dqn_usize pop_count = DQN_MIN ( count , * size ) ;
result = data [ ( * size - 1 ) ] ;
* size - = pop_count ;
return result ;
}
template < typename T > Dqn_ArrayFindResult < T > Dqn_CArray_Find ( T * data , Dqn_usize size , T const & value )
{
Dqn_ArrayFindResult < T > result = { } ;
if ( ! data | | size < = 0 )
return result ;
for ( Dqn_usize index = 0 ; ! result . data & & index < size ; index + + ) {
T * item = data + index ;
if ( * item = = value ) {
result . data = item ;
result . index = index ;
}
}
return result ;
}
2023-07-04 14:04:53 +00:00
# if !defined(DQN_NO_VARRAY)
2024-01-31 12:49:23 +00:00
// NOTE: [$VARR] Dqn_VArray ////////////////////////////////////////////////////////////////////////
template < typename T > Dqn_VArray < T > Dqn_VArray_InitByteSize ( Dqn_usize byte_size , uint8_t arena_flags )
2023-07-04 14:04:53 +00:00
{
2023-08-16 11:59:38 +00:00
Dqn_VArray < T > result = { } ;
2024-01-31 12:49:23 +00:00
result . arena = Dqn_Arena_InitSize ( DQN_ARENA_HEADER_SIZE + byte_size , 0 /*commit*/ , arena_flags | Dqn_ArenaFlag_NoGrow | Dqn_ArenaFlag_NoPoison ) ;
2024-02-01 13:08:31 +00:00
if ( result . arena . curr ) {
result . data = DQN_CAST ( T * ) ( DQN_CAST ( char * ) result . arena . curr + result . arena . curr - > used ) ;
result . max = ( result . arena . curr - > reserve - result . arena . curr - > used ) / sizeof ( T ) ;
}
2023-07-04 14:04:53 +00:00
return result ;
}
2024-01-31 12:49:23 +00:00
template < typename T > Dqn_VArray < T > Dqn_VArray_Init ( Dqn_usize max , uint8_t arena_flags )
2023-07-04 14:04:53 +00:00
{
2024-01-31 12:49:23 +00:00
Dqn_VArray < T > result = Dqn_VArray_InitByteSize < T > ( max * sizeof ( T ) , arena_flags ) ;
2023-08-16 11:59:38 +00:00
DQN_ASSERT ( result . max > = max ) ;
2023-07-04 14:04:53 +00:00
return result ;
}
2024-02-01 13:08:31 +00:00
template < typename T > Dqn_VArray < T > Dqn_VArray_InitSlice ( Dqn_Slice < T > slice , Dqn_usize max , uint8_t arena_flags )
{
Dqn_usize real_max = DQN_MAX ( slice . size , max ) ;
2024-02-11 07:23:13 +00:00
Dqn_VArray < T > result = Dqn_VArray_Init < T > ( real_max , arena_flags ) ;
2024-02-01 13:08:31 +00:00
if ( Dqn_VArray_IsValid ( & result ) )
Dqn_VArray_AddArray ( & result , slice . data , slice . size ) ;
return result ;
}
template < typename T , Dqn_usize N > Dqn_VArray < T > Dqn_VArray_InitCArray ( T const ( & items ) [ N ] , Dqn_usize max , uint8_t arena_flags )
{
Dqn_usize real_max = DQN_MAX ( N , max ) ;
Dqn_VArray < T > result = Dqn_VArray_InitSlice ( Dqn_Slice_Init ( items , N ) , real_max , arena_flags ) ;
return result ;
}
2024-01-31 12:49:23 +00:00
template < typename T > void Dqn_VArray_Deinit ( Dqn_VArray < T > * array )
2023-07-04 14:04:53 +00:00
{
2024-01-31 12:49:23 +00:00
Dqn_Arena_Deinit ( & array - > arena ) ;
* array = { } ;
2023-07-04 14:04:53 +00:00
}
2024-01-31 12:49:23 +00:00
template < typename T > bool Dqn_VArray_IsValid ( Dqn_VArray < T > const * array )
2023-07-04 14:04:53 +00:00
{
2024-01-31 12:49:23 +00:00
bool result = array & & array - > data & & array - > size < = array - > max & & array - > arena . curr ;
return result ;
}
2023-07-04 14:04:53 +00:00
2024-02-01 13:08:31 +00:00
template < typename T > Dqn_Slice < T > Dqn_VArray_Slice ( Dqn_VArray < T > const * array )
{
Dqn_Slice < T > result = { } ;
if ( array )
result = Dqn_Slice_Init < T > ( array - > data , array - > size ) ;
return result ;
}
2024-01-31 12:49:23 +00:00
template < typename T > T * Dqn_VArray_AddArray ( Dqn_VArray < T > * array , T const * items , Dqn_usize count )
{
T * result = Dqn_VArray_MakeArray ( array , count , Dqn_ZeroMem_No ) ;
2023-07-04 14:04:53 +00:00
if ( result )
2024-01-31 12:49:23 +00:00
DQN_MEMCPY ( result , items , count * sizeof ( T ) ) ;
2023-07-04 14:04:53 +00:00
return result ;
}
2024-01-31 12:49:23 +00:00
template < typename T , Dqn_usize N > T * Dqn_VArray_AddCArray ( Dqn_VArray < T > * array , T const ( & items ) [ N ] )
2023-10-24 13:11:48 +00:00
{
2024-01-31 12:49:23 +00:00
T * result = Dqn_VArray_AddArray ( array , items , N ) ;
2023-10-24 13:11:48 +00:00
return result ;
}
2024-01-31 12:49:23 +00:00
template < typename T > T * Dqn_VArray_Add ( Dqn_VArray < T > * array , T const & item )
2023-07-04 14:04:53 +00:00
{
2024-01-31 12:49:23 +00:00
T * result = Dqn_VArray_AddArray ( array , & item , 1 ) ;
return result ;
}
template < typename T > T * Dqn_VArray_MakeArray ( Dqn_VArray < T > * array , Dqn_usize count , Dqn_ZeroMem zero_mem )
{
if ( ! Dqn_VArray_IsValid ( array ) )
return nullptr ;
if ( ! DQN_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 ;
// TODO: Use placement new? Why doesn't this work?
uint8_t prev_flags = array - > arena . flags ;
array - > arena . flags | = ( Dqn_ArenaFlag_NoGrow | Dqn_ArenaFlag_NoPoison ) ;
T * result = Dqn_Arena_NewArray ( & array - > arena , T , count , zero_mem ) ;
array - > arena . flags = prev_flags ;
2023-07-04 14:04:53 +00:00
if ( result )
2024-01-31 12:49:23 +00:00
array - > size + = count ;
2023-07-04 14:04:53 +00:00
return result ;
}
2024-01-31 12:49:23 +00:00
template < typename T > T * Dqn_VArray_Make ( Dqn_VArray < T > * array , Dqn_ZeroMem zero_mem )
2023-10-24 13:11:48 +00:00
{
2024-01-31 12:49:23 +00:00
T * result = Dqn_VArray_MakeArray ( array , 1 , zero_mem ) ;
2023-10-24 13:11:48 +00:00
return result ;
}
2024-01-31 12:49:23 +00:00
template < typename T > T * Dqn_VArray_InsertArray ( Dqn_VArray < T > * array , Dqn_usize index , T const * items , Dqn_usize count )
2023-07-04 14:04:53 +00:00
{
2023-10-24 13:11:48 +00:00
T * result = nullptr ;
2023-08-31 12:10:47 +00:00
if ( ! Dqn_VArray_IsValid ( array ) )
2023-10-24 13:11:48 +00:00
return result ;
2024-03-19 12:11:00 +00:00
if ( Dqn_VArray_Reserve ( array , array - > size + count ) )
2024-01-31 12:49:23 +00:00
result = Dqn_CArray_InsertArray ( array - > data , & array - > size , array - > max , index , items , count ) ;
2023-10-24 13:11:48 +00:00
return result ;
2023-07-04 14:04:53 +00:00
}
2024-01-31 12:49:23 +00:00
template < typename T , Dqn_usize N > T * Dqn_VArray_InsertCArray ( Dqn_VArray < T > * array , Dqn_usize index , T const ( & items ) [ N ] )
{
T * result = Dqn_VArray_InsertArray ( array , index , items , N ) ;
return result ;
}
template < typename T > T * Dqn_VArray_Insert ( Dqn_VArray < T > * array , Dqn_usize index , T const & item )
2023-07-04 14:04:53 +00:00
{
2023-10-24 13:11:48 +00:00
T * result = Dqn_VArray_InsertArray ( array , index , & item , 1 ) ;
return result ;
}
2024-01-31 12:49:23 +00:00
template < typename T > T * Dqn_VArray_PopFront ( Dqn_VArray < T > * array , Dqn_usize count )
2023-10-24 13:11:48 +00:00
{
T * result = Dqn_CArray_PopFront ( array - > data , & array - > size , count ) ;
return result ;
}
2024-01-31 12:49:23 +00:00
template < typename T > T * Dqn_VArray_PopBack ( Dqn_VArray < T > * array , Dqn_usize count )
2023-10-24 13:11:48 +00:00
{
T * result = Dqn_CArray_PopBack ( array - > data , & array - > size , count ) ;
return result ;
}
2024-01-31 12:49:23 +00:00
template < typename T > Dqn_ArrayEraseResult Dqn_VArray_EraseRange ( Dqn_VArray < T > * array , Dqn_usize begin_index , Dqn_isize count , Dqn_ArrayErase erase )
2023-10-24 13:11:48 +00:00
{
Dqn_ArrayEraseResult result = { } ;
if ( ! Dqn_VArray_IsValid ( array ) )
return result ;
result = Dqn_CArray_EraseRange < T > ( array - > data , & array - > size , begin_index , count , erase ) ;
2024-01-31 12:49:23 +00:00
Dqn_Arena_Pop ( & array - > arena , result . items_erased * sizeof ( T ) ) ;
2023-10-24 13:11:48 +00:00
return result ;
}
2024-01-31 12:49:23 +00:00
template < typename T > void Dqn_VArray_Clear ( Dqn_VArray < T > * array , Dqn_ZeroMem zero_mem )
2023-10-24 13:11:48 +00:00
{
if ( array ) {
if ( zero_mem = = Dqn_ZeroMem_Yes )
DQN_MEMSET ( array - > data , 0 , array - > size * sizeof ( T ) ) ;
2024-01-31 12:49:23 +00:00
Dqn_Arena_PopTo ( & array - > arena , 0 ) ;
2023-07-04 14:04:53 +00:00
array - > size = 0 ;
2023-10-24 13:11:48 +00:00
}
2023-07-04 14:04:53 +00:00
}
2024-01-31 12:49:23 +00:00
template < typename T > bool Dqn_VArray_Reserve ( Dqn_VArray < T > * array , Dqn_usize count )
2023-07-04 14:04:53 +00:00
{
if ( ! Dqn_VArray_IsValid ( array ) | | count = = 0 )
2024-01-31 12:49:23 +00:00
return false ;
bool result = Dqn_Arena_CommitTo ( & array - > arena , DQN_ARENA_HEADER_SIZE + ( count * sizeof ( T ) ) ) ;
return result ;
2023-07-04 14:04:53 +00:00
}
# endif // !defined(DQN_NO_VARRAY)
2023-08-31 12:10:47 +00:00
# if !defined(DQN_NO_SARRAY)
2024-04-18 12:59:11 +00:00
// NOTE: [$SARR] Dqn_SArray ////////////////////////////////////////////////////////////////////////
2024-01-31 12:49:23 +00:00
template < typename T > Dqn_SArray < T > Dqn_SArray_Init ( Dqn_Arena * arena , Dqn_usize size , Dqn_ZeroMem zero_mem )
2023-08-31 12:10:47 +00:00
{
Dqn_SArray < T > result = { } ;
2023-10-24 13:11:48 +00:00
if ( ! arena | | ! size )
2023-08-31 12:10:47 +00:00
return result ;
result . data = Dqn_Arena_NewArray ( arena , T , size , zero_mem ) ;
if ( result . data )
result . max = size ;
return result ;
}
2023-10-24 13:11:48 +00:00
2024-02-01 13:08:31 +00:00
template < typename T > Dqn_SArray < T > Dqn_SArray_InitSlice ( Dqn_Arena * arena , Dqn_Slice < T > slice , Dqn_usize size , Dqn_ZeroMem zero_mem )
2023-10-24 13:11:48 +00:00
{
2024-02-01 13:08:31 +00:00
Dqn_usize max = DQN_MAX ( slice . size , size ) ;
Dqn_SArray < T > result = Dqn_SArray_Init < T > ( arena , max , Dqn_ZeroMem_No ) ;
if ( Dqn_SArray_IsValid ( & result ) ) {
Dqn_SArray_AddArray ( & result , slice . data , slice . size ) ;
if ( zero_mem = = Dqn_ZeroMem_Yes )
DQN_MEMSET ( result . data + result . size , 0 , ( result . max - result . size ) * sizeof ( T ) ) ;
2023-10-24 13:11:48 +00:00
}
return result ;
}
2024-02-01 13:08:31 +00:00
template < typename T , size_t N > Dqn_SArray < T > Dqn_SArray_InitCArray ( Dqn_Arena * arena , T const ( & array ) [ N ] , Dqn_usize size , Dqn_ZeroMem zero_mem )
{
2024-02-25 11:37:14 +00:00
Dqn_SArray < T > result = Dqn_SArray_InitSlice ( arena , Dqn_Slice_Init ( DQN_CAST ( T * ) array , N ) , size , zero_mem ) ;
2024-02-01 13:08:31 +00:00
return result ;
}
2024-01-31 12:49:23 +00:00
template < typename T > bool Dqn_SArray_IsValid ( Dqn_SArray < T > const * array )
2023-08-31 12:10:47 +00:00
{
bool result = array & & array - > data & & array - > size < = array - > max ;
return result ;
}
2024-02-01 13:08:31 +00:00
template < typename T > Dqn_Slice < T > Dqn_SArray_Slice ( Dqn_SArray < T > const * array )
2024-01-31 12:49:23 +00:00
{
Dqn_Slice < T > result = { } ;
if ( array )
2024-02-01 13:08:31 +00:00
result = Dqn_Slice_Init < T > ( DQN_CAST ( T * ) array - > data , array - > size ) ;
2024-01-31 12:49:23 +00:00
return result ;
}
template < typename T > T * Dqn_SArray_MakeArray ( Dqn_SArray < T > * array , Dqn_usize count , Dqn_ZeroMem zero_mem )
2023-08-31 12:10:47 +00:00
{
if ( ! Dqn_SArray_IsValid ( array ) )
return nullptr ;
2023-10-24 13:11:48 +00:00
T * result = Dqn_CArray_MakeArray ( array - > data , & array - > size , array - > max , count , zero_mem ) ;
return result ;
}
2024-01-31 12:49:23 +00:00
template < typename T > T * Dqn_SArray_Make ( Dqn_SArray < T > * array , Dqn_ZeroMem zero_mem )
2023-10-24 13:11:48 +00:00
{
T * result = Dqn_SArray_MakeArray ( array , 1 , zero_mem ) ;
2023-08-31 12:10:47 +00:00
return result ;
}
2024-01-31 12:49:23 +00:00
template < typename T > T * Dqn_SArray_AddArray ( Dqn_SArray < T > * array , T const * items , Dqn_usize count )
2023-08-31 12:10:47 +00:00
{
2024-02-01 13:08:31 +00:00
T * result = Dqn_SArray_MakeArray ( array , count , Dqn_ZeroMem_No ) ;
2023-08-31 12:10:47 +00:00
if ( result )
DQN_MEMCPY ( result , items , count * sizeof ( T ) ) ;
2024-02-01 13:08:31 +00:00
return result ;
2023-08-31 12:10:47 +00:00
}
2024-01-31 12:49:23 +00:00
template < typename T , Dqn_usize N > T * Dqn_SArray_AddCArray ( Dqn_SArray < T > * array , T const ( & items ) [ N ] )
{
T * result = Dqn_SArray_AddArray ( array , items , N ) ;
return result ;
}
template < typename T > T * Dqn_SArray_Add ( Dqn_SArray < T > * array , T const & item )
2023-08-31 12:10:47 +00:00
{
T * result = Dqn_SArray_AddArray ( array , & item , 1 ) ;
return result ;
}
2024-04-18 12:59:11 +00:00
template < typename T > T * Dqn_SArray_InsertArray ( Dqn_SArray < T > * array , Dqn_usize index , T const * items , Dqn_usize count )
2023-10-24 13:11:48 +00:00
{
2024-01-31 12:49:23 +00:00
T * result = nullptr ;
2023-10-24 13:11:48 +00:00
if ( ! Dqn_SArray_IsValid ( array ) )
return result ;
2024-01-31 12:49:23 +00:00
result = Dqn_CArray_InsertArray ( array - > data , & array - > size , array - > max , index , items , count ) ;
return result ;
}
template < typename T , Dqn_usize N > T * Dqn_SArray_InsertCArray ( Dqn_SArray < T > * array , Dqn_usize index , T const ( & items ) [ N ] )
{
T * result = Dqn_SArray_InsertArray ( array , index , items , N ) ;
2023-10-24 13:11:48 +00:00
return result ;
}
2024-04-18 12:59:11 +00:00
template < typename T > T * Dqn_SArray_Insert ( Dqn_SArray < T > * array , Dqn_usize index , T const & item )
2023-10-24 13:11:48 +00:00
{
T * result = Dqn_SArray_InsertArray ( array , index , & item , 1 ) ;
return result ;
}
2024-01-31 12:49:23 +00:00
template < typename T > T Dqn_SArray_PopFront ( Dqn_SArray < T > * array , Dqn_usize count )
2023-10-24 13:11:48 +00:00
{
T result = Dqn_CArray_PopFront ( array - > data , & array - > size , count ) ;
return result ;
}
2024-01-31 12:49:23 +00:00
template < typename T > T Dqn_SArray_PopBack ( Dqn_SArray < T > * array , Dqn_usize count )
2023-10-24 13:11:48 +00:00
{
T result = Dqn_CArray_PopBack ( array - > data , & array - > size , count ) ;
return result ;
}
2024-01-31 12:49:23 +00:00
template < typename T > Dqn_ArrayEraseResult Dqn_SArray_EraseRange ( Dqn_SArray < T > * array , Dqn_usize begin_index , Dqn_isize count , Dqn_ArrayErase erase )
2023-08-31 12:10:47 +00:00
{
2024-01-31 12:49:23 +00:00
Dqn_ArrayEraseResult result = { } ;
2023-08-31 12:10:47 +00:00
if ( ! Dqn_SArray_IsValid ( array ) | | array - > size = = 0 | | count = = 0 )
2024-01-31 12:49:23 +00:00
return result ;
result = Dqn_CArray_EraseRange ( array - > data , & array - > size , begin_index , count , erase ) ;
2023-10-24 13:11:48 +00:00
return result ;
2023-08-31 12:10:47 +00:00
}
2024-01-31 12:49:23 +00:00
template < typename T > void Dqn_SArray_Clear ( Dqn_SArray < T > * array )
2023-08-31 12:10:47 +00:00
{
if ( array )
array - > size = 0 ;
}
# endif // !defined(DQN_NO_SARRAY)
# if !defined(DQN_NO_FARRAY)
2024-01-31 12:49:23 +00:00
// NOTE: [$FARR] Dqn_FArray ////////////////////////////////////////////////////////////////////////
template < typename T , Dqn_usize N > Dqn_FArray < T , N > Dqn_FArray_Init ( T const * array , Dqn_usize count )
2023-08-31 12:10:47 +00:00
{
Dqn_FArray < T , N > result = { } ;
2023-10-24 13:11:48 +00:00
bool added = Dqn_FArray_AddArray ( & result , array , count ) ;
2023-08-31 12:10:47 +00:00
DQN_ASSERT ( added ) ;
return result ;
}
2024-01-31 12:49:23 +00:00
2024-02-01 13:08:31 +00:00
template < typename T , Dqn_usize N > Dqn_FArray < T , N > Dqn_FArray_InitSlice ( Dqn_Slice < T > slice )
{
Dqn_FArray < T , N > result = Dqn_FArray_Init ( slice . data , slice . size ) ;
return result ;
}
2024-01-31 12:49:23 +00:00
template < typename T , Dqn_usize N , Dqn_usize K > Dqn_FArray < T , N > Dqn_FArray_InitCArray ( T const ( & items ) [ K ] )
2023-08-31 12:10:47 +00:00
{
2024-02-01 13:08:31 +00:00
Dqn_FArray < T , N > result = Dqn_FArray_Init < T , N > ( items , K ) ;
2023-08-31 12:10:47 +00:00
return result ;
}
2024-01-31 12:49:23 +00:00
template < typename T , Dqn_usize N > bool Dqn_FArray_IsValid ( Dqn_FArray < T , N > const * array )
2023-08-31 12:10:47 +00:00
{
2024-01-31 12:49:23 +00:00
bool result = array & & array - > size < = DQN_ARRAY_UCOUNT ( array - > data ) ;
2023-08-31 12:10:47 +00:00
return result ;
}
2024-01-31 12:49:23 +00:00
template < typename T , Dqn_usize N > Dqn_Slice < T > Dqn_FArray_Slice ( Dqn_FArray < T , N > const * array )
2023-08-31 12:10:47 +00:00
{
2024-01-31 12:49:23 +00:00
Dqn_Slice < T > result = { } ;
if ( array )
result = Dqn_Slice_Init < T > ( DQN_CAST ( T * ) array - > data , array - > size ) ;
2023-10-24 13:11:48 +00:00
return result ;
}
2024-01-31 12:49:23 +00:00
template < typename T , Dqn_usize N > T * Dqn_FArray_AddArray ( Dqn_FArray < T , N > * array , T const * items , Dqn_usize count )
2023-10-24 13:11:48 +00:00
{
T * result = Dqn_FArray_MakeArray ( array , count , Dqn_ZeroMem_No ) ;
2023-08-31 12:10:47 +00:00
if ( result )
DQN_MEMCPY ( result , items , count * sizeof ( T ) ) ;
return result ;
}
2024-01-31 12:49:23 +00:00
template < typename T , Dqn_usize N , Dqn_usize K > T * Dqn_FArray_AddCArray ( Dqn_FArray < T , N > * array , T const ( & items ) [ K ] )
{
T * result = Dqn_FArray_MakeArray ( array , K , Dqn_ZeroMem_No ) ;
if ( result )
DQN_MEMCPY ( result , items , K * sizeof ( T ) ) ;
return result ;
}
template < typename T , Dqn_usize N > T * Dqn_FArray_Add ( Dqn_FArray < T , N > * array , T const & item )
2023-10-24 13:11:48 +00:00
{
T * result = Dqn_FArray_AddArray ( array , & item , 1 ) ;
return result ;
}
2024-01-31 12:49:23 +00:00
template < typename T , Dqn_usize N > T * Dqn_FArray_MakeArray ( Dqn_FArray < T , N > * array , Dqn_usize count , Dqn_ZeroMem zero_mem )
{
if ( ! Dqn_FArray_IsValid ( array ) )
return nullptr ;
T * result = Dqn_CArray_MakeArray ( array - > data , & array - > size , N , count , zero_mem ) ;
return result ;
}
template < typename T , Dqn_usize N > T * Dqn_FArray_Make ( Dqn_FArray < T , N > * array , Dqn_ZeroMem zero_mem )
{
T * result = Dqn_FArray_MakeArray ( array , 1 , zero_mem ) ;
return result ;
}
template < typename T , Dqn_usize N > T * Dqn_FArray_InsertArray ( Dqn_FArray < T , N > * array , Dqn_usize index , T const * items , Dqn_usize count )
2023-10-24 13:11:48 +00:00
{
T * result = nullptr ;
if ( ! Dqn_FArray_IsValid ( array ) )
return result ;
result = Dqn_CArray_InsertArray ( array - > data , & array - > size , N , index , items , count ) ;
return result ;
}
2024-01-31 12:49:23 +00:00
template < typename T , Dqn_usize N , Dqn_usize K > T * Dqn_FArray_InsertCArray ( Dqn_FArray < T , N > * array , Dqn_usize index , T const ( & items ) [ K ] )
{
T * result = Dqn_FArray_InsertArray ( array , index , items , K ) ;
return result ;
}
template < typename T , Dqn_usize N > T * Dqn_FArray_Insert ( Dqn_FArray < T , N > * array , Dqn_usize index , T const & item )
2023-10-24 13:11:48 +00:00
{
T * result = Dqn_FArray_InsertArray ( array , index , & item , 1 ) ;
return result ;
}
2024-01-31 12:49:23 +00:00
template < typename T , Dqn_usize N > T Dqn_FArray_PopFront ( Dqn_FArray < T , N > * array , Dqn_usize count )
2023-10-24 13:11:48 +00:00
{
T result = Dqn_CArray_PopFront ( array - > data , & array - > size , count ) ;
return result ;
}
2024-01-31 12:49:23 +00:00
template < typename T , Dqn_usize N > T Dqn_FArray_PopBack ( Dqn_FArray < T , N > * array , Dqn_usize count )
2023-10-24 13:11:48 +00:00
{
T result = Dqn_CArray_PopBack ( array - > data , & array - > size , count ) ;
return result ;
}
2024-01-31 12:49:23 +00:00
template < typename T , Dqn_usize N > Dqn_ArrayFindResult < T > Dqn_FArray_Find ( Dqn_FArray < T , N > * array , T const & find )
2023-08-31 12:10:47 +00:00
{
2023-10-24 13:11:48 +00:00
Dqn_ArrayFindResult < T > result = Dqn_CArray_Find < T > ( array - > data , array - > size , find ) ;
return result ;
}
2024-01-31 12:49:23 +00:00
template < typename T , Dqn_usize N > Dqn_ArrayEraseResult Dqn_FArray_EraseRange ( Dqn_FArray < T , N > * array , Dqn_usize begin_index , Dqn_isize count , Dqn_ArrayErase erase )
2023-10-24 13:11:48 +00:00
{
Dqn_ArrayEraseResult result = { } ;
2023-08-31 12:10:47 +00:00
if ( ! Dqn_FArray_IsValid ( array ) | | array - > size = = 0 | | count = = 0 )
2023-10-24 13:11:48 +00:00
return result ;
result = Dqn_CArray_EraseRange ( array - > data , & array - > size , begin_index , count , erase ) ;
return result ;
2023-08-31 12:10:47 +00:00
}
2024-01-31 12:49:23 +00:00
template < typename T , Dqn_usize N > void Dqn_FArray_Clear ( Dqn_FArray < T , N > * array )
2023-08-31 12:10:47 +00:00
{
if ( array )
array - > size = 0 ;
}
# endif // !defined(DQN_NO_FARRAY)
# if !defined(DQN_NO_SLICE)
template < typename T > Dqn_Slice < T > Dqn_Slice_Init ( T * const data , Dqn_usize size )
{
Dqn_Slice < T > result = { } ;
if ( data ) {
result . data = data ;
result . size = size ;
}
return result ;
}
2023-10-24 13:11:48 +00:00
template < typename T , Dqn_usize N >
2024-01-31 12:49:23 +00:00
Dqn_Slice < T > Dqn_Slice_InitCArray ( Dqn_Arena * arena , T const ( & array ) [ N ] )
2023-10-24 13:11:48 +00:00
{
Dqn_Slice < T > result = Dqn_Slice_Alloc < T > ( arena , N , Dqn_ZeroMem_No ) ;
if ( result . data )
DQN_MEMCPY ( result . data , array , sizeof ( T ) * N ) ;
return result ;
}
2024-04-18 12:59:11 +00:00
template < typename T > Dqn_Slice < T > Dqn_Slice_CopyPtr ( Dqn_Arena * arena , T * const data , Dqn_usize size )
{
T * copy = Dqn_Arena_NewArrayCopy ( arena , T , data , size ) ;
Dqn_Slice < T > result = Dqn_Slice_Init ( copy , copy ? size : 0 ) ;
return result ;
}
template < typename T > Dqn_Slice < T > Dqn_Slice_Copy ( Dqn_Arena * arena , Dqn_Slice < T > slice )
{
Dqn_Slice < T > result = Dqn_Slice_CopyPtr ( arena , slice . data , slice . size ) ;
return result ;
}
2023-08-31 12:10:47 +00:00
template < typename T > Dqn_Slice < T > Dqn_Slice_Alloc ( Dqn_Arena * arena , Dqn_usize size , Dqn_ZeroMem zero_mem )
{
Dqn_Slice < T > result = { } ;
if ( ! arena | | size = = 0 )
return result ;
result . data = Dqn_Arena_NewArray ( arena , T , size , zero_mem ) ;
if ( result . data )
result . size = size ;
return result ;
}
2023-10-24 13:11:48 +00:00
2023-08-31 12:10:47 +00:00
# endif // !defined(DQN_NO_SLICE)
2023-07-04 14:04:53 +00:00
# if !defined(DQN_NO_DSMAP)
2024-01-31 12:49:23 +00:00
// NOTE: [$DMAP] Dqn_DSMap /////////////////////////////////////////////////////////////////////////
2023-07-04 14:04:53 +00:00
uint32_t const DQN_DS_MAP_DEFAULT_HASH_SEED = 0x8a1ced49 ;
2024-01-31 12:49:23 +00:00
uint32_t const DQN_DS_MAP_SENTINEL_SLOT = 0 ;
2023-07-04 14:04:53 +00:00
2024-08-01 03:34:36 +00:00
template < typename T > Dqn_DSMap < T > Dqn_DSMap_Init ( Dqn_Arena * arena , uint32_t size , Dqn_DSMapFlags flags )
2023-07-04 14:04:53 +00:00
{
Dqn_DSMap < T > result = { } ;
2024-01-31 12:49:23 +00:00
if ( ! DQN_CHECKF ( Dqn_IsPowerOfTwo ( size ) , " Power-of-two size required, given size was '%u' " , size ) )
return result ;
2024-08-01 03:34:36 +00:00
if ( ! DQN_CHECKF ( size > 0 , " Non-zero size must be given " ) )
return result ;
if ( ! DQN_CHECK ( arena ) )
2024-01-31 12:49:23 +00:00
return result ;
result . arena = arena ;
2024-08-01 03:34:36 +00:00
result . hash_to_slot = Dqn_Arena_NewArray ( result . arena , uint32_t , size , Dqn_ZeroMem_Yes ) ;
result . slots = Dqn_Arena_NewArray ( result . arena , Dqn_DSMapSlot < T > , size , Dqn_ZeroMem_Yes ) ;
2024-01-31 12:49:23 +00:00
result . occupied = 1 ; // For sentinel
result . size = size ;
result . initial_size = size ;
2024-08-01 03:34:36 +00:00
result . flags = flags ;
2024-01-31 12:49:23 +00:00
DQN_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? " ) ;
2023-07-04 14:04:53 +00:00
return result ;
}
template < typename T >
2024-01-31 12:49:23 +00:00
void Dqn_DSMap_Deinit ( Dqn_DSMap < T > * map , Dqn_ZeroMem zero_mem )
2023-07-04 14:04:53 +00:00
{
if ( ! map )
return ;
2024-01-31 12:49:23 +00:00
// TODO(doyle): Use zero_mem
( void ) zero_mem ;
Dqn_Arena_Deinit ( map - > arena ) ;
2023-07-04 14:04:53 +00:00
* map = { } ;
}
template < typename T >
bool Dqn_DSMap_IsValid ( Dqn_DSMap < T > const * map )
{
bool result = map & &
2024-01-31 12:49:23 +00:00
map - > arena & &
2023-07-04 14:04:53 +00:00
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 ; // DQN_DS_MAP_SENTINEL_SLOT takes up one slot
return result ;
}
template < typename T >
uint32_t Dqn_DSMap_Hash ( Dqn_DSMap < T > const * map , Dqn_DSMapKey key )
{
uint32_t result = 0 ;
if ( ! map )
return result ;
if ( key . type = = Dqn_DSMapKeyType_U64NoHash ) {
2024-08-01 03:34:36 +00:00
result = DQN_CAST ( uint32_t ) key . u64 ;
return result ;
}
if ( key . type = = Dqn_DSMapKeyType_BufferAsU64NoHash ) {
result = key . hash ;
2023-07-04 14:04:53 +00:00
return result ;
}
uint32_t seed = map - > hash_seed ? map - > hash_seed : DQN_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 ;
uint32_t len = 0 ;
uint32_t h = seed ;
switch ( key . type ) {
2024-08-01 03:34:36 +00:00
case Dqn_DSMapKeyType_BufferAsU64NoHash : /*FALLTHRU*/
2023-07-04 14:04:53 +00:00
case Dqn_DSMapKeyType_U64NoHash : DQN_INVALID_CODE_PATH ; /*FALLTHRU*/
case Dqn_DSMapKeyType_Invalid : break ;
case Dqn_DSMapKeyType_Buffer :
2024-08-01 03:34:36 +00:00
key_ptr = DQN_CAST ( char const * ) key . buffer_data ;
len = key . buffer_size ;
2023-07-04 14:04:53 +00:00
break ;
case Dqn_DSMapKeyType_U64 :
2024-08-01 03:34:36 +00:00
key_ptr = DQN_CAST ( char const * ) & key . u64 ;
len = sizeof ( key . u64 ) ;
2023-07-04 14:04:53 +00:00
break ;
}
// Murmur3 32-bit without UB unaligned accesses
// uint32_t mur3_32_no_UB(const void *key, int len, uint32_t h)
// main body, work on 32-bit blocks at a time
for ( uint32_t i = 0 ; i < len / 4 ; i + + ) {
uint32_t 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
uint32_t 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 >
uint32_t Dqn_DSMap_HashToSlotIndex ( Dqn_DSMap < T > const * map , Dqn_DSMapKey key )
{
2024-08-01 03:34:36 +00:00
DQN_ASSERT ( key . type ! = Dqn_DSMapKeyType_Invalid ) ;
2023-07-04 14:04:53 +00:00
uint32_t result = DQN_DS_MAP_SENTINEL_SLOT ;
if ( ! Dqn_DSMap_IsValid ( map ) )
return result ;
result = key . hash & ( map - > size - 1 ) ;
for ( ; ; ) {
if ( map - > hash_to_slot [ result ] = = DQN_DS_MAP_SENTINEL_SLOT )
return result ;
Dqn_DSMapSlot < T > * slot = map - > slots + map - > hash_to_slot [ result ] ;
if ( slot - > key . type = = Dqn_DSMapKeyType_Invalid | | ( slot - > key . hash = = key . hash & & slot - > key = = key ) )
return result ;
result = ( result + 1 ) & ( map - > size - 1 ) ;
}
}
template < typename T >
2023-10-24 13:11:48 +00:00
Dqn_DSMapResult < T > Dqn_DSMap_Find ( Dqn_DSMap < T > const * map , Dqn_DSMapKey key )
2023-07-04 14:04:53 +00:00
{
2023-10-24 13:11:48 +00:00
Dqn_DSMapResult < T > result = { } ;
2023-07-04 14:04:53 +00:00
if ( Dqn_DSMap_IsValid ( map ) ) {
uint32_t index = Dqn_DSMap_HashToSlotIndex ( map , key ) ;
2023-10-24 13:11:48 +00:00
if ( map - > hash_to_slot [ index ] ! = DQN_DS_MAP_SENTINEL_SLOT ) {
result . slot = map - > slots + map - > hash_to_slot [ index ] ;
result . value = & result . slot - > value ;
result . found = true ;
}
2023-07-04 14:04:53 +00:00
}
2023-10-24 13:11:48 +00:00
return result ;
2023-07-04 14:04:53 +00:00
}
template < typename T >
2023-10-24 13:11:48 +00:00
Dqn_DSMapResult < T > Dqn_DSMap_Make ( Dqn_DSMap < T > * map , Dqn_DSMapKey key )
2023-07-04 14:04:53 +00:00
{
2023-10-24 13:11:48 +00:00
Dqn_DSMapResult < T > result = { } ;
if ( ! Dqn_DSMap_IsValid ( map ) )
return result ;
2023-07-04 14:04:53 +00:00
2023-10-24 13:11:48 +00:00
uint32_t index = Dqn_DSMap_HashToSlotIndex ( map , key ) ;
if ( map - > hash_to_slot [ index ] = = DQN_DS_MAP_SENTINEL_SLOT ) {
// NOTE: Create the 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 ( ! Dqn_DSMap_Resize ( map , map - > size * 2 ) )
return result ;
result = Dqn_DSMap_Make ( map , key ) ;
2023-07-04 14:04:53 +00:00
} else {
2023-10-24 13:11:48 +00:00
result . slot = map - > slots + map - > hash_to_slot [ index ] ;
result . slot - > key = key ; // NOTE: Assign key to new slot
2024-08-01 03:34:36 +00:00
if ( ( result . slot - > key . type = = Dqn_DSMapKeyType_Buffer | |
result - > slot . key . type = = Dqn_DSMapKeyType_BufferAsU64NoHash ) & &
! key . no_copy_buffer ) {
result . slot - > key . buffer_data = Dqn_Arena_Copy ( map - > arena , key . buffer_data , key . buffer_size , 1 ) ;
}
2023-07-04 14:04:53 +00:00
}
2023-10-24 13:11:48 +00:00
} else {
result . slot = map - > slots + map - > hash_to_slot [ index ] ;
result . found = true ;
2023-07-04 14:04:53 +00:00
}
2023-10-24 13:11:48 +00:00
result . value = & result . slot - > value ;
2024-08-01 03:34:36 +00:00
DQN_ASSERT ( result . slot - > key . type ! = Dqn_DSMapKeyType_Invalid ) ;
2023-07-04 14:04:53 +00:00
return result ;
}
template < typename T >
2023-10-24 13:11:48 +00:00
Dqn_DSMapResult < T > Dqn_DSMap_Set ( Dqn_DSMap < T > * map , Dqn_DSMapKey key , T const & value )
2023-07-04 14:04:53 +00:00
{
2023-10-24 13:11:48 +00:00
Dqn_DSMapResult < T > result = { } ;
2023-07-04 14:04:53 +00:00
if ( ! Dqn_DSMap_IsValid ( map ) )
return result ;
2023-10-24 13:11:48 +00:00
result = Dqn_DSMap_Make ( map , key ) ;
result . slot - > value = value ;
return result ;
}
template < typename T >
Dqn_DSMapResult < T > Dqn_DSMap_FindKeyU64 ( Dqn_DSMap < T > const * map , uint64_t key )
{
Dqn_DSMapKey map_key = Dqn_DSMap_KeyU64 ( map , key ) ;
Dqn_DSMapResult < T > result = Dqn_DSMap_Find ( map , map_key ) ;
return result ;
}
template < typename T >
Dqn_DSMapResult < T > Dqn_DSMap_MakeKeyU64 ( Dqn_DSMap < T > * map , uint64_t key )
{
Dqn_DSMapKey map_key = Dqn_DSMap_KeyU64 ( map , key ) ;
Dqn_DSMapResult < T > result = Dqn_DSMap_Make ( map , map_key ) ;
return result ;
}
template < typename T >
Dqn_DSMapResult < T > Dqn_DSMap_SetKeyU64 ( Dqn_DSMap < T > * map , uint64_t key , T const & value )
{
Dqn_DSMapKey map_key = Dqn_DSMap_KeyU64 ( map , key ) ;
Dqn_DSMapResult < T > result = Dqn_DSMap_Set ( map , map_key , value ) ;
return result ;
}
template < typename T >
Dqn_DSMapResult < T > Dqn_DSMap_FindKeyStr8 ( Dqn_DSMap < T > const * map , Dqn_Str8 key )
{
Dqn_DSMapKey map_key = Dqn_DSMap_KeyStr8 ( map , key ) ;
Dqn_DSMapResult < T > result = Dqn_DSMap_Find ( map , map_key ) ;
return result ;
}
template < typename T >
Dqn_DSMapResult < T > Dqn_DSMap_MakeKeyStr8 ( Dqn_DSMap < T > * map , Dqn_Str8 key )
{
Dqn_DSMapKey map_key = Dqn_DSMap_KeyStr8 ( map , key ) ;
Dqn_DSMapResult < T > result = Dqn_DSMap_Make ( map , map_key ) ;
2023-07-04 14:04:53 +00:00
return result ;
}
template < typename T >
2023-10-24 13:11:48 +00:00
Dqn_DSMapResult < T > Dqn_DSMap_SetKeyStr8 ( Dqn_DSMap < T > * map , Dqn_Str8 key , T const & value )
2023-07-04 14:04:53 +00:00
{
2023-10-24 13:11:48 +00:00
Dqn_DSMapKey map_key = Dqn_DSMap_KeyStr8 ( map , key ) ;
Dqn_DSMapResult < T > result = Dqn_DSMap_Set ( map , map_key ) ;
return result ;
2023-07-04 14:04:53 +00:00
}
template < typename T >
bool Dqn_DSMap_Resize ( Dqn_DSMap < T > * map , uint32_t size )
{
if ( ! Dqn_DSMap_IsValid ( map ) | | size < map - > occupied | | size < map - > initial_size )
return false ;
2024-01-31 12:49:23 +00:00
Dqn_Arena * prev_arena = map - > arena ;
Dqn_Arena new_arena = { } ;
new_arena . flags = prev_arena - > flags ;
2024-08-01 03:34:36 +00:00
Dqn_DSMap < T > new_map = Dqn_DSMap_Init < T > ( & new_arena , size , map - > flags ) ;
2023-07-04 14:04:53 +00:00
if ( ! Dqn_DSMap_IsValid ( & new_map ) )
return false ;
new_map . initial_size = map - > initial_size ;
for ( uint32_t old_index = 1 /*Sentinel*/ ; old_index < map - > occupied ; old_index + + ) {
Dqn_DSMapSlot < T > * old_slot = map - > slots + old_index ;
2024-08-01 03:34:36 +00:00
Dqn_DSMapKey old_key = old_slot - > key ;
if ( old_key . type = = Dqn_DSMapKeyType_Invalid )
continue ;
Dqn_DSMap_Set ( & new_map , old_key , old_slot - > value ) ;
2023-07-04 14:04:53 +00:00
}
2024-08-01 03:34:36 +00:00
if ( ( map - > flags & Dqn_DSMapFlags_DontFreeArenaOnResize ) = = 0 )
Dqn_DSMap_Deinit ( map , Dqn_ZeroMem_No ) ;
2024-01-31 12:49:23 +00:00
* 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
2023-07-04 14:04:53 +00:00
return true ;
}
template < typename T >
bool Dqn_DSMap_Erase ( Dqn_DSMap < T > * map , Dqn_DSMapKey key )
{
if ( ! Dqn_DSMap_IsValid ( map ) )
return false ;
uint32_t index = Dqn_DSMap_HashToSlotIndex ( map , key ) ;
uint32_t slot_index = map - > hash_to_slot [ index ] ;
if ( slot_index = = DQN_DS_MAP_SENTINEL_SLOT )
return false ;
// NOTE: Mark the slot as unoccupied
map - > hash_to_slot [ index ] = DQN_DS_MAP_SENTINEL_SLOT ;
map - > slots [ slot_index ] = { } ; // 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 ( uint32_t probe_index = index ; ; ) {
probe_index = ( probe_index + 1 ) & ( map - > size - 1 ) ;
if ( map - > hash_to_slot [ probe_index ] = = DQN_DS_MAP_SENTINEL_SLOT )
break ;
Dqn_DSMapSlot < T > * probe = map - > slots + map - > hash_to_slot [ probe_index ] ;
uint32_t 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 ] = DQN_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*/ ) {
2024-08-01 03:34:36 +00:00
uint32_t last_index = map - > occupied - 1 ;
if ( last_index ! = slot_index ) {
// NOTE: Copy in last slot to the erase slot
Dqn_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
uint32_t hash_to_slot_index = Dqn_DSMap_HashToSlotIndex ( map , last_slot - > key ) ;
map - > hash_to_slot [ hash_to_slot_index ] = slot_index ;
* last_slot = { } ; // TODO: Optional?
}
2023-07-04 14:04:53 +00:00
}
}
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 )
Dqn_DSMap_Resize ( map , map - > size / 2 ) ;
return true ;
}
template < typename T >
2024-08-01 03:34:36 +00:00
Dqn_DSMapKey Dqn_DSMap_KeyBuffer ( Dqn_DSMap < T > const * map , void const * data , Dqn_usize size )
2023-07-04 14:04:53 +00:00
{
2024-08-01 03:34:36 +00:00
DQN_ASSERT ( size > 0 & & size < = UINT32_MAX ) ;
Dqn_DSMapKey result = { } ;
result . type = Dqn_DSMapKeyType_Buffer ;
result . buffer_data = data ;
result . buffer_size = DQN_CAST ( uint32_t ) size ;
result . hash = Dqn_DSMap_Hash ( map , result ) ;
2023-07-04 14:04:53 +00:00
return result ;
}
template < typename T >
2024-08-01 03:34:36 +00:00
Dqn_DSMapKey Dqn_DSMap_KeyBufferAsU64NoHash ( Dqn_DSMap < T > const * map , void const * data , uint32_t size )
2023-07-04 14:04:53 +00:00
{
Dqn_DSMapKey result = { } ;
2024-08-01 03:34:36 +00:00
result . type = Dqn_DSMapKeyType_BufferAsU64NoHash ;
result . buffer_data = data ;
result . buffer_size = DQN_CAST ( uint32_t ) size ;
DQN_ASSERT ( size > = sizeof ( result . hash ) ) ;
DQN_MEMCPY ( & result . hash , data , sizeof ( result . hash ) ) ;
2023-07-04 14:04:53 +00:00
return result ;
}
template < typename T >
2024-08-01 03:34:36 +00:00
Dqn_DSMapKey Dqn_DSMap_KeyU64 ( Dqn_DSMap < T > const * map , uint64_t u64 )
2023-07-04 14:04:53 +00:00
{
2024-08-01 03:34:36 +00:00
Dqn_DSMapKey result = { } ;
result . type = Dqn_DSMapKeyType_U64 ;
result . u64 = u64 ;
result . hash = Dqn_DSMap_Hash ( map , result ) ;
2023-07-04 14:04:53 +00:00
return result ;
}
template < typename T >
2024-08-01 03:34:36 +00:00
Dqn_DSMapKey Dqn_DSMap_KeyStr8 ( Dqn_DSMap < T > const * map , Dqn_Str8 string )
2023-07-04 14:04:53 +00:00
{
2024-08-01 03:34:36 +00:00
Dqn_DSMapKey result = Dqn_DSMap_KeyBuffer ( map , string . data , string . size ) ;
2023-07-04 14:04:53 +00:00
return result ;
}
# endif // !defined(DQN_NO_DSMAP)
2023-07-05 12:39:43 +00:00
# if !defined(DQN_NO_LIST)
2024-01-31 12:49:23 +00:00
// NOTE: [$LIST] Dqn_List //////////////////////////////////////////////////////////////////////////
2024-08-01 03:34:36 +00:00
template < typename T > Dqn_List < T > Dqn_List_Init ( Dqn_usize chunk_size )
2023-07-04 14:04:53 +00:00
{
Dqn_List < T > result = { } ;
result . chunk_size = chunk_size ;
return result ;
}
2024-01-31 12:49:23 +00:00
template < typename T , size_t N > Dqn_List < T > Dqn_List_InitCArray ( Dqn_Arena * arena , Dqn_usize chunk_size , T const ( & array ) [ N ] )
2023-10-24 13:11:48 +00:00
{
Dqn_List < T > result = Dqn_List_Init < T > ( arena , chunk_size ) ;
DQN_FOR_UINDEX ( index , N )
Dqn_List_Add ( & result , array [ index ] ) ;
return result ;
}
template < typename T > Dqn_List < T > Dqn_List_InitSliceCopy ( Dqn_Arena * arena , Dqn_usize chunk_size , Dqn_Slice < T > slice )
{
Dqn_List < T > result = Dqn_List_Init < T > ( arena , chunk_size ) ;
DQN_FOR_UINDEX ( index , slice . size )
Dqn_List_Add ( & result , slice . data [ index ] ) ;
return result ;
}
2024-08-01 03:34:36 +00:00
template < typename T > DQN_API bool Dqn_List_AttachTail_ ( Dqn_List < T > * list , Dqn_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 > DQN_API Dqn_ListChunk < T > * Dqn_List_AllocArena_ ( Dqn_List < T > * list , Dqn_Arena * arena , Dqn_usize count )
{
auto * result = Dqn_Arena_New ( arena , Dqn_ListChunk < T > , Dqn_ZeroMem_Yes ) ;
Dqn_ArenaTempMem tmem = Dqn_Arena_TempMemBegin ( arena ) ;
if ( ! result )
return nullptr ;
Dqn_usize items = DQN_MAX ( list - > chunk_size , count ) ;
result - > data = Dqn_Arena_NewArray ( arena , T , items , Dqn_ZeroMem_Yes ) ;
result - > size = items ;
if ( ! result - > data ) {
Dqn_Arena_TempMemEnd ( tmem ) ;
result = nullptr ;
}
Dqn_List_AttachTail_ ( list , result ) ;
return result ;
}
template < typename T > DQN_API Dqn_ListChunk < T > * Dqn_List_AllocPool_ ( Dqn_List < T > * list , Dqn_ChunkPool * pool , Dqn_usize count )
{
auto * result = Dqn_ChunkPool_New ( pool , Dqn_ListChunk < T > ) ;
if ( ! result )
return nullptr ;
Dqn_usize items = DQN_MAX ( list - > chunk_size , count ) ;
result - > data = Dqn_ChunkPool_NewArray ( pool , T , items ) ;
result - > size = items ;
if ( ! result - > data ) {
Dqn_ChunkPool_Dealloc ( result ) ;
result = nullptr ;
}
Dqn_List_AttachTail_ ( list , result ) ;
return result ;
}
template < typename T > DQN_API T * Dqn_List_MakeArena ( Dqn_List < T > * list , Dqn_Arena * arena , Dqn_usize count )
2023-07-04 14:04:53 +00:00
{
if ( list - > chunk_size = = 0 )
list - > chunk_size = 128 ;
2024-08-01 03:34:36 +00:00
if ( ! list - > tail | | ( list - > tail - > count + count ) > list - > tail - > size ) {
if ( ! Dqn_List_AllocArena_ ( list , arena , count ) )
2023-07-04 14:04:53 +00:00
return nullptr ;
2024-08-01 03:34:36 +00:00
}
2023-07-04 14:04:53 +00:00
2024-08-01 03:34:36 +00:00
T * result = list - > tail - > data + list - > tail - > count ;
list - > tail - > count + = count ;
list - > count + = count ;
return result ;
}
2023-07-04 14:04:53 +00:00
2024-08-01 03:34:36 +00:00
template < typename T > DQN_API T * Dqn_List_MakePool ( Dqn_List < T > * list , Dqn_ChunkPool * pool , Dqn_usize count )
{
if ( list - > chunk_size = = 0 )
list - > chunk_size = 128 ;
2023-07-04 14:04:53 +00:00
2024-08-01 03:34:36 +00:00
if ( ! list - > tail | | ( list - > tail - > count + count ) > list - > tail - > size ) {
if ( ! Dqn_List_AllocPool_ ( list , pool , count ) )
return nullptr ;
2023-07-04 14:04:53 +00:00
}
T * result = list - > tail - > data + list - > tail - > count ;
list - > tail - > count + = count ;
list - > count + = count ;
return result ;
}
2024-08-01 03:34:36 +00:00
template < typename T > DQN_API T * Dqn_List_AddArena ( Dqn_List < T > * list , Dqn_Arena * arena , T const & value )
2023-07-04 14:04:53 +00:00
{
2024-08-01 03:34:36 +00:00
T * result = Dqn_List_MakeArena ( list , arena , 1 ) ;
* result = value ;
return result ;
}
template < typename T > DQN_API T * Dqn_List_AddPool ( Dqn_List < T > * list , Dqn_ChunkPool * pool , T const & value )
{
T * result = Dqn_List_MakePool ( list , pool , 1 ) ;
2023-08-16 11:59:38 +00:00
* result = value ;
2023-07-04 14:04:53 +00:00
return result ;
}
2024-01-31 12:49:23 +00:00
template < typename T , size_t N > DQN_API bool Dqn_List_AddCArray ( Dqn_List < T > * list , T const ( & array ) [ N ] )
{
if ( ! list | | list - > chunk_size < = 0 )
return false ;
for ( T const & item : array ) {
if ( ! Dqn_List_Add ( list , item ) )
return false ;
}
return true ;
}
2024-08-01 03:34:36 +00:00
template < typename T > DQN_API void Dqn_List_AddListArena ( Dqn_List < T > * list , Dqn_Arena * arena , Dqn_List < T > other )
2023-10-24 13:11:48 +00:00
{
if ( ! list | | list - > chunk_size < = 0 )
return ;
2024-08-01 03:34:36 +00:00
// TODO(doyle): Copy chunk by chunk
for ( Dqn_ListIterator < T > it = { } ; Dqn_List_Iterate ( & other , & it , 0 /*start_index*/ ) ; )
Dqn_List_AddArena ( list , arena , * it . data ) ;
}
2023-10-24 13:11:48 +00:00
2024-08-01 03:34:36 +00:00
template < typename T > DQN_API void Dqn_List_AddListPool ( Dqn_List < T > * list , Dqn_ChunkPool * pool , Dqn_List < T > other )
{
if ( ! list | | list - > chunk_size < = 0 )
return ;
2023-10-24 13:11:48 +00:00
// TODO(doyle): Copy chunk by chunk
2024-08-01 03:34:36 +00:00
for ( Dqn_ListIterator < T > it = { } ; Dqn_List_Iterate ( & other , & it , 0 /*start_index*/ ) ; )
Dqn_List_AddPool ( list , pool , * it . data ) ;
2023-10-24 13:11:48 +00:00
}
2023-07-04 14:04:53 +00:00
template < typename T > DQN_API bool Dqn_List_Iterate ( Dqn_List < T > * list , Dqn_ListIterator < T > * it , Dqn_usize start_index )
{
bool result = false ;
if ( ! list | | ! it | | list - > chunk_size < = 0 )
return result ;
2023-10-24 13:11:48 +00:00
if ( it - > init ) {
it - > index + + ;
} else {
2023-07-04 14:04:53 +00:00
* it = { } ;
if ( start_index = = 0 ) {
it - > chunk = list - > head ;
} else {
Dqn_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 )
DQN_ASSERT ( result = = false ) ;
return result ;
}
template < typename T > DQN_API T * Dqn_List_At ( Dqn_List < T > * list , Dqn_usize index , Dqn_ListChunk < T > * * at_chunk )
{
if ( ! list | | ! list - > chunk_size | | index > = list - > count )
return nullptr ;
2024-04-18 12:59:11 +00:00
Dqn_usize total_chunks = ( list - > count / list - > chunk_size ) + ( ( list - > chunk_size % list - > count ) ? 1 : 0 ) ;
2023-07-04 14:04:53 +00:00
Dqn_usize desired_chunk = index / list - > chunk_size ;
Dqn_usize forward_scan_dist = desired_chunk ;
Dqn_usize backward_scan_dist = total_chunks - desired_chunk ;
// NOTE: Linearly scan forwards/backwards to the chunk we need. We don't
// have random access to chunks
Dqn_usize current_chunk = 0 ;
Dqn_ListChunk < T > * * chunk = nullptr ;
if ( forward_scan_dist < = backward_scan_dist ) {
2024-04-18 12:59:11 +00:00
for ( chunk = & list - > head ; * chunk & & current_chunk ! = desired_chunk ; chunk = & ( ( * chunk ) - > next ) , current_chunk + + ) {
2023-07-04 14:04:53 +00:00
}
} else {
current_chunk = total_chunks ;
2024-04-18 12:59:11 +00:00
for ( chunk = & list - > tail ; * chunk & & current_chunk ! = desired_chunk ; chunk = & ( ( * chunk ) - > prev ) , current_chunk - - ) {
2023-07-04 14:04:53 +00:00
}
}
T * result = nullptr ;
if ( * chunk ) {
Dqn_usize relative_index = index % list - > chunk_size ;
result = ( * chunk ) - > data + relative_index ;
DQN_ASSERT ( relative_index < ( * chunk ) - > count ) ;
}
if ( result & & at_chunk )
* at_chunk = * chunk ;
return result ;
}
2023-10-24 13:11:48 +00:00
template < typename T > Dqn_Slice < T > Dqn_List_ToSliceCopy ( Dqn_List < T > const * list , Dqn_Arena * arena )
{
// TODO(doyle): Chunk memcopies is much faster
Dqn_Slice < T > result = Dqn_Slice_Alloc < T > ( arena , list - > count , Dqn_ZeroMem_No ) ;
if ( result . size ) {
Dqn_usize slice_index = 0 ;
2024-08-01 03:34:36 +00:00
DQN_MSVC_WARNING_PUSH
DQN_MSVC_WARNING_DISABLE ( 6011 ) // Dereferencing NULL pointer 'x'
2023-10-24 13:11:48 +00:00
for ( Dqn_ListIterator < T > it = { } ; Dqn_List_Iterate < T > ( DQN_CAST ( Dqn_List < T > * ) list , & it , 0 ) ; )
result . data [ slice_index + + ] = * it . data ;
2024-08-01 03:34:36 +00:00
DQN_MSVC_WARNING_POP
2023-10-24 13:11:48 +00:00
DQN_ASSERT ( slice_index = = result . size ) ;
}
return result ;
}
2023-07-05 12:39:43 +00:00
# endif // !defined(DQN_NO_LIST)