From 7828e6d2ea9138322ecab8d4762001b6b77f2d83 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Wed, 12 Jul 2023 01:33:11 -0400 Subject: [PATCH] More dependency movement from zpl, incremental design improvements. Made token_fmt more ergonomic, going to have to use a similar behavior with the upfront body constructors. --- .vscode/gencpp_lldbvis.py | 84 -- .vscode/launch.json | 12 +- Readme.md | 2 +- gencpp.vcxproj | 14 +- gencpp.vcxproj.filters | 2 +- project/Bloat.cpp | 1152 +++++++++++++++-- project/Bloat.hpp | 663 ++++++++-- project/gen.cpp | 225 ++-- project/gen.hpp | 55 +- scripts/build.ci.ps1 | 124 +- {.vscode => scripts}/gencpp.natvis | 0 test/Parsed/Array.Parsed.hpp | 18 +- test/Parsed/Buffer.Parsed.hpp | 15 +- test/Parsed/HashTable.Parsed.hpp | 54 +- test/Parsed/Ring.Parsed.hpp | 24 +- test/Parsed/Sanity.Parsed.hpp | 18 +- test/Readme.md | 5 +- test/SOA.hpp | 40 +- .../Array.Upfront.hpp} | 64 +- .../Buffer.Upfront.hpp} | 12 +- .../HashTable.Upfront.hpp} | 87 +- .../Ring.Upfront.hpp} | 31 +- .../Sanity.Upfront.hpp} | 26 +- test/gen/meson.build | 4 +- test/{test.NonParsed.cpp => test.Upfront.cpp} | 12 +- test/{test.Parsed.cpp => test.cpp} | 5 +- 26 files changed, 2009 insertions(+), 739 deletions(-) delete mode 100644 .vscode/gencpp_lldbvis.py rename {.vscode => scripts}/gencpp.natvis (100%) rename test/{NonParsed/Array.NonParsed.hpp => Upfront/Array.Upfront.hpp} (86%) rename test/{NonParsed/Buffer.NonParsed.hpp => Upfront/Buffer.Upfront.hpp} (94%) rename test/{NonParsed/HashTable.NonParsed.hpp => Upfront/HashTable.Upfront.hpp} (81%) rename test/{NonParsed/Ring.NonParsed.hpp => Upfront/Ring.Upfront.hpp} (84%) rename test/{NonParsed/Sanity.NonParsed.hpp => Upfront/Sanity.Upfront.hpp} (89%) rename test/{test.NonParsed.cpp => test.Upfront.cpp} (64%) rename test/{test.Parsed.cpp => test.cpp} (88%) diff --git a/.vscode/gencpp_lldbvis.py b/.vscode/gencpp_lldbvis.py deleted file mode 100644 index 872b854..0000000 --- a/.vscode/gencpp_lldbvis.py +++ /dev/null @@ -1,84 +0,0 @@ -import lldb - -class String_SyntheticChildrenProvider: - def __init__(self, valobj, internal_dict): - self.valobj = valobj - - def num_children(self): - return 3 - - def get_child_index(self, name): - if name == "Data": - return 0 - if name == "Length": - return 1 - if name == "Capacity": - return 2 - - return None - - def get_child_at_index(self, index): - if index == 0: - return self.valobj.GetChildMemberWithName("Data") - - data = self.valobj.GetChildMemberWithName("Data") - header_ptr = data.GetValueAsUnsigned() - 16 - target = self.valobj.GetTarget() - header_type = target.FindFirstType("gen::String::Header") - header = self.valobj.CreateValueFromAddress("Header", header_ptr, header_type) - - if index == 1: - return header.GetChildMemberWithName("Length") - - if index == 2: - return header.GetChildMemberWithName("Capacity") - - return None - - def update(self): - pass - -def list_synthetic_providers(debugger): - print("Listing synthetic providers (start)") - - num_categories = debugger.GetNumCategories() - print("Debugger language categories count:", num_categories) - - cpp_category = None - for i in range(num_categories): - print("WERE HERE") - print(debugger) - cat = debugger.GetCategoryAtIndex(i) - print("Category name: {}, language: {}".format(cat.GetName(), cat.GetLanguage())) - if cat.GetLanguage() == lldb.eLanguageTypeC_plus_plus: - cpp_category = cat - break - - if not cpp_category: - print("Could not get C++ category") - return - - synthetic_providers = cpp_category.GetSyntheticChildren() - if not synthetic_providers: - print("Could not get synthetic children") - return - - num_providers = synthetic_providers.GetSize() - print("Number of synthetic providers:", num_providers) - - for i in range(num_providers): - provider = synthetic_providers.GetSyntheticChildAtIndex(i) - print("Provider regex: {}, class name: {}".format(provider.GetRegex(), provider.GetDescription())) - - print("Listing synthetic providers (finish)") - - - - -def __lldb_init_module(debugger, internal_dict): - print("Importing the String visualization") - debugger.HandleCommand("type synthetic add -x '^gen::String$' -l gencpp_libvis.String_SyntheticChildrenProvider") - print("Before list_synthetic_providers") - list_synthetic_providers(debugger) - -lldb.debugger = None diff --git a/.vscode/launch.json b/.vscode/launch.json index ba5fefc..1de23bb 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -12,7 +12,6 @@ "args": [], "cwd": "${workspaceFolder}/test/gen/", "postRunCommands": [ - "command script import \"${workspaceFolder}/.vscode/gencpp_lldbvis.py\"" ] }, { @@ -22,16 +21,7 @@ "program": "${workspaceFolder}/test/gen/build/gencpp.exe", "args": [], "cwd": "${workspaceFolder}/test/gen/", - "visualizerFile": "${workspaceFolder}/.vscode/gencpp.natvis" - }, - { - "type": "cppvsdbg", - "request": "launch", - "name": "Debug gentime parsed vsdbg", - "program": "${workspaceFolder}/test/gen/build/gencpp_parsed.exe", - "args": [], - "cwd": "${workspaceFolder}/test/gen/", - "visualizerFile": "${workspaceFolder}/.vscode/gencpp.natvis" + "visualizerFile": "${workspaceFolder}/scripts/gencpp.natvis" } ] } diff --git a/Readme.md b/Readme.md index 2c15d50..861fab6 100644 --- a/Readme.md +++ b/Readme.md @@ -204,7 +204,7 @@ Data layout of AST struct: ```cpp union { AST* ArrStatic[AST::ArrS_Cap]; - Array ArrDyn; + Array< AST* > ArrDyn; StringCached Content; SpecifierT ArrSpecs[AST::ArrSpecs_Cap]; }; diff --git a/gencpp.vcxproj b/gencpp.vcxproj index 9f4fa15..b8a05e0 100644 --- a/gencpp.vcxproj +++ b/gencpp.vcxproj @@ -113,12 +113,12 @@ - - - - - - + + + + + + @@ -129,7 +129,7 @@ - + diff --git a/gencpp.vcxproj.filters b/gencpp.vcxproj.filters index ead4c20..d73968e 100644 --- a/gencpp.vcxproj.filters +++ b/gencpp.vcxproj.filters @@ -50,7 +50,7 @@ Header Files - + Header Files diff --git a/project/Bloat.cpp b/project/Bloat.cpp index 3aa7089..207edae 100644 --- a/project/Bloat.cpp +++ b/project/Bloat.cpp @@ -1,10 +1,219 @@ #define BLOAT_IMPL #include "Bloat.hpp" +#pragma region Macros +# include + +// NOTE: Ensure we use standard methods for these calls if we use ZPL_PICO +# if ! defined( ZPL_PICO_CUSTOM_ROUTINES ) +# if ! defined( ZPL_MODULE_CORE ) +# define _strlen strlen +# define _printf_err( fmt, ... ) fprintf( stderr, fmt, __VA_ARGS__ ) +# define _printf_err_va( fmt, va ) vfprintf( stderr, fmt, va ) +# else +# define _strlen str_len +# define _printf_err( fmt, ... ) str_fmt_out_err( fmt, __VA_ARGS__ ) +# define _printf_err_va( fmt, va ) str_fmt_out_err_va( fmt, va ) +# endif +# endif + +# include + +# if defined( ZPL_SYSTEM_UNIX ) || defined( ZPL_SYSTEM_MACOS ) +# include +# elif defined( ZPL_SYSTEM_WINDOWS ) +# if ! defined( ZPL_NO_WINDOWS_H ) +# ifndef WIN32_LEAN_AND_MEAN +# ifndef NOMINMAX +# define NOMINMAX +# endif + +# define WIN32_LEAN_AND_MEAN +# define WIN32_MEAN_AND_LEAN +# define VC_EXTRALEAN +# endif +# include +# undef NOMINMAX +# undef WIN32_LEAN_AND_MEAN +# undef WIN32_MEAN_AND_LEAN +# undef VC_EXTRALEAN +# endif +# endif +#pragma endregion Macros + namespace gen { +#pragma region Debug + void assert_handler( char const* condition, char const* file, s32 line, char const* msg, ... ) + { + _printf_err( "%s:(%d): Assert Failure: ", file, line ); + + if ( condition ) + _printf_err( "`%s` ", condition ); + + if ( msg ) + { + va_list va; + va_start( va, msg ); + _printf_err_va( msg, va ); + va_end( va ); + } + + _printf_err( "%s", "\n" ); + } + + s32 assert_crash( char const* condition ) + { + ZPL_PANIC( condition ); + return 0; + } + + #if defined( ZPL_SYSTEM_WINDOWS ) + void process_exit( u32 code ) + { + ExitProcess( code ); + } + #else + # include + + void process_exit( u32 code ) + { + exit( code ); + } + #endif +#pragma endregion Debug + +#pragma region String Ops + internal sw _scan_zpl_i64( const char* text, s32 base, s64* value ) + { + const char* text_begin = text; + s64 result = 0; + b32 negative = false; + + if ( *text == '-' ) + { + negative = true; + text++; + } + + if ( base == 16 && str_compare( text, "0x", 2 ) == 0 ) + text += 2; + + for ( ;; ) + { + s64 v; + if ( char_is_digit( *text ) ) + v = *text - '0'; + else if ( base == 16 && char_is_hex_digit( *text ) ) + v = hex_digit_to_int( *text ); + else + break; + + result *= base; + result += v; + text++; + } + + if ( value ) + { + if ( negative ) + result = -result; + *value = result; + } + + return ( text - text_begin ); + } + + // TODO : Are these good enough for characters? + global const char _num_to_char_table[] = + "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "@$"; + + s64 str_to_i64( const char* str, char** end_ptr, s32 base ) + { + sw len; + s64 value; + + if ( ! base ) + { + if ( ( str_len( str ) > 2 ) && ( str_compare( str, "0x", 2 ) == 0 ) ) + base = 16; + else + base = 10; + } + + len = _scan_zpl_i64( str, base, &value ); + if ( end_ptr ) + *end_ptr = ( char* )str + len; + return value; + } + + void i64_to_str( s64 value, char* string, s32 base ) + { + char* buf = string; + b32 negative = false; + u64 v; + + if ( value < 0 ) + { + negative = true; + value = -value; + } + + v = zpl_cast( u64 ) value; + if ( v != 0 ) + { + while ( v > 0 ) + { + *buf++ = _num_to_char_table[ v % base ]; + v /= base; + } + } + else + { + *buf++ = '0'; + } + if ( negative ) + *buf++ = '-'; + *buf = '\0'; + str_reverse( string ); + } + + void u64_to_str( u64 value, char* string, s32 base ) + { + char* buf = string; + + if ( value ) + { + while ( value > 0 ) + { + *buf++ = _num_to_char_table[ value % base ]; + value /= base; + } + } + else + { + *buf++ = '0'; + } + *buf = '\0'; + + str_reverse( string ); + } +#pragma endregion String Ops + #pragma region Memory + void* mem_copy( void* dest, void const* source, sw n ) + { + if ( dest == NULL ) + { + return NULL; + } + + return memcpy( dest, source, n ); + } struct _heap_stats { @@ -48,126 +257,124 @@ namespace gen 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; - // 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 - // #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; - // 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 ) ); - // #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; - // if ( flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO ) - // { - // zero_size( ptr, size ); - // } - // } - // break; + case EAllocation_FREE : + { + free( old_memory ); + } + 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 ); - // 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; - // if ( flags & ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO ) - // { - // zero_size( ptr, size ); - // } - // } - // break; + case EAllocation_FREE : + { + free( old_memory ); + } + 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_RESIZE : - // { - // AllocatorInfo a = heap(); - // ptr = default_resize_align( a, old_memory, old_size, size, alignment ); - // } - // break; - // #endif + case EAllocation_FREE_ALL : + break; + } - // 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 - // #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; + return ptr; } void* Arena::allocator_proc( void* allocator_data, AllocType type, sw size, sw alignment, void* old_memory, sw old_size, u64 flags ) @@ -327,11 +534,581 @@ namespace gen return pool; } - #pragma endregion Memory -#pragma region File Handling +#pragma region Printing + enum + { + ZPL_FMT_MINUS = ZPL_BIT( 0 ), + ZPL_FMT_PLUS = ZPL_BIT( 1 ), + ZPL_FMT_ALT = ZPL_BIT( 2 ), + ZPL_FMT_SPACE = ZPL_BIT( 3 ), + ZPL_FMT_ZERO = ZPL_BIT( 4 ), + ZPL_FMT_CHAR = ZPL_BIT( 5 ), + ZPL_FMT_SHORT = ZPL_BIT( 6 ), + ZPL_FMT_INT = ZPL_BIT( 7 ), + ZPL_FMT_LONG = ZPL_BIT( 8 ), + ZPL_FMT_LLONG = ZPL_BIT( 9 ), + ZPL_FMT_SIZE = ZPL_BIT( 10 ), + ZPL_FMT_INTPTR = ZPL_BIT( 11 ), + + ZPL_FMT_UNSIGNED = ZPL_BIT( 12 ), + ZPL_FMT_LOWER = ZPL_BIT( 13 ), + ZPL_FMT_UPPER = ZPL_BIT( 14 ), + ZPL_FMT_WIDTH = ZPL_BIT( 15 ), + + ZPL_FMT_DONE = ZPL_BIT( 30 ), + + ZPL_FMT_INTS = ZPL_FMT_CHAR | ZPL_FMT_SHORT | ZPL_FMT_INT | ZPL_FMT_LONG | ZPL_FMT_LLONG | ZPL_FMT_SIZE | ZPL_FMT_INTPTR + }; + + struct _format_info + { + s32 base; + s32 flags; + s32 width; + s32 precision; + }; + + internal sw _print_string( char* text, sw max_len, _format_info* info, char const* str ) + { + sw res = 0, len = 0; + sw remaining = max_len; + char* begin = text; + + if ( str == NULL && max_len >= 6 ) + { + res += str_copy_nulpad( text, "(null)", 6 ); + return res; + } + + if ( info && info->precision >= 0 ) + len = str_len( str, info->precision ); + else + len = str_len( str ); + + if ( info && ( info->width == 0 && info->flags & ZPL_FMT_WIDTH ) ) + { + return res; + } + + if ( info && ( info->width == 0 || info->flags & ZPL_FMT_MINUS ) ) + { + if ( info->precision > 0 ) + len = info->precision < len ? info->precision : len; + if ( res + len > max_len ) + return res; + res += str_copy_nulpad( text, str, len ); + text += res; + + if ( info->width > res ) + { + sw padding = info->width - len; + + char pad = ( info->flags & ZPL_FMT_ZERO ) ? '0' : ' '; + while ( padding-- > 0 && remaining-- > 0 ) + *text++ = pad, res++; + } + } + else + { + if ( info && ( info->width > res ) ) + { + sw padding = info->width - len; + char pad = ( info->flags & ZPL_FMT_ZERO ) ? '0' : ' '; + while ( padding-- > 0 && remaining-- > 0 ) + *text++ = pad, res++; + } + + if ( res + len > max_len ) + return res; + res += str_copy_nulpad( text, str, len ); + } + + if ( info ) + { + if ( info->flags & ZPL_FMT_UPPER ) + str_to_upper( begin ); + else if ( info->flags & ZPL_FMT_LOWER ) + str_to_lower( begin ); + } + + return res; + } + + internal sw _print_char( char* text, sw max_len, _format_info* info, char arg ) + { + char str[ 2 ] = ""; + str[ 0 ] = arg; + return _print_string( text, max_len, info, str ); + } + + internal sw _print_repeated_char( char* text, sw max_len, _format_info* info, char arg ) + { + sw res = 0; + s32 rem = ( info ) ? ( info->width > 0 ) ? info->width : 1 : 1; + res = rem; + while ( rem-- > 0 ) + *text++ = arg; + + return res; + } + + internal sw _print_i64( char* text, sw max_len, _format_info* info, s64 value ) + { + char num[ 130 ]; + i64_to_str( value, num, info ? info->base : 10 ); + return _print_string( text, max_len, info, num ); + } + + internal sw _print_u64( char* text, sw max_len, _format_info* info, u64 value ) + { + char num[ 130 ]; + u64_to_str( value, num, info ? info->base : 10 ); + return _print_string( text, max_len, info, num ); + } + + internal sw _print_f64( char* text, sw max_len, _format_info* info, b32 is_hexadecimal, f64 arg ) + { + // TODO: Handle exponent notation + sw width, len, remaining = max_len; + char* text_begin = text; + + if ( arg ) + { + u64 value; + if ( arg < 0 ) + { + if ( remaining > 1 ) + *text = '-', remaining--; + text++; + arg = -arg; + } + else if ( info->flags & ZPL_FMT_MINUS ) + { + if ( remaining > 1 ) + *text = '+', remaining--; + text++; + } + + value = zpl_cast( u64 ) arg; + len = _print_u64( text, remaining, NULL, value ); + text += len; + + if ( len >= remaining ) + remaining = min( remaining, 1 ); + else + remaining -= len; + arg -= value; + + if ( info->precision < 0 ) + info->precision = 6; + + if ( ( info->flags & ZPL_FMT_ALT ) || info->precision > 0 ) + { + s64 mult = 10; + if ( remaining > 1 ) + *text = '.', remaining--; + text++; + while ( info->precision-- > 0 ) + { + value = zpl_cast( u64 )( arg * mult ); + len = _print_u64( text, remaining, NULL, value ); + text += len; + if ( len >= remaining ) + remaining = min( remaining, 1 ); + else + remaining -= len; + arg -= zpl_cast( f64 ) value / mult; + mult *= 10; + } + } + } + else + { + if ( remaining > 1 ) + *text = '0', remaining--; + text++; + if ( info->flags & ZPL_FMT_ALT ) + { + if ( remaining > 1 ) + *text = '.', remaining--; + text++; + } + } + + width = info->width - ( text - text_begin ); + if ( width > 0 ) + { + char fill = ( info->flags & ZPL_FMT_ZERO ) ? '0' : ' '; + char* end = text + remaining - 1; + len = ( text - text_begin ); + + for ( len = ( text - text_begin ); len--; ) + { + if ( ( text_begin + len + width ) < end ) + *( text_begin + len + width ) = *( text_begin + len ); + } + + len = width; + text += len; + if ( len >= remaining ) + remaining = min( remaining, 1 ); + else + remaining -= len; + + while ( len-- ) + { + if ( text_begin + len < end ) + text_begin[ len ] = fill; + } + } + + return ( text - text_begin ); + } + + ZPL_NEVER_INLINE sw str_fmt_va( char* text, sw max_len, char const* fmt, va_list va ) + { + char const* text_begin = text; + sw remaining = max_len, res; + + while ( *fmt ) + { + _format_info info = { 0 }; + sw len = 0; + info.precision = -1; + + while ( *fmt && *fmt != '%' && remaining ) + *text++ = *fmt++; + + if ( *fmt == '%' ) + { + do + { + switch ( *++fmt ) + { + case '-' : + { + info.flags |= ZPL_FMT_MINUS; + break; + } + case '+' : + { + info.flags |= ZPL_FMT_PLUS; + break; + } + case '#' : + { + info.flags |= ZPL_FMT_ALT; + break; + } + case ' ' : + { + info.flags |= ZPL_FMT_SPACE; + break; + } + case '0' : + { + info.flags |= ( ZPL_FMT_ZERO | ZPL_FMT_WIDTH ); + break; + } + default : + { + info.flags |= ZPL_FMT_DONE; + break; + } + } + } while ( ! ( info.flags & ZPL_FMT_DONE ) ); + } + + // NOTE: Optional Width + if ( *fmt == '*' ) + { + int width = va_arg( va, int ); + if ( width < 0 ) + { + info.flags |= ZPL_FMT_MINUS; + info.width = -width; + } + else + { + info.width = width; + } + info.flags |= ZPL_FMT_WIDTH; + fmt++; + } + else + { + info.width = zpl_cast( s32 ) str_to_i64( fmt, zpl_cast( char** ) & fmt, 10 ); + if ( info.width != 0 ) + { + info.flags |= ZPL_FMT_WIDTH; + } + } + + // NOTE: Optional Precision + if ( *fmt == '.' ) + { + fmt++; + if ( *fmt == '*' ) + { + info.precision = va_arg( va, int ); + fmt++; + } + else + { + info.precision = zpl_cast( s32 ) str_to_i64( fmt, zpl_cast( char** ) & fmt, 10 ); + } + info.flags &= ~ZPL_FMT_ZERO; + } + + switch ( *fmt++ ) + { + case 'h' : + if ( *fmt == 'h' ) + { // hh => char + info.flags |= ZPL_FMT_CHAR; + fmt++; + } + else + { // h => short + info.flags |= ZPL_FMT_SHORT; + } + break; + + case 'l' : + if ( *fmt == 'l' ) + { // ll => long long + info.flags |= ZPL_FMT_LLONG; + fmt++; + } + else + { // l => long + info.flags |= ZPL_FMT_LONG; + } + break; + + break; + + case 'z' : // NOTE: zpl_usize + info.flags |= ZPL_FMT_UNSIGNED; + // fallthrough + case 't' : // NOTE: zpl_isize + info.flags |= ZPL_FMT_SIZE; + break; + + default : + fmt--; + break; + } + + switch ( *fmt ) + { + case 'u' : + info.flags |= ZPL_FMT_UNSIGNED; + // fallthrough + case 'd' : + case 'i' : + info.base = 10; + break; + + case 'o' : + info.base = 8; + break; + + case 'x' : + info.base = 16; + info.flags |= ( ZPL_FMT_UNSIGNED | ZPL_FMT_LOWER ); + break; + + case 'X' : + info.base = 16; + info.flags |= ( ZPL_FMT_UNSIGNED | ZPL_FMT_UPPER ); + break; + + case 'f' : + case 'F' : + case 'g' : + case 'G' : + len = _print_f64( text, remaining, &info, 0, va_arg( va, f64 ) ); + break; + + case 'a' : + case 'A' : + len = _print_f64( text, remaining, &info, 1, va_arg( va, f64 ) ); + break; + + case 'c' : + len = _print_char( text, remaining, &info, zpl_cast( char ) va_arg( va, int ) ); + break; + + case 's' : + len = _print_string( text, remaining, &info, va_arg( va, char* ) ); + break; + + case 'r' : + len = _print_repeated_char( text, remaining, &info, va_arg( va, int ) ); + break; + + case 'p' : + info.base = 16; + info.flags |= ( ZPL_FMT_LOWER | ZPL_FMT_UNSIGNED | ZPL_FMT_ALT | ZPL_FMT_INTPTR ); + break; + + case '%' : + len = _print_char( text, remaining, &info, '%' ); + break; + + default : + fmt--; + break; + } + + fmt++; + + if ( info.base != 0 ) + { + if ( info.flags & ZPL_FMT_UNSIGNED ) + { + u64 value = 0; + switch ( info.flags & ZPL_FMT_INTS ) + { + case ZPL_FMT_CHAR : + value = zpl_cast( u64 ) zpl_cast( u8 ) va_arg( va, int ); + break; + case ZPL_FMT_SHORT : + value = zpl_cast( u64 ) zpl_cast( u16 ) va_arg( va, int ); + break; + case ZPL_FMT_LONG : + value = zpl_cast( u64 ) va_arg( va, unsigned long ); + break; + case ZPL_FMT_LLONG : + value = zpl_cast( u64 ) va_arg( va, unsigned long long ); + break; + case ZPL_FMT_SIZE : + value = zpl_cast( u64 ) va_arg( va, uw ); + break; + case ZPL_FMT_INTPTR : + value = zpl_cast( u64 ) va_arg( va, uptr ); + break; + default : + value = zpl_cast( u64 ) va_arg( va, unsigned int ); + break; + } + + len = _print_u64( text, remaining, &info, value ); + } + else + { + s64 value = 0; + switch ( info.flags & ZPL_FMT_INTS ) + { + case ZPL_FMT_CHAR : + value = zpl_cast( s64 ) zpl_cast( s8 ) va_arg( va, int ); + break; + case ZPL_FMT_SHORT : + value = zpl_cast( s64 ) zpl_cast( s16 ) va_arg( va, int ); + break; + case ZPL_FMT_LONG : + value = zpl_cast( s64 ) va_arg( va, long ); + break; + case ZPL_FMT_LLONG : + value = zpl_cast( s64 ) va_arg( va, long long ); + break; + case ZPL_FMT_SIZE : + value = zpl_cast( s64 ) va_arg( va, uw ); + break; + case ZPL_FMT_INTPTR : + value = zpl_cast( s64 ) va_arg( va, uptr ); + break; + default : + value = zpl_cast( s64 ) va_arg( va, int ); + break; + } + + len = _print_i64( text, remaining, &info, value ); + } + } + + text += len; + if ( len >= remaining ) + remaining = min( remaining, 1 ); + else + remaining -= len; + } + + *text++ = '\0'; + res = ( text - text_begin ); + return ( res >= max_len || res < 0 ) ? -1 : res; + } + + char* str_fmt_buf_va( char const* fmt, va_list va ) + { + local_persist zpl_thread_local char buffer[ ZPL_PRINTF_MAXLEN ]; + str_fmt_va( buffer, size_of( buffer ), fmt, va ); + return buffer; + } + + char* str_fmt_buf( char const* fmt, ... ) + { + va_list va; + char* str; + va_start( va, fmt ); + str = str_fmt_buf_va( fmt, va ); + va_end( va ); + return str; + } + + sw str_fmt_file_va( struct FileInfo* f, char const* fmt, va_list va ) + { + local_persist zpl_thread_local char buf[ ZPL_PRINTF_MAXLEN ]; + sw len = str_fmt_va( buf, size_of( buf ), fmt, va ); + b32 res = file_write( f, buf, len - 1 ); // NOTE: prevent extra whitespace + return res ? len : -1; + } + + sw str_fmt_out_va( char const* fmt, va_list va ) + { + return str_fmt_file_va( file_get_standard( EFileStandard_OUTPUT ), fmt, va ); + } +#pragma endregion Printing + +#pragma region Hashing + global u32 const _crc32_table[ 256 ] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, + 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, + 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, + 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, + 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, + 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, + 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, + 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, + }; + + u32 crc32( void const* data, sw len ) + { + sw remaining; + u32 result = ~( zpl_cast( u32 ) 0 ); + u8 const* c = zpl_cast( u8 const* ) data; + for ( remaining = len; remaining--; c++ ) + result = ( result >> 8 ) ^ ( _crc32_table[ ( result ^ *c ) & 0xff ] ); + return ~result; + } +#pragma endregion Hashing + +#pragma region File Handling #if defined( ZPL_SYSTEM_WINDOWS ) || defined( ZPL_SYSTEM_CYGWIN ) internal wchar_t* _alloc_utf8_to_ucs2( AllocatorInfo a, char const* text, sw* w_len_ ) @@ -600,6 +1377,116 @@ namespace gen internal void _dirinfo_free_entry( DirEntry* entry ); + // TODO: Is this a bad idea? + global b32 _std_file_set = false; + global FileInfo _std_files[ EFileStandard_COUNT ] = { + { + { nullptr, nullptr, nullptr, nullptr }, + { nullptr }, + 0, + nullptr, + 0, + nullptr + } }; + + #if defined( ZPL_SYSTEM_WINDOWS ) || defined( ZPL_SYSTEM_CYGWIN ) + + FileInfo* file_get_standard( FileStandardType std ) + { + if ( ! _std_file_set ) + { + # define ZPL__SET_STD_FILE( type, v ) \ + _std_files[ type ].FD.p = v; \ + _std_files[ type ].Ops = default_file_operations + ZPL__SET_STD_FILE( EFileStandard_INPUT, GetStdHandle( STD_INPUT_HANDLE ) ); + ZPL__SET_STD_FILE( EFileStandard_OUTPUT, GetStdHandle( STD_OUTPUT_HANDLE ) ); + ZPL__SET_STD_FILE( EFileStandard_ERROR, GetStdHandle( STD_ERROR_HANDLE ) ); + # undef ZPL__SET_STD_FILE + _std_file_set = true; + } + return &_std_files[ std ]; + } + + // void file_connect_handle( FileInfo* file, void* handle ) + // { + // ZPL_ASSERT_NOT_NULL( file ); + // ZPL_ASSERT_NOT_NULL( handle ); + + // if ( file->is_temp ) + // return; + + // zero_item( file ); + + // file->fd.p = handle; + // file->ops = default_file_operations; + // } + + // FileError file_truncate( FileInfo* f, s64 size ) + // { + // FileError err = EFileError_NONE; + // s64 prev_offset = file_tell( f ); + // file_seek( f, size ); + // if ( ! SetEndOfFile( f ) ) + // err = EFileError_TRUNCATION_FAILURE; + // file_seek( f, prev_offset ); + // return err; + // } + + // b32 fs_exists( char const* name ) + // { + // WIN32_FIND_DATAW data; + // wchar_t* w_text; + // void* handle; + // b32 found = false; + // AllocatorInfo a = heap_allocator(); + + // w_text = _alloc_utf8_to_ucs2( a, name, NULL ); + // if ( w_text == NULL ) + // { + // return false; + // } + // handle = FindFirstFileW( w_text, &data ); + // free( a, w_text ); + // found = handle != INVALID_HANDLE_VALUE; + // if ( found ) + // FindClose( handle ); + // return found; + // } + + #else // POSIX + + FileInfo* file_get_standard( FileStandardType std ) + { + if ( ! _std_file_set ) + { + # define ZPL__SET_STD_FILE( type, v ) \ + _std_files[ type ].fd.i = v; \ + _std_files[ type ].ops = default_file_operations + ZPL__SET_STD_FILE( EFileStandard_INPUT, 0 ); + ZPL__SET_STD_FILE( EFileStandard_OUTPUT, 1 ); + ZPL__SET_STD_FILE( EFileStandard_ERROR, 2 ); + # undef ZPL__SET_STD_FILE + _std_file_set = true; + } + return &_std_files[ std ]; + } + + // FileError file_truncate( FileInfo* f, s64 size ) + // { + // FileError err = EFileError_NONE; + // int i = ftruncate( f->fd.i, size ); + // if ( i != 0 ) + // err = EFileError_TRUNCATION_FAILURE; + // return err; + // } + + // b32 fs_exists( char const* name ) + // { + // return access( name, F_OK ) != -1; + // } + + #endif + FileError file_close( FileInfo* f ) { if ( ! f ) @@ -703,14 +1590,50 @@ namespace gen dir->Buffer.free(); mfree( ( void* )dir->FullPath ); } - #pragma endreigon File Handling +#pragma region String + String String::fmt( AllocatorInfo allocator, char* buf, sw buf_size, char const* fmt, ... ) + { + va_list va; + va_start( va, fmt ); + str_fmt_va( buf, buf_size, fmt, va ); + va_end( va ); + + return make( allocator, buf ); + } + + String String::fmt_buf( AllocatorInfo allocator, char const* fmt, ... ) + { + local_persist thread_local + char buf[ ZPL_PRINTF_MAXLEN ] = { 0 }; + + va_list va; + va_start( va, fmt ); + str_fmt_va( buf, ZPL_PRINTF_MAXLEN, fmt, va ); + va_end( va ); + + return make( allocator, buf ); + } + + bool String::append_fmt( char const* fmt, ... ) + { + sw res; + char buf[ ZPL_PRINTF_MAXLEN ] = { 0 }; + + va_list va; + va_start( va, fmt ); + res = str_fmt_va( buf, count_of( buf ) - 1, fmt, va ) - 1; + va_end( va ); + + return append( buf, res ); + } +#pragma endregion String + namespace Memory { global AllocatorInfo GlobalAllocator; - - global Array Global_AllocatorBuckets; + global Array Global_AllocatorBuckets; void* Global_Allocator_Proc( void* allocator_data, AllocType type, sw size, sw alignment, void* old_memory, sw old_size, u64 flags ) { @@ -808,6 +1731,5 @@ namespace gen // namespace Memory } - // namespace gen -} \ No newline at end of file +} diff --git a/project/Bloat.hpp b/project/Bloat.hpp index abcca78..2b5ccd6 100644 --- a/project/Bloat.hpp +++ b/project/Bloat.hpp @@ -9,7 +9,7 @@ # define ZPL_IMPLEMENTATION #endif -// TODO: This will be removed when making the library have zero dependencies. +// TODO : This will be removed when making the library have zero dependencies. #pragma region ZPL INCLUDE #if __clang__ # pragma clang diagnostic push @@ -27,10 +27,16 @@ # define ZPL_MODULE_HASHING #include "zpl.h" -#undef Array -#undef heap #undef alloc_item #undef alloc_array +#undef Array +#undef heap +#undef malloc +#undef mfree +#undef ZPL_ASSERT_MSG +#undef ZPL_ASSERT_NOT_NULL +#undef ZPL_DEBUG_TRAP +#undef ZPL_PANIC using zpl::b32; using zpl::s8; @@ -38,12 +44,15 @@ using zpl::s16; using zpl::s32; using zpl::s64; using zpl::u8; +using zpl::u16; using zpl::u32; using zpl::u64; using zpl::uw; using zpl::sw; using zpl::sptr; using zpl::uptr; +using zpl::f32; +using zpl::f64; // using zpl::AllocType; // using zpl::Arena; @@ -63,39 +72,40 @@ using zpl::uptr; // using zpl::ZPL_ALLOCATOR_FLAG_CLEAR_TO_ZERO; -using zpl::align_forward; -using zpl::align_forward_i64; +// using zpl::align_forward; +// using zpl::align_forward_i64; // using zpl::alloc; // using zpl::alloc_align; // using zpl::arena_allocator; // using zpl::arena_init_from_memory; // using zpl::arena_init_from_allocator; // using zpl::arena_free; -using zpl::assert_crash; -using zpl::char_first_occurence; -using zpl::char_is_alpha; -using zpl::char_is_alphanumeric; -using zpl::char_is_digit; -using zpl::char_is_hex_digit; -using zpl::char_is_space; -using zpl::crc32; +// using zpl::assert_crash; +// using zpl::char_first_occurence; +// using zpl::char_is_alpha; +// using zpl::char_is_alphanumeric; +// using zpl::char_is_digit; +// using zpl::char_is_hex_digit; +// using zpl::char_is_space; +// using zpl::crc32; // using zpl::free_all; -using zpl::is_power_of_two; -using zpl::mem_copy; -using zpl::mem_move; -using zpl::mem_set; -using zpl::pointer_add; +// using zpl::is_power_of_two; +// using zpl::mem_copy; +// using zpl::mem_move; +// using zpl::mem_set; +// using zpl::pointer_add; // using zpl::pool_allocator; // using zpl::pool_init; // using zpl::pool_free; -using zpl::process_exit; -using zpl::str_compare; -using zpl::str_copy; -using zpl::str_fmt_buf; -using zpl::str_fmt_va; -using zpl::str_fmt_out_va; +// using zpl::process_exit; +// using zpl::str_compare; +// using zpl::str_copy; +// using zpl::str_fmt_buf; +// using zpl::str_fmt_va; +// using zpl::str_fmt_out_va; +using zpl::str_fmt_out_err; using zpl::str_fmt_out_err_va; -using zpl::str_len; +// using zpl::str_len; using zpl::zero_size; #if __clang__ @@ -114,6 +124,27 @@ using zpl::zero_size; #endif +/* Platform compiler */ + +#if defined( _MSC_VER ) +# define ZPL_COMPILER_MSVC 1 +#elif defined( __GNUC__ ) +# define ZPL_COMPILER_GCC 1 +#elif defined( __clang__ ) +# define ZPL_COMPILER_CLANG 1 +#elif defined( __MINGW32__ ) +# define ZPL_COMPILER_MINGW 1 +#elif defined( __TINYC__ ) +# define ZPL_COMPILER_TINYC 1 +#else +# error Unknown compiler +#endif + +#ifndef zpl_cast +# define zpl_cast( Type ) ( Type ) +#endif + + #include "Banned.define.hpp" @@ -163,8 +194,7 @@ using zpl::zero_size; #define rcast( Type_, Value_ ) reinterpret_cast< Type_ >( Value_ ) #define pcast( Type_, Value_ ) ( * (Type_*)( & (Value_) ) ) #define GEN_STRINGIZE_VA( ... ) #__VA_ARGS__ -#define txt( ... ) GEN_STRINGIZE_VA( __VA_ARGS__ ) -#define txt_to_StrC( ... ) sizeof( GEN_STRINGIZE_VA( __VA_ARGS__ ) ), GEN_STRINGIZE_VA( __VA_ARGS__ ) +#define stringize( ... ) GEN_STRINGIZE_VA( __VA_ARGS__ ) #define do_once() \ do \ { \ @@ -194,7 +224,73 @@ namespace gen constexpr char const* Msg_Invalid_Value = "INVALID VALUE PROVIDED"; + #pragma region Debug + + #ifndef ZPL_DEBUG_TRAP + # if defined( _MSC_VER ) + # if _MSC_VER < 1300 + # define ZPL_DEBUG_TRAP() __asm int 3 /* Trap to debugger! */ + # else + # define ZPL_DEBUG_TRAP() __debugbreak() + # endif + # elif defined( ZPL_COMPILER_TINYC ) + # define ZPL_DEBUG_TRAP() process_exit( 1 ) + # else + # define ZPL_DEBUG_TRAP() __builtin_trap() + # endif + #endif + + #ifndef ZPL_ASSERT_MSG + # define ZPL_ASSERT_MSG( cond, msg, ... ) \ + do \ + { \ + if ( ! ( cond ) ) \ + { \ + assert_handler( #cond, __FILE__, zpl_cast( s64 ) __LINE__, msg, ##__VA_ARGS__ ); \ + ZPL_DEBUG_TRAP(); \ + } \ + } while ( 0 ) + #endif + + #ifndef ZPL_ASSERT_NOT_NULL + # define ZPL_ASSERT_NOT_NULL( ptr ) ZPL_ASSERT_MSG( ( ptr ) != NULL, #ptr " must not be NULL" ) + #endif + + // NOTE: Things that shouldn't happen with a message! + #ifndef ZPL_PANIC + # define ZPL_PANIC( msg, ... ) ZPL_ASSERT_MSG( 0, msg, ##__VA_ARGS__ ) + #endif + + void assert_handler( char const* condition, char const* file, s32 line, char const* msg, ... ); + s32 assert_crash( char const* condition ); + void process_exit( u32 code ); + + #pragma endregion Debug + #pragma region Memory + //! Checks if value is power of 2. + ZPL_DEF_INLINE b32 is_power_of_two( sw x ); + + //! Aligns address to specified alignment. + ZPL_DEF_INLINE void* align_forward( void* ptr, sw alignment ); + + //! Aligns value to a specified alignment. + ZPL_DEF_INLINE s64 align_forward_i64( s64 value, sw alignment ); + + //! Moves pointer forward by bytes. + ZPL_DEF_INLINE void* pointer_add( void* ptr, sw bytes ); + + //! Copy non-overlapping memory from source to destination. + void* mem_copy( void* dest, void const* source, sw size ); + + //! Search for a constant value within the size limit at memory location. + ZPL_DEF void const* mem_find( void const* data, u8 byte_value, sw size ); + + //! Copy memory from source to destination. + ZPL_DEF_INLINE void* mem_move( void* dest, void const* source, sw size ); + + //! Set constant value at memory location with specified size. + ZPL_DEF_INLINE void* mem_set( void* data, u8 byte_value, sw size ); enum AllocType : u8 { @@ -246,7 +342,6 @@ namespace gen # define alloc_array( allocator_, Type, count ) ( Type* )alloc( allocator_, size_of( Type ) * ( count ) ) #endif - /* heap memory analysis tools */ /* define ZPL_HEAP_ANALYSIS to enable this feature */ /* call zpl_heap_stats_init at the beginning of the entry point */ @@ -266,17 +361,168 @@ namespace gen //! The heap allocator backed by operating system's memory manager. constexpr AllocatorInfo heap( void ) { return { heap_allocator_proc, nullptr }; } - // #ifndef malloc + #ifndef malloc + //! Helper to allocate memory using heap allocator. + # define malloc( sz ) alloc( heap(), sz ) - // //! Helper to allocate memory using heap allocator. - // # define malloc( sz ) ZPL_NS( alloc )( ZPL_NS( heap_allocator )(), sz ) + //! Helper to free memory allocated by heap allocator. + # define mfree( ptr ) free( heap(), ptr ) + #endif - // //! Helper to free memory allocated by heap allocator. - // # define mfree( ptr ) ZPL_NS( free )( ZPL_NS( heap_allocator )(), ptr ) + ZPL_IMPL_INLINE b32 is_power_of_two( sw x ) + { + if ( x <= 0 ) + return false; + return ! ( x & ( x - 1 ) ); + } - // //! Alias to heap allocator. - // # define heap ZPL_NS( heap_allocator ) - // #endif + ZPL_IMPL_INLINE void* align_forward( void* ptr, sw alignment ) + { + uptr p; + + ZPL_ASSERT( is_power_of_two( alignment ) ); + + p = zpl_cast( uptr ) ptr; + return zpl_cast( void* )( ( p + ( alignment - 1 ) ) & ~( alignment - 1 ) ); + } + + ZPL_IMPL_INLINE s64 align_forward_i64( s64 value, sw alignment ) + { + return value + ( alignment - value % alignment ) % alignment; + } + + ZPL_IMPL_INLINE void* pointer_add( void* ptr, sw bytes ) + { + return zpl_cast( void* )( zpl_cast( u8* ) ptr + bytes ); + } + + ZPL_IMPL_INLINE void* mem_move( void* dest, void const* source, sw n ) + { + if ( dest == NULL ) + { + return NULL; + } + + u8* d = zpl_cast( u8* ) dest; + u8 const* s = zpl_cast( u8 const* ) source; + + if ( d == s ) + return d; + if ( s + n <= d || d + n <= s ) // NOTE: Non-overlapping + return mem_copy( d, s, n ); + + if ( d < s ) + { + if ( zpl_cast( uptr ) s % size_of( sw ) == zpl_cast( uptr ) d % size_of( sw ) ) + { + while ( zpl_cast( uptr ) d % size_of( sw ) ) + { + if ( ! n-- ) + return dest; + *d++ = *s++; + } + while ( n >= size_of( sw ) ) + { + *zpl_cast( sw* ) d = *zpl_cast( sw* ) s; + n -= size_of( sw ); + d += size_of( sw ); + s += size_of( sw ); + } + } + for ( ; n; n-- ) + *d++ = *s++; + } + else + { + if ( ( zpl_cast( uptr ) s % size_of( sw ) ) == ( zpl_cast( uptr ) d % size_of( sw ) ) ) + { + while ( zpl_cast( uptr )( d + n ) % size_of( sw ) ) + { + if ( ! n-- ) + return dest; + d[ n ] = s[ n ]; + } + while ( n >= size_of( sw ) ) + { + n -= size_of( sw ); + *zpl_cast( sw* )( d + n ) = *zpl_cast( sw* )( s + n ); + } + } + while ( n ) + n--, d[ n ] = s[ n ]; + } + + return dest; + } + + ZPL_IMPL_INLINE void* mem_set( void* dest, u8 c, sw n ) + { + if ( dest == NULL ) + { + return NULL; + } + + u8* s = zpl_cast( u8* ) dest; + sw k; + u32 c32 = ( ( u32 )-1 ) / 255 * c; + + if ( n == 0 ) + return dest; + s[ 0 ] = s[ n - 1 ] = c; + if ( n < 3 ) + return dest; + s[ 1 ] = s[ n - 2 ] = c; + s[ 2 ] = s[ n - 3 ] = c; + if ( n < 7 ) + return dest; + s[ 3 ] = s[ n - 4 ] = c; + if ( n < 9 ) + return dest; + + k = -zpl_cast( sptr ) s & 3; + s += k; + n -= k; + n &= -4; + + *zpl_cast( u32* )( s + 0 ) = c32; + *zpl_cast( u32* )( s + n - 4 ) = c32; + if ( n < 9 ) + return dest; + *zpl_cast( u32* )( s + 4 ) = c32; + *zpl_cast( u32* )( s + 8 ) = c32; + *zpl_cast( u32* )( s + n - 12 ) = c32; + *zpl_cast( u32* )( s + n - 8 ) = c32; + if ( n < 25 ) + return dest; + *zpl_cast( u32* )( s + 12 ) = c32; + *zpl_cast( u32* )( s + 16 ) = c32; + *zpl_cast( u32* )( s + 20 ) = c32; + *zpl_cast( u32* )( s + 24 ) = c32; + *zpl_cast( u32* )( s + n - 28 ) = c32; + *zpl_cast( u32* )( s + n - 24 ) = c32; + *zpl_cast( u32* )( s + n - 20 ) = c32; + *zpl_cast( u32* )( s + n - 16 ) = c32; + + k = 24 + ( zpl_cast( uptr ) s & 4 ); + s += k; + n -= k; + + { + u64 c64 = ( zpl_cast( u64 ) c32 << 32 ) | c32; + while ( n > 31 ) + { + *zpl_cast( u64* )( s + 0 ) = c64; + *zpl_cast( u64* )( s + 8 ) = c64; + *zpl_cast( u64* )( s + 16 ) = c64; + *zpl_cast( u64* )( s + 24 ) = c64; + + n -= 32; + s += 32; + } + } + + return dest; + } ZPL_IMPL_INLINE void* alloc_align( AllocatorInfo a, sw size, sw alignment ) { @@ -338,14 +584,6 @@ namespace gen } } - // ZPL_IMPL_INLINE AllocatorInfo heap( void ) - // { - // AllocatorInfo a; - // a.Proc = heap_allocator_proc; - // a.Data = nullptr; - // return a; - // } - struct Arena { static @@ -466,9 +704,234 @@ namespace gen return { allocator_proc, this }; } }; - #pragma endregion Memory + #pragma region String Ops + ZPL_DEF_INLINE const char* char_first_occurence( const char* str, char c ); + + ZPL_DEF_INLINE b32 char_is_alpha( char c ); + ZPL_DEF_INLINE b32 char_is_alphanumeric( char c ); + ZPL_DEF_INLINE b32 char_is_digit( char c ); + ZPL_DEF_INLINE b32 char_is_hex_digit( char c ); + ZPL_DEF_INLINE b32 char_is_space( char c ); + ZPL_DEF_INLINE char char_to_lower( char c ); + ZPL_DEF_INLINE char char_to_upper( char c ); + + ZPL_DEF_INLINE s32 digit_to_int( char c ); + ZPL_DEF_INLINE s32 hex_digit_to_int( char c ); + + ZPL_DEF_INLINE s32 str_compare( const char* s1, const char* s2 ); + ZPL_DEF_INLINE s32 str_compare( const char* s1, const char* s2, sw len ); + ZPL_DEF_INLINE char* str_copy( char* dest, const char* source, sw len ); + ZPL_DEF_INLINE sw str_copy_nulpad( char* dest, const char* source, sw len ); + ZPL_DEF_INLINE sw str_len( const char* str ); + ZPL_DEF_INLINE sw str_len( const char* str, sw max_len ); + ZPL_DEF_INLINE char* str_reverse( char* str ); // NOTE: ASCII only + + // NOTE: ASCII only + ZPL_DEF_INLINE void str_to_lower( char* str ); + ZPL_DEF_INLINE void str_to_upper( char* str ); + + s64 str_to_i64( const char* str, char** end_ptr, s32 base ); // TODO : Support more than just decimal and hexadecimal + void i64_to_str( s64 value, char* string, s32 base ); + void u64_to_str( u64 value, char* string, s32 base ); + + ZPL_IMPL_INLINE const char* char_first_occurence( const char* s, char c ) + { + char ch = c; + for ( ; *s != ch; s++ ) + { + if ( *s == '\0' ) + return NULL; + } + return s; + } + + ZPL_IMPL_INLINE b32 char_is_alpha( char c ) + { + if ( ( c >= 'A' && c <= 'Z' ) || ( c >= 'a' && c <= 'z' ) ) + return true; + return false; + } + + ZPL_IMPL_INLINE b32 char_is_alphanumeric( char c ) + { + return char_is_alpha( c ) || char_is_digit( c ); + } + + ZPL_IMPL_INLINE b32 char_is_digit( char c ) + { + if ( c >= '0' && c <= '9' ) + return true; + return false; + } + + ZPL_IMPL_INLINE b32 char_is_hex_digit( char c ) + { + if ( char_is_digit( c ) || ( c >= 'a' && c <= 'f' ) || ( c >= 'A' && c <= 'F' ) ) + return true; + return false; + } + + ZPL_IMPL_INLINE b32 char_is_space( char c ) + { + if ( c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v' ) + return true; + return false; + } + + ZPL_IMPL_INLINE char char_to_lower( char c ) + { + if ( c >= 'A' && c <= 'Z' ) + return 'a' + ( c - 'A' ); + return c; + } + + ZPL_IMPL_INLINE char char_to_upper( char c ) + { + if ( c >= 'a' && c <= 'z' ) + return 'A' + ( c - 'a' ); + return c; + } + + ZPL_IMPL_INLINE s32 digit_to_int( char c ) + { + return char_is_digit( c ) ? c - '0' : c - 'W'; + } + + ZPL_IMPL_INLINE s32 hex_digit_to_int( char c ) + { + if ( char_is_digit( c ) ) + return digit_to_int( c ); + else if ( is_between( c, 'a', 'f' ) ) + return c - 'a' + 10; + else if ( is_between( c, 'A', 'F' ) ) + return c - 'A' + 10; + return -1; + } + + ZPL_IMPL_INLINE s32 str_compare( const char* s1, const char* s2 ) + { + while ( *s1 && ( *s1 == *s2 ) ) + { + s1++, s2++; + } + return *( u8* )s1 - *( u8* )s2; + } + + ZPL_IMPL_INLINE s32 str_compare( const char* s1, const char* s2, sw len ) + { + for ( ; len > 0; s1++, s2++, len-- ) + { + if ( *s1 != *s2 ) + return ( ( s1 < s2 ) ? -1 : +1 ); + else if ( *s1 == '\0' ) + return 0; + } + return 0; + } + + ZPL_IMPL_INLINE char* str_copy( char* dest, const char* source, sw len ) + { + ZPL_ASSERT_NOT_NULL( dest ); + if ( source ) + { + char* str = dest; + while ( len > 0 && *source ) + { + *str++ = *source++; + len--; + } + while ( len > 0 ) + { + *str++ = '\0'; + len--; + } + } + return dest; + } + + ZPL_IMPL_INLINE sw str_copy_nulpad( char* dest, const char* source, sw len ) + { + sw result = 0; + ZPL_ASSERT_NOT_NULL( dest ); + if ( source ) + { + const char* source_start = source; + char* str = dest; + while ( len > 0 && *source ) + { + *str++ = *source++; + len--; + } + while ( len > 0 ) + { + *str++ = '\0'; + len--; + } + + result = source - source_start; + } + return result; + } + + ZPL_IMPL_INLINE sw str_len( const char* str ) + { + if ( str == NULL ) + { + return 0; + } + const char* p = str; + while ( *str ) + str++; + return str - p; + } + + ZPL_IMPL_INLINE sw str_len( const char* str, sw max_len ) + { + const char* end = zpl_cast( const char* ) mem_find( str, 0, max_len ); + if ( end ) + return end - str; + return max_len; + } + + ZPL_IMPL_INLINE char* str_reverse( char* str ) + { + sw len = str_len( str ); + char* a = str + 0; + char* b = str + len - 1; + len /= 2; + while ( len-- ) + { + swap( char, *a, *b ); + a++, b--; + } + return str; + } + + ZPL_IMPL_INLINE void str_to_lower( char* str ) + { + if ( ! str ) + return; + while ( *str ) + { + *str = char_to_lower( *str ); + str++; + } + } + + ZPL_IMPL_INLINE void str_to_upper( char* str ) + { + if ( ! str ) + return; + while ( *str ) + { + *str = char_to_upper( *str ); + str++; + } + } + #pragma endregion String Ops + #pragma region Containers #pragma push_macro("template") #undef template @@ -551,7 +1014,6 @@ namespace gen { Data[ idx ] = value; } - // mem_set( Data + begin, value, end - begin) return true; } @@ -618,6 +1080,8 @@ namespace gen { if ( ! grow( num ) ) return false; + + header = get_header(); } header->Num = num; @@ -635,7 +1099,7 @@ namespace gen header.Num = new_capacity; sw size = sizeof( Header ) + sizeof( Type ) * new_capacity; - Header* new_header = reinterpret_cast< Header* >( alloc( header.Allocator, size ) ); + Header* new_header = rcast( Header*, alloc( header.Allocator, size ) ); if ( new_header == nullptr ) return false; @@ -703,6 +1167,19 @@ namespace gen return result; } + static + HashTable init_reserve( AllocatorInfo allocator, sw num ) + { + HashTable result = { { nullptr }, { nullptr } }; + + result.Hashes = Array::init_reserve( allocator, num ); + result.Hashes.get_header()->Num = num; + + result.Entries = Array::init_reserve( allocator, num ); + + return result; + } + void clear( void ) { for ( sw idx = 0; idx < Hashes.num(); idx++ ) @@ -764,10 +1241,7 @@ namespace gen sw idx; sw last_added_index; - HashTable new_ht = init( Hashes.get_header()->Allocator ); - - new_ht.Hashes.resize( new_num ); - new_ht.Entries.reserve( new_ht.Hashes.num() ); + HashTable new_ht = init_reserve( Hashes.get_header()->Allocator, new_num ); Array::Header* hash_header = new_ht.Hashes.get_header(); @@ -798,8 +1272,6 @@ namespace gen } destroy(); - // Hashes = new_ht.Hashes; - // Entries = new_ht.Entries; *this = new_ht; } @@ -926,6 +1398,12 @@ namespace gen #pragma pop_macro("template") #pragma endregion Containers + #pragma region Hashing + + u32 crc32( void const* data, sw len ); + + #pragma endregion Hashing + #pragma region String // Constant string with length. struct StrC @@ -933,18 +1411,20 @@ namespace gen sw Len; char const* Ptr; - static constexpr - StrC from( char const* str ) - { - return { str_len( str ), str }; - } - operator char const* () const { return Ptr; } }; + #define txt_StrC( text ) \ + (StrC){ sizeof( text ) - 1, text } + + StrC to_StrC( char const* str ) + { + return { str_len( str ), str }; + } + // Dynamic String // This is directly based off the ZPL string api. // They used a header pattern @@ -1023,29 +1503,10 @@ namespace gen } static - String fmt( AllocatorInfo allocator, char* buf, sw buf_size, char const* fmt, ... ) - { - va_list va; - va_start( va, fmt ); - str_fmt_va( buf, buf_size, fmt, va ); - va_end( va ); - - return make( allocator, buf ); - } + String fmt( AllocatorInfo allocator, char* buf, sw buf_size, char const* fmt, ... ); static - String fmt_buf( AllocatorInfo allocator, char const* fmt, ... ) - { - local_persist thread_local - char buf[ ZPL_PRINTF_MAXLEN ] = { 0 }; - - va_list va; - va_start( va, fmt ); - str_fmt_va( buf, ZPL_PRINTF_MAXLEN, fmt, va ); - va_end( va ); - - return make( allocator, buf ); - } + String fmt_buf( AllocatorInfo allocator, char const* fmt, ... ); static String join( AllocatorInfo allocator, char const** parts, sw num_parts, char const* glue ) @@ -1151,18 +1612,7 @@ namespace gen return append( other.Data, other.length() ); } - bool append_fmt( char const* fmt, ... ) - { - sw res; - char buf[ ZPL_PRINTF_MAXLEN ] = { 0 }; - - va_list va; - va_start( va, fmt ); - res = str_fmt_va( buf, count_of( buf ) - 1, fmt, va ) - 1; - va_end( va ); - - return append( buf, res ); - } + bool append_fmt( char const* fmt, ... ); sw avail_space() const { @@ -1424,6 +1874,22 @@ namespace gen DirEntry* Dir; }; + enum FileStandardType + { + EFileStandard_INPUT, + EFileStandard_OUTPUT, + EFileStandard_ERROR, + + EFileStandard_COUNT, + }; + + /** + * Get standard file I/O. + * @param std Check zpl_file_standard_type + * @return File handle to standard I/O + */ + FileInfo* file_get_standard( FileStandardType std ); + /** * Closes the file * @param file @@ -1533,6 +1999,7 @@ namespace gen { if ( ! f->Ops.read_at ) f->Ops = default_file_operations; + return f->Ops.write_at( f->FD, buffer, size, offset, bytes_written ); } @@ -1540,6 +2007,17 @@ namespace gen #pragma endregion File Handling + #pragma region Printing + + // NOTE: A locally persisting buffer is used internally + char* str_fmt_buf( char const* fmt, ... ); + char* str_fmt_buf_va( char const* fmt, va_list va ); + sw str_fmt_va( char* str, sw n, char const* fmt, va_list va ); + sw str_fmt_out_va( char const* fmt, va_list va ); + sw str_fmt_file_va( FileInfo* f, char const* fmt, va_list va ); + + #pragma endregion Printing + namespace Memory { // NOTE: This limits the size of the string that can be read from a file or generated to 10 megs. @@ -1556,7 +2034,6 @@ namespace gen void cleanup(); } - inline sw log_fmt(char const* fmt, ...) { diff --git a/project/gen.cpp b/project/gen.cpp index 1e45c0a..84b9036 100644 --- a/project/gen.cpp +++ b/project/gen.cpp @@ -1097,7 +1097,7 @@ namespace gen } Code::Global = make_code(); - Code::Global->Name = get_cached_string( name("Global Code") ); + Code::Global->Name = get_cached_string( txt_StrC("Global Code") ); Code::Global->Content = Code::Global->Name; Code::Invalid = make_code(); @@ -1139,34 +1139,34 @@ namespace gen access_private = make_code(); access_private->Type = ECode::Access_Private; - access_private->Name = get_cached_string( StrC::from("private:") ); + access_private->Name = get_cached_string( txt_StrC("private:") ); access_private.set_global(); access_protected = make_code(); access_protected->Type = ECode::Access_Protected; - access_protected->Name = get_cached_string( StrC::from("protected:") ); + access_protected->Name = get_cached_string( txt_StrC("protected:") ); access_protected.set_global(); access_public = make_code(); access_public->Type = ECode::Access_Public; - access_public->Name = get_cached_string( StrC::from("public:") ); + access_public->Name = get_cached_string( txt_StrC("public:") ); access_public.set_global(); module_global_fragment = make_code(); module_global_fragment->Type = ECode::Untyped; - module_global_fragment->Name = get_cached_string( StrC::from("module;") ); + module_global_fragment->Name = get_cached_string( txt_StrC("module;") ); module_global_fragment->Content = module_global_fragment->Name; module_global_fragment.set_global(); module_private_fragment = make_code(); module_private_fragment->Type = ECode::Untyped; - module_private_fragment->Name = get_cached_string( StrC::from("module : private;") ); + module_private_fragment->Name = get_cached_string( txt_StrC("module : private;") ); module_private_fragment->Content = module_private_fragment->Name; module_private_fragment.set_global(); pragma_once = make_code(); pragma_once->Type = ECode::Untyped; - pragma_once->Name = get_cached_string( StrC::from("#pragma once") ); + pragma_once->Name = get_cached_string( txt_StrC("#pragma once") ); pragma_once->Content = pragma_once->Name; pragma_once.set_global(); @@ -1733,13 +1733,13 @@ namespace gen { \ if ( Name_.Len <= 0 ) \ { \ - log_failure( "gen::" txt(Context_) ": Invalid name length provided - %d", Name_.Len ); \ + log_failure( "gen::" stringize(Context_) ": Invalid name length provided - %d", Name_.Len ); \ return Code::Invalid; \ } \ \ if ( Name_.Ptr == nullptr ) \ { \ - log_failure( "gen::" txt(Context_) ": name is null" ); \ + log_failure( "gen::" stringize(Context_) ": name is null" ); \ return Code::Invalid; \ } \ } @@ -1747,7 +1747,7 @@ namespace gen # define null_check( Context_, Code_ ) \ if ( ! Code_ ) \ { \ - log_failure( "gen::" txt(Context_) ": " txt(Code_) " provided is null" ); \ + log_failure( "gen::" stringize(Context_) ": " stringize(Code_) " provided is null" ); \ return Code::Invalid; \ } @@ -1755,13 +1755,13 @@ namespace gen { \ if ( ! Code_ ) \ { \ - log_failure( "gen::" txt(Context_) ": " txt(Code_) " provided is null" ); \ + log_failure( "gen::" stringize(Context_) ": " stringize(Code_) " provided is null" ); \ return Code::Invalid; \ } \ \ if ( Code_->is_invalid() ) \ { \ - log_failure("gen::" txt(Context_) ": " txt(Code_) " provided is invalid" ); \ + log_failure("gen::" stringize(Context_) ": " stringize(Code_) " provided is invalid" ); \ return Code::Invalid; \ } \ } @@ -2633,7 +2633,7 @@ namespace gen \ if ( num <= 0 ) \ { \ - log_failure("gen::" txt(Name_) ": num cannot be zero or negative"); \ + log_failure("gen::" stringize(Name_) ": num cannot be zero or negative"); \ return Code::Invalid; \ } @@ -2642,7 +2642,7 @@ namespace gen \ if ( num <= 0 ) \ { \ - log_failure("gen::" txt(Name_) ": num cannot be zero or negative"); \ + log_failure("gen::" stringize(Name_) ": num cannot be zero or negative"); \ return Code::Invalid; \ } \ \ @@ -2660,7 +2660,7 @@ namespace gen \ if ( ! entry ) \ { \ - log_failure("gen::" txt(Name_) ": Provided an null entry"); \ + log_failure("gen::" stringize(Name_) ": Provided an null entry"); \ return Code::Invalid; \ } \ \ @@ -2674,7 +2674,7 @@ namespace gen \ if ( ! entry ) \ { \ - log_failure("gen::" txt(Name_) ": Provided an null entry"); \ + log_failure("gen::" stringize(Name_) ": Provided an null entry"); \ return Code::Invalid; \ } \ \ @@ -2682,7 +2682,7 @@ namespace gen { # define def_body_code_validation_end( Name_ ) \ - log_failure("gen::" txt(Name_) ": Entry type is not allowed: %s", entry->debug_str() ); \ + log_failure("gen::" stringize(Name_) ": Entry type is not allowed: %s", entry->debug_str() ); \ return Code::Invalid; \ \ default: \ @@ -3451,7 +3451,7 @@ namespace gen local_persist thread_local Array Tokens = { nullptr }; - s32 left = content.Len -1; + s32 left = content.Len; char const* scanner = content.Ptr; char const* word = scanner; @@ -3898,16 +3898,16 @@ namespace gen } #pragma region Helper Macros -# define check_parse_args( func, def ) \ - if ( def.Len <= 0 ) \ - { \ - log_failure( "gen::" txt(func) ": length must greater than 0" ); \ - return Code::Invalid; \ - } \ - if ( def.Ptr == nullptr ) \ - { \ - log_failure( "gen::" txt(func) ": def was null" ); \ - return Code::Invalid; \ +# define check_parse_args( func, def ) \ + if ( def.Len <= 0 ) \ + { \ + log_failure( "gen::" stringize(func) ": length must greater than 0" ); \ + return Code::Invalid; \ + } \ + if ( def.Ptr == nullptr ) \ + { \ + log_failure( "gen::" stringize(func) ": def was null" ); \ + return Code::Invalid; \ } # define nexttok toks.next() @@ -3950,13 +3950,13 @@ namespace gen if ( left == 0 ) { - log_failure( "%s: Error, unexpected end of typedef definition ( '[]' scope started )", txt(parse_typedef) ); + log_failure( "%s: Error, unexpected end of typedef definition ( '[]' scope started )", stringize(parse_typedef) ); return Code::Invalid; } if ( currtok.Type == TokType::BraceSquare_Close ) { - log_failure( "%s: Error, empty array expression in typedef definition", txt(parse_typedef) ); + log_failure( "%s: Error, empty array expression in typedef definition", stringize(parse_typedef) ); return Code::Invalid; } @@ -3973,13 +3973,13 @@ namespace gen if ( left == 0 ) { - log_failure( "%s: Error, unexpected end of type definition, expected ]", txt(parse_typedef) ); + log_failure( "%s: Error, unexpected end of type definition, expected ]", stringize(parse_typedef) ); return Code::Invalid; } if ( currtok.Type != TokType::BraceSquare_Close ) { - log_failure( "%s: Error, expected ] in type definition, not %s", txt(parse_typedef), str_tok_type( currtok.Type ) ); + log_failure( "%s: Error, expected ] in type definition, not %s", stringize(parse_typedef), str_tok_type( currtok.Type ) ); return Code::Invalid; } @@ -4179,12 +4179,12 @@ namespace gen { using namespace Parser; - Code params = parse_params( toks, txt(parse_function) ); + Code params = parse_params( toks, stringize(parse_function) ); Code body = { nullptr }; if ( check( TokType::BraceCurly_Open ) ) { - body = parse_function_body( toks, txt(parse_function) ); + body = parse_function_body( toks, stringize(parse_function) ); if ( body == Code::Invalid ) return Code::Invalid; } @@ -4438,13 +4438,13 @@ namespace gen eat( TokType::Operator ); // Parse Params - Code params = parse_params( toks, txt(parse_operator) ); + Code params = parse_params( toks, stringize(parse_operator) ); // Parse Body Code body = { nullptr }; if ( check( TokType::BraceCurly_Open ) ) { - body = parse_function_body( toks, txt(parse_function) ); + body = parse_function_body( toks, stringize(parse_function) ); if ( body == Code::Invalid ) return Code::Invalid; } @@ -4471,7 +4471,7 @@ namespace gen { using namespace Parser; - Code array_expr = parse_array_decl( toks, txt(parse_variable) ); + Code array_expr = parse_array_decl( toks, stringize(parse_variable) ); Code expr = Code::Invalid; @@ -4561,7 +4561,7 @@ namespace gen Code result = Code::Invalid; - Code type = parse_type( toks, txt(parse_variable) ); + Code type = parse_type( toks, stringize(parse_variable) ); if ( type == Code::Invalid ) return Code::Invalid; @@ -4569,7 +4569,7 @@ namespace gen if ( check( TokType::Operator) ) { // Dealing with an operator overload - result = parse_operator_after_ret_type( ModuleFlag::None, attributes, specifiers, type, toks, txt(parse_template) ); + result = parse_operator_after_ret_type( ModuleFlag::None, attributes, specifiers, type, toks, stringize(parse_template) ); } else { @@ -4580,7 +4580,7 @@ namespace gen { // Dealing with a function - result = parse_function_after_name( ModuleFlag::None, attributes, specifiers, type, name, toks, txt(parse_template) ); + result = parse_function_after_name( ModuleFlag::None, attributes, specifiers, type, name, toks, stringize(parse_template) ); } else { @@ -4591,7 +4591,7 @@ namespace gen } // Dealing with a variable - result = parse_variable_after_name( ModuleFlag::None, attributes, specifiers, type, name, toks, txt(parse_template) ); + result = parse_variable_after_name( ModuleFlag::None, attributes, specifiers, type, name, toks, stringize(parse_template) ); } } @@ -4746,7 +4746,7 @@ namespace gen break; default: - log_failure( "gen::parse_class_struct_body: invalid specifier " txt(spec) " for variable" ); + log_failure( "gen::parse_class_struct_body: invalid specifier " "%s" " for variable", ESpecifier::to_str(spec) ); return Code::Invalid; } @@ -4948,7 +4948,7 @@ namespace gen case TokType::Decl_Extern_Linkage: if ( which == Extern_Linkage_Body ) - log_failure( "gen::parse_extern_link_body: nested extern linkage" ); + log_failure( "gen::parse_global_nspace: nested extern linkage" ); member = parse_extern_link_body( toks, context ); break; @@ -4979,7 +4979,7 @@ namespace gen case TokType::Module_Export: if ( which == Export_Body ) - log_failure( "gen::parse_extern_link_body: nested export declaration" ); + log_failure( "gen::parse_global_nspace: nested export declaration" ); member = parse_export_body( toks, context ); break; @@ -5054,7 +5054,7 @@ namespace gen break; default: - log_failure( "gen::parse_class_struct_body: invalid specifier " txt(spec) " for variable" ); + log_failure( "gen::parse_global_nspace: invalid specifier " "%s" " for variable", ESpecifier::to_str(spec) ); return Code::Invalid; } @@ -5110,7 +5110,7 @@ namespace gen if ( toks.Arr == nullptr ) return Code::Invalid; - return parse_class_struct( TokType::Decl_Class, toks, txt(parse_class) ); + return parse_class_struct( TokType::Decl_Class, toks, stringize(parse_class) ); } internal @@ -5155,7 +5155,7 @@ namespace gen { eat( TokType::Assign_Classifer ); - type = parse_type( toks, txt(parse_enum) ); + type = parse_type( toks, stringize(parse_enum) ); if ( type == Code::Invalid ) return Code::Invalid; } @@ -5229,7 +5229,7 @@ namespace gen if ( toks.Arr == nullptr ) return Code::Invalid; - return parse_enum( toks, txt(parse_enum) ); + return parse_enum( toks, stringize(parse_enum) ); } internal inline @@ -5247,7 +5247,7 @@ namespace gen if ( toks.Arr == nullptr ) return Code::Invalid; - return parse_export_body( toks, txt(parse_export_body) ); + return parse_export_body( toks, stringize(parse_export_body) ); } internal inline @@ -5295,7 +5295,7 @@ namespace gen if ( toks.Arr == nullptr ) return Code::Invalid; - return parse_extern_link( toks, txt(parse_extern_link) ); + return parse_extern_link( toks, stringize(parse_extern_link) ); } internal @@ -5309,7 +5309,7 @@ namespace gen Code function = { nullptr }; // Type declaration or return type - Code type = parse_type( toks, txt(parse_friend) ); + Code type = parse_type( toks, stringize(parse_friend) ); if ( type == Code::Invalid ) return Code::Invalid; @@ -5317,10 +5317,10 @@ namespace gen if ( currtok.Type == TokType::Identifier ) { // Name - Token name = parse_identifier( toks, txt(parse_friend) ); + Token name = parse_identifier( toks, stringize(parse_friend) ); // Parameter list - Code params = parse_params( toks, txt(parse_friend) ); + Code params = parse_params( toks, stringize(parse_friend) ); function = make_code(); function->Type = Function_Fwd; @@ -5355,7 +5355,7 @@ namespace gen if ( toks.Arr == nullptr ) return Code::Invalid; - return parse_friend( toks, txt(parse_friend) ); + return parse_friend( toks, stringize(parse_friend) ); } internal @@ -5388,7 +5388,7 @@ namespace gen break; default: - log_failure( "gen::parse_variable: invalid specifier " txt(spec) " for variable" ); + log_failure( "gen::parse_functon: invalid specifier " "%s" " for functon", ESpecifier::to_str(spec) ); return Code::Invalid; } @@ -5402,11 +5402,11 @@ namespace gen specifiers = def_specifiers( num_specifiers, specs_found ); } - Code ret_type = parse_type( toks, txt(parse_function) ); + Code ret_type = parse_type( toks, stringize(parse_function) ); if ( ret_type == Code::Invalid ) return Code::Invalid; - Token name = parse_identifier( toks, txt(parse_function) ); + Token name = parse_identifier( toks, stringize(parse_function) ); if ( ! name ) return Code::Invalid; @@ -5425,7 +5425,7 @@ namespace gen if ( toks.Arr == nullptr ) return Code::Invalid; - return parse_functon( toks, txt(parse_function) ); + return parse_functon( toks, stringize(parse_function) ); } Code parse_global_body( StrC def ) @@ -5437,7 +5437,7 @@ namespace gen if ( toks.Arr == nullptr ) return Code::Invalid; - return parse_global_nspace( ECode::Global_Body, toks, txt(parse_global_body) ); + return parse_global_nspace( ECode::Global_Body, toks, stringize(parse_global_body) ); } internal @@ -5446,9 +5446,9 @@ namespace gen using namespace Parser; eat( TokType::Decl_Namespace ); - Token name = parse_identifier( toks, txt(parse_namespace) ); + Token name = parse_identifier( toks, stringize(parse_namespace) ); - Code body = parse_global_nspace( ECode::Namespace_Body, toks, txt(parse_namespace) ); + Code body = parse_global_nspace( ECode::Namespace_Body, toks, stringize(parse_namespace) ); if ( body == Code::Invalid ) return Code::Invalid; @@ -5471,7 +5471,7 @@ namespace gen if ( toks.Arr == nullptr ) return Code::Invalid; - return parse_namespace( toks, txt(parse_namespace) ); + return parse_namespace( toks, stringize(parse_namespace) ); } internal @@ -5500,7 +5500,7 @@ namespace gen break; default: - log_failure( "gen::parse_variable: invalid specifier " txt(spec) " for variable" ); + log_failure( "gen::parse_operator: invalid specifier " "%s" " for operator", ESpecifier::to_str(spec) ); return Code::Invalid; } @@ -5515,7 +5515,7 @@ namespace gen } // Parse Return Type - Code ret_type = parse_type( toks, txt(parse_operator) ); + Code ret_type = parse_type( toks, stringize(parse_operator) ); Code result = parse_operator_after_ret_type( ModuleFlag::None, attributes, specifiers, ret_type, toks, context ); return result; @@ -5530,7 +5530,7 @@ namespace gen if ( toks.Arr == nullptr ) return Code::Invalid; - return parse_operator( toks, txt(parse_operator) ); + return parse_operator( toks, stringize(parse_operator) ); } Code parse_operator_cast( Parser::TokArray& toks, char const* context ) @@ -5539,7 +5539,7 @@ namespace gen eat( TokType::Decl_Operator ); - Code type = parse_type( toks, txt(parse_operator_cast) ); + Code type = parse_type( toks, stringize(parse_operator_cast) ); eat( TokType::Capture_Start ); eat( TokType::Capture_End ); @@ -5597,13 +5597,13 @@ namespace gen if ( toks.Arr == nullptr ) return Code::Invalid; - return parse_operator_cast( toks, txt(parse_operator_cast) ); + return parse_operator_cast( toks, stringize(parse_operator_cast) ); } internal inline Code parse_struct( Parser::TokArray& toks, char const* context ) { - return parse_class_struct( Parser::TokType::Decl_Struct, toks, txt(parse_struct) ); + return parse_class_struct( Parser::TokType::Decl_Struct, toks, stringize(parse_struct) ); } Code parse_struct( StrC def ) @@ -5615,7 +5615,7 @@ namespace gen if ( toks.Arr == nullptr ) return Code::Invalid; - return parse_class_struct( TokType::Decl_Struct, toks, txt(parse_struct) ); + return parse_class_struct( TokType::Decl_Struct, toks, stringize(parse_struct) ); } internal @@ -5629,7 +5629,7 @@ namespace gen eat( TokType::Decl_Template ); - Code params = parse_params( toks, txt(parse_template), UseTemplateCapture ); + Code params = parse_params( toks, stringize(parse_template), UseTemplateCapture ); if ( params == Code::Invalid ) return Code::Invalid; @@ -5639,19 +5639,19 @@ namespace gen { if ( check( TokType::Decl_Class ) ) { - definition = parse_class( toks, txt(parse_template) ); + definition = parse_class( toks, stringize(parse_template) ); break; } if ( check( TokType::Decl_Struct ) ) { - definition = parse_enum( toks, txt(parse_template) ); + definition = parse_enum( toks, stringize(parse_template) ); break; } if ( check( TokType::Decl_Using )) { - definition = parse_using( toks, txt(parse_template) ); + definition = parse_using( toks, stringize(parse_template) ); break; } @@ -5693,7 +5693,7 @@ namespace gen break; default: - log_failure( "gen::parse_template: invalid specifier " txt(spec) " for variable or function" ); + log_failure( "gen::parse_template: invalid specifier %s for variable or function", ESpecifier::to_str( spec ) ); return Code::Invalid; } @@ -5711,7 +5711,7 @@ namespace gen specifiers = def_specifiers( num_specifiers, specs_found ); } - definition = parse_operator_function_or_variable( expects_function, attributes, specifiers, toks, txt(parse_template) ); + definition = parse_operator_function_or_variable( expects_function, attributes, specifiers, toks, stringize(parse_template) ); break; } @@ -5734,7 +5734,7 @@ namespace gen if ( toks.Arr == nullptr ) return Code::Invalid; - return parse_template( toks, txt(parse_template) ); + return parse_template( toks, stringize(parse_template) ); } internal @@ -5915,7 +5915,7 @@ namespace gen if ( toks.Arr == nullptr ) return Code::Invalid; - Code result = parse_type( toks, txt(parse_type) ); + Code result = parse_type( toks, stringize(parse_type) ); return result; } @@ -5931,7 +5931,7 @@ namespace gen eat( TokType::Decl_Typedef ); - type = parse_type( toks, txt(parse_typedef) ); + type = parse_type( toks, stringize(parse_typedef) ); if ( ! check( TokType::Identifier ) ) { @@ -5942,7 +5942,7 @@ namespace gen name = currtok; eat( TokType::Identifier ); - array_expr = parse_array_decl( toks, txt(parse_typedef) ); + array_expr = parse_array_decl( toks, stringize(parse_typedef) ); eat( TokType::Statement_End ); @@ -5970,7 +5970,7 @@ namespace gen if ( toks.Arr == nullptr ) return Code::Invalid; - return parse_typedef( toks, txt(parse_typedef) ); + return parse_typedef( toks, stringize(parse_typedef) ); } internal @@ -6002,7 +6002,7 @@ namespace gen while ( ! check( TokType::BraceCurly_Close ) ) { - Code entry = parse_variable( toks, txt(parse_union) ); + Code entry = parse_variable( toks, stringize(parse_union) ); if ( entry ) body->add_entry( entry ); @@ -6036,7 +6036,7 @@ namespace gen if ( toks.Arr == nullptr ) return Code::Invalid; - return parse_union( toks, txt(parse_union) ); + return parse_union( toks, stringize(parse_union) ); } internal @@ -6072,10 +6072,10 @@ namespace gen eat( TokType::Operator ); - type = parse_type( toks, txt(parse_typedef) ); + type = parse_type( toks, stringize(parse_typedef) ); } - array_expr = parse_array_decl( toks, txt(parse_typedef) ); + array_expr = parse_array_decl( toks, stringize(parse_typedef) ); eat( TokType::Statement_End ); @@ -6104,7 +6104,7 @@ namespace gen if ( toks.Arr == nullptr ) return Code::Invalid; - return parse_using( toks, txt(parse_using) ); + return parse_using( toks, stringize(parse_using) ); } internal @@ -6144,7 +6144,7 @@ namespace gen break; default: - log_failure( "gen::parse_variable: invalid specifier " txt(spec) " for variable" ); + log_failure( "gen::parse_variable: invalid specifier %s for variable", ESpecifier::to_str( spec ) ); return Code::Invalid; } @@ -6162,7 +6162,7 @@ namespace gen specifiers = def_specifiers( num_specifiers, specs_found ); } - Code type = parse_type( toks, txt(parse_variable) ); + Code type = parse_type( toks, stringize(parse_variable) ); if ( type == Code::Invalid ) return Code::Invalid; @@ -6170,7 +6170,7 @@ namespace gen name = currtok; eat( TokType::Identifier ); - Code result = parse_variable_after_name( ModuleFlag::None, attributes, specifiers, type, name, toks, txt(parse_variable) ); + Code result = parse_variable_after_name( ModuleFlag::None, attributes, specifiers, type, name, toks, stringize(parse_variable) ); return result; } @@ -6184,7 +6184,7 @@ namespace gen if ( toks.Arr == nullptr ) return Code::Invalid; - return parse_variable( toks, txt(parse_variable) ); + return parse_variable( toks, stringize(parse_variable) ); } // Undef helper macros @@ -6197,42 +6197,31 @@ namespace gen #pragma endregion Parsing Constructors #pragma region Untyped Constructors - struct TokEntry - { - char const* Str; - sw Length; - }; - - sw token_fmt_va( char* buf, uw buf_size, char const* fmt, s32 num_tokens, va_list va ) + sw token_fmt_va( char* buf, uw buf_size, s32 num_tokens, va_list va ) { char const* buf_begin = buf; sw remaining = buf_size; - HashTable tok_map; + HashTable tok_map; { // TODO : Switch this to use an arena that makes use of the stack (cap the size of the token table to around 4096 bytes) - tok_map = HashTable::init( Memory::GlobalAllocator ); + tok_map = HashTable::init( Memory::GlobalAllocator ); - s32 left = num_tokens; + s32 left = num_tokens - 1; while ( left-- ) { char const* token = va_arg( va, char const* ); - char const* value = va_arg( va, char const* ); + StrC value = va_arg( va, StrC ); - TokEntry entry - { - value, - str_len(value, (sw)128) - }; + u32 key = crc32( token, str_len(token) ); - u32 key = crc32( token, str_len(token, 32) ); - - tok_map.set( key, entry ); + tok_map.set( key, value ); } } - char current = *fmt; + char const* fmt = va_arg( va, char const* ); + char current = *fmt; while ( current ) { @@ -6263,12 +6252,12 @@ namespace gen char const* token = fmt + 1; u32 key = crc32( token, tok_len ); - TokEntry* value = tok_map.get( key ); + StrC* value = tok_map.get( key ); if ( value ) { - sw left = value->Length; - char const* str = value->Str; + sw left = value->Len; + char const* str = value->Ptr; while ( left-- ) { @@ -6295,7 +6284,7 @@ namespace gen tok_map.clear(); - sw result = buf_size - remaining + 1; + sw result = buf_size - remaining; return result; } @@ -6330,21 +6319,21 @@ namespace gen return result; } - Code untyped_token_fmt( char const* fmt, s32 num_tokens, ... ) + Code untyped_token_fmt( s32 num_tokens, ... ) { local_persist thread_local char buf[ZPL_PRINTF_MAXLEN] = { 0 }; va_list va; - va_start(va, fmt); - sw length = token_fmt_va(buf, ZPL_PRINTF_MAXLEN, fmt, num_tokens, va); + va_start(va, num_tokens); + sw length = token_fmt_va(buf, ZPL_PRINTF_MAXLEN, num_tokens, va); va_end(va); Code result = make_code(); - result->Name = get_cached_string( { str_len(fmt, MaxNameLength), fmt } ); + result->Name = get_cached_string( { length, buf } ); result->Type = ECode::Untyped; - result->Content = get_cached_string( { length, buf } ); + result->Content = result->Name; return result; } diff --git a/project/gen.hpp b/project/gen.hpp index d626737..b1851c6 100644 --- a/project/gen.hpp +++ b/project/gen.hpp @@ -97,7 +97,7 @@ namespace gen { static StrC lookup[Num_Types] = { - # define Entry( Type ) { txt_to_StrC( Type ) }, + # define Entry( Type ) { sizeof(stringize(Type)), stringize(Type) }, Define_Types # undef Entry }; @@ -189,7 +189,7 @@ namespace gen { local_persist char const* lookup[ Num_Ops ] = { - # define Entry( Type_, Token_ ) txt(Token_), + # define Entry( Type_, Token_ ) stringize(Token_), Define_Operators # undef Entry "," @@ -252,7 +252,7 @@ namespace gen # define internal internal # define local_persist local_persist - # define Entry( Spec_, Code_ ) { txt_to_StrC(Code_) }, + # define Entry( Spec_, Code_ ) { sizeof(stringize(Code_)), stringize(Code_) }, Define_Specifiers # undef Entry @@ -352,9 +352,9 @@ namespace gen # define GEN_API_Import_Code __declspec(dllimport) # define GEN_Attribute_Keyword __declspec - constexpr char const* API_Export = txt( GEN_API_Export_Code ); - constexpr char const* API_Import = txt( GEN_API_Import_Code ); - constexpr char const* Keyword = txt( GEN_Attribute_Keyword); + constexpr char const* API_Export = stringize( GEN_API_Export_Code ); + constexpr char const* API_Import = stringize( GEN_API_Import_Code ); + constexpr char const* Keyword = stringize( GEN_Attribute_Keyword); #elif ZPL_HAS_ATTRIBUTE( visibility ) || ZPL_GCC_VERSION_CHECK( 3, 3, 0 ) || ZPL_INTEL_VERSION_CHECK( 13, 0, 0 ) # define GEN_API_Export_Code __attribute__ ((visibility ("default"))) @@ -501,7 +501,7 @@ namespace gen char const* debug_str() { - char const* fmt = txt( + char const* fmt = stringize( \nCode Debug: \nType : %s \nParent : %s @@ -773,26 +773,26 @@ namespace gen , ModuleFlag mflags = ModuleFlag::None ); Code def_class_body ( s32 num, ... ); - Code def_class_body ( s32 num, Code* codes ); Code def_enum_body ( s32 num, ... ); - Code def_enum_body ( s32 num, Code* codes ); Code def_export_body ( s32 num, ... ); - Code def_export_body ( s32 num, Code* codes); Code def_extern_link_body( s32 num, ... ); - Code def_extern_link_body( s32 num, Code* codes ); Code def_function_body ( s32 num, ... ); - Code def_function_body ( s32 num, Code* codes ); Code def_global_body ( s32 num, ... ); - Code def_global_body ( s32 num, Code* codes ); Code def_namespace_body ( s32 num, ... ); - Code def_namespace_body ( s32 num, Code* codes ); Code def_params ( s32 num, ... ); - Code def_params ( s32 num, Code* params ); - Code def_specifiers ( s32 num , ... ); - Code def_specifiers ( s32 num, SpecifierT* specs ); + Code def_specifiers ( s32 num, ... ); Code def_struct_body ( s32 num, ... ); - Code def_struct_body ( s32 num, Code* codes ); Code def_union_body ( s32 num, ... ); + Code def_class_body ( s32 num, Code* codes ); + Code def_enum_body ( s32 num, Code* codes ); + Code def_export_body ( s32 num, Code* codes); + Code def_extern_link_body( s32 num, Code* codes ); + Code def_function_body ( s32 num, Code* codes ); + Code def_global_body ( s32 num, Code* codes ); + Code def_namespace_body ( s32 num, Code* codes ); + Code def_params ( s32 num, Code* params ); + Code def_specifiers ( s32 num, SpecifierT* specs ); + Code def_struct_body ( s32 num, Code* codes ); Code def_union_body ( s32 num, Code* codes ); # pragma endregion Upfront @@ -819,18 +819,20 @@ namespace gen # pragma endregion Parsing # pragma region Untyped text - sw token_fmt_va( char* buf, uw buf_size, char const* fmt, s32 num_tokens, va_list va ); + sw token_fmt_va( char* buf, uw buf_size, s32 num_tokens, va_list va ); + //! Do not use directly. Use the token_fmt macro instead. + // Takes a format string (char const*) and a list of tokens (StrC) and returns a StrC of the formatted string. inline - StrC token_fmt( char const* fmt, sw num_tokens, ... ) + StrC _token_fmt( sw num, ... ) { local_persist thread_local char buf[ZPL_PRINTF_MAXLEN] = { 0 }; mem_set( buf, 0, ZPL_PRINTF_MAXLEN ); va_list va; - va_start(va, fmt); - sw result = token_fmt_va(buf, ZPL_PRINTF_MAXLEN, fmt, num_tokens, va); + va_start(va, num ); + sw result = token_fmt_va(buf, ZPL_PRINTF_MAXLEN, num, va); va_end(va); return { result, buf }; @@ -969,10 +971,15 @@ namespace gen // Convienence for defining any name used with the gen api. // Lets you provide the length and string literal to the functions without the need for the DSL. -# define name( Id_ ) { txt_to_StrC( Id_ ) } +# define name( Id_ ) { sizeof(stringize( Id_ )) - 1, stringize(Id_) } // Same as name just used to indicate intention of literal for code instead of names. -# define code( ... ) { txt_to_StrC( __VA_ARGS__ ) } +# define code( ... ) { sizeof(stringize(__VA_ARGS__)) - 1, stringize( __VA_ARGS__ ) } + +# define args( ... ) macro_num_args( __VA_ARGS__ ), __VA_ARGS__ + +// Takes a format string (char const*) and a list of tokens (StrC) and returns a StrC of the formatted string. +# define token_fmt( ... ) _token_fmt( (macro_num_args( __VA_ARGS__ ) + 1) / 2, __VA_ARGS__ ) #pragma endregion Macros #pragma region Constants diff --git a/scripts/build.ci.ps1 b/scripts/build.ci.ps1 index 5d4b3db..c3fb459 100644 --- a/scripts/build.ci.ps1 +++ b/scripts/build.ci.ps1 @@ -13,51 +13,45 @@ foreach ( $arg in $args ) } } +$path_root = git rev-parse --show-toplevel +$path_build = Join-Path $path_root build +$path_scripts = Join-Path $path_root scripts +$path_test = Join-Path $path_root test +$path_gen = Join-Path $path_test gen +$path_test_build = Join-Path $path_test build +$path_gen_build = Join-Path $path_gen build -$path_root = git rev-parse --show-toplevel -$path_build = Join-Path $path_root build -$path_scripts = Join-Path $path_root scripts +write-host "`n`nBuilding Test`n" +if ( -not( Test-Path $path_gen_build ) ) +{ +# Generate build files for meta-program +Push-Location $path_gen + $args_meson = @() + $args_meson += "setup" + $args_meson += $path_gen_build -# if ( $test -eq $true ) -# { - #region Test Build - write-host "`n`nBuilding Test`n" - - $path_test = Join-Path $path_root test - $path_gen = Join-Path $path_test gen - $path_test_build = Join-Path $path_test build - $path_gen_build = Join-Path $path_gen build - - # Generate files using metaprogram. - if ( -not( Test-Path $path_gen_build ) ) - { - $args_meson = @() - $args_meson += "setup" - $args_meson += $path_gen_build - - Push-Location $path_gen - & meson $args_meson - Pop-Location - } + & meson $args_meson +Pop-Location +} +# Compile meta-program +Push-Location $path_root $args_ninja = @() $args_ninja += "-C" $args_ninja += $path_gen_build - Push-Location $path_root & ninja $args_ninja - Pop-Location +Pop-Location - # Test NonParsed - if ($true) { +Push-location $path_gen +# Run meta-program $gencpp = Join-Path $path_gen_build gencpp.exe - Push-location $path_gen - - Write-Host `nGenerating files... + Write-Host `nGenerating files -- Parsed... & $gencpp +# Format generated files Write-Host `nBeginning format... $formatParams = @( '-i' # In-place @@ -72,60 +66,30 @@ $path_scripts = Join-Path $path_root scripts clang-format $formatParams $targetFiles Write-Host "`nFormatting complete" - Pop-Location - } +Pop-Location - # Test Parsed - if ($true) { - $gencpp = Join-Path $path_gen_build gencpp_parsed.exe +# Build the program depending on generated files. +if ( -not( Test-Path $path_test_build ) ) +{ +Push-Location $path_test + $args_meson = @() + $args_meson += "setup" + $args_meson += $path_test_build - Push-location $path_gen +# & meson $args_meson +Pop-Location +} - Write-Host `nGenerating files -- using Parse API... - & $gencpp +Push-Location $path_root + $args_ninja = @() + $args_ninja += "-C" + $args_ninja += $path_test_build - Write-Host `nBeginning format... - $formatParams = @( - '-i' # In-place - '-style=file' # Search for a .clang-format file in the parent directory of the source file. - '-verbose' - ) - - $include = @('*.gen.hpp', '*.gen.cpp') - $exclude = $null - - $targetFiles = @(Get-ChildItem -Recurse -Path $path_gen -Include $include -Exclude $exclude | Select-Object -ExpandProperty FullName) - - clang-format $formatParams $targetFiles - Write-Host "`nFormatting complete" - Pop-Location - } - - - # Build the program depending on generated files. - # if ( -not( Test-Path $path_test_build ) )k - # { - # $args_meson = @() - # $args_meson += "setup" - # $args_meson += $path_test_build - - # Push-Location $path_test - # & meson $args_meson - # Pop-Location - # } - - # $args_ninja = @() - # $args_ninja += "-C" - # $args_ninja += $path_test_build - - # Push-Location $path_root # ninja $args_ninja - # Pop-Location +Pop-Location - # $testcpp = Join-Path $path_test_build testcpp.exe +Push-Location $path_test + $testcpp = Join-Path $path_test_build testcpp.exe - # Push-Location $path_test # & $testcpp - # Pop-Location - # endregion Test Build -# } +Pop-Location diff --git a/.vscode/gencpp.natvis b/scripts/gencpp.natvis similarity index 100% rename from .vscode/gencpp.natvis rename to scripts/gencpp.natvis diff --git a/test/Parsed/Array.Parsed.hpp b/test/Parsed/Array.Parsed.hpp index 9ee4db1..baa5b86 100644 --- a/test/Parsed/Array.Parsed.hpp +++ b/test/Parsed/Array.Parsed.hpp @@ -32,8 +32,8 @@ Code gen__array( StrC type ) name = { name_len, name_str }; }; - Code array = parse_struct( token_fmt( - txt( + Code array = parse_struct( token_fmt( "ArrayType", name, "type", type, + stringize( struct { using Header = ArrayHeader; @@ -208,11 +208,7 @@ Code gen__array( StrC type ) return Data; } }; - ), - // Tokens - 2 - , "ArrayType", (char const*) name - , "type", (char const*) type + ) )); return array; @@ -226,7 +222,7 @@ struct GenArrayRequest }; Array GenArrayRequests; -void gen__array_request( StrC type, sw size, StrC dep = {} ) +void gen__array_request( StrC type, StrC dep = {} ) { do_once_start GenArrayRequests = Array::init( Memory::GlobalAllocator ); @@ -247,7 +243,7 @@ void gen__array_request( StrC type, sw size, StrC dep = {} ) GenArrayRequest request = { dep, type }; GenArrayRequests.append( request ); } -#define gen_array( type ) gen__array_request( { txt_to_StrC(type) }, sizeof(type) ) +#define gen_array( type ) gen__array_request( code(type) ) u32 gen_array_file() { @@ -255,9 +251,11 @@ u32 gen_array_file() gen_array_file; gen_array_file.open( "array.Parsed.gen.hpp" ); - Code include_zpl = def_include( StrC::from("Bloat.hpp") ); + Code include_zpl = def_include( txt_StrC("Bloat.hpp") ); gen_array_file.print( include_zpl ); + gen_array_file.print( def_using_namespace( name(gen))); + Code array_base = gen__array_base(); gen_array_file.print( array_base ); diff --git a/test/Parsed/Buffer.Parsed.hpp b/test/Parsed/Buffer.Parsed.hpp index e48d94a..7941e31 100644 --- a/test/Parsed/Buffer.Parsed.hpp +++ b/test/Parsed/Buffer.Parsed.hpp @@ -27,8 +27,8 @@ Code gen__buffer( StrC type ) name = { name_len, name_str }; }; - Code buffer = parse_struct( token_fmt( - txt( + Code buffer = parse_struct( token_fmt( "BufferName", name, "type", type, + stringize( struct { using Header = BufferHeader; @@ -123,10 +123,7 @@ Code gen__buffer( StrC type ) Type* Data; }; - ), - 2 - , "BufferName", (char const*) name - , "type", (char const*) type + ) )); return buffer; @@ -160,7 +157,7 @@ void gen__buffer_request( StrC type, StrC dep = {} ) GenBufferRequest request = { dep, type }; GenBufferRequests.append( request ); } -#define gen_buffer( type ) gen__buffer_request( { txt_to_StrC(type) } ) +#define gen_buffer( type ) gen__buffer_request( code(type) ) u32 gen_buffer_file() { @@ -168,7 +165,9 @@ u32 gen_buffer_file() gen_buffer_file; gen_buffer_file.open( "buffer.Parsed.gen.hpp" ); - gen_buffer_file.print( def_include( StrC::from("Bloat.hpp")) ); + gen_buffer_file.print( def_include( txt_StrC("Bloat.hpp")) ); + gen_buffer_file.print( def_using_namespace( name(gen))); + gen_buffer_file.print( gen__buffer_base() ); GenBufferRequest* current = GenBufferRequests; diff --git a/test/Parsed/HashTable.Parsed.hpp b/test/Parsed/HashTable.Parsed.hpp index 6147183..55033e0 100644 --- a/test/Parsed/HashTable.Parsed.hpp +++ b/test/Parsed/HashTable.Parsed.hpp @@ -18,7 +18,7 @@ Code gen__hashtable_base() )); } -Code gen__hashtable( StrC type, sw type_size ) +Code gen__hashtable( StrC type ) { StringCached name; { @@ -28,26 +28,23 @@ Code gen__hashtable( StrC type, sw type_size ) name = get_cached_string({ len, name_str }); } - Code ht_entry = parse_struct( token_fmt( - txt( + Code ht_entry = parse_struct( token_fmt( "HashTableName", (StrC)name, "type", type, + stringize( struct _Entry { u64 Key; sw Next; Value; }; - ), - 2 - , "HashTableName", (char const*) name - , "type", (char const*) type + ) )); - StringCached ht_entry_name = get_cached_string( token_fmt( "_Entry", 1, "HashTableName", name ) ); + StringCached ht_entry_name = get_cached_string( token_fmt( "HashTableName", (StrC)name, "_Entry" )); Code array_ht_entry = gen__array( ht_entry_name ); - Code hashtable = parse_struct( token_fmt( - txt( + Code hashtable = parse_struct( token_fmt( "HashTableName", (StrC)name, "type", type, + stringize( struct { using Type = ; @@ -275,10 +272,7 @@ Code gen__hashtable( StrC type, sw type_size ) return 0.75f * Hashes.num() < Entries.num(); } }; - ), - 2 - , "HashTableName", (char const*) name - , "type", (char const*) type + ) )); return def_global_body( 3, ht_entry, array_ht_entry, hashtable ); @@ -288,11 +282,10 @@ struct GenHashTableRequest { StrC Dependency; StrC Type; - sw TypeSize; }; Array GenHashTableRequests; -void gen__hashtable_request( StrC type, sw size, StrC dep = {} ) +void gen__hashtable_request( StrC type, StrC dep = {} ) { do_once_start GenHashTableRequests = Array::init( Memory::GlobalAllocator ); @@ -312,21 +305,24 @@ void gen__hashtable_request( StrC type, sw size, StrC dep = {} ) return; } - GenHashTableRequest request = { dep, type, size}; + GenHashTableRequest request = { dep, type }; GenHashTableRequests.append( request ); } -#define gen_hashtable( type ) gen__hashtable_request( { txt_to_StrC(type) }, sizeof( type )) +#define gen_hashtable( type ) gen__hashtable_request( code(type) ) u32 gen_hashtable_file() { Builder - gen_buffer_file; - gen_buffer_file.open( "hashtable.Parsed.gen.hpp" ); + gen_hashtable_file; + gen_hashtable_file.open( "hashtable.Parsed.gen.hpp" ); - gen_buffer_file.print( def_include( StrC::from("Bloat.hpp")) ); - gen_buffer_file.print( def_include( StrC::from("Array.Parsed.hpp")) ); - gen_buffer_file.print( def_include( StrC::from("array.Parsed.gen.hpp")) ); - gen_buffer_file.print( gen__hashtable_base()); + gen_hashtable_file.print( def_include( txt_StrC("Bloat.hpp")) ); + gen_hashtable_file.print( def_include( txt_StrC("Array.Parsed.hpp")) ); + gen_hashtable_file.print( def_include( txt_StrC("array.Parsed.gen.hpp")) ); + + gen_hashtable_file.print( def_using_namespace( name(gen))); + + gen_hashtable_file.print( gen__hashtable_base()); GenHashTableRequest* current = GenHashTableRequests; s32 left = GenHashTableRequests.num(); @@ -334,7 +330,7 @@ u32 gen_hashtable_file() { GenHashTableRequest const& request = * current; - Code generated_buffer = gen__hashtable( current->Type, current->TypeSize ); + Code generated_buffer = gen__hashtable( current->Type ); if ( request.Dependency ) { @@ -344,15 +340,15 @@ u32 gen_hashtable_file() Code cmt = def_comment( { cmt_len, cmt_str } ); Code include = def_include( request.Dependency ); - gen_buffer_file.print( cmt ); - gen_buffer_file.print( include ); + gen_hashtable_file.print( cmt ); + gen_hashtable_file.print( include ); } - gen_buffer_file.print( generated_buffer ); + gen_hashtable_file.print( generated_buffer ); current++; } - gen_buffer_file.write(); + gen_hashtable_file.write(); return 0; } diff --git a/test/Parsed/Ring.Parsed.hpp b/test/Parsed/Ring.Parsed.hpp index 5643011..5480577 100644 --- a/test/Parsed/Ring.Parsed.hpp +++ b/test/Parsed/Ring.Parsed.hpp @@ -10,7 +10,7 @@ Code gen__ring( StrC type ) { static Code t_allocator_info = def_type( name(AllocatorInfo) ); - String name; + StringCached name; { char const* name_str = str_fmt_buf( "Ring_%s\0", type.Ptr ); s32 name_len = str_len( name_str ); @@ -18,8 +18,10 @@ Code gen__ring( StrC type ) name = get_cached_string({ name_len, name_str }); }; - Code ring = parse_struct( token_fmt( - txt( + StrC buffer_name = to_StrC( str_fmt_buf( "Buffer_%s", type.Ptr )); + + Code ring = parse_struct( token_fmt( "RingName", (StrC)name, "type", type, "BufferName", buffer_name, + stringize( struct { using Type = ; @@ -87,11 +89,7 @@ Code gen__ring( StrC type ) uw Tail; Buffer; }; - ), - 3 - , "RingName", (char const*) name - , "type", (char const*) type - , "BufferName", str_fmt_buf( "Buffer_%s", type.Ptr ) + ) )); return ring; @@ -104,7 +102,7 @@ struct GenRingRequest }; Array GenRingRequests; -void gen__ring_request( StrC type, sw size, StrC dep = {} ) +void gen__ring_request( StrC type, StrC dep = {} ) { do_once_start GenRingRequests = Array::init( Memory::GlobalAllocator ); @@ -128,7 +126,7 @@ void gen__ring_request( StrC type, sw size, StrC dep = {} ) GenRingRequest request = { dep, type }; GenRingRequests.append( request ); } -#define gen_ring( type ) gen__ring_request( { txt_to_StrC(type) }, sizeof( type )) +#define gen_ring( type ) gen__ring_request( code(type) ) u32 gen_ring_file() { @@ -136,10 +134,12 @@ u32 gen_ring_file() gen_ring_file; gen_ring_file.open( "ring.Parsed.gen.hpp" ); - gen_ring_file.print( def_include( StrC::from("Bloat.hpp")) ); - gen_ring_file.print( def_include( StrC::from("buffer.Parsed.gen.hpp")) ); + gen_ring_file.print( def_include( txt_StrC("Bloat.hpp")) ); + gen_ring_file.print( def_include( txt_StrC("buffer.Parsed.gen.hpp")) ); // gen_ring_file.print( gen__ring_base() ); + gen_ring_file.print( def_using_namespace( name(gen))); + GenRingRequest* current = GenRingRequests; s32 left = GenRingRequests.num(); while (left--) diff --git a/test/Parsed/Sanity.Parsed.hpp b/test/Parsed/Sanity.Parsed.hpp index 9ecd11b..98c3dc4 100644 --- a/test/Parsed/Sanity.Parsed.hpp +++ b/test/Parsed/Sanity.Parsed.hpp @@ -10,7 +10,7 @@ u32 gen_sanity() gen_sanity_file; gen_sanity_file.open("./sanity.Parsed.gen.hpp"); - gen_sanity_file.print( def_comment( StrC::from( + gen_sanity_file.print( def_comment( txt_StrC( "The following will show a series of base cases for the gen parsed api.\n" ))); @@ -36,7 +36,7 @@ u32 gen_sanity() {}; )); - empty_body.body()->add_entry( def_comment( StrC::from("Empty class body") ) ); + empty_body.body()->add_entry( def_comment( txt_StrC("Empty class body") ) ); gen_sanity_file.print(fwd); gen_sanity_file.print(empty_body); @@ -72,7 +72,7 @@ u32 gen_sanity() // External Linkage { - Code empty_comment = def_comment( StrC::from("Empty external linkage") ); + Code empty_comment = def_comment( txt_StrC("Empty external linkage") ); Code c_extern = parse_extern_link( code( extern "C" @@ -118,7 +118,7 @@ u32 gen_sanity() } )); - def.body()->add_entry( def_comment( StrC::from("Empty function body") ) ); + def.body()->add_entry( def_comment( txt_StrC("Empty function body") ) ); gen_sanity_file.print(fwd); gen_sanity_file.print(def); @@ -134,7 +134,7 @@ u32 gen_sanity() } )); - def.body()->add_entry( def_comment( StrC::from("Empty namespace body") ) ); + def.body()->add_entry( def_comment( txt_StrC("Empty namespace body") ) ); gen_sanity_file.print(def); } @@ -201,7 +201,7 @@ u32 gen_sanity() } )); - def.body()->add_entry( def_comment( StrC::from("Empty function body") ) ); + def.body()->add_entry( def_comment( txt_StrC("Empty function body") ) ); gen_sanity_file.print(fwd); gen_sanity_file.print(def); @@ -237,7 +237,7 @@ u32 gen_sanity() {}; )); - empty_body.body()->add_entry( def_comment( StrC::from("Empty struct body") ) ); + empty_body.body()->add_entry( def_comment( txt_StrC("Empty struct body") ) ); gen_sanity_file.print(fwd); gen_sanity_file.print(empty_body); @@ -253,7 +253,7 @@ u32 gen_sanity() }; )); - empty.body()->add_entry( def_comment( StrC::from("Empty union body") ) ); + empty.body()->add_entry( def_comment( txt_StrC("Empty union body") ) ); gen_sanity_file.print( parse_typedef( code( typedef unsigned short u16; )) ); gen_sanity_file.print( parse_typedef( code( typedef unsigned long u32; )) ); @@ -330,7 +330,7 @@ u32 gen_sanity() gen_sanity_file.print_fmt("\n"); - gen_sanity_file.print( def_comment( StrC::from( + gen_sanity_file.print( def_comment( txt_StrC( "End of base case tests\n" ))); diff --git a/test/Readme.md b/test/Readme.md index 3579beb..45ca237 100644 --- a/test/Readme.md +++ b/test/Readme.md @@ -8,7 +8,4 @@ be better on in c++ as templates, since the templates they generate are trivial An exmaple of a non-trival generation is a container for elements with SOA or AOS policy for layout. (If a unified element syntax is desired) -The test is divided between two major sets of tests: Parsed and Nonparsed. - -Parsed uses the parsing api strictly. -NonParsed only uses the upfront and incremental constructors. +The test is divided between two major sets of tests: Parsed and Upfront. diff --git a/test/SOA.hpp b/test/SOA.hpp index c54e3ef..aca0340 100644 --- a/test/SOA.hpp +++ b/test/SOA.hpp @@ -30,17 +30,15 @@ Code gen_SOA( Code struct_def, bool use_dynamic = false ) Code entry_arr = { nullptr }; if ( use_dynamic) { - entry_arr = parse_variable( token_fmt( "Array<> ;", 2 - , "type", (char const*)var_type->Name - , "name", (char const*)struct_mem->Name ) - ); + entry_arr = parse_variable( token_fmt( "type", (StrC)var_type->Name, "name", (StrC)struct_mem->Name, + stringize( Array<> ; ) + )); } else { - entry_arr = parse_variable( token_fmt( " [100];", 2 - , "type", (char const*)var_type->Name - , "name", (char const*)struct_mem->Name ) - ); + entry_arr = parse_variable( token_fmt( "type", (StrC)var_type->Name, "name", (StrC)struct_mem->Name, + stringize( [100]; ) + )); } vars.append( entry_arr ); @@ -51,15 +49,14 @@ Code gen_SOA( Code struct_def, bool use_dynamic = false ) Code make; { - make = parse_function( token_fmt( - txt( - static - make( AllocatorInfo allocator ) - { - soa = {}; - } - ), - 1, "SOA_Type", (char const*)name + make = parse_function( token_fmt("SOA_Type", name, + stringize( + static + make( AllocatorInfo allocator ) + { + soa = {}; + } + ) )); if ( use_dynamic ) @@ -68,9 +65,8 @@ Code gen_SOA( Code struct_def, bool use_dynamic = false ) { Code member = vars[idx]; - Code arr_init = def_execution( token_fmt( "soa. = ::init( allocator );", 2 - , "var_name", (char const*)member->Name - , "var_type", (char const*)member->entry(0)->Name + Code arr_init = def_execution( token_fmt( "var_name", (StrC)member->Name, "var_type", (StrC)member->entry(0)->Name, + stringize( soa. = ::init( allocator ); ) )); make.body()->add_entry( arr_init ); @@ -94,8 +90,8 @@ Code gen_SOA( Code struct_def, bool use_dynamic = false ) { Code member = vars[idx]; - content.append_fmt( token_fmt( "[idx],", 1 - , "var_name", (char const*)member->Name + content.append_fmt( token_fmt( "var_name", (StrC)member->Name, + "[idx]," )); } diff --git a/test/NonParsed/Array.NonParsed.hpp b/test/Upfront/Array.Upfront.hpp similarity index 86% rename from test/NonParsed/Array.NonParsed.hpp rename to test/Upfront/Array.Upfront.hpp index 51b5fa6..01908a8 100644 --- a/test/NonParsed/Array.NonParsed.hpp +++ b/test/Upfront/Array.Upfront.hpp @@ -94,16 +94,18 @@ Code gen__array( StrC type ) Code append = def_function( name(append), def_param(t_alias, name(value)), t_bool , def_execution( code( - Header& header = get_header(); + Header* header = get_header(); - if ( header.Num == header.Capacity ) + if ( header->Num == header->Capacity ) { - if ( ! grow( header.Capacity )) + if ( ! grow( header->Capacity )) return false; + + header = get_header(); } - Data[ header.Num ] = value; - header.Num++; + Data[ header->Num ] = value; + header->Num++; return true; )) @@ -111,14 +113,14 @@ Code gen__array( StrC type ) Code back = def_function( name(back), __, t_alias_ref , def_execution( code( - Header& header = get_header(); + Header& header = * get_header(); return Data[ header.Num - 1 ]; )) ); Code clear = def_function( name(clear), __, t_void , def_execution( code( - Header& header = get_header(); + Header& header = * get_header(); header.Num = 0; )) ); @@ -132,7 +134,7 @@ Code gen__array( StrC type ) ); Code body = untyped_str( code( - Header& header = get_header(); + Header& header = * get_header(); if ( begin < 0 || end >= header.Num ) return false; @@ -150,20 +152,20 @@ Code gen__array( StrC type ) Code free = def_function( name(free), __, t_void , def_execution( code( - Header& header = get_header(); - zpl::free( header.Allocator, & header ); + Header* header = get_header(); + gen::free( header->Allocator, header ); )) ); - Code get_header = def_function( name(get_header), __, t_header_ref + Code get_header = def_function( name(get_header), __, t_header_ptr , def_execution( code( - return * ( rcast( Header*, Data ) - 1 ); + return rcast( Header*, Data ) - 1; )) ); Code grow = def_function( name(grow), def_param( t_uw, name(min_capacity)), t_bool , def_execution( code( - Header& header = get_header(); + Header& header = * get_header(); uw new_capacity = grow_formula( header.Capacity ); @@ -176,13 +178,13 @@ Code gen__array( StrC type ) Code num = def_function( name(num), __, t_uw , def_execution( code( - return get_header().Num; + return get_header()->Num; )) ); Code pop = def_function( name(pop), __, t_bool , def_execution( code( - Header& header = get_header(); + Header& header = * get_header(); ZPL_ASSERT( header.Num > 0 ); header.Num--; @@ -191,7 +193,7 @@ Code gen__array( StrC type ) Code remove_at = def_function( name(remove_at), def_param( t_uw, name(idx)), t_void , def_execution( code( - Header* header = & get_header(); + Header* header = get_header(); ZPL_ASSERT( idx < header->Num ); mem_move( header + idx, header + idx + 1, sizeof( Type ) * ( header->Num - idx - 1 ) ); @@ -201,7 +203,7 @@ Code gen__array( StrC type ) Code reserve = def_function( name(reserve), def_param( t_uw, name(new_capacity)), t_bool , def_execution( code( - Header& header = get_header(); + Header& header = * get_header(); if ( header.Capacity < new_capacity ) return set_capacity( new_capacity ); @@ -212,15 +214,17 @@ Code gen__array( StrC type ) Code resize = def_function( name(resize), def_param( t_uw, name(num)), t_bool , def_execution( code( - Header& header = get_header(); + Header* header = get_header(); - if ( num > header.Capacity ) + if ( num > header->Capacity ) { - if ( ! grow( header.Capacity )) + if ( ! grow( header->Capacity )) return false; + + header = get_header(); } - header.Num = num; + header->Num = num; return true; )) ); @@ -228,7 +232,7 @@ Code gen__array( StrC type ) Code set_capacity; { Code body = def_execution( code( - Header& header = get_header(); + Header& header = * get_header(); if ( new_capacity == header.Capacity ) return true; @@ -244,13 +248,11 @@ Code gen__array( StrC type ) mem_move( new_header, & header, sizeof( Header ) + sizeof(Type) * header.Num ); - new_header->Allocator = header.Allocator; - new_header->Num = header.Num; - new_header->Capacity = new_capacity; + new_header->Capacity = new_capacity; - zpl::free( header.Allocator, & header ); + gen::free( header.Allocator, & header ); - Data = (Type*) new_header + 1; + Data = rcast( Type*, new_header + 1); return true; )); @@ -323,17 +325,19 @@ void gen__array_request( StrC type, StrC dep = {} ) GenArrayRequest request = { dep, type }; GenArrayRequests.append( request ); } -#define gen_array( type ) gen__array_request( { txt_to_StrC(type) } ) +#define gen_array( type ) gen__array_request( code(type) ) u32 gen_array_file() { Builder gen_array_file; - gen_array_file.open( "array.NonParsed.gen.hpp" ); + gen_array_file.open( "array.Upfront.gen.hpp" ); - Code include_zpl = def_include( StrC::from("Bloat.hpp") ); + Code include_zpl = def_include( txt_StrC("Bloat.hpp") ); gen_array_file.print( include_zpl ); + gen_array_file.print( def_using_namespace( name(gen))); + Code array_base = gen__array_base(); gen_array_file.print( array_base ); diff --git a/test/NonParsed/Buffer.NonParsed.hpp b/test/Upfront/Buffer.Upfront.hpp similarity index 94% rename from test/NonParsed/Buffer.NonParsed.hpp rename to test/Upfront/Buffer.Upfront.hpp index 1c00fd8..70ad9d5 100644 --- a/test/NonParsed/Buffer.NonParsed.hpp +++ b/test/Upfront/Buffer.Upfront.hpp @@ -208,7 +208,7 @@ struct GenBufferRequest }; Array GenBufferRequests; -void gen__buffer_request( StrC type, sw size, StrC dep = {} ) +void gen__buffer_request( StrC type, StrC dep = {} ) { do_once_start GenBufferRequests = Array::init( Memory::GlobalAllocator ); @@ -226,18 +226,20 @@ void gen__buffer_request( StrC type, sw size, StrC dep = {} ) return; } - GenBufferRequest request = { dep, type, size}; + GenBufferRequest request = { dep, type}; GenBufferRequests.append( request ); } -#define gen_buffer( type ) gen__buffer_request( { txt_to_StrC(type) }, sizeof( type )) +#define gen_buffer( type ) gen__buffer_request( code(type)) u32 gen_buffer_file() { Builder gen_buffer_file; - gen_buffer_file.open( "buffer.NonParsed.gen.hpp" ); + gen_buffer_file.open( "buffer.Upfront.gen.hpp" ); + + gen_buffer_file.print( def_include( txt_StrC("Bloat.hpp")) ); + gen_buffer_file.print( def_using_namespace( name(gen)) ); - gen_buffer_file.print( def_include( StrC::from("Bloat.hpp")) ); gen_buffer_file.print( gen__buffer_base() ); GenBufferRequest* current = GenBufferRequests; diff --git a/test/NonParsed/HashTable.NonParsed.hpp b/test/Upfront/HashTable.Upfront.hpp similarity index 81% rename from test/NonParsed/HashTable.NonParsed.hpp rename to test/Upfront/HashTable.Upfront.hpp index 36f868d..5ed63bf 100644 --- a/test/NonParsed/HashTable.NonParsed.hpp +++ b/test/Upfront/HashTable.Upfront.hpp @@ -2,7 +2,7 @@ #if gen_time #include "gen.hpp" -#include "Array.NonParsed.hpp" +#include "Array.Upfront.hpp" using namespace gen; @@ -74,7 +74,7 @@ Code gen__hashtable( StrC type ) Code init; { - char const* tmpl = txt( + char const* tmpl = stringize( result = { 0 }; result.Hashes = Array_sw ::init( allocator ); @@ -82,11 +82,31 @@ Code gen__hashtable( StrC type ) return result; ); - Code body = def_execution( token_fmt( tmpl, 1, "type", name ) ); + Code body = def_execution( token_fmt( "type", (StrC)name, tmpl ) ); init = def_function( name(init), def_param( t_allocator_info, name(allocator)), t_ht_type, body, spec_static_member ); } + + Code init_reserve; + { + char const* tmpl = stringize( + result = { { nullptr }, { nullptr } }; + + result.Hashes = Array_sw::init_reserve( allocator, num ); + result.Hashes.get_header()->Num = num; + + result.Entries = Array_Entry::init_reserve( allocator, num ); + + return result; + ); + Code body = def_execution( token_fmt( "type", (StrC)name, tmpl ) ); + + Code params = def_params( 2, def_param( t_allocator_info, name(allocator)), def_param( t_sw, name(num))); + + init_reserve = def_function( name(init_reserve), params, t_ht_type, body, spec_static_member ); + } + Code clear = def_function( name(clear), __, t_void , def_execution( code( for ( s32 idx = 0; idx < Hashes.num(); idx++ ) @@ -98,9 +118,9 @@ Code gen__hashtable( StrC type ) Code destroy = def_function( name(destroy), __, t_void , def_execution( code( - if ( Hashes ) + if ( Hashes && Hashes.get_header()->Capacity ) Hashes.free(); - if ( Entries ) + if ( Entries && Hashes.get_header()->Capacity ) Entries.free(); )) ); @@ -108,7 +128,7 @@ Code gen__hashtable( StrC type ) Code get = def_function( name(get), def_param( t_u64, name(key)), t_type_ptr , def_execution( code( sw idx = find( key ).EntryIndex; - if ( idx > 0 ) + if ( idx >= 0 ) return & Entries[ idx ].Value; return nullptr; @@ -117,10 +137,10 @@ Code gen__hashtable( StrC type ) Code using_map_proc; { - char const* tmpl = txt( + char const* tmpl = stringize( void (*) ( u64 key, value ) ); - Code value = untyped_str( token_fmt( tmpl, 1, "type", t_type.to_string() ) ); + Code value = untyped_str( token_fmt( "type", (StrC)t_type.to_string(), tmpl ) ); using_map_proc = def_using ( name(MapProc), value); } @@ -143,10 +163,10 @@ Code gen__hashtable( StrC type ) Code using_map_mut_proc; { - char const* tmpl = txt( + char const* tmpl = stringize( void (*) ( u64 key, value ) ); - Code value = untyped_str( token_fmt( tmpl, 1, "type", t_type_ptr.to_string() ) ); + Code value = untyped_str( token_fmt( "type", (StrC)t_type_ptr.to_string(), tmpl ) ); using_map_mut_proc = def_using ( name(MapMutProc), value); } @@ -176,14 +196,13 @@ Code gen__hashtable( StrC type ) Code rehash; { - char const* tmpl = txt( + char const* tmpl = stringize( sw idx; sw last_added_index; - new_ht = ::init( Hashes.get_header().Allocator ); + new_ht = init_reserve( Hashes.get_header()->Allocator, new_num ); - new_ht.Hashes.resize( new_num ); - new_ht.Entries.reserve( new_ht.Hashes.num() ); + Array_sw::Header* hash_header = new_ht.Hashes.get_header(); for ( idx = 0; idx < new_ht.Hashes.num(); ++idx ) new_ht.Hashes[ idx ] = -1; @@ -211,22 +230,17 @@ Code gen__hashtable( StrC type ) new_ht.Entries[ last_added_index ].Value = entry.Value; } - // *this = new_ht; - - // old_ht.destroy(); - destroy(); - Hashes = new_ht.Hashes; - Entries = new_ht.Entries; + *this = new_ht; ); - Code body = def_execution( token_fmt( tmpl, 1, "type", name ) ); + Code body = def_execution( token_fmt( "type", (StrC)name, tmpl ) ); rehash = def_function( name(rehash), def_param( t_sw, name(new_num)), t_void, body ); } Code rehash_fast; { - char const* tmpl = txt( + char const* tmpl = stringize( sw idx; for ( idx = 0; idx < Entries.num(); idx++ ) @@ -242,7 +256,7 @@ Code gen__hashtable( StrC type ) FindResult find_result; } ); - Code body = def_execution( token_fmt( tmpl, 1, "type", name ) ); + Code body = def_execution( token_fmt( "type", name, tmpl ) ); rehash_fast = def_function( name(rehash_fast), __, t_void, body ); } @@ -358,7 +372,7 @@ Code gen__hashtable( StrC type ) )) ); - hashtable = def_struct( name, def_struct_body( 24 + hashtable = def_struct( name, def_struct_body( 25 , using_entry , using_array_entry , using_find_result @@ -366,6 +380,7 @@ Code gen__hashtable( StrC type ) , using_map_mut_proc , init + , init_reserve , clear , destroy @@ -423,19 +438,21 @@ void gen__hashtable_request( StrC type, StrC dep = {} ) GenHashTableRequest request = { dep, type }; GenHashTableRequests.append( request ); } -#define gen_hashtable( type ) gen__hashtable_request( { txt_to_StrC(type) } ) +#define gen_hashtable( type ) gen__hashtable_request( code(type)) u32 gen_hashtable_file() { Builder - gen_buffer_file; - gen_buffer_file.open( "hashtable.NonParsed.gen.hpp" ); + gen_hashtable_file; + gen_hashtable_file.open( "hashtable.Upfront.gen.hpp" ); - gen_buffer_file.print( def_include( StrC::from("Bloat.hpp")) ); - gen_buffer_file.print( def_include( StrC::from("Array.NonParsed.hpp")) ); - gen_buffer_file.print( def_include( StrC::from("array.NonParsed.gen.hpp")) ); + gen_hashtable_file.print( def_include( txt_StrC("Bloat.hpp")) ); + gen_hashtable_file.print( def_include( txt_StrC("Array.Upfront.hpp")) ); + gen_hashtable_file.print( def_include( txt_StrC("array.Upfront.gen.hpp")) ); - gen_buffer_file.print( gen__hashtable_base()); + gen_hashtable_file.print( def_using_namespace( name(gen))); + + gen_hashtable_file.print( gen__hashtable_base()); GenHashTableRequest* current = GenHashTableRequests; s32 left = GenHashTableRequests.num(); @@ -453,15 +470,15 @@ u32 gen_hashtable_file() Code cmt = def_comment( { cmt_len, cmt_str } ); Code include = def_include( request.Dependency ); - gen_buffer_file.print( cmt ); - gen_buffer_file.print( include ); + gen_hashtable_file.print( cmt ); + gen_hashtable_file.print( include ); } - gen_buffer_file.print( generated_buffer ); + gen_hashtable_file.print( generated_buffer ); current++; } - gen_buffer_file.write(); + gen_hashtable_file.write(); return 0; } diff --git a/test/NonParsed/Ring.NonParsed.hpp b/test/Upfront/Ring.Upfront.hpp similarity index 84% rename from test/NonParsed/Ring.NonParsed.hpp rename to test/Upfront/Ring.Upfront.hpp index fc3ae83..3634af4 100644 --- a/test/NonParsed/Ring.NonParsed.hpp +++ b/test/Upfront/Ring.Upfront.hpp @@ -2,11 +2,11 @@ #if gen_time #include "gen.hpp" -#include "Buffer.NonParsed.hpp" +#include "Buffer.Upfront.hpp" using namespace gen; -Code gen__ring( StrC type, sw type_size ) +Code gen__ring( StrC type ) { static Code t_allocator_info = def_type( name(AllocatorInfo) ); @@ -50,7 +50,7 @@ Code gen__ring( StrC type, sw type_size ) , def_param( t_uw, name(max_size) ) ); - char const* tmpl = txt( + char const* tmpl = stringize( result = { 0 }; result.Backing = allocator; @@ -64,10 +64,7 @@ Code gen__ring( StrC type, sw type_size ) return result; ); - Code body = def_execution( token_fmt( tmpl, 2 - , "type", (char const*)name - , "data_type", (char const*)type - )); + Code body = def_execution( token_fmt( "type", (StrC)name, "data_type", type, tmpl )); init = def_function( name(init), params, t_ring_type, body, spec_static_member ); } @@ -160,11 +157,10 @@ struct GenRingRequest { StrC Dependency; StrC Type; - sw TypeSize; }; Array GenRingRequests; -void gen__ring_request( StrC type, sw size, StrC dep = {} ) +void gen__ring_request( StrC type, StrC dep = {} ) { do_once_start GenRingRequests = Array::init( Memory::GlobalAllocator ); @@ -183,22 +179,23 @@ void gen__ring_request( StrC type, sw size, StrC dep = {} ) } // Ring definition depends on a array and buffer definition. - gen__buffer_request( type, size, dep ); + gen__buffer_request( type, dep ); - GenRingRequest request = { dep, type, size}; + GenRingRequest request = { dep, type }; GenRingRequests.append( request ); } -#define gen_ring( type ) gen__ring_request( { txt_to_StrC(type) }, sizeof( type )) +#define gen_ring( type ) gen__ring_request( code(type) ) u32 gen_ring_file() { Builder gen_ring_file; - gen_ring_file.open( "ring.NonParsed.gen.hpp" ); + gen_ring_file.open( "ring.Upfront.gen.hpp" ); - gen_ring_file.print( def_include( StrC::from("Bloat.hpp")) ); - gen_ring_file.print( def_include( StrC::from("buffer.NonParsed.gen.hpp")) ); - // gen_ring_file.print( gen__ring_base() ); + gen_ring_file.print( def_include( txt_StrC("Bloat.hpp")) ); + gen_ring_file.print( def_include( txt_StrC("buffer.Upfront.gen.hpp")) ); + + gen_ring_file.print( def_using_namespace( name(gen))); GenRingRequest* current = GenRingRequests; s32 left = GenRingRequests.num(); @@ -206,7 +203,7 @@ u32 gen_ring_file() { GenRingRequest const& request = * current; - Code generated_ring = gen__ring( current->Type, current->TypeSize ); + Code generated_ring = gen__ring( current->Type ); if ( request.Dependency ) { diff --git a/test/NonParsed/Sanity.NonParsed.hpp b/test/Upfront/Sanity.Upfront.hpp similarity index 89% rename from test/NonParsed/Sanity.NonParsed.hpp rename to test/Upfront/Sanity.Upfront.hpp index 2a85db3..8a2cea1 100644 --- a/test/NonParsed/Sanity.NonParsed.hpp +++ b/test/Upfront/Sanity.Upfront.hpp @@ -7,17 +7,17 @@ u32 gen_sanity() { Builder gen_sanity_file; - gen_sanity_file.open("./sanity.NonParsed.gen.hpp"); + gen_sanity_file.open("./sanity.Upfront.gen.hpp"); // Comment { - Code comment_test = def_comment( StrC::from("Sanity check: def_comment test") ); + Code comment_test = def_comment( txt_StrC("Sanity check: def_comment test") ); gen_sanity_file.print(comment_test); } gen_sanity_file.print_fmt("\n"); - gen_sanity_file.print( def_comment( StrC::from( + gen_sanity_file.print( def_comment( txt_StrC( "The following will show a series of base cases for the gen api.\n" ))); @@ -26,7 +26,7 @@ u32 gen_sanity() Code fwd = def_class( name(TestEmptyClass) ); Code empty_body; { - Code cmt = def_comment( StrC::from("Empty class body") ); + Code cmt = def_comment( txt_StrC("Empty class body") ); Code body = def_class_body( 1, cmt ); empty_body = def_class( name(TestEmptyClass), body ); @@ -74,7 +74,7 @@ u32 gen_sanity() // External Linkage { Code body = def_extern_link_body( 1 - , def_comment( StrC::from("Empty extern body") ) + , def_comment( txt_StrC("Empty extern body") ) ); Code c_extern = def_extern_link( name(C), body ); @@ -102,7 +102,7 @@ u32 gen_sanity() Code def; { Code body = def_function_body( 1 - , def_comment( StrC::from("Empty function body") ) + , def_comment( txt_StrC("Empty function body") ) ); def = def_function( name(test_function), __, __, body ); @@ -116,7 +116,7 @@ u32 gen_sanity() // Include { - Code include = def_include( StrC::from("../DummyInclude.hpp") ); + Code include = def_include( txt_StrC("../DummyInclude.hpp") ); gen_sanity_file.print(include); } @@ -144,7 +144,7 @@ u32 gen_sanity() Code namespace_def; { Code body = def_namespace_body( 1 - , def_comment( StrC::from("Empty namespace body") ) + , def_comment( txt_StrC("Empty namespace body") ) ); namespace_def = def_namespace( name(TestNamespace), body ); @@ -215,7 +215,7 @@ u32 gen_sanity() Code def, def2; { Code body = def_function_body( 1 - , def_comment( StrC::from("Empty function body") ) + , def_comment( txt_StrC("Empty function body") ) ); Code params = def_params( 2 @@ -261,7 +261,7 @@ u32 gen_sanity() Code fwd = def_class( name(TestEmptyStruct) ); Code empty_body; { - Code cmt = def_comment( StrC::from("Empty struct body") ); + Code cmt = def_comment( txt_StrC("Empty struct body") ); Code body = def_class_body( 1, cmt ); empty_body = def_class( name(TestEmptyStruct), body ); @@ -276,7 +276,7 @@ u32 gen_sanity() // Union { Code body = def_union_body( 1 - , def_comment( StrC::from("Empty union body") ) + , def_comment( txt_StrC("Empty union body") ) ); Code def = def_union( name(TestEmptyUnion), body ); @@ -314,7 +314,7 @@ u32 gen_sanity() Code tmpl = def_template( def_param( t_class, name(Type) ) , def_function( name(test_template), def_param( t_Type, name(a) ), __ - , def_function_body(1, def_comment( StrC::from("Empty template function body"))) + , def_function_body(1, def_comment( txt_StrC("Empty template function body"))) ) ); @@ -323,7 +323,7 @@ u32 gen_sanity() gen_sanity_file.print_fmt("\n"); - gen_sanity_file.print( def_comment( StrC::from( + gen_sanity_file.print( def_comment( txt_StrC( "End of base case tests.\n" ))); diff --git a/test/gen/meson.build b/test/gen/meson.build index 5fd39ef..b3780d5 100644 --- a/test/gen/meson.build +++ b/test/gen/meson.build @@ -11,8 +11,7 @@ includes = include_directories( # get_sources = files('./get_sources.ps1') # sources = files(run_command('powershell', get_sources, check: true).stdout().strip().split('\n')) -sources = [ '../test.NonParsed.cpp' ] -sources_parsed = [ '../test.Parsed.cpp' ] +sources = [ '../test.cpp' ] if get_option('buildtype').startswith('debug') @@ -26,4 +25,3 @@ endif add_project_arguments('-Dgen_time', language : ['c', 'cpp']) executable( 'gencpp', sources, include_directories : includes ) -executable( 'gencpp_parsed', sources_parsed, include_directories : includes ) diff --git a/test/test.NonParsed.cpp b/test/test.Upfront.cpp similarity index 64% rename from test/test.NonParsed.cpp rename to test/test.Upfront.cpp index 99740ce..1434b24 100644 --- a/test/test.NonParsed.cpp +++ b/test/test.Upfront.cpp @@ -1,9 +1,9 @@ #include "Bloat.cpp" -#include "NonParsed\Array.NonParsed.hpp" -#include "NonParsed\Buffer.NonParsed.hpp" -#include "NonParsed\HashTable.NonParsed.hpp" -#include "NonParsed\Ring.NonParsed.hpp" -#include "NonParsed\Sanity.NonParsed.hpp" +#include "Upfront\Array.Upfront.hpp" +#include "Upfront\Buffer.Upfront.hpp" +#include "Upfront\HashTable.Upfront.hpp" +#include "Upfront\Ring.Upfront.hpp" +#include "Upfront\Sanity.Upfront.hpp" #ifdef gen_time @@ -20,7 +20,7 @@ int gen_main() gen_sanity(); gen_array( u8 ); - // gen_array( sw ); + gen_array( sw ); gen_buffer( u8 ); diff --git a/test/test.Parsed.cpp b/test/test.cpp similarity index 88% rename from test/test.Parsed.cpp rename to test/test.cpp index 3f49627..803445a 100644 --- a/test/test.Parsed.cpp +++ b/test/test.cpp @@ -12,6 +12,7 @@ using namespace gen; +// TODO : Rewrite this to include both upfront and parsed testing. int gen_main() { @@ -41,7 +42,7 @@ int gen_main() using u16 = unsigned short; ))); - soa_test.print( def_include( StrC::from("Bloat.hpp"))); + soa_test.print( def_include( txt_StrC("Bloat.hpp"))); soa_test.print( def_using_namespace( name(gen) ) ); @@ -55,7 +56,7 @@ int gen_main() u64 D; }; )), - true + false )); soa_test.write();