2023-04-01 19:21:46 -07:00
|
|
|
#define BLOAT_IMPL
|
2023-04-01 22:07:44 -07:00
|
|
|
#include "Bloat.hpp"
|
2023-04-01 19:21:46 -07:00
|
|
|
|
2023-04-03 23:04:19 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
namespace gen
|
2023-07-10 19:14:41 -07:00
|
|
|
{
|
2023-07-11 15:29:45 -07:00
|
|
|
#pragma region Memory
|
2023-07-10 19:14:41 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
struct _heap_stats
|
|
|
|
{
|
|
|
|
u32 magic;
|
|
|
|
sw used_memory;
|
|
|
|
sw alloc_count;
|
|
|
|
};
|
|
|
|
|
|
|
|
global _heap_stats _heap_stats_info;
|
2023-07-10 19:14:41 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
void heap_stats_init( void )
|
2023-07-10 19:14:41 -07:00
|
|
|
{
|
2023-07-11 15:29:45 -07:00
|
|
|
zero_item( &_heap_stats_info );
|
|
|
|
_heap_stats_info.magic = ZPL_HEAP_STATS_MAGIC;
|
|
|
|
}
|
|
|
|
|
|
|
|
sw heap_stats_used_memory( void )
|
|
|
|
{
|
|
|
|
ZPL_ASSERT_MSG( _heap_stats_info.magic == ZPL_HEAP_STATS_MAGIC, "heap_stats is not initialised yet, call heap_stats_init first!" );
|
|
|
|
return _heap_stats_info.used_memory;
|
|
|
|
}
|
|
|
|
|
|
|
|
sw heap_stats_alloc_count( void )
|
|
|
|
{
|
|
|
|
ZPL_ASSERT_MSG( _heap_stats_info.magic == ZPL_HEAP_STATS_MAGIC, "heap_stats is not initialised yet, call heap_stats_init first!" );
|
|
|
|
return _heap_stats_info.alloc_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
void heap_stats_check( void )
|
|
|
|
{
|
|
|
|
ZPL_ASSERT_MSG( _heap_stats_info.magic == ZPL_HEAP_STATS_MAGIC, "heap_stats is not initialised yet, call heap_stats_init first!" );
|
|
|
|
ZPL_ASSERT( _heap_stats_info.used_memory == 0 );
|
|
|
|
ZPL_ASSERT( _heap_stats_info.alloc_count == 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
struct _heap_alloc_info
|
|
|
|
{
|
|
|
|
sw size;
|
|
|
|
void* physical_start;
|
|
|
|
};
|
|
|
|
|
|
|
|
void* heap_allocator_proc( void* allocator_data, AllocType type, sw size, sw alignment, void* old_memory, sw old_size, u64 flags )
|
|
|
|
{
|
|
|
|
return zpl::heap_allocator_proc( allocator_data, (zpl::AllocType)type, size, alignment, old_memory, old_size, flags );
|
|
|
|
|
|
|
|
// void* ptr = NULL;
|
|
|
|
// // unused( allocator_data );
|
|
|
|
// // unused( old_size );
|
|
|
|
// if ( ! alignment )
|
|
|
|
// alignment = ZPL_DEFAULT_MEMORY_ALIGNMENT;
|
|
|
|
|
|
|
|
// #ifdef ZPL_HEAP_ANALYSIS
|
|
|
|
// sw alloc_info_size = size_of( _heap_alloc_info );
|
|
|
|
// sw alloc_info_remainder = ( alloc_info_size % alignment );
|
|
|
|
// sw track_size = max( alloc_info_size, alignment ) + alloc_info_remainder;
|
|
|
|
// switch ( type )
|
|
|
|
// {
|
|
|
|
// case EAllocation_FREE :
|
|
|
|
// {
|
|
|
|
// if ( ! old_memory )
|
|
|
|
// break;
|
|
|
|
// _heap_alloc_info* alloc_info = zpl_cast( _heap_alloc_info* ) old_memory - 1;
|
|
|
|
// _heap_stats_info.used_memory -= alloc_info->size;
|
|
|
|
// _heap_stats_info.alloc_count--;
|
|
|
|
// old_memory = alloc_info->physical_start;
|
|
|
|
// }
|
|
|
|
// break;
|
|
|
|
// case EAllocation_ALLOC :
|
|
|
|
// {
|
|
|
|
// size += track_size;
|
|
|
|
// }
|
|
|
|
// break;
|
|
|
|
// default :
|
|
|
|
// break;
|
|
|
|
// }
|
|
|
|
// #endif
|
|
|
|
|
|
|
|
// switch ( type )
|
|
|
|
// {
|
|
|
|
// #if defined( ZPL_COMPILER_MSVC ) || ( defined( ZPL_COMPILER_GCC ) && defined( ZPL_SYSTEM_WINDOWS ) ) || ( defined( ZPL_COMPILER_TINYC ) && defined( ZPL_SYSTEM_WINDOWS ) )
|
|
|
|
// case EAllocation_ALLOC :
|
|
|
|
// ptr = _aligned_malloc( size, alignment );
|
|
|
|
// if ( flags & ALLOCATOR_FLAG_CLEAR_TO_ZERO )
|
|
|
|
// zero_size( ptr, size );
|
|
|
|
// break;
|
|
|
|
// case EAllocation_FREE :
|
|
|
|
// _aligned_free( old_memory );
|
|
|
|
// break;
|
|
|
|
// case EAllocation_RESIZE :
|
|
|
|
// {
|
|
|
|
// AllocatorInfo a = heap();
|
|
|
|
// ptr = default_resize_align( a, old_memory, old_size, size, alignment );
|
|
|
|
// }
|
|
|
|
// break;
|
|
|
|
|
|
|
|
// #elif defined( ZPL_SYSTEM_LINUX ) && ! defined( ZPL_CPU_ARM ) && ! defined( ZPL_COMPILER_TINYC )
|
|
|
|
// case EAllocation_ALLOC :
|
|
|
|
// {
|
|
|
|
// ptr = aligned_alloc( alignment, ( size + alignment - 1 ) & ~( alignment - 1 ) );
|
|
|
|
|
|
|
|
// if ( flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO )
|
|
|
|
// {
|
|
|
|
// zero_size( ptr, size );
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// break;
|
|
|
|
|
|
|
|
// case EAllocation_FREE :
|
|
|
|
// {
|
|
|
|
// free( old_memory );
|
|
|
|
// }
|
|
|
|
// break;
|
|
|
|
|
|
|
|
// case EAllocation_RESIZE :
|
|
|
|
// {
|
|
|
|
// AllocatorInfo a = heap();
|
|
|
|
// ptr = default_resize_align( a, old_memory, old_size, size, alignment );
|
|
|
|
// }
|
|
|
|
// break;
|
|
|
|
// #else
|
|
|
|
// case EAllocation_ALLOC :
|
|
|
|
// {
|
|
|
|
// posix_memalign( &ptr, alignment, size );
|
|
|
|
|
|
|
|
// if ( flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO )
|
|
|
|
// {
|
|
|
|
// zero_size( ptr, size );
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// break;
|
|
|
|
|
|
|
|
// case EAllocation_FREE :
|
|
|
|
// {
|
|
|
|
// free( old_memory );
|
|
|
|
// }
|
|
|
|
// break;
|
|
|
|
|
|
|
|
// case EAllocation_RESIZE :
|
|
|
|
// {
|
|
|
|
// AllocatorInfo a = heap();
|
|
|
|
// ptr = default_resize_align( a, old_memory, old_size, size, alignment );
|
|
|
|
// }
|
|
|
|
// break;
|
|
|
|
// #endif
|
|
|
|
|
|
|
|
// case EAllocation_FREE_ALL :
|
|
|
|
// break;
|
|
|
|
// }
|
|
|
|
|
|
|
|
// #ifdef ZPL_HEAP_ANALYSIS
|
|
|
|
// if ( type == EAllocation_ALLOC )
|
|
|
|
// {
|
|
|
|
// _heap_alloc_info* alloc_info = zpl_cast( _heap_alloc_info* )( zpl_cast( char* ) ptr + alloc_info_remainder );
|
|
|
|
// zero_item( alloc_info );
|
|
|
|
// alloc_info->size = size - track_size;
|
|
|
|
// alloc_info->physical_start = ptr;
|
|
|
|
// ptr = zpl_cast( void* )( alloc_info + 1 );
|
|
|
|
// _heap_stats_info.used_memory += alloc_info->size;
|
|
|
|
// _heap_stats_info.alloc_count++;
|
|
|
|
// }
|
|
|
|
// #endif
|
|
|
|
|
|
|
|
// return ptr;
|
|
|
|
}
|
2023-07-10 19:14:41 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
void* Arena::allocator_proc( void* allocator_data, AllocType type, sw size, sw alignment, void* old_memory, sw old_size, u64 flags )
|
|
|
|
{
|
|
|
|
Arena* arena = rcast(Arena*, allocator_data);
|
|
|
|
void* ptr = NULL;
|
|
|
|
|
|
|
|
// unused( old_size );
|
|
|
|
|
|
|
|
switch ( type )
|
|
|
|
{
|
|
|
|
case EAllocation_ALLOC :
|
2023-07-10 19:14:41 -07:00
|
|
|
{
|
2023-07-11 15:29:45 -07:00
|
|
|
void* end = pointer_add( arena->PhysicalStart, arena->TotalUsed );
|
|
|
|
sw total_size = align_forward_i64( size, alignment );
|
|
|
|
|
|
|
|
// NOTE: Out of memory
|
|
|
|
if ( arena->TotalUsed + total_size > (sw) arena->TotalSize )
|
|
|
|
{
|
|
|
|
// zpl__printf_err("%s", "Arena out of memory\n");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr = align_forward( end, alignment );
|
|
|
|
arena->TotalUsed += total_size;
|
|
|
|
|
|
|
|
if ( flags & ALLOCATOR_FLAG_CLEAR_TO_ZERO )
|
|
|
|
zero_size( ptr, size );
|
2023-07-10 19:14:41 -07:00
|
|
|
}
|
2023-07-11 15:29:45 -07:00
|
|
|
break;
|
2023-07-10 19:14:41 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
case EAllocation_FREE :
|
|
|
|
// NOTE: Free all at once
|
|
|
|
// Use Temp_Arena_Memory if you want to free a block
|
|
|
|
break;
|
2023-07-10 19:14:41 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
case EAllocation_FREE_ALL :
|
|
|
|
arena->TotalUsed = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case EAllocation_RESIZE :
|
|
|
|
{
|
|
|
|
// TODO : Check if ptr is on top of stack and just extend
|
|
|
|
AllocatorInfo a = arena->Backing;
|
|
|
|
ptr = default_resize_align( a, old_memory, old_size, size, alignment );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return ptr;
|
|
|
|
}
|
2023-07-10 19:14:41 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
void* Pool::allocator_proc( void* allocator_data, AllocType type, sw size, sw alignment, void* old_memory, sw old_size, u64 flags )
|
|
|
|
{
|
|
|
|
Pool* pool = zpl_cast( Pool* ) allocator_data;
|
|
|
|
void* ptr = NULL;
|
2023-07-10 19:14:41 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
// unused( old_size );
|
2023-07-10 19:14:41 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
switch ( type )
|
|
|
|
{
|
|
|
|
case EAllocation_ALLOC :
|
|
|
|
{
|
|
|
|
uptr next_free;
|
|
|
|
|
|
|
|
ZPL_ASSERT( size == pool->BlockSize );
|
|
|
|
ZPL_ASSERT( alignment == pool->BlockAlign );
|
|
|
|
ZPL_ASSERT( pool->FreeList != NULL );
|
|
|
|
|
|
|
|
next_free = *zpl_cast( uptr* ) pool->FreeList;
|
|
|
|
ptr = pool->FreeList;
|
|
|
|
pool->FreeList = zpl_cast( void* ) next_free;
|
|
|
|
pool->TotalSize += pool->BlockSize;
|
|
|
|
|
|
|
|
if ( flags & ALLOCATOR_FLAG_CLEAR_TO_ZERO )
|
|
|
|
zero_size( ptr, size );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case EAllocation_FREE :
|
|
|
|
{
|
|
|
|
uptr* next;
|
|
|
|
if ( old_memory == NULL )
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
next = zpl_cast( uptr* ) old_memory;
|
|
|
|
*next = zpl_cast( uptr ) pool->FreeList;
|
|
|
|
pool->FreeList = old_memory;
|
|
|
|
pool->TotalSize -= pool->BlockSize;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case EAllocation_FREE_ALL :
|
|
|
|
{
|
|
|
|
sw actual_block_size, block_index;
|
|
|
|
void* curr;
|
|
|
|
uptr* end;
|
|
|
|
|
|
|
|
actual_block_size = pool->BlockSize + pool->BlockAlign;
|
|
|
|
pool->TotalSize = 0;
|
|
|
|
|
|
|
|
// NOTE: Init intrusive freelist
|
|
|
|
curr = pool->PhysicalStart;
|
|
|
|
for ( block_index = 0; block_index < pool->NumBlocks - 1; block_index++ )
|
|
|
|
{
|
|
|
|
uptr* next = zpl_cast( uptr* ) curr;
|
|
|
|
*next = zpl_cast( uptr ) curr + actual_block_size;
|
|
|
|
curr = pointer_add( curr, actual_block_size );
|
|
|
|
}
|
|
|
|
|
|
|
|
end = zpl_cast( uptr* ) curr;
|
|
|
|
*end = zpl_cast( uptr ) NULL;
|
|
|
|
pool->FreeList = pool->PhysicalStart;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case EAllocation_RESIZE :
|
|
|
|
// NOTE: Cannot resize
|
|
|
|
ZPL_PANIC( "You cannot resize something allocated by with a pool." );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ptr;
|
2023-07-10 19:14:41 -07:00
|
|
|
}
|
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
Pool Pool::init_align( AllocatorInfo backing, sw num_blocks, sw block_size, sw block_align )
|
|
|
|
{
|
|
|
|
Pool pool = {};
|
|
|
|
|
|
|
|
sw actual_block_size, pool_size, block_index;
|
|
|
|
void *data, *curr;
|
|
|
|
uptr* end;
|
|
|
|
|
|
|
|
pool.Backing = backing;
|
|
|
|
pool.BlockSize = block_size;
|
|
|
|
pool.BlockAlign = block_align;
|
|
|
|
pool.NumBlocks = num_blocks;
|
|
|
|
|
|
|
|
actual_block_size = block_size + block_align;
|
|
|
|
pool_size = num_blocks * actual_block_size;
|
|
|
|
|
|
|
|
data = alloc_align( backing, pool_size, block_align );
|
|
|
|
|
|
|
|
// NOTE: Init intrusive freelist
|
|
|
|
curr = data;
|
|
|
|
for ( block_index = 0; block_index < num_blocks - 1; block_index++ )
|
|
|
|
{
|
|
|
|
uptr* next = ( uptr* ) curr;
|
|
|
|
*next = ( uptr ) curr + actual_block_size;
|
|
|
|
curr = pointer_add( curr, actual_block_size );
|
|
|
|
}
|
|
|
|
|
|
|
|
end = ( uptr* ) curr;
|
|
|
|
*end = ( uptr ) 0;
|
|
|
|
|
|
|
|
pool.PhysicalStart = data;
|
|
|
|
pool.FreeList = data;
|
|
|
|
|
|
|
|
return pool;
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma endregion Memory
|
2023-07-10 19:14:41 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
#pragma region File Handling
|
2023-07-10 19:14:41 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
#if defined( ZPL_SYSTEM_WINDOWS ) || defined( ZPL_SYSTEM_CYGWIN )
|
|
|
|
|
|
|
|
internal wchar_t* _alloc_utf8_to_ucs2( AllocatorInfo a, char const* text, sw* w_len_ )
|
2023-07-10 19:14:41 -07:00
|
|
|
{
|
2023-07-11 15:29:45 -07:00
|
|
|
wchar_t* w_text = NULL;
|
|
|
|
sw len = 0, w_len = 0, w_len1 = 0;
|
|
|
|
if ( text == NULL )
|
|
|
|
{
|
|
|
|
if ( w_len_ )
|
|
|
|
*w_len_ = w_len;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
len = str_len( text );
|
|
|
|
if ( len == 0 )
|
|
|
|
{
|
|
|
|
if ( w_len_ )
|
|
|
|
*w_len_ = w_len;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
w_len = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, text, zpl_cast( int ) len, NULL, 0 );
|
|
|
|
if ( w_len == 0 )
|
|
|
|
{
|
|
|
|
if ( w_len_ )
|
|
|
|
*w_len_ = w_len;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
w_text = alloc_array( a, wchar_t, w_len + 1 );
|
|
|
|
w_len1 = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, text, zpl_cast( int ) len, w_text, zpl_cast( int ) w_len );
|
|
|
|
if ( w_len1 == 0 )
|
|
|
|
{
|
|
|
|
free( a, w_text );
|
|
|
|
if ( w_len_ )
|
|
|
|
*w_len_ = 0;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
w_text[ w_len ] = 0;
|
|
|
|
if ( w_len_ )
|
|
|
|
*w_len_ = w_len;
|
|
|
|
return w_text;
|
|
|
|
}
|
2023-07-10 19:14:41 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
internal ZPL_FILE_SEEK_PROC( _win32_file_seek )
|
|
|
|
{
|
|
|
|
LARGE_INTEGER li_offset;
|
|
|
|
li_offset.QuadPart = offset;
|
|
|
|
if ( ! SetFilePointerEx( fd.p, li_offset, &li_offset, whence ) )
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2023-07-10 19:14:41 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
if ( new_offset )
|
|
|
|
*new_offset = li_offset.QuadPart;
|
|
|
|
return true;
|
|
|
|
}
|
2023-07-10 19:14:41 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
internal ZPL_FILE_READ_AT_PROC( _win32_file_read )
|
|
|
|
{
|
|
|
|
// unused( stop_at_newline );
|
|
|
|
b32 result = false;
|
|
|
|
_win32_file_seek( fd, offset, ESeekWhence_BEGIN, NULL );
|
|
|
|
DWORD size_ = zpl_cast( DWORD )( size > ZPL_I32_MAX ? ZPL_I32_MAX : size );
|
|
|
|
DWORD bytes_read_;
|
|
|
|
if ( ReadFile( fd.p, buffer, size_, &bytes_read_, NULL ) )
|
|
|
|
{
|
|
|
|
if ( bytes_read )
|
|
|
|
*bytes_read = bytes_read_;
|
|
|
|
result = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal ZPL_FILE_WRITE_AT_PROC( _win32_file_write )
|
|
|
|
{
|
|
|
|
DWORD size_ = zpl_cast( DWORD )( size > ZPL_I32_MAX ? ZPL_I32_MAX : size );
|
|
|
|
DWORD bytes_written_;
|
|
|
|
_win32_file_seek( fd, offset, ESeekWhence_BEGIN, NULL );
|
|
|
|
if ( WriteFile( fd.p, buffer, size_, &bytes_written_, NULL ) )
|
|
|
|
{
|
|
|
|
if ( bytes_written )
|
|
|
|
*bytes_written = bytes_written_;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal ZPL_FILE_CLOSE_PROC( _win32_file_close )
|
|
|
|
{
|
|
|
|
CloseHandle( fd.p );
|
|
|
|
}
|
2023-07-10 19:14:41 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
FileOperations const default_file_operations = { _win32_file_read, _win32_file_write, _win32_file_seek, _win32_file_close };
|
|
|
|
|
|
|
|
ZPL_NEVER_INLINE ZPL_FILE_OPEN_PROC( _win32_file_open )
|
|
|
|
{
|
|
|
|
DWORD desired_access;
|
|
|
|
DWORD creation_disposition;
|
|
|
|
void* handle;
|
|
|
|
wchar_t* w_text;
|
|
|
|
|
|
|
|
switch ( mode & ZPL_FILE_MODES )
|
|
|
|
{
|
|
|
|
case EFileMode_READ :
|
|
|
|
desired_access = GENERIC_READ;
|
|
|
|
creation_disposition = OPEN_EXISTING;
|
|
|
|
break;
|
|
|
|
case EFileMode_WRITE :
|
|
|
|
desired_access = GENERIC_WRITE;
|
|
|
|
creation_disposition = CREATE_ALWAYS;
|
|
|
|
break;
|
|
|
|
case EFileMode_APPEND :
|
|
|
|
desired_access = GENERIC_WRITE;
|
|
|
|
creation_disposition = OPEN_ALWAYS;
|
|
|
|
break;
|
|
|
|
case EFileMode_READ | EFileMode_RW :
|
|
|
|
desired_access = GENERIC_READ | GENERIC_WRITE;
|
|
|
|
creation_disposition = OPEN_EXISTING;
|
|
|
|
break;
|
|
|
|
case EFileMode_WRITE | EFileMode_RW :
|
|
|
|
desired_access = GENERIC_READ | GENERIC_WRITE;
|
|
|
|
creation_disposition = CREATE_ALWAYS;
|
|
|
|
break;
|
|
|
|
case EFileMode_APPEND | EFileMode_RW :
|
|
|
|
desired_access = GENERIC_READ | GENERIC_WRITE;
|
|
|
|
creation_disposition = OPEN_ALWAYS;
|
|
|
|
break;
|
|
|
|
default :
|
|
|
|
ZPL_PANIC( "Invalid file mode" );
|
|
|
|
return EFileError_INVALID;
|
|
|
|
}
|
|
|
|
|
|
|
|
w_text = _alloc_utf8_to_ucs2( heap(), filename, NULL );
|
|
|
|
handle = CreateFileW( w_text, desired_access, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, creation_disposition, FILE_ATTRIBUTE_NORMAL, NULL );
|
|
|
|
|
|
|
|
free( heap(), w_text );
|
|
|
|
|
|
|
|
if ( handle == INVALID_HANDLE_VALUE )
|
|
|
|
{
|
|
|
|
DWORD err = GetLastError();
|
|
|
|
switch ( err )
|
2023-07-10 19:14:41 -07:00
|
|
|
{
|
2023-07-11 15:29:45 -07:00
|
|
|
case ERROR_FILE_NOT_FOUND :
|
|
|
|
return EFileError_NOT_EXISTS;
|
|
|
|
case ERROR_FILE_EXISTS :
|
|
|
|
return EFileError_EXISTS;
|
|
|
|
case ERROR_ALREADY_EXISTS :
|
|
|
|
return EFileError_EXISTS;
|
|
|
|
case ERROR_ACCESS_DENIED :
|
|
|
|
return EFileError_PERMISSION;
|
2023-07-10 19:14:41 -07:00
|
|
|
}
|
2023-07-11 15:29:45 -07:00
|
|
|
return EFileError_INVALID;
|
|
|
|
}
|
2023-07-10 19:14:41 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
if ( mode & EFileMode_APPEND )
|
|
|
|
{
|
|
|
|
LARGE_INTEGER offset = { { 0 } };
|
|
|
|
if ( ! SetFilePointerEx( handle, offset, NULL, ESeekWhence_END ) )
|
2023-07-10 19:14:41 -07:00
|
|
|
{
|
2023-07-11 15:29:45 -07:00
|
|
|
CloseHandle( handle );
|
|
|
|
return EFileError_INVALID;
|
|
|
|
}
|
|
|
|
}
|
2023-07-10 19:14:41 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
fd->p = handle;
|
|
|
|
*ops = default_file_operations;
|
|
|
|
return EFileError_NONE;
|
|
|
|
}
|
2023-07-10 19:14:41 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
#else // POSIX
|
|
|
|
# include <fcntl.h>
|
2023-07-10 19:14:41 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
internal ZPL_FILE_SEEK_PROC( _posix_file_seek )
|
|
|
|
{
|
|
|
|
# if defined( ZPL_SYSTEM_OSX )
|
|
|
|
s64 res = lseek( fd.i, offset, whence );
|
|
|
|
# else // TODO(ZaKlaus): @fixme lseek64
|
|
|
|
s64 res = lseek( fd.i, offset, whence );
|
|
|
|
# endif
|
|
|
|
if ( res < 0 )
|
|
|
|
return false;
|
|
|
|
if ( new_offset )
|
|
|
|
*new_offset = res;
|
|
|
|
return true;
|
|
|
|
}
|
2023-07-10 19:14:41 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
internal ZPL_FILE_READ_AT_PROC( _posix_file_read )
|
|
|
|
{
|
|
|
|
unused( stop_at_newline );
|
|
|
|
sw res = pread( fd.i, buffer, size, offset );
|
|
|
|
if ( res < 0 )
|
|
|
|
return false;
|
|
|
|
if ( bytes_read )
|
|
|
|
*bytes_read = res;
|
|
|
|
return true;
|
2023-07-10 19:14:41 -07:00
|
|
|
}
|
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
internal ZPL_FILE_WRITE_AT_PROC( _posix_file_write )
|
|
|
|
{
|
|
|
|
sw res;
|
|
|
|
s64 curr_offset = 0;
|
|
|
|
_posix_file_seek( fd, 0, ESeekWhence_CURRENT, &curr_offset );
|
|
|
|
if ( curr_offset == offset )
|
|
|
|
{
|
|
|
|
// NOTE: Writing to stdout et al. doesn't like pwrite for numerous reasons
|
|
|
|
res = write( zpl_cast( int ) fd.i, buffer, size );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
res = pwrite( zpl_cast( int ) fd.i, buffer, size, offset );
|
|
|
|
}
|
|
|
|
if ( res < 0 )
|
|
|
|
return false;
|
|
|
|
if ( bytes_written )
|
|
|
|
*bytes_written = res;
|
|
|
|
return true;
|
|
|
|
}
|
2023-07-10 19:14:41 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
internal ZPL_FILE_CLOSE_PROC( _posix_file_close )
|
|
|
|
{
|
|
|
|
close( fd.i );
|
|
|
|
}
|
|
|
|
|
|
|
|
FileOperations const default_file_operations = { _posix_file_read, _posix_file_write, _posix_file_seek, _posix_file_close };
|
2023-07-10 19:14:41 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
ZPL_NEVER_INLINE ZPL_FILE_OPEN_PROC( _posix_file_open )
|
|
|
|
{
|
|
|
|
s32 os_mode;
|
|
|
|
switch ( mode & ZPL_FILE_MODES )
|
|
|
|
{
|
|
|
|
case EFileMode_READ :
|
|
|
|
os_mode = O_RDONLY;
|
|
|
|
break;
|
|
|
|
case EFileMode_WRITE :
|
|
|
|
os_mode = O_WRONLY | O_CREAT | O_TRUNC;
|
|
|
|
break;
|
|
|
|
case EFileMode_APPEND :
|
|
|
|
os_mode = O_WRONLY | O_APPEND | O_CREAT;
|
|
|
|
break;
|
|
|
|
case EFileMode_READ | EFileMode_RW :
|
|
|
|
os_mode = O_RDWR;
|
|
|
|
break;
|
|
|
|
case EFileMode_WRITE | EFileMode_RW :
|
|
|
|
os_mode = O_RDWR | O_CREAT | O_TRUNC;
|
|
|
|
break;
|
|
|
|
case EFileMode_APPEND | EFileMode_RW :
|
|
|
|
os_mode = O_RDWR | O_APPEND | O_CREAT;
|
|
|
|
break;
|
|
|
|
default :
|
|
|
|
ZPL_PANIC( "Invalid file mode" );
|
|
|
|
return EFileError_INVALID;
|
|
|
|
}
|
2023-07-10 19:14:41 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
fd->i = open( filename, os_mode, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH );
|
|
|
|
if ( fd->i < 0 )
|
|
|
|
{
|
|
|
|
// TODO: More file errors
|
|
|
|
return EFileError_INVALID;
|
|
|
|
}
|
2023-07-10 19:14:41 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
*ops = default_file_operations;
|
|
|
|
return EFileError_NONE;
|
|
|
|
}
|
2023-07-10 19:14:41 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
// POSIX
|
|
|
|
#endif
|
2023-07-10 19:14:41 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
internal void _dirinfo_free_entry( DirEntry* entry );
|
|
|
|
|
|
|
|
FileError file_close( FileInfo* f )
|
2023-07-10 19:14:41 -07:00
|
|
|
{
|
2023-07-11 15:29:45 -07:00
|
|
|
if ( ! f )
|
|
|
|
return EFileError_INVALID;
|
|
|
|
|
|
|
|
if ( f->Filename )
|
|
|
|
free( heap(), zpl_cast( char* ) f->Filename );
|
|
|
|
|
|
|
|
#if defined( ZPL_SYSTEM_WINDOWS )
|
|
|
|
if ( f->FD.p == INVALID_HANDLE_VALUE )
|
|
|
|
return EFileError_INVALID;
|
|
|
|
#else
|
|
|
|
if ( f->fd.i < 0 )
|
|
|
|
return EFileError_INVALID;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if ( f->IsTemp )
|
|
|
|
{
|
|
|
|
f->Ops.close( f->FD );
|
|
|
|
return EFileError_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ! f->Ops.read_at )
|
|
|
|
f->Ops = default_file_operations;
|
|
|
|
f->Ops.close( f->FD );
|
|
|
|
|
|
|
|
if ( f->Dir )
|
|
|
|
{
|
|
|
|
_dirinfo_free_entry( f->Dir );
|
|
|
|
mfree( f->Dir );
|
|
|
|
f->Dir = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return EFileError_NONE;
|
2023-07-10 19:14:41 -07:00
|
|
|
}
|
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
FileError file_new( FileInfo* f, FileDescriptor fd, FileOperations ops, char const* filename )
|
|
|
|
{
|
|
|
|
FileError err = EFileError_NONE;
|
|
|
|
sw len = str_len( filename );
|
2023-07-10 19:14:41 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
f->Ops = ops;
|
|
|
|
f->FD = fd;
|
|
|
|
f->Dir = nullptr;
|
|
|
|
f->LastWriteTime = 0;
|
|
|
|
f->Filename = alloc_array( heap(), char, len + 1 );
|
|
|
|
mem_copy( zpl_cast( char* ) f->Filename, zpl_cast( char* ) filename, len + 1 );
|
2023-07-10 19:14:41 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
return err;
|
|
|
|
}
|
2023-07-10 19:14:41 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
FileError file_open_mode( FileInfo* f, FileMode mode, char const* filename )
|
|
|
|
{
|
|
|
|
FileInfo file_ =
|
|
|
|
{
|
|
|
|
{ nullptr, nullptr, nullptr, nullptr },
|
|
|
|
{ nullptr },
|
|
|
|
0,
|
|
|
|
nullptr,
|
|
|
|
0,
|
|
|
|
nullptr
|
|
|
|
};
|
|
|
|
|
|
|
|
*f = file_;
|
|
|
|
FileError err;
|
|
|
|
|
|
|
|
#if defined( ZPL_SYSTEM_WINDOWS ) || defined( ZPL_SYSTEM_CYGWIN )
|
|
|
|
err = _win32_file_open( &f->FD, &f->Ops, mode, filename );
|
|
|
|
#else
|
|
|
|
err = _posix_file_open( &f->fd, &f->ops, mode, filename );
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if ( err == EFileError_NONE )
|
|
|
|
return file_new( f, f->FD, f->Ops, filename );
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
2023-07-10 19:14:41 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
internal void _dirinfo_free_entry( DirEntry* entry )
|
|
|
|
{
|
|
|
|
if ( entry->Info )
|
|
|
|
{
|
|
|
|
dirinfo_free( entry->Info );
|
|
|
|
mfree( entry->Info );
|
|
|
|
entry->Info = nullptr;
|
|
|
|
}
|
|
|
|
}
|
2023-04-09 10:59:39 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
void dirinfo_free( DirInfo* dir )
|
|
|
|
{
|
|
|
|
ZPL_ASSERT_NOT_NULL( dir );
|
2023-04-05 23:21:23 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
for ( sw i = 0; i < array_count( dir->Entries ); ++i )
|
|
|
|
{
|
|
|
|
_dirinfo_free_entry( dir->Entries + i );
|
|
|
|
}
|
|
|
|
|
|
|
|
array_free( dir->Entries );
|
|
|
|
array_free( dir->Filenames );
|
|
|
|
// string_free( dir->Buffer );
|
|
|
|
dir->Buffer.free();
|
|
|
|
mfree( ( void* )dir->FullPath );
|
|
|
|
}
|
2023-07-09 09:35:48 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
#pragma endreigon File Handling
|
|
|
|
|
|
|
|
namespace Memory
|
2023-04-01 19:21:46 -07:00
|
|
|
{
|
2023-07-11 15:29:45 -07:00
|
|
|
global AllocatorInfo GlobalAllocator;
|
2023-04-01 19:21:46 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
global Array<Arena> Global_AllocatorBuckets;
|
|
|
|
|
|
|
|
void* Global_Allocator_Proc( void* allocator_data, AllocType type, sw size, sw alignment, void* old_memory, sw old_size, u64 flags )
|
2023-04-01 19:21:46 -07:00
|
|
|
{
|
2023-07-11 15:29:45 -07:00
|
|
|
Arena& last = Global_AllocatorBuckets.back();
|
|
|
|
|
|
|
|
switch ( type )
|
2023-07-09 09:35:48 -07:00
|
|
|
{
|
2023-07-11 15:29:45 -07:00
|
|
|
case EAllocation_ALLOC:
|
2023-07-09 09:35:48 -07:00
|
|
|
{
|
2023-07-11 15:29:45 -07:00
|
|
|
if ( last.TotalUsed + size > last.TotalSize )
|
|
|
|
{
|
|
|
|
Arena bucket = Arena::init_from_allocator( heap(), BucketSize );
|
2023-07-09 09:35:48 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
if ( bucket.PhysicalStart == nullptr )
|
|
|
|
fatal( "Failed to create bucket for Global_AllocatorBuckets");
|
2023-07-09 09:35:48 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
if ( ! Global_AllocatorBuckets.append( bucket ) )
|
|
|
|
fatal( "Failed to append bucket to Global_AllocatorBuckets");
|
2023-07-09 09:35:48 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
last = Global_AllocatorBuckets.back();
|
|
|
|
}
|
2023-07-09 09:35:48 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
return alloc_align( last, size, alignment );
|
|
|
|
}
|
|
|
|
case EAllocation_FREE:
|
|
|
|
{
|
|
|
|
// Doesn't recycle.
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case EAllocation_FREE_ALL:
|
2023-07-09 09:35:48 -07:00
|
|
|
{
|
2023-07-11 15:29:45 -07:00
|
|
|
// Memory::cleanup instead.
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case EAllocation_RESIZE:
|
|
|
|
{
|
|
|
|
if ( last.TotalUsed + size > last.TotalSize )
|
|
|
|
{
|
|
|
|
Arena bucket = Arena::init_from_allocator( heap(), BucketSize );
|
2023-07-09 09:35:48 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
if ( bucket.PhysicalStart == nullptr )
|
|
|
|
fatal( "Failed to create bucket for Global_AllocatorBuckets");
|
2023-07-09 09:35:48 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
if ( ! Global_AllocatorBuckets.append( bucket ) )
|
|
|
|
fatal( "Failed to append bucket to Global_AllocatorBuckets");
|
2023-07-09 09:35:48 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
last = Global_AllocatorBuckets.back();
|
|
|
|
}
|
2023-07-09 09:35:48 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
void* result = alloc_align( last.Backing, size, alignment );
|
2023-07-09 09:35:48 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
if ( result != nullptr && old_memory != nullptr )
|
|
|
|
{
|
|
|
|
mem_copy( result, old_memory, old_size );
|
|
|
|
}
|
2023-07-09 09:35:48 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
return result;
|
|
|
|
}
|
2023-07-09 09:35:48 -07:00
|
|
|
}
|
2023-07-11 15:29:45 -07:00
|
|
|
|
|
|
|
return nullptr;
|
2023-04-01 19:21:46 -07:00
|
|
|
}
|
2023-07-09 09:35:48 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
void setup()
|
|
|
|
{
|
|
|
|
GlobalAllocator = AllocatorInfo { & Global_Allocator_Proc, nullptr };
|
2023-04-05 23:21:23 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
Global_AllocatorBuckets = Array<Arena>::init_reserve( heap(), 128 );
|
2023-04-05 23:21:23 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
if ( Global_AllocatorBuckets == nullptr )
|
|
|
|
fatal( "Failed to reserve memory for Global_AllocatorBuckets");
|
2023-04-05 23:21:23 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
Arena bucket = Arena::init_from_allocator( heap(), BucketSize );
|
2023-07-09 09:35:48 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
if ( bucket.PhysicalStart == nullptr )
|
|
|
|
fatal( "Failed to create first bucket for Global_AllocatorBuckets");
|
2023-07-09 09:35:48 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
Global_AllocatorBuckets.append( bucket );
|
|
|
|
}
|
2023-04-01 19:21:46 -07:00
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
void cleanup()
|
2023-07-09 09:35:48 -07:00
|
|
|
{
|
2023-07-11 15:29:45 -07:00
|
|
|
s32 index = 0;
|
|
|
|
s32 left = Global_AllocatorBuckets.num();
|
|
|
|
do
|
|
|
|
{
|
|
|
|
Arena* bucket = & Global_AllocatorBuckets[ index ];
|
|
|
|
bucket->free();
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
while ( left--, left );
|
|
|
|
|
|
|
|
Global_AllocatorBuckets.free();
|
2023-07-09 09:35:48 -07:00
|
|
|
}
|
|
|
|
|
2023-07-11 15:29:45 -07:00
|
|
|
// namespace Memory
|
2023-04-05 23:21:23 -07:00
|
|
|
}
|
2023-07-11 15:29:45 -07:00
|
|
|
|
|
|
|
// namespace gen
|
|
|
|
}
|