gencpp/project/dependencies/containers.hpp

602 lines
16 KiB
C++
Raw Normal View History

#ifdef GEN_INTELLISENSE_DIRECTIVES
# pragma once
# include "printing.hpp"
#endif
#pragma region Containers
template<class TType> struct RemoveConst { typedef TType Type; };
template<class TType> struct RemoveConst<const TType> { typedef TType Type; };
template<class TType> struct RemoveConst<const TType[]> { typedef TType Type[]; };
template<class TType, usize Size> struct RemoveConst<const TType[Size]> { typedef TType Type[Size]; };
template<class TType>
using TRemoveConst = typename RemoveConst<TType>::Type;
2024-11-30 10:14:47 -08:00
#pragma region Array
struct ArrayHeader;
template<class Type> struct Array;
template<class Type> Array<Type> array_init(AllocatorInfo allocator);
template<class Type> Array<Type> array_init_reserve(AllocatorInfo allocator, ssize capacity);
template<class Type> usize array_grow_formula(ssize value);
template<class Type> bool append(Array<Type>& array, Array<Type> other);
template<class Type> bool append(Array<Type>& array, Type value);
template<class Type> bool append(Array<Type>& array, Type* items, usize item_num);
template<class Type> bool append_at(Array<Type>& array, Type item, usize idx);
template<class Type> bool append_at(Array<Type>& array, Type* items, usize item_num, usize idx);
template<class Type> Type& back(Array<Type>& array);
template<class Type> void clear(Array<Type>& array);
template<class Type> bool fill(Array<Type>& array, usize begin, usize end, Type value);
template<class Type> void free(Array<Type>& array);
template<class Type> bool grow(Array<Type>& array, usize min_capacity);
template<class Type> usize num(Array<Type>& array);
template<class Type> void pop(Array<Type>& array);
template<class Type> void remove_at(Array<Type>& array, usize idx);
template<class Type> bool reserve(Array<Type>& array, usize new_capacity);
template<class Type> bool resize(Array<Type>& array, usize num);
template<class Type> bool set_capacity(Array<Type>& array, usize new_capacity);
template<class Type> ArrayHeader* get_header(Array<Type>& array);
struct ArrayHeader
{
AllocatorInfo Allocator;
usize Capacity;
usize Num;
};
2023-07-24 15:19:37 -07:00
template<class Type>
struct Array
{
2024-11-30 10:14:47 -08:00
Type* Data;
#if 1
#pragma region Member Mapping
forceinline static Array init(AllocatorInfo allocator) { return GEN_NS array_init<Type>(allocator); }
forceinline static Array init_reserve(AllocatorInfo allocator, ssize capacity) { return GEN_NS array_init_reserve<Type>(allocator, capacity); }
forceinline static usize grow_formula(ssize value) { return GEN_NS array_grow_formula<Type>(value); }
forceinline bool append(Array other) { return GEN_NS append<Type>(*this, other); }
forceinline bool append(Type value) { return GEN_NS append<Type>(*this, value); }
forceinline bool append(Type* items, usize item_num) { return GEN_NS append<Type>(*this, items, item_num); }
forceinline bool append_at(Type item, usize idx) { return GEN_NS append_at<Type>(*this, item, idx); }
forceinline bool append_at(Type* items, usize item_num, usize idx) { return GEN_NS append_at<Type>(*this, items, item_num, idx); }
forceinline Type& back() { return GEN_NS back<Type>(*this); }
forceinline void clear() { GEN_NS clear<Type>(*this); }
forceinline bool fill(usize begin, usize end, Type value) { return GEN_NS fill<Type>(*this, begin, end, value); }
forceinline void free() { GEN_NS free<Type>(*this); }
forceinline ArrayHeader* get_header() { return GEN_NS get_header<Type>(*this); }
forceinline bool grow(usize min_capacity) { return GEN_NS grow<Type>(*this, min_capacity); }
forceinline usize num() { return GEN_NS num<Type>(*this); }
forceinline void pop() { GEN_NS pop<Type>(*this); }
forceinline void remove_at(usize idx) { GEN_NS remove_at<Type>(*this, idx); }
forceinline bool reserve(usize new_capacity) { return GEN_NS reserve<Type>(*this, new_capacity); }
forceinline bool resize(usize num) { return GEN_NS resize<Type>(*this, num); }
forceinline bool set_capacity(usize new_capacity) { return GEN_NS set_capacity<Type>(*this, new_capacity); }
forceinline operator Type*() { return Data; }
forceinline operator Type const*() const { return Data; }
forceinline Type* begin() { return Data; }
forceinline Type* end() { return Data + get_header()->Num; }
#pragma endregion Member Mapping
#endif
};
2024-11-30 10:14:47 -08:00
template<class Type> inline
Array<Type> array_init(AllocatorInfo allocator)
{
return array_init_reserve<Type>(allocator, array_grow_formula<Type>(0));
}
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
template<class Type> inline
Array<Type> array_init_reserve(AllocatorInfo allocator, ssize capacity)
{
ArrayHeader* header = rcast(ArrayHeader*, alloc(allocator, sizeof(ArrayHeader) + sizeof(Type) * capacity));
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
if (header == nullptr)
return {nullptr};
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
header->Allocator = allocator;
header->Capacity = capacity;
header->Num = 0;
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
return {rcast(Type*, header + 1)};
}
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
template<class Type> inline
usize array_grow_formula(ssize value)
{
return 2 * value + 8;
}
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
template<class Type> inline
bool append(Array<Type>& array, Array<Type> other)
{
return append(array, other, num(other));
}
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
template<class Type> inline
bool append(Array<Type>& array, Type value)
{
ArrayHeader* header = get_header(array);
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
if (header->Num == header->Capacity)
{
if (!grow(array, header->Capacity))
return false;
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
header = get_header(array);
}
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
array.Data[header->Num] = value;
header->Num++;
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
return true;
}
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
template<class Type> inline
bool append(Array<Type>& array, Type* items, usize item_num)
{
ArrayHeader* header = get_header(array);
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
if (header->Num + item_num > header->Capacity)
{
if (!grow(array, header->Capacity + item_num))
return false;
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
header = get_header(array);
}
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
mem_copy(array.Data + header->Num, items, item_num * sizeof(Type));
header->Num += item_num;
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
return true;
}
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
template<class Type> inline
bool append_at(Array<Type>& array, Type item, usize idx)
{
ArrayHeader* header = get_header(array);
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
if (idx >= header->Num)
idx = header->Num - 1;
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
if (idx < 0)
idx = 0;
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
if (header->Capacity < header->Num + 1)
{
if (!grow(array, header->Capacity + 1))
return false;
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
header = get_header(array);
}
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
Type* target = array.Data + idx;
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
mem_move(target + 1, target, (header->Num - idx) * sizeof(Type));
header->Num++;
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
return true;
}
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
template<class Type> inline
bool append_at(Array<Type>& array, Type* items, usize item_num, usize idx)
{
ArrayHeader* header = get_header(array);
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
if (idx >= header->Num)
{
return append(array, items, item_num);
}
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
if (item_num > header->Capacity)
{
if (!grow(array, header->Capacity + item_num))
return false;
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
header = get_header(array);
}
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
Type* target = array.Data + idx + item_num;
Type* src = array.Data + idx;
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
mem_move(target, src, (header->Num - idx) * sizeof(Type));
mem_copy(src, items, item_num * sizeof(Type));
header->Num += item_num;
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
return true;
}
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
template<class Type> inline
Type& back(Array<Type>& array)
{
ArrayHeader* header = get_header(array);
return array.Data[header->Num - 1];
}
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
template<class Type> inline
void clear(Array<Type>& array)
{
ArrayHeader* header = get_header(array);
header->Num = 0;
}
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
template<class Type> inline
bool fill(Array<Type>& array, usize begin, usize end, Type value)
{
ArrayHeader* header = get_header(array);
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
if (begin < 0 || end > header->Num)
return false;
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
for (ssize idx = ssize(begin); idx < ssize(end); idx++)
{
array.Data[idx] = value;
}
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
return true;
}
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
template<class Type> inline
void free(Array<Type>& array)
{
ArrayHeader* header = get_header(array);
gen::free(header->Allocator, header);
array.Data = nullptr;
}
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
template<class Type> inline
ArrayHeader* get_header(Array<Type>& array)
{
using NonConstType = TRemoveConst<Type>;
return rcast(ArrayHeader*, const_cast<NonConstType*>(array.Data)) - 1;
}
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
template<class Type> inline
bool grow(Array<Type>& array, usize min_capacity)
{
ArrayHeader* header = get_header(array);
usize new_capacity = array_grow_formula<Type>(header->Capacity);
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
if (new_capacity < min_capacity)
new_capacity = min_capacity;
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
return set_capacity(array, new_capacity);
}
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
template<class Type> inline
usize num(Array<Type>& array)
{
return get_header(array)->Num;
}
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
template<class Type> inline
void pop(Array<Type>& array)
{
ArrayHeader* header = get_header(array);
GEN_ASSERT(header->Num > 0);
header->Num--;
}
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
template<class Type> inline
void remove_at(Array<Type>& array, usize idx)
{
ArrayHeader* header = get_header(array);
GEN_ASSERT(idx < header->Num);
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
mem_move(array.Data + idx, array.Data + idx + 1, sizeof(Type) * (header->Num - idx - 1));
header->Num--;
}
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
template<class Type> inline
bool reserve(Array<Type>& array, usize new_capacity)
{
ArrayHeader* header = get_header(array);
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
if (header->Capacity < new_capacity)
return set_capacity(array, new_capacity);
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
return true;
}
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
template<class Type> inline
bool resize(Array<Type>& array, usize num)
{
ArrayHeader* header = get_header(array);
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
if (header->Capacity < num)
{
if (!grow(array, num))
return false;
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
header = get_header(array);
}
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
header->Num = num;
return true;
}
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
template<class Type> inline
bool set_capacity(Array<Type>& array, usize new_capacity)
{
ArrayHeader* header = get_header(array);
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
if (new_capacity == header->Capacity)
return true;
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
if (new_capacity < header->Num)
{
header->Num = new_capacity;
return true;
}
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
ssize size = sizeof(ArrayHeader) + sizeof(Type) * new_capacity;
ArrayHeader* new_header = rcast(ArrayHeader*, alloc(header->Allocator, size));
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
if (new_header == nullptr)
return false;
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
mem_move(new_header, header, sizeof(ArrayHeader) + sizeof(Type) * header->Num);
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
new_header->Capacity = new_capacity;
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
gen::free(header->Allocator, header);
2023-07-24 15:19:37 -07:00
2024-11-30 10:14:47 -08:00
array.Data = rcast(Type*, new_header + 1);
return true;
}
#pragma endregion Array
2023-07-24 15:19:37 -07:00
2024-04-17 13:55:22 -07:00
// TODO(Ed) : This thing needs ALOT of work.
2023-07-24 15:19:37 -07:00
template<typename Type>
struct HashTable
{
struct FindResult
{
ssize HashIndex;
ssize PrevIndex;
ssize EntryIndex;
2023-07-24 15:19:37 -07:00
};
struct Entry
{
u64 Key;
ssize Next;
2023-07-24 15:19:37 -07:00
Type Value;
};
static constexpr f32 CriticalLoadScale = 0.7f;
2023-07-24 15:19:37 -07:00
static
HashTable init( AllocatorInfo allocator )
{
HashTable<Type> result = init_reserve(allocator, 8);
2023-07-24 15:19:37 -07:00
return result;
}
static
HashTable init_reserve( AllocatorInfo allocator, usize num )
2023-07-24 15:19:37 -07:00
{
HashTable<Type> result = { { nullptr }, { nullptr } };
result.Hashes = Array<ssize>::init_reserve( allocator, num );
2023-07-24 15:19:37 -07:00
result.Hashes.get_header()->Num = num;
result.Hashes.resize( num );
result.Hashes.fill( 0, num, -1);
2023-07-24 15:19:37 -07:00
result.Entries = Array<Entry>::init_reserve( allocator, num );
return result;
}
void clear( void )
{
Entries.clear();
Hashes.fill( 0, Hashes.num(), -1);
2023-07-24 15:19:37 -07:00
}
void destroy( void )
{
if ( Hashes && Hashes.get_header()->Capacity )
{
Hashes.free();
Entries.free();
}
}
Type* get( u64 key )
{
ssize idx = find( key ).EntryIndex;
2023-07-24 15:19:37 -07:00
if ( idx >= 0 )
return & Entries[ idx ].Value;
return nullptr;
}
using MapProc = void (*)( u64 key, Type value );
void map( MapProc map_proc )
{
GEN_ASSERT_NOT_NULL( map_proc );
for ( ssize idx = 0; idx < ssize(Entries.num()); ++idx )
2023-07-24 15:19:37 -07:00
{
map_proc( Entries[ idx ].Key, Entries[ idx ].Value );
}
}
using MapMutProc = void (*)( u64 key, Type* value );
void map_mut( MapMutProc map_proc )
{
GEN_ASSERT_NOT_NULL( map_proc );
for ( ssize idx = 0; idx < ssize(Entries.num()); ++idx )
2023-07-24 15:19:37 -07:00
{
map_proc( Entries[ idx ].Key, & Entries[ idx ].Value );
}
}
void grow()
{
ssize new_num = Array<Entry>::grow_formula( Entries.num() );
2023-07-24 15:19:37 -07:00
rehash( new_num );
}
void rehash( ssize new_num )
2023-07-24 15:19:37 -07:00
{
ssize last_added_index;
2023-07-24 15:19:37 -07:00
HashTable<Type> new_ht = init_reserve( Hashes.get_header()->Allocator, new_num );
for ( ssize idx = 0; idx < ssize(Entries.num()); ++idx )
2023-07-24 15:19:37 -07:00
{
FindResult find_result;
Entry& entry = Entries[ idx ];
2023-07-24 15:19:37 -07:00
find_result = new_ht.find( entry.Key );
last_added_index = new_ht.add_entry( entry.Key );
if ( find_result.PrevIndex < 0 )
new_ht.Hashes[ find_result.HashIndex ] = last_added_index;
else
new_ht.Entries[ find_result.PrevIndex ].Next = last_added_index;
new_ht.Entries[ last_added_index ].Next = find_result.EntryIndex;
new_ht.Entries[ last_added_index ].Value = entry.Value;
}
destroy();
*this = new_ht;
}
void rehash_fast()
{
ssize idx;
2023-07-24 15:19:37 -07:00
for ( idx = 0; idx < ssize(Entries.num()); idx++ )
2023-07-24 15:19:37 -07:00
Entries[ idx ].Next = -1;
for ( idx = 0; idx < ssize(Hashes.num()); idx++ )
2023-07-24 15:19:37 -07:00
Hashes[ idx ] = -1;
for ( idx = 0; idx < ssize(Entries.num()); idx++ )
2023-07-24 15:19:37 -07:00
{
Entry* entry;
2023-07-24 15:19:37 -07:00
FindResult find_result;
entry = & Entries[ idx ];
find_result = find( entry->Key );
if ( find_result.PrevIndex < 0 )
Hashes[ find_result.HashIndex ] = idx;
else
Entries[ find_result.PrevIndex ].Next = idx;
2023-07-24 15:19:37 -07:00
}
}
void remove( u64 key )
{
FindResult find_result = find( key);
if ( find_result.EntryIndex >= 0 )
{
Entries.remove_at( find_result.EntryIndex );
rehash_fast();
}
}
void remove_entry( ssize idx )
2023-07-24 15:19:37 -07:00
{
Entries.remove_at( idx );
}
void set( u64 key, Type value )
{
ssize idx;
2023-07-24 15:19:37 -07:00
FindResult find_result;
if ( full() )
2023-07-24 15:19:37 -07:00
grow();
find_result = find( key );
if ( find_result.EntryIndex >= 0 )
{
idx = find_result.EntryIndex;
}
else
{
idx = add_entry( key );
if ( find_result.PrevIndex >= 0 )
{
Entries[ find_result.PrevIndex ].Next = idx;
}
else
{
Hashes[ find_result.HashIndex ] = idx;
}
}
Entries[ idx ].Value = value;
if ( full() )
grow();
}
ssize slot( u64 key )
2023-07-24 15:19:37 -07:00
{
for ( ssize idx = 0; idx < ssize(Hashes.num()); ++idx )
2023-07-24 15:19:37 -07:00
if ( Hashes[ idx ] == key )
return idx;
return -1;
}
Array< ssize> Hashes;
2023-07-24 15:19:37 -07:00
Array< Entry> Entries;
protected:
ssize add_entry( u64 key )
2023-07-24 15:19:37 -07:00
{
ssize idx;
2023-07-24 15:19:37 -07:00
Entry entry = { key, -1 };
idx = Entries.num();
Entries.append( entry );
return idx;
}
FindResult find( u64 key )
{
FindResult result = { -1, -1, -1 };
if ( Hashes.num() > 0 )
{
result.HashIndex = key % Hashes.num();
result.EntryIndex = Hashes[ result.HashIndex ];
while ( result.EntryIndex >= 0 )
{
if ( Entries[ result.EntryIndex ].Key == key )
break;
result.PrevIndex = result.EntryIndex;
result.EntryIndex = Entries[ result.EntryIndex ].Next;
}
}
return result;
}
b32 full()
{
usize critical_load = usize( CriticalLoadScale * f32(Hashes.num()) );
b32 result = Entries.num() > critical_load;
return result;
2023-07-24 15:19:37 -07:00
}
};
#pragma endregion Containers