mirror of
				https://github.com/Ed94/gencpp.git
				synced 2025-10-31 06:50:53 -07:00 
			
		
		
		
	Compare commits
	
		
			20 Commits
		
	
	
		
			v0.19-Alph
			...
			ed0c0422ad
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| ed0c0422ad | |||
| e5acac1d18 | |||
| c7b072266f | |||
| a96d03eaed | |||
| 0b4ccac8f9 | |||
| 31a3609b28 | |||
| fbdb870986 | |||
| 6d04165b96 | |||
| cc245cc263 | |||
| 06deb1e836 | |||
| 5527a27f7b | |||
| a67fdef20a | |||
| 056a5863b8 | |||
| 79eb5f1f76 | |||
| c6cb583518 | |||
| 34eec66f35 | |||
| 4137ebfbd8 | |||
| 5958dd2055 | |||
| 163ad0a511 | |||
| e3c2a577ba | 
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -31,3 +31,4 @@ project/auxillary/vis_ast/dependencies/temp | |||||||
| test/gen/original | test/gen/original | ||||||
| singleheader/gen/scratch.hpp | singleheader/gen/scratch.hpp | ||||||
| test/gen/scratch.cpp | test/gen/scratch.cpp | ||||||
|  | gen_c_library/gen | ||||||
|   | |||||||
							
								
								
									
										5
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							| @@ -37,7 +37,10 @@ | |||||||
| 		"propidl.h": "c", | 		"propidl.h": "c", | ||||||
| 		"android_native_app_glue.h": "c", | 		"android_native_app_glue.h": "c", | ||||||
| 		"raylib.h": "c", | 		"raylib.h": "c", | ||||||
| 		"*.m": "cpp" | 		"*.m": "cpp", | ||||||
|  | 		"atomic": "cpp", | ||||||
|  | 		"gen.h": "c", | ||||||
|  | 		"string_ops.hpp": "c" | ||||||
| 	}, | 	}, | ||||||
| 	"C_Cpp.intelliSenseEngineFallback": "disabled", | 	"C_Cpp.intelliSenseEngineFallback": "disabled", | ||||||
| 	"mesonbuild.configureOnOpen": true, | 	"mesonbuild.configureOnOpen": true, | ||||||
|   | |||||||
							
								
								
									
										260
									
								
								gen_c_library/c_library.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										260
									
								
								gen_c_library/c_library.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,260 @@ | |||||||
|  | #define GEN_DEFINE_LIBRARY_CODE_CONSTANTS | ||||||
|  | #define GEN_ENFORCE_STRONG_CODE_TYPES | ||||||
|  | #define GEN_EXPOSE_BACKEND | ||||||
|  | #define GEN_SUPPORT_CPP_MEMBER_FEATURES 1 | ||||||
|  | #include "../project/gen.cpp" | ||||||
|  |  | ||||||
|  | #include "helpers/push_ignores.inline.hpp" | ||||||
|  | #include "helpers/helper.hpp" | ||||||
|  |  | ||||||
|  | GEN_NS_BEGIN | ||||||
|  | #include "dependencies/parsing.cpp" | ||||||
|  | GEN_NS_END | ||||||
|  |  | ||||||
|  | #include "auxillary/builder.hpp" | ||||||
|  | #include "auxillary/builder.cpp" | ||||||
|  | #include "auxillary/scanner.hpp" | ||||||
|  |  | ||||||
|  | #include <cstdlib>   // for system() | ||||||
|  |  | ||||||
|  | #include "components/memory.fixed_arena.hpp" | ||||||
|  | #include "components/misc.hpp" | ||||||
|  | #include "components/containers.array.hpp" | ||||||
|  | #include "components/containers.hashtable.hpp" | ||||||
|  |  | ||||||
|  | using namespace gen; | ||||||
|  |  | ||||||
|  | constexpr char const* generation_notice = | ||||||
|  | "// This file was generated automatially by gencpp's c_library.cpp" | ||||||
|  | "(See: https://github.com/Ed94/gencpp)\n\n"; | ||||||
|  |  | ||||||
|  | constexpr StrC roll_own_dependencies_guard_start = txt(R"( | ||||||
|  | //! If its desired to roll your own dependencies, define GEN_ROLL_OWN_DEPENDENCIES before including this file. | ||||||
|  | // Dependencies are derived from the c-zpl library: https://github.com/zpl-c/zpl | ||||||
|  | #ifndef GEN_ROLL_OWN_DEPENDENCIES | ||||||
|  | )"); | ||||||
|  |  | ||||||
|  | constexpr StrC roll_own_dependencies_guard_end = txt(R"( | ||||||
|  | // GEN_ROLL_OWN_DEPENDENCIES | ||||||
|  | #endif | ||||||
|  | )"); | ||||||
|  |  | ||||||
|  | constexpr StrC implementation_guard_start = txt(R"( | ||||||
|  | #pragma region GENCPP IMPLEMENTATION GUARD | ||||||
|  | #if defined(GEN_IMPLEMENTATION) && ! defined(GEN_IMPLEMENTED) | ||||||
|  | #	define GEN_IMPLEMENTED | ||||||
|  | )"); | ||||||
|  |  | ||||||
|  | constexpr StrC implementation_guard_end = txt(R"( | ||||||
|  | #endif | ||||||
|  | #pragma endregion GENCPP IMPLEMENTATION GUARD | ||||||
|  | )"); | ||||||
|  |  | ||||||
|  | void format_file( char const* path ) | ||||||
|  | { | ||||||
|  | 	String resolved_path = String::make(GlobalAllocator, to_str(path)); | ||||||
|  |  | ||||||
|  | 	String style_arg = String::make(GlobalAllocator, txt("-style=file:")); | ||||||
|  | 	style_arg.append("../scripts/.clang-format "); | ||||||
|  |  | ||||||
|  | 	// Need to execute clang format on the generated file to get it to match the original. | ||||||
|  | 	#define clang_format      "clang-format " | ||||||
|  | 	#define cf_format_inplace "-i " | ||||||
|  | 	#define cf_verbose        "-verbose " | ||||||
|  | 	String command = String::make( GlobalAllocator, clang_format ); | ||||||
|  | 	command.append( cf_format_inplace ); | ||||||
|  | 	command.append( cf_verbose ); | ||||||
|  | 	command.append( style_arg ); | ||||||
|  | 	command.append( resolved_path ); | ||||||
|  | 		log_fmt("\tRunning clang-format on file:\n"); | ||||||
|  | 		system( command ); | ||||||
|  | 		log_fmt("\tclang-format finished reformatting.\n"); | ||||||
|  | 	#undef cf_cmd | ||||||
|  | 	#undef cf_format_inplace | ||||||
|  | 	#undef cf_style | ||||||
|  | 	#undef cf_verbse | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Code dump_to_scratch_and_retireve( Code code ) | ||||||
|  | { | ||||||
|  | 	Builder ecode_file_temp = Builder::open("gen/scratch.hpp"); | ||||||
|  | 	ecode_file_temp.print(code); | ||||||
|  | 	ecode_file_temp.write(); | ||||||
|  | 	format_file("gen/scratch.hpp"); | ||||||
|  | 	Code result = scan_file( "gen/scratch.hpp" ); | ||||||
|  | 	remove("gen/scratch.hpp"); | ||||||
|  | 	return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | CodeBody parse_file( const char* path ) | ||||||
|  | { | ||||||
|  | 	FileContents file = file_read_contents( GlobalAllocator, true, path ); | ||||||
|  | 	CodeBody     code = parse_global_body( { file.size, (char const*)file.data } ); | ||||||
|  | 	return code; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int gen_main() | ||||||
|  | { | ||||||
|  | #define project_dir "../project/" | ||||||
|  | 	gen::init(); | ||||||
|  |  | ||||||
|  | 	Code push_ignores           = scan_file( project_dir "helpers/push_ignores.inline.hpp" ); | ||||||
|  | 	Code pop_ignores            = scan_file( project_dir "helpers/pop_ignores.inline.hpp" ); | ||||||
|  | 	Code c_library_header_start = scan_file( "components/header_start.hpp" ); | ||||||
|  |  | ||||||
|  | 	Builder | ||||||
|  | 	header = Builder::open( "gen/gen.h" ); | ||||||
|  | 	header.print_fmt( generation_notice ); | ||||||
|  | 	header.print_fmt("#pragma once\n\n"); | ||||||
|  | 	header.print( push_ignores ); | ||||||
|  |  | ||||||
|  | 	// Headers | ||||||
|  | 	{ | ||||||
|  | 		header.print( c_library_header_start ); | ||||||
|  |  | ||||||
|  | 		Code platform     = scan_file( project_dir "dependencies/platform.hpp" ); | ||||||
|  | 		Code macros       = scan_file( project_dir "dependencies/macros.hpp" ); | ||||||
|  | 		Code basic_types  = scan_file( project_dir "dependencies/basic_types.hpp" ); | ||||||
|  | 		Code debug        = scan_file( project_dir "dependencies/debug.hpp" ); | ||||||
|  |  | ||||||
|  | 		header.print_fmt( roll_own_dependencies_guard_start ); | ||||||
|  | 		header.print( platform ); | ||||||
|  | 		header.print_fmt( "\nGEN_NS_BEGIN\n" ); | ||||||
|  |  | ||||||
|  | 		header.print( macros ); | ||||||
|  | 		header.print( basic_types ); | ||||||
|  | 		header.print( debug ); | ||||||
|  |  | ||||||
|  | 		CodeBody parsed_memory = parse_file( project_dir "dependencies/memory.hpp" ); | ||||||
|  | 		CodeBody memory        = def_body(ECode::Struct_Body); | ||||||
|  | 		for ( Code entry = parsed_memory.begin(); entry != parsed_memory.end(); ++ entry ) | ||||||
|  | 		{ | ||||||
|  | 			switch (entry->Type) | ||||||
|  | 			{ | ||||||
|  | 				case ECode::Using: | ||||||
|  | 				{ | ||||||
|  | 					log_fmt("REPLACE THIS MANUALLY: %S\n", entry->Name); | ||||||
|  | 					CodeUsing   using_ver   = entry.cast<CodeUsing>(); | ||||||
|  | 					CodeTypedef typedef_ver = def_typedef(using_ver->Name, using_ver->UnderlyingType); | ||||||
|  |  | ||||||
|  | 					memory.append(typedef_ver); | ||||||
|  | 				} | ||||||
|  | 				break; | ||||||
|  | 				case ECode::Function: | ||||||
|  | 				{ | ||||||
|  | 					CodeFn fn = entry.cast<CodeFn>(); | ||||||
|  | 					s32 constexpr_found = fn->Specs.remove( ESpecifier::Constexpr ); | ||||||
|  | 					if (constexpr_found > -1) { | ||||||
|  | 						log_fmt("Found constexpr proc\n"); | ||||||
|  | 						fn->Specs.append(ESpecifier::Inline); | ||||||
|  | 					} | ||||||
|  | 					memory.append(entry); | ||||||
|  | 				} | ||||||
|  | 				break; | ||||||
|  | 				case ECode::Class: | ||||||
|  | 				case ECode::Struct: | ||||||
|  | 				{ | ||||||
|  | 					CodeBody body     = entry->Body->operator CodeBody(); | ||||||
|  | 					CodeBody new_body = def_body( entry->Body->Type ); | ||||||
|  | 					for ( Code body_entry = body.begin(); body_entry != body.end(); ++ body_entry ) switch | ||||||
|  | 					(body_entry->Type) { | ||||||
|  | 						case ECode::Preprocess_If: | ||||||
|  | 						{ | ||||||
|  | 							ignore_preprocess_cond_block(txt("GEN_SUPPORT_CPP_MEMBER_FEATURES"), body_entry, body ); | ||||||
|  | 						} | ||||||
|  | 						break; | ||||||
|  |  | ||||||
|  | 						default: | ||||||
|  | 							new_body.append(body_entry); | ||||||
|  | 						break; | ||||||
|  | 					} | ||||||
|  |  | ||||||
|  | 					entry->Body = rcast(AST*, new_body.ast); | ||||||
|  | 					memory.append(entry); | ||||||
|  | 				} | ||||||
|  | 				break; | ||||||
|  | 				case ECode::Preprocess_If: | ||||||
|  | 				{ | ||||||
|  | 					ignore_preprocess_cond_block(txt("GEN_SUPPORT_CPP_MEMBER_FEATURES"), entry, parsed_memory ); | ||||||
|  | 				} | ||||||
|  | 				break; | ||||||
|  | 				case ECode::Preprocess_IfDef: | ||||||
|  | 				{ | ||||||
|  | 					ignore_preprocess_cond_block(txt("GEN_INTELLISENSE_DIRECTIVES"), entry, parsed_memory ); | ||||||
|  | 				} | ||||||
|  | 				break; | ||||||
|  | 				case ECode::Preprocess_Pragma: | ||||||
|  | 				{ | ||||||
|  | 					swap_pragma_region_implementation( txt("FixedArena"), gen_fixed_arenas, entry, memory); | ||||||
|  | 				} | ||||||
|  | 				break; | ||||||
|  | 				default: { | ||||||
|  | 					memory.append(entry); | ||||||
|  | 				} | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		header.print( memory ); | ||||||
|  |  | ||||||
|  | 		Code string_ops = scan_file( project_dir "dependencies/string_ops.hpp" ); | ||||||
|  | 		header.print( string_ops ); | ||||||
|  |  | ||||||
|  | 		CodeBody printing_parsed = parse_file( project_dir "dependencies/printing.hpp" ); | ||||||
|  | 		CodeBody printing        = def_body(ECode::Struct_Body); | ||||||
|  | 		for ( Code entry = printing_parsed.begin(); entry != printing_parsed.end(); ++ entry ) | ||||||
|  | 		{ | ||||||
|  | 			switch (entry->Type) | ||||||
|  | 			{ | ||||||
|  | 				case ECode::Preprocess_IfDef: | ||||||
|  | 				{ | ||||||
|  | 					ignore_preprocess_cond_block(txt("GEN_INTELLISENSE_DIRECTIVES"), entry, printing_parsed ); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (entry->Type == ECode::Variable && | ||||||
|  | 				contains(entry->Name, txt("Msg_Invalid_Value"))) | ||||||
|  | 			{ | ||||||
|  | 				CodeDefine define = def_define(entry->Name, entry->Value->Content); | ||||||
|  | 				printing.append(define); | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			printing.append(entry); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		header.print(printing); | ||||||
|  |  | ||||||
|  | 		CodeBody parsed_containers = parse_file( project_dir "dependencies/containers.hpp" ); | ||||||
|  | 		CodeBody containers        = def_body(ECode::Struct_Body); | ||||||
|  | 		for ( Code entry = parsed_containers.begin(); entry != parsed_containers.end(); ++ entry ) | ||||||
|  | 		{ | ||||||
|  | 			switch ( entry->Type ) | ||||||
|  | 			{ | ||||||
|  | 				case ECode::Preprocess_Pragma: | ||||||
|  | 				{ | ||||||
|  | 					bool found = false; | ||||||
|  |  | ||||||
|  | 					found = swap_pragma_region_implementation( txt("Array"), gen_array_base, entry, containers); | ||||||
|  | 					if (found) break; | ||||||
|  |  | ||||||
|  | 					found = swap_pragma_region_implementation( txt("Hashtable"), gen_hashtable_base, entry, containers); | ||||||
|  | 					if (found) break; | ||||||
|  |  | ||||||
|  | 					containers.append(entry); | ||||||
|  | 				} | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		header.print(containers); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	header.print( pop_ignores ); | ||||||
|  | 	header.write(); | ||||||
|  |  | ||||||
|  | 	format_file( "gen/gen.h" ); | ||||||
|  |  | ||||||
|  | 	gen::deinit(); | ||||||
|  | 	return 0; | ||||||
|  | #undef project_dir | ||||||
|  | } | ||||||
							
								
								
									
										295
									
								
								gen_c_library/components/containers.array.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										295
									
								
								gen_c_library/components/containers.array.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,295 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "../project/gen.hpp" | ||||||
|  |  | ||||||
|  | using namespace gen; | ||||||
|  |  | ||||||
|  | CodeBody gen_array_base() | ||||||
|  | { | ||||||
|  | 	CodeTypedef td_header = parse_typedef( code( typedef struct ArrayHeader ArrayHeader; )); | ||||||
|  | 	CodeStruct  header    = parse_struct( code( | ||||||
|  | 		struct ArrayHeader | ||||||
|  | 		{ | ||||||
|  | 			AllocatorInfo Allocator; | ||||||
|  | 			usize         Capacity; | ||||||
|  | 			usize         Num; | ||||||
|  | 		}; | ||||||
|  | 	)); | ||||||
|  |  | ||||||
|  | 	// Code grow_formula = untyped_str( txt( "#define gen_array_grow_formula( value ) ( 2 * value + 8 )\n" )); | ||||||
|  | 	Code get_header   = untyped_str( txt( "#define array_get_header( Type, self ) ( (ArrayHeader*)( self ) - 1)\n" )); | ||||||
|  |  | ||||||
|  | 	return def_global_body( args( td_header, header, get_header ) ); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | CodeBody gen_array( StrC type, StrC array_name ) | ||||||
|  | { | ||||||
|  | 	String array_type = String::fmt_buf( GlobalAllocator, "%.*s", array_name.Len, array_name.Ptr ); | ||||||
|  | 	String fn         = String::fmt_buf( GlobalAllocator, "%.*s", array_name.Len, array_name.Ptr ); | ||||||
|  | 	str_to_lower(fn.Data); | ||||||
|  |  | ||||||
|  | #pragma push_macro( "GEN_ASSERT" ) | ||||||
|  | #undef GEN_ASSERT | ||||||
|  | 	CodeBody result = parse_global_body( token_fmt( "array_type", (StrC)array_type, "fn", (StrC)fn, "type", (StrC)type | ||||||
|  | 	, stringize( | ||||||
|  | 		typedef <type>* <array_type>; | ||||||
|  |  | ||||||
|  | 		<array_type> <fn>_init           ( AllocatorInfo allocator ); | ||||||
|  | 		<array_type> <fn>_init_reserve   ( AllocatorInfo allocator, usize capacity ); | ||||||
|  | 		bool         <fn>_append         ( <array_type>*  self, <type> value ); | ||||||
|  | 		bool         <fn>_append_items   ( <array_type>*  self, <type>* items, usize item_num ); | ||||||
|  | 		bool         <fn>_append_at      ( <array_type>*  self, <type> item, usize idx ); | ||||||
|  | 		bool         <fn>_append_items_at( <array_type>*  self, <type>* items, usize item_num, usize idx ); | ||||||
|  | 		<type>*      <fn>_back           ( <array_type>  self ); | ||||||
|  | 		void         <fn>_clear          ( <array_type>  self ); | ||||||
|  | 		bool         <fn>_fill		     ( <array_type>  self, usize begin, usize end, <type> value ); | ||||||
|  | 		void         <fn>_free           ( <array_type>  self ); | ||||||
|  | 		bool         <fn>_grow           ( <array_type>* self, usize min_capacity ); | ||||||
|  | 		usize        <fn>_num            ( <array_type>  self ); | ||||||
|  | 		<type>       <fn>_pop 	         ( <array_type>  self ); | ||||||
|  | 		bool         <fn>_reserve        ( <array_type>* self, usize new_capacity ); | ||||||
|  | 		bool         <fn>_resize         ( <array_type>* self, usize num ); | ||||||
|  | 		bool         <fn>_set_capacity   ( <array_type>* self, usize new_capacity ); | ||||||
|  |  | ||||||
|  | 		<array_type> <fn>_init( AllocatorInfo allocator ) | ||||||
|  | 		{ | ||||||
|  | 			return <fn>_init_reserve( allocator, array_grow_formula( 0 ) ); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		<array_type> <fn>_init_reserve( AllocatorInfo allocator, usize capacity ) | ||||||
|  | 		{ | ||||||
|  | 			ArrayHeader* header = cast(ArrayHeader*, alloc( allocator, sizeof(ArrayHeader) + sizeof(<type>) * capacity ) ); | ||||||
|  |  | ||||||
|  | 			if ( header == NULL ) | ||||||
|  | 				return NULL; | ||||||
|  |  | ||||||
|  | 			header->Allocator = allocator; | ||||||
|  | 			header->Capacity  = capacity; | ||||||
|  | 			header->Num       = 0; | ||||||
|  |  | ||||||
|  | 			return cast( <type>*, header + 1 ); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		bool <fn>_append( <array_type>* self, <type> value ) | ||||||
|  | 		{ | ||||||
|  | 			ArrayHeader* header = get_header( * self ); | ||||||
|  |  | ||||||
|  | 			if ( header->Num == header->Capacity ) | ||||||
|  | 			{ | ||||||
|  | 				if ( ! <fn>_grow( self, header->Capacity)) | ||||||
|  | 					return false; | ||||||
|  |  | ||||||
|  | 				header = get_header( * self ); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			(* self)[ header->Num ] = value; | ||||||
|  | 			header->Num++; | ||||||
|  |  | ||||||
|  | 			return true; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		bool <fn>_append_items( <array_type>* self, <type>* items, usize item_num ) | ||||||
|  | 		{ | ||||||
|  | 			ArrayHeader* header = get_header( * self ); | ||||||
|  |  | ||||||
|  | 			if ( header->Num + item_num > header->Capacity ) | ||||||
|  | 			{ | ||||||
|  | 				if ( ! <fn>_grow( self, header->Capacity + item_num )) | ||||||
|  | 					return false; | ||||||
|  |  | ||||||
|  | 				header = get_header( * self ); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			mem_copy( (* self) + header->Num, items, sizeof(<type>) * item_num ); | ||||||
|  | 			header->Num += item_num; | ||||||
|  |  | ||||||
|  | 			return true; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		bool <fn>_append_at( <array_type>* self, <type> item, usize idx ) | ||||||
|  | 		{ | ||||||
|  | 			ArrayHeader* header = get_header( * self ); | ||||||
|  |  | ||||||
|  | 			if ( idx >= header->Num ) | ||||||
|  | 				idx = header->Num - 1; | ||||||
|  |  | ||||||
|  | 			if ( idx < 0 ) | ||||||
|  | 				idx = 0; | ||||||
|  |  | ||||||
|  | 			if ( header->Capacity < header->Num + 1 ) | ||||||
|  | 			{ | ||||||
|  | 				if ( ! <fn>_grow( self, header->Capacity + 1 ) ) | ||||||
|  | 					return false; | ||||||
|  |  | ||||||
|  | 				header = get_header( * self ); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			<array_type> target = (* self) + idx; | ||||||
|  |  | ||||||
|  | 			mem_move( target + 1, target, (header->Num - idx) * sizeof(<type>) ); | ||||||
|  | 			header->Num++; | ||||||
|  |  | ||||||
|  | 			return true; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		bool <fn>_append_items_at( <array_type>* self, <type>* items, usize item_num, usize idx ) | ||||||
|  | 		{ | ||||||
|  | 			ArrayHeader* header = get_header( * self ); | ||||||
|  |  | ||||||
|  | 			if ( idx >= header->Num ) | ||||||
|  | 			{ | ||||||
|  | 				return <fn>_append_items( self, items, item_num ); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if ( item_num > header->Capacity ) | ||||||
|  | 			{ | ||||||
|  | 				if ( ! <fn>_grow( self, item_num + header->Capacity ) ) | ||||||
|  | 					return false; | ||||||
|  |  | ||||||
|  | 				header = get_header( * self ); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			<type>* target = (* self) + idx + item_num; | ||||||
|  | 			<type>* src    = (* self) + idx; | ||||||
|  |  | ||||||
|  | 			mem_move( target, src, (header->Num - idx) * sizeof(<type>) ); | ||||||
|  | 			mem_copy( src, items, item_num * sizeof(<type>) ); | ||||||
|  | 			header->Num += item_num; | ||||||
|  |  | ||||||
|  | 			return true; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		<type>* <fn>_back( <array_type> self ) | ||||||
|  | 		{ | ||||||
|  | 			ArrayHeader* header = get_header( self ); | ||||||
|  |  | ||||||
|  | 			if ( header->Num == 0 ) | ||||||
|  | 				return NULL; | ||||||
|  |  | ||||||
|  | 			return self + header->Num - 1; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		void <fn>_clear( <array_type> self ) | ||||||
|  | 		{ | ||||||
|  | 			ArrayHeader* header = get_header( self ); | ||||||
|  | 			header->Num = 0; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		bool <fn>_fill( <array_type> self, usize begin, usize end, <type> value ) | ||||||
|  | 		{ | ||||||
|  | 			ArrayHeader* header = get_header( self ); | ||||||
|  |  | ||||||
|  | 			if ( begin < 0 || end >= header->Num ) | ||||||
|  | 				return false; | ||||||
|  |  | ||||||
|  | 			for ( ssize idx = begin; idx < end; idx ++ ) | ||||||
|  | 				self[ idx ] = value; | ||||||
|  |  | ||||||
|  | 			return true; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		void <fn>_free( <array_type> self ) | ||||||
|  | 		{ | ||||||
|  | 			ArrayHeader* header = get_header( self ); | ||||||
|  | 			free( header->Allocator, header ); | ||||||
|  | 			self = NULL; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		bool <fn>_grow( <array_type>* self, usize min_capacity ) | ||||||
|  | 		{ | ||||||
|  | 			ArrayHeader* header      = get_header( *self ); | ||||||
|  | 			usize       new_capacity = array_grow_formula( header->Capacity ); | ||||||
|  |  | ||||||
|  | 			if ( new_capacity < min_capacity ) | ||||||
|  | 				new_capacity = min_capacity; | ||||||
|  |  | ||||||
|  | 			return <fn>_set_capacity( self, new_capacity ); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		usize <fn>_num( <array_type> self ) | ||||||
|  | 		{ | ||||||
|  | 			return get_header(self)->Num; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		<type> <fn>_pop( <array_type> self ) | ||||||
|  | 		{ | ||||||
|  | 			ArrayHeader* header = get_header( self ); | ||||||
|  | 			GEN_ASSERT( header->Num > 0 ); | ||||||
|  |  | ||||||
|  | 			<type> result = self[ header->Num - 1 ]; | ||||||
|  | 			header->Num--; | ||||||
|  | 			return result; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		void <fn>_remove_at( <array_type> self, usize idx ) | ||||||
|  | 		{ | ||||||
|  | 			ArrayHeader* header = get_header( self ); | ||||||
|  | 			GEN_ASSERT( idx < header->Num ); | ||||||
|  |  | ||||||
|  | 			mem_move( self + idx, self + idx + 1, sizeof( <type> ) * ( header->Num - idx - 1 ) ); | ||||||
|  | 			header->Num--; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		bool <fn>_reserve( <array_type>* self, usize new_capacity ) | ||||||
|  | 		{ | ||||||
|  | 			ArrayHeader* header = get_header( * self ); | ||||||
|  |  | ||||||
|  | 			if ( header->Capacity < new_capacity ) | ||||||
|  | 				return <fn>_set_capacity( self, new_capacity ); | ||||||
|  |  | ||||||
|  | 			return true; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		bool <fn>_resize( <array_type>* self, usize num ) | ||||||
|  | 		{ | ||||||
|  | 			ArrayHeader* header = get_header( * self ); | ||||||
|  |  | ||||||
|  | 			if ( header->Capacity < num ) | ||||||
|  | 			{ | ||||||
|  | 				if ( ! <fn>_grow( self, num ) ) | ||||||
|  | 					return false; | ||||||
|  |  | ||||||
|  | 				header = get_header( * self ); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			header->Num = num; | ||||||
|  | 			return true; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		bool <fn>_set_capacity( <array_type>* self, usize new_capacity ) | ||||||
|  | 		{ | ||||||
|  | 			ArrayHeader* header = get_header( * self ); | ||||||
|  |  | ||||||
|  | 			if ( new_capacity == header->Capacity ) | ||||||
|  | 				return true; | ||||||
|  |  | ||||||
|  | 			if ( new_capacity < header->Num ) | ||||||
|  | 				header->Num = new_capacity; | ||||||
|  |  | ||||||
|  | 			usize       size       = sizeof( ArrayHeader ) + sizeof( <type> ) * new_capacity; | ||||||
|  | 			ArrayHeader* new_header = cast( ArrayHeader*, alloc( header->Allocator, size )); | ||||||
|  |  | ||||||
|  | 			if ( new_header == NULL ) | ||||||
|  | 				return false; | ||||||
|  |  | ||||||
|  | 			mem_move( new_header, header, sizeof( ArrayHeader ) + sizeof( <type> ) * header->Num ); | ||||||
|  | 			free( header->Allocator, & header ); | ||||||
|  |  | ||||||
|  | 			new_header->Capacity = new_capacity; | ||||||
|  | 			* self = cast( <type>*, new_header + 1 ); | ||||||
|  | 			return true; | ||||||
|  | 		} | ||||||
|  | 	))); | ||||||
|  | #pragma pop_macro( "GEN_ASSERT" ) | ||||||
|  |  | ||||||
|  | 	return def_global_body( args( | ||||||
|  | 		def_pragma( to_str( str_fmt_buf( "region %S", array_type ))), | ||||||
|  | 		fmt_newline, | ||||||
|  | 		result, | ||||||
|  | 		fmt_newline, | ||||||
|  | 		def_pragma( to_str( str_fmt_buf( "endregion %S", array_type ))), | ||||||
|  | 		fmt_newline | ||||||
|  | 	)); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // CodeBody gen_ | ||||||
							
								
								
									
										354
									
								
								gen_c_library/components/containers.hashtable.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										354
									
								
								gen_c_library/components/containers.hashtable.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,354 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "../project/gen.hpp" | ||||||
|  | #include "containers.array.hpp" | ||||||
|  |  | ||||||
|  | using namespace gen; | ||||||
|  |  | ||||||
|  | CodeBody gen_hashtable_base() | ||||||
|  | { | ||||||
|  | 	return parse_global_body( code( | ||||||
|  | 		typedef struct HT_FindResult HT_FindResult; | ||||||
|  | 		struct HT_FindResult | ||||||
|  | 		{ | ||||||
|  | 			ssize HashIndex; | ||||||
|  | 			ssize PrevIndex; | ||||||
|  | 			ssize EntryIndex; | ||||||
|  | 		}; | ||||||
|  | 	)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | CodeBody gen_hashtable( StrC type, StrC hashtable_name ) | ||||||
|  | { | ||||||
|  | 	String | ||||||
|  | 	fn = String::make_reserve( GlobalAllocator, hashtable_name.Len + sizeof("gen") ); | ||||||
|  | 	fn.append_fmt( "%.*s", hashtable_name.Len, hashtable_name.Ptr ); | ||||||
|  | 	str_to_lower(fn.Data); | ||||||
|  |  | ||||||
|  | 	String | ||||||
|  | 	tbl_type = String::make_reserve( GlobalAllocator, hashtable_name.Len + sizeof("gen") ); | ||||||
|  | 	tbl_type.append_fmt( "%.*s", hashtable_name.Len, hashtable_name.Ptr ); | ||||||
|  |  | ||||||
|  | 	String name_lower = String::make( GlobalAllocator, hashtable_name ); | ||||||
|  | 	str_to_lower( name_lower.Data ); | ||||||
|  |  | ||||||
|  | 	String hashtable_entry   = String::fmt_buf( GlobalAllocator, "HTE_%.*s",     hashtable_name.Len, hashtable_name.Ptr ); | ||||||
|  | 	String entry_array_name  = String::fmt_buf( GlobalAllocator, "Arr_HTE_%.*s", hashtable_name.Len, hashtable_name.Ptr ); | ||||||
|  | 	String entry_array_fn_ns = String::fmt_buf( GlobalAllocator, "arr_hte_%.*s", name_lower.length(), name_lower.Data ); | ||||||
|  |  | ||||||
|  | 	CodeBody hashtable_types = parse_global_body( token_fmt( | ||||||
|  | 		"type",        (StrC) type, | ||||||
|  | 		"tbl_name",    (StrC) hashtable_name, | ||||||
|  | 		"tbl_type",    (StrC) tbl_type, | ||||||
|  | 	stringize( | ||||||
|  | 		typedef struct HTE_<tbl_name> HTE_<tbl_name>; | ||||||
|  | 		struct HTE_<tbl_name> | ||||||
|  | 		{ | ||||||
|  | 			u64    Key; | ||||||
|  | 			ssize  Next; | ||||||
|  | 			<type> Value; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		typedef void (* <tbl_type>_MapProc)    ( <tbl_type> self, u64 key, <type> value ); | ||||||
|  | 		typedef void (* <tbl_type>_MapMutProc) ( <tbl_type> self, u64 key, <type>* value ); | ||||||
|  | 	))); | ||||||
|  |  | ||||||
|  | 	CodeBody entry_array = gen_array( hashtable_entry, entry_array_name ); | ||||||
|  |  | ||||||
|  | #pragma push_macro( "GEN_ASSERT" ) | ||||||
|  | #pragma push_macro( "GEN_ASSERT_NOT_NULL" ) | ||||||
|  | #undef GEN_ASSERT | ||||||
|  | #undef GEN_ASSERT_NOT_NULL | ||||||
|  | 	CodeBody hashtable_def = parse_global_body( token_fmt( | ||||||
|  | 		"type",           (StrC) type, | ||||||
|  | 		"tbl_name",       (StrC) hashtable_name, | ||||||
|  | 		"tbl_type",       (StrC) tbl_type, | ||||||
|  | 		"fn",             (StrC) fn, | ||||||
|  | 		"entry_type",     (StrC) hashtable_entry, | ||||||
|  | 		"array_entry",    (StrC) entry_array_name, | ||||||
|  | 		"fn_array",       (StrC) entry_array_fn_ns, | ||||||
|  | 	stringize( | ||||||
|  | 		typedef struct <tbl_type> <tbl_type>; | ||||||
|  | 		struct <tbl_type> | ||||||
|  | 		{ | ||||||
|  | 			Array_ssize   Hashes; | ||||||
|  | 			<array_entry> Entries; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		<tbl_type> <fn>_make        ( AllocatorInfo allocator ); | ||||||
|  | 		<tbl_type> <fn>_make_reserve( AllocatorInfo allocator, ssize num ); | ||||||
|  | 		void       <fn>_clear       ( <tbl_type> self ); | ||||||
|  | 		void       <fn>_destroy     ( <tbl_type> self ); | ||||||
|  | 		<type>*    <fn>_get         ( <tbl_type> self, u64 key ); | ||||||
|  | 		void       <fn>_map         ( <tbl_type> self, <tbl_type>_MapProc map_proc ); | ||||||
|  | 		void       <fn>_map_mut     ( <tbl_type> self, <tbl_type>_MapMutProc map_proc ); | ||||||
|  | 		void       <fn>_grow        ( <tbl_type>* self ); | ||||||
|  | 		void       <fn>_rehash      ( <tbl_type>* self, ssize new_num ); | ||||||
|  | 		void       <fn>_rehash_fast ( <tbl_type> self ); | ||||||
|  | 		void       <fn>_remove      ( <tbl_type> self, u64 key ); | ||||||
|  | 		void       <fn>_remove_entry( <tbl_type> self, ssize idx ); | ||||||
|  | 		void       <fn>_set         ( <tbl_type>* self, u64 key, <type> value ); | ||||||
|  | 		ssize         <fn>_slot        ( <tbl_type> self, u64 key ); | ||||||
|  |  | ||||||
|  | 		ssize            <fn>__add_entry( <tbl_type> self, u64 key ); | ||||||
|  | 		HT_FindResult <fn>__find     ( <tbl_type> self, u64 key ); | ||||||
|  | 		b32           <fn>__full     ( <tbl_type> self ); | ||||||
|  |  | ||||||
|  | 		<tbl_type> <fn>_make( AllocatorInfo allocator ) | ||||||
|  | 		{ | ||||||
|  | 			<tbl_type> | ||||||
|  | 			result        = { NULL, NULL }; | ||||||
|  | 			result.Hashes  = array_ssize_make( allocator ); | ||||||
|  | 			result.Entries = <fn_array>_make( allocator ); | ||||||
|  |  | ||||||
|  | 			return result; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		<tbl_type> <fn>_make_reserve( AllocatorInfo allocator, ssize num ) | ||||||
|  | 		{ | ||||||
|  | 			<tbl_type> | ||||||
|  | 			result         = { NULL, NULL }; | ||||||
|  | 			result.Hashes  = array_ssize_make_reserve( allocator, num ); | ||||||
|  | 			result.Entries = <fn_array>_make_reserve( allocator, num ); | ||||||
|  |  | ||||||
|  | 			return result; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		void <fn>_clear( <tbl_type> self ) | ||||||
|  | 		{ | ||||||
|  | 			for ( ssize idx = 0; idx < array_header( self.Hashes )->Num; idx++ ) | ||||||
|  | 				self.Hashes[idx] = -1; | ||||||
|  |  | ||||||
|  | 			array_ssize_clear( self.Hashes ); | ||||||
|  | 			<fn_array>_clear( self.Entries ); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		void <fn>_destroy( <tbl_type> self ) | ||||||
|  | 		{ | ||||||
|  | 			if ( self.Hashes && self.Entries ) | ||||||
|  | 			{ | ||||||
|  | 				array_ssize_free( self.Hashes ); | ||||||
|  | 				<fn_array>_free( self.Entries ); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		<type>* <fn>_get( <tbl_type> self, u64 key ) | ||||||
|  | 		{ | ||||||
|  | 			ssize idx = <fn>__find( self, key ).EntryIndex; | ||||||
|  | 			if ( idx > 0 ) | ||||||
|  | 				return & self.Entries[idx].Value; | ||||||
|  |  | ||||||
|  | 			return NULL; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		void <fn>_map( <tbl_type> self, <tbl_type>_MapProc map_proc ) | ||||||
|  | 		{ | ||||||
|  | 			GEN_ASSERT_NOT_NULL( map_proc ); | ||||||
|  |  | ||||||
|  | 			for ( ssize idx = 0; idx < array_header( self.Entries )->Num; idx++ ) | ||||||
|  | 			{ | ||||||
|  | 				map_proc( self, self.Entries[idx].Key, self.Entries[idx].Value ); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		void <fn>_map_mut( <tbl_type> self, <tbl_type>_MapMutProc map_proc ) | ||||||
|  | 		{ | ||||||
|  | 			GEN_ASSERT_NOT_NULL( map_proc ); | ||||||
|  |  | ||||||
|  | 			for ( ssize idx = 0; idx < array_header( self.Entries )->Num; idx++ ) | ||||||
|  | 			{ | ||||||
|  | 				map_proc( self, self.Entries[idx].Key, & self.Entries[idx].Value ); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		void <fn>_grow( <tbl_type>* self ) | ||||||
|  | 		{ | ||||||
|  | 			ssize new_num = array_grow_formula( array_header( self->Entries )->Num ); | ||||||
|  | 			<fn>_rehash( self, new_num ); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		void <fn>_rehash( <tbl_type>* self, ssize new_num ) | ||||||
|  | 		{ | ||||||
|  | 			ssize idx; | ||||||
|  | 			ssize last_added_index; | ||||||
|  |  | ||||||
|  | 			ArrayHeader* old_hash_header    = array_header( self->Hashes ); | ||||||
|  | 			ArrayHeader* old_entries_header = array_header( self->Entries ); | ||||||
|  |  | ||||||
|  | 			<tbl_type> new_tbl = <fn>_make_reserve( old_hash_header->Allocator, old_hash_header->Num ); | ||||||
|  |  | ||||||
|  | 			ArrayHeader* new_hash_header = array_header( new_tbl.Hashes ); | ||||||
|  |  | ||||||
|  | 			for ( idx = 0; idx < new_hash_header->Num; idx++ ) | ||||||
|  | 				new_tbl.Hashes[idx] = -1; | ||||||
|  |  | ||||||
|  | 			for ( idx = 0; idx < old_entries_header->Num; idx++ ) | ||||||
|  | 			{ | ||||||
|  | 				<entry_type>*  entry; | ||||||
|  | 				HT_FindResult  find_result; | ||||||
|  |  | ||||||
|  | 				if ( new_hash_header->Num == 0 ) | ||||||
|  | 					<fn>_grow( & new_tbl ); | ||||||
|  |  | ||||||
|  | 				entry            = & self->Entries[ idx ]; | ||||||
|  | 				find_result      = <fn>__find( new_tbl, entry->Key ); | ||||||
|  | 				last_added_index = <fn>__add_entry( new_tbl, entry->Key ); | ||||||
|  |  | ||||||
|  | 				if ( find_result.PrevIndex < 0 ) | ||||||
|  | 					new_tbl.Hashes[ find_result.HashIndex ] = last_added_index; | ||||||
|  | 				else | ||||||
|  | 					new_tbl.Entries[ find_result.PrevIndex ].Next = last_added_index; | ||||||
|  |  | ||||||
|  | 				new_tbl.Entries[ last_added_index ].Next  = find_result.EntryIndex; | ||||||
|  | 				new_tbl.Entries[ last_added_index ].Value = entry->Value; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			<fn>_destroy( *self ); | ||||||
|  | 			* self = new_tbl; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		void <fn>_rehash_fast( <tbl_type> self ) | ||||||
|  | 		{ | ||||||
|  | 			ssize idx; | ||||||
|  |  | ||||||
|  | 			for ( idx = 0; idx < array_header( self.Entries )->Num; idx++ ) | ||||||
|  | 				self.Entries[ idx ].Next = -1; | ||||||
|  |  | ||||||
|  | 			for ( idx = 0; idx < array_header( self.Hashes )->Num; idx++ ) | ||||||
|  | 				self.Hashes[ idx ] = -1; | ||||||
|  |  | ||||||
|  | 			for ( idx = 0; idx < array_header( self.Entries )->Num; idx++ ) | ||||||
|  | 			{ | ||||||
|  | 				<entry_type>*     entry; | ||||||
|  | 				HT_FindResult find_result; | ||||||
|  |  | ||||||
|  | 				entry       = & self.Entries[ idx ]; | ||||||
|  | 				find_result = <fn>__find( self, entry->Key ); | ||||||
|  |  | ||||||
|  | 				if ( find_result.PrevIndex < 0 ) | ||||||
|  | 					self.Hashes[ find_result.HashIndex ] = idx; | ||||||
|  | 				else | ||||||
|  | 					self.Entries[ find_result.PrevIndex ].Next = idx; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		void <fn>_remove( <tbl_type> self, u64 key ) | ||||||
|  | 		{ | ||||||
|  | 			HT_FindResult find_result = <fn>__find( self, key ); | ||||||
|  |  | ||||||
|  | 			if ( find_result.EntryIndex >= 0 ) | ||||||
|  | 			{ | ||||||
|  | 				<fn_array>_remove_at( self.Entries, find_result.EntryIndex ); | ||||||
|  | 				<fn>_rehash_fast( self ); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		void <fn>_remove_entry( <tbl_type> self, ssize idx ) | ||||||
|  | 		{ | ||||||
|  | 			<fn_array>_remove_at( self.Entries, idx ); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		void <fn>_set( <tbl_type>* self, u64 key, <type> value ) | ||||||
|  | 		{ | ||||||
|  | 			ssize            idx; | ||||||
|  | 			HT_FindResult find_result; | ||||||
|  |  | ||||||
|  | 			if ( array_header( self->Hashes )->Num == 0 ) | ||||||
|  | 				<fn>_grow( self ); | ||||||
|  |  | ||||||
|  | 			find_result = <fn>__find( * self, key ); | ||||||
|  |  | ||||||
|  | 			if ( find_result.EntryIndex >= 0 ) | ||||||
|  | 			{ | ||||||
|  | 				idx = find_result.EntryIndex; | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				idx = <fn>__add_entry( * self, key ); | ||||||
|  |  | ||||||
|  | 				if ( find_result.PrevIndex >= 0 ) | ||||||
|  | 				{ | ||||||
|  | 					self->Entries[ find_result.PrevIndex ].Next = idx; | ||||||
|  | 				} | ||||||
|  | 				else | ||||||
|  | 				{ | ||||||
|  | 					self->Hashes[ find_result.HashIndex ] = idx; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			self->Entries[ idx ].Value = value; | ||||||
|  |  | ||||||
|  | 			if ( <fn>__full( * self ) ) | ||||||
|  | 				<fn>_grow( self ); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		ssize <fn>_slot( <tbl_type> self, u64 key ) | ||||||
|  | 		{ | ||||||
|  | 			for ( ssize idx = 0; idx < array_header( self.Hashes )->Num; ++idx ) | ||||||
|  | 				if ( self.Hashes[ idx ] == key ) | ||||||
|  | 					return idx; | ||||||
|  |  | ||||||
|  | 			return -1; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		ssize <fn>__add_entry( <tbl_type> self, u64 key ) | ||||||
|  | 		{ | ||||||
|  | 			ssize idx; | ||||||
|  | 			<entry_type> entry = { key, -1 }; | ||||||
|  |  | ||||||
|  | 			idx = array_header( self.Entries )->Num; | ||||||
|  | 			<fn_array>_append( & self.Entries, entry ); | ||||||
|  | 			return idx; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		HT_FindResult <fn>__find( <tbl_type> self, u64 key ) | ||||||
|  | 		{ | ||||||
|  | 			HT_FindResult result = { -1, -1, -1 }; | ||||||
|  |  | ||||||
|  | 			ArrayHeader* hash_header = array_header( self.Hashes ); | ||||||
|  |  | ||||||
|  | 			if ( hash_header->Num > 0 ) | ||||||
|  | 			{ | ||||||
|  | 				result.HashIndex  = key % hash_header->Num; | ||||||
|  | 				result.EntryIndex = self.Hashes[ result.HashIndex ]; | ||||||
|  |  | ||||||
|  | 				while ( result.EntryIndex >= 0 ) | ||||||
|  | 				{ | ||||||
|  | 					if ( self.Entries[ result.EntryIndex ].Key == key ) | ||||||
|  | 						break; | ||||||
|  |  | ||||||
|  | 					result.PrevIndex  = result.EntryIndex; | ||||||
|  | 					result.EntryIndex = self.Entries[ result.EntryIndex ].Next; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			return result; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		b32 <fn>__full( <tbl_type> self ) | ||||||
|  | 		{ | ||||||
|  | 			ArrayHeader* hash_header    = array_header( self.Hashes ); | ||||||
|  | 			ArrayHeader* entries_header = array_header( self.Entries ); | ||||||
|  |  | ||||||
|  | 			return 0.75f * hash_header->Num < entries_header->Num; | ||||||
|  | 		} | ||||||
|  | 	))); | ||||||
|  | #pragma pop_macro( "GEN_ASSERT" ) | ||||||
|  | #pragma pop_macro( "GEN_ASSERT_NOT_NULL" ) | ||||||
|  |  | ||||||
|  | 	char const* cmt_str = str_fmt_buf( "Name: %.*s Type: %.*s" | ||||||
|  | 		, tbl_type.length(), tbl_type.Data | ||||||
|  | 		, type.Len, type.Ptr ); | ||||||
|  |  | ||||||
|  | 	return def_global_body(args( | ||||||
|  | 		def_pragma( to_str( str_fmt_buf( "region %S", tbl_type ))), | ||||||
|  | 		fmt_newline, | ||||||
|  | 		hashtable_types, | ||||||
|  | 		fmt_newline, | ||||||
|  | 		entry_array, | ||||||
|  | 		hashtable_def, | ||||||
|  | 		fmt_newline, | ||||||
|  | 		def_pragma( to_str( str_fmt_buf( "endregion %S", tbl_type ))), | ||||||
|  | 		fmt_newline | ||||||
|  | 	)); | ||||||
|  | } | ||||||
							
								
								
									
										14
									
								
								gen_c_library/components/header_start.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								gen_c_library/components/header_start.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | /* | ||||||
|  | 	gencpp: An attempt at "simple" staged metaprogramming for c/c++. | ||||||
|  |  | ||||||
|  | 	See Readme.md for more information from the project repository. | ||||||
|  |  | ||||||
|  | 	Public Address: | ||||||
|  | 	https://github.com/Ed94/gencpp | ||||||
|  |  | ||||||
|  | 	This is a single header C-Library variant. | ||||||
|  | 	Define GEN_IMPLEMENTATION before including this file in a single compilation unit. | ||||||
|  | */ | ||||||
|  | #if ! defined(GEN_DONT_ENFORCE_GEN_TIME_GUARD) && ! defined(GEN_TIME) | ||||||
|  | #	error Gen.hpp : GEN_TIME not defined | ||||||
|  | #endif | ||||||
							
								
								
									
										122
									
								
								gen_c_library/components/memory.fixed_arena.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								gen_c_library/components/memory.fixed_arena.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,122 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "../project/gen.hpp" | ||||||
|  |  | ||||||
|  | using namespace gen; | ||||||
|  |  | ||||||
|  | CodeBody gen_fixed_arenas() | ||||||
|  | { | ||||||
|  | 	CodeBody result = def_body(ECode::Global_Body); | ||||||
|  | 	result.append(def_pragma(txt("region FixedArena"))); | ||||||
|  |  | ||||||
|  | 	char const* template_struct = stringize( | ||||||
|  | 		struct FixedArena_<Name> | ||||||
|  | 		{ | ||||||
|  | 			char  memory[<Size>]; | ||||||
|  | 			Arena arena; | ||||||
|  | 		}; | ||||||
|  | 	); | ||||||
|  |  | ||||||
|  | 	char const* template_interface = stringize( | ||||||
|  | 		inline | ||||||
|  | 		void fixed_arena_init_<Name>(FixedArena_<Name>* result) { | ||||||
|  | 			zero_size(& result->memory[0], <Size>); | ||||||
|  | 			result.arena = arena_init_from_memory(& result->memory[0], <Size>); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		inline | ||||||
|  | 		ssize fixed_arena_size_remaining_<Name>(FixedArena_<Name>* fixed_arena, ssize alignment) { | ||||||
|  | 			return size_remaining(fixed_arena->arena, alignment); | ||||||
|  | 		} | ||||||
|  | 	); | ||||||
|  |  | ||||||
|  | 	CodeStruct arena_struct_1kb   = parse_struct( token_fmt_impl( 3, "Name", txt("1KB"),   "Size", txt("kilobytes(1)"),   template_struct )); | ||||||
|  | 	CodeStruct arena_struct_4kb   = parse_struct( token_fmt_impl( 3, "Name", txt("4KB"),   "Size", txt("kilobytes(4)"),   template_struct )); | ||||||
|  | 	CodeStruct arena_struct_8kb   = parse_struct( token_fmt_impl( 3, "Name", txt("8KB"),   "Size", txt("kilobytes(8)"),   template_struct )); | ||||||
|  | 	CodeStruct arena_struct_16kb  = parse_struct( token_fmt_impl( 3, "Name", txt("16KB"),  "Size", txt("kilobytes(16)"),  template_struct )); | ||||||
|  | 	CodeStruct arena_struct_32kb  = parse_struct( token_fmt_impl( 3, "Name", txt("32KB"),  "Size", txt("kilobytes(32)"),  template_struct )); | ||||||
|  | 	CodeStruct arena_struct_64kb  = parse_struct( token_fmt_impl( 3, "Name", txt("64KB"),  "Size", txt("kilobytes(64)"),  template_struct )); | ||||||
|  | 	CodeStruct arena_struct_128kb = parse_struct( token_fmt_impl( 3, "Name", txt("128KB"), "Size", txt("kilobytes(128)"), template_struct )); | ||||||
|  | 	CodeStruct arena_struct_256kb = parse_struct( token_fmt_impl( 3, "Name", txt("256KB"), "Size", txt("kilobytes(256)"), template_struct )); | ||||||
|  | 	CodeStruct arena_struct_512kb = parse_struct( token_fmt_impl( 3, "Name", txt("512KB"), "Size", txt("kilobytes(512)"), template_struct )); | ||||||
|  | 	CodeStruct arena_struct_1mb   = parse_struct( token_fmt_impl( 3, "Name", txt("1MB"),   "Size", txt("megabytes(1)"),   template_struct )); | ||||||
|  | 	CodeStruct arena_struct_2mb   = parse_struct( token_fmt_impl( 3, "Name", txt("2MB"),   "Size", txt("megabytes(2)"),   template_struct )); | ||||||
|  | 	CodeStruct arena_struct_4mb   = parse_struct( token_fmt_impl( 3, "Name", txt("4MB"),   "Size", txt("megabytes(4)"),   template_struct )); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	CodeBody arena_interface_1kb   = parse_global_body( token_fmt_impl( 3, "Name", txt("1KB"),   "Size", txt("kilobytes(1)"),    template_interface )); | ||||||
|  | 	CodeBody arena_interface_4kb   = parse_global_body( token_fmt_impl( 3, "Name", txt("4KB"),   "Size", txt("kilobytes(4)"),    template_interface )); | ||||||
|  | 	CodeBody arena_interface_8kb   = parse_global_body( token_fmt_impl( 3, "Name", txt("8KB"),   "Size", txt("kilobytes(8)"),    template_interface )); | ||||||
|  | 	CodeBody arena_interface_16kb  = parse_global_body( token_fmt_impl( 3, "Name", txt("16KB"),  "Size", txt("kilobytes(16)"),   template_interface )); | ||||||
|  | 	CodeBody arena_interface_32kb  = parse_global_body( token_fmt_impl( 3, "Name", txt("32KB"),  "Size", txt("kilobytes(32)"),   template_interface )); | ||||||
|  | 	CodeBody arena_interface_64kb  = parse_global_body( token_fmt_impl( 3, "Name", txt("64KB"),  "Size", txt("kilobytes(64)"),   template_interface )); | ||||||
|  | 	CodeBody arena_interface_128kb = parse_global_body( token_fmt_impl( 3, "Name", txt("128KB"), "Size", txt("kilobytes(128)"), template_interface )); | ||||||
|  | 	CodeBody arena_interface_256kb = parse_global_body( token_fmt_impl( 3, "Name", txt("256KB"), "Size", txt("kilobytes(256)"), template_interface )); | ||||||
|  | 	CodeBody arena_interface_512kb = parse_global_body( token_fmt_impl( 3, "Name", txt("512KB"), "Size", txt("kilobytes(512)"), template_interface )); | ||||||
|  | 	CodeBody arena_interface_1mb   = parse_global_body( token_fmt_impl( 3, "Name", txt("1MB"),   "Size", txt("megabytes(1)"),   template_interface )); | ||||||
|  | 	CodeBody arena_interface_2mb   = parse_global_body( token_fmt_impl( 3, "Name", txt("2MB"),   "Size", txt("megabytes(2)"),   template_interface )); | ||||||
|  | 	CodeBody arena_interface_4mb   = parse_global_body( token_fmt_impl( 3, "Name", txt("4MB"),   "Size", txt("megabytes(4)"),   template_interface )); | ||||||
|  |  | ||||||
|  | 	result.append(arena_struct_1kb); | ||||||
|  | 	result.append(arena_struct_4kb); | ||||||
|  | 	result.append(arena_struct_8kb); | ||||||
|  | 	result.append(arena_struct_16kb); | ||||||
|  | 	result.append(arena_struct_32kb); | ||||||
|  | 	result.append(arena_struct_128kb); | ||||||
|  | 	result.append(arena_struct_256kb); | ||||||
|  | 	result.append(arena_struct_512kb); | ||||||
|  | 	result.append(arena_struct_1mb); | ||||||
|  | 	result.append(arena_struct_2mb); | ||||||
|  | 	result.append(arena_struct_4mb); | ||||||
|  |  | ||||||
|  | 	result.append(arena_interface_1kb); | ||||||
|  | 	result.append(arena_interface_4kb); | ||||||
|  | 	result.append(arena_interface_8kb); | ||||||
|  | 	result.append(arena_interface_16kb); | ||||||
|  | 	result.append(arena_interface_32kb); | ||||||
|  | 	result.append(arena_interface_128kb); | ||||||
|  | 	result.append(arena_interface_256kb); | ||||||
|  | 	result.append(arena_interface_512kb); | ||||||
|  | 	result.append(arena_interface_1mb); | ||||||
|  | 	result.append(arena_interface_2mb); | ||||||
|  | 	result.append(arena_interface_4mb); | ||||||
|  |  | ||||||
|  | 	CodeDefine def = def_define(txt("fixed_arena_allocator_info(fixed_arena)"), code({ arena_allocator_proc, & fixed_arena.arena }) ); | ||||||
|  | 	result.append(def); | ||||||
|  |  | ||||||
|  | 	result.append(parse_global_body(txt(R"( | ||||||
|  | #define fixed_arena_init(expr) _Generic((expr), \ | ||||||
|  |     FixedArena_1KB*   : fixed_arena_init_1KB,   \ | ||||||
|  |     FixedArena_4KB*   : fixed_arena_init_4KB,   \ | ||||||
|  |     FixedArena_8KB*   : fixed_arena_init_8KB,   \ | ||||||
|  |     FixedArena_16KB*  : fixed_arena_init_16KB,  \ | ||||||
|  |     FixedArena_32KB*  : fixed_arena_init_32KB,  \ | ||||||
|  |     FixedArena_64KB*  : fixed_arena_init_64KB,  \ | ||||||
|  |     FixedArena_128KB* : fixed_arena_init_128KB, \ | ||||||
|  |     FixedArena_256KB* : fixed_arena_init_256KB, \ | ||||||
|  |     FixedArena_512KB* : fixed_arena_init_512KB, \ | ||||||
|  |     FixedArena_1MB*   : fixed_arena_init_1MB,   \ | ||||||
|  |     FixedArena_2MB*   : fixed_arena_init_2MB,   \ | ||||||
|  |     FixedArena_4MB*   : fixed_arena_init_4MB    \ | ||||||
|  | )(expr) | ||||||
|  |  | ||||||
|  | #define fixed_arena_size_remaining(expr, alignment) _Generic((expr), \ | ||||||
|  |     FixedArena_1KB*   : fixed_arena_size_remaining_1KB,              \ | ||||||
|  |     FixedArena_4KB*   : fixed_arena_size_remaining_4KB,              \ | ||||||
|  |     FixedArena_8KB*   : fixed_arena_size_remaining_8KB,              \ | ||||||
|  |     FixedArena_16KB*  : fixed_arena_size_remaining_16KB,             \ | ||||||
|  |     FixedArena_32KB*  : fixed_arena_size_remaining_32KB,             \ | ||||||
|  |     FixedArena_64KB*  : fixed_arena_size_remaining_64KB,             \ | ||||||
|  |     FixedArena_128KB* : fixed_arena_size_remaining_128KB,            \ | ||||||
|  |     FixedArena_256KB* : fixed_arena_size_remaining_256KB,            \ | ||||||
|  |     FixedArena_512KB* : fixed_arena_size_remaining_512KB,            \ | ||||||
|  |     FixedArena_1MB*   : fixed_arena_size_remaining_1MB,              \ | ||||||
|  |     FixedArena_2MB*   : fixed_arena_size_remaining_2MB,              \ | ||||||
|  |     FixedArena_4MB*   : fixed_arena_size_remaining_4MB               \ | ||||||
|  | )(expr, alignment) | ||||||
|  | )" | ||||||
|  | 	))); | ||||||
|  |  | ||||||
|  | 	result.append(def_pragma(txt("endregion FixedArena"))); | ||||||
|  |  | ||||||
|  | 	return result; | ||||||
|  | } | ||||||
							
								
								
									
										68
									
								
								gen_c_library/components/misc.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								gen_c_library/components/misc.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | |||||||
|  | // #pragma once | ||||||
|  | // #include "../project/gen.hpp" | ||||||
|  |  | ||||||
|  | // using namespace gen; | ||||||
|  |  | ||||||
|  | using SwapContentProc = CodeBody(void); | ||||||
|  |  | ||||||
|  | b32 ignore_preprocess_cond_block( StrC cond_sig, Code& entry_iter, CodeBody& body ) | ||||||
|  | { | ||||||
|  | 	CodePreprocessCond cond = entry_iter.cast<CodePreprocessCond>(); | ||||||
|  | 	if ( cond->Content.contains(cond_sig) ) | ||||||
|  | 	{ | ||||||
|  | 		s32 depth = 1; | ||||||
|  | 		++ entry_iter; for(b32 continue_for = true; continue_for && entry_iter != body.end(); ) switch | ||||||
|  | 		(entry_iter->Type) { | ||||||
|  | 			case ECode::Preprocess_If: | ||||||
|  | 			case ECode::Preprocess_IfDef: | ||||||
|  | 			case ECode::Preprocess_IfNotDef: | ||||||
|  | 				depth ++; | ||||||
|  | 			break; | ||||||
|  |  | ||||||
|  | 			case ECode::Preprocess_EndIf: | ||||||
|  | 			{ | ||||||
|  | 				depth --; | ||||||
|  | 				if (depth == 0) { | ||||||
|  | 					continue_for = false; | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			break; | ||||||
|  | 			default: | ||||||
|  | 				++ entry_iter; | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return entry_iter != body.end(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool swap_pragma_region_implementation( StrC region_name, SwapContentProc* swap_content, Code& entry_iter, CodeBody& body ) | ||||||
|  | { | ||||||
|  | 	bool found = false; | ||||||
|  | 	CodePragma possible_region = entry_iter.cast<CodePragma>(); | ||||||
|  |  | ||||||
|  | 	String region_sig    = string_fmt_buf(GlobalAllocator, "region %s",    region_name.Ptr); | ||||||
|  | 	String endregion_sig = string_fmt_buf(GlobalAllocator, "endregion %s", region_name.Ptr); | ||||||
|  | 	if ( possible_region->Content.contains(region_sig)) | ||||||
|  | 	{ | ||||||
|  | 		found = true; | ||||||
|  | 		// body.append(possible_region); | ||||||
|  | 		body.append(swap_content()); | ||||||
|  |  | ||||||
|  | 		++ entry_iter; for(b32 continue_for = true; continue_for; ++entry_iter) switch | ||||||
|  | 		(entry_iter->Type) { | ||||||
|  | 			case ECode::Preprocess_Pragma: | ||||||
|  | 			{ | ||||||
|  | 				CodePragma possible_end_region = entry_iter.cast<CodePragma>(); | ||||||
|  | 				if ( possible_end_region->Content.contains(endregion_sig) ) { | ||||||
|  | 					// body.append(possible_end_region); | ||||||
|  | 					continue_for = false; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 		body.append(entry_iter); | ||||||
|  | 	} | ||||||
|  | 	return found; | ||||||
|  | } | ||||||
| @@ -1,4 +1,4 @@ | |||||||
| # Singleheader | # Singleheader | ||||||
| 
 | 
 | ||||||
| Creates a single header file version of the library using `gen.singleheader.cpp`. | Creates a single header file version of the library using `singleheader.cpp`. | ||||||
| Follows the same convention seen in the gb, stb, and zpl libraries. | Follows the same convention seen in the gb, stb, and zpl libraries. | ||||||
| @@ -12,12 +12,3 @@ | |||||||
| #if ! defined(GEN_DONT_ENFORCE_GEN_TIME_GUARD) && ! defined(GEN_TIME) | #if ! defined(GEN_DONT_ENFORCE_GEN_TIME_GUARD) && ! defined(GEN_TIME) | ||||||
| #	error Gen.hpp : GEN_TIME not defined | #	error Gen.hpp : GEN_TIME not defined | ||||||
| #endif | #endif | ||||||
| 
 |  | ||||||
| #ifdef GEN_DONT_USE_NAMESPACE |  | ||||||
| #	define GEN_NS_BEGIN |  | ||||||
| #	define GEN_NS_END |  | ||||||
| #else |  | ||||||
| #	define GEN_NS_BEGIN namespace gen { |  | ||||||
| #	define GEN_NS_END   } |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| @@ -13,7 +13,7 @@ Builder Builder::open( char const* path ) | |||||||
| 		return result; | 		return result; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	result.Buffer = String::make_reserve( GlobalAllocator, Builder_StrBufferReserve ); | 	result.Buffer = string_make_reserve( GlobalAllocator, Builder_StrBufferReserve ); | ||||||
|  |  | ||||||
| 	// log_fmt("$Builder - Opened file: %s\n", result.File.filename ); | 	// log_fmt("$Builder - Opened file: %s\n", result.File.filename ); | ||||||
| 	return result; | 	return result; | ||||||
| @@ -21,7 +21,7 @@ Builder Builder::open( char const* path ) | |||||||
|  |  | ||||||
| void Builder::pad_lines( s32 num ) | void Builder::pad_lines( s32 num ) | ||||||
| { | { | ||||||
| 	Buffer.append( "\n" ); | 	append( Buffer,  "\n" ); | ||||||
| } | } | ||||||
|  |  | ||||||
| void Builder::print( Code code ) | void Builder::print( Code code ) | ||||||
| @@ -29,7 +29,7 @@ void Builder::print( Code code ) | |||||||
| 	String   str = code->to_string(); | 	String   str = code->to_string(); | ||||||
| 	// const ssize len = str.length(); | 	// const ssize len = str.length(); | ||||||
| 	// log_fmt( "%s - print: %.*s\n", File.filename, len > 80 ? 80 : len, str.Data ); | 	// log_fmt( "%s - print: %.*s\n", File.filename, len > 80 ? 80 : len, str.Data ); | ||||||
| 	Buffer.append( str ); | 	append( Buffer, str ); | ||||||
| } | } | ||||||
|  |  | ||||||
| void Builder::print_fmt( char const* fmt, ... ) | void Builder::print_fmt( char const* fmt, ... ) | ||||||
| @@ -43,17 +43,17 @@ void Builder::print_fmt( char const* fmt, ... ) | |||||||
| 	va_end( va ); | 	va_end( va ); | ||||||
|  |  | ||||||
| 	// log_fmt( "$%s - print_fmt: %.*s\n", File.filename, res > 80 ? 80 : res, buf ); | 	// log_fmt( "$%s - print_fmt: %.*s\n", File.filename, res > 80 ? 80 : res, buf ); | ||||||
| 	Buffer.append( buf, res ); | 	append( Buffer, buf, res ); | ||||||
| } | } | ||||||
|  |  | ||||||
| void Builder::write() | void Builder::write() | ||||||
| { | { | ||||||
| 	b32 result = file_write( & File, Buffer, Buffer.length() ); | 	b32 result = file_write( & File, Buffer, length(Buffer) ); | ||||||
|  |  | ||||||
| 	if ( result == false ) | 	if ( result == false ) | ||||||
| 		log_failure("gen::File::write - Failed to write to file: %s\n", file_name( & File ) ); | 		log_failure("gen::File::write - Failed to write to file: %s\n", file_name( & File ) ); | ||||||
|  |  | ||||||
| 	log_fmt( "Generated: %s\n", File.filename ); | 	log_fmt( "Generated: %s\n", File.filename ); | ||||||
| 	file_close( & File ); | 	file_close( & File ); | ||||||
| 	Buffer.free(); | 	free(Buffer); | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										23
									
								
								project/auxillary/gen_template.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								project/auxillary/gen_template.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||||
|  | #	pragma once | ||||||
|  | #	include "../gen.hpp" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | 	Explicitly generates a resolved definition of a cpp template definition. | ||||||
|  |  | ||||||
|  | 	TODO(Ed): Needs implementing for the C-library variant. | ||||||
|  | 	TODO(Ed): We need a non <token> syntax subst implemtnation for Strings for this to work. It must subst keywords directly based on template parameter names. | ||||||
|  |  | ||||||
|  | 	This is only meant to be used on relatively trivial templates, where the type or numeric is mostly a 'duck' type. | ||||||
|  | 	It cannot parse complex template parameters. | ||||||
|  |  | ||||||
|  | 	The varadic args should correspond 1:1 with the type of objects the generator expects from the template's parameters.alignas. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | CodeOperator gen_operator_template( CodeTemplate template, ... ); | ||||||
|  | CodeFn       gen_func_template( CodeTemplate template, ...  ); | ||||||
|  | Code         gen_class_struct_template( CodeTemplate template, ... ); | ||||||
|  |  | ||||||
|  | Code gen_template( CodeTemplate template, ... ); | ||||||
|  | Code gen_template( StrC template, StrC instantiation ); | ||||||
| @@ -23,9 +23,9 @@ Code scan_file( char const* path ) | |||||||
| 		GEN_FATAL("scan_file: %s is empty", path ); | 		GEN_FATAL("scan_file: %s is empty", path ); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	String str = String::make_reserve( GlobalAllocator, fsize ); | 	String str = string_make_reserve( GlobalAllocator, fsize ); | ||||||
| 		file_read( & file, str, fsize ); | 		file_read( & file, str, fsize ); | ||||||
| 		str.get_header().Length = fsize; | 		get_header(str).Length = fsize; | ||||||
|  |  | ||||||
| 	// Skip GEN_INTELLISENSE_DIRECTIVES preprocessor blocks | 	// Skip GEN_INTELLISENSE_DIRECTIVES preprocessor blocks | ||||||
| 	// Its designed so that the directive should be the first thing in the file. | 	// Its designed so that the directive should be the first thing in the file. | ||||||
| @@ -97,12 +97,12 @@ Code scan_file( char const* path ) | |||||||
| 					if ( (scanner + 2) >= ( str.Data + fsize ) ) | 					if ( (scanner + 2) >= ( str.Data + fsize ) ) | ||||||
| 					{ | 					{ | ||||||
| 						mem_move( str, scanner, left ); | 						mem_move( str, scanner, left ); | ||||||
| 						str.get_header().Length = left; | 						get_header(str).Length = left; | ||||||
| 						break; | 						break; | ||||||
| 					} | 					} | ||||||
|  |  | ||||||
| 					mem_move( str, scanner, left ); | 					mem_move( str, scanner, left ); | ||||||
| 					str.get_header().Length = left; | 					get_header(str).Length = left; | ||||||
|  |  | ||||||
| 					break; | 					break; | ||||||
| 				} | 				} | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| #define GEN_DEFINE_LIBRARY_CODE_CONSTANTS | #define GEN_DEFINE_LIBRARY_CODE_CONSTANTS | ||||||
| #define GEN_ENFORCE_STRONG_CODE_TYPES | #define GEN_ENFORCE_STRONG_CODE_TYPES | ||||||
| #define GEN_EXPOSE_BACKEND | #define GEN_EXPOSE_BACKEND | ||||||
|  | #define GEN_SUPPORT_CPP_MEMBER_FEATURES 0 | ||||||
| #include "gen.cpp" | #include "gen.cpp" | ||||||
|  |  | ||||||
| #include "helpers/push_ignores.inline.hpp" | #include "helpers/push_ignores.inline.hpp" | ||||||
| @@ -24,20 +25,20 @@ constexpr char const* generation_notice = | |||||||
|  |  | ||||||
| void format_file( char const* path ) | void format_file( char const* path ) | ||||||
| { | { | ||||||
| 	String resolved_path = String::make(GlobalAllocator, to_str(path)); | 	String resolved_path = string_make(GlobalAllocator, to_str(path)); | ||||||
|  |  | ||||||
| 	String style_arg = String::make(GlobalAllocator, txt("-style=file:")); | 	String style_arg = string_make(GlobalAllocator, txt("-style=file:")); | ||||||
| 	style_arg.append("../scripts/.clang-format "); | 	append( style_arg, "../scripts/.clang-format "); | ||||||
|  |  | ||||||
| 	// Need to execute clang format on the generated file to get it to match the original. | 	// Need to execute clang format on the generated file to get it to match the original. | ||||||
| 	#define clang_format      "clang-format " | 	#define clang_format      "clang-format " | ||||||
| 	#define cf_format_inplace "-i " | 	#define cf_format_inplace "-i " | ||||||
| 	#define cf_verbose        "-verbose " | 	#define cf_verbose        "-verbose " | ||||||
| 	String command = String::make( GlobalAllocator, clang_format ); | 	String command = string_make( GlobalAllocator, clang_format ); | ||||||
| 	command.append( cf_format_inplace ); | 	append( command, cf_format_inplace ); | ||||||
| 	command.append( cf_verbose ); | 	append( command, cf_verbose ); | ||||||
| 	command.append( style_arg ); | 	append( command, style_arg ); | ||||||
| 	command.append( resolved_path ); | 	append( command, resolved_path ); | ||||||
| 		log_fmt("\tRunning clang-format on file:\n"); | 		log_fmt("\tRunning clang-format on file:\n"); | ||||||
| 		system( command ); | 		system( command ); | ||||||
| 		log_fmt("\tclang-format finished reformatting.\n"); | 		log_fmt("\tclang-format finished reformatting.\n"); | ||||||
|   | |||||||
| @@ -9,16 +9,16 @@ Code Code::Invalid; | |||||||
| // This serializes all the data-members in a "debug" format, where each member is printed with its associated value. | // This serializes all the data-members in a "debug" format, where each member is printed with its associated value. | ||||||
| char const* AST::debug_str() | char const* AST::debug_str() | ||||||
| { | { | ||||||
| 	String result = String::make_reserve( GlobalAllocator, kilobytes(1) ); | 	String result = string_make_reserve( GlobalAllocator, kilobytes(1) ); | ||||||
|  |  | ||||||
| 	if ( Parent ) | 	if ( Parent ) | ||||||
| 		result.append_fmt( "\n\tParent       : %S %S", Parent->type_str(), Name ? Name : "" ); | 		append_fmt( result, "\n\tParent       : %S %S", Parent->type_str(), Name ? Name : "" ); | ||||||
| 	else | 	else | ||||||
| 		result.append_fmt( "\n\tParent       : %S", "Null" ); | 		append_fmt( result, "\n\tParent       : %S", "Null" ); | ||||||
|  |  | ||||||
| 	result.append_fmt( "\n\tName         : %S", Name ? Name : "Null" ); | 	append_fmt( result, "\n\tName         : %S", Name ? Name : "Null" ); | ||||||
| 	result.append_fmt( "\n\tType         : %S", type_str() ); | 	append_fmt( result, "\n\tType         : %S", type_str() ); | ||||||
| 	result.append_fmt( "\n\tModule Flags : %S", to_str( ModuleFlags ) ); | 	append_fmt( result, "\n\tModule Flags : %S", to_str( ModuleFlags ) ); | ||||||
|  |  | ||||||
| 	switch ( Type ) | 	switch ( Type ) | ||||||
| 	{ | 	{ | ||||||
| @@ -30,9 +30,9 @@ char const* AST::debug_str() | |||||||
| 		case Access_Protected: | 		case Access_Protected: | ||||||
| 		case Access_Public: | 		case Access_Public: | ||||||
| 			if ( Prev ) | 			if ( Prev ) | ||||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
| 			if ( Next ) | 			if ( Next ) | ||||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
| 		break; | 		break; | ||||||
|  |  | ||||||
| 		case Untyped: | 		case Untyped: | ||||||
| @@ -48,74 +48,74 @@ char const* AST::debug_str() | |||||||
| 		case Preprocess_IfDef: | 		case Preprocess_IfDef: | ||||||
| 		case Preprocess_IfNotDef: | 		case Preprocess_IfNotDef: | ||||||
| 			if ( Prev ) | 			if ( Prev ) | ||||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
| 			if ( Next ) | 			if ( Next ) | ||||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
|  |  | ||||||
| 			result.append_fmt( "\n\tContent: %S", Content ); | 			append_fmt( result, "\n\tContent: %S", Content ); | ||||||
| 		break; | 		break; | ||||||
|  |  | ||||||
| 		case Class: | 		case Class: | ||||||
| 		case Struct: | 		case Struct: | ||||||
| 			if ( Prev ) | 			if ( Prev ) | ||||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
| 			if ( Next ) | 			if ( Next ) | ||||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
|  |  | ||||||
| 			result.append_fmt( "\n\tInlineCmd   : %S", InlineCmt  ? InlineCmt->Content      : "Null" ); | 			append_fmt( result, "\n\tInlineCmd   : %S", InlineCmt  ? InlineCmt->Content      : "Null" ); | ||||||
| 			result.append_fmt( "\n\tAttributes  : %S", Attributes ? Attributes->to_string() : "Null" ); | 			append_fmt( result, "\n\tAttributes  : %S", Attributes ? Attributes->to_string() : "Null" ); | ||||||
| 			result.append_fmt( "\n\tParentAccess: %s", ParentType ? to_str( ParentAccess )  : "No Parent" ); | 			append_fmt( result, "\n\tParentAccess: %s", ParentType ? to_str( ParentAccess )  : "No Parent" ); | ||||||
| 			result.append_fmt( "\n\tParentType  : %s", ParentType ? ParentType->type_str()  : "Null" ); | 			append_fmt( result, "\n\tParentType  : %s", ParentType ? ParentType->type_str()  : "Null" ); | ||||||
| 			result.append_fmt( "\n\tBody        : %S", Body       ? Body->debug_str()       : "Null" ); | 			append_fmt( result, "\n\tBody        : %S", Body       ? Body->debug_str()       : "Null" ); | ||||||
| 		break; | 		break; | ||||||
|  |  | ||||||
| 		case Class_Fwd: | 		case Class_Fwd: | ||||||
| 		case Struct_Fwd: | 		case Struct_Fwd: | ||||||
| 			if ( Prev ) | 			if ( Prev ) | ||||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
| 			if ( Next ) | 			if ( Next ) | ||||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
|  |  | ||||||
| 			result.append_fmt( "\n\tInlineCmd   : %S", InlineCmt  ? InlineCmt->Content      : "Null" ); | 			append_fmt( result, "\n\tInlineCmd   : %S", InlineCmt  ? InlineCmt->Content      : "Null" ); | ||||||
| 			result.append_fmt( "\n\tAttributes  : %S", Attributes ? Attributes->to_string() : "Null" ); | 			append_fmt( result, "\n\tAttributes  : %S", Attributes ? Attributes->to_string() : "Null" ); | ||||||
| 			result.append_fmt( "\n\tParentAccess: %s", ParentType ? to_str( ParentAccess )  : "No Parent" ); | 			append_fmt( result, "\n\tParentAccess: %s", ParentType ? to_str( ParentAccess )  : "No Parent" ); | ||||||
| 			result.append_fmt( "\n\tParentType  : %s", ParentType ? ParentType->type_str()  : "Null" ); | 			append_fmt( result, "\n\tParentType  : %s", ParentType ? ParentType->type_str()  : "Null" ); | ||||||
| 		break; | 		break; | ||||||
|  |  | ||||||
| 		case Constructor: | 		case Constructor: | ||||||
| 			if ( Prev ) | 			if ( Prev ) | ||||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
| 			if ( Next ) | 			if ( Next ) | ||||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
|  |  | ||||||
| 			result.append_fmt( "\n\tInlineCmt      : %S", InlineCmt       ? InlineCmt->Content           : "Null" ); | 			append_fmt( result, "\n\tInlineCmt      : %S", InlineCmt       ? InlineCmt->Content           : "Null" ); | ||||||
| 			result.append_fmt( "\n\tSpecs          : %S", Specs           ? Specs->to_string()           : "Null" ); | 			append_fmt( result, "\n\tSpecs          : %S", Specs           ? Specs->to_string()           : "Null" ); | ||||||
| 			result.append_fmt( "\n\tInitializerList: %S", InitializerList ? InitializerList->to_string() : "Null" ); | 			append_fmt( result, "\n\tInitializerList: %S", InitializerList ? InitializerList->to_string() : "Null" ); | ||||||
| 			result.append_fmt( "\n\tParams         : %S", Params          ? Params->to_string()          : "Null" ); | 			append_fmt( result, "\n\tParams         : %S", Params          ? Params->to_string()          : "Null" ); | ||||||
| 			result.append_fmt( "\n\tBody           : %S", Body            ? Body->debug_str()            : "Null" ); | 			append_fmt( result, "\n\tBody           : %S", Body            ? Body->debug_str()            : "Null" ); | ||||||
| 		break; | 		break; | ||||||
|  |  | ||||||
| 		case Constructor_Fwd: | 		case Constructor_Fwd: | ||||||
| 			if ( Prev ) | 			if ( Prev ) | ||||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
| 			if ( Next ) | 			if ( Next ) | ||||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
|  |  | ||||||
| 			result.append_fmt( "\n\tInlineCmt      : %S", InlineCmt       ? InlineCmt->Content           : "Null" ); | 			append_fmt( result, "\n\tInlineCmt      : %S", InlineCmt       ? InlineCmt->Content           : "Null" ); | ||||||
| 			result.append_fmt( "\n\tSpecs          : %S", Specs           ? Specs->to_string()           : "Null" ); | 			append_fmt( result, "\n\tSpecs          : %S", Specs           ? Specs->to_string()           : "Null" ); | ||||||
| 			result.append_fmt( "\n\tInitializerList: %S", InitializerList ? InitializerList->to_string() : "Null" ); | 			append_fmt( result, "\n\tInitializerList: %S", InitializerList ? InitializerList->to_string() : "Null" ); | ||||||
| 			result.append_fmt( "\n\tParams         : %S", Params          ? Params->to_string()          : "Null" ); | 			append_fmt( result, "\n\tParams         : %S", Params          ? Params->to_string()          : "Null" ); | ||||||
| 		break; | 		break; | ||||||
|  |  | ||||||
| 		case Destructor: | 		case Destructor: | ||||||
| 			if ( Prev ) | 			if ( Prev ) | ||||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
| 			if ( Next ) | 			if ( Next ) | ||||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
|  |  | ||||||
| 			result.append_fmt( "\n\tInlineCmt      : %S", InlineCmt ? InlineCmt->Content : "Null" ); | 			append_fmt( result, "\n\tInlineCmt      : %S", InlineCmt ? InlineCmt->Content : "Null" ); | ||||||
| 			result.append_fmt( "\n\tSpecs          : %S", Specs     ? Specs->to_string() : "Null" ); | 			append_fmt( result, "\n\tSpecs          : %S", Specs     ? Specs->to_string() : "Null" ); | ||||||
| 			result.append_fmt( "\n\tBody           : %S", Body      ? Body->debug_str()  : "Null" ); | 			append_fmt( result, "\n\tBody           : %S", Body      ? Body->debug_str()  : "Null" ); | ||||||
| 		break; | 		break; | ||||||
|  |  | ||||||
| 		case Destructor_Fwd: | 		case Destructor_Fwd: | ||||||
| @@ -124,208 +124,208 @@ char const* AST::debug_str() | |||||||
| 		case Enum: | 		case Enum: | ||||||
| 		case Enum_Class: | 		case Enum_Class: | ||||||
| 			if ( Prev ) | 			if ( Prev ) | ||||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
| 			if ( Next ) | 			if ( Next ) | ||||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
|  |  | ||||||
| 			result.append_fmt( "\n\tInlineCmt       : %S", InlineCmt      ? InlineCmt->Content          : "Null" ); | 			append_fmt( result, "\n\tInlineCmt       : %S", InlineCmt      ? InlineCmt->Content          : "Null" ); | ||||||
| 			result.append_fmt( "\n\tAttributes      : %S", Attributes     ? Attributes->to_string()     : "Null" ); | 			append_fmt( result, "\n\tAttributes      : %S", Attributes     ? Attributes->to_string()     : "Null" ); | ||||||
| 			result.append_fmt( "\n\tUnderlying Type : %S", UnderlyingType ? UnderlyingType->to_string() : "Null" ); | 			append_fmt( result, "\n\tUnderlying Type : %S", UnderlyingType ? UnderlyingType->to_string() : "Null" ); | ||||||
| 			result.append_fmt( "\n\tBody            : %S", Body           ? Body->debug_str()           : "Null" ); | 			append_fmt( result, "\n\tBody            : %S", Body           ? Body->debug_str()           : "Null" ); | ||||||
| 		break; | 		break; | ||||||
|  |  | ||||||
| 		case Enum_Fwd: | 		case Enum_Fwd: | ||||||
| 		case Enum_Class_Fwd: | 		case Enum_Class_Fwd: | ||||||
| 			if ( Prev ) | 			if ( Prev ) | ||||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
| 			if ( Next ) | 			if ( Next ) | ||||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
|  |  | ||||||
| 			result.append_fmt( "\n\tInlineCmt       : %S", InlineCmt      ? InlineCmt->Content          : "Null" ); | 			append_fmt( result, "\n\tInlineCmt       : %S", InlineCmt      ? InlineCmt->Content          : "Null" ); | ||||||
| 			result.append_fmt( "\n\tAttributes      : %S", Attributes     ? Attributes->to_string()     : "Null" ); | 			append_fmt( result, "\n\tAttributes      : %S", Attributes     ? Attributes->to_string()     : "Null" ); | ||||||
| 			result.append_fmt( "\n\tUnderlying Type : %S", UnderlyingType ? UnderlyingType->to_string() : "Null" ); | 			append_fmt( result, "\n\tUnderlying Type : %S", UnderlyingType ? UnderlyingType->to_string() : "Null" ); | ||||||
| 		break; | 		break; | ||||||
|  |  | ||||||
| 		case Extern_Linkage: | 		case Extern_Linkage: | ||||||
| 		case Namespace: | 		case Namespace: | ||||||
| 			if ( Prev ) | 			if ( Prev ) | ||||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
| 			if ( Next ) | 			if ( Next ) | ||||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
|  |  | ||||||
| 			result.append_fmt( "\n\tBody: %S", Body ? Body->debug_str() : "Null" ); | 			append_fmt( result, "\n\tBody: %S", Body ? Body->debug_str() : "Null" ); | ||||||
| 		break; | 		break; | ||||||
|  |  | ||||||
| 		case Friend: | 		case Friend: | ||||||
| 			if ( Prev ) | 			if ( Prev ) | ||||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
| 			if ( Next ) | 			if ( Next ) | ||||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
|  |  | ||||||
| 			result.append_fmt( "\n\tInlineCmt  : %S", InlineCmt   ? InlineCmt->Content       : "Null" ); | 			append_fmt( result, "\n\tInlineCmt  : %S", InlineCmt   ? InlineCmt->Content       : "Null" ); | ||||||
| 			result.append_fmt( "\n\tDeclaration: %S", Declaration ? Declaration->to_string() : "Null" ); | 			append_fmt( result, "\n\tDeclaration: %S", Declaration ? Declaration->to_string() : "Null" ); | ||||||
| 		break; | 		break; | ||||||
|  |  | ||||||
| 		case Function: | 		case Function: | ||||||
| 			if ( Prev ) | 			if ( Prev ) | ||||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
| 			if ( Next ) | 			if ( Next ) | ||||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
|  |  | ||||||
| 			result.append_fmt( "\n\tInlineCmt : %S", InlineCmt  ? InlineCmt->Content      : "Null" ); | 			append_fmt( result, "\n\tInlineCmt : %S", InlineCmt  ? InlineCmt->Content      : "Null" ); | ||||||
| 			result.append_fmt( "\n\tAttributes: %S", Attributes ? Attributes->to_string() : "Null" ); | 			append_fmt( result, "\n\tAttributes: %S", Attributes ? Attributes->to_string() : "Null" ); | ||||||
| 			result.append_fmt( "\n\tSpecs     : %S", Specs      ? Specs->to_string()      : "Null" ); | 			append_fmt( result, "\n\tSpecs     : %S", Specs      ? Specs->to_string()      : "Null" ); | ||||||
| 			result.append_fmt( "\n\tReturnType: %S", ReturnType ? ReturnType->to_string() : "Null" ); | 			append_fmt( result, "\n\tReturnType: %S", ReturnType ? ReturnType->to_string() : "Null" ); | ||||||
| 			result.append_fmt( "\n\tParams    : %S", Params     ? Params->to_string()     : "Null" ); | 			append_fmt( result, "\n\tParams    : %S", Params     ? Params->to_string()     : "Null" ); | ||||||
| 			result.append_fmt( "\n\tBody      : %S", Body       ? Body->debug_str()       : "Null" ); | 			append_fmt( result, "\n\tBody      : %S", Body       ? Body->debug_str()       : "Null" ); | ||||||
| 		break; | 		break; | ||||||
|  |  | ||||||
| 		case Function_Fwd: | 		case Function_Fwd: | ||||||
| 			if ( Prev ) | 			if ( Prev ) | ||||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
| 			if ( Next ) | 			if ( Next ) | ||||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
|  |  | ||||||
| 			result.append_fmt( "\n\tInlineCmt : %S", InlineCmt  ? InlineCmt->Content      : "Null" ); | 			append_fmt( result, "\n\tInlineCmt : %S", InlineCmt  ? InlineCmt->Content      : "Null" ); | ||||||
| 			result.append_fmt( "\n\tAttributes: %S", Attributes ? Attributes->to_string() : "Null" ); | 			append_fmt( result, "\n\tAttributes: %S", Attributes ? Attributes->to_string() : "Null" ); | ||||||
| 			result.append_fmt( "\n\tSpecs     : %S", Specs      ? Specs->to_string()      : "Null" ); | 			append_fmt( result, "\n\tSpecs     : %S", Specs      ? Specs->to_string()      : "Null" ); | ||||||
| 			result.append_fmt( "\n\tReturnType: %S", ReturnType ? ReturnType->to_string() : "Null" ); | 			append_fmt( result, "\n\tReturnType: %S", ReturnType ? ReturnType->to_string() : "Null" ); | ||||||
| 			result.append_fmt( "\n\tParams    : %S", Params     ? Params->to_string()     : "Null" ); | 			append_fmt( result, "\n\tParams    : %S", Params     ? Params->to_string()     : "Null" ); | ||||||
| 		break; | 		break; | ||||||
|  |  | ||||||
| 		case Module: | 		case Module: | ||||||
| 			if ( Prev ) | 			if ( Prev ) | ||||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
| 			if ( Next ) | 			if ( Next ) | ||||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
| 		break; | 		break; | ||||||
|  |  | ||||||
| 		case Operator: | 		case Operator: | ||||||
| 		case Operator_Member: | 		case Operator_Member: | ||||||
| 			if ( Prev ) | 			if ( Prev ) | ||||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
| 			if ( Next ) | 			if ( Next ) | ||||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
|  |  | ||||||
| 			result.append_fmt( "\n\tInlineCmt : %S", InlineCmt  ? InlineCmt->Content      : "Null" ); | 			append_fmt( result, "\n\tInlineCmt : %S", InlineCmt  ? InlineCmt->Content      : "Null" ); | ||||||
| 			result.append_fmt( "\n\tAttributes: %S", Attributes ? Attributes->to_string() : "Null" ); | 			append_fmt( result, "\n\tAttributes: %S", Attributes ? Attributes->to_string() : "Null" ); | ||||||
| 			result.append_fmt( "\n\tSpecs     : %S", Specs      ? Specs->to_string()      : "Null" ); | 			append_fmt( result, "\n\tSpecs     : %S", Specs      ? Specs->to_string()      : "Null" ); | ||||||
| 			result.append_fmt( "\n\tReturnType: %S", ReturnType ? ReturnType->to_string() : "Null" ); | 			append_fmt( result, "\n\tReturnType: %S", ReturnType ? ReturnType->to_string() : "Null" ); | ||||||
| 			result.append_fmt( "\n\tParams    : %S", Params     ? Params->to_string()     : "Null" ); | 			append_fmt( result, "\n\tParams    : %S", Params     ? Params->to_string()     : "Null" ); | ||||||
| 			result.append_fmt( "\n\tBody      : %S", Body       ? Body->debug_str()       : "Null" ); | 			append_fmt( result, "\n\tBody      : %S", Body       ? Body->debug_str()       : "Null" ); | ||||||
| 			result.append_fmt( "\n\tOp        : %S", to_str( Op ) ); | 			append_fmt( result, "\n\tOp        : %S", to_str( Op ) ); | ||||||
| 		break; | 		break; | ||||||
|  |  | ||||||
| 		case Operator_Fwd: | 		case Operator_Fwd: | ||||||
| 		case Operator_Member_Fwd: | 		case Operator_Member_Fwd: | ||||||
| 			if ( Prev ) | 			if ( Prev ) | ||||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
| 			if ( Next ) | 			if ( Next ) | ||||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
|  |  | ||||||
| 			result.append_fmt( "\n\tInlineCmt : %S", InlineCmt  ? InlineCmt->Content      : "Null" ); | 			append_fmt( result, "\n\tInlineCmt : %S", InlineCmt  ? InlineCmt->Content      : "Null" ); | ||||||
| 			result.append_fmt( "\n\tAttributes: %S", Attributes ? Attributes->to_string() : "Null" ); | 			append_fmt( result, "\n\tAttributes: %S", Attributes ? Attributes->to_string() : "Null" ); | ||||||
| 			result.append_fmt( "\n\tSpecs     : %S", Specs      ? Specs->to_string()      : "Null" ); | 			append_fmt( result, "\n\tSpecs     : %S", Specs      ? Specs->to_string()      : "Null" ); | ||||||
| 			result.append_fmt( "\n\tReturnType: %S", ReturnType ? ReturnType->to_string() : "Null" ); | 			append_fmt( result, "\n\tReturnType: %S", ReturnType ? ReturnType->to_string() : "Null" ); | ||||||
| 			result.append_fmt( "\n\tParams    : %S", Params     ? Params->to_string()     : "Null" ); | 			append_fmt( result, "\n\tParams    : %S", Params     ? Params->to_string()     : "Null" ); | ||||||
| 			result.append_fmt( "\n\tOp        : %S", to_str( Op ) ); | 			append_fmt( result, "\n\tOp        : %S", to_str( Op ) ); | ||||||
| 		break; | 		break; | ||||||
|  |  | ||||||
| 		case Operator_Cast: | 		case Operator_Cast: | ||||||
| 			if ( Prev ) | 			if ( Prev ) | ||||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
| 			if ( Next ) | 			if ( Next ) | ||||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
|  |  | ||||||
| 			result.append_fmt( "\n\tInlineCmt : %S", InlineCmt  ? InlineCmt->Content     : "Null" ); | 			append_fmt( result, "\n\tInlineCmt : %S", InlineCmt  ? InlineCmt->Content     : "Null" ); | ||||||
| 			result.append_fmt( "\n\tSpecs     : %S", Specs      ? Specs->to_string()     : "Null" ); | 			append_fmt( result, "\n\tSpecs     : %S", Specs      ? Specs->to_string()     : "Null" ); | ||||||
| 			result.append_fmt( "\n\tValueType : %S", ValueType  ? ValueType->to_string() : "Null" ); | 			append_fmt( result, "\n\tValueType : %S", ValueType  ? ValueType->to_string() : "Null" ); | ||||||
| 			result.append_fmt( "\n\tBody      : %S", Body       ? Body->debug_str()      : "Null" ); | 			append_fmt( result, "\n\tBody      : %S", Body       ? Body->debug_str()      : "Null" ); | ||||||
| 		break; | 		break; | ||||||
|  |  | ||||||
| 		case Operator_Cast_Fwd: | 		case Operator_Cast_Fwd: | ||||||
| 			if ( Prev ) | 			if ( Prev ) | ||||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
| 			if ( Next ) | 			if ( Next ) | ||||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
|  |  | ||||||
| 			result.append_fmt( "\n\tInlineCmt : %S", InlineCmt  ? InlineCmt->Content     : "Null" ); | 			append_fmt( result, "\n\tInlineCmt : %S", InlineCmt  ? InlineCmt->Content     : "Null" ); | ||||||
| 			result.append_fmt( "\n\tSpecs     : %S", Specs      ? Specs->to_string()     : "Null" ); | 			append_fmt( result, "\n\tSpecs     : %S", Specs      ? Specs->to_string()     : "Null" ); | ||||||
| 			result.append_fmt( "\n\tValueType : %S", ValueType  ? ValueType->to_string() : "Null" ); | 			append_fmt( result, "\n\tValueType : %S", ValueType  ? ValueType->to_string() : "Null" ); | ||||||
| 		break; | 		break; | ||||||
|  |  | ||||||
| 		case Parameters: | 		case Parameters: | ||||||
| 			result.append_fmt( "\n\tNumEntries: %d", NumEntries ); | 			append_fmt( result, "\n\tNumEntries: %d", NumEntries ); | ||||||
| 			result.append_fmt( "\n\tLast      : %S", Last->Name ); | 			append_fmt( result, "\n\tLast      : %S", Last->Name ); | ||||||
| 			result.append_fmt( "\n\tNext      : %S", Next->Name ); | 			append_fmt( result, "\n\tNext      : %S", Next->Name ); | ||||||
| 			result.append_fmt( "\n\tValueType : %S", ValueType ? ValueType->to_string() : "Null" ); | 			append_fmt( result, "\n\tValueType : %S", ValueType ? ValueType->to_string() : "Null" ); | ||||||
| 			result.append_fmt( "\n\tValue     : %S", Value     ? Value->to_string()     : "Null" ); | 			append_fmt( result, "\n\tValue     : %S", Value     ? Value->to_string()     : "Null" ); | ||||||
| 		break; | 		break; | ||||||
|  |  | ||||||
| 		case Specifiers: | 		case Specifiers: | ||||||
| 		{ | 		{ | ||||||
| 			result.append_fmt( "\n\tNumEntries: %d", NumEntries ); | 			append_fmt( result, "\n\tNumEntries: %d", NumEntries ); | ||||||
| 			result.append( "\n\tArrSpecs: " ); | 			GEN_NS append( result, "\n\tArrSpecs: " ); | ||||||
|  |  | ||||||
| 			s32 idx  = 0; | 			s32 idx  = 0; | ||||||
| 			s32 left = NumEntries; | 			s32 left = NumEntries; | ||||||
| 			while ( left-- ) | 			while ( left-- ) | ||||||
| 			{ | 			{ | ||||||
| 				StrC spec = ESpecifier::to_str( ArrSpecs[idx] ); | 				StrC spec = ESpecifier::to_str( ArrSpecs[idx] ); | ||||||
| 				result.append_fmt( "%.*s, ", spec.Len, spec.Ptr ); | 				append_fmt( result, "%.*s, ", spec.Len, spec.Ptr ); | ||||||
| 				idx++; | 				idx++; | ||||||
| 			} | 			} | ||||||
| 			result.append_fmt( "\n\tNextSpecs: %S", NextSpecs ? NextSpecs->debug_str() : "Null" ); | 			append_fmt( result, "\n\tNextSpecs: %S", NextSpecs ? NextSpecs->debug_str() : "Null" ); | ||||||
| 		} | 		} | ||||||
| 		break; | 		break; | ||||||
|  |  | ||||||
| 		case Template: | 		case Template: | ||||||
| 			if ( Prev ) | 			if ( Prev ) | ||||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
| 			if ( Next ) | 			if ( Next ) | ||||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
|  |  | ||||||
| 			result.append_fmt( "\n\tParams     : %S", Params      ? Params->to_string()      : "Null" ); | 			append_fmt( result, "\n\tParams     : %S", Params      ? Params->to_string()      : "Null" ); | ||||||
| 			result.append_fmt( "\n\tDeclaration: %S", Declaration ? Declaration->to_string() : "Null" ); | 			append_fmt( result, "\n\tDeclaration: %S", Declaration ? Declaration->to_string() : "Null" ); | ||||||
| 		break; | 		break; | ||||||
|  |  | ||||||
| 		case Typedef: | 		case Typedef: | ||||||
| 			if ( Prev ) | 			if ( Prev ) | ||||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
| 			if ( Next ) | 			if ( Next ) | ||||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
|  |  | ||||||
| 			result.append_fmt( "\n\tInlineCmt     : %S", InlineCmt      ? InlineCmt->Content          : "Null" ); | 			append_fmt( result, "\n\tInlineCmt     : %S", InlineCmt      ? InlineCmt->Content          : "Null" ); | ||||||
| 			result.append_fmt( "\n\tUnderlyingType: %S", UnderlyingType ? UnderlyingType->to_string() : "Null" ); | 			append_fmt( result, "\n\tUnderlyingType: %S", UnderlyingType ? UnderlyingType->to_string() : "Null" ); | ||||||
| 		break; | 		break; | ||||||
|  |  | ||||||
| 		case Typename: | 		case Typename: | ||||||
| 			result.append_fmt( "\n\tAttributes     : %S", Attributes ? Attributes->to_string() : "Null" ); | 			append_fmt( result, "\n\tAttributes     : %S", Attributes ? Attributes->to_string() : "Null" ); | ||||||
| 			result.append_fmt( "\n\tSpecs          : %S", Specs      ? Specs->to_string()      : "Null" ); | 			append_fmt( result, "\n\tSpecs          : %S", Specs      ? Specs->to_string()      : "Null" ); | ||||||
| 			result.append_fmt( "\n\tReturnType     : %S", ReturnType ? ReturnType->to_string() : "Null" ); | 			append_fmt( result, "\n\tReturnType     : %S", ReturnType ? ReturnType->to_string() : "Null" ); | ||||||
| 			result.append_fmt( "\n\tParams         : %S", Params     ? Params->to_string()     : "Null" ); | 			append_fmt( result, "\n\tParams         : %S", Params     ? Params->to_string()     : "Null" ); | ||||||
| 			result.append_fmt( "\n\tArrExpr        : %S", ArrExpr    ? ArrExpr->to_string()    : "Null" ); | 			append_fmt( result, "\n\tArrExpr        : %S", ArrExpr    ? ArrExpr->to_string()    : "Null" ); | ||||||
| 		break; | 		break; | ||||||
|  |  | ||||||
| 		case Union: | 		case Union: | ||||||
| 			if ( Prev ) | 			if ( Prev ) | ||||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
| 			if ( Next ) | 			if ( Next ) | ||||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
|  |  | ||||||
| 			result.append_fmt( "\n\tAttributes: %S", Attributes ? Attributes->to_string() : "Null" ); | 			append_fmt( result, "\n\tAttributes: %S", Attributes ? Attributes->to_string() : "Null" ); | ||||||
| 			result.append_fmt( "\n\tBody      : %S", Body       ? Body->debug_str()       : "Null" ); | 			append_fmt( result, "\n\tBody      : %S", Body       ? Body->debug_str()       : "Null" ); | ||||||
| 		break; | 		break; | ||||||
|  |  | ||||||
| 		case Using: | 		case Using: | ||||||
| 			if ( Prev ) | 			if ( Prev ) | ||||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
| 			if ( Next ) | 			if ( Next ) | ||||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
|  |  | ||||||
| 			result.append_fmt( "\n\tInlineCmt     : %S", InlineCmt      ? InlineCmt->Content          : "Null" ); | 			append_fmt( result, "\n\tInlineCmt     : %S", InlineCmt      ? InlineCmt->Content          : "Null" ); | ||||||
| 			result.append_fmt( "\n\tAttributes    : %S", Attributes     ? Attributes->to_string()     : "Null" ); | 			append_fmt( result, "\n\tAttributes    : %S", Attributes     ? Attributes->to_string()     : "Null" ); | ||||||
| 			result.append_fmt( "\n\tUnderlyingType: %S", UnderlyingType ? UnderlyingType->to_string() : "Null" ); | 			append_fmt( result, "\n\tUnderlyingType: %S", UnderlyingType ? UnderlyingType->to_string() : "Null" ); | ||||||
| 		break; | 		break; | ||||||
|  |  | ||||||
| 		case Variable: | 		case Variable: | ||||||
| @@ -333,25 +333,25 @@ char const* AST::debug_str() | |||||||
| 			if ( Parent && Parent->Type == Variable ) | 			if ( Parent && Parent->Type == Variable ) | ||||||
| 			{ | 			{ | ||||||
| 				// Its a NextVar | 				// Its a NextVar | ||||||
| 				result.append_fmt( "\n\tSpecs       : %S", Specs        ? Specs->to_string()        : "Null" ); | 				append_fmt( result, "\n\tSpecs       : %S", Specs        ? Specs->to_string()        : "Null" ); | ||||||
| 				result.append_fmt( "\n\tValue       : %S", Value        ? Value->to_string()        : "Null" ); | 				append_fmt( result, "\n\tValue       : %S", Value        ? Value->to_string()        : "Null" ); | ||||||
| 				result.append_fmt( "\n\tBitfieldSize: %S", BitfieldSize ? BitfieldSize->to_string() : "Null" ); | 				append_fmt( result, "\n\tBitfieldSize: %S", BitfieldSize ? BitfieldSize->to_string() : "Null" ); | ||||||
| 				result.append_fmt( "\n\tNextVar     : %S", NextVar      ? NextVar->debug_str()      : "Null" ); | 				append_fmt( result, "\n\tNextVar     : %S", NextVar      ? NextVar->debug_str()      : "Null" ); | ||||||
| 				break; | 				break; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			if ( Prev ) | 			if ( Prev ) | ||||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
| 			if ( Next ) | 			if ( Next ) | ||||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||||
|  |  | ||||||
| 			result.append_fmt( "\n\tInlineCmt   : %S", InlineCmt    ? InlineCmt->Content        : "Null" ); | 			append_fmt( result, "\n\tInlineCmt   : %S", InlineCmt    ? InlineCmt->Content        : "Null" ); | ||||||
| 			result.append_fmt( "\n\tAttributes  : %S", Attributes   ? Attributes->to_string()   : "Null" ); | 			append_fmt( result, "\n\tAttributes  : %S", Attributes   ? Attributes->to_string()   : "Null" ); | ||||||
| 			result.append_fmt( "\n\tSpecs       : %S", Specs        ? Specs->to_string()        : "Null" ); | 			append_fmt( result, "\n\tSpecs       : %S", Specs        ? Specs->to_string()        : "Null" ); | ||||||
| 			result.append_fmt( "\n\tValueType   : %S", ValueType    ? ValueType->to_string()    : "Null" ); | 			append_fmt( result, "\n\tValueType   : %S", ValueType    ? ValueType->to_string()    : "Null" ); | ||||||
| 			result.append_fmt( "\n\tBitfieldSize: %S", BitfieldSize ? BitfieldSize->to_string() : "Null" ); | 			append_fmt( result, "\n\tBitfieldSize: %S", BitfieldSize ? BitfieldSize->to_string() : "Null" ); | ||||||
| 			result.append_fmt( "\n\tValue       : %S", Value        ? Value->to_string()        : "Null" ); | 			append_fmt( result, "\n\tValue       : %S", Value        ? Value->to_string()        : "Null" ); | ||||||
| 			result.append_fmt( "\n\tNextVar     : %S", NextVar      ? NextVar->debug_str()      : "Null" ); | 			append_fmt( result, "\n\tNextVar     : %S", NextVar      ? NextVar->debug_str()      : "Null" ); | ||||||
| 		break; | 		break; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -372,7 +372,7 @@ AST* AST::duplicate() | |||||||
|  |  | ||||||
| String AST::to_string() | String AST::to_string() | ||||||
| { | { | ||||||
| 	String result = String::make( GlobalAllocator, "" ); | 	String result = string_make( GlobalAllocator, "" ); | ||||||
| 	to_string( result ); | 	to_string( result ); | ||||||
| 	return result; | 	return result; | ||||||
| } | } | ||||||
| @@ -390,25 +390,25 @@ void AST::to_string( String& result ) | |||||||
| 		#ifdef GEN_DONT_ALLOW_INVALID_CODE | 		#ifdef GEN_DONT_ALLOW_INVALID_CODE | ||||||
| 			log_failure("Attempted to serialize invalid code! - %S", Parent ? Parent->debug_str() : Name ); | 			log_failure("Attempted to serialize invalid code! - %S", Parent ? Parent->debug_str() : Name ); | ||||||
| 		#else | 		#else | ||||||
| 			result.append_fmt( "Invalid Code!" ); | 			append_fmt( result, "Invalid Code!" ); | ||||||
| 		#endif | 		#endif | ||||||
| 		break; | 		break; | ||||||
|  |  | ||||||
| 		case NewLine: | 		case NewLine: | ||||||
| 			result.append("\n"); | 			GEN_NS append( result,"\n"); | ||||||
| 		break; | 		break; | ||||||
|  |  | ||||||
| 		case Untyped: | 		case Untyped: | ||||||
| 		case Execution: | 		case Execution: | ||||||
| 		case Comment: | 		case Comment: | ||||||
| 		case PlatformAttributes: | 		case PlatformAttributes: | ||||||
| 			result.append( Content ); | 			GEN_NS append( result, Content ); | ||||||
| 		break; | 		break; | ||||||
|  |  | ||||||
| 		case Access_Private: | 		case Access_Private: | ||||||
| 		case Access_Protected: | 		case Access_Protected: | ||||||
| 		case Access_Public: | 		case Access_Public: | ||||||
| 			result.append( Name ); | 			GEN_NS append( result, Name ); | ||||||
| 		break; | 		break; | ||||||
|  |  | ||||||
| 		case Class: | 		case Class: | ||||||
| @@ -659,8 +659,8 @@ bool AST::is_equal( AST* other ) | |||||||
| 			"so it must be verified by eye for now\n"                     \ | 			"so it must be verified by eye for now\n"                     \ | ||||||
| 			"AST   Content:\n%S\n"                                        \ | 			"AST   Content:\n%S\n"                                        \ | ||||||
| 			"Other Content:\n%S\n"                                        \ | 			"Other Content:\n%S\n"                                        \ | ||||||
| 			, content.visualize_whitespace()                              \ | 			, visualize_whitespace(content)                               \ | ||||||
| 			, other->content.visualize_whitespace()                       \ | 			, visualize_whitespace(other->content)                        \ | ||||||
| 		);                                                                \ | 		);                                                                \ | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -377,6 +377,7 @@ struct AST | |||||||
| 		AccessSpec    ParentAccess; | 		AccessSpec    ParentAccess; | ||||||
| 		s32           NumEntries; | 		s32           NumEntries; | ||||||
| 		s32           VarConstructorInit;  // Used by variables to know that initialization is using a constructor expression instead of an assignment expression. | 		s32           VarConstructorInit;  // Used by variables to know that initialization is using a constructor expression instead of an assignment expression. | ||||||
|  | 		b32           EnumUnderlyingMacro; // Used by enums incase the user wants to wrap underlying type specification in a macro | ||||||
| 	}; | 	}; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -174,7 +174,7 @@ struct AST_Enum | |||||||
| 			CodeAttributes Attributes; | 			CodeAttributes Attributes; | ||||||
| 			char           _PAD_SPEC_  [ sizeof(AST*) ]; | 			char           _PAD_SPEC_  [ sizeof(AST*) ]; | ||||||
| 			CodeType       UnderlyingType; | 			CodeType       UnderlyingType; | ||||||
| 			char	       _PAD_PARAMS_[ sizeof(AST*) ]; | 			Code           UnderlyingTypeMacro; | ||||||
| 			CodeBody       Body; | 			CodeBody       Body; | ||||||
| 			char 	       _PAD_PROPERTIES_2_[ sizeof(AST*) ]; | 			char 	       _PAD_PROPERTIES_2_[ sizeof(AST*) ]; | ||||||
| 		}; | 		}; | ||||||
| @@ -186,7 +186,7 @@ struct AST_Enum | |||||||
| 	StringCached           Name; | 	StringCached           Name; | ||||||
| 	CodeT                  Type; | 	CodeT                  Type; | ||||||
| 	ModuleFlag             ModuleFlags; | 	ModuleFlag             ModuleFlags; | ||||||
| 	char 			       _PAD_UNUSED_[ sizeof(u32) ]; | 	b32                    EnumUnderlyingMacro; | ||||||
| }; | }; | ||||||
| static_assert( sizeof(AST_Enum) == sizeof(AST), "ERROR: AST_Enum is not the same size as AST"); | static_assert( sizeof(AST_Enum) == sizeof(AST), "ERROR: AST_Enum is not the same size as AST"); | ||||||
|  |  | ||||||
|   | |||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -165,6 +165,46 @@ struct CodeSpecifiers | |||||||
|  |  | ||||||
| 		return -1; | 		return -1; | ||||||
| 	} | 	} | ||||||
|  | 	s32 remove( SpecifierT to_remove ) | ||||||
|  | 	{ | ||||||
|  | 		if ( ast == nullptr ) | ||||||
|  | 		{ | ||||||
|  | 			log_failure("CodeSpecifiers: Attempted to append to a null specifiers AST!"); | ||||||
|  | 			return -1; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if ( raw()->NumEntries == AST::ArrSpecs_Cap ) | ||||||
|  | 		{ | ||||||
|  | 			log_failure("CodeSpecifiers: Attempted to append over %d specifiers to a specifiers AST!", AST::ArrSpecs_Cap ); | ||||||
|  | 			return -1; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		s32 result = -1; | ||||||
|  |  | ||||||
|  | 		s32 curr = 0; | ||||||
|  | 		s32 next = 0; | ||||||
|  | 		for(; next < raw()->NumEntries; ++ curr, ++ next) | ||||||
|  | 		{ | ||||||
|  | 			SpecifierT spec = raw()->ArrSpecs[next]; | ||||||
|  | 			if (spec == to_remove) | ||||||
|  | 			{ | ||||||
|  | 				result = next; | ||||||
|  |  | ||||||
|  | 				next ++; | ||||||
|  | 				if (next >= raw()->NumEntries) | ||||||
|  | 					break; | ||||||
|  |  | ||||||
|  | 				spec = raw()->ArrSpecs[next]; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			raw()->ArrSpecs[ curr ] = spec; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (result > -1) { | ||||||
|  | 			raw()->NumEntries --; | ||||||
|  | 		} | ||||||
|  | 		return result; | ||||||
|  | 	} | ||||||
| 	void to_string( String& result ); | 	void to_string( String& result ); | ||||||
| 	AST* raw() | 	AST* raw() | ||||||
| 	{ | 	{ | ||||||
|   | |||||||
| @@ -133,6 +133,7 @@ extern CodeType t_typename; | |||||||
|  |  | ||||||
| #pragma region Macros | #pragma region Macros | ||||||
|  |  | ||||||
|  | #ifndef token_fmt | ||||||
| #	define gen_main main | #	define gen_main main | ||||||
|  |  | ||||||
| #	define __ NoCode | #	define __ NoCode | ||||||
| @@ -151,6 +152,7 @@ extern CodeType t_typename; | |||||||
|  |  | ||||||
| 	// Takes a format string (char const*) and a list of tokens (StrC) and returns a StrC of the formatted string. | 	// Takes a format string (char const*) and a list of tokens (StrC) and returns a StrC of the formatted string. | ||||||
| #	define token_fmt( ... ) GEN_NS token_fmt_impl( (num_args( __VA_ARGS__ ) + 1) / 2, __VA_ARGS__ ) | #	define token_fmt( ... ) GEN_NS token_fmt_impl( (num_args( __VA_ARGS__ ) + 1) / 2, __VA_ARGS__ ) | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #pragma endregion Macros | #pragma endregion Macros | ||||||
|  |  | ||||||
|   | |||||||
| @@ -78,7 +78,7 @@ void CodeClass::add_interface( CodeType type ) | |||||||
| 	if ( possible_slot.ast ) | 	if ( possible_slot.ast ) | ||||||
| 	{ | 	{ | ||||||
| 		// Were adding an interface to parent type, so we need to make sure the parent type is public. | 		// Were adding an interface to parent type, so we need to make sure the parent type is public. | ||||||
| 		ast->ParentAccess = AccessSpec::Public; | 		ast->ParentAccess = AccessSpec_Public; | ||||||
| 		// If your planning on adding a proper parent, | 		// If your planning on adding a proper parent, | ||||||
| 		// then you'll need to move this over to ParentType->next and update ParentAccess accordingly. | 		// then you'll need to move this over to ParentType->next and update ParentAccess accordingly. | ||||||
| 	} | 	} | ||||||
| @@ -151,7 +151,7 @@ void CodeStruct::add_interface( CodeType type ) | |||||||
| 	if ( possible_slot.ast ) | 	if ( possible_slot.ast ) | ||||||
| 	{ | 	{ | ||||||
| 		// Were adding an interface to parent type, so we need to make sure the parent type is public. | 		// Were adding an interface to parent type, so we need to make sure the parent type is public. | ||||||
| 		ast->ParentAccess = AccessSpec::Public; | 		ast->ParentAccess = AccessSpec_Public; | ||||||
| 		// If your planning on adding a proper parent, | 		// If your planning on adding a proper parent, | ||||||
| 		// then you'll need to move this over to ParentType->next and update ParentAccess accordingly. | 		// then you'll need to move this over to ParentType->next and update ParentAccess accordingly. | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -11,7 +11,7 @@ internal void deinit(); | |||||||
| internal | internal | ||||||
| void* Global_Allocator_Proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ) | void* Global_Allocator_Proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ) | ||||||
| { | { | ||||||
| 	Arena* last = & Global_AllocatorBuckets.back(); | 	Arena* last = & back(Global_AllocatorBuckets); | ||||||
|  |  | ||||||
| 	switch ( type ) | 	switch ( type ) | ||||||
| 	{ | 	{ | ||||||
| @@ -19,18 +19,18 @@ void* Global_Allocator_Proc( void* allocator_data, AllocType type, ssize size, s | |||||||
| 		{ | 		{ | ||||||
| 			if ( ( last->TotalUsed + size ) > last->TotalSize ) | 			if ( ( last->TotalUsed + size ) > last->TotalSize ) | ||||||
| 			{ | 			{ | ||||||
| 				Arena bucket = Arena::init_from_allocator( heap(), Global_BucketSize ); | 				Arena bucket = arena_init_from_allocator( heap(), Global_BucketSize ); | ||||||
|  |  | ||||||
| 				if ( bucket.PhysicalStart == nullptr ) | 				if ( bucket.PhysicalStart == nullptr ) | ||||||
| 					GEN_FATAL( "Failed to create bucket for Global_AllocatorBuckets"); | 					GEN_FATAL( "Failed to create bucket for Global_AllocatorBuckets"); | ||||||
|  |  | ||||||
| 				if ( ! Global_AllocatorBuckets.append( bucket ) ) | 				if ( ! append( Global_AllocatorBuckets, bucket ) ) | ||||||
| 					GEN_FATAL( "Failed to append bucket to Global_AllocatorBuckets"); | 					GEN_FATAL( "Failed to append bucket to Global_AllocatorBuckets"); | ||||||
|  |  | ||||||
| 				last = & Global_AllocatorBuckets.back(); | 				last = & back(Global_AllocatorBuckets); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			return alloc_align( * last, size, alignment ); | 			return alloc_align( allocator_info(* last), size, alignment ); | ||||||
| 		} | 		} | ||||||
| 		case EAllocation_FREE: | 		case EAllocation_FREE: | ||||||
| 		{ | 		{ | ||||||
| @@ -46,15 +46,15 @@ void* Global_Allocator_Proc( void* allocator_data, AllocType type, ssize size, s | |||||||
| 		{ | 		{ | ||||||
| 			if ( last->TotalUsed + size > last->TotalSize ) | 			if ( last->TotalUsed + size > last->TotalSize ) | ||||||
| 			{ | 			{ | ||||||
| 				Arena bucket = Arena::init_from_allocator( heap(), Global_BucketSize ); | 				Arena bucket = arena_init_from_allocator( heap(), Global_BucketSize ); | ||||||
|  |  | ||||||
| 				if ( bucket.PhysicalStart == nullptr ) | 				if ( bucket.PhysicalStart == nullptr ) | ||||||
| 					GEN_FATAL( "Failed to create bucket for Global_AllocatorBuckets"); | 					GEN_FATAL( "Failed to create bucket for Global_AllocatorBuckets"); | ||||||
|  |  | ||||||
| 				if ( ! Global_AllocatorBuckets.append( bucket ) ) | 				if ( ! append( Global_AllocatorBuckets, bucket ) ) | ||||||
| 					GEN_FATAL( "Failed to append bucket to Global_AllocatorBuckets"); | 					GEN_FATAL( "Failed to append bucket to Global_AllocatorBuckets"); | ||||||
|  |  | ||||||
| 				last = & Global_AllocatorBuckets.back(); | 				last = & back(Global_AllocatorBuckets); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			void* result = alloc_align( last->Backing, size, alignment ); | 			void* result = alloc_align( last->Backing, size, alignment ); | ||||||
| @@ -75,8 +75,8 @@ internal | |||||||
| void define_constants() | void define_constants() | ||||||
| { | { | ||||||
| 	Code::Global                         = make_code(); | 	Code::Global                         = make_code(); | ||||||
| 	Code::Global->Name    = get_cached_string( txt("Global Code") ); | 	scast(String, Code::Global->Name)    = get_cached_string( txt("Global Code") ); | ||||||
| 	Code::Global->Content = Code::Global->Name; | 	scast(String, Code::Global->Content) = Code::Global->Name; | ||||||
|  |  | ||||||
| 	Code::Invalid = make_code(); | 	Code::Invalid = make_code(); | ||||||
| 	Code::Invalid.set_global(); | 	Code::Invalid.set_global(); | ||||||
| @@ -226,6 +226,10 @@ void define_constants() | |||||||
| #	pragma pop_macro("local_persist") | #	pragma pop_macro("local_persist") | ||||||
| #	pragma pop_macro("neverinline") | #	pragma pop_macro("neverinline") | ||||||
|  |  | ||||||
|  | #	pragma push_macro("enum_underlying") | ||||||
|  |  | ||||||
|  | #	pragma pop_macro("enum_underlying") | ||||||
|  |  | ||||||
| #	undef def_constant_spec | #	undef def_constant_spec | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -235,28 +239,27 @@ void init() | |||||||
| 	{ | 	{ | ||||||
| 		GlobalAllocator = AllocatorInfo { & Global_Allocator_Proc, nullptr }; | 		GlobalAllocator = AllocatorInfo { & Global_Allocator_Proc, nullptr }; | ||||||
|  |  | ||||||
| 		Global_AllocatorBuckets = Array<Arena>::init_reserve( heap(), 128 ); | 		Global_AllocatorBuckets = array_init_reserve<Arena>( heap(), 128 ); | ||||||
|  |  | ||||||
| 		if ( Global_AllocatorBuckets == nullptr ) | 		if ( Global_AllocatorBuckets == nullptr ) | ||||||
| 			GEN_FATAL( "Failed to reserve memory for Global_AllocatorBuckets"); | 			GEN_FATAL( "Failed to reserve memory for Global_AllocatorBuckets"); | ||||||
|  |  | ||||||
| 		Arena bucket = Arena::init_from_allocator( heap(), Global_BucketSize ); | 		Arena bucket = arena_init_from_allocator( heap(), Global_BucketSize ); | ||||||
|  |  | ||||||
| 		if ( bucket.PhysicalStart == nullptr ) | 		if ( bucket.PhysicalStart == nullptr ) | ||||||
| 			GEN_FATAL( "Failed to create first bucket for Global_AllocatorBuckets"); | 			GEN_FATAL( "Failed to create first bucket for Global_AllocatorBuckets"); | ||||||
|  |  | ||||||
| 		Global_AllocatorBuckets.append( bucket ); | 		append( Global_AllocatorBuckets, bucket ); | ||||||
|  |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Setup the arrays | 	// Setup the arrays | ||||||
| 	{ | 	{ | ||||||
| 		CodePools = Array<Pool>::init_reserve( Allocator_DataArrays, InitSize_DataArrays ); | 		CodePools = array_init_reserve<Pool>( Allocator_DataArrays, InitSize_DataArrays ); | ||||||
|  |  | ||||||
| 		if ( CodePools == nullptr ) | 		if ( CodePools == nullptr ) | ||||||
| 			GEN_FATAL( "gen::init: Failed to initialize the CodePools array" ); | 			GEN_FATAL( "gen::init: Failed to initialize the CodePools array" ); | ||||||
|  |  | ||||||
| 		StringArenas = Array<Arena>::init_reserve( Allocator_DataArrays, InitSize_DataArrays ); | 		StringArenas = array_init_reserve<Arena>( Allocator_DataArrays, InitSize_DataArrays ); | ||||||
|  |  | ||||||
| 		if ( StringArenas == nullptr ) | 		if ( StringArenas == nullptr ) | ||||||
| 			GEN_FATAL( "gen::init: Failed to initialize the StringArenas array" ); | 			GEN_FATAL( "gen::init: Failed to initialize the StringArenas array" ); | ||||||
| @@ -264,33 +267,33 @@ void init() | |||||||
|  |  | ||||||
| 	// Setup the code pool and code entries arena. | 	// Setup the code pool and code entries arena. | ||||||
| 	{ | 	{ | ||||||
| 		Pool code_pool = Pool::init( Allocator_CodePool, CodePool_NumBlocks, sizeof(AST) ); | 		Pool code_pool = pool_init( Allocator_CodePool, CodePool_NumBlocks, sizeof(AST) ); | ||||||
|  |  | ||||||
| 		if ( code_pool.PhysicalStart == nullptr ) | 		if ( code_pool.PhysicalStart == nullptr ) | ||||||
| 			GEN_FATAL( "gen::init: Failed to initialize the code pool" ); | 			GEN_FATAL( "gen::init: Failed to initialize the code pool" ); | ||||||
|  |  | ||||||
| 		CodePools.append( code_pool ); | 		append(CodePools, code_pool ); | ||||||
|  |  | ||||||
| 		LexArena = Arena::init_from_allocator( Allocator_Lexer, LexAllocator_Size ); | 		LexArena = arena_init_from_allocator( Allocator_Lexer, LexAllocator_Size ); | ||||||
|  |  | ||||||
| 		Arena string_arena = Arena::init_from_allocator( Allocator_StringArena, SizePer_StringArena ); | 		Arena string_arena = arena_init_from_allocator( Allocator_StringArena, SizePer_StringArena ); | ||||||
|  |  | ||||||
| 		if ( string_arena.PhysicalStart == nullptr ) | 		if ( string_arena.PhysicalStart == nullptr ) | ||||||
| 			GEN_FATAL( "gen::init: Failed to initialize the string arena" ); | 			GEN_FATAL( "gen::init: Failed to initialize the string arena" ); | ||||||
|  |  | ||||||
| 		StringArenas.append( string_arena ); | 		append(StringArenas, string_arena ); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Setup the hash tables | 	// Setup the hash tables | ||||||
| 	{ | 	{ | ||||||
| 		StringCache = StringTable::init( Allocator_StringTable ); | 		StringCache = hashtable_init<StringCached>(Allocator_StringTable); | ||||||
|  |  | ||||||
| 		if ( StringCache.Entries == nullptr ) | 		if ( StringCache.Entries == nullptr ) | ||||||
| 			GEN_FATAL( "gen::init: Failed to initialize the StringCache"); | 			GEN_FATAL( "gen::init: Failed to initialize the StringCache"); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Preprocessor Defines | 	// Preprocessor Defines | ||||||
| 	PreprocessorDefines = Array<StringCached>::init_reserve( GlobalAllocator, kilobytes(1) ); | 	PreprocessorDefines = array_init_reserve<StringCached>( GlobalAllocator, kilobytes(1) ); | ||||||
|  |  | ||||||
| 	define_constants(); | 	define_constants(); | ||||||
| 	parser::init(); | 	parser::init(); | ||||||
| @@ -299,62 +302,62 @@ void init() | |||||||
| void deinit() | void deinit() | ||||||
| { | { | ||||||
| 	usize index = 0; | 	usize index = 0; | ||||||
| 	usize left  = CodePools.num(); | 	usize left  = num(CodePools); | ||||||
| 	do | 	do | ||||||
| 	{ | 	{ | ||||||
| 		Pool* code_pool = & CodePools[index]; | 		Pool* code_pool = & CodePools[index]; | ||||||
| 		code_pool->free(); | 		free(* code_pool); | ||||||
| 		index++; | 		index++; | ||||||
| 	} | 	} | ||||||
| 	while ( left--, left ); | 	while ( left--, left ); | ||||||
|  |  | ||||||
| 	index = 0; | 	index = 0; | ||||||
| 	left  = StringArenas.num(); | 	left  = num(StringArenas); | ||||||
| 	do | 	do | ||||||
| 	{ | 	{ | ||||||
| 		Arena* string_arena = & StringArenas[index]; | 		Arena* string_arena = & StringArenas[index]; | ||||||
| 		string_arena->free(); | 		free(* string_arena); | ||||||
| 		index++; | 		index++; | ||||||
| 	} | 	} | ||||||
| 	while ( left--, left ); | 	while ( left--, left ); | ||||||
|  |  | ||||||
| 	StringCache.destroy(); | 	destroy(StringCache); | ||||||
|  |  | ||||||
| 	CodePools.free(); | 	free(CodePools); | ||||||
| 	StringArenas.free(); | 	free(StringArenas); | ||||||
|  |  | ||||||
| 	LexArena.free(); | 	free(LexArena); | ||||||
|  |  | ||||||
| 	PreprocessorDefines.free(); | 	free(PreprocessorDefines); | ||||||
|  |  | ||||||
| 	index = 0; | 	index = 0; | ||||||
| 	left  = Global_AllocatorBuckets.num(); | 	left  = num(Global_AllocatorBuckets); | ||||||
| 	do | 	do | ||||||
| 	{ | 	{ | ||||||
| 		Arena* bucket = & Global_AllocatorBuckets[ index ]; | 		Arena* bucket = & Global_AllocatorBuckets[ index ]; | ||||||
| 		bucket->free(); | 		free(* bucket); | ||||||
| 		index++; | 		index++; | ||||||
| 	} | 	} | ||||||
| 	while ( left--, left ); | 	while ( left--, left ); | ||||||
|  |  | ||||||
| 	Global_AllocatorBuckets.free(); | 	free(Global_AllocatorBuckets); | ||||||
| 	parser::deinit(); | 	parser::deinit(); | ||||||
| } | } | ||||||
|  |  | ||||||
| void reset() | void reset() | ||||||
| { | { | ||||||
| 	s32 index = 0; | 	s32 index = 0; | ||||||
| 	s32 left  = CodePools.num(); | 	s32 left  = num(CodePools); | ||||||
| 	do | 	do | ||||||
| 	{ | 	{ | ||||||
| 		Pool* code_pool = & CodePools[index]; | 		Pool* code_pool = & CodePools[index]; | ||||||
| 		code_pool->clear(); | 		clear(* code_pool); | ||||||
| 		index++; | 		index++; | ||||||
| 	} | 	} | ||||||
| 	while ( left--, left ); | 	while ( left--, left ); | ||||||
|  |  | ||||||
| 	index = 0; | 	index = 0; | ||||||
| 	left  = StringArenas.num(); | 	left  = num(StringArenas); | ||||||
| 	do | 	do | ||||||
| 	{ | 	{ | ||||||
| 		Arena* string_arena = & StringArenas[index]; | 		Arena* string_arena = & StringArenas[index]; | ||||||
| @@ -363,28 +366,28 @@ void reset() | |||||||
| 	} | 	} | ||||||
| 	while ( left--, left ); | 	while ( left--, left ); | ||||||
|  |  | ||||||
| 	StringCache.clear(); | 	clear(StringCache); | ||||||
|  |  | ||||||
| 	define_constants(); | 	define_constants(); | ||||||
| } | } | ||||||
|  |  | ||||||
| AllocatorInfo get_string_allocator( s32 str_length ) | AllocatorInfo get_string_allocator( s32 str_length ) | ||||||
| { | { | ||||||
| 	Arena* last = & StringArenas.back(); | 	Arena* last = & back(StringArenas); | ||||||
|  |  | ||||||
| 	usize size_req = str_length + sizeof(String::Header) + sizeof(char*); | 	usize size_req = str_length + sizeof(StringHeader) + sizeof(char*); | ||||||
|  |  | ||||||
| 	if ( last->TotalUsed + ssize(size_req) > last->TotalSize ) | 	if ( last->TotalUsed + ssize(size_req) > last->TotalSize ) | ||||||
| 	{ | 	{ | ||||||
| 		Arena new_arena = Arena::init_from_allocator( Allocator_StringArena, SizePer_StringArena ); | 		Arena new_arena = arena_init_from_allocator( Allocator_StringArena, SizePer_StringArena ); | ||||||
|  |  | ||||||
| 		if ( ! StringArenas.append( new_arena ) ) | 		if ( ! append(StringArenas, new_arena ) ) | ||||||
| 			GEN_FATAL( "gen::get_string_allocator: Failed to allocate a new string arena" ); | 			GEN_FATAL( "gen::get_string_allocator: Failed to allocate a new string arena" ); | ||||||
|  |  | ||||||
| 		last = & StringArenas.back(); | 		last = & back(StringArenas); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return * last; | 	return allocator_info(* last); | ||||||
| } | } | ||||||
|  |  | ||||||
| // Will either make or retrive a code string. | // Will either make or retrive a code string. | ||||||
| @@ -393,14 +396,14 @@ StringCached get_cached_string( StrC str ) | |||||||
| 	s32 hash_length = str.Len > kilobytes(1) ? kilobytes(1) : str.Len; | 	s32 hash_length = str.Len > kilobytes(1) ? kilobytes(1) : str.Len; | ||||||
| 	u64 key         = crc32( str.Ptr, hash_length ); | 	u64 key         = crc32( str.Ptr, hash_length ); | ||||||
| 	{ | 	{ | ||||||
| 		StringCached* result = StringCache.get( key ); | 		StringCached* result = get(StringCache, key ); | ||||||
|  |  | ||||||
| 		if ( result ) | 		if ( result ) | ||||||
| 			return * result; | 			return * result; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	String result = String::make( get_string_allocator( str.Len ), str ); | 	String result = string_make( get_string_allocator( str.Len ), str ); | ||||||
| 	StringCache.set( key, result ); | 	set<StringCached>(StringCache, key, result ); | ||||||
|  |  | ||||||
| 	return result; | 	return result; | ||||||
| } | } | ||||||
| @@ -408,21 +411,21 @@ StringCached get_cached_string( StrC str ) | |||||||
| // Used internally to retireve a Code object form the CodePool. | // Used internally to retireve a Code object form the CodePool. | ||||||
| Code make_code() | Code make_code() | ||||||
| { | { | ||||||
| 	Pool* allocator = & CodePools.back(); | 	Pool* allocator = & back(CodePools); | ||||||
| 	if ( allocator->FreeList == nullptr ) | 	if ( allocator->FreeList == nullptr ) | ||||||
| 	{ | 	{ | ||||||
| 		Pool code_pool = Pool::init( Allocator_CodePool, CodePool_NumBlocks, sizeof(AST) ); | 		Pool code_pool = pool_init( Allocator_CodePool, CodePool_NumBlocks, sizeof(AST) ); | ||||||
|  |  | ||||||
| 		if ( code_pool.PhysicalStart == nullptr ) | 		if ( code_pool.PhysicalStart == nullptr ) | ||||||
| 			GEN_FATAL( "gen::make_code: Failed to allocate a new code pool - CodePool allcoator returned nullptr." ); | 			GEN_FATAL( "gen::make_code: Failed to allocate a new code pool - CodePool allcoator returned nullptr." ); | ||||||
|  |  | ||||||
| 		if ( ! CodePools.append( code_pool ) ) | 		if ( ! append( CodePools, code_pool ) ) | ||||||
| 			GEN_FATAL( "gen::make_code: Failed to allocate a new code pool - CodePools failed to append new pool." ); | 			GEN_FATAL( "gen::make_code: Failed to allocate a new code pool - CodePools failed to append new pool." ); | ||||||
|  |  | ||||||
| 		allocator = & CodePools.back(); | 		allocator = & back(CodePools); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	Code result { rcast( AST*, alloc( * allocator, sizeof(AST) )) }; | 	Code result { rcast( AST*, alloc( allocator_info(* allocator), sizeof(AST) )) }; | ||||||
| 	mem_set( result.ast, 0, sizeof(AST) ); | 	mem_set( result.ast, 0, sizeof(AST) ); | ||||||
| 	// result->Type = ECode::Invalid; | 	// result->Type = ECode::Invalid; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -44,9 +44,9 @@ CodeComment    def_comment   ( StrC content ); | |||||||
|  |  | ||||||
| CodeClass def_class( StrC name | CodeClass def_class( StrC name | ||||||
| 	, Code           body         = NoCode | 	, Code           body         = NoCode | ||||||
| 	, CodeType       parent       = NoCode, AccessSpec access = AccessSpec::Default | 	, CodeType       parent       = NoCode, AccessSpec access = AccessSpec_Default | ||||||
| 	, CodeAttributes attributes   = NoCode | 	, CodeAttributes attributes   = NoCode | ||||||
| 	, ModuleFlag     mflags       = ModuleFlag::None | 	, ModuleFlag     mflags       = ModuleFlag_None | ||||||
| 	, CodeType*      interfaces   = nullptr, s32 num_interfaces = 0 ); | 	, CodeType*      interfaces   = nullptr, s32 num_interfaces = 0 ); | ||||||
|  |  | ||||||
| CodeConstructor def_constructor( CodeParam params = NoCode, Code initializer_list = NoCode, Code body = NoCode ); | CodeConstructor def_constructor( CodeParam params = NoCode, Code initializer_list = NoCode, Code body = NoCode ); | ||||||
| @@ -57,8 +57,8 @@ CodeDestructor def_destructor( Code body = NoCode, CodeSpecifiers specifiers = N | |||||||
|  |  | ||||||
| CodeEnum def_enum( StrC name | CodeEnum def_enum( StrC name | ||||||
| 	, Code         body      = NoCode,           CodeType       type       = NoCode | 	, Code         body      = NoCode,           CodeType       type       = NoCode | ||||||
| 	, EnumT        specifier = EnumRegular, CodeAttributes attributes = NoCode | 	, EnumT        specifier = EnumDecl_Regular, CodeAttributes attributes = NoCode | ||||||
| 	, ModuleFlag   mflags    = ModuleFlag::None ); | 	, ModuleFlag   mflags    = ModuleFlag_None ); | ||||||
|  |  | ||||||
| CodeExec   def_execution  ( StrC content ); | CodeExec   def_execution  ( StrC content ); | ||||||
| CodeExtern def_extern_link( StrC name, Code body ); | CodeExtern def_extern_link( StrC name, Code body ); | ||||||
| @@ -67,16 +67,16 @@ CodeFriend def_friend     ( Code symbol ); | |||||||
| CodeFn def_function( StrC name | CodeFn def_function( StrC name | ||||||
| 	, CodeParam      params     = NoCode, CodeType       ret_type   = NoCode, Code body = NoCode | 	, CodeParam      params     = NoCode, CodeType       ret_type   = NoCode, Code body = NoCode | ||||||
| 	, CodeSpecifiers specifiers = NoCode, CodeAttributes attributes = NoCode | 	, CodeSpecifiers specifiers = NoCode, CodeAttributes attributes = NoCode | ||||||
| 	, ModuleFlag mflags     = ModuleFlag::None ); | 	, ModuleFlag mflags     = ModuleFlag_None ); | ||||||
|  |  | ||||||
| CodeInclude   def_include  ( StrC content, bool foreign = false ); | CodeInclude   def_include  ( StrC content, bool foreign = false ); | ||||||
| CodeModule    def_module   ( StrC name,            ModuleFlag mflags = ModuleFlag::None ); | CodeModule    def_module   ( StrC name,            ModuleFlag mflags = ModuleFlag_None ); | ||||||
| CodeNS        def_namespace( StrC name, Code body, ModuleFlag mflags = ModuleFlag::None ); | CodeNS        def_namespace( StrC name, Code body, ModuleFlag mflags = ModuleFlag_None ); | ||||||
|  |  | ||||||
| CodeOperator def_operator( OperatorT op, StrC nspace | CodeOperator def_operator( OperatorT op, StrC nspace | ||||||
| 	, CodeParam      params     = NoCode, CodeType       ret_type   = NoCode, Code body = NoCode | 	, CodeParam      params     = NoCode, CodeType       ret_type   = NoCode, Code body = NoCode | ||||||
| 	, CodeSpecifiers specifiers = NoCode, CodeAttributes attributes = NoCode | 	, CodeSpecifiers specifiers = NoCode, CodeAttributes attributes = NoCode | ||||||
| 	, ModuleFlag     mflags     = ModuleFlag::None ); | 	, ModuleFlag     mflags     = ModuleFlag_None ); | ||||||
|  |  | ||||||
| CodeOpCast def_operator_cast( CodeType type, Code body = NoCode, CodeSpecifiers specs = NoCode ); | CodeOpCast def_operator_cast( CodeType type, Code body = NoCode, CodeSpecifiers specs = NoCode ); | ||||||
|  |  | ||||||
| @@ -89,27 +89,27 @@ CodeSpecifiers def_specifier( SpecifierT specifier ); | |||||||
|  |  | ||||||
| CodeStruct def_struct( StrC name | CodeStruct def_struct( StrC name | ||||||
| 	, Code           body       = NoCode | 	, Code           body       = NoCode | ||||||
| 	, CodeType       parent     = NoCode, AccessSpec access = AccessSpec::Default | 	, CodeType       parent     = NoCode, AccessSpec access = AccessSpec_Default | ||||||
| 	, CodeAttributes attributes = NoCode | 	, CodeAttributes attributes = NoCode | ||||||
| 	, ModuleFlag     mflags     = ModuleFlag::None | 	, ModuleFlag     mflags     = ModuleFlag_None | ||||||
| 	, CodeType*      interfaces = nullptr, s32 num_interfaces = 0 ); | 	, CodeType*      interfaces = nullptr, s32 num_interfaces = 0 ); | ||||||
|  |  | ||||||
| CodeTemplate def_template( CodeParam params, Code definition, ModuleFlag mflags = ModuleFlag::None ); | CodeTemplate def_template( CodeParam params, Code definition, ModuleFlag mflags = ModuleFlag_None ); | ||||||
|  |  | ||||||
| CodeType    def_type   ( StrC name, Code arrayexpr = NoCode, CodeSpecifiers specifiers = NoCode, CodeAttributes attributes = NoCode ); | CodeType    def_type   ( StrC name, Code arrayexpr = NoCode, CodeSpecifiers specifiers = NoCode, CodeAttributes attributes = NoCode ); | ||||||
| CodeTypedef def_typedef( StrC name, Code type, CodeAttributes attributes = NoCode, ModuleFlag mflags = ModuleFlag::None ); | CodeTypedef def_typedef( StrC name, Code type, CodeAttributes attributes = NoCode, ModuleFlag mflags = ModuleFlag_None ); | ||||||
|  |  | ||||||
| CodeUnion def_union( StrC name, Code body, CodeAttributes attributes = NoCode, ModuleFlag mflags = ModuleFlag::None ); | CodeUnion def_union( StrC name, Code body, CodeAttributes attributes = NoCode, ModuleFlag mflags = ModuleFlag_None ); | ||||||
|  |  | ||||||
| CodeUsing def_using( StrC name, CodeType type = NoCode | CodeUsing def_using( StrC name, CodeType type = NoCode | ||||||
| 	, CodeAttributes attributess = NoCode | 	, CodeAttributes attributess = NoCode | ||||||
| 	, ModuleFlag     mflags      = ModuleFlag::None ); | 	, ModuleFlag     mflags      = ModuleFlag_None ); | ||||||
|  |  | ||||||
| CodeUsing def_using_namespace( StrC name ); | CodeUsing def_using_namespace( StrC name ); | ||||||
|  |  | ||||||
| CodeVar def_variable( CodeType type, StrC name, Code value = NoCode | CodeVar def_variable( CodeType type, StrC name, Code value = NoCode | ||||||
| 	, CodeSpecifiers specifiers = NoCode, CodeAttributes attributes = NoCode | 	, CodeSpecifiers specifiers = NoCode, CodeAttributes attributes = NoCode | ||||||
| 	, ModuleFlag     mflags     = ModuleFlag::None ); | 	, ModuleFlag     mflags     = ModuleFlag_None ); | ||||||
|  |  | ||||||
| // Constructs an empty body. Use AST::validate_body() to check if the body is was has valid entries. | // Constructs an empty body. Use AST::validate_body() to check if the body is was has valid entries. | ||||||
| CodeBody def_body( CodeT type ); | CodeBody def_body( CodeT type ); | ||||||
|   | |||||||
| @@ -16,8 +16,8 @@ ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va ) | |||||||
| 		local_persist | 		local_persist | ||||||
| 		char tok_map_mem[ TokenFmt_TokenMap_MemSize ]; | 		char tok_map_mem[ TokenFmt_TokenMap_MemSize ]; | ||||||
|  |  | ||||||
| 		tok_map_arena = Arena::init_from_memory( tok_map_mem, sizeof(tok_map_mem) ); | 		tok_map_arena = arena_init_from_memory( tok_map_mem, sizeof(tok_map_mem) ); | ||||||
| 		tok_map       = HashTable<StrC>::init( tok_map_arena ); | 		tok_map       = hashtable_init<StrC>( allocator_info(tok_map_arena) ); | ||||||
|  |  | ||||||
| 		s32 left = num_tokens - 1; | 		s32 left = num_tokens - 1; | ||||||
|  |  | ||||||
| @@ -28,7 +28,7 @@ ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va ) | |||||||
|  |  | ||||||
| 			u32 key = crc32( token, str_len(token) ); | 			u32 key = crc32( token, str_len(token) ); | ||||||
|  |  | ||||||
| 			tok_map.set( key, value ); | 			set(tok_map, key, value ); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -64,7 +64,7 @@ ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va ) | |||||||
| 			char const* token = fmt + 1; | 			char const* token = fmt + 1; | ||||||
|  |  | ||||||
| 			u32       key   = crc32( token, tok_len ); | 			u32       key   = crc32( token, tok_len ); | ||||||
| 			StrC*     value = tok_map.get( key ); | 			StrC*     value = get(tok_map, key ); | ||||||
|  |  | ||||||
| 			if ( value ) | 			if ( value ) | ||||||
| 			{ | 			{ | ||||||
| @@ -94,8 +94,8 @@ ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va ) | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	tok_map.clear(); | 	clear(tok_map); | ||||||
| 	tok_map_arena.free(); | 	free(tok_map_arena); | ||||||
|  |  | ||||||
| 	ssize result = buf_size - remaining; | 	ssize result = buf_size - remaining; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -458,7 +458,7 @@ CodeComment def_comment( StrC content ) | |||||||
|  |  | ||||||
| 	static char line[ MaxCommentLineLength ]; | 	static char line[ MaxCommentLineLength ]; | ||||||
|  |  | ||||||
| 	String      cmt_formatted = String::make_reserve( GlobalAllocator, kilobytes(1) ); | 	String      cmt_formatted = string_make_reserve( GlobalAllocator, kilobytes(1) ); | ||||||
| 	char const* end           = content.Ptr + content.Len; | 	char const* end           = content.Ptr + content.Len; | ||||||
| 	char const* scanner       = content.Ptr; | 	char const* scanner       = content.Ptr; | ||||||
| 	s32         curr          = 0; | 	s32         curr          = 0; | ||||||
| @@ -474,15 +474,15 @@ CodeComment def_comment( StrC content ) | |||||||
| 		length++; | 		length++; | ||||||
|  |  | ||||||
| 		str_copy( line, scanner, length ); | 		str_copy( line, scanner, length ); | ||||||
| 		cmt_formatted.append_fmt( "//%.*s", length, line ); | 		append_fmt(cmt_formatted, "//%.*s", length, line ); | ||||||
| 		mem_set( line, 0, MaxCommentLineLength ); | 		mem_set( line, 0, MaxCommentLineLength ); | ||||||
|  |  | ||||||
| 		scanner += length; | 		scanner += length; | ||||||
| 	} | 	} | ||||||
| 	while ( scanner <= end ); | 	while ( scanner <= end ); | ||||||
|  |  | ||||||
| 	if ( cmt_formatted.back() != '\n' ) | 	if ( back(cmt_formatted) != '\n' ) | ||||||
| 		cmt_formatted.append( "\n" ); | 		append( cmt_formatted, "\n" ); | ||||||
|  |  | ||||||
| 	Code | 	Code | ||||||
| 	result          = make_code(); | 	result          = make_code(); | ||||||
| @@ -490,7 +490,7 @@ CodeComment def_comment( StrC content ) | |||||||
| 	result->Name    = get_cached_string( cmt_formatted ); | 	result->Name    = get_cached_string( cmt_formatted ); | ||||||
| 	result->Content = result->Name; | 	result->Content = result->Name; | ||||||
|  |  | ||||||
| 	cmt_formatted.free(); | 	free(cmt_formatted); | ||||||
|  |  | ||||||
| 	return (CodeComment) result; | 	return (CodeComment) result; | ||||||
| } | } | ||||||
| @@ -719,14 +719,14 @@ CodeEnum def_enum( StrC name | |||||||
| 				return CodeInvalid; | 				return CodeInvalid; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		result->Type = specifier == EnumClass ? | 		result->Type = specifier == EnumDecl_Class ? | ||||||
| 			Enum_Class : Enum; | 			Enum_Class : Enum; | ||||||
|  |  | ||||||
| 		result->Body = body; | 		result->Body = body; | ||||||
| 	} | 	} | ||||||
| 	else | 	else | ||||||
| 	{ | 	{ | ||||||
| 		result->Type = specifier == EnumClass ? | 		result->Type = specifier == EnumDecl_Class ? | ||||||
| 			Enum_Class_Fwd : Enum_Fwd; | 			Enum_Class_Fwd : Enum_Fwd; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -1145,16 +1145,16 @@ CodePreprocessCond def_preprocess_cond( EPreprocessCond type, StrC expr ) | |||||||
|  |  | ||||||
| 	switch (type) | 	switch (type) | ||||||
| 	{ | 	{ | ||||||
| 		case EPreprocessCond::If: | 		case PreprocessCond_If: | ||||||
| 			result->Type = Preprocess_If; | 			result->Type = Preprocess_If; | ||||||
| 		break; | 		break; | ||||||
| 		case EPreprocessCond::IfDef: | 		case PreprocessCond_IfDef: | ||||||
| 			result->Type = Preprocess_IfDef; | 			result->Type = Preprocess_IfDef; | ||||||
| 		break; | 		break; | ||||||
| 		case EPreprocessCond::IfNotDef: | 		case PreprocessCond_IfNotDef: | ||||||
| 			result->Type = Preprocess_IfNotDef; | 			result->Type = Preprocess_IfNotDef; | ||||||
| 		break; | 		break; | ||||||
| 		case EPreprocessCond::ElIf: | 		case PreprocessCond_ElIf: | ||||||
| 			result->Type = Preprocess_ElIf; | 			result->Type = Preprocess_ElIf; | ||||||
| 		break; | 		break; | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -89,11 +89,11 @@ struct Token | |||||||
|  |  | ||||||
| 	String to_string() | 	String to_string() | ||||||
| 	{ | 	{ | ||||||
| 		String result = String::make_reserve( GlobalAllocator, kilobytes(4) ); | 		String result = string_make_reserve( GlobalAllocator, kilobytes(4) ); | ||||||
|  |  | ||||||
| 		StrC type_str = ETokType::to_str( Type ); | 		StrC type_str = ETokType::to_str( Type ); | ||||||
|  |  | ||||||
| 		result.append_fmt( "Line: %d Column: %d, Type: %.*s Content: %.*s" | 		append_fmt( result, "Line: %d Column: %d, Type: %.*s Content: %.*s" | ||||||
| 			, Line, Column | 			, Line, Column | ||||||
| 			, type_str.Len, type_str.Ptr | 			, type_str.Len, type_str.Ptr | ||||||
| 			, Length, Text | 			, Length, Text | ||||||
| @@ -222,7 +222,7 @@ s32 lex_preprocessor_directive( | |||||||
| 	, Token&           token ) | 	, Token&           token ) | ||||||
| { | { | ||||||
| 	char const* hash = scanner; | 	char const* hash = scanner; | ||||||
| 	Tokens.append( { hash, 1, TokType::Preprocess_Hash, line, column, TF_Preprocess } ); | 	append(Tokens, { hash, 1, TokType::Preprocess_Hash, line, column, TF_Preprocess } ); | ||||||
|  |  | ||||||
| 	move_forward(); | 	move_forward(); | ||||||
| 	SkipWhitespace(); | 	SkipWhitespace(); | ||||||
| @@ -298,14 +298,14 @@ s32 lex_preprocessor_directive( | |||||||
|  |  | ||||||
| 		token.Length = token.Length + token.Text - hash; | 		token.Length = token.Length + token.Text - hash; | ||||||
| 		token.Text   = hash; | 		token.Text   = hash; | ||||||
| 		Tokens.append( token ); | 		append(Tokens, token ); | ||||||
| 		return Lex_Continue; // Skip found token, its all handled here. | 		return Lex_Continue; // Skip found token, its all handled here. | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if ( token.Type == TokType::Preprocess_Else || token.Type == TokType::Preprocess_EndIf ) | 	if ( token.Type == TokType::Preprocess_Else || token.Type == TokType::Preprocess_EndIf ) | ||||||
| 	{ | 	{ | ||||||
| 		token.Flags |= TF_Preprocess_Cond; | 		token.Flags |= TF_Preprocess_Cond; | ||||||
| 		Tokens.append( token ); | 		append(Tokens, token ); | ||||||
| 		end_line(); | 		end_line(); | ||||||
| 		return Lex_Continue; | 		return Lex_Continue; | ||||||
| 	} | 	} | ||||||
| @@ -314,7 +314,7 @@ s32 lex_preprocessor_directive( | |||||||
| 		token.Flags |= TF_Preprocess_Cond; | 		token.Flags |= TF_Preprocess_Cond; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	Tokens.append( token ); | 	append(Tokens, token ); | ||||||
|  |  | ||||||
| 	SkipWhitespace(); | 	SkipWhitespace(); | ||||||
|  |  | ||||||
| @@ -338,10 +338,10 @@ s32 lex_preprocessor_directive( | |||||||
| 			name.Length++; | 			name.Length++; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		Tokens.append( name ); | 		append(Tokens, name ); | ||||||
|  |  | ||||||
| 		u64 key = crc32( name.Text, name.Length ); | 		u64 key = crc32( name.Text, name.Length ); | ||||||
| 		defines.set( key, name ); | 		set<StrC>(defines, key, name ); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	Token preprocess_content = { scanner, 0, TokType::Preprocess_Content, line, column, TF_Preprocess }; | 	Token preprocess_content = { scanner, 0, TokType::Preprocess_Content, line, column, TF_Preprocess }; | ||||||
| @@ -352,7 +352,7 @@ s32 lex_preprocessor_directive( | |||||||
|  |  | ||||||
| 		if ( current != '"' && current != '<' ) | 		if ( current != '"' && current != '<' ) | ||||||
| 		{ | 		{ | ||||||
| 			String directive_str = String::fmt_buf( GlobalAllocator, "%.*s", min( 80, left + preprocess_content.Length ), token.Text ); | 			String directive_str = string_fmt_buf( GlobalAllocator, "%.*s", min( 80, left + preprocess_content.Length ), token.Text ); | ||||||
|  |  | ||||||
| 			log_failure( "gen::Parser::lex: Expected '\"' or '<' after #include, not '%c' (%d, %d)\n%s" | 			log_failure( "gen::Parser::lex: Expected '\"' or '<' after #include, not '%c' (%d, %d)\n%s" | ||||||
| 				, current | 				, current | ||||||
| @@ -384,7 +384,7 @@ s32 lex_preprocessor_directive( | |||||||
| 			move_forward(); | 			move_forward(); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		Tokens.append( preprocess_content ); | 		append(Tokens, preprocess_content ); | ||||||
| 		return Lex_Continue; // Skip found token, its all handled here. | 		return Lex_Continue; // Skip found token, its all handled here. | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -419,8 +419,8 @@ s32 lex_preprocessor_directive( | |||||||
| 			} | 			} | ||||||
| 			else | 			else | ||||||
| 			{ | 			{ | ||||||
| 				String directive_str = String::make_length( GlobalAllocator, token.Text, token.Length ); | 				String directive_str = string_make_length( GlobalAllocator, token.Text, token.Length ); | ||||||
| 				String content_str   = String::fmt_buf( GlobalAllocator, "%.*s", min( 400, left + preprocess_content.Length ), preprocess_content.Text ); | 				String content_str   = string_fmt_buf( GlobalAllocator, "%.*s", min( 400, left + preprocess_content.Length ), preprocess_content.Text ); | ||||||
|  |  | ||||||
| 				log_failure( "gen::Parser::lex: Invalid escape sequence '\\%c' (%d, %d)" | 				log_failure( "gen::Parser::lex: Invalid escape sequence '\\%c' (%d, %d)" | ||||||
| 							" in preprocessor directive '%s' (%d, %d)\n%s" | 							" in preprocessor directive '%s' (%d, %d)\n%s" | ||||||
| @@ -446,7 +446,7 @@ s32 lex_preprocessor_directive( | |||||||
| 		preprocess_content.Length++; | 		preprocess_content.Length++; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	Tokens.append( preprocess_content ); | 	append(Tokens, preprocess_content ); | ||||||
| 	return Lex_Continue; // Skip found token, its all handled here. | 	return Lex_Continue; // Skip found token, its all handled here. | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -461,7 +461,7 @@ void lex_found_token( StrC& content | |||||||
| { | { | ||||||
| 	if ( token.Type != TokType::Invalid ) | 	if ( token.Type != TokType::Invalid ) | ||||||
| 	{ | 	{ | ||||||
| 		Tokens.append( token ); | 		append(Tokens, token ); | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -488,7 +488,7 @@ void lex_found_token( StrC& content | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		token.Type = type; | 		token.Type = type; | ||||||
| 		Tokens.append( token ); | 		append(Tokens, token ); | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -498,7 +498,7 @@ void lex_found_token( StrC& content | |||||||
| 	{ | 	{ | ||||||
| 		token.Type   = type; | 		token.Type   = type; | ||||||
| 		token.Flags |= TF_Specifier; | 		token.Flags |= TF_Specifier; | ||||||
| 		Tokens.append( token ); | 		append(Tokens, token ); | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -506,7 +506,7 @@ void lex_found_token( StrC& content | |||||||
| 	if ( type != TokType::Invalid ) | 	if ( type != TokType::Invalid ) | ||||||
| 	{ | 	{ | ||||||
| 		token.Type = type; | 		token.Type = type; | ||||||
| 		Tokens.append( token ); | 		append(Tokens, token ); | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -516,7 +516,7 @@ void lex_found_token( StrC& content | |||||||
| 	else | 	else | ||||||
| 		key = crc32( token.Text, token.Length ); | 		key = crc32( token.Text, token.Length ); | ||||||
|  |  | ||||||
| 	StrC* define = defines.get( key ); | 	StrC* define = get(defines, key ); | ||||||
| 	if ( define ) | 	if ( define ) | ||||||
| 	{ | 	{ | ||||||
| 		token.Type = TokType::Preprocess_Macro; | 		token.Type = TokType::Preprocess_Macro; | ||||||
| @@ -558,7 +558,7 @@ void lex_found_token( StrC& content | |||||||
| 		token.Type = TokType::Identifier; | 		token.Type = TokType::Identifier; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	Tokens.append( token ); | 	append(Tokens, token ); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -582,11 +582,11 @@ TokArray lex( StrC content ) | |||||||
| 		return { { nullptr }, 0 }; | 		return { { nullptr }, 0 }; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	for ( StringCached entry : PreprocessorDefines ) | 	foreach( StringCached, entry, PreprocessorDefines ) | ||||||
| 	{ | 	{ | ||||||
| 		s32         length  = 0; | 		s32         length  = 0; | ||||||
| 		char const* scanner = entry.Data; | 		char const* scanner = entry.Data; | ||||||
| 		while ( entry.length() > length && (char_is_alphanumeric( *scanner ) || *scanner == '_') ) | 		while ( GEN_NS length(entry) > length && (char_is_alphanumeric( *scanner ) || *scanner == '_') ) | ||||||
| 		{ | 		{ | ||||||
| 			scanner++; | 			scanner++; | ||||||
| 			length ++; | 			length ++; | ||||||
| @@ -597,10 +597,10 @@ TokArray lex( StrC content ) | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		u64 key = crc32( entry.Data, length ); | 		u64 key = crc32( entry.Data, length ); | ||||||
| 		defines.set( key, entry ); | 		set<StrC>(defines, key, entry ); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	Tokens.clear(); | 	clear(Tokens); | ||||||
|  |  | ||||||
| 	while (left ) | 	while (left ) | ||||||
| 	{ | 	{ | ||||||
| @@ -630,7 +630,7 @@ TokArray lex( StrC content ) | |||||||
| 				token.Type = TokType::NewLine; | 				token.Type = TokType::NewLine; | ||||||
| 				token.Length++; | 				token.Length++; | ||||||
|  |  | ||||||
| 				Tokens.append( token ); | 				append(Tokens, token ); | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @@ -678,7 +678,7 @@ TokArray lex( StrC content ) | |||||||
| 					} | 					} | ||||||
| 					else | 					else | ||||||
| 					{ | 					{ | ||||||
| 						String context_str = String::fmt_buf( GlobalAllocator, "%s", scanner, min( 100, left ) ); | 						String context_str = string_fmt_buf( GlobalAllocator, "%s", scanner, min( 100, left ) ); | ||||||
|  |  | ||||||
| 						log_failure( "gen::lex: invalid varadic argument, expected '...' got '..%c' (%d, %d)\n%s", current, line, column, context_str ); | 						log_failure( "gen::lex: invalid varadic argument, expected '...' got '..%c' (%d, %d)\n%s", current, line, column, context_str ); | ||||||
| 					} | 					} | ||||||
| @@ -1099,7 +1099,7 @@ TokArray lex( StrC content ) | |||||||
| 							move_forward(); | 							move_forward(); | ||||||
| 							token.Length++; | 							token.Length++; | ||||||
| 						} | 						} | ||||||
| 						Tokens.append( token ); | 						append(Tokens, token ); | ||||||
| 						continue; | 						continue; | ||||||
| 					} | 					} | ||||||
| 					else if ( current == '*' ) | 					else if ( current == '*' ) | ||||||
| @@ -1135,7 +1135,7 @@ TokArray lex( StrC content ) | |||||||
| 							move_forward(); | 							move_forward(); | ||||||
| 							token.Length++; | 							token.Length++; | ||||||
| 						} | 						} | ||||||
| 						Tokens.append( token ); | 						append(Tokens, token ); | ||||||
| 						// end_line(); | 						// end_line(); | ||||||
| 						continue; | 						continue; | ||||||
| 					} | 					} | ||||||
| @@ -1228,9 +1228,9 @@ TokArray lex( StrC content ) | |||||||
| 		} | 		} | ||||||
| 		else | 		else | ||||||
| 		{ | 		{ | ||||||
| 			s32 start = max( 0, Tokens.num() - 100 ); | 			s32 start = max( 0, num(Tokens) - 100 ); | ||||||
| 			log_fmt("\n%d\n", start); | 			log_fmt("\n%d\n", start); | ||||||
| 			for ( s32 idx = start; idx < Tokens.num(); idx++ ) | 			for ( s32 idx = start; idx < num(Tokens); idx++ ) | ||||||
| 			{ | 			{ | ||||||
| 				log_fmt( "Token %d Type: %s : %.*s\n" | 				log_fmt( "Token %d Type: %s : %.*s\n" | ||||||
| 					, idx | 					, idx | ||||||
| @@ -1239,7 +1239,7 @@ TokArray lex( StrC content ) | |||||||
| 				); | 				); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			String context_str = String::fmt_buf( GlobalAllocator, "%.*s", min( 100, left ), scanner ); | 			String context_str = string_fmt_buf( GlobalAllocator, "%.*s", min( 100, left ), scanner ); | ||||||
| 			log_failure( "Failed to lex token '%c' (%d, %d)\n%s", current, line, column, context_str ); | 			log_failure( "Failed to lex token '%c' (%d, %d)\n%s", current, line, column, context_str ); | ||||||
|  |  | ||||||
| 			// Skip to next whitespace since we can't know if anything else is valid until then. | 			// Skip to next whitespace since we can't know if anything else is valid until then. | ||||||
| @@ -1253,13 +1253,13 @@ TokArray lex( StrC content ) | |||||||
| 		lex_found_token( content, left, scanner, line, column, defines, token ); | 		lex_found_token( content, left, scanner, line, column, defines, token ); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if ( Tokens.num() == 0 ) | 	if ( num(Tokens) == 0 ) | ||||||
| 	{ | 	{ | ||||||
| 		log_failure( "Failed to lex any tokens" ); | 		log_failure( "Failed to lex any tokens" ); | ||||||
| 		return { { nullptr }, 0 }; | 		return { { nullptr }, 0 }; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	defines.clear(); | 	clear(defines); | ||||||
| 	// defines_map_arena.free(); | 	// defines_map_arena.free(); | ||||||
| 	return { Tokens, 0 }; | 	return { Tokens, 0 }; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -45,31 +45,31 @@ struct ParseContext | |||||||
|  |  | ||||||
| 	String to_string() | 	String to_string() | ||||||
| 	{ | 	{ | ||||||
| 		String result = String::make_reserve( GlobalAllocator, kilobytes(4) ); | 		String result = string_make_reserve( GlobalAllocator, kilobytes(4) ); | ||||||
|  |  | ||||||
| 		Token scope_start = Scope->Start; | 		Token scope_start = Scope->Start; | ||||||
| 		Token last_valid  = Tokens.Idx >= Tokens.Arr.num() ? Tokens.Arr[Tokens.Arr.num() -1] : Tokens.current(); | 		Token last_valid  = Tokens.Idx >= num(Tokens.Arr) ? Tokens.Arr[num(Tokens.Arr) -1] : Tokens.current(); | ||||||
|  |  | ||||||
| 		sptr        length  = scope_start.Length; | 		sptr        length  = scope_start.Length; | ||||||
| 		char const* current = scope_start.Text + length; | 		char const* current = scope_start.Text + length; | ||||||
| 		while ( current <= Tokens.Arr.back().Text && *current != '\n' && length < 74 ) | 		while ( current <= back(Tokens.Arr).Text && *current != '\n' && length < 74 ) | ||||||
| 		{ | 		{ | ||||||
| 			current++; | 			current++; | ||||||
| 			length++; | 			length++; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		String line = String::make( GlobalAllocator, { length, scope_start.Text } ); | 		String line = string_make( GlobalAllocator, { length, scope_start.Text } ); | ||||||
| 		result.append_fmt("\tScope    : %s\n", line ); | 		append_fmt( result, "\tScope    : %s\n", line ); | ||||||
| 		line.free(); | 		free(line); | ||||||
|  |  | ||||||
| 		sptr   dist            = (sptr)last_valid.Text - (sptr)scope_start.Text + 2; | 		sptr   dist            = (sptr)last_valid.Text - (sptr)scope_start.Text + 2; | ||||||
| 		sptr   length_from_err = dist; | 		sptr   length_from_err = dist; | ||||||
| 		String line_from_err   = String::make( GlobalAllocator, { length_from_err, last_valid.Text } ); | 		String line_from_err   = string_make( GlobalAllocator, { length_from_err, last_valid.Text } ); | ||||||
|  |  | ||||||
| 		if ( length_from_err < 100 ) | 		if ( length_from_err < 100 ) | ||||||
| 			result.append_fmt("\t(%d, %d):%*c\n", last_valid.Line, last_valid.Column, length_from_err, '^' ); | 			append_fmt(result, "\t(%d, %d):%*c\n", last_valid.Line, last_valid.Column, length_from_err, '^' ); | ||||||
| 		else | 		else | ||||||
| 			result.append_fmt("\t(%d, %d)\n", last_valid.Line, last_valid.Column ); | 			append_fmt(result, "\t(%d, %d)\n", last_valid.Line, last_valid.Column ); | ||||||
|  |  | ||||||
| 		StackNode* curr_scope = Scope; | 		StackNode* curr_scope = Scope; | ||||||
| 		s32 level = 0; | 		s32 level = 0; | ||||||
| @@ -77,11 +77,11 @@ struct ParseContext | |||||||
| 		{ | 		{ | ||||||
| 			if ( curr_scope->Name ) | 			if ( curr_scope->Name ) | ||||||
| 			{ | 			{ | ||||||
| 				result.append_fmt("\t%d: %s, AST Name: %.*s\n", level, curr_scope->ProcName.Ptr, curr_scope->Name.Length, curr_scope->Name.Text ); | 				append_fmt(result, "\t%d: %s, AST Name: %.*s\n", level, curr_scope->ProcName.Ptr, curr_scope->Name.Length, curr_scope->Name.Text ); | ||||||
| 			} | 			} | ||||||
| 			else | 			else | ||||||
| 			{ | 			{ | ||||||
| 				result.append_fmt("\t%d: %s\n", level, curr_scope->ProcName.Ptr ); | 				append_fmt(result, "\t%d: %s\n", level, curr_scope->ProcName.Ptr ); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			curr_scope = curr_scope->Prev; | 			curr_scope = curr_scope->Prev; | ||||||
| @@ -96,7 +96,7 @@ global ParseContext Context; | |||||||
|  |  | ||||||
| bool TokArray::__eat( TokType type ) | bool TokArray::__eat( TokType type ) | ||||||
| { | { | ||||||
| 	if ( Arr.num() - Idx <= 0 ) | 	if ( num(Arr) - Idx <= 0 ) | ||||||
| 	{ | 	{ | ||||||
| 		log_failure( "No tokens left.\n%s", Context.to_string() ); | 		log_failure( "No tokens left.\n%s", Context.to_string() ); | ||||||
| 		return false; | 		return false; | ||||||
| @@ -132,12 +132,12 @@ bool TokArray::__eat( TokType type ) | |||||||
| internal | internal | ||||||
| void init() | void init() | ||||||
| { | { | ||||||
| 	Tokens = Array<Token>::init_reserve( LexArena | 	Tokens = array_init_reserve<Token>( allocator_info(LexArena) | ||||||
| 		, ( LexAllocator_Size - sizeof( Array<Token>::Header ) ) / sizeof(Token) | 		, ( LexAllocator_Size - sizeof( ArrayHeader ) ) / sizeof(Token) | ||||||
| 	); | 	); | ||||||
|  |  | ||||||
| 	defines_map_arena = Arena_256KB::init(); | 	fixed_arena_init(defines_map_arena); | ||||||
| 	defines           = HashTable<StrC>::init_reserve( defines_map_arena, 256 ); | 	defines = hashtable_init_reserve<StrC>( allocator_info(defines_map_arena), 256 ); | ||||||
| } | } | ||||||
|  |  | ||||||
| internal | internal | ||||||
| @@ -167,7 +167,7 @@ if ( def.Ptr == nullptr )                                                      \ | |||||||
| #	define prevtok        Context.Tokens.previous() | #	define prevtok        Context.Tokens.previous() | ||||||
| #	define nexttok		  Context.Tokens.next() | #	define nexttok		  Context.Tokens.next() | ||||||
| #	define eat( Type_ )   Context.Tokens.__eat( Type_ ) | #	define eat( Type_ )   Context.Tokens.__eat( Type_ ) | ||||||
| #	define left           ( Context.Tokens.Arr.num() - Context.Tokens.Idx ) | #	define left           ( num(Context.Tokens.Arr) - Context.Tokens.Idx ) | ||||||
|  |  | ||||||
| #ifdef check | #ifdef check | ||||||
| #define CHECK_WAS_DEFINED | #define CHECK_WAS_DEFINED | ||||||
| @@ -243,7 +243,7 @@ constexpr bool strip_formatting_dont_preserve_newlines = false; | |||||||
| internal | internal | ||||||
| String strip_formatting( StrC raw_text, bool preserve_newlines = true ) | String strip_formatting( StrC raw_text, bool preserve_newlines = true ) | ||||||
| { | { | ||||||
| 	String content = String::make_reserve( GlobalAllocator, raw_text.Len ); | 	String content = string_make_reserve( GlobalAllocator, raw_text.Len ); | ||||||
|  |  | ||||||
| 	if ( raw_text.Len == 0 ) | 	if ( raw_text.Len == 0 ) | ||||||
| 		return content; | 		return content; | ||||||
| @@ -290,7 +290,7 @@ String strip_formatting( StrC raw_text, bool preserve_newlines = true ) | |||||||
| 			if ( tokleft ) | 			if ( tokleft ) | ||||||
| 				move_fwd(); | 				move_fwd(); | ||||||
|  |  | ||||||
| 			content.append( cut_ptr, cut_length ); | 			append( content, cut_ptr, cut_length ); | ||||||
| 			last_cut = sptr( scanner ) - sptr( raw_text.Ptr ); | 			last_cut = sptr( scanner ) - sptr( raw_text.Ptr ); | ||||||
| 			continue; | 			continue; | ||||||
| 		} | 		} | ||||||
| @@ -312,7 +312,7 @@ String strip_formatting( StrC raw_text, bool preserve_newlines = true ) | |||||||
| 			if ( tokleft ) | 			if ( tokleft ) | ||||||
| 				move_fwd(); | 				move_fwd(); | ||||||
|  |  | ||||||
| 			content.append( cut_ptr, cut_length ); | 			append( content, cut_ptr, cut_length ); | ||||||
| 			last_cut = sptr( scanner ) - sptr( raw_text.Ptr ); | 			last_cut = sptr( scanner ) - sptr( raw_text.Ptr ); | ||||||
| 			continue; | 			continue; | ||||||
| 		} | 		} | ||||||
| @@ -326,7 +326,7 @@ String strip_formatting( StrC raw_text, bool preserve_newlines = true ) | |||||||
| 			scanner += 2; | 			scanner += 2; | ||||||
| 			tokleft -= 2; | 			tokleft -= 2; | ||||||
|  |  | ||||||
| 			content.append( cut_ptr, cut_length ); | 			append( content,  cut_ptr, cut_length ); | ||||||
| 			last_cut = sptr( scanner ) - sptr( raw_text.Ptr ); | 			last_cut = sptr( scanner ) - sptr( raw_text.Ptr ); | ||||||
| 			continue; | 			continue; | ||||||
| 		} | 		} | ||||||
| @@ -345,7 +345,7 @@ String strip_formatting( StrC raw_text, bool preserve_newlines = true ) | |||||||
| 			if (tokleft) | 			if (tokleft) | ||||||
| 				move_fwd(); | 				move_fwd(); | ||||||
|  |  | ||||||
| 			content.append( cut_ptr, cut_length ); | 			append( content,  cut_ptr, cut_length ); | ||||||
| 			last_cut = sptr( scanner ) - sptr( raw_text.Ptr ); | 			last_cut = sptr( scanner ) - sptr( raw_text.Ptr ); | ||||||
| 			continue; | 			continue; | ||||||
| 		} | 		} | ||||||
| @@ -354,10 +354,10 @@ String strip_formatting( StrC raw_text, bool preserve_newlines = true ) | |||||||
| 		if (scanner[0] == '\t') | 		if (scanner[0] == '\t') | ||||||
| 		{ | 		{ | ||||||
| 			if (pos > last_cut) | 			if (pos > last_cut) | ||||||
| 				content.append(cut_ptr, cut_length); | 				append( content, cut_ptr, cut_length); | ||||||
|  |  | ||||||
| 			if ( content.back() != ' ' ) | 			if ( back( content ) != ' ' ) | ||||||
| 				content.append(' '); | 				append( content, ' '); | ||||||
|  |  | ||||||
| 			move_fwd(); | 			move_fwd(); | ||||||
| 			last_cut = sptr(scanner) - sptr(raw_text.Ptr); | 			last_cut = sptr(scanner) - sptr(raw_text.Ptr); | ||||||
| @@ -373,17 +373,17 @@ String strip_formatting( StrC raw_text, bool preserve_newlines = true ) | |||||||
| 				scanner += 2; | 				scanner += 2; | ||||||
| 				tokleft -= 2; | 				tokleft -= 2; | ||||||
|  |  | ||||||
| 				content.append( cut_ptr, cut_length ); | 				append( content,  cut_ptr, cut_length ); | ||||||
| 				last_cut = sptr( scanner ) - sptr( raw_text.Ptr ); | 				last_cut = sptr( scanner ) - sptr( raw_text.Ptr ); | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			if ( pos > last_cut ) | 			if ( pos > last_cut ) | ||||||
| 				content.append( cut_ptr, cut_length ); | 				append( content,  cut_ptr, cut_length ); | ||||||
|  |  | ||||||
| 			// Replace with a space | 			// Replace with a space | ||||||
| 			if ( content.back() != ' ' ) | 			if ( back( content ) != ' ' ) | ||||||
| 				content.append( ' ' ); | 				append( content,  ' ' ); | ||||||
|  |  | ||||||
| 			scanner += 2; | 			scanner += 2; | ||||||
| 			tokleft -= 2; | 			tokleft -= 2; | ||||||
| @@ -400,17 +400,17 @@ String strip_formatting( StrC raw_text, bool preserve_newlines = true ) | |||||||
|  |  | ||||||
| 				move_fwd(); | 				move_fwd(); | ||||||
|  |  | ||||||
| 				content.append( cut_ptr, cut_length ); | 				append( content,  cut_ptr, cut_length ); | ||||||
| 				last_cut = sptr( scanner ) - sptr( raw_text.Ptr ); | 				last_cut = sptr( scanner ) - sptr( raw_text.Ptr ); | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			if ( pos > last_cut ) | 			if ( pos > last_cut ) | ||||||
| 				content.append( cut_ptr, cut_length ); | 				append( content,  cut_ptr, cut_length ); | ||||||
|  |  | ||||||
| 			// Replace with a space | 			// Replace with a space | ||||||
| 			if ( content.back() != ' ' ) | 			if ( back( content ) != ' ' ) | ||||||
| 				content.append( ' ' ); | 				append( content,  ' ' ); | ||||||
|  |  | ||||||
| 			move_fwd(); | 			move_fwd(); | ||||||
|  |  | ||||||
| @@ -421,7 +421,7 @@ String strip_formatting( StrC raw_text, bool preserve_newlines = true ) | |||||||
| 		// Escaped newlines | 		// Escaped newlines | ||||||
| 		if ( scanner[0] == '\\' ) | 		if ( scanner[0] == '\\' ) | ||||||
| 		{ | 		{ | ||||||
| 			content.append( cut_ptr, cut_length ); | 			append( content,  cut_ptr, cut_length ); | ||||||
|  |  | ||||||
| 			s32 amount_to_skip = 1; | 			s32 amount_to_skip = 1; | ||||||
| 			if ( tokleft > 1 && scanner[1] == '\n' ) | 			if ( tokleft > 1 && scanner[1] == '\n' ) | ||||||
| @@ -448,7 +448,7 @@ String strip_formatting( StrC raw_text, bool preserve_newlines = true ) | |||||||
| 		// Consectuive spaces | 		// Consectuive spaces | ||||||
| 		if ( tokleft > 1 && char_is_space( scanner[0] ) && char_is_space( scanner[ 1 ] ) ) | 		if ( tokleft > 1 && char_is_space( scanner[0] ) && char_is_space( scanner[ 1 ] ) ) | ||||||
| 		{ | 		{ | ||||||
| 			content.append( cut_ptr, cut_length ); | 			append( content,  cut_ptr, cut_length ); | ||||||
| 			do | 			do | ||||||
| 			{ | 			{ | ||||||
| 				move_fwd(); | 				move_fwd(); | ||||||
| @@ -458,8 +458,8 @@ String strip_formatting( StrC raw_text, bool preserve_newlines = true ) | |||||||
| 			last_cut = sptr( scanner ) - sptr( raw_text.Ptr ); | 			last_cut = sptr( scanner ) - sptr( raw_text.Ptr ); | ||||||
|  |  | ||||||
| 			// Preserve only 1 space of formattting | 			// Preserve only 1 space of formattting | ||||||
| 			if ( content.back() != ' ' ) | 			if ( back( content ) != ' ' ) | ||||||
| 				content.append( ' ' ); | 				append( content,  ' ' ); | ||||||
|  |  | ||||||
| 			continue; | 			continue; | ||||||
| 		} | 		} | ||||||
| @@ -469,7 +469,7 @@ String strip_formatting( StrC raw_text, bool preserve_newlines = true ) | |||||||
|  |  | ||||||
| 	if ( last_cut < raw_text.Len ) | 	if ( last_cut < raw_text.Len ) | ||||||
| 	{ | 	{ | ||||||
| 		content.append( cut_ptr, raw_text.Len - last_cut ); | 		append( content,  cut_ptr, raw_text.Len - last_cut ); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| #undef cut_ptr | #undef cut_ptr | ||||||
| @@ -682,17 +682,17 @@ Code parse_class_struct( TokType which, bool inplace_def = false ) | |||||||
|  |  | ||||||
| 	Token name { nullptr, 0, TokType::Invalid }; | 	Token name { nullptr, 0, TokType::Invalid }; | ||||||
|  |  | ||||||
| 	AccessSpec     access     = AccessSpec::Default; | 	AccessSpec     access     = AccessSpec_Default; | ||||||
| 	CodeType       parent     = { nullptr }; | 	CodeType       parent     = { nullptr }; | ||||||
| 	CodeBody       body       = { nullptr }; | 	CodeBody       body       = { nullptr }; | ||||||
| 	CodeAttributes attributes = { nullptr }; | 	CodeAttributes attributes = { nullptr }; | ||||||
| 	ModuleFlag     mflags     = ModuleFlag::None; | 	ModuleFlag     mflags     = ModuleFlag_None; | ||||||
|  |  | ||||||
| 	CodeClass result = CodeInvalid; | 	CodeClass result = CodeInvalid; | ||||||
|  |  | ||||||
| 	if ( check(TokType::Module_Export) ) | 	if ( check(TokType::Module_Export) ) | ||||||
| 	{ | 	{ | ||||||
| 		mflags = ModuleFlag::Export; | 		mflags = ModuleFlag_Export; | ||||||
| 		eat( TokType::Module_Export ); | 		eat( TokType::Module_Export ); | ||||||
| 	} | 	} | ||||||
| 	// <ModuleFlags> | 	// <ModuleFlags> | ||||||
| @@ -712,7 +712,10 @@ Code parse_class_struct( TokType which, bool inplace_def = false ) | |||||||
|  |  | ||||||
| 	local_persist | 	local_persist | ||||||
| 	char interface_arr_mem[ kilobytes(4) ] {0}; | 	char interface_arr_mem[ kilobytes(4) ] {0}; | ||||||
| 	Array<CodeType> interfaces = Array<CodeType>::init_reserve( Arena::init_from_memory(interface_arr_mem, kilobytes(4) ), 4 ); | 	Array<CodeType> interfaces; { | ||||||
|  | 		Arena arena = arena_init_from_memory( interface_arr_mem, kilobytes(4) ); | ||||||
|  | 		interfaces  = array_init_reserve<CodeType>( allocator_info(arena), 4 ); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	// TODO(Ed) : Make an AST_DerivedType, we'll store any arbitary derived type into there as a linear linked list of them. | 	// TODO(Ed) : Make an AST_DerivedType, we'll store any arbitary derived type into there as a linear linked list of them. | ||||||
| 	if ( check( TokType::Assign_Classifer ) ) | 	if ( check( TokType::Assign_Classifer ) ) | ||||||
| @@ -742,7 +745,7 @@ Code parse_class_struct( TokType which, bool inplace_def = false ) | |||||||
| 			} | 			} | ||||||
| 			Token interface_tok = parse_identifier(); | 			Token interface_tok = parse_identifier(); | ||||||
|  |  | ||||||
| 			interfaces.append( def_type( interface_tok ) ); | 			append(interfaces, def_type( interface_tok ) ); | ||||||
| 			// <ModuleFlags> <class/struct> <Attributes> <Name> : <Access Specifier> <Name>, ... | 			// <ModuleFlags> <class/struct> <Attributes> <Name> : <Access Specifier> <Name>, ... | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -774,7 +777,7 @@ Code parse_class_struct( TokType which, bool inplace_def = false ) | |||||||
| 	if ( inline_cmt ) | 	if ( inline_cmt ) | ||||||
| 		result->InlineCmt = inline_cmt; | 		result->InlineCmt = inline_cmt; | ||||||
|  |  | ||||||
| 	interfaces.free(); | 	free(interfaces); | ||||||
| 	return result; | 	return result; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1036,8 +1039,8 @@ CodeBody parse_class_struct_body( TokType which, Token name ) | |||||||
|  |  | ||||||
| 					if ( attributes ) | 					if ( attributes ) | ||||||
| 					{ | 					{ | ||||||
| 						String fused = String::make_reserve( GlobalAllocator, attributes->Content.length() + more_attributes->Content.length() ); | 						String fused = string_make_reserve( GlobalAllocator, length(attributes->Content) + length(more_attributes->Content) ); | ||||||
| 						fused.append_fmt( "%S %S", attributes->Content, more_attributes->Content ); | 						append_fmt( fused, "%S %S", attributes->Content, more_attributes->Content ); | ||||||
|  |  | ||||||
| 						attributes->Name    = get_cached_string(fused); | 						attributes->Name    = get_cached_string(fused); | ||||||
| 						attributes->Content = attributes->Name; | 						attributes->Content = attributes->Name; | ||||||
| @@ -1149,7 +1152,7 @@ Code parse_complicated_definition( TokType which ) | |||||||
|  |  | ||||||
| 	s32 idx         = tokens.Idx; | 	s32 idx         = tokens.Idx; | ||||||
| 	s32 level       = 0; | 	s32 level       = 0; | ||||||
| 	for ( ; idx < tokens.Arr.num(); idx++ ) | 	for ( ; idx < num(tokens.Arr); idx++ ) | ||||||
| 	{ | 	{ | ||||||
| 		if ( tokens[ idx ].Type == TokType::BraceCurly_Open ) | 		if ( tokens[ idx ].Type == TokType::BraceCurly_Open ) | ||||||
| 			level++; | 			level++; | ||||||
| @@ -1481,8 +1484,8 @@ CodeFn parse_function_after_name( | |||||||
| 	using namespace ECode; | 	using namespace ECode; | ||||||
|  |  | ||||||
| 	String | 	String | ||||||
| 	name_stripped = String::make( GlobalAllocator, name ); | 	name_stripped = string_make( GlobalAllocator, name ); | ||||||
| 	name_stripped.strip_space(); | 	strip_space(name_stripped); | ||||||
|  |  | ||||||
| 	CodeFn | 	CodeFn | ||||||
| 	result              = (CodeFn) make_code(); | 	result              = (CodeFn) make_code(); | ||||||
| @@ -1834,7 +1837,7 @@ CodeBody parse_global_nspace( CodeT which ) | |||||||
| 				bool found_operator_cast_outside_class_implmentation = false; | 				bool found_operator_cast_outside_class_implmentation = false; | ||||||
| 				s32  idx = Context.Tokens.Idx; | 				s32  idx = Context.Tokens.Idx; | ||||||
|  |  | ||||||
| 				for ( ; idx < Context.Tokens.Arr.num(); idx++ ) | 				for ( ; idx < num(Context.Tokens.Arr); idx++ ) | ||||||
| 				{ | 				{ | ||||||
| 					Token tok = Context.Tokens[ idx ]; | 					Token tok = Context.Tokens[ idx ]; | ||||||
|  |  | ||||||
| @@ -1906,14 +1909,14 @@ Code parse_global_nspace_constructor_destructor( CodeSpecifiers specifiers ) | |||||||
|  |  | ||||||
| 	s32   idx = tokens.Idx; | 	s32   idx = tokens.Idx; | ||||||
| 	Token nav = tokens[ idx ]; | 	Token nav = tokens[ idx ]; | ||||||
| 	for ( ; idx < tokens.Arr.num(); idx++, nav = tokens[ idx ] ) | 	for ( ; idx < num(tokens.Arr); idx++, nav = tokens[ idx ] ) | ||||||
| 	{ | 	{ | ||||||
| 		if ( nav.Text[0] == '<' ) | 		if ( nav.Text[0] == '<' ) | ||||||
| 		{ | 		{ | ||||||
| 			// Skip templated expressions as they mey have expressions with the () operators | 			// Skip templated expressions as they mey have expressions with the () operators | ||||||
| 			s32 capture_level  = 0; | 			s32 capture_level  = 0; | ||||||
| 			s32 template_level = 0; | 			s32 template_level = 0; | ||||||
| 			for ( ; idx < tokens.Arr.num(); idx++, nav = tokens[idx] ) | 			for ( ; idx < num(tokens.Arr); idx++, nav = tokens[idx] ) | ||||||
| 			{ | 			{ | ||||||
| 				if (nav.Text[ 0 ] == '<') | 				if (nav.Text[ 0 ] == '<') | ||||||
| 					++ template_level; | 					++ template_level; | ||||||
| @@ -2508,7 +2511,7 @@ Code parse_operator_function_or_variable( bool expects_function, CodeAttributes | |||||||
| 	bool found_operator = false; | 	bool found_operator = false; | ||||||
| 	s32  idx            = Context.Tokens.Idx; | 	s32  idx            = Context.Tokens.Idx; | ||||||
|  |  | ||||||
| 	for ( ; idx < Context.Tokens.Arr.num(); idx++ ) | 	for ( ; idx < num(Context.Tokens.Arr); idx++ ) | ||||||
| 	{ | 	{ | ||||||
| 		Token tok = Context.Tokens[ idx ]; | 		Token tok = Context.Tokens[ idx ]; | ||||||
|  |  | ||||||
| @@ -2531,7 +2534,7 @@ Code parse_operator_function_or_variable( bool expects_function, CodeAttributes | |||||||
| 	if ( found_operator ) | 	if ( found_operator ) | ||||||
| 	{ | 	{ | ||||||
| 		// Dealing with an operator overload | 		// Dealing with an operator overload | ||||||
| 		result = parse_operator_after_ret_type( ModuleFlag::None, attributes, specifiers, type ); | 		result = parse_operator_after_ret_type( ModuleFlag_None, attributes, specifiers, type ); | ||||||
| 		// <Attributes> <Specifiers> <ReturnType> operator ... | 		// <Attributes> <Specifiers> <ReturnType> operator ... | ||||||
| 	} | 	} | ||||||
| 	else | 	else | ||||||
| @@ -2549,7 +2552,7 @@ Code parse_operator_function_or_variable( bool expects_function, CodeAttributes | |||||||
| 		if ( detected_capture && ! detected_comma ) | 		if ( detected_capture && ! detected_comma ) | ||||||
| 		{ | 		{ | ||||||
| 			// Dealing with a function | 			// Dealing with a function | ||||||
| 			result = parse_function_after_name( ModuleFlag::None, attributes, specifiers, type, name ); | 			result = parse_function_after_name( ModuleFlag_None, attributes, specifiers, type, name ); | ||||||
| 			// <Attributes> <Specifiers> <ReturnType> <Name> ( ... | 			// <Attributes> <Specifiers> <ReturnType> <Name> ( ... | ||||||
| 		} | 		} | ||||||
| 		else | 		else | ||||||
| @@ -2562,7 +2565,7 @@ Code parse_operator_function_or_variable( bool expects_function, CodeAttributes | |||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			// Dealing with a variable | 			// Dealing with a variable | ||||||
| 			result = parse_variable_after_name( ModuleFlag::None, attributes, specifiers, type, name ); | 			result = parse_variable_after_name( ModuleFlag_None, attributes, specifiers, type, name ); | ||||||
| 			// <Attributes> <Specifiers> <ValueType> <Name> ... | 			// <Attributes> <Specifiers> <ValueType> <Name> ... | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -3316,7 +3319,7 @@ CodeVar parse_variable_declaration_list() | |||||||
| 		eat( TokType::Identifier ); | 		eat( TokType::Identifier ); | ||||||
| 		// , <Specifiers> <Name> | 		// , <Specifiers> <Name> | ||||||
|  |  | ||||||
| 		CodeVar var = parse_variable_after_name( ModuleFlag::None, NoCode, specifiers, NoCode, name ); | 		CodeVar var = parse_variable_after_name( ModuleFlag_None, NoCode, specifiers, NoCode, name ); | ||||||
| 		// , <Specifiers> <Name> ... | 		// , <Specifiers> <Name> ... | ||||||
|  |  | ||||||
| 		if ( ! result ) | 		if ( ! result ) | ||||||
| @@ -3586,6 +3589,8 @@ CodeEnum parse_enum( bool inplace_def ) | |||||||
| 	} | 	} | ||||||
| 	// enum <class> <Attributes> <Name> | 	// enum <class> <Attributes> <Name> | ||||||
|  |  | ||||||
|  | 	b32  use_macro_underlying = false; | ||||||
|  | 	Code underlying_macro = { nullptr }; | ||||||
| 	if ( currtok.Type == TokType::Assign_Classifer ) | 	if ( currtok.Type == TokType::Assign_Classifer ) | ||||||
| 	{ | 	{ | ||||||
| 		eat( TokType::Assign_Classifer ); | 		eat( TokType::Assign_Classifer ); | ||||||
| @@ -3600,6 +3605,17 @@ CodeEnum parse_enum( bool inplace_def ) | |||||||
| 		} | 		} | ||||||
| 		// enum <class> <Attributes> <Name> : <UnderlyingType> | 		// enum <class> <Attributes> <Name> : <UnderlyingType> | ||||||
| 	} | 	} | ||||||
|  | 	else if ( currtok.Type == TokType::Preprocess_Define ) | ||||||
|  | 	{ | ||||||
|  | 		// We'll support the enum_underlying macro | ||||||
|  | 		StrC sig = txt("enum_underlying"); | ||||||
|  |  | ||||||
|  | 		if (currtok.Length >= sig.Len && str_compare(currtok.Text, sig.Ptr, sig.Len) == 0 ) | ||||||
|  | 		{ | ||||||
|  | 			use_macro_underlying = true; | ||||||
|  | 			underlying_macro     = parse_simple_preprocess( ETokType::Preprocess_Macro); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	CodeBody body = { nullptr }; | 	CodeBody body = { nullptr }; | ||||||
|  |  | ||||||
| @@ -3767,11 +3783,18 @@ CodeEnum parse_enum( bool inplace_def ) | |||||||
| 		result->Attributes = attributes; | 		result->Attributes = attributes; | ||||||
|  |  | ||||||
| 	if ( type ) | 	if ( type ) | ||||||
|  | 	{ | ||||||
|  | 		result->EnumUnderlyingMacro = use_macro_underlying; | ||||||
|  | 		if ( use_macro_underlying ) | ||||||
|  | 			result->UnderlyingTypeMacro = underlying_macro; | ||||||
|  | 		else | ||||||
| 			result->UnderlyingType = type; | 			result->UnderlyingType = type; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	if ( inline_cmt ) | 	if ( inline_cmt ) | ||||||
| 		result->InlineCmt = inline_cmt; | 		result->InlineCmt = inline_cmt; | ||||||
|  |  | ||||||
|  |  | ||||||
| 	Context.pop(); | 	Context.pop(); | ||||||
| 	return result; | 	return result; | ||||||
| } | } | ||||||
| @@ -3857,7 +3880,7 @@ CodeFriend parse_friend() | |||||||
| 		Context.Scope->Name = name; | 		Context.Scope->Name = name; | ||||||
| 		// friend <ReturnType> <Name> | 		// friend <ReturnType> <Name> | ||||||
|  |  | ||||||
| 		function = parse_function_after_name( ModuleFlag::None, NoCode, NoCode, type, name ); | 		function = parse_function_after_name( ModuleFlag_None, NoCode, NoCode, type, name ); | ||||||
|  |  | ||||||
| 		// Parameter list | 		// Parameter list | ||||||
| 		// CodeParam params = parse_params(); | 		// CodeParam params = parse_params(); | ||||||
| @@ -3911,11 +3934,11 @@ CodeFn parse_function() | |||||||
|  |  | ||||||
| 	CodeAttributes attributes = { nullptr }; | 	CodeAttributes attributes = { nullptr }; | ||||||
| 	CodeSpecifiers specifiers = { nullptr }; | 	CodeSpecifiers specifiers = { nullptr }; | ||||||
| 	ModuleFlag     mflags     = ModuleFlag::None; | 	ModuleFlag     mflags     = ModuleFlag_None; | ||||||
|  |  | ||||||
| 	if ( check(TokType::Module_Export) ) | 	if ( check(TokType::Module_Export) ) | ||||||
| 	{ | 	{ | ||||||
| 		mflags = ModuleFlag::Export; | 		mflags = ModuleFlag_Export; | ||||||
| 		eat( TokType::Module_Export ); | 		eat( TokType::Module_Export ); | ||||||
| 	} | 	} | ||||||
| 	// <export> | 	// <export> | ||||||
| @@ -4021,14 +4044,14 @@ CodeOperator parse_operator() | |||||||
|  |  | ||||||
| 	CodeAttributes attributes = { nullptr }; | 	CodeAttributes attributes = { nullptr }; | ||||||
| 	CodeSpecifiers specifiers = { nullptr }; | 	CodeSpecifiers specifiers = { nullptr }; | ||||||
| 	ModuleFlag     mflags     = ModuleFlag::None; | 	ModuleFlag     mflags     = ModuleFlag_None; | ||||||
|  |  | ||||||
| 	SpecifierT specs_found[16] { ESpecifier::NumSpecifiers }; | 	SpecifierT specs_found[16] { ESpecifier::NumSpecifiers }; | ||||||
| 	s32        NumSpecifiers = 0; | 	s32        NumSpecifiers = 0; | ||||||
|  |  | ||||||
| 	if ( check(TokType::Module_Export) ) | 	if ( check(TokType::Module_Export) ) | ||||||
| 	{ | 	{ | ||||||
| 		mflags = ModuleFlag::Export; | 		mflags = ModuleFlag_Export; | ||||||
| 		eat( TokType::Module_Export ); | 		eat( TokType::Module_Export ); | ||||||
| 	} | 	} | ||||||
| 	// <export> | 	// <export> | ||||||
| @@ -4111,7 +4134,7 @@ CodeOpCast parse_operator_cast( CodeSpecifiers specifiers ) | |||||||
| 	Code type = parse_type(); | 	Code type = parse_type(); | ||||||
| 	// <Specifiers> <Qualifier> :: ... operator <UnderlyingType> | 	// <Specifiers> <Qualifier> :: ... operator <UnderlyingType> | ||||||
|  |  | ||||||
| 	Context.Scope->Name = { type->Name.Data, type->Name.length() }; | 	Context.Scope->Name = { type->Name.Data, length(type->Name) }; | ||||||
|  |  | ||||||
| 	eat( TokType::Capture_Start ); | 	eat( TokType::Capture_Start ); | ||||||
| 	eat( TokType::Capture_End ); | 	eat( TokType::Capture_End ); | ||||||
| @@ -4209,11 +4232,11 @@ CodeTemplate parse_template() | |||||||
|  |  | ||||||
| 	push_scope(); | 	push_scope(); | ||||||
|  |  | ||||||
| 	ModuleFlag mflags = ModuleFlag::None; | 	ModuleFlag mflags = ModuleFlag_None; | ||||||
|  |  | ||||||
| 	if ( check( TokType::Module_Export ) ) | 	if ( check( TokType::Module_Export ) ) | ||||||
| 	{ | 	{ | ||||||
| 		mflags = ModuleFlag::Export; | 		mflags = ModuleFlag_Export; | ||||||
| 		eat( TokType::Module_Export ); | 		eat( TokType::Module_Export ); | ||||||
| 	} | 	} | ||||||
| 	// <export> template | 	// <export> template | ||||||
| @@ -4345,7 +4368,7 @@ CodeTemplate parse_template() | |||||||
| 			bool found_operator_cast_outside_class_implmentation = false; | 			bool found_operator_cast_outside_class_implmentation = false; | ||||||
| 			s32  idx = Context.Tokens.Idx; | 			s32  idx = Context.Tokens.Idx; | ||||||
|  |  | ||||||
| 			for ( ; idx < Context.Tokens.Arr.num(); idx++ ) | 			for ( ; idx < num(Context.Tokens.Arr); idx++ ) | ||||||
| 			{ | 			{ | ||||||
| 				Token tok = Context.Tokens[ idx ]; | 				Token tok = Context.Tokens[ idx ]; | ||||||
|  |  | ||||||
| @@ -4852,11 +4875,11 @@ CodeTypedef parse_typedef() | |||||||
| 	Code  array_expr  = { nullptr }; | 	Code  array_expr  = { nullptr }; | ||||||
| 	Code  type        = { nullptr }; | 	Code  type        = { nullptr }; | ||||||
|  |  | ||||||
| 	ModuleFlag mflags = ModuleFlag::None; | 	ModuleFlag mflags = ModuleFlag_None; | ||||||
|  |  | ||||||
| 	if ( check(TokType::Module_Export) ) | 	if ( check(TokType::Module_Export) ) | ||||||
| 	{ | 	{ | ||||||
| 		mflags = ModuleFlag::Export; | 		mflags = ModuleFlag_Export; | ||||||
| 		eat( TokType::Module_Export ); | 		eat( TokType::Module_Export ); | ||||||
| 	} | 	} | ||||||
| 	// <ModuleFlags> | 	// <ModuleFlags> | ||||||
| @@ -4893,7 +4916,7 @@ CodeTypedef parse_typedef() | |||||||
|  |  | ||||||
| 			s32 idx = tokens.Idx; | 			s32 idx = tokens.Idx; | ||||||
| 			s32 level = 0; | 			s32 level = 0; | ||||||
| 			for ( ; idx < tokens.Arr.num(); idx ++ ) | 			for ( ; idx < num(tokens.Arr); idx ++ ) | ||||||
| 			{ | 			{ | ||||||
| 				if ( tokens[idx].Type == TokType::BraceCurly_Open ) | 				if ( tokens[idx].Type == TokType::BraceCurly_Open ) | ||||||
| 					level++; | 					level++; | ||||||
| @@ -5047,11 +5070,11 @@ CodeUnion parse_union( bool inplace_def ) | |||||||
| { | { | ||||||
| 	push_scope(); | 	push_scope(); | ||||||
|  |  | ||||||
| 	ModuleFlag mflags = ModuleFlag::None; | 	ModuleFlag mflags = ModuleFlag_None; | ||||||
|  |  | ||||||
| 	if ( check(TokType::Module_Export) ) | 	if ( check(TokType::Module_Export) ) | ||||||
| 	{ | 	{ | ||||||
| 		mflags = ModuleFlag::Export; | 		mflags = ModuleFlag_Export; | ||||||
| 		eat( TokType::Module_Export ); | 		eat( TokType::Module_Export ); | ||||||
| 	} | 	} | ||||||
| 	// <ModuleFlags> | 	// <ModuleFlags> | ||||||
| @@ -5196,12 +5219,12 @@ CodeUsing parse_using() | |||||||
|  |  | ||||||
| 	bool is_namespace = false; | 	bool is_namespace = false; | ||||||
|  |  | ||||||
| 	ModuleFlag     mflags     = ModuleFlag::None; | 	ModuleFlag     mflags     = ModuleFlag_None; | ||||||
| 	CodeAttributes attributes = { nullptr }; | 	CodeAttributes attributes = { nullptr }; | ||||||
|  |  | ||||||
| 	if ( check(TokType::Module_Export) ) | 	if ( check(TokType::Module_Export) ) | ||||||
| 	{ | 	{ | ||||||
| 		mflags = ModuleFlag::Export; | 		mflags = ModuleFlag_Export; | ||||||
| 		eat( TokType::Module_Export ); | 		eat( TokType::Module_Export ); | ||||||
| 	} | 	} | ||||||
| 	// <ModuleFlags> | 	// <ModuleFlags> | ||||||
| @@ -5290,13 +5313,13 @@ CodeVar parse_variable() | |||||||
| 	SpecifierT specs_found[16] { ESpecifier::NumSpecifiers }; | 	SpecifierT specs_found[16] { ESpecifier::NumSpecifiers }; | ||||||
| 	s32        NumSpecifiers = 0; | 	s32        NumSpecifiers = 0; | ||||||
|  |  | ||||||
| 	ModuleFlag	   mflags     = ModuleFlag::None; | 	ModuleFlag	   mflags     = ModuleFlag_None; | ||||||
| 	CodeAttributes attributes = { nullptr }; | 	CodeAttributes attributes = { nullptr }; | ||||||
| 	CodeSpecifiers specifiers = { nullptr }; | 	CodeSpecifiers specifiers = { nullptr }; | ||||||
|  |  | ||||||
| 	if ( check(TokType::Module_Export) ) | 	if ( check(TokType::Module_Export) ) | ||||||
| 	{ | 	{ | ||||||
| 		mflags = ModuleFlag::Export; | 		mflags = ModuleFlag_Export; | ||||||
| 		eat( TokType::Module_Export ); | 		eat( TokType::Module_Export ); | ||||||
| 	} | 	} | ||||||
| 	// <ModuleFlags> | 	// <ModuleFlags> | ||||||
|   | |||||||
| @@ -13,63 +13,71 @@ using LogFailType = ssize(*)(char const*, ...); | |||||||
| 	#define log_failure GEN_FATAL | 	#define log_failure GEN_FATAL | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| enum class AccessSpec : u32 | enum AccessSpec enum_underlying(u32) | ||||||
| { | { | ||||||
| 	Default, | 	AccessSpec_Default, | ||||||
| 	Private, | 	AccessSpec_Private, | ||||||
| 	Protected, | 	AccessSpec_Protected, | ||||||
| 	Public, | 	AccessSpec_Public, | ||||||
|  |  | ||||||
| 	Num_AccessSpec, | 	AccessSpec_Num_AccessSpec, | ||||||
| 	Invalid, | 	AccessSpec_Invalid, | ||||||
|  |  | ||||||
|  | 	AccessSpec_SizeDef = GEN_U32_MAX, | ||||||
| }; | }; | ||||||
|  | static_assert( size_of(AccessSpec) == size_of(u32)); | ||||||
|  |  | ||||||
| inline | inline | ||||||
| char const* to_str( AccessSpec type ) | char const* to_str( AccessSpec type ) | ||||||
| { | { | ||||||
| 	local_persist | 	local_persist | ||||||
| 	char const* lookup[ (u32)AccessSpec::Num_AccessSpec ] = { | 	char const* lookup[ (u32)AccessSpec_Num_AccessSpec ] = { | ||||||
| 		"", | 		"", | ||||||
| 		"private", | 		"private", | ||||||
| 		"protected", | 		"protected", | ||||||
| 		"public", | 		"public", | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	if ( type > AccessSpec::Public ) | 	if ( type > AccessSpec_Public ) | ||||||
| 		return "Invalid"; | 		return "Invalid"; | ||||||
|  |  | ||||||
| 	return lookup[ (u32)type ]; | 	return lookup[ (u32)type ]; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | enum CodeFlag enum_underlying(u32) | ||||||
| enum CodeFlag : u32 |  | ||||||
| { | { | ||||||
| 	None          = 0, | 	CodeFlag_None          = 0, | ||||||
| 	FunctionType  = bit(0), | 	CodeFlag_FunctionType  = bit(0), | ||||||
| 	ParamPack     = bit(1), | 	CodeFlag_ParamPack     = bit(1), | ||||||
| 	Module_Export = bit(2), | 	CodeFlag_Module_Export = bit(2), | ||||||
| 	Module_Import = bit(3), | 	CodeFlag_Module_Import = bit(3), | ||||||
|  |  | ||||||
|  | 	CodeFlag_SizeDef = GEN_U32_MAX, | ||||||
| }; | }; | ||||||
|  | static_assert( size_of(CodeFlag) == size_of(u32)); | ||||||
|  |  | ||||||
| // Used to indicate if enum definitoin is an enum class or regular enum. | // Used to indicate if enum definitoin is an enum class or regular enum. | ||||||
| enum class EnumT : u8 | enum EnumDecl enum_underlying(u8) | ||||||
| { | { | ||||||
| 	Regular, | 	EnumDecl_Regular, | ||||||
| 	Class | 	EnumDecl_Class, | ||||||
|  |  | ||||||
|  | 	EnumT_SizeDef = GEN_U8_MAX, | ||||||
| }; | }; | ||||||
|  | typedef u8 EnumT; | ||||||
|  |  | ||||||
| constexpr EnumT EnumClass   = EnumT::Class; | enum ModuleFlag enum_underlying(u32) | ||||||
| constexpr EnumT EnumRegular = EnumT::Regular; |  | ||||||
|  |  | ||||||
| enum class ModuleFlag : u32 |  | ||||||
| { | { | ||||||
| 	None    = 0, | 	ModuleFlag_None    = 0, | ||||||
| 	Export  = bit(0), | 	ModuleFlag_Export  = bit(0), | ||||||
| 	Import  = bit(1), | 	ModuleFlag_Import  = bit(1), | ||||||
|  |  | ||||||
| 	Num_ModuleFlags, | 	Num_ModuleFlags, | ||||||
| 	Invalid, | 	ModuleFlag_Invalid, | ||||||
|  |  | ||||||
|  | 	ModuleFlag_SizeDef = GEN_U32_MAX, | ||||||
| }; | }; | ||||||
|  | static_assert( size_of(ModuleFlag) == size_of(u32)); | ||||||
|  |  | ||||||
| inline | inline | ||||||
| StrC to_str( ModuleFlag flag ) | StrC to_str( ModuleFlag flag ) | ||||||
| @@ -81,7 +89,7 @@ StrC to_str( ModuleFlag flag ) | |||||||
| 		{ sizeof("import"), "import" }, | 		{ sizeof("import"), "import" }, | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	if ( flag > ModuleFlag::Import ) | 	if ( flag > ModuleFlag_Import ) | ||||||
| 		return { sizeof("invalid"), "invalid" }; | 		return { sizeof("invalid"), "invalid" }; | ||||||
|  |  | ||||||
| 	return lookup[ (u32)flag ]; | 	return lookup[ (u32)flag ]; | ||||||
| @@ -93,15 +101,13 @@ ModuleFlag operator|( ModuleFlag A, ModuleFlag B) | |||||||
| 	return (ModuleFlag)( (u32)A | (u32)B ); | 	return (ModuleFlag)( (u32)A | (u32)B ); | ||||||
| } | } | ||||||
|  |  | ||||||
| enum class EPreprocessCond : u32 | enum EPreprocessCond enum_underlying(u32) | ||||||
| { | { | ||||||
| 	If, | 	PreprocessCond_If, | ||||||
| 	IfDef, | 	PreprocessCond_IfDef, | ||||||
| 	IfNotDef, | 	PreprocessCond_IfNotDef, | ||||||
| 	ElIf | 	PreprocessCond_ElIf, | ||||||
| }; |  | ||||||
|  |  | ||||||
| constexpr EPreprocessCond PreprocessCond_If       = EPreprocessCond::If; | 	EPreprocessCond_SizeDef = GEN_U32_MAX, | ||||||
| constexpr EPreprocessCond PreprocessCond_IfDef    = EPreprocessCond::IfDef; | }; | ||||||
| constexpr EPreprocessCond PreprocessCond_IfNotDef = EPreprocessCond::IfNotDef; | static_assert( size_of(EPreprocessCond) == size_of(u32)); | ||||||
| constexpr EPreprocessCond PreprocessCond_ElIf     = EPreprocessCond::ElIf; |  | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||||
| #	pragma once | #	pragma once | ||||||
|  | #	include "platform.hpp" | ||||||
| #	include "macros.hpp" | #	include "macros.hpp" | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| @@ -122,13 +123,21 @@ typedef s8  b8; | |||||||
| typedef s16 b16; | typedef s16 b16; | ||||||
| typedef s32 b32; | typedef s32 b32; | ||||||
|  |  | ||||||
| using mem_ptr       = void*; | typedef void*       mem_ptr; | ||||||
| using mem_ptr_const = void const*; | typedef void const* mem_ptr_const ; | ||||||
|  |  | ||||||
|  | #if ! GEN_COMPILER_C | ||||||
| template<typename Type> uptr to_uptr( Type* ptr ) { return (uptr)ptr; } | template<typename Type> uptr to_uptr( Type* ptr ) { return (uptr)ptr; } | ||||||
| template<typename Type> sptr to_sptr( Type* ptr ) { return (sptr)ptr; } | template<typename Type> sptr to_sptr( Type* ptr ) { return (sptr)ptr; } | ||||||
|  |  | ||||||
| template<typename Type> mem_ptr       to_mem_ptr      ( Type ptr ) { return (mem_ptr)      ptr; } | template<typename Type> mem_ptr       to_mem_ptr      ( Type ptr ) { return (mem_ptr)      ptr; } | ||||||
| template<typename Type> mem_ptr_const to_mem_ptr_const( Type ptr ) { return (mem_ptr_const)ptr; } | template<typename Type> mem_ptr_const to_mem_ptr_const( Type ptr ) { return (mem_ptr_const)ptr; } | ||||||
|  | #else | ||||||
|  | #define to_utpr( ptr ) ((uptr)(ptr)) | ||||||
|  | #define to_stpr( ptr ) ((sptr)(ptr)) | ||||||
|  |  | ||||||
|  | #define to_mem_ptr( ptr)       ((mem_ptr)ptr) | ||||||
|  | #define to_mem_ptr_const( ptr) ((mem_ptr)ptr) | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #pragma endregion Basic Types | #pragma endregion Basic Types | ||||||
|   | |||||||
| @@ -13,26 +13,101 @@ template<class TType, usize Size> struct RemoveConst<const TType[Size]> { typede | |||||||
| template<class TType> | template<class TType> | ||||||
| using TRemoveConst = typename RemoveConst<TType>::Type; | using TRemoveConst = typename RemoveConst<TType>::Type; | ||||||
|  |  | ||||||
|  | #pragma region Array | ||||||
|  | #if ! GEN_COMPILER_C | ||||||
|  | #define Array(Type) Array<Type> | ||||||
|  |  | ||||||
|  | // #define array_init(Type, ...)         array_init        <Type>(__VA_ARGS__) | ||||||
|  | // #define array_init_reserve(Type, ...) array_init_reserve<Type>(__VA_ARGS__) | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | struct ArrayHeader; | ||||||
|  |  | ||||||
|  | #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||||
|  | template<class Type> struct Array; | ||||||
|  | #else | ||||||
| template<class Type> | template<class Type> | ||||||
| struct Array | using Array = Type*; | ||||||
| { | #endif | ||||||
| 	struct Header |  | ||||||
| 	{ | usize array_grow_formula(ssize value); | ||||||
|  |  | ||||||
|  | template<class Type> Array<Type>  array_init(AllocatorInfo allocator); | ||||||
|  | template<class Type> Array<Type>  array_init_reserve(AllocatorInfo allocator, ssize capacity); | ||||||
|  | template<class Type> bool         append(Array<Type>& array, Array<Type> other); | ||||||
|  | template<class Type> bool         append(Array<Type>& array, Type value); | ||||||
|  | template<class Type> bool         append(Array<Type>& array, Type* items, usize item_num); | ||||||
|  | template<class Type> bool         append_at(Array<Type>& array, Type item, usize idx); | ||||||
|  | template<class Type> bool         append_at(Array<Type>& array, Type* items, usize item_num, usize idx); | ||||||
|  | template<class Type> Type&        back(Array<Type>& array); | ||||||
|  | template<class Type> void         clear(Array<Type>& array); | ||||||
|  | template<class Type> bool         fill(Array<Type>& array, usize begin, usize end, Type value); | ||||||
|  | template<class Type> void         free(Array<Type>& array); | ||||||
|  | template<class Type> bool         grow(Array<Type>& array, usize min_capacity); | ||||||
|  | template<class Type> usize        num(Array<Type>& array); | ||||||
|  | template<class Type> void         pop(Array<Type>& array); | ||||||
|  | template<class Type> void         remove_at(Array<Type>& array, usize idx); | ||||||
|  | template<class Type> bool         reserve(Array<Type>& array, usize new_capacity); | ||||||
|  | template<class Type> bool         resize(Array<Type>& array, usize num); | ||||||
|  | template<class Type> bool         set_capacity(Array<Type>& array, usize new_capacity); | ||||||
|  | template<class Type> ArrayHeader* get_header(Array<Type>& array); | ||||||
|  |  | ||||||
|  | template<class Type> forceinline Type* begin(Array<Type>& array)             { return array;      } | ||||||
|  | template<class Type> forceinline Type* end(Array<Type>& array)               { return array + get_header(array)->Num; } | ||||||
|  | template<class Type> forceinline Type* next(Array<Type>& array, Type* entry) { return entry + 1; } | ||||||
|  |  | ||||||
|  | struct ArrayHeader { | ||||||
| 	AllocatorInfo Allocator; | 	AllocatorInfo Allocator; | ||||||
| 	usize         Capacity; | 	usize         Capacity; | ||||||
| 	usize         Num; | 	usize         Num; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| 	static | #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||||
| 	Array init( AllocatorInfo allocator ) | template<class Type> | ||||||
|  | struct Array | ||||||
| { | { | ||||||
| 		return init_reserve( allocator, grow_formula(0) ); | 	Type* Data; | ||||||
|  |  | ||||||
|  | #pragma region Member Mapping | ||||||
|  | 	forceinline static Array  init(AllocatorInfo allocator)                         { return GEN_NS array_init<Type>(allocator); } | ||||||
|  | 	forceinline static Array  init_reserve(AllocatorInfo allocator, ssize capacity) { return GEN_NS array_init_reserve<Type>(allocator, capacity); } | ||||||
|  | 	forceinline static usize  grow_formula(ssize value)                             { return GEN_NS array_grow_formula<Type>(value); } | ||||||
|  |  | ||||||
|  | 	forceinline bool         append(Array other)                               { return GEN_NS append<Type>(*this, other); } | ||||||
|  | 	forceinline bool         append(Type value)                                { return GEN_NS append<Type>(*this, value); } | ||||||
|  | 	forceinline bool         append(Type* items, usize item_num)               { return GEN_NS append<Type>(*this, items, item_num); } | ||||||
|  | 	forceinline bool         append_at(Type item, usize idx)                   { return GEN_NS append_at<Type>(*this, item, idx); } | ||||||
|  | 	forceinline bool         append_at(Type* items, usize item_num, usize idx) { return GEN_NS append_at<Type>(*this, items, item_num, idx); } | ||||||
|  | 	forceinline Type&        back()                                            { return GEN_NS back<Type>(*this); } | ||||||
|  | 	forceinline void         clear()                                           { GEN_NS clear<Type>(*this); } | ||||||
|  | 	forceinline bool         fill(usize begin, usize end, Type value)          { return GEN_NS fill<Type>(*this, begin, end, value); } | ||||||
|  | 	forceinline void         free()                                            { GEN_NS free<Type>(*this); } | ||||||
|  | 	forceinline ArrayHeader* get_header()                                      { return GEN_NS get_header<Type>(*this); } | ||||||
|  | 	forceinline bool         grow(usize min_capacity)                          { return GEN_NS grow<Type>(*this, min_capacity); } | ||||||
|  | 	forceinline usize        num()                                             { return GEN_NS num<Type>(*this); } | ||||||
|  | 	forceinline void         pop()                                             { GEN_NS pop<Type>(*this); } | ||||||
|  | 	forceinline void         remove_at(usize idx)                              { GEN_NS remove_at<Type>(*this, idx); } | ||||||
|  | 	forceinline bool         reserve(usize new_capacity)                       { return GEN_NS reserve<Type>(*this, new_capacity); } | ||||||
|  | 	forceinline bool         resize(usize num)                                 { return GEN_NS resize<Type>(*this, num); } | ||||||
|  | 	forceinline bool         set_capacity(usize new_capacity)                  { return GEN_NS set_capacity<Type>(*this, new_capacity); } | ||||||
|  |  | ||||||
|  | 	forceinline operator Type*()             { return Data; } | ||||||
|  | 	forceinline operator Type const*() const { return Data; } | ||||||
|  | 	forceinline Type* begin()                { return Data; } | ||||||
|  | 	forceinline Type* end()                  { return Data + get_header()->Num; } | ||||||
|  | #pragma endregion Member Mapping | ||||||
|  | }; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | template<class Type> inline | ||||||
|  | Array<Type> array_init(AllocatorInfo allocator) { | ||||||
|  | 	return array_init_reserve<Type>(allocator, array_grow_formula(0)); | ||||||
| } | } | ||||||
|  |  | ||||||
| 	static | template<class Type> inline | ||||||
| 	Array init_reserve( AllocatorInfo allocator, ssize capacity ) | Array<Type> array_init_reserve(AllocatorInfo allocator, ssize capacity) | ||||||
| { | { | ||||||
| 		Header* header = rcast( Header*, alloc( allocator, sizeof(Header) + sizeof(Type) * capacity )); | 	ArrayHeader* header = rcast(ArrayHeader*, alloc(allocator, sizeof(ArrayHeader) + sizeof(Type) * capacity)); | ||||||
|  |  | ||||||
| 	if (header == nullptr) | 	if (header == nullptr) | ||||||
|  		return {nullptr}; |  		return {nullptr}; | ||||||
| @@ -44,56 +119,55 @@ struct Array | |||||||
| 	return {rcast(Type*, header + 1)}; | 	return {rcast(Type*, header + 1)}; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	static | usize array_grow_formula(ssize value) { | ||||||
| 	usize grow_formula( usize value ) |  | ||||||
| 	{ |  | ||||||
| 	return 2 * value + 8; | 	return 2 * value + 8; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	bool append( Array other ) | template<class Type> inline | ||||||
| 	{ | bool append(Array<Type>& array, Array<Type> other) { | ||||||
| 		return append( other, other.num() ); | 	return append(array, other, num(other)); | ||||||
| } | } | ||||||
|  |  | ||||||
| 	bool append( Type value ) | template<class Type> inline | ||||||
|  | bool append(Array<Type>& array, Type value) | ||||||
| { | { | ||||||
| 		Header* header = get_header(); | 	ArrayHeader* header = get_header(array); | ||||||
|  |  | ||||||
| 	if (header->Num == header->Capacity) | 	if (header->Num == header->Capacity) | ||||||
| 	{ | 	{ | ||||||
| 			if ( ! grow( header->Capacity )) | 		if (!grow(array, header->Capacity)) | ||||||
| 			return false; | 			return false; | ||||||
|  | 		header = get_header(array); | ||||||
| 			header = get_header(); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 		Data[ header->Num ] = value; | 	array[header->Num] = value; | ||||||
| 	header->Num++; | 	header->Num++; | ||||||
|  |  | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	bool append( Type* items, usize item_num ) | template<class Type> inline | ||||||
|  | bool append(Array<Type>& array, Type* items, usize item_num) | ||||||
| { | { | ||||||
| 		Header* header = get_header(); | 	ArrayHeader* header = get_header(array); | ||||||
|  |  | ||||||
| 	if (header->Num + item_num > header->Capacity) | 	if (header->Num + item_num > header->Capacity) | ||||||
| 	{ | 	{ | ||||||
| 			if ( ! grow( header->Capacity + item_num )) | 		if (!grow(array, header->Capacity + item_num)) | ||||||
| 			return false; | 			return false; | ||||||
|  | 		header = get_header(array); | ||||||
| 			header = get_header(); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 		mem_copy( Data + header->Num, items, item_num * sizeof(Type) ); | 	mem_copy(array.Data + header->Num, items, item_num * sizeof(Type)); | ||||||
| 	header->Num += item_num; | 	header->Num += item_num; | ||||||
|  |  | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	bool append_at( Type item, usize idx ) | template<class Type> inline | ||||||
|  | bool append_at(Array<Type>& array, Type item, usize idx) | ||||||
| { | { | ||||||
| 		Header* header = get_header(); | 	ArrayHeader* header = get_header(array); | ||||||
|  |  | ||||||
| 	if (idx >= header->Num) | 	if (idx >= header->Num) | ||||||
| 	 	idx = header->Num - 1; | 	 	idx = header->Num - 1; | ||||||
| @@ -103,13 +177,13 @@ struct Array | |||||||
|  |  | ||||||
| 	if (header->Capacity < header->Num + 1) | 	if (header->Capacity < header->Num + 1) | ||||||
| 	{ | 	{ | ||||||
| 			if ( ! grow( header->Capacity + 1 )) | 		if (!grow(array, header->Capacity + 1)) | ||||||
| 			return false; | 			return false; | ||||||
|  |  | ||||||
| 			header = get_header(); | 		header = get_header(array); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 		Type* target = Data + idx; | 	Type* target = array + idx; | ||||||
|  |  | ||||||
| 	mem_move(target + 1, target, (header->Num - idx) * sizeof(Type)); | 	mem_move(target + 1, target, (header->Num - idx) * sizeof(Type)); | ||||||
| 	header->Num++; | 	header->Num++; | ||||||
| @@ -117,25 +191,26 @@ struct Array | |||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	bool append_at( Type* items, usize item_num, usize idx ) | template<class Type> inline | ||||||
|  | bool append_at(Array<Type>& array, Type* items, usize item_num, usize idx) | ||||||
| { | { | ||||||
| 		Header* header = get_header(); | 	ArrayHeader* header = get_header(array); | ||||||
|  |  | ||||||
| 	if (idx >= header->Num) | 	if (idx >= header->Num) | ||||||
| 	{ | 	{ | ||||||
| 			return append( items, item_num ); | 		return append(array, items, item_num); | ||||||
|  	} |  	} | ||||||
|  |  | ||||||
| 	if (item_num > header->Capacity) | 	if (item_num > header->Capacity) | ||||||
| 	{ | 	{ | ||||||
| 			if ( ! grow( header->Capacity + item_num ) ) | 		if (!grow(array, header->Capacity + item_num)) | ||||||
| 			return false; | 			return false; | ||||||
|  |  | ||||||
| 			header = get_header(); | 		header = get_header(array); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 		Type* target = Data + idx + item_num; | 	Type* target = array.Data + idx + item_num; | ||||||
| 		Type* src    = Data + idx; | 	Type* src    = array.Data + idx; | ||||||
|  |  | ||||||
| 	mem_move(target, src, (header->Num - idx) * sizeof(Type)); | 	mem_move(target, src, (header->Num - idx) * sizeof(Type)); | ||||||
| 	mem_copy(src, items, item_num * sizeof(Type)); | 	mem_copy(src, items, item_num * sizeof(Type)); | ||||||
| @@ -144,268 +219,310 @@ struct Array | |||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	Type& back( void ) | template<class Type> inline | ||||||
| 	{ | Type& back(Array<Type>& array) { | ||||||
| 		Header& header = * get_header(); | 	ArrayHeader* header = get_header(array); | ||||||
| 		return Data[ header.Num - 1 ]; | 	return array[header->Num - 1]; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	void clear( void ) | template<class Type> inline | ||||||
| 	{ | void clear(Array<Type>& array) { | ||||||
| 		Header& header = * get_header(); | 	ArrayHeader* header = get_header(array); | ||||||
| 		header.Num     = 0; | 	header->Num = 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	bool fill( usize begin, usize end, Type value ) | template<class Type> inline | ||||||
|  | bool fill(Array<Type>& array, usize begin, usize end, Type value) | ||||||
| { | { | ||||||
| 		Header& header = * get_header(); | 	ArrayHeader* header = get_header(array); | ||||||
|  |  | ||||||
| 		if ( begin < 0 || end > header.Num ) | 	if (begin < 0 || end > header->Num) | ||||||
| 	return false; | 	return false; | ||||||
|  |  | ||||||
| 	for (ssize idx = ssize(begin); idx < ssize(end); idx++) | 	for (ssize idx = ssize(begin); idx < ssize(end); idx++) | ||||||
| 	{ | 	{ | ||||||
| 			Data[ idx ] = value; | 		array[idx] = value; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	void free( void ) | template<class Type> inline | ||||||
| 	{ | void free(Array<Type>& array) { | ||||||
| 		Header& header = * get_header(); | 	ArrayHeader* header = get_header(array); | ||||||
| 		gen::free( header.Allocator, &header ); | 	GEN_NS free(header->Allocator, header); | ||||||
|  | 	Type*& Data = rcast(Type*&, array); | ||||||
| 	Data = nullptr; | 	Data = nullptr; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	Header* get_header( void ) | template<class Type> inline | ||||||
| 	{ | ArrayHeader* get_header(Array<Type>& array) { | ||||||
| 	using NonConstType = TRemoveConst<Type>; | 	using NonConstType = TRemoveConst<Type>; | ||||||
| 		return rcast( Header*, const_cast<NonConstType*>(Data) ) - 1 ; | 	Type* Data = array; // This should do nothing in C but in C++ gets member Data struct. | ||||||
|  | 	return rcast(ArrayHeader*, const_cast<NonConstType*>(Data)) - 1; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	bool grow( usize min_capacity ) | template<class Type> inline | ||||||
|  | bool grow(Array<Type>& array, usize min_capacity) | ||||||
| { | { | ||||||
| 		Header& header       = * get_header(); | 	ArrayHeader* header = get_header(array); | ||||||
| 		usize      new_capacity = grow_formula( header.Capacity ); | 	usize new_capacity = array_grow_formula(header->Capacity); | ||||||
|  |  | ||||||
| 	if (new_capacity < min_capacity) | 	if (new_capacity < min_capacity) | ||||||
| 	new_capacity = min_capacity; | 	new_capacity = min_capacity; | ||||||
|  |  | ||||||
| 		return set_capacity( new_capacity ); | 	return set_capacity(array, new_capacity); | ||||||
| } | } | ||||||
|  |  | ||||||
| 	usize num( void ) | template<class Type> inline | ||||||
| 	{ | usize num(Array<Type>& array) { | ||||||
| 		return get_header()->Num; | 	return get_header(array)->Num; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	void pop( void ) | template<class Type> inline | ||||||
| 	{ | void pop(Array<Type>& array) { | ||||||
| 		Header& header = * get_header(); | 	ArrayHeader* header = get_header(array); | ||||||
|  | 	GEN_ASSERT(header->Num > 0); | ||||||
| 		GEN_ASSERT( header.Num > 0 ); |  | ||||||
| 		header.Num--; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	void remove_at( usize idx ) |  | ||||||
| 	{ |  | ||||||
| 		Header* header = get_header(); |  | ||||||
| 		GEN_ASSERT( idx < header->Num ); |  | ||||||
|  |  | ||||||
| 		mem_move( header + idx, header + idx + 1, sizeof( Type ) * ( header->Num - idx - 1 ) ); |  | ||||||
| 	header->Num--; | 	header->Num--; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	bool reserve( usize new_capacity ) | template<class Type> inline | ||||||
|  | void remove_at(Array<Type>& array, usize idx) | ||||||
| { | { | ||||||
| 		Header& header = * get_header(); | 	ArrayHeader* header = get_header(array); | ||||||
|  | 	GEN_ASSERT(idx < header->Num); | ||||||
|  |  | ||||||
| 		if ( header.Capacity < new_capacity ) | 	mem_move(array + idx, array + idx + 1, sizeof(Type) * (header->Num - idx - 1)); | ||||||
| 			return set_capacity( new_capacity ); | 	header->Num--; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<class Type> inline | ||||||
|  | bool reserve(Array<Type>& array, usize new_capacity) | ||||||
|  | { | ||||||
|  | 	ArrayHeader* header = get_header(array); | ||||||
|  |  | ||||||
|  | 	if (header->Capacity < new_capacity) | ||||||
|  |  		return set_capacity(array, new_capacity); | ||||||
|  |  | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	bool resize( usize num ) | template<class Type> inline | ||||||
|  | bool resize(Array<Type>& array, usize num) | ||||||
| { | { | ||||||
| 		Header* header = get_header(); | 	ArrayHeader* header = get_header(array); | ||||||
|  |  | ||||||
| 		if ( header->Capacity < num ) | 	if (header->Capacity < num) { | ||||||
| 		{ | 		if (!grow(array, num)) | ||||||
| 			if ( ! grow( num ) ) |  | ||||||
| 			return false; | 			return false; | ||||||
|  | 		header = get_header(array); | ||||||
| 			header = get_header(); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	header->Num = num; | 	header->Num = num; | ||||||
|  	return true; |  	return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	bool set_capacity( usize new_capacity ) | template<class Type> inline | ||||||
|  | bool set_capacity(Array<Type>& array, usize new_capacity) | ||||||
| { | { | ||||||
| 		Header& header = * get_header(); | 	ArrayHeader* header = get_header(array); | ||||||
|  |  | ||||||
| 		if ( new_capacity == header.Capacity ) | 	if (new_capacity == header->Capacity) | ||||||
| 	return true; | 	return true; | ||||||
|  |  | ||||||
| 		if ( new_capacity < header.Num ) | 	if (new_capacity < header->Num) | ||||||
| 	{ | 	{ | ||||||
| 			// Already have the memory, mine as well keep it. | 		header->Num = new_capacity; | ||||||
| 			header.Num = new_capacity; |  | ||||||
| 		return true; | 		return true; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 		ssize      size       = sizeof( Header ) + sizeof( Type ) * new_capacity; | 	ssize size = sizeof(ArrayHeader) + sizeof(Type) * new_capacity; | ||||||
| 		Header* new_header = rcast( Header*, alloc( header.Allocator, size ) ); | 	ArrayHeader* new_header = rcast(ArrayHeader*, alloc(header->Allocator, size)); | ||||||
|  |  | ||||||
| 	if (new_header == nullptr) | 	if (new_header == nullptr) | ||||||
| 		return false; | 		return false; | ||||||
|  |  | ||||||
| 		mem_move( new_header, &header, sizeof( Header ) + sizeof( Type ) * header.Num ); | 	mem_move(new_header, header, sizeof(ArrayHeader) + sizeof(Type) * header->Num); | ||||||
|  |  | ||||||
| 	new_header->Capacity = new_capacity; | 	new_header->Capacity = new_capacity; | ||||||
|  |  | ||||||
| 		gen::free( header.Allocator, &header ); | 	GEN_NS free(header->Allocator, header); | ||||||
|  |  | ||||||
|  | 	Type*& Data = rcast(Type*&, array); | ||||||
| 	Data = rcast(Type*, new_header + 1); | 	Data = rcast(Type*, new_header + 1); | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	Type* Data; | #define array_init(Type, allocator)                            array_init<Type>(allocator) | ||||||
|  | #define array_init(Type, allocator)                            array_init<Type>(allocator) | ||||||
|  | #define array_init_reserve(Type, allocator, capacity)          array_init_reserve<Type>(allocator, capacity) | ||||||
|  | #define array_append(Type, array, other)                       append<Type>(array, other) | ||||||
|  | #define array_append_value(Type, array, value)                 append<Type>(array, value) | ||||||
|  | #define array_append_items(Type, array, items, item_num)       append<Type>(array, items, item_num) | ||||||
|  | #define array_append_at(Type, array, item, idx)                append_at<Type>(array, item, idx) | ||||||
|  | #define array_append_items_at(Type, array, items, num, idx)    append_at<Type>(array, items, num, idx) | ||||||
|  | #define array_back(Type, array)                                back<Type>(array) | ||||||
|  | #define array_clear(Type, array)                               clear<Type>(array) | ||||||
|  | #define array_fill(Type, array, begin, end, value)             fill<Type>(array, begin, end, value) | ||||||
|  | #define array_free(Type, array)                                free<Type>(array) | ||||||
|  | #define array_grow(Type, array, min_capacity)                  grow<Type>(array, min_capacity) | ||||||
|  | #define array_num(Type, array)                                 num<Type>(array) | ||||||
|  | #define array_pop(Type, array)                                 pop<Type>(array) | ||||||
|  | #define array_remove_at(Type, array, idx)                      remove_at<Type>(array, idx) | ||||||
|  | #define array_reserve(Type, array, new_capacity)               reserve<Type>(array, new_capacity) | ||||||
|  | #define array_resize(Type, array, num)                         resize<Type>(array, num) | ||||||
|  | #define array_set_capacity(Type, array, new_capacity)          set_capacity<Type>(array, new_capacity) | ||||||
|  | #define array_get_header(array)                                get_header(array) | ||||||
|  |  | ||||||
| 	operator Type*() | #pragma endregion Array | ||||||
| 	{ |  | ||||||
| 		return Data; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	operator Type const*() const |  | ||||||
| 	{ |  | ||||||
| 		return Data; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// For-range based support |  | ||||||
|  |  | ||||||
| 	Type* begin() |  | ||||||
| 	{ |  | ||||||
| 		return Data; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	Type* end() |  | ||||||
| 	{ |  | ||||||
| 		return Data + get_header()->Num; |  | ||||||
| 	} |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| // TODO(Ed) : This thing needs ALOT of work. | // TODO(Ed) : This thing needs ALOT of work. | ||||||
|  |  | ||||||
| template<typename Type> | #pragma region HashTable | ||||||
| struct HashTable | template<class Type> struct HashTable; | ||||||
| { |  | ||||||
| 	struct FindResult | struct HashTableFindResult { | ||||||
| 	{ |  | ||||||
| 	ssize HashIndex; | 	ssize HashIndex; | ||||||
| 	ssize PrevIndex; | 	ssize PrevIndex; | ||||||
| 	ssize EntryIndex; | 	ssize EntryIndex; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| 	struct Entry | template<class Type> | ||||||
| 	{ | struct HashTableEntry { | ||||||
| 	u64   Key; | 	u64   Key; | ||||||
| 	ssize Next; | 	ssize Next; | ||||||
| 	Type  Value; | 	Type  Value; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| 	static constexpr f32 CriticalLoadScale = 0.7f; | #define HashTableEntry(Type) HashTableEntry<Type> | ||||||
|  |  | ||||||
| 	static | template<class Type> HashTable<Type>       hashtable_init(AllocatorInfo allocator); | ||||||
| 	HashTable init( AllocatorInfo allocator ) | template<class Type> HashTable<Type>       hashtable_init_reserve(AllocatorInfo allocator, usize num); | ||||||
|  | template<class Type> void                  clear(HashTable<Type>& table); | ||||||
|  | template<class Type> void                  destroy(HashTable<Type>& table); | ||||||
|  | template<class Type> Type*                 get(HashTable<Type>& table, u64 key); | ||||||
|  | template<class Type> void                  grow(HashTable<Type>& table); | ||||||
|  | template<class Type> void                  rehash(HashTable<Type>& table, ssize new_num); | ||||||
|  | template<class Type> void                  rehash_fast(HashTable<Type>& table); | ||||||
|  | template<class Type> void                  remove(HashTable<Type>& table, u64 key); | ||||||
|  | template<class Type> void                  remove_entry(HashTable<Type>& table, ssize idx); | ||||||
|  | template<class Type> void                  set(HashTable<Type>& table, u64 key, Type value); | ||||||
|  | template<class Type> ssize                 slot(HashTable<Type>& table, u64 key); | ||||||
|  | template<class Type> ssize                 add_entry(HashTable<Type>& table, u64 key); | ||||||
|  | template<class Type> HashTableFindResult   find(HashTable<Type>& table, u64 key); | ||||||
|  | template<class Type> bool                  full(HashTable<Type>& table); | ||||||
|  | template<class Type> void                  map(HashTable<Type>& table, void (*map_proc)(u64 key, Type value)); | ||||||
|  | template<class Type> void                  map_mut(HashTable<Type>& table, void (*map_proc)(u64 key, Type* value)); | ||||||
|  |  | ||||||
|  | static constexpr f32 HashTable_CriticalLoadScale = 0.7f; | ||||||
|  |  | ||||||
|  | template<typename Type> | ||||||
|  | struct HashTable | ||||||
| { | { | ||||||
| 		HashTable<Type> result = init_reserve(allocator, 8); | 	Array<ssize>                Hashes; | ||||||
|  | 	Array<HashTableEntry<Type>> Entries; | ||||||
|  |  | ||||||
|  | #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||||
|  | #pragma region Member Mapping | ||||||
|  | 	forceinline static HashTable init(AllocatorInfo allocator)                    { return GEN_NS hashtable_init<Type>(allocator); } | ||||||
|  | 	forceinline static HashTable init_reserve(AllocatorInfo allocator, usize num) { return GEN_NS hashtable_init_reserve<Type>(allocator, num); } | ||||||
|  |  | ||||||
|  | 	forceinline void  clear()                           { GEN_NS clear<Type>(*this); } | ||||||
|  | 	forceinline void  destroy()                         { GEN_NS destroy<Type>(*this); } | ||||||
|  | 	forceinline Type* get(u64 key)                      { return GEN_NS get<Type>(*this, key); } | ||||||
|  | 	forceinline void  grow()                            { GEN_NS grow<Type>(*this); } | ||||||
|  | 	forceinline void  rehash(ssize new_num)             { GEN_NS rehash<Type>(*this, new_num); } | ||||||
|  | 	forceinline void  rehash_fast()                     { GEN_NS rehash_fast<Type>(*this); } | ||||||
|  | 	forceinline void  remove(u64 key)                   { GEN_NS remove<Type>(*this, key); } | ||||||
|  | 	forceinline void  remove_entry(ssize idx)           { GEN_NS remove_entry<Type>(*this, idx); } | ||||||
|  | 	forceinline void  set(u64 key, Type value)          { GEN_NS set<Type>(*this, key, value); } | ||||||
|  | 	forceinline ssize slot(u64 key)                     { return GEN_NS slot<Type>(*this, key); } | ||||||
|  | 	forceinline void  map(void (*proc)(u64, Type))      { GEN_NS map<Type>(*this, proc); } | ||||||
|  | 	forceinline void  map_mut(void (*proc)(u64, Type*)) { GEN_NS map_mut<Type>(*this, proc); } | ||||||
|  | #pragma endregion Member Mapping | ||||||
|  | #endif | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename Type> inline | ||||||
|  | HashTable<Type> hashtable_init(AllocatorInfo allocator) { | ||||||
|  | 	HashTable<Type> result = hashtable_init_reserve<Type>(allocator, 8); | ||||||
| 	return result; | 	return result; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	static | template<typename Type> inline | ||||||
| 	HashTable init_reserve( AllocatorInfo allocator, usize num ) | HashTable<Type> hashtable_init_reserve(AllocatorInfo allocator, usize num) | ||||||
| { | { | ||||||
| 	HashTable<Type> result = { { nullptr }, { nullptr } }; | 	HashTable<Type> result = { { nullptr }, { nullptr } }; | ||||||
|  |  | ||||||
| 		result.Hashes  = Array<ssize>::init_reserve( allocator, num ); | 	result.Hashes = array_init_reserve<ssize>(allocator, num); | ||||||
| 		result.Hashes.get_header()->Num = num; | 	get_header(result.Hashes)->Num = num; | ||||||
| 		result.Hashes.resize( num ); | 	resize(result.Hashes, num); | ||||||
| 		result.Hashes.fill( 0, num, -1); | 	fill<ssize>(result.Hashes, 0, num, -1); | ||||||
|  |  | ||||||
| 		result.Entries = Array<Entry>::init_reserve( allocator, num ); | 	result.Entries = array_init_reserve<HashTableEntry<Type>>(allocator, num); | ||||||
| 	return result; | 	return result; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	void clear( void ) | template<typename Type> inline | ||||||
| 	{ | void clear(HashTable<Type>& table) { | ||||||
| 		Entries.clear(); | 	clear(table.Entries); | ||||||
| 		Hashes.fill( 0, Hashes.num(), -1); | 	fill<ssize>(table.Hashes, 0, num(table.Hashes), -1); | ||||||
| } | } | ||||||
|  |  | ||||||
| 	void destroy( void ) | template<typename Type> inline | ||||||
| 	{ | void destroy(HashTable<Type>& table) { | ||||||
| 		if ( Hashes && Hashes.get_header()->Capacity ) | 	if (table.Hashes && get_header(table.Hashes)->Capacity) { | ||||||
| 		{ | 		free(table.Hashes); | ||||||
| 			Hashes.free(); | 		free(table.Entries); | ||||||
| 			Entries.free(); |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| 	Type* get( u64 key ) | template<typename Type> inline | ||||||
| 	{ | Type* get(HashTable<Type>& table, u64 key) { | ||||||
| 		ssize idx = find( key ).EntryIndex; | 	ssize idx = find(table, key).EntryIndex; | ||||||
| 	if (idx >= 0) | 	if (idx >= 0) | ||||||
| 			return & Entries[ idx ].Value; | 		return &table.Entries[idx].Value; | ||||||
|  |  | ||||||
| 	return nullptr; | 	return nullptr; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	using MapProc = void (*)( u64 key, Type  value ); | template<typename Type> inline | ||||||
|  | void map(HashTable<Type>& table, void (*map_proc)(u64 key, Type value)) { | ||||||
| 	void map( MapProc map_proc ) |  | ||||||
| 	{ |  | ||||||
| 	GEN_ASSERT_NOT_NULL(map_proc); | 	GEN_ASSERT_NOT_NULL(map_proc); | ||||||
|  |  | ||||||
| 		for ( ssize idx = 0; idx < ssize(Entries.num()); ++idx ) | 	for (ssize idx = 0; idx < ssize(table.Entries.num()); ++idx) { | ||||||
| 		{ | 		map_proc(table.Entries[idx].Key, table.Entries[idx].Value); | ||||||
| 			map_proc( Entries[ idx ].Key, Entries[ idx ].Value ); |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| 	using MapMutProc = void (*)( u64 key, Type* value ); | template<typename Type> inline | ||||||
|  | void map_mut(HashTable<Type>& table, void (*map_proc)(u64 key, Type* value)) { | ||||||
| 	void map_mut( MapMutProc map_proc ) |  | ||||||
| 	{ |  | ||||||
| 	GEN_ASSERT_NOT_NULL(map_proc); | 	GEN_ASSERT_NOT_NULL(map_proc); | ||||||
|  |  | ||||||
| 		for ( ssize idx = 0; idx < ssize(Entries.num()); ++idx ) | 	for (ssize idx = 0; idx < ssize(table.Entries.num()); ++idx) { | ||||||
| 		{ | 		map_proc(table.Entries[idx].Key, &table.Entries[idx].Value); | ||||||
| 			map_proc( Entries[ idx ].Key, & Entries[ idx ].Value ); |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| 	void grow() | template<typename Type> inline | ||||||
| 	{ | void grow(HashTable<Type>& table) { | ||||||
| 		ssize new_num = Array<Entry>::grow_formula( Entries.num() ); | 	ssize new_num = array_grow_formula(num(table.Entries)); | ||||||
| 		rehash( new_num ); | 	rehash(table, new_num); | ||||||
| } | } | ||||||
|  |  | ||||||
| 	void rehash( ssize new_num ) | template<typename Type> inline | ||||||
|  | void rehash(HashTable<Type>& table, ssize new_num) | ||||||
| { | { | ||||||
| 	ssize last_added_index; | 	ssize last_added_index; | ||||||
|  | 	HashTable<Type> new_ht = hashtable_init_reserve<Type>(get_header(table.Hashes)->Allocator, new_num); | ||||||
|  |  | ||||||
| 		HashTable<Type> new_ht = init_reserve( Hashes.get_header()->Allocator, new_num ); | 	for (ssize idx = 0; idx < ssize(num(table.Entries)); ++idx) | ||||||
| 		for ( ssize idx = 0; idx < ssize(Entries.num()); ++idx ) |  | ||||||
| 	{ | 	{ | ||||||
| 			FindResult find_result; | 		HashTableFindResult find_result; | ||||||
|  | 		HashTableEntry<Type>& entry = table.Entries[idx]; | ||||||
|  |  | ||||||
| 			Entry& entry     = Entries[ idx ]; | 		find_result = find(new_ht, entry.Key); | ||||||
| 			find_result      = new_ht.find( entry.Key ); | 		last_added_index = add_entry(new_ht, entry.Key); | ||||||
| 			last_added_index = new_ht.add_entry( entry.Key ); |  | ||||||
|  |  | ||||||
| 		if (find_result.PrevIndex < 0) | 		if (find_result.PrevIndex < 0) | ||||||
| 			new_ht.Hashes[find_result.HashIndex] = last_added_index; | 			new_ht.Hashes[find_result.HashIndex] = last_added_index; | ||||||
| @@ -416,136 +533,149 @@ struct HashTable | |||||||
| 		new_ht.Entries[last_added_index].Value = entry.Value; | 		new_ht.Entries[last_added_index].Value = entry.Value; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 		destroy(); | 	destroy(table); | ||||||
| 		*this = new_ht; | 	table = new_ht; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	void rehash_fast() | template<typename Type> inline | ||||||
|  | void rehash_fast(HashTable<Type>& table) | ||||||
| { | { | ||||||
| 	ssize idx; | 	ssize idx; | ||||||
|  |  | ||||||
| 		for ( idx = 0; idx < ssize(Entries.num()); idx++ ) | 	for (idx = 0; idx < ssize(table.Entries.num()); idx++) | ||||||
| 			Entries[ idx ].Next = -1; | 		table.Entries[idx].Next = -1; | ||||||
|  |  | ||||||
| 		for ( idx = 0; idx < ssize(Hashes.num()); idx++ ) | 	for (idx = 0; idx < ssize(table.Hashes.num()); idx++) | ||||||
| 			Hashes[ idx ] = -1; | 		table.Hashes[idx] = -1; | ||||||
|  |  | ||||||
| 		for ( idx = 0; idx < ssize(Entries.num()); idx++ ) | 	for (idx = 0; idx < ssize(table.Entries.num()); idx++) | ||||||
| 	{ | 	{ | ||||||
| 			Entry*     entry; | 		HashTableEntry<Type>* entry; | ||||||
| 			FindResult find_result; | 		HashTableFindResult find_result; | ||||||
|  |  | ||||||
| 			entry       = & Entries[ idx ]; | 		entry = &table.Entries[idx]; | ||||||
| 			find_result = find( entry->Key ); | 		find_result = find(table, entry->Key); | ||||||
|  |  | ||||||
| 		if (find_result.PrevIndex < 0) | 		if (find_result.PrevIndex < 0) | ||||||
| 				Hashes[ find_result.HashIndex ] = idx; | 			table.Hashes[find_result.HashIndex] = idx; | ||||||
| 		else | 		else | ||||||
| 				Entries[ find_result.PrevIndex ].Next = idx; | 			table.Entries[find_result.PrevIndex].Next = idx; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| 	void remove( u64 key ) | template<typename Type> inline | ||||||
| 	{ | void remove(HashTable<Type>& table, u64 key) { | ||||||
| 		FindResult find_result = find( key); | 	HashTableFindResult find_result = find(table, key); | ||||||
|  |  | ||||||
| 		if ( find_result.EntryIndex >= 0 ) | 	if (find_result.EntryIndex >= 0) { | ||||||
| 		{ | 		table.Entries.remove_at(find_result.EntryIndex); | ||||||
| 			Entries.remove_at( find_result.EntryIndex ); | 		rehash_fast(table); | ||||||
| 			rehash_fast(); |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| 	void remove_entry( ssize idx ) | template<typename Type> inline | ||||||
| 	{ | void remove_entry(HashTable<Type>& table, ssize idx) { | ||||||
| 		Entries.remove_at( idx ); | 	table.Entries.remove_at(idx); | ||||||
| } | } | ||||||
|  |  | ||||||
| 	void set( u64 key, Type value ) | template<typename Type> inline | ||||||
|  | void set(HashTable<Type>& table, u64 key, Type value) | ||||||
| { | { | ||||||
| 	ssize idx; | 	ssize idx; | ||||||
| 		FindResult find_result; | 	HashTableFindResult find_result; | ||||||
|  |  | ||||||
| 		if ( full() ) | 	if (full(table)) | ||||||
| 			grow(); | 		grow(table); | ||||||
|  |  | ||||||
| 		find_result = find( key ); | 	find_result = find(table, key); | ||||||
| 		if ( find_result.EntryIndex >= 0 ) | 	if (find_result.EntryIndex >= 0) { | ||||||
| 		{ |  | ||||||
| 		idx = find_result.EntryIndex; | 		idx = find_result.EntryIndex; | ||||||
| 	} | 	} | ||||||
| 	else | 	else | ||||||
| 	{ | 	{ | ||||||
| 			idx = add_entry( key ); | 		idx = add_entry(table, key); | ||||||
|  |  | ||||||
| 			if ( find_result.PrevIndex >= 0 ) | 		if (find_result.PrevIndex >= 0) { | ||||||
| 			{ | 			table.Entries[find_result.PrevIndex].Next = idx; | ||||||
| 				Entries[ find_result.PrevIndex ].Next = idx; |  | ||||||
| 		} | 		} | ||||||
| 			else | 		else { | ||||||
| 			{ | 			table.Hashes[find_result.HashIndex] = idx; | ||||||
| 				Hashes[ find_result.HashIndex ] = idx; |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 		Entries[ idx ].Value = value; | 	table.Entries[idx].Value = value; | ||||||
|  |  | ||||||
| 		if ( full() ) | 	if (full(table)) | ||||||
| 			grow(); | 		grow(table); | ||||||
| } | } | ||||||
|  |  | ||||||
| 	ssize slot( u64 key ) | template<typename Type> inline | ||||||
| 	{ | ssize slot(HashTable<Type>& table, u64 key) { | ||||||
| 		for ( ssize idx = 0; idx < ssize(Hashes.num()); ++idx ) | 	for (ssize idx = 0; idx < ssize(table.Hashes.num()); ++idx) | ||||||
| 			if ( Hashes[ idx ] == key ) | 		if (table.Hashes[idx] == key) | ||||||
| 			return idx; | 			return idx; | ||||||
|  |  | ||||||
| 	return -1; | 	return -1; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	Array< ssize>    Hashes; | template<typename Type> inline | ||||||
| 	Array< Entry> Entries; | ssize add_entry(HashTable<Type>& table, u64 key) { | ||||||
|  |  | ||||||
| protected: |  | ||||||
|  |  | ||||||
| 	ssize add_entry( u64 key ) |  | ||||||
| 	{ |  | ||||||
| 	ssize idx; | 	ssize idx; | ||||||
| 		Entry entry = { key, -1 }; | 	HashTableEntry<Type> entry = { key, -1 }; | ||||||
|  |  | ||||||
| 		idx = Entries.num(); | 	idx = num(table.Entries); | ||||||
| 		Entries.append( entry ); | 	append(table.Entries, entry); | ||||||
| 	return idx; | 	return idx; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	FindResult find( u64 key ) | template<typename Type> inline | ||||||
|  | HashTableFindResult find(HashTable<Type>& table, u64 key) | ||||||
| { | { | ||||||
| 		FindResult result = { -1, -1, -1 }; | 	HashTableFindResult result = { -1, -1, -1 }; | ||||||
|  |  | ||||||
| 		if ( Hashes.num() > 0 ) | 	if (num(table.Hashes) > 0) | ||||||
| 	{ | 	{ | ||||||
| 			result.HashIndex    = key % Hashes.num(); | 		result.HashIndex = key % num(table.Hashes); | ||||||
| 			result.EntryIndex  = Hashes[ result.HashIndex ]; | 		result.EntryIndex = table.Hashes[result.HashIndex]; | ||||||
|  |  | ||||||
| 		while (result.EntryIndex >= 0) | 		while (result.EntryIndex >= 0) | ||||||
| 		{ | 		{ | ||||||
| 				if ( Entries[ result.EntryIndex ].Key == key ) | 			if (table.Entries[result.EntryIndex].Key == key) | ||||||
| 				break; | 				break; | ||||||
|  |  | ||||||
| 			result.PrevIndex = result.EntryIndex; | 			result.PrevIndex = result.EntryIndex; | ||||||
| 				result.EntryIndex = Entries[ result.EntryIndex ].Next; | 			result.EntryIndex = table.Entries[result.EntryIndex].Next; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return result; | 	return result; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	b32 full() | template<typename Type> inline | ||||||
| 	{ | bool full(HashTable<Type>& table) { | ||||||
| 		usize critical_load = usize( CriticalLoadScale * f32(Hashes.num()) ); | 	usize critical_load = usize(HashTable_CriticalLoadScale * f32(num(table.Hashes))); | ||||||
| 		b32 result = Entries.num() > critical_load; | 	b32 result = num(table.Entries) > critical_load; | ||||||
| 	return result; | 	return result; | ||||||
| } | } | ||||||
| }; |  | ||||||
|  | #define hashtable_init(Type, allocator)               hashtable_init<Type>(allocator) | ||||||
|  | #define hashtable_init_reserve(Type, allocator, num)  hashtable_init_reserve<Type>(allocator, num) | ||||||
|  | #define hashtable_clear(Type, table)                  clear<Type>(table) | ||||||
|  | #define hashtable_destroy(Type, table)                destroy<Type>(table) | ||||||
|  | #define hashtable_get(Type, table, key)               get<Type>(table, key) | ||||||
|  | #define hashtable_grow(Type, table)                   grow<Type>(table) | ||||||
|  | #define hashtable_rehash(Type, table, new_num)        rehash<Type>(table, new_num) | ||||||
|  | #define hashtable_rehash_fast(Type, table)            rehash_fast<Type>(table) | ||||||
|  | #define hashtable_remove(Type, table, key)            remove<Type>(table, key) | ||||||
|  | #define hashtable_remove_entry(Type, table, idx)      remove_entry<Type>(table, idx) | ||||||
|  | #define hashtable_set(Type, table, key, value)        set<Type>(table, key, value) | ||||||
|  | #define hashtable_slot(Type, table, key)              slot<Type>(table, key) | ||||||
|  | #define hashtable_add_entry(Type, table, key)         add_entry<Type>(table, key) | ||||||
|  | #define hashtable_find(Type, table, key)              find<Type>(table, key) | ||||||
|  | #define hashtable_full(Type, table)                   full<Type>(table) | ||||||
|  | #define hashtable_map(Type, table, map_proc)          map<Type>(table, map_proc) | ||||||
|  | #define hashtable_map_mut(Type, table, map_proc)      map_mut<Type>(table, map_proc) | ||||||
|  |  | ||||||
|  | #pragma endregion HashTable | ||||||
|  |  | ||||||
| #pragma endregion Containers | #pragma endregion Containers | ||||||
|   | |||||||
| @@ -505,7 +505,7 @@ b8 file_stream_new( FileInfo* file, AllocatorInfo allocator ) | |||||||
| 	d->allocator = allocator; | 	d->allocator = allocator; | ||||||
| 	d->flags     = EFileStream_CLONE_WRITABLE; | 	d->flags     = EFileStream_CLONE_WRITABLE; | ||||||
| 	d->cap       = 0; | 	d->cap       = 0; | ||||||
| 	d->buf       = Array<u8>::init( allocator ); | 	d->buf       = array_init<u8>( allocator ); | ||||||
|  |  | ||||||
| 	if ( ! d->buf ) | 	if ( ! d->buf ) | ||||||
| 		return false; | 		return false; | ||||||
| @@ -531,7 +531,7 @@ b8 file_stream_open( FileInfo* file, AllocatorInfo allocator, u8* buffer, ssize | |||||||
| 	d->flags     = flags; | 	d->flags     = flags; | ||||||
| 	if ( d->flags & EFileStream_CLONE_WRITABLE ) | 	if ( d->flags & EFileStream_CLONE_WRITABLE ) | ||||||
| 	{ | 	{ | ||||||
| 		Array<u8> arr = Array<u8>::init_reserve( allocator, size ); | 		Array<u8> arr = array_init_reserve<u8>( allocator, size ); | ||||||
| 		d->buf = arr; | 		d->buf = arr; | ||||||
|  |  | ||||||
| 		if ( ! d->buf ) | 		if ( ! d->buf ) | ||||||
| @@ -540,7 +540,7 @@ b8 file_stream_open( FileInfo* file, AllocatorInfo allocator, u8* buffer, ssize | |||||||
| 		mem_copy( d->buf, buffer, size ); | 		mem_copy( d->buf, buffer, size ); | ||||||
| 		d->cap = size; | 		d->cap = size; | ||||||
|  |  | ||||||
| 		arr.get_header()->Num = size; | 		get_header(arr)->Num = size; | ||||||
| 	} | 	} | ||||||
| 	else | 	else | ||||||
| 	{ | 	{ | ||||||
| @@ -610,9 +610,9 @@ GEN_FILE_WRITE_AT_PROC( _memory_file_write ) | |||||||
| 	{ | 	{ | ||||||
| 		Array<u8> arr = { d->buf }; | 		Array<u8> arr = { d->buf }; | ||||||
|  |  | ||||||
| 		if ( arr.get_header()->Capacity < usize(new_cap) ) | 		if ( get_header(arr)->Capacity < usize(new_cap) ) | ||||||
| 		{ | 		{ | ||||||
| 			if ( ! arr.grow( ( s64 )( new_cap ) ) ) | 			if ( ! grow( arr, ( s64 )( new_cap ) ) ) | ||||||
| 				return false; | 				return false; | ||||||
| 			d->buf = arr; | 			d->buf = arr; | ||||||
| 		} | 		} | ||||||
| @@ -626,7 +626,7 @@ GEN_FILE_WRITE_AT_PROC( _memory_file_write ) | |||||||
|  |  | ||||||
| 		mem_copy( d->buf + offset + rwlen, pointer_add_const( buffer, rwlen ), extralen ); | 		mem_copy( d->buf + offset + rwlen, pointer_add_const( buffer, rwlen ), extralen ); | ||||||
| 		d->cap = new_cap; | 		d->cap = new_cap; | ||||||
| 		arr.get_header()->Capacity = new_cap; | 		get_header(arr)->Capacity = new_cap; | ||||||
| 	} | 	} | ||||||
| 	else | 	else | ||||||
| 	{ | 	{ | ||||||
| @@ -647,7 +647,7 @@ GEN_FILE_CLOSE_PROC( _memory_file_close ) | |||||||
| 	if ( d->flags & EFileStream_CLONE_WRITABLE ) | 	if ( d->flags & EFileStream_CLONE_WRITABLE ) | ||||||
| 	{ | 	{ | ||||||
| 		Array<u8> arr = { d->buf }; | 		Array<u8> arr = { d->buf }; | ||||||
| 		arr.free(); | 		free(arr); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	free( allocator, d ); | 	free( allocator, d ); | ||||||
|   | |||||||
| @@ -23,6 +23,7 @@ | |||||||
| #define bitfield_is_equal( Type, Field, Mask ) ( (Type(Mask) & Type(Field)) == Type(Mask) ) | #define bitfield_is_equal( Type, Field, Mask ) ( (Type(Mask) & Type(Field)) == Type(Mask) ) | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #if ! GEN_C_COMPILER | ||||||
| #	ifndef ccast | #	ifndef ccast | ||||||
| #	define ccast( type, value ) ( const_cast< type >( (value) ) ) | #	define ccast( type, value ) ( const_cast< type >( (value) ) ) | ||||||
| #	endif | #	endif | ||||||
| @@ -35,6 +36,20 @@ | |||||||
| #	ifndef scast | #	ifndef scast | ||||||
| #	define scast( type, value ) static_cast< type >( value ) | #	define scast( type, value ) static_cast< type >( value ) | ||||||
| #	endif | #	endif | ||||||
|  | #else | ||||||
|  | #	ifndef ccast | ||||||
|  | #	define ccast( type, value ) ( (type)(value) ) | ||||||
|  | #	endif | ||||||
|  | #	ifndef pcast | ||||||
|  | #	define pcast( type, value ) ( (type)(value) ) | ||||||
|  | #	endif | ||||||
|  | #	ifndef rcast | ||||||
|  | #	define rcast( type, value ) ( (type)(value) ) | ||||||
|  | #	endif | ||||||
|  | #	ifndef scast | ||||||
|  | #	define scast( type, value ) ( (type)(value) ) | ||||||
|  | #	endif | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #ifndef stringize | #ifndef stringize | ||||||
| #define stringize_va( ... ) #__VA_ARGS__ | #define stringize_va( ... ) #__VA_ARGS__ | ||||||
| @@ -123,20 +138,20 @@ | |||||||
| #define min( a, b ) ( (a < b) ? (a) : (b) ) | #define min( a, b ) ( (a < b) ? (a) : (b) ) | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #if defined( _MSC_VER ) || defined( GEN_COMPILER_TINYC ) | #if GEN_COMPILER_MSVC || GEN_COMPILER_TINYC | ||||||
| #	define offset_of( Type, element ) ( ( GEN_NS( ssize ) ) & ( ( ( Type* )0 )->element ) ) | #	define offset_of( Type, element ) ( ( GEN_NS( ssize ) ) & ( ( ( Type* )0 )->element ) ) | ||||||
| #else | #else | ||||||
| #	define offset_of( Type, element ) __builtin_offsetof( Type, element ) | #	define offset_of( Type, element ) __builtin_offsetof( Type, element ) | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #ifndef        forceinline | #ifndef        forceinline | ||||||
| #	ifdef GEN_COMPILER_MSVC | #	if GEN_COMPILER_MSVC | ||||||
| #		define forceinline __forceinline | #		define forceinline __forceinline | ||||||
| #		define neverinline __declspec( noinline ) | #		define neverinline __declspec( noinline ) | ||||||
| #	elif defined(GEN_COMPILER_GCC) | #	elif GEN_COMPILER_GCC | ||||||
| #		define forceinline inline __attribute__((__always_inline__)) | #		define forceinline inline __attribute__((__always_inline__)) | ||||||
| #		define neverinline __attribute__( ( __noinline__ ) ) | #		define neverinline __attribute__( ( __noinline__ ) ) | ||||||
| #	elif defined(GEN_COMPILER_CLANG) | #	elif GEN_COMPILER_CLANG | ||||||
| #	if __has_attribute(__always_inline__) | #	if __has_attribute(__always_inline__) | ||||||
| #		define forceinline inline __attribute__((__always_inline__)) | #		define forceinline inline __attribute__((__always_inline__)) | ||||||
| #		define neverinline __attribute__( ( __noinline__ ) ) | #		define neverinline __attribute__( ( __noinline__ ) ) | ||||||
| @@ -151,11 +166,11 @@ | |||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #ifndef        neverinline | #ifndef        neverinline | ||||||
| #	ifdef GEN_COMPILER_MSVC | #	if GEN_COMPILER_MSVC | ||||||
| #		define neverinline __declspec( noinline ) | #		define neverinline __declspec( noinline ) | ||||||
| #	elif defined(GEN_COMPILER_GCC) | #	elif GEN_COMPILER_GCC | ||||||
| #		define neverinline __attribute__( ( __noinline__ ) ) | #		define neverinline __attribute__( ( __noinline__ ) ) | ||||||
| #	elif defined(GEN_COMPILER_CLANG) | #	elif GEN_COMPILER_CLANG | ||||||
| #	if __has_attribute(__always_inline__) | #	if __has_attribute(__always_inline__) | ||||||
| #		define neverinline __attribute__( ( __noinline__ ) ) | #		define neverinline __attribute__( ( __noinline__ ) ) | ||||||
| #	else | #	else | ||||||
| @@ -166,4 +181,38 @@ | |||||||
| #	endif | #	endif | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #if !defined(GEN_SUPPORT_CPP_MEMBER_FEATURES) && (!GEN_COMPILER_C || __STDC_VERSION__ < 202311L) | ||||||
|  | #	define GEN_SUPPORT_CPP_MEMBER_FEATURES 0 | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if !defined(typeof) && (!GEN_COMPILER_C || __STDC_VERSION__ < 202311L) | ||||||
|  | #	if ! GEN_COMPILER_C | ||||||
|  | #		define typeof decltype | ||||||
|  | #	elif defined(_MSC_VER) | ||||||
|  | #		define typeof(x) __typeof(x) | ||||||
|  | #	elif defined(__GNUC__) || defined(__clang__) | ||||||
|  | #		define typeof(x) __typeof__(x) | ||||||
|  | #	else | ||||||
|  | #		error "Compiler not supported" | ||||||
|  | #	endif | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | // This is intended to only really be used internally or with the C-library variant | ||||||
|  | // C++ users can just use the for-range directly. | ||||||
|  | #if GEN_COMPILER_C | ||||||
|  | #	define foreach(Type, entry_id, iterable) for ( Type entry_id = begin(iterable); entry_id != end(iterable); entry_id = next(iterable, entry_id) ) | ||||||
|  | #else | ||||||
|  | #	define foreach(Type, entry_id, iterable) for ( Type entry_id : iterable ) | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if GENC_COMPILERC | ||||||
|  | #	if __STDC_VERSION__ >= 202311L | ||||||
|  | #		define enum_underlying(type) : type | ||||||
|  | #	else | ||||||
|  | #		define enum_underlying(type) | ||||||
|  | #   endif | ||||||
|  | #else | ||||||
|  | #	define enum_underlying(type) : type | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #pragma endregion Macros | #pragma endregion Macros | ||||||
|   | |||||||
| @@ -334,7 +334,7 @@ ssize virtual_memory_page_size( ssize* alignment_out ) | |||||||
|  |  | ||||||
| #pragma endregion VirtualMemory | #pragma endregion VirtualMemory | ||||||
|  |  | ||||||
| void* Arena::allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ) | void* arena_allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ) | ||||||
| { | { | ||||||
| 	Arena* arena = rcast(Arena*, allocator_data); | 	Arena* arena = rcast(Arena*, allocator_data); | ||||||
| 	void*      ptr   = NULL; | 	void*      ptr   = NULL; | ||||||
| @@ -384,7 +384,7 @@ void* Arena::allocator_proc( void* allocator_data, AllocType type, ssize size, s | |||||||
| 	return ptr; | 	return ptr; | ||||||
| } | } | ||||||
|  |  | ||||||
| void* Pool::allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ) | void* pool_allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ) | ||||||
| { | { | ||||||
| 	Pool* pool = rcast( Pool*, allocator_data); | 	Pool* pool = rcast( Pool*, allocator_data); | ||||||
| 	void* ptr  = NULL; | 	void* ptr  = NULL; | ||||||
| @@ -457,7 +457,7 @@ void* Pool::allocator_proc( void* allocator_data, AllocType type, ssize size, ss | |||||||
| 	return ptr; | 	return ptr; | ||||||
| } | } | ||||||
|  |  | ||||||
| Pool Pool::init_align( AllocatorInfo backing, ssize num_blocks, ssize block_size, ssize block_align ) | Pool pool_init_align( AllocatorInfo backing, ssize num_blocks, ssize block_size, ssize block_align ) | ||||||
| { | { | ||||||
| 	Pool pool = {}; | 	Pool pool = {}; | ||||||
|  |  | ||||||
| @@ -495,16 +495,16 @@ Pool Pool::init_align( AllocatorInfo backing, ssize num_blocks, ssize block_size | |||||||
| 	return pool; | 	return pool; | ||||||
| } | } | ||||||
|  |  | ||||||
| void Pool::clear() | void clear(Pool& pool) | ||||||
| { | { | ||||||
| 	ssize actual_block_size, block_index; | 	ssize actual_block_size, block_index; | ||||||
| 	void* curr; | 	void* curr; | ||||||
| 	uptr* end; | 	uptr* end; | ||||||
|  |  | ||||||
| 	actual_block_size = BlockSize + BlockAlign; | 	actual_block_size = pool.BlockSize + pool.BlockAlign; | ||||||
|  |  | ||||||
| 	curr = PhysicalStart; | 	curr = pool.PhysicalStart; | ||||||
| 	for ( block_index = 0; block_index < NumBlocks - 1; block_index++ ) | 	for ( block_index = 0; block_index < pool.NumBlocks - 1; block_index++ ) | ||||||
| 	{ | 	{ | ||||||
| 		uptr* next = ( uptr* ) curr; | 		uptr* next = ( uptr* ) curr; | ||||||
| 		*next      = ( uptr  ) curr + actual_block_size; | 		*next      = ( uptr  ) curr + actual_block_size; | ||||||
| @@ -514,7 +514,7 @@ void Pool::clear() | |||||||
| 	end  =  ( uptr* ) curr; | 	end  =  ( uptr* ) curr; | ||||||
| 	*end =  ( uptr )  NULL; | 	*end =  ( uptr )  NULL; | ||||||
|  |  | ||||||
| 	FreeList = PhysicalStart; | 	pool.FreeList = pool.PhysicalStart; | ||||||
| } | } | ||||||
|  |  | ||||||
| #pragma endregion Memory | #pragma endregion Memory | ||||||
|   | |||||||
| @@ -14,6 +14,7 @@ | |||||||
| #define GEN__HIGHS         ( GEN__ONES * ( GEN_U8_MAX / 2 + 1 ) ) | #define GEN__HIGHS         ( GEN__ONES * ( GEN_U8_MAX / 2 + 1 ) ) | ||||||
| #define GEN__HAS_ZERO( x ) ( ( ( x ) - GEN__ONES ) & ~( x ) & GEN__HIGHS ) | #define GEN__HAS_ZERO( x ) ( ( ( x ) - GEN__ONES ) & ~( x ) & GEN__HIGHS ) | ||||||
|  |  | ||||||
|  | #if ! GEN_COMPILER_C | ||||||
| 	template< class Type > | 	template< class Type > | ||||||
| 	void swap( Type& a, Type& b ) | 	void swap( Type& a, Type& b ) | ||||||
| 	{ | 	{ | ||||||
| @@ -21,6 +22,15 @@ void swap( Type& a, Type& b ) | |||||||
| 		a = b; | 		a = b; | ||||||
| 		b = tmp; | 		b = tmp; | ||||||
| 	} | 	} | ||||||
|  | #else | ||||||
|  | 	#define swap( a, b ) \ | ||||||
|  | 	do {                 \ | ||||||
|  | 		typeof(a)        \ | ||||||
|  | 		temp = (a);      \ | ||||||
|  | 		(a)  = (b);      \ | ||||||
|  | 		(b)  = temp;     \ | ||||||
|  | 	} while(0) | ||||||
|  | #endif | ||||||
|  |  | ||||||
| //! Checks if value is power of 2. | //! Checks if value is power of 2. | ||||||
| b32 is_power_of_two( ssize x ); | b32 is_power_of_two( ssize x ); | ||||||
| @@ -70,10 +80,7 @@ enum AllocType : u8 | |||||||
| 	EAllocation_RESIZE, | 	EAllocation_RESIZE, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| using AllocatorProc = void* ( void* allocator_data, AllocType type | typedef void*(AllocatorProc)( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ); | ||||||
| 	, ssize size, ssize alignment |  | ||||||
| 	, void* old_memory, ssize old_size |  | ||||||
| 	, u64 flags ); |  | ||||||
|  |  | ||||||
| struct AllocatorInfo | struct AllocatorInfo | ||||||
| { | { | ||||||
| @@ -170,29 +177,80 @@ b32 gen_vm_purge( VirtualMemory vm ); | |||||||
| //! Retrieve VM's page size and alignment. | //! Retrieve VM's page size and alignment. | ||||||
| ssize gen_virtual_memory_page_size( ssize* alignment_out ); | ssize gen_virtual_memory_page_size( ssize* alignment_out ); | ||||||
|  |  | ||||||
|  | #pragma region Arena | ||||||
|  | struct Arena; | ||||||
|  |  | ||||||
|  | AllocatorInfo allocator_info( Arena& arena ); | ||||||
|  |  | ||||||
|  | // Remove static keyword and rename allocator_proc | ||||||
|  | void* arena_allocator_proc(void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags); | ||||||
|  |  | ||||||
|  | // Add these declarations after the Arena struct | ||||||
|  | Arena arena_init_from_allocator(AllocatorInfo backing, ssize size); | ||||||
|  | Arena arena_init_from_memory( void* start, ssize size ); | ||||||
|  | Arena init_sub(Arena& parent, ssize size); | ||||||
|  | ssize alignment_of(Arena& arena, ssize alignment); | ||||||
|  |  | ||||||
|  | // This id is defined by Unreal for asserts | ||||||
|  | #pragma push_macro("check") | ||||||
|  | #undef check | ||||||
|  | void   check(Arena& arena); | ||||||
|  | #pragma pop_macro("check") | ||||||
|  |  | ||||||
|  | void  free(Arena& arena); | ||||||
|  | ssize size_remaining(Arena& arena, ssize alignment); | ||||||
|  |  | ||||||
| struct Arena | struct Arena | ||||||
| { | { | ||||||
| 	static | 	AllocatorInfo Backing; | ||||||
| 	void* allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ); | 	void*         PhysicalStart; | ||||||
|  | 	ssize         TotalSize; | ||||||
|  | 	ssize         TotalUsed; | ||||||
|  | 	ssize         TempCount; | ||||||
|  |  | ||||||
| 	static | #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||||
| 	Arena init_from_memory( void* start, ssize size ) | #pragma region Member Mapping | ||||||
| 	{ | 	forceinline operator AllocatorInfo() { return GEN_NS allocator_info(* this); } | ||||||
| 		return |  | ||||||
|  | 	forceinline static void* allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ) { return GEN_NS arena_allocator_proc( allocator_data, type, size, alignment, old_memory, old_size, flags ); } | ||||||
|  | 	forceinline static Arena init_from_memory( void* start, ssize size )                                                                                      { return GEN_NS arena_init_from_memory( start, size ); } | ||||||
|  | 	forceinline static Arena init_from_allocator( AllocatorInfo backing, ssize size )                                                                         { return GEN_NS arena_init_from_allocator( backing, size ); } | ||||||
|  | 	forceinline static Arena init_sub( Arena& parent, ssize size )                                                                                            { return GEN_NS arena_init_from_allocator( parent.Backing, size ); } | ||||||
|  | 	forceinline        ssize alignment_of( ssize alignment )                                                                                                  { return GEN_NS alignment_of(* this, alignment); } | ||||||
|  | 	forceinline        void  free()                                                                                                                           { return GEN_NS free(* this);  } | ||||||
|  | 	forceinline        ssize size_remaining( ssize alignment )                                                                                                { return GEN_NS size_remaining(* this, alignment); } | ||||||
|  |  | ||||||
|  | // This id is defined by Unreal for asserts | ||||||
|  | #pragma push_macro("check") | ||||||
|  | #undef check | ||||||
|  | 	forceinline void check() { GEN_NS check(* this); } | ||||||
|  | #pragma pop_macro("check") | ||||||
|  |  | ||||||
|  | #pragma endregion Member Mapping | ||||||
|  | #endif | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | inline | ||||||
|  | AllocatorInfo allocator_info( Arena& arena ) { | ||||||
|  | 	return { arena_allocator_proc, &arena }; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline | ||||||
|  | Arena arena_init_from_memory( void* start, ssize size ) | ||||||
| { | { | ||||||
|  | 	Arena arena = { | ||||||
| 		{ nullptr, nullptr }, | 		{ nullptr, nullptr }, | ||||||
| 		start, | 		start, | ||||||
| 		size, | 		size, | ||||||
| 		0, | 		0, | ||||||
| 		0 | 		0 | ||||||
| 	}; | 	}; | ||||||
|  | 	return arena; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	static | inline | ||||||
| 	Arena init_from_allocator( AllocatorInfo backing, ssize size ) | Arena arena_init_from_allocator(AllocatorInfo backing, ssize size) { | ||||||
| 	{ | 	Arena result = { | ||||||
| 		Arena result = |  | ||||||
| 		{ |  | ||||||
| 		backing, | 		backing, | ||||||
| 		alloc(backing, size), | 		alloc(backing, size), | ||||||
| 		size, | 		size, | ||||||
| @@ -202,19 +260,19 @@ struct Arena | |||||||
| 	return result; | 	return result; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	static | inline | ||||||
| 	Arena init_sub( Arena& parent, ssize size ) | Arena init_sub(Arena& parent, ssize size) { | ||||||
| 	{ | 	return arena_init_from_allocator(parent.Backing, size); | ||||||
| 		return init_from_allocator( parent.Backing, size ); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| 	ssize alignment_of( ssize alignment ) | inline | ||||||
|  | ssize alignment_of(Arena& arena, ssize alignment) | ||||||
| { | { | ||||||
| 	ssize alignment_offset, result_pointer, mask; | 	ssize alignment_offset, result_pointer, mask; | ||||||
| 	GEN_ASSERT(is_power_of_two(alignment)); | 	GEN_ASSERT(is_power_of_two(alignment)); | ||||||
|  |  | ||||||
| 	alignment_offset = 0; | 	alignment_offset = 0; | ||||||
| 		result_pointer   = (ssize) PhysicalStart + TotalUsed; | 	result_pointer  = (ssize)arena.PhysicalStart + arena.TotalUsed; | ||||||
| 	mask            = alignment - 1; | 	mask            = alignment - 1; | ||||||
|  |  | ||||||
| 	if (result_pointer & mask) | 	if (result_pointer & mask) | ||||||
| @@ -223,68 +281,73 @@ struct Arena | |||||||
| 	return alignment_offset; | 	return alignment_offset; | ||||||
| } | } | ||||||
|  |  | ||||||
| // This id is defined by Unreal for asserts |  | ||||||
| #pragma push_macro("check") | #pragma push_macro("check") | ||||||
| #undef check | #undef check | ||||||
| 	void check() | inline | ||||||
|  | void check(Arena& arena) | ||||||
| { | { | ||||||
| 		GEN_ASSERT( TempCount == 0 ); |     GEN_ASSERT(arena.TempCount == 0); | ||||||
| } | } | ||||||
| #pragma pop_macro("check") | #pragma pop_macro("check") | ||||||
|  |  | ||||||
| 	void free() | inline | ||||||
|  | void free(Arena& arena) | ||||||
| { | { | ||||||
| 		if ( Backing.Proc ) | 	if (arena.Backing.Proc) | ||||||
| 	{ | 	{ | ||||||
| 			gen::free( Backing, PhysicalStart ); | 		GEN_NS free(arena.Backing, arena.PhysicalStart); | ||||||
| 			PhysicalStart = nullptr; | 		arena.PhysicalStart = nullptr; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| 	ssize size_remaining( ssize alignment ) | inline | ||||||
|  | ssize size_remaining(Arena& arena, ssize alignment) | ||||||
| { | { | ||||||
| 		ssize result = TotalSize - ( TotalUsed + alignment_of( alignment ) ); | 	ssize result = arena.TotalSize - (arena.TotalUsed + alignment_of(arena, alignment)); | ||||||
| 	return result; | 	return result; | ||||||
| } | } | ||||||
|  | #pragma endregion Arena | ||||||
|  |  | ||||||
| 	AllocatorInfo Backing; | #pragma region FixedArena | ||||||
| 	void*         PhysicalStart; | template<s32 Size> | ||||||
| 	ssize            TotalSize; | struct FixedArena; | ||||||
| 	ssize            TotalUsed; |  | ||||||
| 	ssize            TempCount; |  | ||||||
|  |  | ||||||
| 	operator AllocatorInfo() | template<s32 Size> AllocatorInfo    allocator_info( FixedArena<Size>& fixed_arena ); | ||||||
| 	{ | template<s32 Size> FixedArena<Size> fixed_arena_init(); | ||||||
| 		return { allocator_proc, this }; | template<s32 Size> ssize            size_remaining(FixedArena<Size>& fixed_arena, ssize alignment); | ||||||
| 	} |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| // Just a wrapper around using an arena with memory associated with its scope instead of from an allocator. | // Just a wrapper around using an arena with memory associated with its scope instead of from an allocator. | ||||||
| // Used for static segment or stack allocations. | // Used for static segment or stack allocations. | ||||||
| template< s32 Size > | template< s32 Size > | ||||||
| struct FixedArena | struct FixedArena | ||||||
| { | { | ||||||
| 	static |  | ||||||
| 	FixedArena init() |  | ||||||
| 	{ |  | ||||||
| 		FixedArena result = { Arena::init_from_memory( result.memory, Size ), {0} }; |  | ||||||
| 		return result; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	ssize size_remaining( ssize alignment ) |  | ||||||
| 	{ |  | ||||||
| 		return arena.size_remaining( alignment ); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	operator AllocatorInfo() |  | ||||||
| 	{ |  | ||||||
| 		return { Arena::allocator_proc, &arena }; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	Arena arena; |  | ||||||
| 	char  memory[Size]; | 	char  memory[Size]; | ||||||
|  | 	Arena arena; | ||||||
|  |  | ||||||
|  | #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||||
|  | #pragma region Member Mapping | ||||||
|  | 	forceinline operator AllocatorInfo() { return GEN_NS allocator_info(* this); } | ||||||
|  |  | ||||||
|  | 	forceinline static FixedArena init()                          { FixedArena result; GEN_NS fixed_arena_init<Size>(result); return result; } | ||||||
|  | 	forceinline ssize             size_remaining(ssize alignment) { GEN_NS size_remaining(*this, alignment); } | ||||||
|  | #pragma endregion Member Mapping | ||||||
|  | #endif | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | template<s32 Size> inline | ||||||
|  | AllocatorInfo allocator_info( FixedArena<Size>& fixed_arena ) { return { arena_allocator_proc, & fixed_arena.arena }; } | ||||||
|  |  | ||||||
|  | template<s32 Size> inline | ||||||
|  | void fixed_arena_init(FixedArena<Size>& result) { | ||||||
|  |     zero_size(& result.memory[0], Size); | ||||||
|  |     result.arena = arena_init_from_memory(& result.memory[0], Size); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<s32 Size> inline | ||||||
|  | ssize size_remaining(FixedArena<Size>& fixed_arena, ssize alignment) { | ||||||
|  |     return size_remaining(fixed_arena.arena, alignment); | ||||||
|  | } | ||||||
|  |  | ||||||
| using Arena_1KB   = FixedArena< kilobytes( 1 ) >; | using Arena_1KB   = FixedArena< kilobytes( 1 ) >; | ||||||
| using Arena_4KB   = FixedArena< kilobytes( 4 ) >; | using Arena_4KB   = FixedArena< kilobytes( 4 ) >; | ||||||
| using Arena_8KB   = FixedArena< kilobytes( 8 ) >; | using Arena_8KB   = FixedArena< kilobytes( 8 ) >; | ||||||
| @@ -297,31 +360,20 @@ using Arena_512KB = FixedArena< kilobytes( 512 ) >; | |||||||
| using Arena_1MB   = FixedArena< megabytes( 1 ) >; | using Arena_1MB   = FixedArena< megabytes( 1 ) >; | ||||||
| using Arena_2MB   = FixedArena< megabytes( 2 ) >; | using Arena_2MB   = FixedArena< megabytes( 2 ) >; | ||||||
| using Arena_4MB   = FixedArena< megabytes( 4 ) >; | using Arena_4MB   = FixedArena< megabytes( 4 ) >; | ||||||
|  | #pragma endregion FixedArena | ||||||
|  |  | ||||||
|  | #pragma region Pool | ||||||
|  | struct Pool; | ||||||
|  |  | ||||||
|  | AllocatorInfo allocator_info(Pool& pool); | ||||||
|  | void*         pool_allocator_proc(void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags); | ||||||
|  | Pool          pool_init(AllocatorInfo backing, ssize num_blocks, ssize block_size); | ||||||
|  | Pool          pool_init_align(AllocatorInfo backing, ssize num_blocks, ssize block_size, ssize block_align); | ||||||
|  | void          clear(Pool& pool); | ||||||
|  | void          free(Pool& pool); | ||||||
|  |  | ||||||
| struct Pool | struct Pool | ||||||
| { | { | ||||||
| 	static |  | ||||||
| 	void* allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ); |  | ||||||
|  |  | ||||||
| 	static |  | ||||||
| 	Pool init( AllocatorInfo backing, ssize num_blocks, ssize block_size ) |  | ||||||
| 	{ |  | ||||||
| 		return init_align( backing, num_blocks, block_size, GEN_DEFAULT_MEMORY_ALIGNMENT ); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	static |  | ||||||
| 	Pool init_align( AllocatorInfo backing, ssize num_blocks, ssize block_size, ssize block_align ); |  | ||||||
|  |  | ||||||
| 	void clear(); |  | ||||||
|  |  | ||||||
| 	void free() |  | ||||||
| 	{ |  | ||||||
| 		if ( Backing.Proc ) |  | ||||||
| 		{ |  | ||||||
| 			gen::free( Backing, PhysicalStart ); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	AllocatorInfo Backing; | 	AllocatorInfo Backing; | ||||||
| 	void*         PhysicalStart; | 	void*         PhysicalStart; | ||||||
| 	void*         FreeList; | 	void*         FreeList; | ||||||
| @@ -330,12 +382,36 @@ struct Pool | |||||||
| 	ssize         TotalSize; | 	ssize         TotalSize; | ||||||
| 	ssize         NumBlocks; | 	ssize         NumBlocks; | ||||||
|  |  | ||||||
| 	operator AllocatorInfo() | #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||||
| 	{ | #pragma region Member Mapping | ||||||
| 		return { allocator_proc, this }; |     forceinline operator AllocatorInfo() { return GEN_NS allocator_info(* this); } | ||||||
| 	} |  | ||||||
|  |     forceinline static void* allocator_proc(void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags) { return GEN_NS pool_allocator_proc(allocator_data, type, size, alignment, old_memory, old_size, flags); } | ||||||
|  |     forceinline static Pool  init(AllocatorInfo backing, ssize num_blocks, ssize block_size)                                                                { return GEN_NS pool_init(backing, num_blocks, block_size); } | ||||||
|  |     forceinline static Pool  init_align(AllocatorInfo backing, ssize num_blocks, ssize block_size, ssize block_align)                                       { return GEN_NS pool_init_align(backing, num_blocks, block_size, block_align); } | ||||||
|  |     forceinline        void  clear() { GEN_NS clear(* this); } | ||||||
|  |     forceinline        void  free()  { GEN_NS free(* this); } | ||||||
|  | #pragma endregion | ||||||
|  | #endif | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | inline | ||||||
|  | AllocatorInfo allocator_info(Pool& pool) { | ||||||
|  |    return { pool_allocator_proc, &pool }; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline | ||||||
|  | Pool pool_init(AllocatorInfo backing, ssize num_blocks, ssize block_size) { | ||||||
|  |    return pool_init_align(backing, num_blocks, block_size, GEN_DEFAULT_MEMORY_ALIGNMENT); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline | ||||||
|  | void free(Pool& pool) { | ||||||
|  |    if(pool.Backing.Proc) { | ||||||
|  |        GEN_NS free(pool.Backing, pool.PhysicalStart); | ||||||
|  |    } | ||||||
|  | } | ||||||
|  | #pragma endregion Pool | ||||||
|  |  | ||||||
| inline | inline | ||||||
| b32 is_power_of_two( ssize x ) { | b32 is_power_of_two( ssize x ) { | ||||||
|   | |||||||
| @@ -23,7 +23,7 @@ u8 adt_make_branch( ADT_Node* node, AllocatorInfo backing, char const* name, b32 | |||||||
| 	node->type   = type; | 	node->type   = type; | ||||||
| 	node->name   = name; | 	node->name   = name; | ||||||
| 	node->parent = parent; | 	node->parent = parent; | ||||||
| 	node->nodes  = Array<ADT_Node>::init( backing ); | 	node->nodes  = array_init<ADT_Node>( backing ); | ||||||
|  |  | ||||||
| 	if ( ! node->nodes ) | 	if ( ! node->nodes ) | ||||||
| 		return EADT_ERROR_OUT_OF_MEMORY; | 		return EADT_ERROR_OUT_OF_MEMORY; | ||||||
| @@ -36,12 +36,12 @@ u8 adt_destroy_branch( ADT_Node* node ) | |||||||
| 	GEN_ASSERT_NOT_NULL( node ); | 	GEN_ASSERT_NOT_NULL( node ); | ||||||
| 	if ( ( node->type == EADT_TYPE_OBJECT || node->type == EADT_TYPE_ARRAY ) && node->nodes ) | 	if ( ( node->type == EADT_TYPE_OBJECT || node->type == EADT_TYPE_ARRAY ) && node->nodes ) | ||||||
| 	{ | 	{ | ||||||
| 		for ( ssize i = 0; i < scast(ssize, node->nodes.num()); ++i ) | 		for ( ssize i = 0; i < scast(ssize, num(node->nodes)); ++i ) | ||||||
| 		{ | 		{ | ||||||
| 			adt_destroy_branch( node->nodes + i ); | 			adt_destroy_branch( node->nodes + i ); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		node->nodes.free(); | 		free(node->nodes); | ||||||
| 	} | 	} | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| @@ -66,7 +66,7 @@ ADT_Node* adt_find( ADT_Node* node, char const* name, b32 deep_search ) | |||||||
| 		return NULL; | 		return NULL; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	for ( ssize i = 0; i < scast(ssize, node->nodes.num()); i++ ) | 	for ( ssize i = 0; i < scast(ssize, num(node->nodes)); i++ ) | ||||||
| 	{ | 	{ | ||||||
| 		if ( ! str_compare( node->nodes[ i ].name, name ) ) | 		if ( ! str_compare( node->nodes[ i ].name, name ) ) | ||||||
| 		{ | 		{ | ||||||
| @@ -76,7 +76,7 @@ ADT_Node* adt_find( ADT_Node* node, char const* name, b32 deep_search ) | |||||||
|  |  | ||||||
| 	if ( deep_search ) | 	if ( deep_search ) | ||||||
| 	{ | 	{ | ||||||
| 		for ( ssize i = 0; i < scast(ssize, node->nodes.num()); i++ ) | 		for ( ssize i = 0; i < scast(ssize, num(node->nodes)); i++ ) | ||||||
| 		{ | 		{ | ||||||
| 			ADT_Node* res = adt_find( node->nodes + i, name, deep_search ); | 			ADT_Node* res = adt_find( node->nodes + i, name, deep_search ); | ||||||
|  |  | ||||||
| @@ -132,7 +132,7 @@ internal ADT_Node* _adt_get_value( ADT_Node* node, char const* value ) | |||||||
|  |  | ||||||
| internal ADT_Node* _adt_get_field( ADT_Node* node, char* name, char* value ) | internal ADT_Node* _adt_get_field( ADT_Node* node, char* name, char* value ) | ||||||
| { | { | ||||||
| 	for ( ssize i = 0; i < scast(ssize, node->nodes.num()); i++ ) | 	for ( ssize i = 0; i < scast(ssize, num(node->nodes)); i++ ) | ||||||
| 	{ | 	{ | ||||||
| 		if ( ! str_compare( node->nodes[ i ].name, name ) ) | 		if ( ! str_compare( node->nodes[ i ].name, name ) ) | ||||||
| 		{ | 		{ | ||||||
| @@ -207,7 +207,7 @@ ADT_Node* adt_query( ADT_Node* node, char const* uri ) | |||||||
| 			/* run a value comparison against any child that is an object node */ | 			/* run a value comparison against any child that is an object node */ | ||||||
| 			else if ( node->type == EADT_TYPE_ARRAY ) | 			else if ( node->type == EADT_TYPE_ARRAY ) | ||||||
| 			{ | 			{ | ||||||
| 				for ( ssize i = 0; i < scast(ssize, node->nodes.num()); i++ ) | 				for ( ssize i = 0; i < scast(ssize, num(node->nodes)); i++ ) | ||||||
| 				{ | 				{ | ||||||
| 					ADT_Node* child = &node->nodes[ i ]; | 					ADT_Node* child = &node->nodes[ i ]; | ||||||
| 					if ( child->type != EADT_TYPE_OBJECT ) | 					if ( child->type != EADT_TYPE_OBJECT ) | ||||||
| @@ -225,7 +225,7 @@ ADT_Node* adt_query( ADT_Node* node, char const* uri ) | |||||||
| 		/* [value] */ | 		/* [value] */ | ||||||
| 		else | 		else | ||||||
| 		{ | 		{ | ||||||
| 			for ( ssize i = 0; i < scast(ssize, node->nodes.num()); i++ ) | 			for ( ssize i = 0; i < scast(ssize, num(node->nodes)); i++ ) | ||||||
| 			{ | 			{ | ||||||
| 				ADT_Node* child = &node->nodes[ i ]; | 				ADT_Node* child = &node->nodes[ i ]; | ||||||
| 				if ( _adt_get_value( child, l_b2 ) ) | 				if ( _adt_get_value( child, l_b2 ) ) | ||||||
| @@ -257,7 +257,7 @@ ADT_Node* adt_query( ADT_Node* node, char const* uri ) | |||||||
| 	else | 	else | ||||||
| 	{ | 	{ | ||||||
| 		ssize idx = ( ssize )str_to_i64( buf, NULL, 10 ); | 		ssize idx = ( ssize )str_to_i64( buf, NULL, 10 ); | ||||||
| 		if ( idx >= 0 && idx < scast(ssize, node->nodes.num()) ) | 		if ( idx >= 0 && idx < scast(ssize, num(node->nodes)) ) | ||||||
| 		{ | 		{ | ||||||
| 			found_node = &node->nodes[ idx ]; | 			found_node = &node->nodes[ idx ]; | ||||||
|  |  | ||||||
| @@ -282,12 +282,12 @@ ADT_Node* adt_alloc_at( ADT_Node* parent, ssize index ) | |||||||
| 	if ( ! parent->nodes ) | 	if ( ! parent->nodes ) | ||||||
| 		return NULL; | 		return NULL; | ||||||
|  |  | ||||||
| 	if ( index < 0 || index > scast(ssize, parent->nodes.num()) ) | 	if ( index < 0 || index > scast(ssize, num(parent->nodes)) ) | ||||||
| 		return NULL; | 		return NULL; | ||||||
|  |  | ||||||
| 	ADT_Node o = { 0 }; | 	ADT_Node o = { 0 }; | ||||||
| 	o.parent   = parent; | 	o.parent   = parent; | ||||||
| 	if ( ! parent->nodes.append_at( o, index ) ) | 	if ( ! append_at( parent->nodes, o, index ) ) | ||||||
| 		return NULL; | 		return NULL; | ||||||
|  |  | ||||||
| 	return parent->nodes + index; | 	return parent->nodes + index; | ||||||
| @@ -303,7 +303,7 @@ ADT_Node* adt_alloc( ADT_Node* parent ) | |||||||
| 	if ( ! parent->nodes ) | 	if ( ! parent->nodes ) | ||||||
| 		return NULL; | 		return NULL; | ||||||
|  |  | ||||||
| 	return adt_alloc_at( parent, parent->nodes.num() ); | 	return adt_alloc_at( parent, num(parent->nodes) ); | ||||||
| } | } | ||||||
|  |  | ||||||
| b8 adt_set_obj( ADT_Node* obj, char const* name, AllocatorInfo backing ) | b8 adt_set_obj( ADT_Node* obj, char const* name, AllocatorInfo backing ) | ||||||
| @@ -357,7 +357,7 @@ ADT_Node* adt_move_node( ADT_Node* node, ADT_Node* new_parent ) | |||||||
| 	GEN_ASSERT_NOT_NULL( node ); | 	GEN_ASSERT_NOT_NULL( node ); | ||||||
| 	GEN_ASSERT_NOT_NULL( new_parent ); | 	GEN_ASSERT_NOT_NULL( new_parent ); | ||||||
| 	GEN_ASSERT( new_parent->type == EADT_TYPE_ARRAY || new_parent->type == EADT_TYPE_OBJECT ); | 	GEN_ASSERT( new_parent->type == EADT_TYPE_ARRAY || new_parent->type == EADT_TYPE_OBJECT ); | ||||||
| 	return adt_move_node_at( node, new_parent, new_parent->nodes.num() ); | 	return adt_move_node_at( node, new_parent, num(new_parent->nodes) ); | ||||||
| } | } | ||||||
|  |  | ||||||
| void adt_swap_nodes( ADT_Node* node, ADT_Node* other_node ) | void adt_swap_nodes( ADT_Node* node, ADT_Node* other_node ) | ||||||
| @@ -381,7 +381,7 @@ void adt_remove_node( ADT_Node* node ) | |||||||
| 	GEN_ASSERT_NOT_NULL( node->parent ); | 	GEN_ASSERT_NOT_NULL( node->parent ); | ||||||
| 	ADT_Node* parent = node->parent; | 	ADT_Node* parent = node->parent; | ||||||
| 	ssize        index  = ( pointer_diff( parent->nodes, node ) / size_of( ADT_Node ) ); | 	ssize        index  = ( pointer_diff( parent->nodes, node ) / size_of( ADT_Node ) ); | ||||||
| 	parent->nodes.remove_at( index ); | 	remove_at( parent->nodes, index ); | ||||||
| } | } | ||||||
|  |  | ||||||
| ADT_Node* adt_append_obj( ADT_Node* parent, char const* name ) | ADT_Node* adt_append_obj( ADT_Node* parent, char const* name ) | ||||||
| @@ -389,7 +389,7 @@ ADT_Node* adt_append_obj( ADT_Node* parent, char const* name ) | |||||||
| 	ADT_Node* o = adt_alloc( parent ); | 	ADT_Node* o = adt_alloc( parent ); | ||||||
| 	if ( ! o ) | 	if ( ! o ) | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 	if ( adt_set_obj( o, name, parent->nodes.get_header()->Allocator ) ) | 	if ( adt_set_obj( o, name, get_header(parent->nodes)->Allocator ) ) | ||||||
| 	{ | 	{ | ||||||
| 		adt_remove_node( o ); | 		adt_remove_node( o ); | ||||||
| 		return NULL; | 		return NULL; | ||||||
| @@ -402,7 +402,7 @@ ADT_Node* adt_append_arr( ADT_Node* parent, char const* name ) | |||||||
| 	ADT_Node* o = adt_alloc( parent ); | 	ADT_Node* o = adt_alloc( parent ); | ||||||
| 	if ( ! o ) | 	if ( ! o ) | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 	if ( adt_set_arr( o, name, parent->nodes.get_header()->Allocator ) ) | 	if ( adt_set_arr( o, name, get_header(parent->nodes)->Allocator ) ) | ||||||
| 	{ | 	{ | ||||||
| 		adt_remove_node( o ); | 		adt_remove_node( o ); | ||||||
| 		return NULL; | 		return NULL; | ||||||
| @@ -447,7 +447,7 @@ char* adt_parse_number_strict( ADT_Node* node, char* base_str ) | |||||||
| 	while ( *e ) | 	while ( *e ) | ||||||
| 		++e; | 		++e; | ||||||
|  |  | ||||||
| 	while ( *p && ( str_find( "eE.+-", *p ) || char_is_hex_digit( *p ) ) ) | 	while ( *p && ( char_first_occurence( "eE.+-", *p ) || char_is_hex_digit( *p ) ) ) | ||||||
| 	{ | 	{ | ||||||
| 		++p; | 		++p; | ||||||
| 	} | 	} | ||||||
| @@ -476,7 +476,7 @@ char* adt_parse_number( ADT_Node* node, char* base_str ) | |||||||
| 	u8        node_props = 0; | 	u8        node_props = 0; | ||||||
|  |  | ||||||
| 	/* skip false positives and special cases */ | 	/* skip false positives and special cases */ | ||||||
| 	if ( ! ! str_find( "eE", *p ) || ( ! ! str_find( ".+-", *p ) && ! char_is_hex_digit( *( p + 1 ) ) && *( p + 1 ) != '.' ) ) | 	if ( ! ! char_first_occurence( "eE", *p ) || ( ! ! char_first_occurence( ".+-", *p ) && ! char_is_hex_digit( *( p + 1 ) ) && *( p + 1 ) != '.' ) ) | ||||||
| 	{ | 	{ | ||||||
| 		return ++base_str; | 		return ++base_str; | ||||||
| 	} | 	} | ||||||
| @@ -552,7 +552,7 @@ char* adt_parse_number( ADT_Node* node, char* base_str ) | |||||||
| 	char expbuf[ 6 ] = { 0 }; | 	char expbuf[ 6 ] = { 0 }; | ||||||
| 	ssize   expi        = 0; | 	ssize   expi        = 0; | ||||||
|  |  | ||||||
| 	if ( *e && ! ! str_find( "eE", *e ) ) | 	if ( *e && ! ! char_first_occurence( "eE", *e ) ) | ||||||
| 	{ | 	{ | ||||||
| 		++e; | 		++e; | ||||||
| 		if ( *e == '+' || *e == '-' || char_is_digit( *e ) ) | 		if ( *e == '+' || *e == '-' || char_is_digit( *e ) ) | ||||||
| @@ -748,7 +748,7 @@ ADT_Error adt_print_string( FileInfo* file, ADT_Node* node, char const* escaped_ | |||||||
| 	{ | 	{ | ||||||
| 		p = str_skip_any( p, escaped_chars ); | 		p = str_skip_any( p, escaped_chars ); | ||||||
| 		_adt_fprintf( file, "%.*s", pointer_diff( b, p ), b ); | 		_adt_fprintf( file, "%.*s", pointer_diff( b, p ), b ); | ||||||
| 		if ( *p && ! ! str_find( escaped_chars, *p ) ) | 		if ( *p && ! ! char_first_occurence( escaped_chars, *p ) ) | ||||||
| 		{ | 		{ | ||||||
| 			_adt_fprintf( file, "%s%c", escape_symbol, *p ); | 			_adt_fprintf( file, "%s%c", escape_symbol, *p ); | ||||||
| 			p++; | 			p++; | ||||||
| @@ -946,12 +946,12 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if ( columnIndex >= scast(ssize, root->nodes.num()) ) | 		if ( columnIndex >= scast(ssize, num(root->nodes)) ) | ||||||
| 		{ | 		{ | ||||||
| 			adt_append_arr( root, NULL ); | 			adt_append_arr( root, NULL ); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		root->nodes[ columnIndex ].nodes.append( rowItem ); | 		append(root->nodes[ columnIndex ].nodes, rowItem ); | ||||||
|  |  | ||||||
| 		if ( delimiter == delim ) | 		if ( delimiter == delim ) | ||||||
| 		{ | 		{ | ||||||
| @@ -979,7 +979,7 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b | |||||||
| 	} | 	} | ||||||
| 	while ( *currentChar ); | 	while ( *currentChar ); | ||||||
|  |  | ||||||
| 	if ( root->nodes.num() == 0 ) | 	if (num( root->nodes) == 0 ) | ||||||
| 	{ | 	{ | ||||||
| 		GEN_CSV_ASSERT( "unexpected end of input. stream is empty." ); | 		GEN_CSV_ASSERT( "unexpected end of input. stream is empty." ); | ||||||
| 		error = ECSV_Error__UNEXPECTED_END_OF_INPUT; | 		error = ECSV_Error__UNEXPECTED_END_OF_INPUT; | ||||||
| @@ -989,12 +989,12 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b | |||||||
| 	/* consider first row as a header. */ | 	/* consider first row as a header. */ | ||||||
| 	if ( has_header ) | 	if ( has_header ) | ||||||
| 	{ | 	{ | ||||||
| 		for ( ssize i = 0; i < scast(ssize, root->nodes.num()); i++ ) | 		for ( ssize i = 0; i < scast(ssize, num(root->nodes)); i++ ) | ||||||
| 		{ | 		{ | ||||||
| 			CSV_Object* col = root->nodes + i; | 			CSV_Object* col = root->nodes + i; | ||||||
| 			CSV_Object* hdr = col->nodes; | 			CSV_Object* hdr = col->nodes; | ||||||
| 			col->name       = hdr->string; | 			col->name       = hdr->string; | ||||||
| 			col->nodes.remove_at( 0 ); | 			remove_at(col->nodes, 0 ); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -1057,11 +1057,11 @@ void csv_write_delimiter( FileInfo* file, CSV_Object* obj, char delimiter ) | |||||||
| 	GEN_ASSERT_NOT_NULL( file ); | 	GEN_ASSERT_NOT_NULL( file ); | ||||||
| 	GEN_ASSERT_NOT_NULL( obj ); | 	GEN_ASSERT_NOT_NULL( obj ); | ||||||
| 	GEN_ASSERT( obj->nodes ); | 	GEN_ASSERT( obj->nodes ); | ||||||
| 	ssize cols = obj->nodes.num(); | 	ssize cols = num(obj->nodes); | ||||||
| 	if ( cols == 0 ) | 	if ( cols == 0 ) | ||||||
| 		return; | 		return; | ||||||
|  |  | ||||||
| 	ssize rows = obj->nodes[ 0 ].nodes.num(); | 	ssize rows = num(obj->nodes[ 0 ].nodes); | ||||||
| 	if ( rows == 0 ) | 	if ( rows == 0 ) | ||||||
| 		return; | 		return; | ||||||
|  |  | ||||||
| @@ -1102,7 +1102,7 @@ String csv_write_string_delimiter( AllocatorInfo a, CSV_Object* obj, char delimi | |||||||
|  |  | ||||||
| 	ssize  fsize; | 	ssize  fsize; | ||||||
| 	u8*    buf    = file_stream_buf( &tmp, &fsize ); | 	u8*    buf    = file_stream_buf( &tmp, &fsize ); | ||||||
| 	String output = String::make_length( a, ( char* )buf, fsize ); | 	String output = string_make_length( a, ( char* )buf, fsize ); | ||||||
| 	file_close( &tmp ); | 	file_close( &tmp ); | ||||||
| 	return output; | 	return output; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -76,13 +76,18 @@ | |||||||
| /* Platform compiler */ | /* Platform compiler */ | ||||||
|  |  | ||||||
| #if defined( _MSC_VER ) | #if defined( _MSC_VER ) | ||||||
|  | #	define GEN_COMPILER_CLANG 0 | ||||||
| #	define GEN_COMPILER_MSVC  1 | #	define GEN_COMPILER_MSVC  1 | ||||||
|  | #	define GEN_COMPILER_GCC   0 | ||||||
| #elif defined( __GNUC__ ) | #elif defined( __GNUC__ ) | ||||||
|  | #	define GEN_COMPILER_CLANG 0 | ||||||
|  | #	define GEN_COMPILER_MSVC  0 | ||||||
| #	define GEN_COMPILER_GCC   1 | #	define GEN_COMPILER_GCC   1 | ||||||
| #elif defined( __clang__ ) | #elif defined( __clang__ ) | ||||||
| #	define GEN_COMPILER_CLANG 1 | #	define GEN_COMPILER_CLANG 1 | ||||||
| #elif defined( __MINGW32__ ) | #	define GEN_COMPILER_MSVC  0 | ||||||
| #	define GEN_COMPILER_MINGW 1 | #	define GEN_COMPILER_GCC   1 | ||||||
|  | #else | ||||||
| #	error Unknown compiler | #	error Unknown compiler | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| @@ -101,6 +106,14 @@ | |||||||
| #  define GEN_GCC_VERSION_CHECK(major,minor,patch) (0) | #  define GEN_GCC_VERSION_CHECK(major,minor,patch) (0) | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #ifndef GEN_COMPIELR_C | ||||||
|  | #	if defined(__STDC_VERSION__) | ||||||
|  | #		define GEN_COMPILER_C 1 | ||||||
|  | #	else | ||||||
|  | #		define GEN_COMPILER_C 0 | ||||||
|  | #	endif | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #pragma endregion Platform Detection | #pragma endregion Platform Detection | ||||||
|  |  | ||||||
| #pragma region Mandatory Includes | #pragma region Mandatory Includes | ||||||
| @@ -114,11 +127,23 @@ | |||||||
|  |  | ||||||
| #pragma endregion Mandatory Includes | #pragma endregion Mandatory Includes | ||||||
|  |  | ||||||
| #ifdef GEN_DONT_USE_NAMESPACE | #if GEN_DONT_USE_NAMESPACE | ||||||
|  | #	if GEN_COMPILER_C | ||||||
|  | #		define GEN_NS_ENUM_BEGIN | ||||||
|  | #		define GEN_NS_ENUM_END | ||||||
| #		define GEN_NS | #		define GEN_NS | ||||||
| #		define GEN_NS_BEGIN | #		define GEN_NS_BEGIN | ||||||
| #		define GEN_NS_END | #		define GEN_NS_END | ||||||
| #	else | #	else | ||||||
|  | #		define GEN_NS_ENUM_BEGIN namespace gen_internal_enums { | ||||||
|  | #		define GEN_NS_ENUM_END   } | ||||||
|  | #		define GEN_NS       :: | ||||||
|  | #		define GEN_NS_BEGIN | ||||||
|  | #		define GEN_NS_END | ||||||
|  | #	endif | ||||||
|  | #else | ||||||
|  | #	define GEN_NS_ENUM_BEGIN namespace gen_internal_enums { | ||||||
|  | #	define GEN_NS_ENUM_END   } | ||||||
| #	define GEN_NS       gen:: | #	define GEN_NS       gen:: | ||||||
| #	define GEN_NS_BEGIN namespace gen { | #	define GEN_NS_BEGIN namespace gen { | ||||||
| #	define GEN_NS_END   } | #	define GEN_NS_END   } | ||||||
|   | |||||||
| @@ -422,7 +422,7 @@ neverinline ssize str_fmt_va( char* text, ssize max_len, char const* fmt, va_lis | |||||||
| 			{ | 			{ | ||||||
| 				String gen_str = String { va_arg( va, char*) }; | 				String gen_str = String { va_arg( va, char*) }; | ||||||
|  |  | ||||||
| 				info.precision = gen_str.length(); | 				info.precision = length(gen_str); | ||||||
| 				len            = _print_string( text, remaining, &info, gen_str ); | 				len            = _print_string( text, remaining, &info, gen_str ); | ||||||
| 			} | 			} | ||||||
| 			break; | 			break; | ||||||
|   | |||||||
| @@ -6,7 +6,6 @@ | |||||||
| #pragma region String Ops | #pragma region String Ops | ||||||
|  |  | ||||||
| const char* char_first_occurence( const char* str, char c ); | const char* char_first_occurence( const char* str, char c ); | ||||||
| constexpr auto str_find = &char_first_occurence; |  | ||||||
|  |  | ||||||
| b32   char_is_alpha( char c ); | b32   char_is_alpha( char c ); | ||||||
| b32   char_is_alphanumeric( char c ); | b32   char_is_alphanumeric( char c ); | ||||||
|   | |||||||
| @@ -4,20 +4,9 @@ | |||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #pragma region String | #pragma region String | ||||||
|  | String string_make_length( AllocatorInfo allocator, char const* str, ssize length ) | ||||||
| String String::fmt( AllocatorInfo allocator, char* buf, ssize buf_size, char const* fmt, ... ) |  | ||||||
| { | { | ||||||
| 	va_list va; | 	constexpr ssize header_size = sizeof( StringHeader ); | ||||||
| 	va_start( va, fmt ); |  | ||||||
| 	str_fmt_va( buf, buf_size, fmt, va ); |  | ||||||
| 	va_end( va ); |  | ||||||
|  |  | ||||||
| 	return make( allocator, buf ); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| String String::make_length( AllocatorInfo allocator, char const* str, ssize length ) |  | ||||||
| { |  | ||||||
| 	constexpr ssize header_size = sizeof( Header ); |  | ||||||
|  |  | ||||||
| 	s32   alloc_size = header_size + length + 1; | 	s32   alloc_size = header_size + length + 1; | ||||||
| 	void* allocation = alloc( allocator, alloc_size ); | 	void* allocation = alloc( allocator, alloc_size ); | ||||||
| @@ -25,8 +14,8 @@ String String::make_length( AllocatorInfo allocator, char const* str, ssize leng | |||||||
| 	if ( allocation == nullptr ) | 	if ( allocation == nullptr ) | ||||||
| 		return { nullptr }; | 		return { nullptr }; | ||||||
|  |  | ||||||
| 	Header& | 	StringHeader& | ||||||
| 	header = * rcast(Header*, allocation); | 	header = * rcast(StringHeader*, allocation); | ||||||
| 	header = { allocator, length, length }; | 	header = { allocator, length, length }; | ||||||
|  |  | ||||||
| 	String  result = { rcast( char*, allocation) + header_size }; | 	String  result = { rcast( char*, allocation) + header_size }; | ||||||
| @@ -41,9 +30,9 @@ String String::make_length( AllocatorInfo allocator, char const* str, ssize leng | |||||||
| 	return result; | 	return result; | ||||||
| } | } | ||||||
|  |  | ||||||
| String String::make_reserve( AllocatorInfo allocator, ssize capacity ) | String string_make_reserve( AllocatorInfo allocator, ssize capacity ) | ||||||
| { | { | ||||||
| 	constexpr ssize header_size = sizeof( Header ); | 	constexpr ssize header_size = sizeof( StringHeader ); | ||||||
|  |  | ||||||
| 	s32   alloc_size = header_size + capacity + 1; | 	s32   alloc_size = header_size + capacity + 1; | ||||||
| 	void* allocation = alloc( allocator, alloc_size ); | 	void* allocation = alloc( allocator, alloc_size ); | ||||||
| @@ -53,8 +42,8 @@ String String::make_reserve( AllocatorInfo allocator, ssize capacity ) | |||||||
|  |  | ||||||
| 	mem_set( allocation, 0, alloc_size ); | 	mem_set( allocation, 0, alloc_size ); | ||||||
|  |  | ||||||
| 	Header* | 	StringHeader* | ||||||
| 		header            = rcast(Header*, allocation); | 	header            = rcast(StringHeader*, allocation); | ||||||
| 	header->Allocator = allocator; | 	header->Allocator = allocator; | ||||||
| 	header->Capacity  = capacity; | 	header->Capacity  = capacity; | ||||||
| 	header->Length    = 0; | 	header->Length    = 0; | ||||||
| @@ -62,69 +51,4 @@ String String::make_reserve( AllocatorInfo allocator, ssize capacity ) | |||||||
| 	String result = { rcast(char*, allocation) + header_size }; | 	String result = { rcast(char*, allocation) + header_size }; | ||||||
| 	return result; | 	return result; | ||||||
| } | } | ||||||
|  |  | ||||||
| String String::fmt_buf( AllocatorInfo allocator, char const* fmt, ... ) |  | ||||||
| { |  | ||||||
| 	local_persist thread_local |  | ||||||
| 	char buf[ GEN_PRINTF_MAXLEN ] = { 0 }; |  | ||||||
|  |  | ||||||
| 	va_list va; |  | ||||||
| 	va_start( va, fmt ); |  | ||||||
| 	str_fmt_va( buf, GEN_PRINTF_MAXLEN, fmt, va ); |  | ||||||
| 	va_end( va ); |  | ||||||
|  |  | ||||||
| 	return make( allocator, buf ); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| bool String::append_fmt( char const* fmt, ... ) |  | ||||||
| { |  | ||||||
| 	ssize   res; |  | ||||||
| 	char buf[ GEN_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 String::make_space_for( char const* str, ssize add_len ) |  | ||||||
| { |  | ||||||
| 	ssize available = avail_space(); |  | ||||||
|  |  | ||||||
| 	// NOTE: Return if there is enough space left |  | ||||||
| 	if ( available >= add_len ) |  | ||||||
| 	{ |  | ||||||
| 		return true; |  | ||||||
| 	} |  | ||||||
| 	else |  | ||||||
| 	{ |  | ||||||
| 		ssize new_len, old_size, new_size; |  | ||||||
|  |  | ||||||
| 		void* ptr; |  | ||||||
| 		void* new_ptr; |  | ||||||
|  |  | ||||||
| 		AllocatorInfo allocator = get_header().Allocator; |  | ||||||
| 		Header*       header	= nullptr; |  | ||||||
|  |  | ||||||
| 		new_len  = grow_formula( length() + add_len ); |  | ||||||
| 		ptr      = & get_header(); |  | ||||||
| 		old_size = size_of( Header ) + length() + 1; |  | ||||||
| 		new_size = size_of( Header ) + new_len + 1; |  | ||||||
|  |  | ||||||
| 		new_ptr = resize( allocator, ptr, old_size, new_size ); |  | ||||||
|  |  | ||||||
| 		if ( new_ptr == nullptr ) |  | ||||||
| 			return false; |  | ||||||
|  |  | ||||||
| 		header            = rcast( Header*, new_ptr); |  | ||||||
| 		header->Allocator = allocator; |  | ||||||
| 		header->Capacity  = new_len; |  | ||||||
|  |  | ||||||
| 		Data = rcast( char*, header + 1 ); |  | ||||||
|  |  | ||||||
| 		return true; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| #pragma endregion String | #pragma endregion String | ||||||
|   | |||||||
| @@ -19,8 +19,7 @@ struct StrC | |||||||
| #define txt( text )         StrC { sizeof( text ) - 1, ( text ) } | #define txt( text )         StrC { sizeof( text ) - 1, ( text ) } | ||||||
|  |  | ||||||
| inline | inline | ||||||
| StrC to_str( char const* str ) | StrC to_str( char const* str ) { | ||||||
| { |  | ||||||
| 	return { str_len( str ), str }; | 	return { str_len( str ), str }; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -28,232 +27,463 @@ StrC to_str( char const* str ) | |||||||
| // This is directly based off the ZPL string api. | // This is directly based off the ZPL string api. | ||||||
| // They used a header pattern | // They used a header pattern | ||||||
| // I kept it for simplicty of porting but its not necessary to keep it that way. | // I kept it for simplicty of porting but its not necessary to keep it that way. | ||||||
| struct String | #pragma region String | ||||||
| { | struct StringHeader; | ||||||
| 	struct Header |  | ||||||
| 	{ | #if GEN_COMPILER_C | ||||||
|  | typedef char* String; | ||||||
|  | #else | ||||||
|  | struct String; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | String        string_make(AllocatorInfo allocator, char const* str); | ||||||
|  | String        string_make(AllocatorInfo allocator, StrC str); | ||||||
|  | String        string_make_reserve(AllocatorInfo allocator, ssize capacity); | ||||||
|  | String        string_make_length(AllocatorInfo allocator, char const* str, ssize length); | ||||||
|  | String        string_fmt(AllocatorInfo allocator, char* buf, ssize buf_size, char const* fmt, ...); | ||||||
|  | String        string_fmt_buf(AllocatorInfo allocator, char const* fmt, ...); | ||||||
|  | String        string_join(AllocatorInfo allocator, char const** parts, ssize num_parts, char const* glue); | ||||||
|  | usize         string_grow_formula(usize value); | ||||||
|  | bool          are_equal(String lhs, String rhs); | ||||||
|  | bool          are_equal(String lhs, StrC rhs); | ||||||
|  | bool          make_space_for(String& str, char const* to_append, ssize add_len); | ||||||
|  | bool          append(String& str, char c); | ||||||
|  | bool          append(String& str, char const* str_to_append); | ||||||
|  | bool          append(String& str, char const* str_to_append, ssize length); | ||||||
|  | bool          append(String& str, StrC str_to_append); | ||||||
|  | bool          append(String& str, const String other); | ||||||
|  | bool          append_fmt(String& str, char const* fmt, ...); | ||||||
|  | ssize         avail_space(String const& str); | ||||||
|  | char&         back(String& str); | ||||||
|  | bool          contains(String const& str, StrC substring); | ||||||
|  | bool          contains(String const& str, String const& substring); | ||||||
|  | ssize         capacity(String const& str); | ||||||
|  | void          clear(String& str); | ||||||
|  | String        duplicate(String const& str, AllocatorInfo allocator); | ||||||
|  | void          free(String& str); | ||||||
|  | StringHeader& get_header(String& str); | ||||||
|  | ssize         length(String const& str); | ||||||
|  | b32           starts_with(String const& str, StrC substring); | ||||||
|  | b32           starts_with(String const& str, String substring); | ||||||
|  | void          skip_line(String& str); | ||||||
|  | void          strip_space(String& str); | ||||||
|  | void          trim(String& str, char const* cut_set); | ||||||
|  | void          trim_space(String& str); | ||||||
|  | String        visualize_whitespace(String const& str); | ||||||
|  |  | ||||||
|  | struct StringHeader { | ||||||
| 	AllocatorInfo Allocator; | 	AllocatorInfo Allocator; | ||||||
| 	ssize         Capacity; | 	ssize         Capacity; | ||||||
| 	ssize         Length; | 	ssize         Length; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| 	static | #if ! GEN_COMPILER_C | ||||||
| 	usize grow_formula( usize value ) | struct String | ||||||
| { | { | ||||||
|  | 	char* Data; | ||||||
|  |  | ||||||
|  | 	forceinline operator bool()              { return Data != nullptr; } | ||||||
|  | 	forceinline operator char*()             { return Data; } | ||||||
|  | 	forceinline operator char const*() const { return Data; } | ||||||
|  | 	forceinline operator StrC() const        { return { GEN_NS length(* this), Data }; } | ||||||
|  |  | ||||||
|  | 	String const& operator=(String const& other) const { | ||||||
|  | 		if (this == &other) | ||||||
|  | 			return *this; | ||||||
|  |  | ||||||
|  | 		String* this_ = ccast(String*, this); | ||||||
|  | 		this_->Data = other.Data; | ||||||
|  |  | ||||||
|  | 		return *this; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	forceinline char& operator[](ssize index)             { return Data[index]; } | ||||||
|  | 	forceinline char const& operator[](ssize index) const { return Data[index]; } | ||||||
|  |  | ||||||
|  | 	forceinline char* begin() const { return Data; } | ||||||
|  | 	forceinline char* end() const   { return Data + GEN_NS length(* this); } | ||||||
|  |  | ||||||
|  | #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||||
|  | #pragma region Member Mapping | ||||||
|  | 	forceinline static String make(AllocatorInfo allocator, char const* str)                { return GEN_NS string_make(allocator, str); } | ||||||
|  | 	forceinline static String make(AllocatorInfo allocator, StrC str)                       { return GEN_NS string_make(allocator, str); } | ||||||
|  | 	forceinline static String make_reserve(AllocatorInfo allocator, ssize cap)              { return GEN_NS string_make_reserve(allocator, cap); } | ||||||
|  | 	forceinline static String make_length(AllocatorInfo a, char const* s, ssize l)          { return GEN_NS string_make_length(a, s, l); } | ||||||
|  | 	forceinline static String join(AllocatorInfo a, char const** p, ssize n, char const* g) { return GEN_NS string_join(a, p, n, g); } | ||||||
|  | 	forceinline static usize  grow_formula(usize value)                                     { return GEN_NS string_grow_formula(value); } | ||||||
|  | 	forceinline static bool   are_equal(String lhs, String rhs)                             { return GEN_NS are_equal(lhs, rhs); } | ||||||
|  | 	forceinline static bool   are_equal(String lhs, StrC rhs)                               { return GEN_NS are_equal(lhs, rhs); } | ||||||
|  |  | ||||||
|  | 	static | ||||||
|  | 	String fmt(AllocatorInfo allocator, char* buf, ssize buf_size, char const* fmt, ...) { | ||||||
|  | 		va_list va; | ||||||
|  | 		va_start(va, fmt); | ||||||
|  | 		str_fmt_va(buf, buf_size, fmt, va); | ||||||
|  | 		va_end(va); | ||||||
|  | 		return GEN_NS string_make(allocator, buf); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	static | ||||||
|  | 	String fmt_buf(AllocatorInfo allocator, char const* fmt, ...) { | ||||||
|  | 		local_persist thread_local | ||||||
|  | 		char buf[GEN_PRINTF_MAXLEN] = { 0 }; | ||||||
|  | 		va_list va; | ||||||
|  | 		va_start(va, fmt); | ||||||
|  | 		str_fmt_va(buf, GEN_PRINTF_MAXLEN, fmt, va); | ||||||
|  | 		va_end(va); | ||||||
|  | 		return GEN_NS string_make(allocator, buf); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	forceinline bool          make_space_for(char const* str, ssize add_len) { return GEN_NS make_space_for(*this, str, add_len); } | ||||||
|  | 	forceinline bool          append(char c)                                 { return GEN_NS append(*this, c); } | ||||||
|  | 	forceinline bool          append(char const* str)                        { return GEN_NS append(*this, str); } | ||||||
|  | 	forceinline bool          append(char const* str, ssize length)          { return GEN_NS append(*this, str, length); } | ||||||
|  | 	forceinline bool          append(StrC str)                               { return GEN_NS append(*this, str); } | ||||||
|  | 	forceinline bool          append(const String other)                     { return GEN_NS append(*this, other); } | ||||||
|  | 	forceinline ssize         avail_space() const                            { return GEN_NS avail_space(*this); } | ||||||
|  | 	forceinline char&         back()                                         { return GEN_NS back(*this); } | ||||||
|  | 	forceinline bool          contains(StrC substring) const                 { return GEN_NS contains(*this, substring); } | ||||||
|  | 	forceinline bool          contains(String const& substring) const        { return GEN_NS contains(*this, substring); } | ||||||
|  | 	forceinline ssize         capacity() const                               { return GEN_NS capacity(*this); } | ||||||
|  | 	forceinline void          clear()                                        { GEN_NS clear(*this); } | ||||||
|  | 	forceinline String        duplicate(AllocatorInfo allocator) const       { return GEN_NS duplicate(*this, allocator); } | ||||||
|  | 	forceinline void          free()                                         { GEN_NS free(*this); } | ||||||
|  | 	forceinline ssize         length() const                                 { return GEN_NS length(*this); } | ||||||
|  | 	forceinline b32           starts_with(StrC substring) const              { return GEN_NS starts_with(*this, substring); } | ||||||
|  | 	forceinline b32           starts_with(String substring) const            { return GEN_NS starts_with(*this, substring); } | ||||||
|  | 	forceinline void          skip_line()                                    { GEN_NS skip_line(*this); } | ||||||
|  | 	forceinline void          strip_space()                                  { GEN_NS strip_space(*this); } | ||||||
|  | 	forceinline void          trim(char const* cut_set)                      { GEN_NS trim(*this, cut_set); } | ||||||
|  | 	forceinline void          trim_space()                                   { GEN_NS trim_space(*this); } | ||||||
|  | 	forceinline String        visualize_whitespace() const                   { return GEN_NS visualize_whitespace(*this); } | ||||||
|  | 	forceinline StringHeader& get_header()                                   { return GEN_NS get_header(*this); } | ||||||
|  |  | ||||||
|  | 	bool append_fmt(char const* fmt, ...) { | ||||||
|  | 		ssize res; | ||||||
|  | 		char buf[GEN_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 GEN_NS append(*this, buf, res); | ||||||
|  | 	} | ||||||
|  | #pragma endregion Member Mapping | ||||||
|  | #endif | ||||||
|  | }; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | inline char* begin(String& str) { return str; } | ||||||
|  | inline char* end(String& str)   { return scast(char*, str) + length(str); } | ||||||
|  | inline char* next(String& str)  { return scast(char*, str) + 1; } | ||||||
|  |  | ||||||
|  | inline | ||||||
|  | usize string_grow_formula(usize value) { | ||||||
| 	// Using a very aggressive growth formula to reduce time mem_copying with recursive calls to append in this library. | 	// Using a very aggressive growth formula to reduce time mem_copying with recursive calls to append in this library. | ||||||
| 	return 4 * value + 8; | 	return 4 * value + 8; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	static | inline | ||||||
| 	String make( AllocatorInfo allocator, char const* str ) | String string_make(AllocatorInfo allocator, char const* str) { | ||||||
| 	{ |  | ||||||
| 	ssize length = str ? str_len(str) : 0; | 	ssize length = str ? str_len(str) : 0; | ||||||
| 		return make_length( allocator, str, length ); | 	return string_make_length(allocator, str, length); | ||||||
| } | } | ||||||
|  |  | ||||||
| 	static | inline | ||||||
| 	String make( AllocatorInfo allocator, StrC str ) | String string_make(AllocatorInfo allocator, StrC str) { | ||||||
| 	{ | 	return string_make_length(allocator, str.Ptr, str.Len); | ||||||
| 		return make_length( allocator, str.Ptr, str.Len ); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| 	static | inline | ||||||
| 	String make_reserve( AllocatorInfo allocator, ssize capacity ); | String string_fmt(AllocatorInfo allocator, char* buf, ssize buf_size, char const* fmt, ...) { | ||||||
|  | 	va_list va; | ||||||
|  | 	va_start(va, fmt); | ||||||
|  | 	str_fmt_va(buf, buf_size, fmt, va); | ||||||
|  | 	va_end(va); | ||||||
|  |  | ||||||
| 	static | 	return string_make(allocator, buf); | ||||||
| 	String make_length( AllocatorInfo allocator, char const* str, ssize length ); | } | ||||||
|  |  | ||||||
| 	static | inline | ||||||
| 	String fmt( AllocatorInfo allocator, char* buf, ssize buf_size, char const* fmt, ... ); | String string_fmt_buf(AllocatorInfo allocator, char const* fmt, ...) | ||||||
|  |  | ||||||
| 	static |  | ||||||
| 	String fmt_buf( AllocatorInfo allocator, char const* fmt, ... ); |  | ||||||
|  |  | ||||||
| 	static |  | ||||||
| 	String join( AllocatorInfo allocator, char const** parts, ssize num_parts, char const* glue ) |  | ||||||
| { | { | ||||||
| 		String result = make( allocator, "" ); | 	local_persist thread_local | ||||||
|  | 	char buf[GEN_PRINTF_MAXLEN] = { 0 }; | ||||||
|  |  | ||||||
|  | 	va_list va; | ||||||
|  | 	va_start(va, fmt); | ||||||
|  | 	str_fmt_va(buf, GEN_PRINTF_MAXLEN, fmt, va); | ||||||
|  | 	va_end(va); | ||||||
|  |  | ||||||
|  | 	return string_make(allocator, buf); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline | ||||||
|  | String string_join(AllocatorInfo allocator, char const** parts, ssize num_parts, char const* glue) | ||||||
|  | { | ||||||
|  | 	String result = string_make(allocator, ""); | ||||||
|  |  | ||||||
| 	for (ssize idx = 0; idx < num_parts; ++idx) | 	for (ssize idx = 0; idx < num_parts; ++idx) | ||||||
| 	{ | 	{ | ||||||
| 			result.append( parts[ idx ] ); | 		append(result, parts[idx]); | ||||||
|  |  | ||||||
| 		if (idx < num_parts - 1) | 		if (idx < num_parts - 1) | ||||||
| 				result.append( glue ); | 			append(result, glue); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return result; | 	return result; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	static | inline | ||||||
|  | bool append(String& str, char c) { | ||||||
|  | 	return append(str, &c, 1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline | ||||||
|  | bool append(String& str, char const* str_to_append) { | ||||||
|  | 	return append(str, str_to_append, str_len(str_to_append)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline | ||||||
|  | bool append(String& str, char const* str_to_append, ssize append_length) | ||||||
|  | { | ||||||
|  | 	if (sptr(str_to_append) > 0) | ||||||
|  | 	{ | ||||||
|  | 		ssize curr_len = length(str); | ||||||
|  |  | ||||||
|  | 		if (!make_space_for(str, str_to_append, append_length)) | ||||||
|  | 			return false; | ||||||
|  |  | ||||||
|  | 		StringHeader& header = get_header(str); | ||||||
|  |  | ||||||
|  | 		mem_copy( scast(char*, str) + curr_len, str_to_append, append_length); | ||||||
|  |  | ||||||
|  | 		str[curr_len + append_length] = '\0'; | ||||||
|  |  | ||||||
|  | 		header.Length = curr_len + append_length; | ||||||
|  | 	} | ||||||
|  | 	return str_to_append != nullptr; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline | ||||||
|  | bool append(String& str, StrC str_to_append) { | ||||||
|  | 	return append(str, str_to_append.Ptr, str_to_append.Len); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline | ||||||
|  | bool append(String& str, const String other) { | ||||||
|  | 	return append(str, other, length(other)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool append_fmt(String& str, char const* fmt, ...) { | ||||||
|  | 	ssize res; | ||||||
|  | 	char buf[GEN_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(str, buf, res); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline | ||||||
| bool are_equal(String lhs, String rhs) | bool are_equal(String lhs, String rhs) | ||||||
| { | { | ||||||
| 		if ( lhs.length() != rhs.length() ) | 	if (length(lhs) != length(rhs)) | ||||||
| 		return false; | 		return false; | ||||||
|  |  | ||||||
| 		for ( ssize idx = 0; idx < lhs.length(); ++idx ) | 	for (ssize idx = 0; idx < length(lhs); ++idx) | ||||||
| 		if (lhs[idx] != rhs[idx]) | 		if (lhs[idx] != rhs[idx]) | ||||||
| 			return false; | 			return false; | ||||||
|  |  | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	static | inline | ||||||
| bool are_equal(String lhs, StrC rhs) | bool are_equal(String lhs, StrC rhs) | ||||||
| { | { | ||||||
| 		if ( lhs.length() != (rhs.Len) ) | 	if (length(lhs) != (rhs.Len)) | ||||||
| 		return false; | 		return false; | ||||||
|  |  | ||||||
| 		for ( ssize idx = 0; idx < lhs.length(); ++idx ) | 	for (ssize idx = 0; idx < length(lhs); ++idx) | ||||||
| 		if (lhs[idx] != rhs[idx]) | 		if (lhs[idx] != rhs[idx]) | ||||||
| 			return false; | 			return false; | ||||||
|  |  | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	bool make_space_for( char const* str, ssize add_len ); | inline | ||||||
|  | ssize avail_space(String const& str) { | ||||||
| 	bool append( char c ) | 	StringHeader const& header = *rcast(StringHeader const*, scast(char const*, str) - sizeof(StringHeader)); | ||||||
| 	{ |  | ||||||
| 		return append( & c, 1 ); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	bool append( char const* str ) |  | ||||||
| 	{ |  | ||||||
| 		return append( str, str_len( str ) ); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	bool append( char const* str, ssize length ) |  | ||||||
| 	{ |  | ||||||
| 		if ( sptr(str) > 0 ) |  | ||||||
| 		{ |  | ||||||
| 			ssize curr_len = this->length(); |  | ||||||
|  |  | ||||||
| 			if ( ! make_space_for( str, length ) ) |  | ||||||
| 				return false; |  | ||||||
|  |  | ||||||
| 			Header& header = get_header(); |  | ||||||
|  |  | ||||||
| 			mem_copy( Data + curr_len, str, length ); |  | ||||||
|  |  | ||||||
| 			Data[ curr_len + length ] = '\0'; |  | ||||||
|  |  | ||||||
| 			header.Length = curr_len + length; |  | ||||||
| 		} |  | ||||||
| 		return str != nullptr; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	bool append( StrC str) |  | ||||||
| 	{ |  | ||||||
| 		return append( str.Ptr, str.Len ); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	bool append( const String other ) |  | ||||||
| 	{ |  | ||||||
| 		return append( other.Data, other.length() ); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	bool append_fmt( char const* fmt, ... ); |  | ||||||
|  |  | ||||||
| 	ssize avail_space() const |  | ||||||
| 	{ |  | ||||||
| 		Header const& |  | ||||||
| 		header = * rcast( Header const*, Data - sizeof( Header )); |  | ||||||
|  |  | ||||||
| 	return header.Capacity - header.Length; | 	return header.Capacity - header.Length; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	char& back() | inline | ||||||
| 	{ | char& back(String& str) { | ||||||
| 		return Data[ length() - 1 ]; | 	return str.Data[length(str) - 1]; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	ssize capacity() const | inline | ||||||
|  | bool contains(String const& str, StrC substring) | ||||||
| { | { | ||||||
| 		Header const& | 	StringHeader const& header = *rcast(StringHeader const*, scast(char const*, str) - sizeof(StringHeader)); | ||||||
| 		header = * rcast( Header const*, Data - sizeof( Header )); |  | ||||||
|  |  | ||||||
|  | 	if (substring.Len > header.Length) | ||||||
|  | 		return false; | ||||||
|  |  | ||||||
|  | 	ssize main_len = header.Length; | ||||||
|  | 	ssize sub_len = substring.Len; | ||||||
|  |  | ||||||
|  | 	for (ssize idx = 0; idx <= main_len - sub_len; ++idx) | ||||||
|  | 	{ | ||||||
|  | 		if (str_compare(str.Data + idx, substring.Ptr, sub_len) == 0) | ||||||
|  | 			return true; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline | ||||||
|  | bool contains(String const& str, String const& substring) | ||||||
|  | { | ||||||
|  | 	StringHeader const& header = *rcast(StringHeader const*, scast(char const*, str) - sizeof(StringHeader)); | ||||||
|  |  | ||||||
|  | 	if (length(substring) > header.Length) | ||||||
|  | 		return false; | ||||||
|  |  | ||||||
|  | 	ssize main_len = header.Length; | ||||||
|  | 	ssize sub_len = length(substring); | ||||||
|  |  | ||||||
|  | 	for (ssize idx = 0; idx <= main_len - sub_len; ++idx) | ||||||
|  | 	{ | ||||||
|  | 		if (str_compare(str.Data + idx, substring.Data, sub_len) == 0) | ||||||
|  | 			return true; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline | ||||||
|  | ssize capacity(String const& str) { | ||||||
|  |    StringHeader const& header = *rcast(StringHeader const*, scast(char const*, str) - sizeof(StringHeader)); | ||||||
|    return header.Capacity; |    return header.Capacity; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	void clear() | inline | ||||||
| 	{ | void clear(String& str) { | ||||||
| 		get_header().Length = 0; |    get_header(str).Length = 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	String duplicate( AllocatorInfo allocator ) const | inline | ||||||
| 	{ | String duplicate(String const& str, AllocatorInfo allocator) { | ||||||
| 		return make_length( allocator, Data, length() ); |    return string_make_length(allocator, str, length(str)); | ||||||
| } | } | ||||||
|  |  | ||||||
| 	void free() | inline | ||||||
| 	{ | void free(String& str) { | ||||||
| 		if ( ! Data ) |    if (!str.Data) | ||||||
|    	return; |    	return; | ||||||
|  |  | ||||||
| 		Header& header = get_header(); |    StringHeader& header = get_header(str); | ||||||
|  |    GEN_NS free(header.Allocator, &header); | ||||||
| 		gen::free( header.Allocator, & header ); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| 	Header& get_header() | inline | ||||||
| 	{ | StringHeader& get_header(String& str) { | ||||||
| 		return *(Header*)(Data - sizeof(Header)); |    return *(StringHeader*)(str.Data - sizeof(StringHeader)); | ||||||
| } | } | ||||||
|  |  | ||||||
| 	ssize length() const | inline | ||||||
|  | ssize length(String const& str) | ||||||
| { | { | ||||||
| 		Header const& |    StringHeader const& header = *rcast(StringHeader const*, scast(char const*, str) - sizeof(StringHeader)); | ||||||
| 		header = * rcast( Header const*, Data - sizeof( Header )); |  | ||||||
|  |  | ||||||
|    return header.Length; |    return header.Length; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	b32 starts_with( StrC substring ) const | inline | ||||||
|  | bool make_space_for(String& str, char const* to_append, ssize add_len) | ||||||
| { | { | ||||||
| 		if (substring.Len > length()) | 	ssize available = avail_space(str); | ||||||
|  |  | ||||||
|  | 	if (available >= add_len) { | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		ssize new_len, old_size, new_size; | ||||||
|  | 		void* ptr; | ||||||
|  | 		void* new_ptr; | ||||||
|  |  | ||||||
|  | 		AllocatorInfo allocator = get_header(str).Allocator; | ||||||
|  | 		StringHeader* header = nullptr; | ||||||
|  |  | ||||||
|  | 		new_len = string_grow_formula(length(str) + add_len); | ||||||
|  | 		ptr = &get_header(str); | ||||||
|  | 		old_size = size_of(StringHeader) + length(str) + 1; | ||||||
|  | 		new_size = size_of(StringHeader) + new_len + 1; | ||||||
|  |  | ||||||
|  | 		new_ptr = resize(allocator, ptr, old_size, new_size); | ||||||
|  |  | ||||||
|  | 		if (new_ptr == nullptr) | ||||||
| 			return false; | 			return false; | ||||||
|  |  | ||||||
| 		b32 result = str_compare(Data, substring.Ptr, substring.Len ) == 0; | 		header = rcast(StringHeader*, new_ptr); | ||||||
|  | 		header->Allocator = allocator; | ||||||
|  | 		header->Capacity = new_len; | ||||||
|  |  | ||||||
|  | 		str.Data = rcast(char*, header + 1); | ||||||
|  |  | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline | ||||||
|  | b32 starts_with(String const& str, StrC substring) { | ||||||
|  | 	if (substring.Len > length(str)) | ||||||
|  | 	return false; | ||||||
|  |  | ||||||
|  | 	b32 result = str_compare(str.Data, substring.Ptr, substring.Len) == 0; | ||||||
| 	return result; | 	return result; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	b32 starts_with( String substring ) const | inline | ||||||
| 	{ | b32 starts_with(String const& str, String substring) { | ||||||
| 		if (substring.length() > length()) | 	if (length(substring) > length(str)) | ||||||
| 		return false; | 		return false; | ||||||
|  |  | ||||||
| 		b32 result = str_compare(Data, substring, substring.length() - 1 ) == 0; | 	b32 result = str_compare(str.Data, substring.Data, length(substring) - 1) == 0; | ||||||
| 	return result; | 	return result; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	void skip_line() | inline | ||||||
|  | void skip_line(String& str) | ||||||
| { | { | ||||||
| #define current (*scanner) | #define current (*scanner) | ||||||
| 		char* scanner = Data; | 	char* scanner = str.Data; | ||||||
| 		while ( current != '\r' && current != '\n' ) | 	while (current != '\r' && current != '\n') { | ||||||
| 		{ |  | ||||||
|  		++scanner; |  		++scanner; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 		s32 new_length = scanner - Data; | 	s32 new_length = scanner - str.Data; | ||||||
|  |  | ||||||
| 		if ( current == '\r' ) | 	if (current == '\r') { | ||||||
| 		{ |  | ||||||
| 		new_length += 1; | 		new_length += 1; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 		mem_move( Data, scanner, new_length ); | 	mem_move(str.Data, scanner, new_length); | ||||||
|  |  | ||||||
| 		Header* header = & get_header(); | 	StringHeader* header = &get_header(str); | ||||||
| 	header->Length = new_length; | 	header->Length = new_length; | ||||||
| #undef current | #undef current | ||||||
| } | } | ||||||
|  |  | ||||||
| 	void strip_space() | inline | ||||||
|  | void strip_space(String& str) | ||||||
| { | { | ||||||
| 		char* write_pos = Data; |    char* write_pos = str.Data; | ||||||
| 		char* read_pos  = Data; |    char* read_pos = str.Data; | ||||||
|  |  | ||||||
|    while (*read_pos) |    while (*read_pos) | ||||||
|    { |    { | ||||||
| @@ -268,15 +498,16 @@ struct String | |||||||
|    write_pos[0] = '\0';  // Null-terminate the modified string |    write_pos[0] = '\0';  // Null-terminate the modified string | ||||||
|  |  | ||||||
|    // Update the length if needed |    // Update the length if needed | ||||||
| 		get_header().Length = write_pos - Data; |    get_header(str).Length = write_pos - str.Data; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	void trim( char const* cut_set ) | inline | ||||||
|  | void trim(String& str, char const* cut_set) | ||||||
| { | { | ||||||
|    ssize len = 0; |    ssize len = 0; | ||||||
|  |  | ||||||
| 		char* start_pos = Data; |    char* start_pos = str.Data; | ||||||
| 		char* end_pos   = Data + length() - 1; |    char* end_pos = str.Data + length(str) - 1; | ||||||
|  |  | ||||||
|    while (start_pos <= end_pos && char_first_occurence(cut_set, *start_pos)) |    while (start_pos <= end_pos && char_first_occurence(cut_set, *start_pos)) | ||||||
|    	start_pos++; |    	start_pos++; | ||||||
| @@ -286,130 +517,64 @@ struct String | |||||||
|  |  | ||||||
|    len = scast(ssize, (start_pos > end_pos) ? 0 : ((end_pos - start_pos) + 1)); |    len = scast(ssize, (start_pos > end_pos) ? 0 : ((end_pos - start_pos) + 1)); | ||||||
|  |  | ||||||
| 		if ( Data != start_pos ) |    if (str.Data != start_pos) | ||||||
| 			mem_move( Data, start_pos, len ); |    	mem_move(str.Data, start_pos, len); | ||||||
|  |  | ||||||
| 		Data[ len ] = '\0'; |    str.Data[len] = '\0'; | ||||||
|  |  | ||||||
| 		get_header().Length = len; |    get_header(str).Length = len; | ||||||
| } | } | ||||||
|  |  | ||||||
| 	void trim_space() | inline | ||||||
| 	{ | void trim_space(String& str) { | ||||||
| 		return trim( " \t\r\n\v\f" ); |    trim(str, " \t\r\n\v\f"); | ||||||
| } | } | ||||||
|  |  | ||||||
| 	// Debug function that provides a copy of the string with whitespace characters visualized. | inline | ||||||
| 	String visualize_whitespace() const | String visualize_whitespace(String const& str) | ||||||
| { | { | ||||||
| 		Header* header = (Header*)(Data - sizeof(Header)); | 	StringHeader* header = (StringHeader*)(scast(char const*, str) - sizeof(StringHeader)); | ||||||
|  | 	String        result = string_make_reserve(header->Allocator, length(str) * 2); // Assume worst case for space requirements. | ||||||
|  |  | ||||||
| 		String result = make_reserve(header->Allocator, length() * 2); // Assume worst case for space requirements. | 	for (auto c : str) switch (c) | ||||||
|  |  | ||||||
| 		for ( char c : *this ) |  | ||||||
| 		{ |  | ||||||
| 			switch ( c ) |  | ||||||
| 	{ | 	{ | ||||||
| 		case ' ': | 		case ' ': | ||||||
| 					result.append( txt("·") ); | 			append(result, txt("·")); | ||||||
| 		break; | 		break; | ||||||
| 		case '\t': | 		case '\t': | ||||||
| 					result.append( txt("→") ); | 			append(result, txt("→")); | ||||||
| 		break; | 		break; | ||||||
| 		case '\n': | 		case '\n': | ||||||
| 					result.append( txt("↵") ); | 			append(result, txt("↵")); | ||||||
| 		break; | 		break; | ||||||
| 		case '\r': | 		case '\r': | ||||||
| 					result.append( txt("⏎") ); | 			append(result, txt("⏎")); | ||||||
| 		break; | 		break; | ||||||
| 		case '\v': | 		case '\v': | ||||||
| 					result.append( txt("⇕") ); | 			append(result, txt("⇕")); | ||||||
| 		break; | 		break; | ||||||
| 		case '\f': | 		case '\f': | ||||||
| 					result.append( txt("⌂") ); | 			append(result, txt("⌂")); | ||||||
| 		break; | 		break; | ||||||
| 		default: | 		default: | ||||||
| 					result.append(c); | 			append(result, c); | ||||||
| 		break; | 		break; | ||||||
| 	} | 	} | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 	return result; | 	return result; | ||||||
| } | } | ||||||
|  | #pragma endregion String | ||||||
|  |  | ||||||
| 	// For-range support | struct String_POD { | ||||||
|  |  | ||||||
| 	char* begin() const |  | ||||||
| 	{ |  | ||||||
| 		return Data; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	char* end() const |  | ||||||
| 	{ |  | ||||||
| 		Header const& |  | ||||||
| 		header = * rcast( Header const*, Data - sizeof( Header )); |  | ||||||
|  |  | ||||||
| 		return Data + header.Length; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	operator bool() |  | ||||||
| 	{ |  | ||||||
| 		return Data != nullptr; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	operator char* () |  | ||||||
| 	{ |  | ||||||
| 		return Data; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	operator char const* () const |  | ||||||
| 	{ |  | ||||||
| 		return Data; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	operator StrC() const |  | ||||||
| 	{ |  | ||||||
| 		return { length(), Data }; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Used with cached strings |  | ||||||
| 	// Essentially makes the string a string view. |  | ||||||
| 	String const& operator = ( String const& other ) const |  | ||||||
| 	{ |  | ||||||
| 		if ( this == & other ) |  | ||||||
| 			return *this; |  | ||||||
|  |  | ||||||
| 		String* |  | ||||||
| 		this_ = ccast(String*, this); |  | ||||||
| 		this_->Data = other.Data; |  | ||||||
|  |  | ||||||
| 		return *this; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	char& operator [] ( ssize index ) |  | ||||||
| 	{ |  | ||||||
| 		return Data[ index ]; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	char const& operator [] ( ssize index ) const |  | ||||||
| 	{ |  | ||||||
| 		return Data[ index ]; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	char* Data; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| struct String_POD |  | ||||||
| { |  | ||||||
| 	char* Data; | 	char* Data; | ||||||
| }; | }; | ||||||
| static_assert( sizeof( String_POD ) == sizeof( String ), "String is not a POD" ); | static_assert( sizeof( String_POD ) == sizeof( String ), "String is not a POD" ); | ||||||
|  |  | ||||||
| // Implements basic string interning. Data structure is based off the ZPL Hashtable. | // Implements basic string interning. Data structure is based off the ZPL Hashtable. | ||||||
| using StringTable = HashTable<String const>; | typedef HashTable<String const>   StringTable; | ||||||
|  |  | ||||||
| // Represents strings cached with the string table. | // Represents strings cached with the string table. | ||||||
| // Should never be modified, if changed string is desired, cache_string( str ) another. | // Should never be modified, if changed string is desired, cache_string( str ) another. | ||||||
| using StringCached = String const; | typedef String const   StringCached; | ||||||
|  |  | ||||||
| #pragma endregion Strings | #pragma endregion Strings | ||||||
|   | |||||||
| @@ -11,23 +11,23 @@ using namespace gen; | |||||||
| CodeBody gen_ecode( char const* path ) | CodeBody gen_ecode( char const* path ) | ||||||
| { | { | ||||||
| 	char  scratch_mem[kilobytes(1)]; | 	char  scratch_mem[kilobytes(1)]; | ||||||
| 	Arena scratch = Arena::init_from_memory( scratch_mem, sizeof(scratch_mem) ); | 	Arena scratch = arena_init_from_memory( scratch_mem, sizeof(scratch_mem) ); | ||||||
|  |  | ||||||
| 	file_read_contents( scratch, zero_terminate, path ); | 	file_read_contents( allocator_info(scratch), zero_terminate, path ); | ||||||
|  |  | ||||||
| 	CSV_Object csv_nodes; | 	CSV_Object csv_nodes; | ||||||
| 	csv_parse( &csv_nodes, scratch_mem, GlobalAllocator, false ); | 	csv_parse( &csv_nodes, scratch_mem, GlobalAllocator, false ); | ||||||
|  |  | ||||||
| 	Array<ADT_Node> enum_strs = csv_nodes.nodes[0].nodes; | 	Array<ADT_Node> enum_strs = csv_nodes.nodes[0].nodes; | ||||||
|  |  | ||||||
| 	String enum_entries   = String::make_reserve( GlobalAllocator, kilobytes(1) ); | 	String enum_entries   = string_make_reserve( GlobalAllocator, kilobytes(1) ); | ||||||
| 	String to_str_entries = String::make_reserve( GlobalAllocator, kilobytes(1) ); | 	String to_str_entries = string_make_reserve( GlobalAllocator, kilobytes(1) ); | ||||||
|  |  | ||||||
| 	for ( ADT_Node node : enum_strs ) | 	for ( ADT_Node node : enum_strs ) | ||||||
| 	{ | 	{ | ||||||
| 		char const* code = node.string; | 		char const* code = node.string; | ||||||
| 		enum_entries.append_fmt( "%s,\n", code ); | 		append_fmt( enum_entries, "%s,\n", code ); | ||||||
| 		to_str_entries.append_fmt( "{ sizeof(\"%s\"), \"%s\" },\n", code, code ); | 		append_fmt( to_str_entries, "{ sizeof(\"%s\"), \"%s\" },\n", code, code ); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	CodeEnum enum_code = parse_enum(gen::token_fmt_impl((3 + 1) / 2, "entries", (StrC)enum_entries, "enum Type : u32 { <entries> NumTypes };")); | 	CodeEnum enum_code = parse_enum(gen::token_fmt_impl((3 + 1) / 2, "entries", (StrC)enum_entries, "enum Type : u32 { <entries> NumTypes };")); | ||||||
| @@ -57,9 +57,9 @@ CodeBody gen_ecode( char const* path ) | |||||||
| CodeBody gen_eoperator( char const* path ) | CodeBody gen_eoperator( char const* path ) | ||||||
| { | { | ||||||
| 	char scratch_mem[kilobytes(4)]; | 	char scratch_mem[kilobytes(4)]; | ||||||
| 	Arena scratch = Arena::init_from_memory( scratch_mem, sizeof(scratch_mem) ); | 	Arena scratch = arena_init_from_memory( scratch_mem, sizeof(scratch_mem) ); | ||||||
|  |  | ||||||
| 	file_read_contents( scratch, zero_terminate, path ); | 	file_read_contents( allocator_info(scratch), zero_terminate, path ); | ||||||
|  |  | ||||||
| 	CSV_Object csv_nodes; | 	CSV_Object csv_nodes; | ||||||
| 	csv_parse( &csv_nodes, scratch_mem, GlobalAllocator, false ); | 	csv_parse( &csv_nodes, scratch_mem, GlobalAllocator, false ); | ||||||
| @@ -67,16 +67,16 @@ CodeBody gen_eoperator( char const* path ) | |||||||
| 	Array<ADT_Node> enum_strs = csv_nodes.nodes[0].nodes; | 	Array<ADT_Node> enum_strs = csv_nodes.nodes[0].nodes; | ||||||
| 	Array<ADT_Node> str_strs  = csv_nodes.nodes[1].nodes; | 	Array<ADT_Node> str_strs  = csv_nodes.nodes[1].nodes; | ||||||
|  |  | ||||||
| 	String enum_entries   = String::make_reserve( GlobalAllocator, kilobytes(1) ); | 	String enum_entries   = string_make_reserve( GlobalAllocator, kilobytes(1) ); | ||||||
| 	String to_str_entries = String::make_reserve( GlobalAllocator, kilobytes(1) ); | 	String to_str_entries = string_make_reserve( GlobalAllocator, kilobytes(1) ); | ||||||
|  |  | ||||||
| 	for (usize idx = 0; idx < enum_strs.num(); idx++) | 	for (usize idx = 0; idx < num(enum_strs); idx++) | ||||||
| 	{ | 	{ | ||||||
| 		char const* enum_str     = enum_strs[idx].string; | 		char const* enum_str     = enum_strs[idx].string; | ||||||
| 		char const* entry_to_str = str_strs [idx].string; | 		char const* entry_to_str = str_strs [idx].string; | ||||||
|  |  | ||||||
| 		enum_entries.append_fmt( "%s,\n", enum_str ); | 		append_fmt( enum_entries, "%s,\n", enum_str ); | ||||||
| 		to_str_entries.append_fmt( "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str); | 		append_fmt( to_str_entries, "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	CodeEnum  enum_code = parse_enum(token_fmt("entries", (StrC)enum_entries, stringize( | 	CodeEnum  enum_code = parse_enum(token_fmt("entries", (StrC)enum_entries, stringize( | ||||||
| @@ -113,9 +113,9 @@ CodeBody gen_eoperator( char const* path ) | |||||||
| CodeBody gen_especifier( char const* path ) | CodeBody gen_especifier( char const* path ) | ||||||
| { | { | ||||||
| 	char scratch_mem[kilobytes(4)]; | 	char scratch_mem[kilobytes(4)]; | ||||||
| 	Arena scratch = Arena::init_from_memory( scratch_mem, sizeof(scratch_mem) ); | 	Arena scratch = arena_init_from_memory( scratch_mem, sizeof(scratch_mem) ); | ||||||
|  |  | ||||||
| 	file_read_contents( scratch, zero_terminate, path ); | 	file_read_contents( allocator_info(scratch), zero_terminate, path ); | ||||||
|  |  | ||||||
| 	CSV_Object csv_nodes; | 	CSV_Object csv_nodes; | ||||||
| 	csv_parse( &csv_nodes, scratch_mem, GlobalAllocator, false ); | 	csv_parse( &csv_nodes, scratch_mem, GlobalAllocator, false ); | ||||||
| @@ -123,16 +123,16 @@ CodeBody gen_especifier( char const* path ) | |||||||
| 	Array<ADT_Node> enum_strs = csv_nodes.nodes[0].nodes; | 	Array<ADT_Node> enum_strs = csv_nodes.nodes[0].nodes; | ||||||
| 	Array<ADT_Node> str_strs  = csv_nodes.nodes[1].nodes; | 	Array<ADT_Node> str_strs  = csv_nodes.nodes[1].nodes; | ||||||
|  |  | ||||||
| 	String enum_entries   = String::make_reserve( GlobalAllocator, kilobytes(1) ); | 	String enum_entries   = string_make_reserve( GlobalAllocator, kilobytes(1) ); | ||||||
| 	String to_str_entries = String::make_reserve( GlobalAllocator, kilobytes(1) ); | 	String to_str_entries = string_make_reserve( GlobalAllocator, kilobytes(1) ); | ||||||
|  |  | ||||||
| 	for (usize idx = 0; idx < enum_strs.num(); idx++) | 	for (usize idx = 0; idx < num(enum_strs); idx++) | ||||||
| 	{ | 	{ | ||||||
| 		char const* enum_str     = enum_strs[idx].string; | 		char const* enum_str     = enum_strs[idx].string; | ||||||
| 		char const* entry_to_str = str_strs [idx].string; | 		char const* entry_to_str = str_strs [idx].string; | ||||||
|  |  | ||||||
| 		enum_entries.append_fmt( "%s,\n", enum_str ); | 		append_fmt( enum_entries, "%s,\n", enum_str ); | ||||||
| 		to_str_entries.append_fmt( "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str); | 		append_fmt( to_str_entries, "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	CodeEnum  enum_code = parse_enum(token_fmt("entries", (StrC)enum_entries, stringize( | 	CodeEnum  enum_code = parse_enum(token_fmt("entries", (StrC)enum_entries, stringize( | ||||||
| @@ -218,14 +218,16 @@ CodeBody gen_especifier( char const* path ) | |||||||
| CodeBody gen_etoktype( char const* etok_path, char const* attr_path ) | CodeBody gen_etoktype( char const* etok_path, char const* attr_path ) | ||||||
| { | { | ||||||
| 	char  scratch_mem[kilobytes(16)]; | 	char  scratch_mem[kilobytes(16)]; | ||||||
| 	Arena scratch = Arena::init_from_memory( scratch_mem, sizeof(scratch_mem) ); | 	Arena scratch = arena_init_from_memory( scratch_mem, sizeof(scratch_mem) ); | ||||||
|  |  | ||||||
| 	FileContents enum_content = file_read_contents( scratch, zero_terminate, etok_path ); | 	AllocatorInfo scratch_info = allocator_info(scratch); | ||||||
|  |  | ||||||
|  | 	FileContents enum_content = file_read_contents( scratch_info, zero_terminate, etok_path ); | ||||||
|  |  | ||||||
| 	CSV_Object csv_enum_nodes; | 	CSV_Object csv_enum_nodes; | ||||||
| 	csv_parse( &csv_enum_nodes, rcast(char*, enum_content.data), GlobalAllocator, false ); | 	csv_parse( &csv_enum_nodes, rcast(char*, enum_content.data), GlobalAllocator, false ); | ||||||
|  |  | ||||||
| 	FileContents attrib_content = file_read_contents( scratch, zero_terminate, attr_path ); | 	FileContents attrib_content = file_read_contents( scratch_info, zero_terminate, attr_path ); | ||||||
|  |  | ||||||
| 	CSV_Object csv_attr_nodes; | 	CSV_Object csv_attr_nodes; | ||||||
| 	csv_parse( &csv_attr_nodes, rcast(char*, attrib_content.data), GlobalAllocator, false ); | 	csv_parse( &csv_attr_nodes, rcast(char*, attrib_content.data), GlobalAllocator, false ); | ||||||
| @@ -235,34 +237,34 @@ CodeBody gen_etoktype( char const* etok_path, char const* attr_path ) | |||||||
| 	Array<ADT_Node> attribute_strs     = csv_attr_nodes.nodes[0].nodes; | 	Array<ADT_Node> attribute_strs     = csv_attr_nodes.nodes[0].nodes; | ||||||
| 	Array<ADT_Node> attribute_str_strs = csv_attr_nodes.nodes[1].nodes; | 	Array<ADT_Node> attribute_str_strs = csv_attr_nodes.nodes[1].nodes; | ||||||
|  |  | ||||||
| 	String enum_entries             = String::make_reserve( GlobalAllocator, kilobytes(2) ); | 	String enum_entries             = string_make_reserve( GlobalAllocator, kilobytes(2) ); | ||||||
| 	String to_str_entries           = String::make_reserve( GlobalAllocator, kilobytes(4) ); | 	String to_str_entries           = string_make_reserve( GlobalAllocator, kilobytes(4) ); | ||||||
| 	String attribute_entries        = String::make_reserve( GlobalAllocator, kilobytes(2) ); | 	String attribute_entries        = string_make_reserve( GlobalAllocator, kilobytes(2) ); | ||||||
| 	String to_str_attributes        = String::make_reserve( GlobalAllocator, kilobytes(4) ); | 	String to_str_attributes        = string_make_reserve( GlobalAllocator, kilobytes(4) ); | ||||||
| 	String attribute_define_entries = String::make_reserve( GlobalAllocator, kilobytes(4) ); | 	String attribute_define_entries = string_make_reserve( GlobalAllocator, kilobytes(4) ); | ||||||
|  |  | ||||||
| 	for (usize idx = 0; idx < enum_strs.num(); idx++) | 	for (usize idx = 0; idx < num(enum_strs); idx++) | ||||||
| 	{ | 	{ | ||||||
| 		char const* enum_str     = enum_strs[idx].string; | 		char const* enum_str     = enum_strs[idx].string; | ||||||
| 		char const* entry_to_str = enum_str_strs [idx].string; | 		char const* entry_to_str = enum_str_strs [idx].string; | ||||||
|  |  | ||||||
| 		enum_entries.append_fmt( "%s,\n", enum_str ); | 		append_fmt( enum_entries, "%s,\n", enum_str ); | ||||||
| 		to_str_entries.append_fmt( "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str); | 		append_fmt( to_str_entries, "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	for ( usize idx = 0; idx < attribute_strs.num(); idx++ ) | 	for ( usize idx = 0; idx < num(attribute_strs); idx++ ) | ||||||
| 	{ | 	{ | ||||||
| 		char const* attribute_str = attribute_strs[idx].string; | 		char const* attribute_str = attribute_strs[idx].string; | ||||||
| 		char const* entry_to_str  = attribute_str_strs [idx].string; | 		char const* entry_to_str  = attribute_str_strs [idx].string; | ||||||
|  |  | ||||||
| 		attribute_entries.append_fmt( "Attribute_%s,\n", attribute_str ); | 		append_fmt( attribute_entries, "Attribute_%s,\n", attribute_str ); | ||||||
| 		to_str_attributes.append_fmt( "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str); | 		append_fmt( to_str_attributes, "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str); | ||||||
| 		attribute_define_entries.append_fmt( "Entry( Attribute_%s, \"%s\" )", attribute_str, entry_to_str ); | 		append_fmt( attribute_define_entries, "Entry( Attribute_%s, \"%s\" )", attribute_str, entry_to_str ); | ||||||
|  |  | ||||||
| 		if ( idx < attribute_strs.num() - 1 ) | 		if ( idx < num(attribute_strs) - 1 ) | ||||||
| 			attribute_define_entries.append( " \\\n"); | 			append( attribute_define_entries, " \\\n"); | ||||||
| 		else | 		else | ||||||
| 			attribute_define_entries.append( "\n"); | 			append( attribute_define_entries, "\n"); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| #pragma push_macro("GEN_DEFINE_ATTRIBUTE_TOKENS") | #pragma push_macro("GEN_DEFINE_ATTRIBUTE_TOKENS") | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								project/helpers/member_proc_support.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								project/helpers/member_proc_support.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "gen.hpp" | ||||||
|  |  | ||||||
|  | GEN_NS_BEGIN | ||||||
|  | #include "dependencies/parsing.hpp" | ||||||
|  | GEN_NS_END | ||||||
|  |  | ||||||
|  | using namespace gen; | ||||||
|  |  | ||||||
| @@ -44,6 +44,7 @@ Push-Location $path_root | |||||||
| 	   $verbose      = $false | 	   $verbose      = $false | ||||||
| [bool] $bootstrap    = $false | [bool] $bootstrap    = $false | ||||||
| [bool] $singleheader = $false | [bool] $singleheader = $false | ||||||
|  | [bool] $c_library    = $false | ||||||
| [bool] $unreal       = $false | [bool] $unreal       = $false | ||||||
| [bool] $test         = $false | [bool] $test         = $false | ||||||
|  |  | ||||||
| @@ -59,6 +60,7 @@ if ( $args ) { $args | ForEach-Object { | |||||||
| 		"debug"               { $release      = $false } | 		"debug"               { $release      = $false } | ||||||
| 		"bootstrap"           { $bootstrap    = $true } | 		"bootstrap"           { $bootstrap    = $true } | ||||||
| 		"singleheader"        { $singleheader = $true } | 		"singleheader"        { $singleheader = $true } | ||||||
|  | 		"c_library"           { $c_library    = $true } | ||||||
| 		"unreal"              { $unreal       = $true } | 		"unreal"              { $unreal       = $true } | ||||||
| 		"test"                { $test         = $true } | 		"test"                { $test         = $true } | ||||||
| 	} | 	} | ||||||
| @@ -88,7 +90,7 @@ else { | |||||||
| 	$optimize = $true | 	$optimize = $true | ||||||
| } | } | ||||||
|  |  | ||||||
| if ( $bootstrap -eq $false -and $singleheader -eq $false -and $unreal -eq $false -and $test -eq $false ) { | if ( $bootstrap -eq $false -and $singleheader -eq $false -and $c_library -eq $false -and $unreal -eq $false -and $test -eq $false ) { | ||||||
| 	throw "No build target specified. One must be specified, this script will not assume one" | 	throw "No build target specified. One must be specified, this script will not assume one" | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -103,8 +105,9 @@ write-host "Build Type: $(if ($release) {"Release"} else {"Debug"} )" | |||||||
| $path_build        = Join-Path $path_root build | $path_build        = Join-Path $path_root build | ||||||
| $path_project      = Join-Path $path_root project | $path_project      = Join-Path $path_root project | ||||||
| $path_scripts      = Join-Path $path_root scripts | $path_scripts      = Join-Path $path_root scripts | ||||||
| $path_singleheader = Join-Path $path_root singleheader | $path_c_library    = join-Path $path_root gen_c_library | ||||||
| $path_unreal       = Join-Path $path_root unreal_engine | $path_singleheader = Join-Path $path_root gen_singleheader | ||||||
|  | $path_unreal       = Join-Path $path_root gen_unreal_engine | ||||||
| $path_test         = Join-Path $path_root test | $path_test         = Join-Path $path_root test | ||||||
|  |  | ||||||
| if ( $bootstrap ) | if ( $bootstrap ) | ||||||
| @@ -187,6 +190,44 @@ if ( $singleheader ) | |||||||
| 	Pop-Location | 	Pop-Location | ||||||
| } | } | ||||||
|  |  | ||||||
|  | if ( $c_library ) | ||||||
|  | { | ||||||
|  | 	$path_build = join-path $path_c_library build | ||||||
|  | 	$path_gen   = join-path $path_c_library gen | ||||||
|  |  | ||||||
|  | 	if ( -not(Test-Path($path_build) )) { | ||||||
|  | 		New-Item -ItemType Directory -Path $path_build | ||||||
|  | 	} | ||||||
|  | 	if ( -not(Test-Path($path_gen) )) { | ||||||
|  | 		New-Item -ItemType Directory -Path $path_gen | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	$includes    = @( $path_project ) | ||||||
|  | 	$unit       = join-path $path_c_library "c_library.cpp" | ||||||
|  | 	$executable = join-path $path_build     "c_library.exe" | ||||||
|  |  | ||||||
|  | 	$compiler_args = @() | ||||||
|  | 	$compiler_args += ( $flag_define + 'GEN_TIME' ) | ||||||
|  |  | ||||||
|  | 	$linker_args   = @( | ||||||
|  | 		$flag_link_win_subsystem_console | ||||||
|  | 	) | ||||||
|  |  | ||||||
|  | 	build-simple $path_build $includes $compiler_args $linker_args $unit $executable | ||||||
|  |  | ||||||
|  | 	Push-Location $path_c_library | ||||||
|  | 		if ( Test-Path( $executable ) ) { | ||||||
|  | 			write-host "`nRunning c_library generator" | ||||||
|  | 			$time_taken = Measure-Command { & $executable | ||||||
|  | 					| ForEach-Object { | ||||||
|  | 						write-host `t $_ -ForegroundColor Green | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			write-host "`nc_library generator completed in $($time_taken.TotalMilliseconds) ms" | ||||||
|  | 		} | ||||||
|  | 	Pop-Location | ||||||
|  | } | ||||||
|  |  | ||||||
| if ( $unreal ) | if ( $unreal ) | ||||||
| { | { | ||||||
| 	$path_build = join-path $path_unreal build | 	$path_build = join-path $path_unreal build | ||||||
|   | |||||||
							
								
								
									
										24
									
								
								scripts/c_library.refactor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								scripts/c_library.refactor
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | |||||||
|  |  __VERSION 1 | ||||||
|  |  | ||||||
|  | // This is a example template to be used with the refactor program | ||||||
|  | // Use it to refactor the naming convention of this library to your own. | ||||||
|  | // Can be used as an aid to help use use your project's implementation if it fullfills the dependencies of this project. | ||||||
|  | // Example: Most likely have a memory and string library already, just rename the functions and make sure the args are the same. | ||||||
|  | // Program: https://github.com/Ed94/refactor | ||||||
|  |  | ||||||
|  | // NOTE: Due to the current limitations of the program, not every symbol in the library can be renamed. | ||||||
|  | // This is due to the program not actually parsing C/C++. | ||||||
|  |  | ||||||
|  | // not       : Ignore | ||||||
|  | // include   : #includes | ||||||
|  | // word      : Alphanumeric or underscore | ||||||
|  | // namespace : Prefix search and replace (c-namspaces). | ||||||
|  | // regex     : Unavailable in __VERSION 1. | ||||||
|  |  | ||||||
|  | // Precedence (highest to lowest): | ||||||
|  | // word, namespace, regex | ||||||
|  |  | ||||||
|  | // Gen Macro namespace | ||||||
|  | // namespace GEN_, new_namespace_ | ||||||
|  |  | ||||||
|  | // TODO(Ed): This will be large as nearly all symbols will need to optionally support getting prefixed with gen_ or something else the user wants. | ||||||
							
								
								
									
										0
									
								
								scripts/refactor_c_library.ps1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								scripts/refactor_c_library.ps1
									
									
									
									
									
										Normal file
									
								
							
		Reference in New Issue
	
	Block a user