mirror of
				https://github.com/Ed94/gencpp.git
				synced 2025-11-03 23:36:12 -08:00 
			
		
		
		
	Lexer tokens now tracked using TokenSlice. ParserContext as the id for current token during traversal. Last progress on errors needs updates to interface.parsing.cpp Not adding message support yet as that will need to revamped with the logging, right now just focused on getting both lexer on parser to use proper info data structures. Thinking of separating ParseContext from the general lib Context, plan is to just have the parser context have its allocator and other references it needs. So there will seem to be redundant parameter passing to some procedures for now. The big endgoal of this other than the parser's compression is the ability to support mult-threading. Immediate concern other than making sure everything necessary is only within ParseContext, etc is things related to logging, or otherwise that is not thread dependent. Those can get guarded but I don't have full intuition on what will have that (most likely the library's provided allocator/s as well will need guards introduced). I'll concern myself more with charting those out once things are at least lifted properly. Worst case a trivial situation can be achived by the user by just abusing multiple contextes/allocators/etc as we already have in place.
		
			
				
	
	
		
			827 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			827 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#ifdef 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;
 | 
						|
 | 
						|
template <class TType> struct RemovePtr         { typedef TType Type; };
 | 
						|
template <class TType> struct RemovePtr<TType*> { typedef TType Type; };
 | 
						|
 | 
						|
template <class TType> using TRemovePtr = typename RemovePtr<TType>::Type;
 | 
						|
 | 
						|
#pragma region Slice
 | 
						|
#if 0
 | 
						|
#define Slice(Type) Slice<Type>
 | 
						|
 | 
						|
template<class Type> struct Slice;
 | 
						|
 | 
						|
template<class Type>
 | 
						|
Type* slice_get(Slice<Type> self, ssize id) { 
 | 
						|
	GEN_ASSERT(id > -1);
 | 
						|
	GEN_ASSERT(id < self.len);
 | 
						|
	return self.ptr[id];
 | 
						|
 }
 | 
						|
 | 
						|
template<class Type>
 | 
						|
struct Slice
 | 
						|
{
 | 
						|
	Type* ptr;
 | 
						|
	ssize len;
 | 
						|
 | 
						|
#if GEN_COMPILER_CPP
 | 
						|
	forceinline operator Token* ()               const { return ptr; }
 | 
						|
	forceinline Token& operator[]( ssize index ) const { return ptr[index]; }
 | 
						|
 | 
						|
	forceinline Type* begin() { return ptr; }
 | 
						|
	forceinline Type* end()   { return ptr + len; }
 | 
						|
#endif
 | 
						|
 | 
						|
#if ! GEN_C_LIKE_CPP && GEN_COMPILER_CPP
 | 
						|
	forceinline Type& back() { return ptr[len - 1]; }
 | 
						|
#endif
 | 
						|
};
 | 
						|
#endif
 | 
						|
#pragma endregion Slice
 | 
						|
 | 
						|
#pragma region Array
 | 
						|
#define Array(Type) Array<Type>
 | 
						|
 | 
						|
// #define array_init(Type, ...)         array_init        <Type>(__VA_ARGS__)
 | 
						|
// #define array_init_reserve(Type, ...) array_init_reserve<Type>(__VA_ARGS__)
 | 
						|
 | 
						|
struct ArrayHeader;
 | 
						|
 | 
						|
template<class Type> struct Array;
 | 
						|
#define get_array_underlying_type(array) typename TRemovePtr<typeof(array)>:: DataType
 | 
						|
 | 
						|
usize array_grow_formula(ssize value);
 | 
						|
 | 
						|
template<class Type> Array<Type>  array_init           (AllocatorInfo allocator);
 | 
						|
template<class Type> Array<Type>  array_init_reserve   (AllocatorInfo allocator, ssize capacity);
 | 
						|
template<class Type> bool         array_append_array   (Array<Type>* array, Array<Type> other);
 | 
						|
template<class Type> bool         array_append         (Array<Type>* array, Type value);
 | 
						|
template<class Type> bool         array_append_items   (Array<Type>* array, Type* items, usize item_num);
 | 
						|
template<class Type> bool         array_append_at      (Array<Type>* array, Type item, usize idx);
 | 
						|
template<class Type> bool         array_append_items_at(Array<Type>* array, Type* items, usize item_num, usize idx);
 | 
						|
template<class Type> Type*        array_back           (Array<Type>  array);
 | 
						|
template<class Type> void         array_clear          (Array<Type>  array);
 | 
						|
template<class Type> bool         array_fill           (Array<Type>  array, usize begin, usize end, Type value);
 | 
						|
template<class Type> void         array_free           (Array<Type>* array);
 | 
						|
template<class Type> bool         arary_grow           (Array<Type>* array, usize min_capacity);
 | 
						|
template<class Type> usize        array_num            (Array<Type>  array);
 | 
						|
template<class Type> void         arary_pop            (Array<Type>  array);
 | 
						|
template<class Type> void         arary_remove_at      (Array<Type>  array, usize idx);
 | 
						|
template<class Type> bool         arary_reserve        (Array<Type>* array, usize new_capacity);
 | 
						|
template<class Type> bool         arary_resize         (Array<Type>* array, usize num);
 | 
						|
template<class Type> bool         arary_set_capacity   (Array<Type>* array, usize new_capacity);
 | 
						|
template<class Type> ArrayHeader* arary_get_header     (Array<Type>  array);
 | 
						|
 | 
						|
struct ArrayHeader {
 | 
						|
	AllocatorInfo Allocator;
 | 
						|
	usize         Capacity;
 | 
						|
	usize         Num;
 | 
						|
};
 | 
						|
 | 
						|
template<class Type>
 | 
						|
struct Array
 | 
						|
{
 | 
						|
	Type* Data;
 | 
						|
 | 
						|
#if ! GEN_C_LIKE_CPP
 | 
						|
#pragma region Member Mapping
 | 
						|
	forceinline static Array  init(AllocatorInfo allocator)                         { return array_init<Type>(allocator); }
 | 
						|
	forceinline static Array  init_reserve(AllocatorInfo allocator, ssize capacity) { return array_init_reserve<Type>(allocator, capacity); }
 | 
						|
	forceinline static usize  grow_formula(ssize value)                             { return array_grow_formula<Type>(value); }
 | 
						|
 | 
						|
	forceinline bool         append(Array other)                               { return array_append_array<Type>(this, other); }
 | 
						|
	forceinline bool         append(Type value)                                { return array_append<Type>(this, value); }
 | 
						|
	forceinline bool         append(Type* items, usize item_num)               { return array_append_items<Type>(this, items, item_num); }
 | 
						|
	forceinline bool         append_at(Type item, usize idx)                   { return array_append_at<Type>(this, item, idx); }
 | 
						|
	forceinline bool         append_at(Type* items, usize item_num, usize idx) { return array_append_items_at<Type>(this, items, item_num, idx); }
 | 
						|
	forceinline Type*        back()                                            { return array_back<Type>(* this); }
 | 
						|
	forceinline void         clear()                                           {        array_clear<Type>(* this); }
 | 
						|
	forceinline bool         fill(usize begin, usize end, Type value)          { return array_fill<Type>(* this, begin, end, value); }
 | 
						|
	forceinline void         free()                                            {        array_free<Type>(this); }
 | 
						|
	forceinline ArrayHeader* get_header()                                      { return array_get_header<Type>(* this); }
 | 
						|
	forceinline bool         grow(usize min_capacity)                          { return array_grow<Type>(this, min_capacity); }
 | 
						|
	forceinline usize        num()                                             { return array_num<Type>(*this); }
 | 
						|
	forceinline void         pop()                                             {        array_pop<Type>(* this); }
 | 
						|
	forceinline void         remove_at(usize idx)                              {        array_remove_at<Type>(* this, idx); }
 | 
						|
	forceinline bool         reserve(usize new_capacity)                       { return array_reserve<Type>(this, new_capacity); }
 | 
						|
	forceinline bool         resize(usize num)                                 { return array_resize<Type>(this, num); }
 | 
						|
	forceinline bool         set_capacity(usize new_capacity)                  { return array_set_capacity<Type>(this, new_capacity); }
 | 
						|
#pragma endregion Member Mapping
 | 
						|
#endif
 | 
						|
 | 
						|
	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; }
 | 
						|
 | 
						|
	forceinline Type&       operator[](ssize index)       { return Data[index]; }
 | 
						|
	forceinline Type const& operator[](ssize index) const { return Data[index]; }
 | 
						|
 | 
						|
	using DataType = Type;
 | 
						|
};
 | 
						|
 | 
						|
#if 0
 | 
						|
template<class Type> bool append(Array<Type>& array, Array<Type> other)                         { return append( & array, other ); }
 | 
						|
template<class Type> bool append(Array<Type>& array, Type value)                                { return append( & array, value ); }
 | 
						|
template<class Type> bool append(Array<Type>& array, Type* items, usize item_num)               { return append( & array, items, item_num ); }
 | 
						|
template<class Type> bool append_at(Array<Type>& array, Type item, usize idx)                   { return append_at( & array, item, idx ); }
 | 
						|
template<class Type> bool append_at(Array<Type>& array, Type* items, usize item_num, usize idx) { return append_at( & array, items, item_num, idx ); }
 | 
						|
template<class Type> void free(Array<Type>& array)                                              { return free( & array ); }
 | 
						|
template<class Type> bool grow(Array<Type>& array, usize min_capacity)                          { return grow( & array, min_capacity); }
 | 
						|
template<class Type> bool reserve(Array<Type>& array, usize new_capacity)                       { return reserve( & array, new_capacity); }
 | 
						|
template<class Type> bool resize(Array<Type>& array, usize num)                                 { return resize( & array, num); }
 | 
						|
template<class Type> bool set_capacity(Array<Type>& array, usize new_capacity)                  { return set_capacity( & array, new_capacity); }
 | 
						|
 | 
						|
template<class Type> forceinline Type* begin(Array<Type>& array)             { return array;      }
 | 
						|
template<class Type> forceinline Type* end(Array<Type>& array)               { return array + array_get_header(array)->Num; }
 | 
						|
template<class Type> forceinline Type* next(Array<Type>& array, Type* entry) { return entry + 1; }
 | 
						|
#endif
 | 
						|
 | 
						|
template<class Type> forceinline Type* array_begin(Array<Type> array)             { return array;      }
 | 
						|
template<class Type> forceinline Type* array_end(Array<Type> array)               { return array + array_get_header(array)->Num; }
 | 
						|
template<class Type> forceinline Type* array_next(Array<Type> array, Type* entry) { return ++ entry; }
 | 
						|
 | 
						|
template<class Type> inline
 | 
						|
Array<Type> array_init(AllocatorInfo allocator) {
 | 
						|
	return array_init_reserve<Type>(allocator, array_grow_formula(0));
 | 
						|
}
 | 
						|
 | 
						|
template<class Type> inline
 | 
						|
Array<Type> array_init_reserve(AllocatorInfo allocator, ssize capacity)
 | 
						|
{
 | 
						|
	GEN_ASSERT(capacity > 0);
 | 
						|
	ArrayHeader* header = rcast(ArrayHeader*, alloc(allocator, sizeof(ArrayHeader) + sizeof(Type) * capacity));
 | 
						|
 | 
						|
	if (header == nullptr)
 | 
						|
		return {nullptr};
 | 
						|
 | 
						|
	header->Allocator = allocator;
 | 
						|
	header->Capacity  = capacity;
 | 
						|
	header->Num       = 0;
 | 
						|
 | 
						|
	return {rcast(Type*, header + 1)};
 | 
						|
}
 | 
						|
 | 
						|
forceinline
 | 
						|
usize array_grow_formula(ssize value) {
 | 
						|
	return 2 * value + 8;
 | 
						|
}
 | 
						|
 | 
						|
template<class Type> inline
 | 
						|
bool array_append_array(Array<Type>* array, Array<Type> other) {
 | 
						|
	return array_append_items(array, (Type*)other, array_num(other));
 | 
						|
}
 | 
						|
 | 
						|
template<class Type> inline
 | 
						|
bool array_append(Array<Type>* array, Type value)
 | 
						|
{
 | 
						|
	GEN_ASSERT(  array != nullptr);
 | 
						|
	GEN_ASSERT(* array != nullptr);
 | 
						|
	ArrayHeader* header = array_get_header(* array);
 | 
						|
 | 
						|
	if (header->Num == header->Capacity)
 | 
						|
	{
 | 
						|
		if ( ! array_grow(array, header->Capacity))
 | 
						|
			return false;
 | 
						|
		header = array_get_header(* array);
 | 
						|
	}
 | 
						|
 | 
						|
	(*array)[ header->Num] = value;
 | 
						|
	header->Num++;
 | 
						|
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
template<class Type> inline
 | 
						|
bool array_append_items(Array<Type>* array, Type* items, usize item_num)
 | 
						|
{
 | 
						|
	GEN_ASSERT(  array != nullptr);
 | 
						|
	GEN_ASSERT(* array != nullptr);
 | 
						|
	GEN_ASSERT(items != nullptr);
 | 
						|
	GEN_ASSERT(item_num > 0);
 | 
						|
	ArrayHeader* header = array_get_header(* array);
 | 
						|
 | 
						|
	if (header->Num + item_num > header->Capacity)
 | 
						|
	{
 | 
						|
		if ( ! array_grow(array, header->Capacity + item_num))
 | 
						|
			return false;
 | 
						|
		header = array_get_header(* array);
 | 
						|
	}
 | 
						|
 | 
						|
	mem_copy((Type*)array + header->Num, items, item_num * sizeof(Type));
 | 
						|
	header->Num += item_num;
 | 
						|
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
template<class Type> inline
 | 
						|
bool array_append_at(Array<Type>* array, Type item, usize idx)
 | 
						|
{
 | 
						|
	GEN_ASSERT(  array != nullptr);
 | 
						|
	GEN_ASSERT(* array != nullptr);
 | 
						|
	ArrayHeader* header = array_get_header(* array);
 | 
						|
 | 
						|
	ssize slot = idx;
 | 
						|
	if (slot >= (ssize)(header->Num))
 | 
						|
		slot = header->Num - 1;
 | 
						|
 | 
						|
	if (slot < 0)
 | 
						|
		slot = 0;
 | 
						|
 | 
						|
	if (header->Capacity < header->Num + 1)
 | 
						|
	{
 | 
						|
		if ( ! array_grow(array, header->Capacity + 1))
 | 
						|
			return false;
 | 
						|
 | 
						|
		header = array_get_header(* array);
 | 
						|
	}
 | 
						|
 | 
						|
	Type* target = &(*array)[slot];
 | 
						|
 | 
						|
	mem_move(target + 1, target, (header->Num - slot) * sizeof(Type));
 | 
						|
	header->Num++;
 | 
						|
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
template<class Type> inline
 | 
						|
bool array_append_items_at(Array<Type>* array, Type* items, usize item_num, usize idx)
 | 
						|
{
 | 
						|
	GEN_ASSERT(  array != nullptr);
 | 
						|
	GEN_ASSERT(* array != nullptr);
 | 
						|
	ArrayHeader* header = get_header(array);
 | 
						|
 | 
						|
	if (idx >= header->Num)
 | 
						|
	{
 | 
						|
		return array_append_items(array, items, item_num);
 | 
						|
	}
 | 
						|
 | 
						|
	if (item_num > header->Capacity)
 | 
						|
	{
 | 
						|
		if (! grow(array, header->Capacity + item_num))
 | 
						|
			return false;
 | 
						|
 | 
						|
		header = get_header(array);
 | 
						|
	}
 | 
						|
 | 
						|
	Type* target = array.Data + idx + item_num;
 | 
						|
	Type* src    = array.Data + idx;
 | 
						|
 | 
						|
	mem_move(target, src, (header->Num - idx) * sizeof(Type));
 | 
						|
	mem_copy(src, items, item_num * sizeof(Type));
 | 
						|
	header->Num += item_num;
 | 
						|
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
template<class Type> inline
 | 
						|
Type* array_back(Array<Type> array)
 | 
						|
{
 | 
						|
	GEN_ASSERT(array != nullptr);
 | 
						|
 | 
						|
	ArrayHeader* header = array_get_header(array);
 | 
						|
	if (header->Num <= 0)
 | 
						|
		return nullptr;
 | 
						|
 | 
						|
	return & (array)[header->Num - 1];
 | 
						|
}
 | 
						|
 | 
						|
template<class Type> inline
 | 
						|
void array_clear(Array<Type> array) {
 | 
						|
	GEN_ASSERT(array != nullptr);
 | 
						|
	ArrayHeader* header = array_get_header(array);
 | 
						|
	header->Num = 0;
 | 
						|
}
 | 
						|
 | 
						|
template<class Type> inline
 | 
						|
bool array_fill(Array<Type> array, usize begin, usize end, Type value)
 | 
						|
{
 | 
						|
	GEN_ASSERT(array != nullptr);
 | 
						|
	GEN_ASSERT(begin <= end);
 | 
						|
	ArrayHeader* header = array_get_header(array);
 | 
						|
 | 
						|
	if (begin < 0 || end > header->Num)
 | 
						|
		return false;
 | 
						|
 | 
						|
	for (ssize idx = ssize(begin); idx < ssize(end); idx++) {
 | 
						|
		array[idx] = value;
 | 
						|
	}
 | 
						|
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
template<class Type> forceinline
 | 
						|
void array_free(Array<Type>* array) {
 | 
						|
	GEN_ASSERT(  array != nullptr);
 | 
						|
	GEN_ASSERT(* array != nullptr);
 | 
						|
	ArrayHeader* header = array_get_header(* array);
 | 
						|
	allocator_free(header->Allocator, header);
 | 
						|
	Type** Data = (Type**)array;
 | 
						|
	*Data = nullptr;
 | 
						|
}
 | 
						|
 | 
						|
template<class Type> forceinline
 | 
						|
ArrayHeader* array_get_header(Array<Type> array) {
 | 
						|
	GEN_ASSERT(array != nullptr);
 | 
						|
    Type* Data = array;
 | 
						|
 | 
						|
	using NonConstType = TRemoveConst<Type>;
 | 
						|
    return rcast(ArrayHeader*, const_cast<NonConstType*>(Data)) - 1;
 | 
						|
}
 | 
						|
 | 
						|
template<class Type> forceinline
 | 
						|
bool array_grow(Array<Type>* array, usize min_capacity)
 | 
						|
{
 | 
						|
	GEN_ASSERT(  array != nullptr);
 | 
						|
	GEN_ASSERT(* array != nullptr);
 | 
						|
	GEN_ASSERT( min_capacity > 0 );
 | 
						|
	ArrayHeader* header       = array_get_header(* array);
 | 
						|
	usize        new_capacity = array_grow_formula(header->Capacity);
 | 
						|
 | 
						|
	if (new_capacity < min_capacity)
 | 
						|
		new_capacity = min_capacity;
 | 
						|
 | 
						|
	return array_set_capacity(array, new_capacity);
 | 
						|
}
 | 
						|
 | 
						|
template<class Type> forceinline
 | 
						|
usize array_num(Array<Type> array) {
 | 
						|
	GEN_ASSERT(array != nullptr);
 | 
						|
	return array_get_header(array)->Num;
 | 
						|
}
 | 
						|
 | 
						|
template<class Type> forceinline
 | 
						|
void array_pop(Array<Type> array) {
 | 
						|
	GEN_ASSERT(array != nullptr);
 | 
						|
	ArrayHeader* header = array_get_header(array);
 | 
						|
	GEN_ASSERT(header->Num > 0);
 | 
						|
	header->Num--;
 | 
						|
}
 | 
						|
 | 
						|
template<class Type> inline
 | 
						|
void array_remove_at(Array<Type> array, usize idx)
 | 
						|
{
 | 
						|
	GEN_ASSERT(array != nullptr);
 | 
						|
	ArrayHeader* header = array_get_header(array);
 | 
						|
	GEN_ASSERT(idx < header->Num);
 | 
						|
 | 
						|
	mem_move(array + idx, array + idx + 1, sizeof(Type) * (header->Num - idx - 1));
 | 
						|
	header->Num--;
 | 
						|
}
 | 
						|
 | 
						|
template<class Type> inline
 | 
						|
bool array_reserve(Array<Type>* array, usize new_capacity)
 | 
						|
{
 | 
						|
	GEN_ASSERT(  array != nullptr);
 | 
						|
	GEN_ASSERT(* array != nullptr);
 | 
						|
	ArrayHeader* header = array_get_header(array);
 | 
						|
 | 
						|
	if (header->Capacity < new_capacity)
 | 
						|
		return set_capacity(array, new_capacity);
 | 
						|
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
template<class Type> inline
 | 
						|
bool array_resize(Array<Type>* array, usize num)
 | 
						|
{
 | 
						|
	GEN_ASSERT(  array != nullptr);
 | 
						|
	GEN_ASSERT(* array != nullptr);
 | 
						|
	ArrayHeader* header = array_get_header(* array);
 | 
						|
 | 
						|
	if (header->Capacity < num) {
 | 
						|
		if (! array_grow( array, num))
 | 
						|
			return false;
 | 
						|
		header = array_get_header(* array);
 | 
						|
	}
 | 
						|
 | 
						|
	header->Num = num;
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
template<class Type> inline
 | 
						|
bool array_set_capacity(Array<Type>* array, usize new_capacity)
 | 
						|
{
 | 
						|
	GEN_ASSERT(  array != nullptr);
 | 
						|
	GEN_ASSERT(* array != nullptr);
 | 
						|
	ArrayHeader* header = array_get_header(* array);
 | 
						|
 | 
						|
	if (new_capacity == header->Capacity)
 | 
						|
		return true;
 | 
						|
 | 
						|
	if (new_capacity < header->Num)
 | 
						|
	{
 | 
						|
		header->Num = new_capacity;
 | 
						|
		return true;
 | 
						|
	}
 | 
						|
 | 
						|
	ssize        size       = sizeof(ArrayHeader) + sizeof(Type) * new_capacity;
 | 
						|
	ArrayHeader* new_header = rcast(ArrayHeader*, alloc(header->Allocator, size));
 | 
						|
 | 
						|
	if (new_header == nullptr)
 | 
						|
		return false;
 | 
						|
 | 
						|
	mem_move(new_header, header, sizeof(ArrayHeader) + sizeof(Type) * header->Num);
 | 
						|
 | 
						|
	new_header->Capacity = new_capacity;
 | 
						|
 | 
						|
	allocator_free(header->Allocator, header);
 | 
						|
 | 
						|
	Type** Data = (Type**)array;
 | 
						|
	* Data = rcast(Type*, new_header + 1);
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
// These are intended for use in the base library of gencpp and the C-variant of the library
 | 
						|
// It provides a interoperability between the C++ and C implementation of arrays. (not letting these do any crazy substiution though)
 | 
						|
// They are undefined in gen.hpp and gen.cpp at the end of the files.
 | 
						|
// The cpp library expects the user to use the regular calls as they can resolve the type fine.
 | 
						|
 | 
						|
#define array_init(type, allocator)                        array_init           <type>                               (allocator )
 | 
						|
#define array_init_reserve(type, allocator, cap)           array_init_reserve   <type>                               (allocator, cap)
 | 
						|
#define array_append_array(array, other)                   array_append_array   < get_array_underlying_type(array) > (& array, other )
 | 
						|
#define array_append(array, value)                         array_append         < get_array_underlying_type(array) > (& array, value )
 | 
						|
#define array_append_items(array, items, item_num)         array_append_items   < get_array_underlying_type(array) > (& array, items, item_num )
 | 
						|
#define array_append_at(array, item, idx )                 array_append_at      < get_array_underlying_type(array) > (& array, item, idx )
 | 
						|
#define array_append_at_items(array, items, item_num, idx) array_append_at_items< get_array_underlying_type(array) > (& items, item_num, idx )
 | 
						|
#define array_back(array)                                  array_back           < get_array_underlying_type(array) > (array )
 | 
						|
#define array_clear(array)                                 array_clear          < get_array_underlying_type(array) > (array )
 | 
						|
#define array_fill(array, begin, end, value)               array_fill           < get_array_underlying_type(array) > (array, begin, end, value )
 | 
						|
#define array_free(array)                                  array_free           < get_array_underlying_type(array) > (& array )
 | 
						|
#define arary_grow(array, min_capacity)                    arary_grow           < get_array_underlying_type(array) > (& array, min_capacity)
 | 
						|
#define array_num(array)                                   array_num            < get_array_underlying_type(array) > (array )
 | 
						|
#define arary_pop(array)                                   arary_pop            < get_array_underlying_type(array) > (array )
 | 
						|
#define arary_remove_at(array, idx)                        arary_remove_at      < get_array_underlying_type(array) > (idx)
 | 
						|
#define arary_reserve(array, new_capacity)                 arary_reserve        < get_array_underlying_type(array) > (& array, new_capacity )
 | 
						|
#define arary_resize(array, num)                           arary_resize         < get_array_underlying_type(array) > (& array, num)
 | 
						|
#define arary_set_capacity(new_capacity)                   arary_set_capacity   < get_array_underlying_type(array) > (& array, new_capacity )
 | 
						|
#define arary_get_header(array)                            arary_get_header     < get_array_underlying_type(array) > (array )
 | 
						|
 | 
						|
#pragma endregion Array
 | 
						|
 | 
						|
#pragma region HashTable
 | 
						|
#define HashTable(Type) HashTable<Type>
 | 
						|
 | 
						|
template<class Type> struct HashTable;
 | 
						|
 | 
						|
#ifndef get_hashtable_underlying_type
 | 
						|
#define get_hashtable_underlying_type(table) typename TRemovePtr<typeof(table)>:: DataType
 | 
						|
#endif
 | 
						|
 | 
						|
struct HashTableFindResult {
 | 
						|
	ssize HashIndex;
 | 
						|
	ssize PrevIndex;
 | 
						|
	ssize EntryIndex;
 | 
						|
};
 | 
						|
 | 
						|
template<class Type>
 | 
						|
struct HashTableEntry {
 | 
						|
	u64   Key;
 | 
						|
	ssize Next;
 | 
						|
	Type  Value;
 | 
						|
};
 | 
						|
 | 
						|
#define HashTableEntry(Type) HashTableEntry<Type>
 | 
						|
 | 
						|
template<class Type> HashTable<Type>       hashtable_init        (AllocatorInfo allocator);
 | 
						|
template<class Type> HashTable<Type>       hashtable_init_reserve(AllocatorInfo allocator, usize num);
 | 
						|
template<class Type> void                  hashtable_clear       (HashTable<Type>  table);
 | 
						|
template<class Type> void                  hashtable_destroy     (HashTable<Type>* table);
 | 
						|
template<class Type> Type*                 hashtable_get         (HashTable<Type>  table, u64 key);
 | 
						|
template<class Type> void                  hashtable_grow        (HashTable<Type>* table);
 | 
						|
template<class Type> void                  hashtable_rehash      (HashTable<Type>* table, ssize new_num);
 | 
						|
template<class Type> void                  hashtable_rehash_fast (HashTable<Type>  table);
 | 
						|
template<class Type> void                  hashtable_remove      (HashTable<Type>  table, u64 key);
 | 
						|
template<class Type> void                  hashtable_remove_entry(HashTable<Type>  table, ssize idx);
 | 
						|
template<class Type> void                  hashtable_set         (HashTable<Type>* table, u64 key, Type value);
 | 
						|
template<class Type> ssize                 hashtable_slot        (HashTable<Type>  table, u64 key);
 | 
						|
template<class Type> void                  hashtable_map         (HashTable<Type>  table, void (*map_proc)(u64 key, Type value));
 | 
						|
template<class Type> void                  hashtable_map_mut     (HashTable<Type>  table, void (*map_proc)(u64 key, Type* value));
 | 
						|
 | 
						|
template<class Type> ssize                 hashtable__add_entry  (HashTable<Type>* table, u64 key);
 | 
						|
template<class Type> HashTableFindResult   hashtable__find       (HashTable<Type>  table, u64 key);
 | 
						|
template<class Type> bool                  hashtable__full       (HashTable<Type>  table);
 | 
						|
 | 
						|
static constexpr f32 HashTable_CriticalLoadScale = 0.7f;
 | 
						|
 | 
						|
template<typename Type>
 | 
						|
struct HashTable
 | 
						|
{
 | 
						|
	Array<ssize>                Hashes;
 | 
						|
	Array<HashTableEntry<Type>> Entries;
 | 
						|
 | 
						|
#if ! GEN_C_LIKE_CPP
 | 
						|
#pragma region Member Mapping
 | 
						|
	forceinline static HashTable init(AllocatorInfo allocator)                    { return	hashtable_init<Type>(allocator); }
 | 
						|
	forceinline static HashTable init_reserve(AllocatorInfo allocator, usize num) { return	hashtable_init_reserve<Type>(allocator, num); }
 | 
						|
 | 
						|
	forceinline void  clear()                           {        clear<Type>(*this); }
 | 
						|
	forceinline void  destroy()                         {        destroy<Type>(*this); }
 | 
						|
	forceinline Type* get(u64 key)                      { return get<Type>(*this, key); }
 | 
						|
	forceinline void  grow()                            {        grow<Type>(*this); }
 | 
						|
	forceinline void  rehash(ssize new_num)             {        rehash<Type>(*this, new_num); }
 | 
						|
	forceinline void  rehash_fast()                     {        rehash_fast<Type>(*this); }
 | 
						|
	forceinline void  remove(u64 key)                   {        remove<Type>(*this, key); }
 | 
						|
	forceinline void  remove_entry(ssize idx)           {        remove_entry<Type>(*this, idx); }
 | 
						|
	forceinline void  set(u64 key, Type value)          {        set<Type>(*this, key, value); }
 | 
						|
	forceinline ssize slot(u64 key)                     { return slot<Type>(*this, key); }
 | 
						|
	forceinline void  map(void (*proc)(u64, Type))      {        map<Type>(*this, proc); }
 | 
						|
	forceinline void  map_mut(void (*proc)(u64, Type*)) {        map_mut<Type>(*this, proc); }
 | 
						|
#pragma endregion Member Mapping
 | 
						|
#endif
 | 
						|
 | 
						|
	using DataType = Type;
 | 
						|
};
 | 
						|
 | 
						|
#if GEN_SUPPORT_CPP_REFERENCES
 | 
						|
template<class Type> void  destroy  (HashTable<Type>& table)                      { destroy(& table); }
 | 
						|
template<class Type> void  grow     (HashTable<Type>& table)                      { grow(& table); }
 | 
						|
template<class Type> void  rehash   (HashTable<Type>& table, ssize new_num)       { rehash(& table, new_num); }
 | 
						|
template<class Type> void  set      (HashTable<Type>& table, u64 key, Type value) { set(& table, key, value); }
 | 
						|
template<class Type> ssize add_entry(HashTable<Type>& table, u64 key)             { add_entry(& table, key); }
 | 
						|
#endif
 | 
						|
 | 
						|
template<typename Type> inline
 | 
						|
HashTable<Type> hashtable_init(AllocatorInfo allocator) {
 | 
						|
	HashTable<Type> result = hashtable_init_reserve<Type>(allocator, 8);
 | 
						|
	return result;
 | 
						|
}
 | 
						|
 | 
						|
template<typename Type> inline
 | 
						|
HashTable<Type> hashtable_init_reserve(AllocatorInfo allocator, usize num)
 | 
						|
{
 | 
						|
	HashTable<Type> result = { { nullptr }, { nullptr } };
 | 
						|
 | 
						|
	result.Hashes = array_init_reserve<ssize>(allocator, num);
 | 
						|
	array_get_header(result.Hashes)->Num = num;
 | 
						|
	array_resize(& result.Hashes, num);
 | 
						|
	array_fill(result.Hashes, 0, num, (ssize)-1);
 | 
						|
 | 
						|
	result.Entries = array_init_reserve<HashTableEntry<Type>>(allocator, num);
 | 
						|
	return result;
 | 
						|
}
 | 
						|
 | 
						|
template<typename Type> forceinline
 | 
						|
void hashtable_clear(HashTable<Type> table) {
 | 
						|
	GEN_ASSERT_NOT_NULL(table.Hashes);
 | 
						|
	GEN_ASSERT_NOT_NULL(table.Entries);
 | 
						|
	array_clear(table.Entries);
 | 
						|
	array_fill(table.Hashes, 0, array_num(table.Hashes), (ssize)-1);
 | 
						|
}
 | 
						|
 | 
						|
template<typename Type> forceinline
 | 
						|
void hashtable_destroy(HashTable<Type>* table) {
 | 
						|
	GEN_ASSERT_NOT_NULL(table->Hashes);
 | 
						|
	GEN_ASSERT_NOT_NULL(table->Entries);
 | 
						|
	if (table->Hashes && array_get_header(table->Hashes)->Capacity) {
 | 
						|
		array_free(table->Hashes);
 | 
						|
		array_free(table->Entries);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
template<typename Type> forceinline
 | 
						|
Type* hashtable_get(HashTable<Type> table, u64 key) {
 | 
						|
	GEN_ASSERT_NOT_NULL(table.Hashes);
 | 
						|
	GEN_ASSERT_NOT_NULL(table.Entries);
 | 
						|
	ssize idx = hashtable__find(table, key).EntryIndex;
 | 
						|
	if (idx >= 0)
 | 
						|
		return & table.Entries[idx].Value;
 | 
						|
 | 
						|
	return nullptr;
 | 
						|
}
 | 
						|
 | 
						|
template<typename Type> forceinline
 | 
						|
void hashtable_map(HashTable<Type> table, void (*map_proc)(u64 key, Type value)) {
 | 
						|
	GEN_ASSERT_NOT_NULL(table.Hashes);
 | 
						|
	GEN_ASSERT_NOT_NULL(table.Entries);
 | 
						|
	GEN_ASSERT_NOT_NULL(map_proc);
 | 
						|
 | 
						|
	for (ssize idx = 0; idx < ssize(num(table.Entries)); ++idx) {
 | 
						|
		map_proc(table.Entries[idx].Key, table.Entries[idx].Value);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
template<typename Type> forceinline
 | 
						|
void hashtable_map_mut(HashTable<Type> table, void (*map_proc)(u64 key, Type* value)) {
 | 
						|
	GEN_ASSERT_NOT_NULL(table.Hashes);
 | 
						|
	GEN_ASSERT_NOT_NULL(table.Entries);
 | 
						|
	GEN_ASSERT_NOT_NULL(map_proc);
 | 
						|
 | 
						|
	for (ssize idx = 0; idx < ssize(num(table.Entries)); ++idx) {
 | 
						|
		map_proc(table.Entries[idx].Key, & table.Entries[idx].Value);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
template<typename Type> forceinline
 | 
						|
void hashtable_grow(HashTable<Type>* table) {
 | 
						|
	GEN_ASSERT_NOT_NULL(table);
 | 
						|
	GEN_ASSERT_NOT_NULL(table->Hashes);
 | 
						|
	GEN_ASSERT_NOT_NULL(table->Entries);
 | 
						|
	ssize new_num = array_grow_formula( array_num(table->Entries));
 | 
						|
	hashtable_rehash(table, new_num);
 | 
						|
}
 | 
						|
 | 
						|
template<typename Type> inline
 | 
						|
void hashtable_rehash(HashTable<Type>* table, ssize new_num)
 | 
						|
{
 | 
						|
	GEN_ASSERT_NOT_NULL(table);
 | 
						|
	GEN_ASSERT_NOT_NULL(table->Hashes);
 | 
						|
	GEN_ASSERT_NOT_NULL(table->Entries);
 | 
						|
	ssize last_added_index;
 | 
						|
	HashTable<Type> new_ht = hashtable_init_reserve<Type>( array_get_header(table->Hashes)->Allocator, new_num);
 | 
						|
 | 
						|
	for (ssize idx = 0; idx < ssize( array_num(table->Entries)); ++idx)
 | 
						|
	{
 | 
						|
		HashTableFindResult find_result;
 | 
						|
		HashTableEntry<Type>& entry = table->Entries[idx];
 | 
						|
 | 
						|
		find_result = hashtable__find(new_ht, entry.Key);
 | 
						|
		last_added_index = hashtable__add_entry(& new_ht, 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;
 | 
						|
	}
 | 
						|
 | 
						|
	hashtable_destroy(table);
 | 
						|
	* table = new_ht;
 | 
						|
}
 | 
						|
 | 
						|
template<typename Type> inline
 | 
						|
void hashtable_rehash_fast(HashTable<Type> table)
 | 
						|
{
 | 
						|
	GEN_ASSERT_NOT_NULL(table.Hashes);
 | 
						|
	GEN_ASSERT_NOT_NULL(table.Entries);
 | 
						|
	ssize idx;
 | 
						|
 | 
						|
	for (idx = 0; idx < ssize(num(table.Entries)); idx++)
 | 
						|
		table.Entries[idx].Next = -1;
 | 
						|
 | 
						|
	for (idx = 0; idx < ssize(num(table.Hashes)); idx++)
 | 
						|
		table.Hashes[idx] = -1;
 | 
						|
 | 
						|
	for (idx = 0; idx < ssize(num(table.Entries)); idx++)
 | 
						|
	{
 | 
						|
		HashTableEntry<Type>* entry;
 | 
						|
		HashTableFindResult find_result;
 | 
						|
 | 
						|
		entry = &table.Entries[idx];
 | 
						|
		find_result = find(table, entry->Key);
 | 
						|
 | 
						|
		if (find_result.PrevIndex < 0)
 | 
						|
			table.Hashes[find_result.HashIndex] = idx;
 | 
						|
		else
 | 
						|
			table.Entries[find_result.PrevIndex].Next = idx;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
template<typename Type> forceinline
 | 
						|
void hashtable_remove(HashTable<Type> table, u64 key) {
 | 
						|
	GEN_ASSERT_NOT_NULL(table.Hashes);
 | 
						|
	GEN_ASSERT_NOT_NULL(table.Entries);
 | 
						|
	HashTableFindResult find_result = find(table, key);
 | 
						|
 | 
						|
	if (find_result.EntryIndex >= 0) {
 | 
						|
		remove_at(table.Entries, find_result.EntryIndex);
 | 
						|
		rehash_fast(table);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
template<typename Type> forceinline
 | 
						|
void hashtable_remove_entry(HashTable<Type> table, ssize idx) {
 | 
						|
	GEN_ASSERT_NOT_NULL(table.Hashes);
 | 
						|
	GEN_ASSERT_NOT_NULL(table.Entries);
 | 
						|
	remove_at(table.Entries, idx);
 | 
						|
}
 | 
						|
 | 
						|
template<typename Type> inline
 | 
						|
void hashtable_set(HashTable<Type>* table, u64 key, Type value)
 | 
						|
{
 | 
						|
	GEN_ASSERT_NOT_NULL(table);
 | 
						|
	GEN_ASSERT_NOT_NULL(table->Hashes);
 | 
						|
	GEN_ASSERT_NOT_NULL(table->Entries);
 | 
						|
	ssize idx;
 | 
						|
	HashTableFindResult find_result;
 | 
						|
 | 
						|
	if (hashtable_full(* table))
 | 
						|
		hashtable_grow(table);
 | 
						|
 | 
						|
	find_result = hashtable__find(* table, key);
 | 
						|
	if (find_result.EntryIndex >= 0) {
 | 
						|
		idx = find_result.EntryIndex;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		idx = hashtable__add_entry(table, key);
 | 
						|
 | 
						|
		if (find_result.PrevIndex >= 0) {
 | 
						|
			table->Entries[find_result.PrevIndex].Next = idx;
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			table->Hashes[find_result.HashIndex] = idx;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	table->Entries[idx].Value = value;
 | 
						|
 | 
						|
	if (hashtable_full(* table))
 | 
						|
		hashtable_grow(table);
 | 
						|
}
 | 
						|
 | 
						|
template<typename Type> forceinline
 | 
						|
ssize hashtable_slot(HashTable<Type> table, u64 key) {
 | 
						|
	GEN_ASSERT_NOT_NULL(table.Hashes);
 | 
						|
	GEN_ASSERT_NOT_NULL(table.Entries);
 | 
						|
	for (ssize idx = 0; idx < ssize(num(table.Hashes)); ++idx)
 | 
						|
		if (table.Hashes[idx] == key)
 | 
						|
			return idx;
 | 
						|
 | 
						|
	return -1;
 | 
						|
}
 | 
						|
 | 
						|
template<typename Type> forceinline
 | 
						|
ssize hashtable__add_entry(HashTable<Type>* table, u64 key) {
 | 
						|
	GEN_ASSERT_NOT_NULL(table);
 | 
						|
	GEN_ASSERT_NOT_NULL(table->Hashes);
 | 
						|
	GEN_ASSERT_NOT_NULL(table->Entries);
 | 
						|
	ssize idx;
 | 
						|
	HashTableEntry<Type> entry = { key, -1 };
 | 
						|
 | 
						|
	idx = array_num(table->Entries);
 | 
						|
	array_append( table->Entries, entry);
 | 
						|
	return idx;
 | 
						|
}
 | 
						|
 | 
						|
template<typename Type> inline
 | 
						|
HashTableFindResult hashtable__find(HashTable<Type> table, u64 key)
 | 
						|
{
 | 
						|
	GEN_ASSERT_NOT_NULL(table.Hashes);
 | 
						|
	GEN_ASSERT_NOT_NULL(table.Entries);
 | 
						|
	HashTableFindResult result = { -1, -1, -1 };
 | 
						|
 | 
						|
	if (array_num(table.Hashes) > 0)
 | 
						|
	{
 | 
						|
		result.HashIndex = key % array_num(table.Hashes);
 | 
						|
		result.EntryIndex = table.Hashes[result.HashIndex];
 | 
						|
 | 
						|
		while (result.EntryIndex >= 0)
 | 
						|
		{
 | 
						|
			if (table.Entries[result.EntryIndex].Key == key)
 | 
						|
				break;
 | 
						|
 | 
						|
			result.PrevIndex  = result.EntryIndex;
 | 
						|
			result.EntryIndex = table.Entries[result.EntryIndex].Next;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return result;
 | 
						|
}
 | 
						|
 | 
						|
template<typename Type> forceinline
 | 
						|
b32 hashtable_full(HashTable<Type> table) {
 | 
						|
	GEN_ASSERT_NOT_NULL(table.Hashes);
 | 
						|
	GEN_ASSERT_NOT_NULL(table.Entries);
 | 
						|
	usize critical_load = usize(HashTable_CriticalLoadScale * f32(array_num(table.Hashes)));
 | 
						|
	b32 result = array_num(table.Entries) > critical_load;
 | 
						|
	return result;
 | 
						|
}
 | 
						|
 | 
						|
#define hashtable_init(type, allocator)              hashtable_init        <type              >(allocator)
 | 
						|
#define hashtable_init_reserve(type, allocator, num) hashtable_init_reserve<type              >(allocator, num)
 | 
						|
#define hashtable_clear(table)                       hashtable_clear       < get_hashtable_underlying_type(table) >(table)
 | 
						|
#define hashtable_destroy(table)                     hashtable_destroy     < get_hashtable_underlying_type(table) >(& table)
 | 
						|
#define hashtable_get(table, key)                    hashtable_get         < get_hashtable_underlying_type(table) >(table, key)
 | 
						|
#define hashtable_grow(table)                        hashtable_grow        < get_hashtable_underlying_type(table) >(& table)
 | 
						|
#define hashtable_rehash(table, new_num)             hashtable_rehash      < get_hashtable_underlying_type(table) >(& table, new_num)
 | 
						|
#define hashtable_rehash_fast(table)                 hashtable_rehash_fast < get_hashtable_underlying_type(table) >(table)
 | 
						|
#define hashtable_remove(table, key)                 hashtable_remove      < get_hashtable_underlying_type(table) >(table, key)
 | 
						|
#define hashtable_remove_entry(table, idx)           hashtable_remove_entry< get_hashtable_underlying_type(table) >(table, idx)
 | 
						|
#define hashtable_set(table, key, value)             hashtable_set         < get_hashtable_underlying_type(table) >(& table, key, value)
 | 
						|
#define hashtable_slot(table, key)                   hashtable_slot        < get_hashtable_underlying_type(table) >(table, key)
 | 
						|
#define hashtable_map(table, map_proc)               hashtable_map         < get_hashtable_underlying_type(table) >(table, map_proc)
 | 
						|
#define hashtable_map_mut(table, map_proc)           hashtable_map_mut     < get_hashtable_underlying_type(table) >(table, map_proc)
 | 
						|
 | 
						|
//#define hashtable_add_entry(table, key)              hashtable_add_entry   < get_hashtable_underlying_type(table) >(& table, key)
 | 
						|
//#define hashtable_find(table, key)                   hashtable_find        < get_hashtable_underlying_type(table) >(table, key)
 | 
						|
//#define hashtable_full(table)                        hashtable_full        < get_hashtable_underlying_type(table) >(table)
 | 
						|
 | 
						|
#pragma endregion HashTable
 | 
						|
 | 
						|
#pragma endregion Containers
 |