mirror of
				https://github.com/Ed94/gencpp.git
				synced 2025-10-31 06:50:53 -07:00 
			
		
		
		
	Compare commits
	
		
			34 Commits
		
	
	
		
			v0.19-Alph
			...
			c38b077c37
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| c38b077c37 | |||
| f9b5029e64 | |||
| 2b24511f7d | |||
| 5cd69e1742 | |||
| 007bfa0cb0 | |||
| 37c33ffb3e | |||
| 937235b776 | |||
| f9c21ebc04 | |||
| fec709cc76 | |||
| 80cb3f4eca | |||
| 9e88cb8724 | |||
| f61c1c560d | |||
| 8ef982003a | |||
| 31691b1466 | |||
| 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 | ||||
| singleheader/gen/scratch.hpp | ||||
| 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", | ||||
| 		"android_native_app_glue.h": "c", | ||||
| 		"raylib.h": "c", | ||||
| 		"*.m": "cpp" | ||||
| 		"*.m": "cpp", | ||||
| 		"atomic": "cpp", | ||||
| 		"gen.h": "c", | ||||
| 		"string_ops.hpp": "c" | ||||
| 	}, | ||||
| 	"C_Cpp.intelliSenseEngineFallback": "disabled", | ||||
| 	"mesonbuild.configureOnOpen": true, | ||||
|   | ||||
| @@ -25,6 +25,8 @@ This library was written in a subset of C++ where the following are not used at | ||||
| * Exceptions | ||||
|  | ||||
| Polymorphic & Member-functions are used as an ergonomic choice, along with a conserative use of operator overloads.   | ||||
| The base library itself does not use anything but C-like features to allow for generating a derviative compatiable with C (WIP). | ||||
|  | ||||
| There are only 4 template definitions in the entire library. (`Array<Type>`, `Hashtable<Type>`, `swap<Type>`, and `AST/Code::cast<Type>`) | ||||
|  | ||||
| Two generic templated containers are used throughout the library: | ||||
|   | ||||
							
								
								
									
										398
									
								
								gen_c_library/c_library.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										398
									
								
								gen_c_library/c_library.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,398 @@ | ||||
| #define GEN_DEFINE_LIBRARY_CODE_CONSTANTS | ||||
| #define GEN_ENFORCE_STRONG_CODE_TYPES | ||||
| #define GEN_EXPOSE_BACKEND | ||||
| #define GEN_SUPPORT_CPP_MEMBER_FEATURES 1 | ||||
| #define GEN_SUPPORT_CPP_REFERENCES      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 } ); | ||||
| 	log_fmt("\nParsed: %s\n", path); | ||||
| 	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::Global_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.code_cast<CodeUsing>(); | ||||
| 					CodeTypedef typedef_ver = def_typedef(using_ver->Name, using_ver->UnderlyingType); | ||||
|  | ||||
| 					memory.append(typedef_ver); | ||||
| 				} | ||||
| 				break; | ||||
| 				case ECode::Function_Fwd: | ||||
| 				{ | ||||
| 					CodeFn fn = entry.code_cast<CodeFn>(); | ||||
| 					if ( fn->Name.is_equal(txt("free")) ) | ||||
| 					{ | ||||
| 						fn->Name = get_cached_string(txt("gen_free_ptr")); | ||||
| 					} | ||||
| 					memory.append(entry); | ||||
| 				} | ||||
| 				break; | ||||
| 				case ECode::Function: | ||||
| 				{ | ||||
| 					CodeFn fn = entry.code_cast<CodeFn>(); | ||||
| 					s32 constexpr_found = fn->Specs.remove( ESpecifier::Constexpr ); | ||||
| 					if (constexpr_found > -1) { | ||||
| 						log_fmt("Found constexpr: %S\n", entry->to_string()); | ||||
| 						fn->Specs.append(ESpecifier::Inline); | ||||
| 					} | ||||
| 					if ( fn->Name.is_equal(txt("free")) ) | ||||
| 					{ | ||||
| 						fn->Name = get_cached_string(txt("gen_free_ptr")); | ||||
| 					} | ||||
| 					memory.append(entry); | ||||
| 				} | ||||
| 				break; | ||||
| 				case ECode::Template: | ||||
| 				{ | ||||
| 					CodeTemplate tmpl = entry.code_cast<CodeTemplate>(); | ||||
| 					if ( tmpl->Declaration->Name.contains(txt("swap"))) | ||||
| 					{ | ||||
| 						CodeBody macro_swap = parse_global_body( txt(R"( | ||||
| #define swap( a, b )              \ | ||||
| 	do                            \ | ||||
| 	{                             \ | ||||
| 		typeof( a ) temp = ( a ); \ | ||||
| 		( a )            = ( b ); \ | ||||
| 		( b )            = temp;  \ | ||||
| 	} while ( 0 ) | ||||
| )" | ||||
| 						)); | ||||
| 						memory.append(macro_swap); | ||||
| 					} | ||||
| 				} | ||||
| 				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: | ||||
| 				{ | ||||
| 					b32 found = ignore_preprocess_cond_block(txt("GEN_SUPPORT_CPP_MEMBER_FEATURES"), entry, parsed_memory ); | ||||
| 					if (found) break; | ||||
|  | ||||
| 					memory.append(entry); | ||||
| 				} | ||||
| 				break; | ||||
| 				case ECode::Preprocess_IfDef: | ||||
| 				{ | ||||
| 					b32 found = ignore_preprocess_cond_block(txt("GEN_INTELLISENSE_DIRECTIVES"), entry, parsed_memory ); | ||||
| 					if (found) break; | ||||
|  | ||||
| 					memory.append(entry); | ||||
| 				} | ||||
| 				break; | ||||
| 				case ECode::Preprocess_Pragma: | ||||
| 				{ | ||||
| 					b32 found = swap_pragma_region_implementation( txt("FixedArena"), gen_fixed_arenas, entry, memory); | ||||
| 					if (found) break; | ||||
|  | ||||
| 					memory.append(entry); | ||||
| 				} | ||||
| 				break; | ||||
| 				default: { | ||||
| 					memory.append(entry); | ||||
| 				} | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 		header.print( dump_to_scratch_and_retireve(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::Global_Body); | ||||
| 		for ( Code entry = printing_parsed.begin(); entry != printing_parsed.end(); ++ entry ) | ||||
| 		{ | ||||
| 			switch (entry->Type) | ||||
| 			{ | ||||
| 				case ECode::Preprocess_IfDef: | ||||
| 				{ | ||||
| 					b32 found = ignore_preprocess_cond_block(txt("GEN_INTELLISENSE_DIRECTIVES"), entry, printing_parsed ); | ||||
| 					if (found) break; | ||||
|  | ||||
| 					printing.append(entry); | ||||
| 				} | ||||
| 				break; | ||||
| 				case ECode::Variable: | ||||
| 				{ | ||||
| 					if (contains(entry->Name, txt("Msg_Invalid_Value"))) | ||||
| 					{ | ||||
| 						CodeDefine define = def_define(entry->Name, entry->Value->Content); | ||||
| 						printing.append(define); | ||||
| 						continue; | ||||
| 					} | ||||
| 					printing.append(entry); | ||||
| 				} | ||||
| 				break; | ||||
| 				default: | ||||
| 					printing.append(entry); | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 		header.print(dump_to_scratch_and_retireve(printing)); | ||||
|  | ||||
| 		CodeBody containers = def_body(ECode::Global_Body); | ||||
| 		{ | ||||
| 			containers.append( def_pragma(code(region Containers))); | ||||
|  | ||||
| 			containers.append( gen_array_base() ); | ||||
| 			containers.append( gen_hashtable_base() ); | ||||
|  | ||||
| 			containers.append( def_pragma(code(endregion Containers))); | ||||
| 		} | ||||
| 		header.print(fmt_newline); | ||||
| 		header.print(dump_to_scratch_and_retireve(containers)); | ||||
|  | ||||
| 		Code hashing = scan_file( project_dir "dependencies/hashing.hpp" ); | ||||
| 		header.print( hashing ); | ||||
|  | ||||
| 		CodeBody parsed_strings = parse_file( project_dir "dependencies/strings.hpp" ); | ||||
| 		CodeBody strings        = def_body(ECode::Global_Body); | ||||
| 		for ( Code entry = parsed_strings.begin(); entry != parsed_strings.end(); ++ entry ) | ||||
| 		{ | ||||
| 			switch (entry->Type) | ||||
| 			{ | ||||
| 				case ECode::Preprocess_If: | ||||
| 				{ | ||||
| 					ignore_preprocess_cond_block(txt("! GEN_COMPILER_C"), entry, parsed_strings); | ||||
| 				} | ||||
| 				break; | ||||
|  | ||||
| 				case ECode::Preprocess_IfDef: | ||||
| 				{ | ||||
| 					ignore_preprocess_cond_block(txt("GEN_INTELLISENSE_DIRECTIVES"), entry, parsed_strings ); | ||||
| 				} | ||||
| 				break; | ||||
|  | ||||
| 				case ECode::Struct_Fwd: | ||||
| 				{ | ||||
| 					if ( entry->Name.is_equal(txt("String")) ) | ||||
| 					{ | ||||
| 						CodeTypedef c_def = parse_typedef(code( typedef char* String; )); | ||||
| 						strings.append(c_def); | ||||
| 						strings.append(fmt_newline); | ||||
| 						++ entry; | ||||
| 						continue; | ||||
| 					} | ||||
| 					strings.append(entry); | ||||
| 				} | ||||
| 				break; | ||||
|  | ||||
| 				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: | ||||
| 						{ | ||||
| 							b32 found = ignore_preprocess_cond_block(txt("! GEN_COMPILER_C"), body_entry, body ); | ||||
| 							if (found) break; | ||||
|  | ||||
| 							new_body.append(body_entry); | ||||
| 						} | ||||
| 						break; | ||||
| 						default: | ||||
| 							new_body.append(body_entry); | ||||
| 						break; | ||||
| 					} | ||||
| 					entry->Body = rcast(AST*, new_body.ast); | ||||
| 					strings.append(entry); | ||||
| 				} | ||||
| 				break; | ||||
|  | ||||
| 				default: | ||||
| 					strings.append(entry); | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 		header.print(dump_to_scratch_and_retireve(strings)); | ||||
|  | ||||
| 		Code filesystem = scan_file( project_dir "dependencies/filesystem.hpp" ); | ||||
| 		Code timing = scan_file( project_dir "dependencies/timing.hpp" ); | ||||
| 		// header.print( filesystem ); | ||||
| 		// header.print( timing ); | ||||
|  | ||||
| 		header.print_fmt( "\nGEN_NS_END\n" ); | ||||
| 		header.print_fmt( roll_own_dependencies_guard_end ); | ||||
|  | ||||
| 		Code types      = scan_file( project_dir "components/types.hpp" ); | ||||
| 		Code ast        = scan_file( project_dir "components/ast.hpp" ); | ||||
| 		Code ast_types  = scan_file( project_dir "components/ast_types.hpp" ); | ||||
| 		Code code_types = scan_file( project_dir "components/code_types.hpp" ); | ||||
| 		Code interface  = scan_file( project_dir "components/interface.hpp" ); | ||||
| 		Code inlines 	= scan_file( project_dir "components/inlines.hpp" ); | ||||
| 		Code header_end = scan_file( project_dir "components/header_end.hpp" ); | ||||
|  | ||||
| 		CodeBody ecode       = gen_ecode     ( project_dir "enums/ECode.csv" ); | ||||
| 		CodeBody eoperator   = gen_eoperator ( project_dir "enums/EOperator.csv" ); | ||||
| 		CodeBody especifier  = gen_especifier( project_dir "enums/ESpecifier.csv" ); | ||||
| 		CodeBody ast_inlines = gen_ast_inlines(); | ||||
|  | ||||
| #if 0 | ||||
| 		header.print_fmt("#pragma region Types\n"); | ||||
| 		header.print( types ); | ||||
| 		header.print( fmt_newline ); | ||||
| 		header.print( dump_to_scratch_and_retireve( ecode )); | ||||
| 		header.print( fmt_newline ); | ||||
| 		header.print( dump_to_scratch_and_retireve( eoperator )); | ||||
| 		header.print( fmt_newline ); | ||||
| 		header.print( dump_to_scratch_and_retireve( especifier )); | ||||
| 		header.print( fmt_newline ); | ||||
| 		header.print_fmt("#pragma endregion Types\n\n"); | ||||
| 	#endif | ||||
| 	} | ||||
|  | ||||
| 	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( fmt_newline, td_header, header, get_header, fmt_newline ) ); | ||||
| }; | ||||
|  | ||||
| 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; | ||||
| } | ||||
							
								
								
									
										72
									
								
								gen_c_library/components/misc.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								gen_c_library/components/misc.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | ||||
| // #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 ) | ||||
| { | ||||
| 	b32 found = false; | ||||
| 	CodePreprocessCond cond = entry_iter.code_cast<CodePreprocessCond>(); | ||||
| 	if ( cond->Content.contains(cond_sig) ) | ||||
| 	{ | ||||
| 		log_fmt("Preprocess cond found: %S\n", cond->Content); | ||||
| 		found = true; | ||||
|  | ||||
| 		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 found; | ||||
| } | ||||
|  | ||||
| bool swap_pragma_region_implementation( StrC region_name, SwapContentProc* swap_content, Code& entry_iter, CodeBody& body ) | ||||
| { | ||||
| 	bool found = false; | ||||
| 	CodePragma possible_region = entry_iter.code_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.code_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; | ||||
| } | ||||
							
								
								
									
										7
									
								
								gen_c_library/gen.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								gen_c_library/gen.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| #define GEN_IMPLEMENTATION | ||||
| #include "gen/gen.h" | ||||
|  | ||||
| int main() | ||||
| { | ||||
| 	// init(); | ||||
| } | ||||
| @@ -1,4 +1,4 @@ | ||||
| # 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. | ||||
| @@ -12,12 +12,3 @@ | ||||
| #if ! defined(GEN_DONT_ENFORCE_GEN_TIME_GUARD) && ! defined(GEN_TIME) | ||||
| #	error Gen.hpp : GEN_TIME not defined | ||||
| #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 | ||||
| 
 | ||||
| @@ -30,6 +30,13 @@ Feature Macros: | ||||
| * `GEN_ROLL_OWN_DEPENDENCIES` : Optional override so that user may define the dependencies themselves. | ||||
| * `GEN_DONT_ALLOW_INVALID_CODE` (Not implemented yet) : Will fail when an invalid code is constructed, parsed, or serialized. | ||||
|  | ||||
| By default the base library implementation strictly uses a C-like interface. This is to allow for the generation of a C-variant of the library using [gen_c_library](../gen_c_library/). However, the library was written in C++ and supports some of its features: | ||||
|  | ||||
| * `GEN_SUPPORT_CPP_REFERENCES` : Will enable support for reference interface on some definitions | ||||
| * `GEN_SUPPORT_CPP_MEMBER_FEATURES` : Will enable support for definitions to have their interface as members. | ||||
|  | ||||
| *Note: A variant of the C++ library could be generated where those additonal support features are removed (see gen_c_library implementation for an idea of how)* | ||||
|  | ||||
| ## On multi-threading | ||||
|  | ||||
| Currently unsupported. I want the library to be *stable* and *correct*, with the addition of exhausting all basic single-threaded optimizations before I consider multi-threading. | ||||
|   | ||||
| @@ -13,7 +13,7 @@ Builder Builder::open( char const* path ) | ||||
| 		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 ); | ||||
| 	return result; | ||||
| @@ -21,7 +21,7 @@ Builder Builder::open( char const* path ) | ||||
|  | ||||
| void Builder::pad_lines( s32 num ) | ||||
| { | ||||
| 	Buffer.append( "\n" ); | ||||
| 	append( & Buffer,  "\n" ); | ||||
| } | ||||
|  | ||||
| void Builder::print( Code code ) | ||||
| @@ -29,7 +29,7 @@ void Builder::print( Code code ) | ||||
| 	String   str = code->to_string(); | ||||
| 	// const ssize len = str.length(); | ||||
| 	// 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, ... ) | ||||
| @@ -43,17 +43,17 @@ void Builder::print_fmt( char const* fmt, ... ) | ||||
| 	va_end( va ); | ||||
|  | ||||
| 	// 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() | ||||
| { | ||||
| 	b32 result = file_write( & File, Buffer, Buffer.length() ); | ||||
| 	b32 result = file_write( & File, Buffer, length(Buffer) ); | ||||
|  | ||||
| 	if ( result == false ) | ||||
| 		log_failure("gen::File::write - Failed to write to file: %s\n", file_name( & File ) ); | ||||
|  | ||||
| 	log_fmt( "Generated: %s\n", File.filename ); | ||||
| 	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 ); | ||||
| 	} | ||||
|  | ||||
| 	String str = String::make_reserve( GlobalAllocator, fsize ); | ||||
| 	String str = string_make_reserve( GlobalAllocator, fsize ); | ||||
| 		file_read( & file, str, fsize ); | ||||
| 		str.get_header().Length = fsize; | ||||
| 		get_header(str)->Length = fsize; | ||||
|  | ||||
| 	// Skip GEN_INTELLISENSE_DIRECTIVES preprocessor blocks | ||||
| 	// 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 ) ) | ||||
| 					{ | ||||
| 						mem_move( str, scanner, left ); | ||||
| 						str.get_header().Length = left; | ||||
| 						get_header(str)->Length = left; | ||||
| 						break; | ||||
| 					} | ||||
|  | ||||
| 					mem_move( str, scanner, left ); | ||||
| 					str.get_header().Length = left; | ||||
| 					get_header(str)->Length = left; | ||||
|  | ||||
| 					break; | ||||
| 				} | ||||
|   | ||||
| @@ -1,6 +1,8 @@ | ||||
| #define GEN_DEFINE_LIBRARY_CODE_CONSTANTS | ||||
| #define GEN_ENFORCE_STRONG_CODE_TYPES | ||||
| #define GEN_EXPOSE_BACKEND | ||||
| #define GEN_SUPPORT_CPP_MEMBER_FEATURES 1 | ||||
| #define GEN_SUPPORT_CPP_REFERENCES      0 | ||||
| #include "gen.cpp" | ||||
|  | ||||
| #include "helpers/push_ignores.inline.hpp" | ||||
| @@ -24,20 +26,20 @@ constexpr char const* generation_notice = | ||||
|  | ||||
| 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:")); | ||||
| 	style_arg.append("../scripts/.clang-format "); | ||||
| 	String style_arg = string_make(GlobalAllocator, txt("-style=file:")); | ||||
| 	append( & style_arg, "../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 ); | ||||
| 	String command = string_make( GlobalAllocator, clang_format ); | ||||
| 	append( & command, cf_format_inplace ); | ||||
| 	append( & command, cf_verbose ); | ||||
| 	append( & command, style_arg ); | ||||
| 	append( & command, resolved_path ); | ||||
| 		log_fmt("\tRunning clang-format on file:\n"); | ||||
| 		system( command ); | ||||
| 		log_fmt("\tclang-format finished reformatting.\n"); | ||||
| @@ -62,6 +64,8 @@ int gen_main() | ||||
| { | ||||
| 	gen::init(); | ||||
|  | ||||
| 	// PreprocessorDefines.append("GEN_NS"); | ||||
|  | ||||
| 	Code push_ignores = scan_file( "helpers/push_ignores.inline.hpp" ); | ||||
| 	Code pop_ignores  = scan_file( "helpers/pop_ignores.inline.hpp" ); | ||||
|  | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -146,6 +146,19 @@ namespace parser | ||||
| 	struct Token; | ||||
| } | ||||
|  | ||||
| template< class Type> forceinline Type tmpl_cast( Code* self ) { return * rcast( Type*, self ); } | ||||
| #if ! GEN_COMPILER_C && 0 | ||||
| template< class Type> forceinline Type tmpl_cast( Code& self ) { return * rcast( Type*, & self ); } | ||||
| #endif | ||||
|  | ||||
| char const* debug_str (Code code); | ||||
| Code        duplicate (Code code); | ||||
| bool        is_equal  (Code code, Code other); | ||||
| bool        is_body   (Code code); | ||||
| bool        is_valid  (Code code); | ||||
| void        set_global(Code code); | ||||
| String      to_string (Code code); | ||||
|  | ||||
| /* | ||||
| 	AST* wrapper | ||||
| 	- Not constantly have to append the '*' as this is written often.. | ||||
| @@ -153,31 +166,26 @@ namespace parser | ||||
| */ | ||||
| struct Code | ||||
| { | ||||
| #	pragma region Statics | ||||
| 	// Used to identify ASTs that should always be duplicated. (Global constant ASTs) | ||||
| 	static Code Global; | ||||
|  | ||||
| 	// Used to identify invalid generated code. | ||||
| 	static Code Invalid; | ||||
| #	pragma endregion Statics | ||||
| 	AST* ast; | ||||
|  | ||||
| #	define Using_Code( Typename )          \ | ||||
| 	char const* debug_str();               \ | ||||
| 	Code        duplicate();			   \ | ||||
| 	bool        is_equal( Code other );    \ | ||||
| 	bool        is_valid();                \ | ||||
| 	void        set_global();              \ | ||||
| 	char const* debug_str()                { return GEN_NS debug_str(* this); } \ | ||||
| 	Code        duplicate()                { return GEN_NS duplicate(* this); }	\ | ||||
| 	bool        is_equal( Code other )     { return GEN_NS is_equal(* this, other); } \ | ||||
| 	bool        is_body()                  { return GEN_NS is_body(* this); } \ | ||||
| 	bool        is_valid()                 { return GEN_NS is_valid(* this); } \ | ||||
| 	void        set_global()               { return GEN_NS set_global(* this); } \ | ||||
| 	String      to_string();               \ | ||||
| 	Typename&   operator = ( AST* other ); \ | ||||
| 	Typename&   operator = ( Code other ); \ | ||||
| 	bool        operator ==( Code other ); \ | ||||
| 	bool        operator !=( Code other ); \ | ||||
| 	bool        operator ==( Code other ) { return (AST*)ast == other.ast; } \ | ||||
| 	bool        operator !=( Code other ) { return (AST*)ast != other.ast; } \ | ||||
| 	operator bool(); | ||||
|  | ||||
| 	Using_Code( Code ); | ||||
|  | ||||
| 	template< class Type > | ||||
| 	forceinline Type cast() | ||||
| 	forceinline Type code_cast() | ||||
| 	{ | ||||
| 		return * rcast( Type*, this ); | ||||
| 	} | ||||
| @@ -200,8 +208,6 @@ struct Code | ||||
| 		return *this; | ||||
| 	} | ||||
|  | ||||
| 	AST* ast; | ||||
|  | ||||
| #ifdef GEN_ENFORCE_STRONG_CODE_TYPES | ||||
| #	define operator explicit operator | ||||
| #endif | ||||
| @@ -237,6 +243,14 @@ struct Code | ||||
| 	#undef operator | ||||
| }; | ||||
|  | ||||
| #pragma region Statics | ||||
| // Used to identify ASTs that should always be duplicated. (Global constant ASTs) | ||||
| extern Code Code_Global; | ||||
|  | ||||
| // Used to identify invalid generated code. | ||||
| extern Code Code_Invalid; | ||||
| #pragma endregion Statics | ||||
|  | ||||
| struct Code_POD | ||||
| { | ||||
| 	AST* ast; | ||||
| @@ -247,32 +261,55 @@ static_assert( sizeof(Code) == sizeof(Code_POD), "ERROR: Code is not POD" ); | ||||
| // Desired width of the AST data structure. | ||||
| constexpr int const AST_POD_Size = 128; | ||||
|  | ||||
| void        append     ( AST* self, AST* other ); | ||||
| char const* debug_str  ( AST* self ); | ||||
| AST*        duplicate  ( AST* self ); | ||||
| Code*       entry      ( AST* self, u32 idx ); | ||||
| bool        has_entries( AST* self ); | ||||
| bool        is_body    ( AST* self ); | ||||
| bool        is_equal   ( AST* self, AST* other ); | ||||
| String      to_string  ( AST* self ); | ||||
| char const* type_str   ( AST* self ); | ||||
|  | ||||
| #if GEN_CPP_SUPPORT_REFERENCES | ||||
| void        append   ( AST& self, AST& other ) { return append(& self, & other); } | ||||
| bool        is_body  ( AST& self )             { return is_body(& self); } | ||||
| bool        is_equal ( AST& self, AST& other ) { return is_equal(& self, & other); } | ||||
| char const* debug_str( AST& self )             { return debug_str( & self ); } | ||||
| String      to_string( AST& self )             { return to_string( & self ); } | ||||
| char const* type_str ( AST& self )             { return type_str( & self ); } | ||||
| #endif | ||||
|  | ||||
| /* | ||||
| 	Simple AST POD with functionality to seralize into C++ syntax. | ||||
| */ | ||||
| struct AST | ||||
| { | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| #	pragma region Member Functions | ||||
| 	void        append     ( AST* other ); | ||||
| 	char const* debug_str  (); | ||||
| 	AST*        duplicate  (); | ||||
| 	Code&       entry      ( u32 idx ); | ||||
| 	void        append     ( AST* other ) { GEN_NS append(this, other); } | ||||
| 	char const* debug_str  ()             { return GEN_NS debug_str(this); } | ||||
| 	AST*        duplicate  ()             { return GEN_NS duplicate(this); } | ||||
| 	Code*       entry      ( u32 idx )    { return GEN_NS entry(this, idx); } | ||||
| 	bool        has_entries(); | ||||
| 	bool        is_equal   ( AST* other ); | ||||
| 	char const* type_str(); | ||||
| 	bool        is_equal   ( AST* other )  { return GEN_NS is_equal(this, other); } | ||||
| 	bool        is_body()                  { return GEN_NS is_body(this); } | ||||
| 	char const* type_str()                 { return GEN_NS type_str(this); } | ||||
| 	bool        validate_body(); | ||||
|  | ||||
| 	String to_string(); | ||||
|  | ||||
| 	neverinline | ||||
| 	void to_string( String& result ); | ||||
| 	String to_string(); //{ return GEN_NS to_string(this); } | ||||
|  | ||||
| 	template< class Type > | ||||
| 	forceinline Type cast() | ||||
| 	forceinline Type code_cast() | ||||
| 	{ | ||||
| 		return * this; | ||||
| 	} | ||||
|  | ||||
| 	neverinline | ||||
| 	void to_string( String& result ); | ||||
| #	pragma endregion Member Functions | ||||
| #endif | ||||
|  | ||||
| 	operator Code(); | ||||
| 	operator CodeBody(); | ||||
| 	operator CodeAttributes(); | ||||
| @@ -303,7 +340,6 @@ struct AST | ||||
| 	operator CodeUnion(); | ||||
| 	operator CodeUsing(); | ||||
| 	operator CodeVar(); | ||||
| #	pragma endregion Member Functions | ||||
|  | ||||
| 	constexpr static | ||||
| 	int ArrSpecs_Cap = | ||||
| @@ -376,7 +412,8 @@ struct AST | ||||
| 		OperatorT     Op; | ||||
| 		AccessSpec    ParentAccess; | ||||
| 		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 | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| @@ -443,12 +480,9 @@ struct AST_POD | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| struct test { | ||||
| 	SpecifierT ArrSpecs[AST::ArrSpecs_Cap]; // Specifiers | ||||
| 	AST* NextSpecs;                         // Specifiers; If ArrSpecs is full, then NextSpecs is used. | ||||
| }; | ||||
|  | ||||
| constexpr int pls = sizeof(test); | ||||
| // TODO(Ed): Convert | ||||
| String      to_string  ( AST* self ) { return self->to_string(); } | ||||
|  | ||||
| // Its intended for the AST to have equivalent size to its POD. | ||||
| // All extra functionality within the AST namespace should just be syntatic sugar. | ||||
| @@ -457,4 +491,4 @@ static_assert( sizeof(AST_POD) == AST_POD_Size,    "ERROR: AST POD is not size o | ||||
|  | ||||
| // Used when the its desired when omission is allowed in a definition. | ||||
| #define NoCode      { nullptr } | ||||
| #define CodeInvalid (* Code::Invalid.ast) // Uses an implicitly overloaded cast from the AST to the desired code type. | ||||
| #define InvalidCode (* Code_Invalid.ast) // Uses an implicitly overloaded cast from the AST to the desired code type. | ||||
|   | ||||
| @@ -174,7 +174,7 @@ struct AST_Enum | ||||
| 			CodeAttributes Attributes; | ||||
| 			char           _PAD_SPEC_  [ sizeof(AST*) ]; | ||||
| 			CodeType       UnderlyingType; | ||||
| 			char	       _PAD_PARAMS_[ sizeof(AST*) ]; | ||||
| 			Code           UnderlyingTypeMacro; | ||||
| 			CodeBody       Body; | ||||
| 			char 	       _PAD_PROPERTIES_2_[ sizeof(AST*) ]; | ||||
| 		}; | ||||
| @@ -186,7 +186,7 @@ struct AST_Enum | ||||
| 	StringCached           Name; | ||||
| 	CodeT                  Type; | ||||
| 	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"); | ||||
|  | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -11,33 +11,30 @@ struct CodeBody | ||||
|  | ||||
| 	void append( Code other ) | ||||
| 	{ | ||||
| 		raw()->append( other.ast ); | ||||
| 		GEN_ASSERT(other.ast != nullptr); | ||||
|  | ||||
| 		if (other.is_body()) { | ||||
| 			append( cast(CodeBody, & other) ); | ||||
| 		} | ||||
|  | ||||
| 		GEN_NS append( raw(), other.ast ); | ||||
| 	} | ||||
| 	void append( CodeBody body ) | ||||
| 	{ | ||||
| 		for ( Code entry : body ) | ||||
| 		{ | ||||
| 		for ( Code entry : body ) { | ||||
| 			append( entry ); | ||||
| 		} | ||||
| 	} | ||||
| 	bool has_entries() | ||||
| 	{ | ||||
| 		return rcast( AST*, ast )->has_entries(); | ||||
| 	} | ||||
| 	bool has_entries() { return GEN_NS has_entries(rcast( AST*, ast )); } | ||||
| 	AST* raw()         { return rcast( AST*, ast ); } | ||||
|  | ||||
| 	void to_string( String& result ); | ||||
| 	void to_string_export( String& result ); | ||||
| 	AST* raw() | ||||
| 	{ | ||||
| 		return rcast( AST*, ast ); | ||||
| 	} | ||||
| 	AST_Body* operator->() | ||||
| 	{ | ||||
| 		return ast; | ||||
| 	} | ||||
| 	operator Code() | ||||
| 	{ | ||||
| 		return * rcast( Code*, this ); | ||||
| 	} | ||||
|  | ||||
| 	AST_Body* operator->() { return ast; } | ||||
|  | ||||
| 	operator Code() { return * rcast( Code*, this ); } | ||||
|  | ||||
| #pragma region Iterator | ||||
| 	Code begin() | ||||
| 	{ | ||||
| @@ -165,6 +162,46 @@ struct CodeSpecifiers | ||||
|  | ||||
| 		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 ); | ||||
| 	AST* raw() | ||||
| 	{ | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -133,6 +133,7 @@ extern CodeType t_typename; | ||||
|  | ||||
| #pragma region Macros | ||||
|  | ||||
| #ifndef token_fmt | ||||
| #	define gen_main main | ||||
|  | ||||
| #	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. | ||||
| #	define token_fmt( ... ) GEN_NS token_fmt_impl( (num_args( __VA_ARGS__ ) + 1) / 2, __VA_ARGS__ ) | ||||
| #endif | ||||
|  | ||||
| #pragma endregion Macros | ||||
|  | ||||
|   | ||||
| @@ -4,56 +4,82 @@ | ||||
| #endif | ||||
|  | ||||
| inline | ||||
| void AST::append( AST* other ) | ||||
| void append( AST* self, AST* other ) | ||||
| { | ||||
| 	GEN_ASSERT(self  != nullptr); | ||||
| 	GEN_ASSERT(other != nullptr); | ||||
|  | ||||
| 	if ( other->Parent ) | ||||
| 		other = other->duplicate(); | ||||
| 		other = duplicate(other); | ||||
|  | ||||
| 	other->Parent = this; | ||||
| 	other->Parent = self; | ||||
|  | ||||
| 	if ( Front == nullptr ) | ||||
| 	if ( self->Front == nullptr ) | ||||
| 	{ | ||||
| 		Front = other; | ||||
| 		Back  = other; | ||||
| 		self->Front = other; | ||||
| 		self->Back  = other; | ||||
|  | ||||
| 		NumEntries++; | ||||
| 		self->NumEntries++; | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	AST* | ||||
| 		Current       = Back; | ||||
| 	Current       = self->Back; | ||||
| 	Current->Next = other; | ||||
| 	other->Prev   = Current; | ||||
| 	Back          = other; | ||||
| 	NumEntries++; | ||||
| 	self->Back    = other; | ||||
| 	self->NumEntries++; | ||||
| } | ||||
|  | ||||
| inline | ||||
| Code& AST::entry( u32 idx ) | ||||
| Code* entry( AST* self, u32 idx ) | ||||
| { | ||||
| 	AST** current = & Front; | ||||
| 	GEN_ASSERT(self != nullptr); | ||||
| 	AST** current = & self->Front; | ||||
| 	while ( idx >= 0 && current != nullptr ) | ||||
| 	{ | ||||
| 		if ( idx == 0 ) | ||||
| 			return * rcast( Code*, current); | ||||
| 			return rcast( Code*, current); | ||||
|  | ||||
| 		current = & ( * current )->Next; | ||||
| 		idx--; | ||||
| 	} | ||||
|  | ||||
| 	return * rcast( Code*, current); | ||||
| 	return rcast( Code*, current); | ||||
| } | ||||
|  | ||||
| inline | ||||
| bool AST::has_entries() | ||||
| bool has_entries(AST* self) | ||||
| { | ||||
| 	return NumEntries > 0; | ||||
| 	GEN_ASSERT(self != nullptr); | ||||
| 	return self->NumEntries > 0; | ||||
| } | ||||
|  | ||||
| inline | ||||
| char const* AST::type_str() | ||||
| bool is_body(AST* self) | ||||
| { | ||||
| 	return ECode::to_str( Type ); | ||||
| 	GEN_ASSERT(self != nullptr); | ||||
| 	switch (self->Type) | ||||
| 	{ | ||||
| 		case ECode::Enum_Body: | ||||
| 		case ECode::Class_Body: | ||||
| 		case ECode::Union_Body: | ||||
| 		case ECode::Export_Body: | ||||
| 		case ECode::Global_Body: | ||||
| 		case ECode::Struct_Body: | ||||
| 		case ECode::Function_Body: | ||||
| 		case ECode::Namespace_Body: | ||||
| 		case ECode::Extern_Linkage_Body: | ||||
| 			return true; | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline | ||||
| char const* type_str(AST* self) | ||||
| { | ||||
| 	GEN_ASSERT(self != nullptr); | ||||
| 	return ECode::to_str( self->Type ); | ||||
| } | ||||
|  | ||||
| inline | ||||
| @@ -62,6 +88,69 @@ AST::operator Code() | ||||
| 	return { this }; | ||||
| } | ||||
|  | ||||
| #pragma region Code | ||||
|  | ||||
| inline | ||||
| char const* debug_str( Code code ) | ||||
| { | ||||
| 	if ( code.ast == nullptr ) | ||||
| 		return "Code::debug_str: AST is null!"; | ||||
|  | ||||
| 	return debug_str( code.ast ); | ||||
| } | ||||
|  | ||||
| inline | ||||
| Code duplicate( Code code ) | ||||
| { | ||||
| 	if ( code.ast == nullptr ) | ||||
| 	{ | ||||
| 		log_failure("Code::duplicate: Cannot duplicate code, AST is null!"); | ||||
| 		return Code_Invalid; | ||||
| 	} | ||||
|  | ||||
| 	return { duplicate(code.ast) }; | ||||
| } | ||||
|  | ||||
| inline | ||||
| bool is_body(Code code) | ||||
| { | ||||
| 	if ( code.ast == nullptr ) | ||||
| 	{ | ||||
| 		return is_body(code.ast); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline | ||||
| bool is_equal( Code self, Code other ) | ||||
| { | ||||
| 	if ( self.ast == nullptr || other.ast == nullptr ) | ||||
| 	{ | ||||
| 		// Just check if they're both null. | ||||
| 		// log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); | ||||
| 		return self.ast == nullptr && other.ast == nullptr; | ||||
| 	} | ||||
| 	return is_equal( self.ast, other.ast ); | ||||
| } | ||||
|  | ||||
| inline | ||||
| bool is_valid(Code self) | ||||
| { | ||||
| 	return self.ast != nullptr && self.ast->Type != CodeT::Invalid; | ||||
| } | ||||
|  | ||||
| inline | ||||
| void set_global(Code self) | ||||
| { | ||||
| 	if ( self.ast == nullptr ) | ||||
| 	{ | ||||
| 		log_failure("Code::set_global: Cannot set code as global, AST is null!"); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	self->Parent = Code_Global.ast; | ||||
| } | ||||
|  | ||||
| inline | ||||
| Code& Code::operator ++() | ||||
| { | ||||
| @@ -71,6 +160,8 @@ Code& Code::operator ++() | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
| #pragma endregion Code | ||||
|  | ||||
| inline | ||||
| void CodeClass::add_interface( CodeType type ) | ||||
| { | ||||
| @@ -78,7 +169,7 @@ void CodeClass::add_interface( CodeType type ) | ||||
| 	if ( possible_slot.ast ) | ||||
| 	{ | ||||
| 		// 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, | ||||
| 		// then you'll need to move this over to ParentType->next and update ParentAccess accordingly. | ||||
| 	} | ||||
| @@ -98,7 +189,7 @@ void CodeParam::append( CodeParam other ) | ||||
| 	AST* entry = (AST*) other.ast; | ||||
|  | ||||
| 	if ( entry->Parent ) | ||||
| 		entry = entry->duplicate(); | ||||
| 		entry = GEN_NS duplicate( entry ); | ||||
|  | ||||
| 	entry->Parent = self; | ||||
|  | ||||
| @@ -151,7 +242,7 @@ void CodeStruct::add_interface( CodeType type ) | ||||
| 	if ( possible_slot.ast ) | ||||
| 	{ | ||||
| 		// 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, | ||||
| 		// then you'll need to move this over to ParentType->next and update ParentAccess accordingly. | ||||
| 	} | ||||
| @@ -183,7 +274,7 @@ CodeBody def_body( CodeT type ) | ||||
|  | ||||
| 		default: | ||||
| 			log_failure( "def_body: Invalid type %s", (char const*)ECode::to_str(type) ); | ||||
| 			return (CodeBody)Code::Invalid; | ||||
| 			return (CodeBody)Code_Invalid; | ||||
| 	} | ||||
|  | ||||
| 	Code | ||||
|   | ||||
| @@ -11,7 +11,7 @@ internal void deinit(); | ||||
| internal | ||||
| 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 ) | ||||
| 	{ | ||||
| @@ -19,18 +19,18 @@ void* Global_Allocator_Proc( void* allocator_data, AllocType type, ssize size, s | ||||
| 		{ | ||||
| 			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 ) | ||||
| 					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"); | ||||
|  | ||||
| 				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: | ||||
| 		{ | ||||
| @@ -46,15 +46,15 @@ void* Global_Allocator_Proc( void* allocator_data, AllocType type, ssize size, s | ||||
| 		{ | ||||
| 			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 ) | ||||
| 					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"); | ||||
|  | ||||
| 				last = & Global_AllocatorBuckets.back(); | ||||
| 				last = back(& Global_AllocatorBuckets); | ||||
| 			} | ||||
|  | ||||
| 			void* result = alloc_align( last->Backing, size, alignment ); | ||||
| @@ -74,16 +74,16 @@ void* Global_Allocator_Proc( void* allocator_data, AllocType type, ssize size, s | ||||
| internal | ||||
| void define_constants() | ||||
| { | ||||
| 	Code::Global          = make_code(); | ||||
| 	Code::Global->Name    = get_cached_string( txt("Global Code") ); | ||||
| 	Code::Global->Content = Code::Global->Name; | ||||
| 	Code_Global                         = make_code(); | ||||
| 	scast(String, Code_Global->Name)    = get_cached_string( txt("Global Code") ); | ||||
| 	scast(String, Code_Global->Content) = Code_Global->Name; | ||||
|  | ||||
| 	Code::Invalid = make_code(); | ||||
| 	Code::Invalid.set_global(); | ||||
| 	Code_Invalid = make_code(); | ||||
| 	Code_Invalid.set_global(); | ||||
|  | ||||
| 	t_empty          = (CodeType) make_code(); | ||||
| 	t_empty->Type    = ECode::Typename; | ||||
| 	t_empty->Name    = get_cached_string( txt("") ); | ||||
| 	t_empty       = (CodeType) make_code(); | ||||
| 	t_empty->Type = ECode::Typename; | ||||
| 	t_empty->Name = get_cached_string( txt("") ); | ||||
| 	t_empty.set_global(); | ||||
|  | ||||
| 	access_private       = make_code(); | ||||
| @@ -226,6 +226,10 @@ void define_constants() | ||||
| #	pragma pop_macro("local_persist") | ||||
| #	pragma pop_macro("neverinline") | ||||
|  | ||||
| #	pragma push_macro("enum_underlying") | ||||
|  | ||||
| #	pragma pop_macro("enum_underlying") | ||||
|  | ||||
| #	undef def_constant_spec | ||||
| } | ||||
|  | ||||
| @@ -235,28 +239,27 @@ void init() | ||||
| 	{ | ||||
| 		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 ) | ||||
| 			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 ) | ||||
| 			GEN_FATAL( "Failed to create first bucket for Global_AllocatorBuckets"); | ||||
|  | ||||
| 		Global_AllocatorBuckets.append( bucket ); | ||||
|  | ||||
| 		append( & Global_AllocatorBuckets, bucket ); | ||||
| 	} | ||||
|  | ||||
| 	// Setup the arrays | ||||
| 	{ | ||||
| 		CodePools = Array<Pool>::init_reserve( Allocator_DataArrays, InitSize_DataArrays ); | ||||
| 		CodePools = array_init_reserve<Pool>( Allocator_DataArrays, InitSize_DataArrays ); | ||||
|  | ||||
| 		if ( CodePools == nullptr ) | ||||
| 			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 ) | ||||
| 			GEN_FATAL( "gen::init: Failed to initialize the StringArenas array" ); | ||||
| @@ -264,33 +267,33 @@ void init() | ||||
|  | ||||
| 	// 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 ) | ||||
| 			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 ) | ||||
| 			GEN_FATAL( "gen::init: Failed to initialize the string arena" ); | ||||
|  | ||||
| 		StringArenas.append( string_arena ); | ||||
| 		append( & StringArenas, string_arena ); | ||||
| 	} | ||||
|  | ||||
| 	// Setup the hash tables | ||||
| 	{ | ||||
| 		StringCache = StringTable::init( Allocator_StringTable ); | ||||
| 		StringCache = hashtable_init<StringCached>(Allocator_StringTable); | ||||
|  | ||||
| 		if ( StringCache.Entries == nullptr ) | ||||
| 			GEN_FATAL( "gen::init: Failed to initialize the StringCache"); | ||||
| 	} | ||||
|  | ||||
| 	// Preprocessor Defines | ||||
| 	PreprocessorDefines = Array<StringCached>::init_reserve( GlobalAllocator, kilobytes(1) ); | ||||
| 	PreprocessorDefines = array_init_reserve<StringCached>( GlobalAllocator, kilobytes(1) ); | ||||
|  | ||||
| 	define_constants(); | ||||
| 	parser::init(); | ||||
| @@ -299,62 +302,62 @@ void init() | ||||
| void deinit() | ||||
| { | ||||
| 	usize index = 0; | ||||
| 	usize left  = CodePools.num(); | ||||
| 	usize left  = num(CodePools); | ||||
| 	do | ||||
| 	{ | ||||
| 		Pool* code_pool = & CodePools[index]; | ||||
| 		code_pool->free(); | ||||
| 		free(code_pool); | ||||
| 		index++; | ||||
| 	} | ||||
| 	while ( left--, left ); | ||||
|  | ||||
| 	index = 0; | ||||
| 	left  = StringArenas.num(); | ||||
| 	left  = num(StringArenas); | ||||
| 	do | ||||
| 	{ | ||||
| 		Arena* string_arena = & StringArenas[index]; | ||||
| 		string_arena->free(); | ||||
| 		free(string_arena); | ||||
| 		index++; | ||||
| 	} | ||||
| 	while ( left--, left ); | ||||
|  | ||||
| 	StringCache.destroy(); | ||||
| 	destroy(& StringCache); | ||||
|  | ||||
| 	CodePools.free(); | ||||
| 	StringArenas.free(); | ||||
| 	free( & CodePools); | ||||
| 	free( & StringArenas); | ||||
|  | ||||
| 	LexArena.free(); | ||||
| 	free(& LexArena); | ||||
|  | ||||
| 	PreprocessorDefines.free(); | ||||
| 	free(& PreprocessorDefines); | ||||
|  | ||||
| 	index = 0; | ||||
| 	left  = Global_AllocatorBuckets.num(); | ||||
| 	left  = num(Global_AllocatorBuckets); | ||||
| 	do | ||||
| 	{ | ||||
| 		Arena* bucket = & Global_AllocatorBuckets[ index ]; | ||||
| 		bucket->free(); | ||||
| 		free(bucket); | ||||
| 		index++; | ||||
| 	} | ||||
| 	while ( left--, left ); | ||||
|  | ||||
| 	Global_AllocatorBuckets.free(); | ||||
| 	free(Global_AllocatorBuckets); | ||||
| 	parser::deinit(); | ||||
| } | ||||
|  | ||||
| void reset() | ||||
| { | ||||
| 	s32 index = 0; | ||||
| 	s32 left  = CodePools.num(); | ||||
| 	s32 left  = num(CodePools); | ||||
| 	do | ||||
| 	{ | ||||
| 		Pool* code_pool = & CodePools[index]; | ||||
| 		code_pool->clear(); | ||||
| 		clear(* code_pool); | ||||
| 		index++; | ||||
| 	} | ||||
| 	while ( left--, left ); | ||||
|  | ||||
| 	index = 0; | ||||
| 	left  = StringArenas.num(); | ||||
| 	left  = num(StringArenas); | ||||
| 	do | ||||
| 	{ | ||||
| 		Arena* string_arena = & StringArenas[index]; | ||||
| @@ -363,28 +366,28 @@ void reset() | ||||
| 	} | ||||
| 	while ( left--, left ); | ||||
|  | ||||
| 	StringCache.clear(); | ||||
| 	clear(StringCache); | ||||
|  | ||||
| 	define_constants(); | ||||
| } | ||||
|  | ||||
| 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 ) | ||||
| 	{ | ||||
| 		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" ); | ||||
|  | ||||
| 		last = & StringArenas.back(); | ||||
| 		last = back(& StringArenas); | ||||
| 	} | ||||
|  | ||||
| 	return * last; | ||||
| 	return allocator_info(last); | ||||
| } | ||||
|  | ||||
| // 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; | ||||
| 	u64 key         = crc32( str.Ptr, hash_length ); | ||||
| 	{ | ||||
| 		StringCached* result = StringCache.get( key ); | ||||
| 		StringCached* result = get(StringCache, key ); | ||||
|  | ||||
| 		if ( result ) | ||||
| 			return * result; | ||||
| 	} | ||||
|  | ||||
| 	String result = String::make( get_string_allocator( str.Len ), str ); | ||||
| 	StringCache.set( key, result ); | ||||
| 	String result = string_make( get_string_allocator( str.Len ), str ); | ||||
| 	set<StringCached>(& StringCache, key, result ); | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
| @@ -408,21 +411,21 @@ StringCached get_cached_string( StrC str ) | ||||
| // Used internally to retireve a Code object form the CodePool. | ||||
| Code make_code() | ||||
| { | ||||
| 	Pool* allocator = & CodePools.back(); | ||||
| 	Pool* allocator = back( & CodePools); | ||||
| 	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 ) | ||||
| 			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." ); | ||||
|  | ||||
| 		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) ); | ||||
| 	// result->Type = ECode::Invalid; | ||||
|  | ||||
|   | ||||
| @@ -44,9 +44,9 @@ CodeComment    def_comment   ( StrC content ); | ||||
|  | ||||
| CodeClass def_class( StrC name | ||||
| 	, Code           body         = NoCode | ||||
| 	, CodeType       parent       = NoCode, AccessSpec access = AccessSpec::Default | ||||
| 	, CodeType       parent       = NoCode, AccessSpec access = AccessSpec_Default | ||||
| 	, CodeAttributes attributes   = NoCode | ||||
| 	, ModuleFlag     mflags       = ModuleFlag::None | ||||
| 	, ModuleFlag     mflags       = ModuleFlag_None | ||||
| 	, CodeType*      interfaces   = nullptr, s32 num_interfaces = 0 ); | ||||
|  | ||||
| CodeConstructor def_constructor( CodeParam params = NoCode, Code initializer_list = NoCode, Code body = NoCode ); | ||||
| @@ -56,9 +56,9 @@ CodeDefine def_define( StrC name, StrC content ); | ||||
| CodeDestructor def_destructor( Code body = NoCode, CodeSpecifiers specifiers = NoCode ); | ||||
|  | ||||
| CodeEnum def_enum( StrC name | ||||
| 	, Code         body      = NoCode,      CodeType       type       = NoCode | ||||
| 	, EnumT        specifier = EnumRegular, CodeAttributes attributes = NoCode | ||||
| 	, ModuleFlag   mflags    = ModuleFlag::None ); | ||||
| 	, Code         body      = NoCode,           CodeType       type       = NoCode | ||||
| 	, EnumT        specifier = EnumDecl_Regular, CodeAttributes attributes = NoCode | ||||
| 	, ModuleFlag   mflags    = ModuleFlag_None ); | ||||
|  | ||||
| CodeExec   def_execution  ( StrC content ); | ||||
| CodeExtern def_extern_link( StrC name, Code body ); | ||||
| @@ -67,16 +67,16 @@ CodeFriend def_friend     ( Code symbol ); | ||||
| CodeFn def_function( StrC name | ||||
| 	, CodeParam      params     = NoCode, CodeType       ret_type   = NoCode, Code body = NoCode | ||||
| 	, CodeSpecifiers specifiers = NoCode, CodeAttributes attributes = NoCode | ||||
| 	, ModuleFlag mflags     = ModuleFlag::None ); | ||||
| 	, ModuleFlag mflags     = ModuleFlag_None ); | ||||
|  | ||||
| CodeInclude   def_include  ( StrC content, bool foreign = false ); | ||||
| CodeModule    def_module   ( StrC name,            ModuleFlag mflags = ModuleFlag::None ); | ||||
| CodeNS        def_namespace( StrC name, Code body, ModuleFlag mflags = ModuleFlag::None ); | ||||
| CodeModule    def_module   ( StrC name,            ModuleFlag mflags = ModuleFlag_None ); | ||||
| CodeNS        def_namespace( StrC name, Code body, ModuleFlag mflags = ModuleFlag_None ); | ||||
|  | ||||
| CodeOperator def_operator( OperatorT op, StrC nspace | ||||
| 	, CodeParam      params     = NoCode, CodeType       ret_type   = NoCode, Code body = 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 ); | ||||
|  | ||||
| @@ -89,27 +89,27 @@ CodeSpecifiers def_specifier( SpecifierT specifier ); | ||||
|  | ||||
| CodeStruct def_struct( StrC name | ||||
| 	, Code           body       = NoCode | ||||
| 	, CodeType       parent     = NoCode, AccessSpec access = AccessSpec::Default | ||||
| 	, CodeType       parent     = NoCode, AccessSpec access = AccessSpec_Default | ||||
| 	, CodeAttributes attributes = NoCode | ||||
| 	, ModuleFlag     mflags     = ModuleFlag::None | ||||
| 	, ModuleFlag     mflags     = ModuleFlag_None | ||||
| 	, 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 ); | ||||
| 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 | ||||
| 	, CodeAttributes attributess = NoCode | ||||
| 	, ModuleFlag     mflags      = ModuleFlag::None ); | ||||
| 	, ModuleFlag     mflags      = ModuleFlag_None ); | ||||
|  | ||||
| CodeUsing def_using_namespace( StrC name ); | ||||
|  | ||||
| CodeVar def_variable( CodeType type, StrC name, Code value = 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. | ||||
| CodeBody def_body( CodeT type ); | ||||
|   | ||||
| @@ -15,7 +15,7 @@ CodeClass parse_class( StrC def ) | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	push_scope(); | ||||
| @@ -31,7 +31,7 @@ CodeConstructor parse_constructor( StrC def ) | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	// TODO(Ed): Constructors can have prefix attributes | ||||
|  | ||||
| @@ -61,7 +61,7 @@ CodeConstructor parse_constructor( StrC def ) | ||||
| 			default : | ||||
| 				log_failure( "Invalid specifier %s for variable\n%s", ESpecifier::to_str( spec ), Context.to_string() ); | ||||
| 				Context.pop(); | ||||
| 				return CodeInvalid; | ||||
| 				return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		// Every specifier after would be considered part of the type type signature | ||||
| @@ -91,7 +91,7 @@ CodeDestructor parse_destructor( StrC def ) | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	// TODO(Ed): Destructors can have prefix attributes | ||||
| 	// TODO(Ed): Destructors can have virtual | ||||
| @@ -110,7 +110,7 @@ CodeEnum parse_enum( StrC def ) | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 	{ | ||||
| 		Context.pop(); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| @@ -124,7 +124,7 @@ CodeBody parse_export_body( StrC def ) | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parse_export_body(); | ||||
| @@ -137,7 +137,7 @@ CodeExtern parse_extern_link( StrC def ) | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parse_extern_link(); | ||||
| @@ -150,7 +150,7 @@ CodeFriend parse_friend( StrC def ) | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parse_friend(); | ||||
| @@ -163,7 +163,7 @@ CodeFn parse_function( StrC def ) | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return (CodeFn) parse_function(); | ||||
| @@ -176,7 +176,7 @@ CodeBody parse_global_body( StrC def ) | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	push_scope(); | ||||
| @@ -192,7 +192,7 @@ CodeNS parse_namespace( StrC def ) | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parse_namespace(); | ||||
| @@ -205,7 +205,7 @@ CodeOperator parse_operator( StrC def ) | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return (CodeOperator) parse_operator(); | ||||
| @@ -218,7 +218,7 @@ CodeOpCast parse_operator_cast( StrC def ) | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parse_operator_cast(); | ||||
| @@ -231,7 +231,7 @@ CodeStruct parse_struct( StrC def ) | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	push_scope(); | ||||
| @@ -247,7 +247,7 @@ CodeTemplate parse_template( StrC def ) | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parse_template(); | ||||
| @@ -260,7 +260,7 @@ CodeType parse_type( StrC def ) | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parse_type(); | ||||
| @@ -273,7 +273,7 @@ CodeTypedef parse_typedef( StrC def ) | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parse_typedef(); | ||||
| @@ -286,7 +286,7 @@ CodeUnion parse_union( StrC def ) | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parse_union(); | ||||
| @@ -299,7 +299,7 @@ CodeUsing parse_using( StrC def ) | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parse_using(); | ||||
| @@ -312,7 +312,7 @@ CodeVar parse_variable( StrC def ) | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parse_variable(); | ||||
|   | ||||
| @@ -6,7 +6,7 @@ | ||||
| ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va ) | ||||
| { | ||||
| 	char const* buf_begin = buf; | ||||
| 	ssize          remaining = buf_size; | ||||
| 	ssize       remaining = buf_size; | ||||
|  | ||||
| 	local_persist | ||||
| 	Arena tok_map_arena; | ||||
| @@ -16,8 +16,8 @@ ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va ) | ||||
| 		local_persist | ||||
| 		char tok_map_mem[ TokenFmt_TokenMap_MemSize ]; | ||||
|  | ||||
| 		tok_map_arena = Arena::init_from_memory( tok_map_mem, sizeof(tok_map_mem) ); | ||||
| 		tok_map       = HashTable<StrC>::init( tok_map_arena ); | ||||
| 		tok_map_arena = arena_init_from_memory( tok_map_mem, sizeof(tok_map_mem) ); | ||||
| 		tok_map       = hashtable_init<StrC>( allocator_info(& tok_map_arena) ); | ||||
|  | ||||
| 		s32 left = num_tokens - 1; | ||||
|  | ||||
| @@ -27,8 +27,7 @@ ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va ) | ||||
| 			StrC        value = va_arg( va, StrC ); | ||||
|  | ||||
| 			u32 key = crc32( token, str_len(token) ); | ||||
|  | ||||
| 			tok_map.set( key, value ); | ||||
| 			set(& tok_map, key, value ); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @@ -64,7 +63,7 @@ ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va ) | ||||
| 			char const* token = fmt + 1; | ||||
|  | ||||
| 			u32       key   = crc32( token, tok_len ); | ||||
| 			StrC*     value = tok_map.get( key ); | ||||
| 			StrC*     value = get(tok_map, key ); | ||||
|  | ||||
| 			if ( value ) | ||||
| 			{ | ||||
| @@ -94,8 +93,8 @@ ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va ) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	tok_map.clear(); | ||||
| 	tok_map_arena.free(); | ||||
| 	clear(tok_map); | ||||
| 	free(& tok_map_arena); | ||||
|  | ||||
| 	ssize result = buf_size - remaining; | ||||
|  | ||||
| @@ -107,7 +106,7 @@ Code untyped_str( StrC content ) | ||||
| 	if ( content.Len == 0 ) | ||||
| 	{ | ||||
| 		log_failure( "untyped_str: empty string" ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	Code | ||||
| @@ -119,7 +118,7 @@ Code untyped_str( StrC content ) | ||||
| 	if ( result->Name == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "untyped_str: could not cache string" ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	return result; | ||||
| @@ -130,7 +129,7 @@ Code untyped_fmt( char const* fmt, ...) | ||||
| 	if ( fmt == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "untyped_fmt: null format string" ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	local_persist thread_local | ||||
| @@ -150,7 +149,7 @@ Code untyped_fmt( char const* fmt, ...) | ||||
| 	if ( result->Name == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "untyped_fmt: could not cache string" ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	return result; | ||||
| @@ -161,7 +160,7 @@ Code untyped_token_fmt( s32 num_tokens, ... ) | ||||
| 	if ( num_tokens == 0 ) | ||||
| 	{ | ||||
| 		log_failure( "untyped_token_fmt: zero tokens" ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	local_persist thread_local | ||||
| @@ -181,7 +180,7 @@ Code untyped_token_fmt( s32 num_tokens, ... ) | ||||
| 	if ( result->Name == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "untyped_fmt: could not cache string" ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	return result; | ||||
|   | ||||
| @@ -381,13 +381,13 @@ OpValidateResult operator__validate( OperatorT op, CodeParam params_code, CodeTy | ||||
| 	if ( Name_.Len <= 0 )                                                                             \ | ||||
| 	{                                                                                                 \ | ||||
| 		log_failure( "gen::" stringize(Context_) ": Invalid name length provided - %d",  Name_.Len ); \ | ||||
| 		return CodeInvalid;                                                                           \ | ||||
| 		return InvalidCode;                                                                           \ | ||||
| 	}                                                                                                 \ | ||||
| 																									  \ | ||||
| 	if ( Name_.Ptr == nullptr )                                                                       \ | ||||
| 	{                                                                                                 \ | ||||
| 		log_failure( "gen::" stringize(Context_) ": name is null" );                                  \ | ||||
| 		return CodeInvalid;                                                                           \ | ||||
| 		return InvalidCode;                                                                           \ | ||||
| 	}                                                                                                 \ | ||||
| } | ||||
|  | ||||
| @@ -395,7 +395,7 @@ OpValidateResult operator__validate( OperatorT op, CodeParam params_code, CodeTy | ||||
| 	if ( ! Code_ )                                                                            \ | ||||
| 	{                                                                                         \ | ||||
| 		log_failure( "gen::" stringize(Context_) ": " stringize(Code_) " provided is null" ); \ | ||||
| 		return CodeInvalid;                                                                   \ | ||||
| 		return InvalidCode;                                                                   \ | ||||
| 	} | ||||
|  | ||||
| #define null_or_invalid_check( Context_, Code_ )                                                \ | ||||
| @@ -403,19 +403,19 @@ OpValidateResult operator__validate( OperatorT op, CodeParam params_code, CodeTy | ||||
| 	if ( ! Code_ )                                                                              \ | ||||
| 	{                                                                                           \ | ||||
| 		log_failure( "gen::" stringize(Context_) ": " stringize(Code_) " provided is null" );   \ | ||||
| 		return CodeInvalid;                                                                     \ | ||||
| 		return InvalidCode;                                                                     \ | ||||
| 	}                                                                                           \ | ||||
| 																								\ | ||||
| 	if ( Code_->is_invalid() )                                                                  \ | ||||
| 	{                                                                                           \ | ||||
| 		log_failure("gen::" stringize(Context_) ": " stringize(Code_) " provided is invalid" ); \ | ||||
| 		return CodeInvalid;                                                                     \ | ||||
| 		return InvalidCode;                                                                     \ | ||||
| 	}                                                                                           \ | ||||
| } | ||||
|  | ||||
| #define not_implemented( Context_ )                             \ | ||||
| 	log_failure( "gen::%s: This function is not implemented" ); \ | ||||
| 	return CodeInvalid; | ||||
| 	return InvalidCode; | ||||
| #pragma endregion Helper Marcos | ||||
|  | ||||
|  | ||||
| @@ -436,7 +436,7 @@ CodeAttributes def_attributes( StrC content ) | ||||
| 	if ( content.Len <= 0 || content.Ptr == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_attributes: Invalid attributes provided" ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	Code | ||||
| @@ -453,12 +453,12 @@ CodeComment def_comment( StrC content ) | ||||
| 	if ( content.Len <= 0 || content.Ptr == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_comment: Invalid comment provided:" ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	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* scanner       = content.Ptr; | ||||
| 	s32         curr          = 0; | ||||
| @@ -474,15 +474,15 @@ CodeComment def_comment( StrC content ) | ||||
| 		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 ); | ||||
|  | ||||
| 		scanner += length; | ||||
| 	} | ||||
| 	while ( scanner <= end ); | ||||
|  | ||||
| 	if ( cmt_formatted.back() != '\n' ) | ||||
| 		cmt_formatted.append( "\n" ); | ||||
| 	if ( * back(& cmt_formatted) != '\n' ) | ||||
| 		append( & cmt_formatted, "\n" ); | ||||
|  | ||||
| 	Code | ||||
| 	result          = make_code(); | ||||
| @@ -490,7 +490,7 @@ CodeComment def_comment( StrC content ) | ||||
| 	result->Name    = get_cached_string( cmt_formatted ); | ||||
| 	result->Content = result->Name; | ||||
|  | ||||
| 	cmt_formatted.free(); | ||||
| 	free(& cmt_formatted); | ||||
|  | ||||
| 	return (CodeComment) result; | ||||
| } | ||||
| @@ -502,7 +502,7 @@ CodeConstructor def_constructor( CodeParam params, Code initializer_list, Code b | ||||
| 	if ( params && params->Type != Parameters ) | ||||
| 	{ | ||||
| 		log_failure("gen::def_constructor: params must be of Parameters type - %s", params.debug_str()); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	CodeConstructor | ||||
| @@ -528,7 +528,7 @@ CodeConstructor def_constructor( CodeParam params, Code initializer_list, Code b | ||||
|  | ||||
| 			default: | ||||
| 				log_failure("gen::def_constructor: body must be either of Function_Body or Untyped type - %s", body.debug_str()); | ||||
| 				return CodeInvalid; | ||||
| 				return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		result->Type = Constructor; | ||||
| @@ -556,13 +556,13 @@ CodeClass def_class( StrC name | ||||
| 	if ( attributes && attributes->Type != PlatformAttributes ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_class: attributes was not a 'PlatformAttributes' type: %s", attributes.debug_str() ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	if ( parent && ( parent->Type != Class && parent->Type != Struct && parent->Type != Typename && parent->Type != Untyped ) ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_class: parent provided is not type 'Class', 'Struct', 'Typeanme', or 'Untyped': %s", parent.debug_str() ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	CodeClass | ||||
| @@ -580,7 +580,7 @@ CodeClass def_class( StrC name | ||||
|  | ||||
| 			default: | ||||
| 				log_failure("gen::def_class: body must be either of Class_Body or Untyped type - %s", body.debug_str()); | ||||
| 				return CodeInvalid; | ||||
| 				return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		result->Type = Class; | ||||
| @@ -623,7 +623,7 @@ CodeDefine def_define( StrC name, StrC content ) | ||||
| 	if ( content.Len <= 0 || content.Ptr == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_define: Invalid value provided" ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| @@ -648,7 +648,7 @@ CodeDestructor def_destructor( Code body, CodeSpecifiers specifiers ) | ||||
| 	if ( specifiers && specifiers->Type != Specifiers ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_destructor: specifiers was not a 'Specifiers' type: %s", specifiers.debug_str() ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	CodeDestructor result = (CodeDestructor) make_code(); | ||||
| @@ -666,7 +666,7 @@ CodeDestructor def_destructor( Code body, CodeSpecifiers specifiers ) | ||||
|  | ||||
| 			default: | ||||
| 				log_failure("gen::def_destructor: body must be either of Function_Body or Untyped type - %s", body.debug_str()); | ||||
| 				return CodeInvalid; | ||||
| 				return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		result->Type = Destructor; | ||||
| @@ -692,13 +692,13 @@ CodeEnum def_enum( StrC name | ||||
| 	if ( type && type->Type != Typename ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_enum: enum underlying type provided was not of type Typename: %s", type.debug_str() ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	if ( attributes && attributes->Type != PlatformAttributes ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_enum: attributes was not a 'PlatformAttributes' type: %s", attributes.debug_str() ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	CodeEnum | ||||
| @@ -716,17 +716,17 @@ CodeEnum def_enum( StrC name | ||||
|  | ||||
| 			default: | ||||
| 				log_failure( "gen::def_enum: body must be of Enum_Body or Untyped type %s", body.debug_str()); | ||||
| 				return CodeInvalid; | ||||
| 				return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		result->Type = specifier == EnumClass ? | ||||
| 		result->Type = specifier == EnumDecl_Class ? | ||||
| 			Enum_Class : Enum; | ||||
|  | ||||
| 		result->Body = body; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		result->Type = specifier == EnumClass ? | ||||
| 		result->Type = specifier == EnumDecl_Class ? | ||||
| 			Enum_Class_Fwd : Enum_Fwd; | ||||
| 	} | ||||
|  | ||||
| @@ -740,7 +740,7 @@ CodeEnum def_enum( StrC name | ||||
| 	else if ( result->Type != Enum_Class_Fwd && result->Type != Enum_Fwd ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_enum: enum forward declaration must have an underlying type" ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	return result; | ||||
| @@ -751,7 +751,7 @@ CodeExec def_execution( StrC content ) | ||||
| 	if ( content.Len <= 0 || content.Ptr == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_execution: Invalid execution provided" ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	Code | ||||
| @@ -773,7 +773,7 @@ CodeExtern def_extern_link( StrC name, Code body ) | ||||
| 	if ( body->Type != Extern_Linkage_Body && body->Type != Untyped ) | ||||
| 	{ | ||||
| 		log_failure("gen::def_extern_linkage: body is not of extern_linkage or untyped type %s", body->debug_str()); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	CodeExtern | ||||
| @@ -805,7 +805,7 @@ CodeFriend def_friend( Code declaration ) | ||||
|  | ||||
| 		default: | ||||
| 			log_failure("gen::def_friend: requires declartion to have class, function, operator, or struct - %s", declaration->debug_str()); | ||||
| 			return CodeInvalid; | ||||
| 			return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	CodeFriend | ||||
| @@ -829,25 +829,25 @@ CodeFn def_function( StrC name | ||||
| 	if ( params && params->Type != Parameters ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_function: params was not a `Parameters` type: %s", params.debug_str() ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	if ( ret_type && ret_type->Type != Typename ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_function: ret_type was not a Typename: %s", ret_type.debug_str() ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	if ( specifiers && specifiers->Type != Specifiers ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_function: specifiers was not a `Specifiers` type: %s", specifiers.debug_str() ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	if ( attributes && attributes->Type != PlatformAttributes ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_function: attributes was not a `PlatformAttributes` type: %s", attributes.debug_str() ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	CodeFn | ||||
| @@ -867,7 +867,7 @@ CodeFn def_function( StrC name | ||||
| 			default: | ||||
| 			{ | ||||
| 				log_failure("gen::def_function: body must be either of Function_Body, Execution, or Untyped type. %s", body->debug_str()); | ||||
| 				return CodeInvalid; | ||||
| 				return InvalidCode; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| @@ -905,7 +905,7 @@ CodeInclude def_include( StrC path, bool foreign ) | ||||
| 	if ( path.Len <= 0 || path.Ptr == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_include: Invalid path provided - %d" ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	StrC content = foreign ? | ||||
| @@ -945,7 +945,7 @@ CodeNS def_namespace( StrC name, Code body, ModuleFlag mflags ) | ||||
| 	if ( body->Type != Namespace_Body && body->Type != Untyped ) | ||||
| 	{ | ||||
| 		log_failure("gen::def_namespace: body is not of namespace or untyped type %s", body.debug_str()); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	CodeNS | ||||
| @@ -968,20 +968,20 @@ CodeOperator def_operator( OperatorT op, StrC nspace | ||||
| 	if ( attributes && attributes->Type != PlatformAttributes ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_operator: PlatformAttributes was provided but its not of attributes type: %s", attributes.debug_str() ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	if ( specifiers && specifiers->Type != Specifiers ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_operator: Specifiers was provided but its not of specifiers type: %s", specifiers.debug_str() ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	OpValidateResult check_result = operator__validate( op, params_code, ret_type, specifiers ); | ||||
|  | ||||
| 	if ( check_result == OpValidateResult::Fail ) | ||||
| 	{ | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	char const* name = nullptr; | ||||
| @@ -1009,7 +1009,7 @@ CodeOperator def_operator( OperatorT op, StrC nspace | ||||
| 			default: | ||||
| 			{ | ||||
| 				log_failure("gen::def_operator: body must be either of Function_Body, Execution, or Untyped type. %s", body->debug_str()); | ||||
| 				return CodeInvalid; | ||||
| 				return InvalidCode; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| @@ -1046,7 +1046,7 @@ CodeOpCast def_operator_cast( CodeType type, Code body, CodeSpecifiers const_spe | ||||
| 	if ( type->Type != Typename ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_operator_cast: type is not a typename - %s", type.debug_str() ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	CodeOpCast result = (CodeOpCast) make_code(); | ||||
| @@ -1058,7 +1058,7 @@ CodeOpCast def_operator_cast( CodeType type, Code body, CodeSpecifiers const_spe | ||||
| 		if ( body->Type != Function_Body && body->Type != Execution ) | ||||
| 		{ | ||||
| 			log_failure( "gen::def_operator_cast: body is not of function body or execution type - %s", body.debug_str() ); | ||||
| 			return CodeInvalid; | ||||
| 			return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		result->Body = body; | ||||
| @@ -1087,13 +1087,13 @@ CodeParam def_param( CodeType type, StrC name, Code value ) | ||||
| 	if ( type->Type != Typename ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_param: type is not a typename - %s", type.debug_str() ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	if ( value && value->Type != Untyped ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_param: value is not untyped - %s", value.debug_str() ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	CodeParam | ||||
| @@ -1118,7 +1118,7 @@ CodePragma def_pragma( StrC directive ) | ||||
| 	if ( directive.Len <= 0 || directive.Ptr == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_comment: Invalid comment provided:" ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	CodePragma | ||||
| @@ -1136,7 +1136,7 @@ CodePreprocessCond def_preprocess_cond( EPreprocessCond type, StrC expr ) | ||||
| 	if ( expr.Len <= 0 || expr.Ptr == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_comment: Invalid comment provided:" ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	CodePreprocessCond | ||||
| @@ -1145,16 +1145,16 @@ CodePreprocessCond def_preprocess_cond( EPreprocessCond type, StrC expr ) | ||||
|  | ||||
| 	switch (type) | ||||
| 	{ | ||||
| 		case EPreprocessCond::If: | ||||
| 		case PreprocessCond_If: | ||||
| 			result->Type = Preprocess_If; | ||||
| 		break; | ||||
| 		case EPreprocessCond::IfDef: | ||||
| 		case PreprocessCond_IfDef: | ||||
| 			result->Type = Preprocess_IfDef; | ||||
| 		break; | ||||
| 		case EPreprocessCond::IfNotDef: | ||||
| 		case PreprocessCond_IfNotDef: | ||||
| 			result->Type = Preprocess_IfNotDef; | ||||
| 		break; | ||||
| 		case EPreprocessCond::ElIf: | ||||
| 		case PreprocessCond_ElIf: | ||||
| 			result->Type = Preprocess_ElIf; | ||||
| 		break; | ||||
| 	} | ||||
| @@ -1184,19 +1184,19 @@ CodeStruct def_struct( StrC name | ||||
| 	if ( attributes && attributes->Type != PlatformAttributes ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_struct: attributes was not a `PlatformAttributes` type - %s", attributes.debug_str() ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	if ( parent && parent->Type != Typename ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_struct: parent was not a `Struct` type - %s", parent.debug_str() ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	if ( body && body->Type != Struct_Body ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_struct: body was not a Struct_Body type - %s", body.debug_str() ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	CodeStruct | ||||
| @@ -1243,7 +1243,7 @@ CodeTemplate def_template( CodeParam params, Code declaration, ModuleFlag mflags | ||||
| 	if ( params && params->Type != ECode::Parameters ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_template: params is not of parameters type - %s", params.debug_str() ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	switch (declaration->Type ) | ||||
| @@ -1276,19 +1276,19 @@ CodeType def_type( StrC name, Code arrayexpr, CodeSpecifiers specifiers, CodeAtt | ||||
| 	if ( attributes && attributes->Type != ECode::PlatformAttributes ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_type: attributes is not of attributes type - %s", attributes.debug_str() ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	if ( specifiers && specifiers->Type != ECode::Specifiers ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_type: specifiers is not of specifiers type - %s", specifiers.debug_str() ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	if ( arrayexpr && arrayexpr->Type != ECode::Untyped ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_type: arrayexpr is not of untyped type - %s", arrayexpr->debug_str() ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	CodeType | ||||
| @@ -1330,13 +1330,13 @@ CodeTypedef def_typedef( StrC name, Code type, CodeAttributes attributes, Module | ||||
| 			break; | ||||
| 		default: | ||||
| 			log_failure( "gen::def_typedef: type was not a Class, Enum, Function Forward, Struct, Typename, or Union - %s", type.debug_str() ); | ||||
| 			return CodeInvalid; | ||||
| 			return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	if ( attributes && attributes->Type != ECode::PlatformAttributes ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_typedef: attributes was not a PlatformAttributes - %s", attributes.debug_str() ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	// Registering the type. | ||||
| @@ -1345,7 +1345,7 @@ CodeTypedef def_typedef( StrC name, Code type, CodeAttributes attributes, Module | ||||
| 	if ( ! registered_type ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_typedef: failed to register type" ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	CodeTypedef | ||||
| @@ -1360,7 +1360,7 @@ CodeTypedef def_typedef( StrC name, Code type, CodeAttributes attributes, Module | ||||
| 		if (type->Type != Untyped) | ||||
| 		{ | ||||
| 			log_failure( "gen::def_typedef: name was empty and type was not untyped (indicating its a function typedef) - %s", type.debug_str() ); | ||||
| 			return CodeInvalid; | ||||
| 			return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		result->Name       = get_cached_string( type->Name ); | ||||
| @@ -1382,13 +1382,13 @@ CodeUnion def_union( StrC name, Code body, CodeAttributes attributes, ModuleFlag | ||||
| 	if ( body->Type != ECode::Union_Body ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_union: body was not a Union_Body type - %s", body.debug_str() ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	if ( attributes && attributes->Type != ECode::PlatformAttributes ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_union: attributes was not a PlatformAttributes type - %s", attributes.debug_str() ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	CodeUnion | ||||
| @@ -1419,13 +1419,13 @@ CodeUsing def_using( StrC name, CodeType type | ||||
| 	if ( ! register_type ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_using: failed to register type" ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	if ( attributes && attributes->Type != ECode::PlatformAttributes ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_using: attributes was not a PlatformAttributes type - %s", attributes.debug_str() ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	CodeUsing | ||||
| @@ -1465,25 +1465,25 @@ CodeVar def_variable( CodeType type, StrC name, Code value | ||||
| 	if ( attributes && attributes->Type != ECode::PlatformAttributes ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_variable: attributes was not a `PlatformAttributes` type - %s", attributes.debug_str() ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	if ( specifiers && specifiers->Type != ECode::Specifiers ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_variable: specifiers was not a `Specifiers` type - %s", specifiers.debug_str() ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	if ( type->Type != ECode::Typename ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_variable: type was not a Typename - %s", type.debug_str() ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	if ( value && value->Type != ECode::Untyped ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_variable: value was not a `Untyped` type - %s", value.debug_str() ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	CodeVar | ||||
| @@ -1513,7 +1513,7 @@ using namespace ECode;                                                        \ | ||||
| if ( num <= 0 )                                                               \ | ||||
| {                                                                             \ | ||||
| 	log_failure("gen::" stringize(Name_) ": num cannot be zero or negative"); \ | ||||
| 	return CodeInvalid;                                                       \ | ||||
| 	return InvalidCode;                                                       \ | ||||
| } | ||||
|  | ||||
| #define def_body_code_array_start( Name_ )                                     \ | ||||
| @@ -1522,13 +1522,13 @@ using namespace ECode;                                                         \ | ||||
| if ( num <= 0 )                                                                \ | ||||
| {                                                                              \ | ||||
| 	log_failure("gen::" stringize(Name_) ": num cannot be zero or negative");  \ | ||||
| 	return CodeInvalid;                                                        \ | ||||
| 	return InvalidCode;                                                        \ | ||||
| }                                                                              \ | ||||
| 																			   \ | ||||
| if ( codes == nullptr )                                                        \ | ||||
| {                                                                              \ | ||||
| 	log_failure("gen::" stringize(Name_)" : Provided a null array of codes");  \ | ||||
| 	return CodeInvalid;                                                        \ | ||||
| 	return InvalidCode;                                                        \ | ||||
| } | ||||
|  | ||||
| #pragma endregion Helper Macros for def_**_body functions | ||||
| @@ -1552,14 +1552,14 @@ CodeBody def_class_body( s32 num, ... ) | ||||
| 			log_failure("gen::" | ||||
| 						"def_class_body" | ||||
| 						": Provided an null entry"); | ||||
| 			return CodeInvalid; | ||||
| 			return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		switch (entry->Type) | ||||
| 		{ | ||||
| 			GEN_AST_BODY_CLASS_UNALLOWED_TYPES | ||||
| 				log_failure("gen::" "def_class_body" ": Entry type is not allowed: %s", entry.debug_str()); | ||||
| 				return CodeInvalid; | ||||
| 				return InvalidCode; | ||||
|  | ||||
| 			default: | ||||
| 			break; | ||||
| @@ -1589,14 +1589,14 @@ CodeBody def_class_body( s32 num, Code* codes ) | ||||
| 		if (!entry) | ||||
| 		{ | ||||
| 			log_failure("gen::" "def_class_body" ": Provided an null entry"); | ||||
| 			return CodeInvalid; | ||||
| 			return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		switch (entry->Type) | ||||
| 		{ | ||||
| 			GEN_AST_BODY_CLASS_UNALLOWED_TYPES | ||||
| 				log_failure("gen::" "def_class_body" ": Entry type is not allowed: %s", entry.debug_str()); | ||||
| 				return CodeInvalid; | ||||
| 				return InvalidCode; | ||||
|  | ||||
| 			default: | ||||
| 			break; | ||||
| @@ -1627,13 +1627,13 @@ CodeBody def_enum_body( s32 num, ... ) | ||||
| 		if ( ! entry ) | ||||
| 		{ | ||||
| 			log_failure("gen::def_enum_body: Provided a null entry"); | ||||
| 			return CodeInvalid; | ||||
| 			return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		if ( entry->Type != Untyped && entry->Type != Comment ) | ||||
| 		{ | ||||
| 			log_failure("gen::def_enum_body: Entry type is not allowed - %s. Must be of untyped or comment type.", entry.debug_str() ); | ||||
| 			return CodeInvalid; | ||||
| 			return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		result.append( entry ); | ||||
| @@ -1659,13 +1659,13 @@ CodeBody def_enum_body( s32 num, Code* codes ) | ||||
| 		if ( ! entry ) | ||||
| 		{ | ||||
| 			log_failure("gen::def_enum_body: Provided a null entry"); | ||||
| 			return CodeInvalid; | ||||
| 			return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		if ( entry->Type != Untyped && entry->Type != Comment ) | ||||
| 		{ | ||||
| 			log_failure("gen::def_enum_body: Entry type is not allowed: %s", entry.debug_str() ); | ||||
| 			return CodeInvalid; | ||||
| 			return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		result.append( entry ); | ||||
| @@ -1693,14 +1693,14 @@ CodeBody def_export_body( s32 num, ... ) | ||||
| 		if (!entry) | ||||
| 		{ | ||||
| 			log_failure("gen::" "def_export_body" ": Provided an null entry"); | ||||
| 			return CodeInvalid; | ||||
| 			return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		switch (entry->Type) | ||||
| 		{ | ||||
| 			GEN_AST_BODY_EXPORT_UNALLOWED_TYPES | ||||
| 				log_failure("gen::" "def_export_body" ": Entry type is not allowed: %s", entry.debug_str()); | ||||
| 				return CodeInvalid; | ||||
| 				return InvalidCode; | ||||
|  | ||||
| 			default: | ||||
| 			break; | ||||
| @@ -1730,14 +1730,14 @@ CodeBody def_export_body( s32 num, Code* codes ) | ||||
| 		if (!entry) | ||||
| 		{ | ||||
| 			log_failure("gen::" "def_export_body" ": Provided an null entry"); | ||||
| 			return CodeInvalid; | ||||
| 			return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		switch (entry->Type) | ||||
| 		{ | ||||
| 			GEN_AST_BODY_EXPORT_UNALLOWED_TYPES | ||||
| 				log_failure("gen::" "def_export_body" ": Entry type is not allowed: %s", entry.debug_str()); | ||||
| 				return CodeInvalid; | ||||
| 				return InvalidCode; | ||||
|  | ||||
| 			default: | ||||
| 			break; | ||||
| @@ -1768,14 +1768,14 @@ CodeBody def_extern_link_body( s32 num, ... ) | ||||
| 		if (!entry) | ||||
| 		{ | ||||
| 			log_failure("gen::" "def_extern_linkage_body" ": Provided an null entry"); | ||||
| 			return CodeInvalid; | ||||
| 			return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		switch (entry->Type) | ||||
| 		{ | ||||
| 			GEN_AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES | ||||
| 				log_failure("gen::" "def_extern_linkage_body" ": Entry type is not allowed: %s", entry.debug_str()); | ||||
| 				return CodeInvalid; | ||||
| 				return InvalidCode; | ||||
|  | ||||
| 			default: | ||||
| 			break; | ||||
| @@ -1805,14 +1805,14 @@ CodeBody def_extern_link_body( s32 num, Code* codes ) | ||||
| 		if (!entry) | ||||
| 		{ | ||||
| 			log_failure("gen::" "def_extern_linkage_body" ": Provided an null entry"); | ||||
| 			return CodeInvalid; | ||||
| 			return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		switch (entry->Type) | ||||
| 		{ | ||||
| 			GEN_AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES | ||||
| 				log_failure("gen::" "def_extern_linkage_body" ": Entry type is not allowed: %s", entry.debug_str()); | ||||
| 				return CodeInvalid; | ||||
| 				return InvalidCode; | ||||
|  | ||||
| 			default: | ||||
| 			break; | ||||
| @@ -1844,7 +1844,7 @@ CodeBody def_function_body( s32 num, ... ) | ||||
| 		if (!entry) | ||||
| 		{ | ||||
| 			log_failure("gen::" stringize(def_function_body) ": Provided an null entry"); | ||||
| 			return CodeInvalid; | ||||
| 			return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		switch (entry->Type) | ||||
| @@ -1852,7 +1852,7 @@ CodeBody def_function_body( s32 num, ... ) | ||||
|  | ||||
| 			GEN_AST_BODY_FUNCTION_UNALLOWED_TYPES | ||||
| 				log_failure("gen::" stringize(def_function_body) ": Entry type is not allowed: %s", entry.debug_str()); | ||||
| 				return CodeInvalid; | ||||
| 				return InvalidCode; | ||||
|  | ||||
| 			default: | ||||
| 			break; | ||||
| @@ -1882,14 +1882,14 @@ CodeBody def_function_body( s32 num, Code* codes ) | ||||
| 		if (!entry) | ||||
| 		{ | ||||
| 			log_failure("gen::" "def_function_body" ": Provided an null entry"); | ||||
| 			return CodeInvalid; | ||||
| 			return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		switch (entry->Type) | ||||
| 		{ | ||||
| 			GEN_AST_BODY_FUNCTION_UNALLOWED_TYPES | ||||
| 				log_failure("gen::" "def_function_body" ": Entry type is not allowed: %s", entry.debug_str()); | ||||
| 				return CodeInvalid; | ||||
| 				return InvalidCode; | ||||
|  | ||||
| 			default: | ||||
| 			break; | ||||
| @@ -1919,18 +1919,18 @@ CodeBody def_global_body( s32 num, ... ) | ||||
| 		if (!entry) | ||||
| 		{ | ||||
| 			log_failure("gen::" "def_global_body" ": Provided an null entry"); | ||||
| 			return CodeInvalid; | ||||
| 			return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		switch (entry->Type) | ||||
| 		{ | ||||
| 			case Global_Body: | ||||
| 				result.append( entry.cast<CodeBody>() ) ; | ||||
| 				result.append( entry.code_cast<CodeBody>() ) ; | ||||
| 				continue; | ||||
|  | ||||
| 			GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES | ||||
| 				log_failure("gen::" "def_global_body" ": Entry type is not allowed: %s", entry.debug_str()); | ||||
| 				return (*Code::Invalid.ast); | ||||
| 				return InvalidCode; | ||||
|  | ||||
| 			default: | ||||
| 			break; | ||||
| @@ -1960,18 +1960,18 @@ CodeBody def_global_body( s32 num, Code* codes ) | ||||
| 		if (!entry) | ||||
| 		{ | ||||
| 			log_failure("gen::" "def_global_body" ": Provided an null entry"); | ||||
| 			return CodeInvalid; | ||||
| 			return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		switch (entry->Type) | ||||
| 		{ | ||||
| 			case Global_Body: | ||||
| 				result.append( entry.cast<CodeBody>() ) ; | ||||
| 				result.append( entry.code_cast<CodeBody>() ) ; | ||||
| 				continue; | ||||
|  | ||||
| 			GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES | ||||
| 				log_failure("gen::" "def_global_body" ": Entry type is not allowed: %s", entry.debug_str()); | ||||
| 				return CodeInvalid; | ||||
| 				return InvalidCode; | ||||
|  | ||||
| 			default: | ||||
| 			break; | ||||
| @@ -2002,14 +2002,14 @@ CodeBody def_namespace_body( s32 num, ... ) | ||||
| 		if (!entry) | ||||
| 		{ | ||||
| 			log_failure("gen::" "def_namespace_body" ": Provided an null entry"); | ||||
| 			return CodeInvalid; | ||||
| 			return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		switch (entry->Type) | ||||
| 		{ | ||||
| 			GEN_AST_BODY_NAMESPACE_UNALLOWED_TYPES | ||||
| 				log_failure("gen::" "def_namespace_body" ": Entry type is not allowed: %s", entry.debug_str()); | ||||
| 				return CodeInvalid; | ||||
| 				return InvalidCode; | ||||
|  | ||||
| 			default: | ||||
| 			break; | ||||
| @@ -2039,14 +2039,14 @@ CodeBody def_namespace_body( s32 num, Code* codes ) | ||||
| 		if (!entry) | ||||
| 		{ | ||||
| 			log_failure("gen::" "def_namespace_body" ": Provided an null entry"); | ||||
| 			return CodeInvalid; | ||||
| 			return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		switch (entry->Type) | ||||
| 		{ | ||||
| 			GEN_AST_BODY_NAMESPACE_UNALLOWED_TYPES | ||||
| 				log_failure("gen::" "def_namespace_body" ": Entry type is not allowed: %s", entry.debug_str() ); | ||||
| 				return CodeInvalid; | ||||
| 				return InvalidCode; | ||||
|  | ||||
| 			default: break; | ||||
| 		} | ||||
| @@ -2073,7 +2073,7 @@ CodeParam def_params( s32 num, ... ) | ||||
| 	if ( param->Type != Parameters ) | ||||
| 	{ | ||||
| 		log_failure( "gen::def_params: param %d is not a Parameters", num - num + 1 ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	CodeParam result = (CodeParam) param.duplicate(); | ||||
| @@ -2086,7 +2086,7 @@ CodeParam def_params( s32 num, ... ) | ||||
| 		if ( param->Type != Parameters ) | ||||
| 		{ | ||||
| 			log_failure( "gen::def_params: param %d is not a Parameters", num - num + 1 ); | ||||
| 			return CodeInvalid; | ||||
| 			return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		result.append( param ); | ||||
| @@ -2104,13 +2104,13 @@ CodeParam def_params( s32 num, CodeParam* codes ) | ||||
| 	if ( current.ast == nullptr )                                                                               \ | ||||
| 	{                                                                                                           \ | ||||
| 		log_failure("gen::def_params: Provide a null code in codes array");                                     \ | ||||
| 		return CodeInvalid;                                                                                     \ | ||||
| 		return InvalidCode;                                                                                     \ | ||||
| 	}                                                                                                           \ | ||||
| 																												\ | ||||
| 	if (current->Type != Parameters )                                                                           \ | ||||
| 	{                                                                                                           \ | ||||
| 		log_failure("gen::def_params: Code in coes array is not of paramter type - %s", current.debug_str() );  \ | ||||
| 		return CodeInvalid;                                                                                     \ | ||||
| 		return InvalidCode;                                                                                     \ | ||||
| 	} | ||||
|  | ||||
| 	CodeParam current = (CodeParam) codes->duplicate(); | ||||
| @@ -2137,13 +2137,13 @@ CodeSpecifiers def_specifiers( s32 num, ... ) | ||||
| 	if ( num <= 0 ) | ||||
| 	{ | ||||
| 		log_failure("gen::def_specifiers: num cannot be zero or less"); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	if ( num > AST::ArrSpecs_Cap ) | ||||
| 	{ | ||||
| 		log_failure("gen::def_specifiers: num of speciifers to define AST larger than AST specicifier capacity - %d", num); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	CodeSpecifiers | ||||
| @@ -2169,13 +2169,13 @@ CodeSpecifiers def_specifiers( s32 num, SpecifierT* specs ) | ||||
| 	if ( num <= 0 ) | ||||
| 	{ | ||||
| 		log_failure("gen::def_specifiers: num cannot be zero or less"); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	if ( num > AST::ArrSpecs_Cap ) | ||||
| 	{ | ||||
| 		log_failure("gen::def_specifiers: num of speciifers to define AST larger than AST specicifier capacity - %d", num); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	CodeSpecifiers | ||||
| @@ -2211,14 +2211,14 @@ CodeBody def_struct_body( s32 num, ... ) | ||||
| 		if (!entry) | ||||
| 		{ | ||||
| 			log_failure("gen::" "def_struct_body" ": Provided an null entry"); | ||||
| 			return CodeInvalid; | ||||
| 			return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		switch (entry->Type) | ||||
| 		{ | ||||
| 			GEN_AST_BODY_STRUCT_UNALLOWED_TYPES | ||||
| 				log_failure("gen::" "def_struct_body" ": Entry type is not allowed: %s", entry.debug_str()); | ||||
| 				return CodeInvalid; | ||||
| 				return InvalidCode; | ||||
|  | ||||
| 			default: | ||||
| 			break; | ||||
| @@ -2248,14 +2248,14 @@ CodeBody def_struct_body( s32 num, Code* codes ) | ||||
| 		if (!entry) | ||||
| 		{ | ||||
| 			log_failure("gen::" "def_struct_body" ": Provided an null entry"); | ||||
| 			return CodeInvalid; | ||||
| 			return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		switch (entry->Type) | ||||
| 		{ | ||||
| 			GEN_AST_BODY_STRUCT_UNALLOWED_TYPES | ||||
| 				log_failure("gen::" "def_struct_body" ": Entry type is not allowed: %s", entry.debug_str() ); | ||||
| 				return CodeInvalid; | ||||
| 				return InvalidCode; | ||||
|  | ||||
| 			default: | ||||
| 			break; | ||||
| @@ -2286,13 +2286,13 @@ CodeBody def_union_body( s32 num, ... ) | ||||
| 		if ( ! entry ) | ||||
| 		{ | ||||
| 			log_failure("gen::def_union_body: Provided a null entry"); | ||||
| 			return CodeInvalid; | ||||
| 			return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		if ( entry->Type != Untyped && entry->Type != Comment ) | ||||
| 		{ | ||||
| 			log_failure("gen::def_union_body: Entry type is not allowed - %s. Must be of untyped or comment type.", entry.debug_str() ); | ||||
| 			return CodeInvalid; | ||||
| 			return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		result.append( entry ); | ||||
| @@ -2318,13 +2318,13 @@ CodeBody def_union_body( s32 num, CodeUnion* codes ) | ||||
| 		if ( ! entry ) | ||||
| 		{ | ||||
| 			log_failure("gen::def_union_body: Provided a null entry"); | ||||
| 			return CodeInvalid; | ||||
| 			return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		if ( entry->Type != Untyped && entry->Type != Comment ) | ||||
| 		{ | ||||
| 			log_failure("gen::def_union_body: Entry type is not allowed: %s", entry.debug_str() ); | ||||
| 			return CodeInvalid; | ||||
| 			return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		result.append( entry ); | ||||
|   | ||||
| @@ -89,11 +89,11 @@ struct Token | ||||
|  | ||||
| 	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 ); | ||||
|  | ||||
| 		result.append_fmt( "Line: %d Column: %d, Type: %.*s Content: %.*s" | ||||
| 		append_fmt( & result, "Line: %d Column: %d, Type: %.*s Content: %.*s" | ||||
| 			, Line, Column | ||||
| 			, type_str.Len, type_str.Ptr | ||||
| 			, Length, Text | ||||
| @@ -222,7 +222,7 @@ s32 lex_preprocessor_directive( | ||||
| 	, Token&           token ) | ||||
| { | ||||
| 	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(); | ||||
| 	SkipWhitespace(); | ||||
| @@ -298,14 +298,14 @@ s32 lex_preprocessor_directive( | ||||
|  | ||||
| 		token.Length = token.Length + token.Text - hash; | ||||
| 		token.Text   = hash; | ||||
| 		Tokens.append( token ); | ||||
| 		append( & Tokens, token ); | ||||
| 		return Lex_Continue; // Skip found token, its all handled here. | ||||
| 	} | ||||
|  | ||||
| 	if ( token.Type == TokType::Preprocess_Else || token.Type == TokType::Preprocess_EndIf ) | ||||
| 	{ | ||||
| 		token.Flags |= TF_Preprocess_Cond; | ||||
| 		Tokens.append( token ); | ||||
| 		append( & Tokens, token ); | ||||
| 		end_line(); | ||||
| 		return Lex_Continue; | ||||
| 	} | ||||
| @@ -314,7 +314,7 @@ s32 lex_preprocessor_directive( | ||||
| 		token.Flags |= TF_Preprocess_Cond; | ||||
| 	} | ||||
|  | ||||
| 	Tokens.append( token ); | ||||
| 	append( & Tokens, token ); | ||||
|  | ||||
| 	SkipWhitespace(); | ||||
|  | ||||
| @@ -338,10 +338,10 @@ s32 lex_preprocessor_directive( | ||||
| 			name.Length++; | ||||
| 		} | ||||
|  | ||||
| 		Tokens.append( name ); | ||||
| 		append( & Tokens, name ); | ||||
|  | ||||
| 		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 }; | ||||
| @@ -352,7 +352,7 @@ s32 lex_preprocessor_directive( | ||||
|  | ||||
| 		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" | ||||
| 				, current | ||||
| @@ -384,7 +384,7 @@ s32 lex_preprocessor_directive( | ||||
| 			move_forward(); | ||||
| 		} | ||||
|  | ||||
| 		Tokens.append( preprocess_content ); | ||||
| 		append( & Tokens, preprocess_content ); | ||||
| 		return Lex_Continue; // Skip found token, its all handled here. | ||||
| 	} | ||||
|  | ||||
| @@ -419,8 +419,8 @@ s32 lex_preprocessor_directive( | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				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 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 ); | ||||
|  | ||||
| 				log_failure( "gen::Parser::lex: Invalid escape sequence '\\%c' (%d, %d)" | ||||
| 							" in preprocessor directive '%s' (%d, %d)\n%s" | ||||
| @@ -446,7 +446,7 @@ s32 lex_preprocessor_directive( | ||||
| 		preprocess_content.Length++; | ||||
| 	} | ||||
|  | ||||
| 	Tokens.append( preprocess_content ); | ||||
| 	append( & Tokens, preprocess_content ); | ||||
| 	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 ) | ||||
| 	{ | ||||
| 		Tokens.append( token ); | ||||
| 		append( & Tokens, token ); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| @@ -488,7 +488,7 @@ void lex_found_token( StrC& content | ||||
| 		} | ||||
|  | ||||
| 		token.Type = type; | ||||
| 		Tokens.append( token ); | ||||
| 		append( & Tokens, token ); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| @@ -498,7 +498,7 @@ void lex_found_token( StrC& content | ||||
| 	{ | ||||
| 		token.Type   = type; | ||||
| 		token.Flags |= TF_Specifier; | ||||
| 		Tokens.append( token ); | ||||
| 		append( & Tokens, token ); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| @@ -506,7 +506,7 @@ void lex_found_token( StrC& content | ||||
| 	if ( type != TokType::Invalid ) | ||||
| 	{ | ||||
| 		token.Type = type; | ||||
| 		Tokens.append( token ); | ||||
| 		append( & Tokens, token ); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| @@ -516,7 +516,7 @@ void lex_found_token( StrC& content | ||||
| 	else | ||||
| 		key = crc32( token.Text, token.Length ); | ||||
|  | ||||
| 	StrC* define = defines.get( key ); | ||||
| 	StrC* define = get(defines, key ); | ||||
| 	if ( define ) | ||||
| 	{ | ||||
| 		token.Type = TokType::Preprocess_Macro; | ||||
| @@ -558,7 +558,7 @@ void lex_found_token( StrC& content | ||||
| 		token.Type = TokType::Identifier; | ||||
| 	} | ||||
|  | ||||
| 	Tokens.append( token ); | ||||
| 	append( & Tokens, token ); | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -579,14 +579,14 @@ TokArray lex( StrC content ) | ||||
| 	if ( left <= 0 ) | ||||
| 	{ | ||||
| 		log_failure( "gen::lex: no tokens found (only whitespace provided)" ); | ||||
| 		return { { nullptr }, 0 }; | ||||
| 		return { {}, 0 }; | ||||
| 	} | ||||
|  | ||||
| 	for ( StringCached entry : PreprocessorDefines ) | ||||
| 	foreach( StringCached, entry, PreprocessorDefines ) | ||||
| 	{ | ||||
| 		s32         length  = 0; | ||||
| 		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++; | ||||
| 			length ++; | ||||
| @@ -597,10 +597,10 @@ TokArray lex( StrC content ) | ||||
| 		} | ||||
|  | ||||
| 		u64 key = crc32( entry.Data, length ); | ||||
| 		defines.set( key, entry ); | ||||
| 		set<StrC>(& defines, key, entry ); | ||||
| 	} | ||||
|  | ||||
| 	Tokens.clear(); | ||||
| 	clear(Tokens); | ||||
|  | ||||
| 	while (left ) | ||||
| 	{ | ||||
| @@ -630,7 +630,7 @@ TokArray lex( StrC content ) | ||||
| 				token.Type = TokType::NewLine; | ||||
| 				token.Length++; | ||||
|  | ||||
| 				Tokens.append( token ); | ||||
| 				append( & Tokens, token ); | ||||
| 				continue; | ||||
| 			} | ||||
| 		} | ||||
| @@ -652,7 +652,7 @@ TokArray lex( StrC content ) | ||||
| 						continue; | ||||
|  | ||||
| 					case Lex_ReturnNull: | ||||
| 						return { { nullptr }, 0 }; | ||||
| 						return { {}, 0 }; | ||||
| 				} | ||||
| 			} | ||||
| 			case '.': | ||||
| @@ -678,7 +678,7 @@ TokArray lex( StrC content ) | ||||
| 					} | ||||
| 					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 ); | ||||
| 					} | ||||
| @@ -1099,7 +1099,7 @@ TokArray lex( StrC content ) | ||||
| 							move_forward(); | ||||
| 							token.Length++; | ||||
| 						} | ||||
| 						Tokens.append( token ); | ||||
| 						append( & Tokens, token ); | ||||
| 						continue; | ||||
| 					} | ||||
| 					else if ( current == '*' ) | ||||
| @@ -1135,7 +1135,7 @@ TokArray lex( StrC content ) | ||||
| 							move_forward(); | ||||
| 							token.Length++; | ||||
| 						} | ||||
| 						Tokens.append( token ); | ||||
| 						append( & Tokens, token ); | ||||
| 						// end_line(); | ||||
| 						continue; | ||||
| 					} | ||||
| @@ -1228,9 +1228,9 @@ TokArray lex( StrC content ) | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			s32 start = max( 0, Tokens.num() - 100 ); | ||||
| 			s32 start = max( 0, num(Tokens) - 100 ); | ||||
| 			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" | ||||
| 					, 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 ); | ||||
|  | ||||
| 			// 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 ); | ||||
| 	} | ||||
|  | ||||
| 	if ( Tokens.num() == 0 ) | ||||
| 	if ( num(Tokens) == 0 ) | ||||
| 	{ | ||||
| 		log_failure( "Failed to lex any tokens" ); | ||||
| 		return { { nullptr }, 0 }; | ||||
| 		return { {}, 0 }; | ||||
| 	} | ||||
|  | ||||
| 	defines.clear(); | ||||
| 	clear(defines); | ||||
| 	// defines_map_arena.free(); | ||||
| 	return { Tokens, 0 }; | ||||
| } | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -13,63 +13,71 @@ using LogFailType = ssize(*)(char const*, ...); | ||||
| 	#define log_failure GEN_FATAL | ||||
| #endif | ||||
|  | ||||
| enum class AccessSpec : u32 | ||||
| enum AccessSpec enum_underlying(u32) | ||||
| { | ||||
| 	Default, | ||||
| 	Private, | ||||
| 	Protected, | ||||
| 	Public, | ||||
| 	AccessSpec_Default, | ||||
| 	AccessSpec_Private, | ||||
| 	AccessSpec_Protected, | ||||
| 	AccessSpec_Public, | ||||
|  | ||||
| 	Num_AccessSpec, | ||||
| 	Invalid, | ||||
| 	AccessSpec_Num_AccessSpec, | ||||
| 	AccessSpec_Invalid, | ||||
|  | ||||
| 	AccessSpec_SizeDef = GEN_U32_MAX, | ||||
| }; | ||||
| static_assert( size_of(AccessSpec) == size_of(u32), "AccessSpec not u32 size" ); | ||||
|  | ||||
| inline | ||||
| char const* to_str( AccessSpec type ) | ||||
| { | ||||
| 	local_persist | ||||
| 	char const* lookup[ (u32)AccessSpec::Num_AccessSpec ] = { | ||||
| 	char const* lookup[ (u32)AccessSpec_Num_AccessSpec ] = { | ||||
| 		"", | ||||
| 		"private", | ||||
| 		"protected", | ||||
| 		"public", | ||||
| 	}; | ||||
|  | ||||
| 	if ( type > AccessSpec::Public ) | ||||
| 	if ( type > AccessSpec_Public ) | ||||
| 		return "Invalid"; | ||||
|  | ||||
| 	return lookup[ (u32)type ]; | ||||
| } | ||||
|  | ||||
|  | ||||
| enum CodeFlag : u32 | ||||
| enum CodeFlag enum_underlying(u32) | ||||
| { | ||||
| 	None          = 0, | ||||
| 	FunctionType  = bit(0), | ||||
| 	ParamPack     = bit(1), | ||||
| 	Module_Export = bit(2), | ||||
| 	Module_Import = bit(3), | ||||
| 	CodeFlag_None          = 0, | ||||
| 	CodeFlag_FunctionType  = bit(0), | ||||
| 	CodeFlag_ParamPack     = bit(1), | ||||
| 	CodeFlag_Module_Export = bit(2), | ||||
| 	CodeFlag_Module_Import = bit(3), | ||||
|  | ||||
| 	CodeFlag_SizeDef = GEN_U32_MAX, | ||||
| }; | ||||
| static_assert( size_of(CodeFlag) == size_of(u32), "CodeFlag not u32 size" ); | ||||
|  | ||||
| // Used to indicate if enum definitoin is an enum class or regular enum. | ||||
| enum class EnumT : u8 | ||||
| enum EnumDecl enum_underlying(u8) | ||||
| { | ||||
| 	Regular, | ||||
| 	Class | ||||
| 	EnumDecl_Regular, | ||||
| 	EnumDecl_Class, | ||||
|  | ||||
| 	EnumT_SizeDef = GEN_U8_MAX, | ||||
| }; | ||||
| typedef u8 EnumT; | ||||
|  | ||||
| constexpr EnumT EnumClass   = EnumT::Class; | ||||
| constexpr EnumT EnumRegular = EnumT::Regular; | ||||
|  | ||||
| enum class ModuleFlag : u32 | ||||
| enum ModuleFlag enum_underlying(u32) | ||||
| { | ||||
| 	None    = 0, | ||||
| 	Export  = bit(0), | ||||
| 	Import  = bit(1), | ||||
| 	ModuleFlag_None    = 0, | ||||
| 	ModuleFlag_Export  = bit(0), | ||||
| 	ModuleFlag_Import  = bit(1), | ||||
|  | ||||
| 	Num_ModuleFlags, | ||||
| 	Invalid, | ||||
| 	ModuleFlag_Invalid, | ||||
|  | ||||
| 	ModuleFlag_SizeDef = GEN_U32_MAX, | ||||
| }; | ||||
| static_assert( size_of(ModuleFlag) == size_of(u32), "ModuleFlag not u32 size" ); | ||||
|  | ||||
| inline | ||||
| StrC to_str( ModuleFlag flag ) | ||||
| @@ -81,7 +89,7 @@ StrC to_str( ModuleFlag flag ) | ||||
| 		{ sizeof("import"), "import" }, | ||||
| 	}; | ||||
|  | ||||
| 	if ( flag > ModuleFlag::Import ) | ||||
| 	if ( flag > ModuleFlag_Import ) | ||||
| 		return { sizeof("invalid"), "invalid" }; | ||||
|  | ||||
| 	return lookup[ (u32)flag ]; | ||||
| @@ -93,15 +101,13 @@ ModuleFlag operator|( ModuleFlag A, ModuleFlag B) | ||||
| 	return (ModuleFlag)( (u32)A | (u32)B ); | ||||
| } | ||||
|  | ||||
| enum class EPreprocessCond : u32 | ||||
| enum EPreprocessCond enum_underlying(u32) | ||||
| { | ||||
| 	If, | ||||
| 	IfDef, | ||||
| 	IfNotDef, | ||||
| 	ElIf | ||||
| }; | ||||
| 	PreprocessCond_If, | ||||
| 	PreprocessCond_IfDef, | ||||
| 	PreprocessCond_IfNotDef, | ||||
| 	PreprocessCond_ElIf, | ||||
|  | ||||
| constexpr EPreprocessCond PreprocessCond_If       = EPreprocessCond::If; | ||||
| constexpr EPreprocessCond PreprocessCond_IfDef    = EPreprocessCond::IfDef; | ||||
| constexpr EPreprocessCond PreprocessCond_IfNotDef = EPreprocessCond::IfNotDef; | ||||
| constexpr EPreprocessCond PreprocessCond_ElIf     = EPreprocessCond::ElIf; | ||||
| 	EPreprocessCond_SizeDef = GEN_U32_MAX, | ||||
| }; | ||||
| static_assert( size_of(EPreprocessCond) == size_of(u32), "EPreprocessCond not u32 size" ); | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	pragma once | ||||
| #	include "platform.hpp" | ||||
| #	include "macros.hpp" | ||||
| #endif | ||||
|  | ||||
| @@ -122,13 +123,21 @@ typedef s8  b8; | ||||
| typedef s16 b16; | ||||
| typedef s32 b32; | ||||
|  | ||||
| using mem_ptr       = void*; | ||||
| using mem_ptr_const = void const*; | ||||
| typedef void*       mem_ptr; | ||||
| typedef void const* mem_ptr_const ; | ||||
|  | ||||
| #if ! GEN_COMPILER_C | ||||
| 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> 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; } | ||||
| #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 | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -24,7 +24,7 @@ | ||||
| 	{                                                                                        \ | ||||
| 		if ( ! ( cond ) )                                                                    \ | ||||
| 		{                                                                                    \ | ||||
| 			assert_handler( #cond, __FILE__, scast( s64, __LINE__ ), msg, ##__VA_ARGS__ ); \ | ||||
| 			assert_handler( #cond, __FILE__, scast( s64, __LINE__ ), msg, ##__VA_ARGS__ );   \ | ||||
| 			GEN_DEBUG_TRAP();                                                                \ | ||||
| 		}                                                                                    \ | ||||
| 	} while ( 0 ) | ||||
|   | ||||
| @@ -505,7 +505,7 @@ b8 file_stream_new( FileInfo* file, AllocatorInfo allocator ) | ||||
| 	d->allocator = allocator; | ||||
| 	d->flags     = EFileStream_CLONE_WRITABLE; | ||||
| 	d->cap       = 0; | ||||
| 	d->buf       = Array<u8>::init( allocator ); | ||||
| 	d->buf       = array_init<u8>( allocator ); | ||||
|  | ||||
| 	if ( ! d->buf ) | ||||
| 		return false; | ||||
| @@ -531,7 +531,7 @@ b8 file_stream_open( FileInfo* file, AllocatorInfo allocator, u8* buffer, ssize | ||||
| 	d->flags     = flags; | ||||
| 	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; | ||||
|  | ||||
| 		if ( ! d->buf ) | ||||
| @@ -540,7 +540,7 @@ b8 file_stream_open( FileInfo* file, AllocatorInfo allocator, u8* buffer, ssize | ||||
| 		mem_copy( d->buf, buffer, size ); | ||||
| 		d->cap = size; | ||||
|  | ||||
| 		arr.get_header()->Num = size; | ||||
| 		get_header(arr)->Num = size; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| @@ -610,9 +610,9 @@ GEN_FILE_WRITE_AT_PROC( _memory_file_write ) | ||||
| 	{ | ||||
| 		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; | ||||
| 			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 ); | ||||
| 		d->cap = new_cap; | ||||
| 		arr.get_header()->Capacity = new_cap; | ||||
| 		get_header(arr)->Capacity = new_cap; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| @@ -647,7 +647,7 @@ GEN_FILE_CLOSE_PROC( _memory_file_close ) | ||||
| 	if ( d->flags & EFileStream_CLONE_WRITABLE ) | ||||
| 	{ | ||||
| 		Array<u8> arr = { d->buf }; | ||||
| 		arr.free(); | ||||
| 		free(& arr); | ||||
| 	} | ||||
|  | ||||
| 	free( allocator, d ); | ||||
|   | ||||
| @@ -23,17 +23,39 @@ | ||||
| #define bitfield_is_equal( Type, Field, Mask ) ( (Type(Mask) & Type(Field)) == Type(Mask) ) | ||||
| #endif | ||||
|  | ||||
| #ifndef ccast | ||||
| #define ccast( type, value ) ( const_cast< type >( (value) ) ) | ||||
| #endif | ||||
| #ifndef pcast | ||||
| #define pcast( type, value ) ( * reinterpret_cast< type* >( & ( value ) ) ) | ||||
| #endif | ||||
| #ifndef rcast | ||||
| #define rcast( type, value ) reinterpret_cast< type >( value ) | ||||
| #endif | ||||
| #ifndef scast | ||||
| #define scast( type, value ) static_cast< type >( value ) | ||||
|  | ||||
| #if ! GEN_C_COMPILER | ||||
| #	ifndef cast | ||||
| #	define cast( type, value ) (tmpl_cast<type>( value )) | ||||
| #	endif | ||||
| #	ifndef ccast | ||||
| #	define ccast( type, value ) ( const_cast< type >( (value) ) ) | ||||
| #	endif | ||||
| #	ifndef pcast | ||||
| #	define pcast( type, value ) ( * reinterpret_cast< type* >( & ( value ) ) ) | ||||
| #	endif | ||||
| #	ifndef rcast | ||||
| #	define rcast( type, value ) reinterpret_cast< type >( value ) | ||||
| #	endif | ||||
| #	ifndef scast | ||||
| #	define scast( type, value ) static_cast< type >( value ) | ||||
| #	endif | ||||
| #else | ||||
| #	ifndef cast | ||||
| #	define cast( type, value )  ( (type)(value) ) | ||||
| #	endif | ||||
| #	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 | ||||
| @@ -123,20 +145,20 @@ | ||||
| #define min( a, b ) ( (a < b) ? (a) : (b) ) | ||||
| #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 ) ) | ||||
| #else | ||||
| #	define offset_of( Type, element ) __builtin_offsetof( Type, element ) | ||||
| #endif | ||||
|  | ||||
| #ifndef        forceinline | ||||
| #	ifdef GEN_COMPILER_MSVC | ||||
| #	if GEN_COMPILER_MSVC | ||||
| #		define forceinline __forceinline | ||||
| #		define neverinline __declspec( noinline ) | ||||
| #	elif defined(GEN_COMPILER_GCC) | ||||
| #	elif GEN_COMPILER_GCC | ||||
| #		define forceinline inline __attribute__((__always_inline__)) | ||||
| #		define neverinline __attribute__( ( __noinline__ ) ) | ||||
| #	elif defined(GEN_COMPILER_CLANG) | ||||
| #	elif GEN_COMPILER_CLANG | ||||
| #	if __has_attribute(__always_inline__) | ||||
| #		define forceinline inline __attribute__((__always_inline__)) | ||||
| #		define neverinline __attribute__( ( __noinline__ ) ) | ||||
| @@ -151,11 +173,11 @@ | ||||
| #endif | ||||
|  | ||||
| #ifndef        neverinline | ||||
| #	ifdef GEN_COMPILER_MSVC | ||||
| #	if GEN_COMPILER_MSVC | ||||
| #		define neverinline __declspec( noinline ) | ||||
| #	elif defined(GEN_COMPILER_GCC) | ||||
| #	elif GEN_COMPILER_GCC | ||||
| #		define neverinline __attribute__( ( __noinline__ ) ) | ||||
| #	elif defined(GEN_COMPILER_CLANG) | ||||
| #	elif GEN_COMPILER_CLANG | ||||
| #	if __has_attribute(__always_inline__) | ||||
| #		define neverinline __attribute__( ( __noinline__ ) ) | ||||
| #	else | ||||
| @@ -166,4 +188,50 @@ | ||||
| #	endif | ||||
| #endif | ||||
|  | ||||
| #if !defined(GEN_SUPPORT_CPP_REFERENCES) && (GEN_COMPILER_C || __STDC_VERSION__ < 202311L) | ||||
| #	undef    GEN_SUPPORT_CPP_REFERENCES | ||||
| #	define   GEN_SUPPORT_CPP_REFERENCES 0 | ||||
| #endif | ||||
|  | ||||
| #if !defined(GEN_SUPPORT_CPP_MEMBER_FEATURES) && (GEN_COMPILER_C || __STDC_VERSION__ < 202311L) | ||||
| #	undef    GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| #	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 GEN_COMPILER_C | ||||
| #	if __STDC_VERSION__ >= 202311L | ||||
| #		define enum_underlying(type) : type | ||||
| #	else | ||||
| #		define enum_underlying(type) | ||||
| #   endif | ||||
| #else | ||||
| #	define enum_underlying(type) : type | ||||
| #endif | ||||
|  | ||||
| #if GEN_COMPILER_C | ||||
| #	ifndef nullptr | ||||
| #		define nullptr NULL | ||||
| #	endif | ||||
| #endif | ||||
|  | ||||
| #pragma endregion Macros | ||||
|   | ||||
| @@ -334,7 +334,7 @@ ssize virtual_memory_page_size( ssize* alignment_out ) | ||||
|  | ||||
| #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); | ||||
| 	void*      ptr   = NULL; | ||||
| @@ -384,7 +384,7 @@ void* Arena::allocator_proc( void* allocator_data, AllocType type, ssize size, s | ||||
| 	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); | ||||
| 	void* ptr  = NULL; | ||||
| @@ -457,7 +457,7 @@ void* Pool::allocator_proc( void* allocator_data, AllocType type, ssize size, ss | ||||
| 	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 = {}; | ||||
|  | ||||
| @@ -495,16 +495,16 @@ Pool Pool::init_align( AllocatorInfo backing, ssize num_blocks, ssize block_size | ||||
| 	return pool; | ||||
| } | ||||
|  | ||||
| void Pool::clear() | ||||
| void clear(Pool& pool) | ||||
| { | ||||
| 	ssize    actual_block_size, block_index; | ||||
| 	ssize actual_block_size, block_index; | ||||
| 	void* curr; | ||||
| 	uptr* end; | ||||
|  | ||||
| 	actual_block_size = BlockSize + BlockAlign; | ||||
| 	actual_block_size = pool.BlockSize + pool.BlockAlign; | ||||
|  | ||||
| 	curr = PhysicalStart; | ||||
| 	for ( block_index = 0; block_index < NumBlocks - 1; block_index++ ) | ||||
| 	curr = pool.PhysicalStart; | ||||
| 	for ( block_index = 0; block_index < pool.NumBlocks - 1; block_index++ ) | ||||
| 	{ | ||||
| 		uptr* next = ( uptr* ) curr; | ||||
| 		*next      = ( uptr  ) curr + actual_block_size; | ||||
| @@ -514,7 +514,7 @@ void Pool::clear() | ||||
| 	end  =  ( uptr* ) curr; | ||||
| 	*end =  ( uptr )  NULL; | ||||
|  | ||||
| 	FreeList = PhysicalStart; | ||||
| 	pool.FreeList = pool.PhysicalStart; | ||||
| } | ||||
|  | ||||
| #pragma endregion Memory | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
|  | ||||
| #pragma region Memory | ||||
|  | ||||
| #define kilobytes( x ) ( ( x ) * ( s64 )( 1024 ) ) | ||||
| #define kilobytes( x ) (          ( x ) * ( s64 )( 1024 ) ) | ||||
| #define megabytes( x ) ( kilobytes( x ) * ( s64 )( 1024 ) ) | ||||
| #define gigabytes( x ) ( megabytes( x ) * ( s64 )( 1024 ) ) | ||||
| #define terabytes( x ) ( gigabytes( x ) * ( s64 )( 1024 ) ) | ||||
| @@ -62,24 +62,23 @@ void zero_size( void* ptr, ssize size ); | ||||
| //! Clears up an array. | ||||
| #define zero_array( a, count ) zero_size( ( a ), size_of( *( a ) ) * count ) | ||||
|  | ||||
| enum AllocType : u8 | ||||
| enum AllocType_Def //enum_underlying(u8) | ||||
| { | ||||
| 	EAllocation_ALLOC, | ||||
| 	EAllocation_FREE, | ||||
| 	EAllocation_FREE_ALL, | ||||
| 	EAllocation_RESIZE, | ||||
| }; | ||||
| typedef enum AllocType_Def AllocType; | ||||
|  | ||||
| using AllocatorProc = void* ( void* allocator_data, AllocType type | ||||
| 	, ssize size, ssize alignment | ||||
| 	, void* old_memory, ssize old_size | ||||
| 	, u64 flags ); | ||||
| typedef void*(AllocatorProc)( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ); | ||||
|  | ||||
| struct AllocatorInfo | ||||
| struct AllocatorInfo_Def | ||||
| { | ||||
| 	AllocatorProc* Proc; | ||||
| 	void*          Data; | ||||
| }; | ||||
| typedef struct AllocatorInfo_Def AllocatorInfo; | ||||
|  | ||||
| enum AllocFlag | ||||
| { | ||||
| @@ -135,7 +134,7 @@ void* default_resize_align( AllocatorInfo a, void* ptr, ssize old_size, ssize ne | ||||
| void* heap_allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ); | ||||
|  | ||||
| //! The heap allocator backed by operating system's memory manager. | ||||
| constexpr AllocatorInfo heap( void ) { return { heap_allocator_proc, nullptr }; } | ||||
| constexpr AllocatorInfo heap( void ) { AllocatorInfo allocator = { heap_allocator_proc, nullptr }; return allocator; } | ||||
|  | ||||
| //! Helper to allocate memory using heap allocator. | ||||
| #define malloc( sz ) alloc( heap(), sz ) | ||||
| @@ -170,121 +169,206 @@ b32 gen_vm_purge( VirtualMemory vm ); | ||||
| //! Retrieve VM's page size and alignment. | ||||
| ssize gen_virtual_memory_page_size( ssize* alignment_out ); | ||||
|  | ||||
| struct Arena | ||||
| { | ||||
| 	static | ||||
| 	void* allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ); | ||||
| #pragma region Arena | ||||
| struct Arena; | ||||
|  | ||||
| 	static | ||||
| 	Arena init_from_memory( void* start, ssize size ) | ||||
| 	{ | ||||
| 		return | ||||
| 		{ | ||||
| 			{ nullptr, nullptr }, | ||||
| 			start, | ||||
| 			size, | ||||
| 			0, | ||||
| 			0 | ||||
| 		}; | ||||
| 	} | ||||
| AllocatorInfo allocator_info( Arena* arena ); | ||||
|  | ||||
| 	static | ||||
| 	Arena init_from_allocator( AllocatorInfo backing, ssize size ) | ||||
| 	{ | ||||
| 		Arena result = | ||||
| 		{ | ||||
| 		backing, | ||||
| 		alloc( backing, size), | ||||
| 		size, | ||||
| 		0, | ||||
| 		0 | ||||
| 		}; | ||||
| 		return result; | ||||
| 	} | ||||
| // 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); | ||||
|  | ||||
| 	static | ||||
| 	Arena init_sub( Arena& parent, ssize size ) | ||||
| 	{ | ||||
| 		return init_from_allocator( parent.Backing, size ); | ||||
| 	} | ||||
| // 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 ); | ||||
|  | ||||
| 	ssize alignment_of( ssize alignment ) | ||||
| 	{ | ||||
| 		ssize alignment_offset, result_pointer, mask; | ||||
| 		GEN_ASSERT( is_power_of_two( alignment ) ); | ||||
|  | ||||
| 		alignment_offset = 0; | ||||
| 		result_pointer   = (ssize) PhysicalStart + TotalUsed; | ||||
| 		mask             = alignment - 1; | ||||
|  | ||||
| 		if ( result_pointer & mask ) | ||||
| 			alignment_offset = alignment - ( result_pointer & mask ); | ||||
|  | ||||
| 		return alignment_offset; | ||||
| 	} | ||||
| Arena init_sub      (Arena* parent, ssize size); | ||||
| ssize alignment_of  (Arena* arena, ssize alignment); | ||||
| void  free          (Arena* arena); | ||||
| ssize size_remaining(Arena* arena, ssize alignment); | ||||
|  | ||||
| // This id is defined by Unreal for asserts | ||||
| #pragma push_macro("check") | ||||
| #undef check | ||||
| 	void check() | ||||
| 	{ | ||||
| 		GEN_ASSERT( TempCount == 0 ); | ||||
| 	} | ||||
| void   check(Arena* arena); | ||||
| #pragma pop_macro("check") | ||||
|  | ||||
| 	void free() | ||||
| 	{ | ||||
| 		if ( Backing.Proc ) | ||||
| 		{ | ||||
| 			gen::free( Backing, PhysicalStart ); | ||||
| 			PhysicalStart = nullptr; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	ssize size_remaining( ssize alignment ) | ||||
| 	{ | ||||
| 		ssize result = TotalSize - ( TotalUsed + alignment_of( alignment ) ); | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| struct Arena | ||||
| { | ||||
| 	AllocatorInfo Backing; | ||||
| 	void*         PhysicalStart; | ||||
| 	ssize            TotalSize; | ||||
| 	ssize            TotalUsed; | ||||
| 	ssize            TempCount; | ||||
| 	ssize         TotalSize; | ||||
| 	ssize         TotalUsed; | ||||
| 	ssize         TempCount; | ||||
|  | ||||
| 	operator AllocatorInfo() | ||||
| 	{ | ||||
| 		return { allocator_proc, this }; | ||||
| 	} | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| #pragma region Member Mapping | ||||
| 	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 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 | ||||
| }; | ||||
|  | ||||
| #if GEN_SUPPORT_CPP_REFERENCES | ||||
| forceinline AllocatorInfo allocator_info(Arena& arena )                 { return allocator_info(& arena); } | ||||
| forceinline Arena         init_sub      (Arena& parent, ssize size)     { return init_sub( & parent, size); } | ||||
| forceinline ssize         alignment_of  (Arena& arena, ssize alignment) { return alignment_of( & arena, alignment); } | ||||
| forceinline void          free          (Arena& arena)                  { return free(& arena); } | ||||
| forceinline ssize         size_remaining(Arena& arena, ssize alignment) { return size_remaining(& arena, alignment); } | ||||
|  | ||||
| // This id is defined by Unreal for asserts | ||||
| #pragma push_macro("check") | ||||
| #undef check | ||||
| forceinline void check(Arena& arena) { return check(& arena); }; | ||||
| #pragma pop_macro("check") | ||||
| #endif | ||||
|  | ||||
|  | ||||
| inline | ||||
| AllocatorInfo allocator_info( Arena* arena ) { | ||||
| 	GEN_ASSERT(arena != nullptr); | ||||
| 	return { arena_allocator_proc, arena }; | ||||
| } | ||||
|  | ||||
| inline | ||||
| Arena arena_init_from_memory( void* start, ssize size ) | ||||
| { | ||||
| 	Arena arena = { | ||||
| 		{ nullptr, nullptr }, | ||||
| 		start, | ||||
| 		size, | ||||
| 		0, | ||||
| 		0 | ||||
| 	}; | ||||
| 	return arena; | ||||
| } | ||||
|  | ||||
| inline | ||||
| Arena arena_init_from_allocator(AllocatorInfo backing, ssize size) { | ||||
| 	Arena result = { | ||||
| 		backing, | ||||
| 		alloc(backing, size), | ||||
| 		size, | ||||
| 		0, | ||||
| 		0 | ||||
| 	}; | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| inline | ||||
| Arena init_sub(Arena* parent, ssize size) { | ||||
| 	GEN_ASSERT(parent != nullptr); | ||||
| 	return arena_init_from_allocator(parent->Backing, size); | ||||
| } | ||||
|  | ||||
| inline | ||||
| ssize alignment_of(Arena* arena, ssize alignment) | ||||
| { | ||||
| 	GEN_ASSERT(arena != nullptr); | ||||
| 	ssize alignment_offset, result_pointer, mask; | ||||
| 	GEN_ASSERT(is_power_of_two(alignment)); | ||||
|  | ||||
| 	alignment_offset = 0; | ||||
| 	result_pointer  = (ssize)arena->PhysicalStart + arena->TotalUsed; | ||||
| 	mask            = alignment - 1; | ||||
|  | ||||
| 	if (result_pointer & mask) | ||||
| 	alignment_offset = alignment - (result_pointer & mask); | ||||
|  | ||||
| 	return alignment_offset; | ||||
| } | ||||
|  | ||||
| #pragma push_macro("check") | ||||
| #undef check | ||||
| inline | ||||
| void check(Arena* arena) | ||||
| { | ||||
|     GEN_ASSERT(arena != nullptr ); | ||||
|     GEN_ASSERT(arena->TempCount == 0); | ||||
| } | ||||
| #pragma pop_macro("check") | ||||
|  | ||||
| inline | ||||
| void free(Arena* arena) | ||||
| { | ||||
| 	GEN_ASSERT(arena != nullptr); | ||||
| 	if (arena->Backing.Proc) | ||||
| 	{ | ||||
| 		GEN_NS free(arena->Backing, arena->PhysicalStart); | ||||
| 		arena->PhysicalStart = nullptr; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| inline | ||||
| ssize size_remaining(Arena* arena, ssize alignment) | ||||
| { | ||||
| 	GEN_ASSERT(arena != nullptr); | ||||
| 	ssize result = arena->TotalSize - (arena->TotalUsed + alignment_of(arena, alignment)); | ||||
| 	return result; | ||||
| } | ||||
| #pragma endregion Arena | ||||
|  | ||||
| #pragma region FixedArena | ||||
| template<s32 Size> | ||||
| struct FixedArena; | ||||
|  | ||||
| template<s32 Size> FixedArena<Size> fixed_arena_init(); | ||||
| template<s32 Size> AllocatorInfo    allocator_info(FixedArena<Size>* fixed_arena ); | ||||
| template<s32 Size> ssize            size_remaining(FixedArena<Size>* fixed_arena, ssize alignment); | ||||
|  | ||||
| #if GEN_SUPPORT_CPP_REFERENCES | ||||
| template<s32 Size> AllocatorInfo    allocator_info( FixedArena<Size>& fixed_arena )                { return allocator_info(& fixed_arena); } | ||||
| template<s32 Size> ssize            size_remaining(FixedArena<Size>& fixed_arena, ssize alignment) { return size_remaining( & fixed_arena, alignment); } | ||||
| #endif | ||||
|  | ||||
| // 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. | ||||
| template< s32 Size > | ||||
| 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 }; | ||||
| 	} | ||||
|  | ||||
| 	char  memory[Size]; | ||||
| 	Arena arena; | ||||
| 	char  memory[ Size ]; | ||||
|  | ||||
| #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 ) { | ||||
| 	GEN_ASSERT(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_4KB   = FixedArena< kilobytes( 4 ) >; | ||||
| using Arena_8KB   = FixedArena< kilobytes( 8 ) >; | ||||
| @@ -297,31 +381,27 @@ using Arena_512KB = FixedArena< kilobytes( 512 ) >; | ||||
| using Arena_1MB   = FixedArena< megabytes( 1 ) >; | ||||
| using Arena_2MB   = FixedArena< megabytes( 2 ) >; | ||||
| using Arena_4MB   = FixedArena< megabytes( 4 ) >; | ||||
| #pragma endregion FixedArena | ||||
|  | ||||
| #pragma region Pool | ||||
| struct 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); | ||||
| AllocatorInfo allocator_info(Pool* pool); | ||||
| void          clear(Pool* pool); | ||||
| void          free(Pool* pool); | ||||
|  | ||||
| #if GEN_SUPPORT_CPP_REFERENCES | ||||
| AllocatorInfo allocator_info(Pool& pool); | ||||
| void          clear(Pool& pool); | ||||
| void          free(Pool& pool); | ||||
| #endif | ||||
|  | ||||
| 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; | ||||
| 	void*         PhysicalStart; | ||||
| 	void*         FreeList; | ||||
| @@ -330,12 +410,36 @@ struct Pool | ||||
| 	ssize         TotalSize; | ||||
| 	ssize         NumBlocks; | ||||
|  | ||||
| 	operator AllocatorInfo() | ||||
| 	{ | ||||
| 		return { allocator_proc, this }; | ||||
| 	} | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| #pragma region Member Mapping | ||||
|     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 | ||||
| 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->name   = name; | ||||
| 	node->parent = parent; | ||||
| 	node->nodes  = Array<ADT_Node>::init( backing ); | ||||
| 	node->nodes  = array_init<ADT_Node>( backing ); | ||||
|  | ||||
| 	if ( ! node->nodes ) | ||||
| 		return EADT_ERROR_OUT_OF_MEMORY; | ||||
| @@ -36,12 +36,12 @@ u8 adt_destroy_branch( ADT_Node* node ) | ||||
| 	GEN_ASSERT_NOT_NULL( node ); | ||||
| 	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 ); | ||||
| 		} | ||||
|  | ||||
| 		node->nodes.free(); | ||||
| 		free(& node->nodes); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| @@ -66,7 +66,7 @@ ADT_Node* adt_find( ADT_Node* node, char const* name, b32 deep_search ) | ||||
| 		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 ) ) | ||||
| 		{ | ||||
| @@ -76,7 +76,7 @@ ADT_Node* adt_find( ADT_Node* node, char const* name, b32 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 ); | ||||
|  | ||||
| @@ -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 ) | ||||
| { | ||||
| 	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 ) ) | ||||
| 		{ | ||||
| @@ -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 */ | ||||
| 			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 ]; | ||||
| 					if ( child->type != EADT_TYPE_OBJECT ) | ||||
| @@ -225,7 +225,7 @@ ADT_Node* adt_query( ADT_Node* node, char const* uri ) | ||||
| 		/* [value] */ | ||||
| 		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 ]; | ||||
| 				if ( _adt_get_value( child, l_b2 ) ) | ||||
| @@ -257,7 +257,7 @@ ADT_Node* adt_query( ADT_Node* node, char const* uri ) | ||||
| 	else | ||||
| 	{ | ||||
| 		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 ]; | ||||
|  | ||||
| @@ -282,15 +282,16 @@ ADT_Node* adt_alloc_at( ADT_Node* parent, ssize index ) | ||||
| 	if ( ! parent->nodes ) | ||||
| 		return NULL; | ||||
|  | ||||
| 	if ( index < 0 || index > scast(ssize, parent->nodes.num()) ) | ||||
| 	if ( index < 0 || index > scast(ssize, num(parent->nodes)) ) | ||||
| 		return NULL; | ||||
|  | ||||
| 	ADT_Node o = { 0 }; | ||||
| 	o.parent   = parent; | ||||
| 	if ( ! parent->nodes.append_at( o, index ) ) | ||||
| 	if ( ! append_at( & parent->nodes, o, index ) ) | ||||
| 		return NULL; | ||||
|  | ||||
| 	return parent->nodes + index; | ||||
| 	ADT_Node* node = & parent->nodes[index]; | ||||
| 	return node; | ||||
| } | ||||
|  | ||||
| ADT_Node* adt_alloc( ADT_Node* parent ) | ||||
| @@ -303,7 +304,7 @@ ADT_Node* adt_alloc( ADT_Node* parent ) | ||||
| 	if ( ! parent->nodes ) | ||||
| 		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 ) | ||||
| @@ -357,7 +358,7 @@ ADT_Node* adt_move_node( ADT_Node* node, ADT_Node* new_parent ) | ||||
| 	GEN_ASSERT_NOT_NULL( node ); | ||||
| 	GEN_ASSERT_NOT_NULL( new_parent ); | ||||
| 	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 ) | ||||
| @@ -381,7 +382,7 @@ void adt_remove_node( ADT_Node* node ) | ||||
| 	GEN_ASSERT_NOT_NULL( node->parent ); | ||||
| 	ADT_Node* parent = node->parent; | ||||
| 	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 ) | ||||
| @@ -389,7 +390,7 @@ ADT_Node* adt_append_obj( ADT_Node* parent, char const* name ) | ||||
| 	ADT_Node* o = adt_alloc( parent ); | ||||
| 	if ( ! o ) | ||||
| 		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 ); | ||||
| 		return NULL; | ||||
| @@ -402,7 +403,9 @@ ADT_Node* adt_append_arr( ADT_Node* parent, char const* name ) | ||||
| 	ADT_Node* o = adt_alloc( parent ); | ||||
| 	if ( ! o ) | ||||
| 		return NULL; | ||||
| 	if ( adt_set_arr( o, name, parent->nodes.get_header()->Allocator ) ) | ||||
|  | ||||
| 	ArrayHeader* node_header = get_header(parent->nodes); | ||||
| 	if ( adt_set_arr( o, name, node_header->Allocator ) ) | ||||
| 	{ | ||||
| 		adt_remove_node( o ); | ||||
| 		return NULL; | ||||
| @@ -447,7 +450,7 @@ char* adt_parse_number_strict( ADT_Node* node, char* base_str ) | ||||
| 	while ( *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; | ||||
| 	} | ||||
| @@ -476,7 +479,7 @@ char* adt_parse_number( ADT_Node* node, char* base_str ) | ||||
| 	u8        node_props = 0; | ||||
|  | ||||
| 	/* 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; | ||||
| 	} | ||||
| @@ -552,7 +555,7 @@ char* adt_parse_number( ADT_Node* node, char* base_str ) | ||||
| 	char expbuf[ 6 ] = { 0 }; | ||||
| 	ssize   expi        = 0; | ||||
|  | ||||
| 	if ( *e && ! ! str_find( "eE", *e ) ) | ||||
| 	if ( *e && ! ! char_first_occurence( "eE", *e ) ) | ||||
| 	{ | ||||
| 		++e; | ||||
| 		if ( *e == '+' || *e == '-' || char_is_digit( *e ) ) | ||||
| @@ -748,7 +751,7 @@ ADT_Error adt_print_string( FileInfo* file, ADT_Node* node, char const* escaped_ | ||||
| 	{ | ||||
| 		p = str_skip_any( p, escaped_chars ); | ||||
| 		_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 ); | ||||
| 			p++; | ||||
| @@ -946,12 +949,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 ); | ||||
| 		} | ||||
|  | ||||
| 		root->nodes[ columnIndex ].nodes.append( rowItem ); | ||||
| 		append( & root->nodes[ columnIndex ].nodes, rowItem ); | ||||
|  | ||||
| 		if ( delimiter == delim ) | ||||
| 		{ | ||||
| @@ -979,7 +982,7 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b | ||||
| 	} | ||||
| 	while ( *currentChar ); | ||||
|  | ||||
| 	if ( root->nodes.num() == 0 ) | ||||
| 	if (num( root->nodes) == 0 ) | ||||
| 	{ | ||||
| 		GEN_CSV_ASSERT( "unexpected end of input. stream is empty." ); | ||||
| 		error = ECSV_Error__UNEXPECTED_END_OF_INPUT; | ||||
| @@ -989,12 +992,12 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b | ||||
| 	/* consider first row as a 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* hdr = col->nodes; | ||||
| 			col->name       = hdr->string; | ||||
| 			col->nodes.remove_at( 0 ); | ||||
| 			remove_at(col->nodes, 0 ); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @@ -1057,11 +1060,11 @@ void csv_write_delimiter( FileInfo* file, CSV_Object* obj, char delimiter ) | ||||
| 	GEN_ASSERT_NOT_NULL( file ); | ||||
| 	GEN_ASSERT_NOT_NULL( obj ); | ||||
| 	GEN_ASSERT( obj->nodes ); | ||||
| 	ssize cols = obj->nodes.num(); | ||||
| 	ssize cols = num(obj->nodes); | ||||
| 	if ( cols == 0 ) | ||||
| 		return; | ||||
|  | ||||
| 	ssize rows = obj->nodes[ 0 ].nodes.num(); | ||||
| 	ssize rows = num(obj->nodes[ 0 ].nodes); | ||||
| 	if ( rows == 0 ) | ||||
| 		return; | ||||
|  | ||||
| @@ -1099,10 +1102,10 @@ String csv_write_string_delimiter( AllocatorInfo a, CSV_Object* obj, char delimi | ||||
| 	FileInfo tmp; | ||||
| 	file_stream_new( &tmp, a ); | ||||
| 	csv_write_delimiter( &tmp, obj, delimiter ); | ||||
| 	 | ||||
|  | ||||
| 	ssize  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 ); | ||||
| 	return output; | ||||
| } | ||||
|   | ||||
| @@ -83,7 +83,7 @@ struct ADT_Node | ||||
| 	union | ||||
| 	{ | ||||
| 		char const*     string; | ||||
| 		Array<ADT_Node> nodes;    ///< zpl_array | ||||
| 		Array(ADT_Node) nodes;    ///< zpl_array | ||||
|  | ||||
| 		struct | ||||
| 		{ | ||||
|   | ||||
| @@ -76,13 +76,18 @@ | ||||
| /* Platform compiler */ | ||||
|  | ||||
| #if defined( _MSC_VER ) | ||||
| #	define GEN_COMPILER_MSVC 1 | ||||
| #	define GEN_COMPILER_CLANG 0 | ||||
| #	define GEN_COMPILER_MSVC  1 | ||||
| #	define GEN_COMPILER_GCC   0 | ||||
| #elif defined( __GNUC__ ) | ||||
| #	define GEN_COMPILER_GCC 1 | ||||
| #	define GEN_COMPILER_CLANG 0 | ||||
| #	define GEN_COMPILER_MSVC  0 | ||||
| #	define GEN_COMPILER_GCC   1 | ||||
| #elif defined( __clang__ ) | ||||
| #	define GEN_COMPILER_CLANG 1 | ||||
| #elif defined( __MINGW32__ ) | ||||
| #	define GEN_COMPILER_MINGW 1 | ||||
| #	define GEN_COMPILER_MSVC  0 | ||||
| #	define GEN_COMPILER_GCC   1 | ||||
| #else | ||||
| #	error Unknown compiler | ||||
| #endif | ||||
|  | ||||
| @@ -101,6 +106,14 @@ | ||||
| #  define GEN_GCC_VERSION_CHECK(major,minor,patch) (0) | ||||
| #endif | ||||
|  | ||||
| #ifndef GEN_COMPILER_C | ||||
| #	if defined(__STDC_VERSION__) | ||||
| #		define GEN_COMPILER_C 1 | ||||
| #	else | ||||
| #		define GEN_COMPILER_C 0 | ||||
| #	endif | ||||
| #endif | ||||
|  | ||||
| #pragma endregion Platform Detection | ||||
|  | ||||
| #pragma region Mandatory Includes | ||||
| @@ -112,13 +125,29 @@ | ||||
| #		include <intrin.h> | ||||
| #	endif | ||||
|  | ||||
| #if GEN_COMPILER_C | ||||
| #include <assert.h> | ||||
| #endif | ||||
|  | ||||
| #pragma endregion Mandatory Includes | ||||
|  | ||||
| #ifdef GEN_DONT_USE_NAMESPACE | ||||
| #	define GEN_NS | ||||
| #	define GEN_NS_BEGIN | ||||
| #	define GEN_NS_END | ||||
| #if GEN_DONT_USE_NAMESPACE || GEN_COMPILER_C | ||||
| #	if GEN_COMPILER_C | ||||
| #		define GEN_NS_ENUM_BEGIN | ||||
| #		define GEN_NS_ENUM_END | ||||
| #		define GEN_NS | ||||
| #		define GEN_NS_BEGIN | ||||
| #		define GEN_NS_END | ||||
| #	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_BEGIN namespace gen { | ||||
| #	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*) }; | ||||
|  | ||||
| 				info.precision = gen_str.length(); | ||||
| 				info.precision = length(gen_str); | ||||
| 				len            = _print_string( text, remaining, &info, gen_str ); | ||||
| 			} | ||||
| 			break; | ||||
|   | ||||
| @@ -6,7 +6,6 @@ | ||||
| #pragma region String Ops | ||||
|  | ||||
| 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_alphanumeric( char c ); | ||||
|   | ||||
| @@ -4,20 +4,9 @@ | ||||
| #endif | ||||
|  | ||||
| #pragma region String | ||||
|  | ||||
| String String::fmt( AllocatorInfo allocator, char* buf, ssize buf_size, char const* fmt, ... ) | ||||
| String string_make_length( AllocatorInfo allocator, char const* str, ssize length ) | ||||
| { | ||||
| 	va_list va; | ||||
| 	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 ); | ||||
| 	constexpr ssize header_size = sizeof( StringHeader ); | ||||
|  | ||||
| 	s32   alloc_size = header_size + length + 1; | ||||
| 	void* allocation = alloc( allocator, alloc_size ); | ||||
| @@ -25,8 +14,8 @@ String String::make_length( AllocatorInfo allocator, char const* str, ssize leng | ||||
| 	if ( allocation == nullptr ) | ||||
| 		return { nullptr }; | ||||
|  | ||||
| 	Header& | ||||
| 	header = * rcast(Header*, allocation); | ||||
| 	StringHeader& | ||||
| 	header = * rcast(StringHeader*, allocation); | ||||
| 	header = { allocator, length, length }; | ||||
|  | ||||
| 	String  result = { rcast( char*, allocation) + header_size }; | ||||
| @@ -41,9 +30,9 @@ String String::make_length( AllocatorInfo allocator, char const* str, ssize leng | ||||
| 	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; | ||||
| 	void* allocation = alloc( allocator, alloc_size ); | ||||
| @@ -53,8 +42,8 @@ String String::make_reserve( AllocatorInfo allocator, ssize capacity ) | ||||
|  | ||||
| 	mem_set( allocation, 0, alloc_size ); | ||||
|  | ||||
| 	Header* | ||||
| 		header            = rcast(Header*, allocation); | ||||
| 	StringHeader* | ||||
| 	header            = rcast(StringHeader*, allocation); | ||||
| 	header->Allocator = allocator; | ||||
| 	header->Capacity  = capacity; | ||||
| 	header->Length    = 0; | ||||
| @@ -62,69 +51,4 @@ String String::make_reserve( AllocatorInfo allocator, ssize capacity ) | ||||
| 	String result = { rcast(char*, allocation) + header_size }; | ||||
| 	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 | ||||
|   | ||||
| @@ -8,19 +8,20 @@ | ||||
| // Constant string with length. | ||||
| struct StrC | ||||
| { | ||||
| 	ssize          Len; | ||||
| 	ssize       Len; | ||||
| 	char const* Ptr; | ||||
|  | ||||
| #if ! GEN_COMPILER_C | ||||
| 	operator char const* ()               const { return Ptr; } | ||||
| 	char const& operator[]( ssize index ) const { return Ptr[index]; } | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| #define cast_to_strc( str ) * rcast( StrC*, (str) - sizeof(ssize) ) | ||||
| #define txt( text )         StrC { sizeof( text ) - 1, ( text ) } | ||||
|  | ||||
| inline | ||||
| StrC to_str( char const* str ) | ||||
| { | ||||
| StrC to_str( char const* str ) { | ||||
| 	return { str_len( str ), str }; | ||||
| } | ||||
|  | ||||
| @@ -28,388 +29,572 @@ StrC to_str( char const* str ) | ||||
| // This is directly based off the ZPL string api. | ||||
| // They used a header pattern | ||||
| // I kept it for simplicty of porting but its not necessary to keep it that way. | ||||
| #pragma region String | ||||
| struct StringHeader; | ||||
| struct String; | ||||
|  | ||||
| usize string_grow_formula(usize value); | ||||
|  | ||||
| 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); | ||||
| bool          are_equal           (String const lhs, String const rhs); | ||||
| bool          are_equal           (String const 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, String const 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; | ||||
| 	ssize         Capacity; | ||||
| 	ssize         Length; | ||||
| }; | ||||
|  | ||||
| #if ! GEN_COMPILER_C | ||||
| struct String | ||||
| { | ||||
| 	struct Header | ||||
| 	{ | ||||
| 		AllocatorInfo Allocator; | ||||
| 		ssize            Capacity; | ||||
| 		ssize            Length; | ||||
| 	}; | ||||
| 	char* Data; | ||||
|  | ||||
| 	static | ||||
| 	usize grow_formula( usize value ) | ||||
| 	{ | ||||
| 		// Using a very aggressive growth formula to reduce time mem_copying with recursive calls to append in this library. | ||||
| 		return 4 * value + 8; | ||||
| 	} | ||||
| 	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 }; } | ||||
|  | ||||
| 	static | ||||
| 	String make( AllocatorInfo allocator, char const* str ) | ||||
| 	{ | ||||
| 		ssize length = str ? str_len( str ) : 0; | ||||
| 		return make_length( allocator, str, length ); | ||||
| 	} | ||||
|  | ||||
| 	static | ||||
| 	String make( AllocatorInfo allocator, StrC str ) | ||||
| 	{ | ||||
| 		return make_length( allocator, str.Ptr, str.Len ); | ||||
| 	} | ||||
|  | ||||
| 	static | ||||
| 	String make_reserve( AllocatorInfo allocator, ssize capacity ); | ||||
|  | ||||
| 	static | ||||
| 	String make_length( AllocatorInfo allocator, char const* str, ssize length ); | ||||
|  | ||||
| 	static | ||||
| 	String fmt( AllocatorInfo allocator, char* buf, ssize buf_size, 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, "" ); | ||||
|  | ||||
| 		for ( ssize idx = 0; idx < num_parts; ++idx ) | ||||
| 		{ | ||||
| 			result.append( parts[ idx ] ); | ||||
|  | ||||
| 			if ( idx < num_parts - 1 ) | ||||
| 				result.append( glue ); | ||||
| 		} | ||||
|  | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	static | ||||
| 	bool are_equal( String lhs, String rhs ) | ||||
| 	{ | ||||
| 		if ( lhs.length() != rhs.length() ) | ||||
| 			return false; | ||||
|  | ||||
| 		for ( ssize idx = 0; idx < lhs.length(); ++idx ) | ||||
| 			if ( lhs[ idx ] != rhs[ idx ] ) | ||||
| 				return false; | ||||
|  | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	static | ||||
| 	bool are_equal( String lhs, StrC rhs ) | ||||
| 	{ | ||||
| 		if ( lhs.length() != (rhs.Len) ) | ||||
| 			return false; | ||||
|  | ||||
| 		for ( ssize idx = 0; idx < lhs.length(); ++idx ) | ||||
| 			if ( lhs[idx] != rhs[idx] ) | ||||
| 				return false; | ||||
|  | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	bool make_space_for( char const* str, ssize add_len ); | ||||
|  | ||||
| 	bool append( char c ) | ||||
| 	{ | ||||
| 		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; | ||||
| 	} | ||||
|  | ||||
| 	char& back() | ||||
| 	{ | ||||
| 		return Data[ length() - 1 ]; | ||||
| 	} | ||||
|  | ||||
| 	ssize capacity() const | ||||
| 	{ | ||||
| 		Header const& | ||||
| 		header = * rcast( Header const*, Data - sizeof( Header )); | ||||
|  | ||||
| 		return header.Capacity; | ||||
| 	} | ||||
|  | ||||
| 	void clear() | ||||
| 	{ | ||||
| 		get_header().Length = 0; | ||||
| 	} | ||||
|  | ||||
| 	String duplicate( AllocatorInfo allocator ) const | ||||
| 	{ | ||||
| 		return make_length( allocator, Data, length() ); | ||||
| 	} | ||||
|  | ||||
| 	void free() | ||||
| 	{ | ||||
| 		if ( ! Data ) | ||||
| 			return; | ||||
|  | ||||
| 		Header& header = get_header(); | ||||
|  | ||||
| 		gen::free( header.Allocator, & header ); | ||||
| 	} | ||||
|  | ||||
| 	Header& get_header() | ||||
| 	{ | ||||
| 		return *(Header*)(Data - sizeof(Header)); | ||||
| 	} | ||||
|  | ||||
| 	ssize length() const | ||||
| 	{ | ||||
| 		Header const& | ||||
| 		header = * rcast( Header const*, Data - sizeof( Header )); | ||||
|  | ||||
| 		return header.Length; | ||||
| 	} | ||||
|  | ||||
| 	b32 starts_with( StrC substring ) const | ||||
| 	{ | ||||
| 		if (substring.Len > length()) | ||||
| 			return false; | ||||
|  | ||||
| 		b32 result = str_compare(Data, substring.Ptr, substring.Len ) == 0; | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	b32 starts_with( String substring ) const | ||||
| 	{ | ||||
| 		if (substring.length() > length()) | ||||
| 			return false; | ||||
|  | ||||
| 		b32 result = str_compare(Data, substring, substring.length() - 1 ) == 0; | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	void skip_line() | ||||
| 	{ | ||||
| 	#define current (*scanner) | ||||
| 		char* scanner = Data; | ||||
| 		while ( current != '\r' && current != '\n' ) | ||||
| 		{ | ||||
| 			++ scanner; | ||||
| 		} | ||||
|  | ||||
| 		s32 new_length = scanner - Data; | ||||
|  | ||||
| 		if ( current == '\r' ) | ||||
| 		{ | ||||
| 			new_length += 1; | ||||
| 		} | ||||
|  | ||||
| 		mem_move( Data, scanner, new_length ); | ||||
|  | ||||
| 		Header* header = & get_header(); | ||||
| 		header->Length = new_length; | ||||
| 	#undef current | ||||
| 	} | ||||
|  | ||||
| 	void strip_space() | ||||
| 	{ | ||||
| 		char* write_pos = Data; | ||||
| 		char* read_pos  = Data; | ||||
|  | ||||
| 		while ( * read_pos) | ||||
| 		{ | ||||
| 			if ( ! char_is_space( *read_pos )) | ||||
| 			{ | ||||
| 				*write_pos = *read_pos; | ||||
| 				write_pos++; | ||||
| 			} | ||||
| 			read_pos++; | ||||
| 		} | ||||
|  | ||||
| 		write_pos[0] = '\0';  // Null-terminate the modified string | ||||
|  | ||||
| 		// Update the length if needed | ||||
| 		get_header().Length = write_pos - Data; | ||||
| 	} | ||||
|  | ||||
| 	void trim( char const* cut_set ) | ||||
| 	{ | ||||
| 		ssize len = 0; | ||||
|  | ||||
| 		char* start_pos = Data; | ||||
| 		char* end_pos   = Data + length() - 1; | ||||
|  | ||||
| 		while ( start_pos <= end_pos && char_first_occurence( cut_set, *start_pos ) ) | ||||
| 			start_pos++; | ||||
|  | ||||
| 		while ( end_pos > start_pos && char_first_occurence( cut_set, *end_pos ) ) | ||||
| 			end_pos--; | ||||
|  | ||||
| 		len = scast( ssize, ( start_pos > end_pos ) ? 0 : ( ( end_pos - start_pos ) + 1 ) ); | ||||
|  | ||||
| 		if ( Data != start_pos ) | ||||
| 			mem_move( Data, start_pos, len ); | ||||
|  | ||||
| 		Data[ len ] = '\0'; | ||||
|  | ||||
| 		get_header().Length = len; | ||||
| 	} | ||||
|  | ||||
| 	void trim_space() | ||||
| 	{ | ||||
| 		return trim( " \t\r\n\v\f" ); | ||||
| 	} | ||||
|  | ||||
| 	// Debug function that provides a copy of the string with whitespace characters visualized. | ||||
| 	String visualize_whitespace() const | ||||
| 	{ | ||||
| 		Header* header = (Header*)(Data - sizeof(Header)); | ||||
|  | ||||
| 		String result = make_reserve(header->Allocator, length() * 2); // Assume worst case for space requirements. | ||||
|  | ||||
| 		for ( char c : *this ) | ||||
| 		{ | ||||
| 			switch ( c ) | ||||
| 			{ | ||||
| 				case ' ': | ||||
| 					result.append( txt("·") ); | ||||
| 				break; | ||||
| 				case '\t': | ||||
| 					result.append( txt("→") ); | ||||
| 				break; | ||||
| 				case '\n': | ||||
| 					result.append( txt("↵") ); | ||||
| 				break; | ||||
| 				case '\r': | ||||
| 					result.append( txt("⏎") ); | ||||
| 				break; | ||||
| 				case '\v': | ||||
| 					result.append( txt("⇕") ); | ||||
| 				break; | ||||
| 				case '\f': | ||||
| 					result.append( txt("⌂") ); | ||||
| 				break; | ||||
| 				default: | ||||
| 					result.append(c); | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	// For-range support | ||||
|  | ||||
| 	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 ) | ||||
| 	String const& operator=(String const& other) const { | ||||
| 		if (this == &other) | ||||
| 			return *this; | ||||
|  | ||||
| 		String* | ||||
| 		this_ = ccast(String*, this); | ||||
| 		String* this_ = ccast(String*, this); | ||||
| 		this_->Data = other.Data; | ||||
|  | ||||
| 		return *this; | ||||
| 	} | ||||
|  | ||||
| 	char& operator [] ( ssize index ) | ||||
| 	{ | ||||
| 		return Data[ index ]; | ||||
| 	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); } | ||||
|  | ||||
| 	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); | ||||
| 	} | ||||
|  | ||||
| 	char const& operator [] ( ssize index ) const | ||||
| 	{ | ||||
| 		return Data[ index ]; | ||||
| 	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); | ||||
| 	} | ||||
|  | ||||
| 	char* Data; | ||||
| 	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 bool          is_equal(String const& other) const            { return GEN_NS are_equal(* this, other); } | ||||
| 	forceinline bool          is_equal(StrC other) const                     { return GEN_NS are_equal(* this, other); } | ||||
| 	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 | ||||
|  | ||||
| struct String_POD | ||||
| #if GEN_SUPPORT_CPP_REFERENCES | ||||
| 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, ...); | ||||
| char&         back(String& str); | ||||
| void          clear(String& str); | ||||
| void          free(String& str); | ||||
| #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. | ||||
| 	return 4 * value + 8; | ||||
| } | ||||
|  | ||||
| inline | ||||
| String string_make(AllocatorInfo allocator, char const* str) { | ||||
| 	ssize length = str ? str_len(str) : 0; | ||||
| 	return string_make_length(allocator, str, length); | ||||
| } | ||||
|  | ||||
| inline | ||||
| String string_make(AllocatorInfo allocator, StrC str) { | ||||
| 	return string_make_length(allocator, str.Ptr, str.Len); | ||||
| } | ||||
|  | ||||
| inline | ||||
| 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); | ||||
|  | ||||
| 	return string_make(allocator, buf); | ||||
| } | ||||
|  | ||||
| inline | ||||
| 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 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) | ||||
| 	{ | ||||
| 		append(& result, parts[idx]); | ||||
|  | ||||
| 		if (idx < num_parts - 1) | ||||
| 			append(& result, glue); | ||||
| 	} | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| inline | ||||
| bool append(String* str, char c) { | ||||
| 	GEN_ASSERT(str != nullptr); | ||||
| 	return append(str, &c, 1); | ||||
| } | ||||
|  | ||||
| inline | ||||
| bool append(String* str, char const* str_to_append) { | ||||
| 	GEN_ASSERT(str != nullptr); | ||||
| 	return append(str, str_to_append, str_len(str_to_append)); | ||||
| } | ||||
|  | ||||
| inline | ||||
| bool append(String* str, char const* str_to_append, ssize append_length) | ||||
| { | ||||
| 	GEN_ASSERT(str != nullptr); | ||||
| 	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); | ||||
|  | ||||
| 		char* Data = * str; | ||||
| 		mem_copy( Data + curr_len, str_to_append, append_length); | ||||
|  | ||||
| 		Data[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) { | ||||
| 	GEN_ASSERT(str != nullptr); | ||||
| 	return append(str, str_to_append.Ptr, str_to_append.Len); | ||||
| } | ||||
|  | ||||
| inline | ||||
| bool append(String* str, const String other) { | ||||
| 	GEN_ASSERT(str != nullptr); | ||||
| 	return append(str, other, length(other)); | ||||
| } | ||||
|  | ||||
| bool append_fmt(String* str, char const* fmt, ...) { | ||||
| 	GEN_ASSERT(str != nullptr); | ||||
| 	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 const lhs, String const rhs) | ||||
| { | ||||
| 	if (length(lhs) != length(rhs)) | ||||
| 		return false; | ||||
|  | ||||
| 	for (ssize idx = 0; idx < length(lhs); ++idx) | ||||
| 		if (lhs[idx] != rhs[idx]) | ||||
| 			return false; | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| inline | ||||
| bool are_equal(String const lhs, StrC rhs) | ||||
| { | ||||
| 	if (length(lhs) != (rhs.Len)) | ||||
| 		return false; | ||||
|  | ||||
| 	for (ssize idx = 0; idx < length(lhs); ++idx) | ||||
| 		if (lhs[idx] != rhs.Ptr[idx]) | ||||
| 			return false; | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| inline | ||||
| ssize avail_space(String const str) { | ||||
| 	StringHeader const* header = rcast(StringHeader const*, scast(char const*, str) - sizeof(StringHeader)); | ||||
| 	return header->Capacity - header->Length; | ||||
| } | ||||
|  | ||||
| inline | ||||
| char* back(String* str) { | ||||
| 	return & (*str)[length(* str) - 1]; | ||||
| } | ||||
|  | ||||
| inline | ||||
| bool contains(String const str, StrC substring) | ||||
| { | ||||
| 	StringHeader const* header = rcast(StringHeader const*, scast(char const*, str) - sizeof(StringHeader)); | ||||
|  | ||||
| 	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 + 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 + idx, substring, 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; | ||||
| } | ||||
|  | ||||
| inline | ||||
| void clear(String str) { | ||||
|    get_header(str)->Length = 0; | ||||
| } | ||||
|  | ||||
| inline | ||||
| String duplicate(String const str, AllocatorInfo allocator) { | ||||
|    return string_make_length(allocator, str, length(str)); | ||||
| } | ||||
|  | ||||
| inline | ||||
| void free(String* str) { | ||||
| 	GEN_ASSERT(str != nullptr); | ||||
| 	if (! (* str)) | ||||
| 		return; | ||||
|  | ||||
| 	StringHeader* header = get_header(* str); | ||||
| 	GEN_NS free(header->Allocator, header); | ||||
| } | ||||
|  | ||||
| inline | ||||
| StringHeader* get_header(String str) { | ||||
|    return (StringHeader*)(scast(char*, str) - sizeof(StringHeader)); | ||||
| } | ||||
|  | ||||
| inline | ||||
| ssize length(String const str) | ||||
| { | ||||
|    StringHeader const& header = *rcast(StringHeader const*, scast(char const*, str) - sizeof(StringHeader)); | ||||
|    return header.Length; | ||||
| } | ||||
|  | ||||
| inline | ||||
| bool make_space_for(String* str, char const* to_append, ssize add_len) | ||||
| { | ||||
| 	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; | ||||
|  | ||||
| 		header = rcast(StringHeader*, new_ptr); | ||||
| 		header->Allocator = allocator; | ||||
| 		header->Capacity  = new_len; | ||||
|  | ||||
| 		char** Data = rcast(char**, 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; | ||||
| } | ||||
|  | ||||
| inline | ||||
| b32 starts_with(String const str, String substring) { | ||||
| 	if (length(substring) > length(str)) | ||||
| 		return false; | ||||
|  | ||||
| 	b32 result = str_compare(str.Data, substring.Data, length(substring) - 1) == 0; | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| inline | ||||
| void skip_line(String str) | ||||
| { | ||||
| #define current (*scanner) | ||||
| 	char* scanner = str.Data; | ||||
| 	while (current != '\r' && current != '\n') { | ||||
|  		++scanner; | ||||
| 	} | ||||
|  | ||||
| 	s32 new_length = scanner - str.Data; | ||||
|  | ||||
| 	if (current == '\r') { | ||||
| 		new_length += 1; | ||||
| 	} | ||||
|  | ||||
| 	mem_move(str.Data, scanner, new_length); | ||||
|  | ||||
| 	StringHeader* header = get_header(str); | ||||
| 	header->Length = new_length; | ||||
| #undef current | ||||
| } | ||||
|  | ||||
| inline | ||||
| void strip_space(String str) | ||||
| { | ||||
|    char* write_pos = str; | ||||
|    char* read_pos  = str; | ||||
|  | ||||
|    while (* read_pos) | ||||
|    { | ||||
|    	if (! char_is_space(* read_pos)) | ||||
|    	{ | ||||
|    		* write_pos = * read_pos; | ||||
|    		  write_pos++; | ||||
|    	} | ||||
|    	read_pos++; | ||||
|    } | ||||
|  | ||||
|    write_pos[0] = '\0';  // Null-terminate the modified string | ||||
|  | ||||
|    // Update the length if needed | ||||
|    get_header(str)->Length = write_pos - str.Data; | ||||
| } | ||||
|  | ||||
| inline | ||||
| void trim(String str, char const* cut_set) | ||||
| { | ||||
|    ssize len = 0; | ||||
|  | ||||
|    char* start_pos = str.Data; | ||||
|    char* end_pos = str.Data + length(str) - 1; | ||||
|  | ||||
|    while (start_pos <= end_pos && char_first_occurence(cut_set, *start_pos)) | ||||
|    	start_pos++; | ||||
|  | ||||
|    while (end_pos > start_pos && char_first_occurence(cut_set, *end_pos)) | ||||
|    	end_pos--; | ||||
|  | ||||
|    len = scast(ssize, (start_pos > end_pos) ? 0 : ((end_pos - start_pos) + 1)); | ||||
|  | ||||
|    if (str.Data != start_pos) | ||||
|    	mem_move(str.Data, start_pos, len); | ||||
|  | ||||
|    str.Data[len] = '\0'; | ||||
|  | ||||
|    get_header(str)->Length = len; | ||||
| } | ||||
|  | ||||
| inline | ||||
| void trim_space(String str) { | ||||
|    trim(str, " \t\r\n\v\f"); | ||||
| } | ||||
|  | ||||
| inline | ||||
| String visualize_whitespace(String const str) | ||||
| { | ||||
| 	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. | ||||
|  | ||||
| 	for (auto c : str) switch (c) | ||||
| 	{ | ||||
| 		case ' ': | ||||
| 			append(& result, txt("·")); | ||||
| 		break; | ||||
| 		case '\t': | ||||
| 			append(& result, txt("→")); | ||||
| 		break; | ||||
| 		case '\n': | ||||
| 			append(& result, txt("↵")); | ||||
| 		break; | ||||
| 		case '\r': | ||||
| 			append(& result, txt("⏎")); | ||||
| 		break; | ||||
| 		case '\v': | ||||
| 			append(& result, txt("⇕")); | ||||
| 		break; | ||||
| 		case '\f': | ||||
| 			append(& result, txt("⌂")); | ||||
| 		break; | ||||
| 		default: | ||||
| 			append(& result, c); | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
| #pragma endregion String | ||||
|  | ||||
| struct String_POD { | ||||
| 	char* Data; | ||||
| }; | ||||
| static_assert( sizeof( String_POD ) == sizeof( String ), "String is not a POD" ); | ||||
|  | ||||
| // 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. | ||||
| // Should never be modified, if changed string is desired, cache_string( str ) another. | ||||
| using StringCached = String const; | ||||
| typedef String const   StringCached; | ||||
|  | ||||
| #pragma endregion Strings | ||||
|   | ||||
| @@ -11,23 +11,24 @@ using namespace gen; | ||||
| CodeBody gen_ecode( char const* path ) | ||||
| { | ||||
| 	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_parse( &csv_nodes, scratch_mem, GlobalAllocator, false ); | ||||
|  | ||||
| 	Array<ADT_Node> enum_strs = csv_nodes.nodes[0].nodes; | ||||
|  | ||||
| 	String enum_entries   = String::make_reserve( GlobalAllocator, kilobytes(1) ); | ||||
| 	String to_str_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) ); | ||||
|  | ||||
| 	for ( ADT_Node node : enum_strs ) | ||||
| 	for ( ADT_Node& node : enum_strs ) | ||||
| 	{ | ||||
| 		char const* code = node.string; | ||||
| 		enum_entries.append_fmt( "%s,\n", code ); | ||||
| 		to_str_entries.append_fmt( "{ sizeof(\"%s\"), \"%s\" },\n", code, code ); | ||||
|  | ||||
| 		append_fmt( & enum_entries, "%s,\n", 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 };")); | ||||
| @@ -57,9 +58,9 @@ CodeBody gen_ecode( char const* path ) | ||||
| CodeBody gen_eoperator( char const* path ) | ||||
| { | ||||
| 	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_parse( &csv_nodes, scratch_mem, GlobalAllocator, false ); | ||||
| @@ -67,16 +68,16 @@ CodeBody gen_eoperator( char const* path ) | ||||
| 	Array<ADT_Node> enum_strs = csv_nodes.nodes[0].nodes; | ||||
| 	Array<ADT_Node> str_strs  = csv_nodes.nodes[1].nodes; | ||||
|  | ||||
| 	String enum_entries   = String::make_reserve( GlobalAllocator, kilobytes(1) ); | ||||
| 	String to_str_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) ); | ||||
|  | ||||
| 	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* entry_to_str = str_strs [idx].string; | ||||
|  | ||||
| 		enum_entries.append_fmt( "%s,\n", enum_str ); | ||||
| 		to_str_entries.append_fmt( "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str); | ||||
| 		append_fmt( & enum_entries, "%s,\n", enum_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( | ||||
| @@ -113,9 +114,9 @@ CodeBody gen_eoperator( char const* path ) | ||||
| CodeBody gen_especifier( char const* path ) | ||||
| { | ||||
| 	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_parse( &csv_nodes, scratch_mem, GlobalAllocator, false ); | ||||
| @@ -123,16 +124,16 @@ CodeBody gen_especifier( char const* path ) | ||||
| 	Array<ADT_Node> enum_strs = csv_nodes.nodes[0].nodes; | ||||
| 	Array<ADT_Node> str_strs  = csv_nodes.nodes[1].nodes; | ||||
|  | ||||
| 	String enum_entries   = String::make_reserve( GlobalAllocator, kilobytes(1) ); | ||||
| 	String to_str_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) ); | ||||
|  | ||||
| 	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* entry_to_str = str_strs [idx].string; | ||||
|  | ||||
| 		enum_entries.append_fmt( "%s,\n", enum_str ); | ||||
| 		to_str_entries.append_fmt( "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str); | ||||
| 		append_fmt( & enum_entries, "%s,\n", enum_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( | ||||
| @@ -218,14 +219,16 @@ CodeBody gen_especifier( char const* path ) | ||||
| CodeBody gen_etoktype( char const* etok_path, char const* attr_path ) | ||||
| { | ||||
| 	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_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_parse( &csv_attr_nodes, rcast(char*, attrib_content.data), GlobalAllocator, false ); | ||||
| @@ -235,34 +238,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_str_strs = csv_attr_nodes.nodes[1].nodes; | ||||
|  | ||||
| 	String enum_entries             = String::make_reserve( GlobalAllocator, kilobytes(2) ); | ||||
| 	String to_str_entries           = String::make_reserve( GlobalAllocator, kilobytes(4) ); | ||||
| 	String attribute_entries        = String::make_reserve( GlobalAllocator, kilobytes(2) ); | ||||
| 	String to_str_attributes        = String::make_reserve( GlobalAllocator, kilobytes(4) ); | ||||
| 	String attribute_define_entries = String::make_reserve( GlobalAllocator, kilobytes(4) ); | ||||
| 	String enum_entries             = string_make_reserve( GlobalAllocator, kilobytes(2) ); | ||||
| 	String to_str_entries           = string_make_reserve( GlobalAllocator, kilobytes(4) ); | ||||
| 	String attribute_entries        = string_make_reserve( GlobalAllocator, kilobytes(2) ); | ||||
| 	String to_str_attributes        = 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* entry_to_str = enum_str_strs [idx].string; | ||||
|  | ||||
| 		enum_entries.append_fmt( "%s,\n", enum_str ); | ||||
| 		to_str_entries.append_fmt( "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str); | ||||
| 		append_fmt( & enum_entries, "%s,\n", enum_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* entry_to_str  = attribute_str_strs [idx].string; | ||||
|  | ||||
| 		attribute_entries.append_fmt( "Attribute_%s,\n", attribute_str ); | ||||
| 		to_str_attributes.append_fmt( "{ 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_entries, "Attribute_%s,\n", attribute_str ); | ||||
| 		append_fmt( & to_str_attributes, "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str); | ||||
| 		append_fmt( & attribute_define_entries, "Entry( Attribute_%s, \"%s\" )", attribute_str, entry_to_str ); | ||||
|  | ||||
| 		if ( idx < attribute_strs.num() - 1 ) | ||||
| 			attribute_define_entries.append( " \\\n"); | ||||
| 		if ( idx < num(attribute_strs) - 1 ) | ||||
| 			append( & attribute_define_entries, " \\\n"); | ||||
| 		else | ||||
| 			attribute_define_entries.append( "\n"); | ||||
| 			append( & attribute_define_entries, "\n"); | ||||
| 	} | ||||
|  | ||||
| #pragma push_macro("GEN_DEFINE_ATTRIBUTE_TOKENS") | ||||
| @@ -340,59 +343,17 @@ CodeBody gen_etoktype( char const* etok_path, char const* attr_path ) | ||||
|  | ||||
| CodeBody gen_ast_inlines() | ||||
| { | ||||
| #pragma push_macro("GEN_NS") | ||||
| #pragma push_macro("rcast") | ||||
| #pragma push_macro("log_failure") | ||||
| #pragma push_macro("CodeInvalid") | ||||
| #undef GEN_NS | ||||
| #undef rcast | ||||
| #undef log_failure | ||||
| #undef CodeInvalid | ||||
| 	char const* code_impl_tmpl = stringize( | ||||
| 		\n | ||||
| 		inline | ||||
| 		char const* <typename>::debug_str() | ||||
| 		{ | ||||
| 			if ( ast == nullptr ) | ||||
| 				return "Code::debug_str: AST is null!"; | ||||
|  | ||||
| 			return rcast(AST*, ast)->debug_str(); | ||||
| 		} | ||||
| 		inline | ||||
| 		Code <typename>::duplicate() | ||||
| 		{ | ||||
| 			if ( ast == nullptr ) | ||||
| 			{ | ||||
| 				log_failure("Code::duplicate: Cannot duplicate code, AST is null!"); | ||||
| 				return Code::Invalid; | ||||
| 			} | ||||
|  | ||||
| 			return { rcast(AST*, ast)->duplicate() }; | ||||
| 		} | ||||
| 		inline | ||||
| 		bool <typename>::is_equal( Code other ) | ||||
| 		{ | ||||
| 			if ( ast == nullptr || other.ast == nullptr ) | ||||
| 			{ | ||||
| 				// Just check if they're both null. | ||||
| 				// log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); | ||||
| 				return ast == nullptr && other.ast == nullptr; | ||||
| 			} | ||||
| 			return rcast(AST*, ast)->is_equal( other.ast ); | ||||
| 		} | ||||
| 		inline | ||||
| 		bool <typename>::is_valid() | ||||
| 		{ | ||||
| 			return (AST*) ast != nullptr && rcast( AST*, ast)->Type != CodeT::Invalid; | ||||
| 		} | ||||
| 		inline | ||||
| 		void <typename>::set_global() | ||||
| 		{ | ||||
| 			if ( ast == nullptr ) | ||||
| 			{ | ||||
| 				log_failure("Code::set_global: Cannot set code as global, AST is null!"); | ||||
| 				return; | ||||
| 			} | ||||
|  | ||||
| 			rcast(AST*, ast)->Parent = Code::Global.ast; | ||||
| 		} | ||||
| 		inline | ||||
| 		<typename>& <typename>::operator =( Code other ) | ||||
| 		{ | ||||
| 			if ( other.ast && other->Parent ) | ||||
| @@ -405,16 +366,6 @@ CodeBody gen_ast_inlines() | ||||
| 			return *this; | ||||
| 		} | ||||
| 		inline | ||||
| 		bool <typename>::operator ==( Code other ) | ||||
| 		{ | ||||
| 			return (AST*) ast == other.ast; | ||||
| 		} | ||||
| 		inline | ||||
| 		bool <typename>::operator !=( Code other ) | ||||
| 		{ | ||||
| 			return (AST*) ast != other.ast; | ||||
| 		} | ||||
| 		inline | ||||
| 		<typename>::operator bool() | ||||
| 		{ | ||||
| 			return ast != nullptr; | ||||
| @@ -444,6 +395,8 @@ CodeBody gen_ast_inlines() | ||||
| 		} | ||||
| 		\n | ||||
| 	); | ||||
| #pragma pop_macro("GEN_NS") | ||||
| #pragma pop_macro("CodeInvalid") | ||||
|  | ||||
| 	CodeBody impl_code          = parse_global_body( token_fmt( "typename", StrC name(Code),               code_impl_tmpl )); | ||||
| 	CodeBody impl_code_body     = parse_global_body( token_fmt( "typename", StrC name(CodeBody),           code_impl_tmpl )); | ||||
|   | ||||
							
								
								
									
										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 | ||||
| [bool] $bootstrap    = $false | ||||
| [bool] $singleheader = $false | ||||
| [bool] $c_library    = $false | ||||
| [bool] $unreal       = $false | ||||
| [bool] $test         = $false | ||||
|  | ||||
| @@ -59,6 +60,7 @@ if ( $args ) { $args | ForEach-Object { | ||||
| 		"debug"               { $release      = $false } | ||||
| 		"bootstrap"           { $bootstrap    = $true } | ||||
| 		"singleheader"        { $singleheader = $true } | ||||
| 		"c_library"           { $c_library    = $true } | ||||
| 		"unreal"              { $unreal       = $true } | ||||
| 		"test"                { $test         = $true } | ||||
| 	} | ||||
| @@ -88,7 +90,7 @@ else { | ||||
| 	$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" | ||||
| } | ||||
|  | ||||
| @@ -103,8 +105,9 @@ write-host "Build Type: $(if ($release) {"Release"} else {"Debug"} )" | ||||
| $path_build        = Join-Path $path_root build | ||||
| $path_project      = Join-Path $path_root project | ||||
| $path_scripts      = Join-Path $path_root scripts | ||||
| $path_singleheader = Join-Path $path_root singleheader | ||||
| $path_unreal       = Join-Path $path_root unreal_engine | ||||
| $path_c_library    = join-Path $path_root gen_c_library | ||||
| $path_singleheader = Join-Path $path_root gen_singleheader | ||||
| $path_unreal       = Join-Path $path_root gen_unreal_engine | ||||
| $path_test         = Join-Path $path_root test | ||||
|  | ||||
| if ( $bootstrap ) | ||||
| @@ -187,6 +190,68 @@ if ( $singleheader ) | ||||
| 	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 | ||||
|  | ||||
| 	$unit       = join-path $path_c_library "gen.c" | ||||
| 	$executable = join-path $path_build     "gen_c_library_test.exe" | ||||
|  | ||||
| 	if ($vendor -eq "clang") { | ||||
| 		$compiler_args += "-x" | ||||
| 		$compiler_args += "c" | ||||
| 	} elseif ($vendor -eq "msvc") { | ||||
| 		$compiler_args += "/TC" | ||||
| 	} | ||||
|  | ||||
| 	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 test" | ||||
| 			$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 ) | ||||
| { | ||||
| 	$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