mirror of
				https://github.com/Ed94/gencpp.git
				synced 2025-10-30 14:30:53 -07:00 
			
		
		
		
	Compare commits
	
		
			84 Commits
		
	
	
		
			v0.18-Alph
			...
			8bb2bc7b1b
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 8bb2bc7b1b | |||
| a3407c14d5 | |||
| 47b9c37e94 | |||
| 1c3134218e | |||
| a3e7ec4c72 | |||
| cae1555b11 | |||
| f7709bb64e | |||
| 3a55af9ce4 | |||
| 6081834687 | |||
| a3548a5bd3 | |||
| d686831a7c | |||
| ba1dd1894a | |||
| e00b2f8afb | |||
| 72d088c566 | |||
| c6fba23173 | |||
| d45908fb32 | |||
| a7c9dad9fd | |||
| 63ebd0d094 | |||
| f28ae57f16 | |||
| 2fe708e4be | |||
| 69a9abcd59 | |||
| defe42c15c | |||
| 05e65aa464 | |||
| 8f47f3b30f | |||
| 0bad61fda6 | |||
| ea18792373 | |||
| 16b8a3a164 | |||
| 5b0079fb0c | |||
| 9321a04ebc | |||
| 9b68791e38 | |||
| 2dcc968c39 | |||
| 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 | |||
| 81a0376c99 | |||
| 1417a68757 | |||
| 1e4d5ce630 | |||
| 0f2763a115 | |||
| 420f452d35 | |||
| 908c385de5 | |||
| c1878265c8 | |||
| 23742868c4 | |||
| 2e5e31ed3b | |||
| 00df336610 | |||
| d89c9a6072 | |||
| 6aa99ac1d5 | |||
| 3989f5fa83 | |||
| f90c0a59b6 | |||
| 33f992ef56 | |||
| 0542204b35 | |||
| e5616c5879 | |||
| 40a256f6c3 | |||
| b8e1aa6eb7 | 
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -29,3 +29,6 @@ release/** | ||||
| ! **/Unreal/validate.unreal.cpp | ||||
| project/auxillary/vis_ast/dependencies/temp | ||||
| test/gen/original | ||||
| singleheader/gen/scratch.hpp | ||||
| test/gen/scratch.cpp | ||||
| gen_c_library/gen | ||||
|   | ||||
							
								
								
									
										9
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
								
							| @@ -41,6 +41,15 @@ | ||||
| 			"cwd": "${workspaceFolder}/singleheader/", | ||||
| 			"visualizerFile": "${workspaceFolder}/scripts/gencpp.natvis" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"type": "cppvsdbg", | ||||
| 			"request": "launch", | ||||
| 			"name": "Debug unreal vsdbg", | ||||
| 			"program": "${workspaceFolder}/unreal_engine/build/unreal.exe", | ||||
| 			"args": [], | ||||
| 			"cwd": "${workspaceFolder}/unreal_engine/", | ||||
| 			"visualizerFile": "${workspaceFolder}/scripts/gencpp.natvis" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"type": "cppvsdbg", | ||||
| 			"request": "launch", | ||||
|   | ||||
							
								
								
									
										21
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							| @@ -37,7 +37,26 @@ | ||||
| 		"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", | ||||
| 		"assert.h": "c", | ||||
| 		"intrin.h": "c", | ||||
| 		"bit": "cpp", | ||||
| 		"cmath": "cpp", | ||||
| 		"cstddef": "cpp", | ||||
| 		"cstdint": "cpp", | ||||
| 		"cstdio": "cpp", | ||||
| 		"cstdlib": "cpp", | ||||
| 		"cstring": "cpp", | ||||
| 		"ctime": "cpp", | ||||
| 		"cwchar": "cpp", | ||||
| 		"iosfwd": "cpp", | ||||
| 		"new": "cpp", | ||||
| 		"typeinfo": "cpp", | ||||
| 		"unordered_map": "cpp", | ||||
| 		"xstddef": "cpp" | ||||
| 	}, | ||||
| 	"C_Cpp.intelliSenseEngineFallback": "disabled", | ||||
| 	"mesonbuild.configureOnOpen": true, | ||||
|   | ||||
							
								
								
									
										14
									
								
								Readme.md
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								Readme.md
									
									
									
									
									
								
							| @@ -67,7 +67,7 @@ Example using each construction interface: | ||||
| Validation and construction through a functional interface. | ||||
|  | ||||
| ```cpp | ||||
| Code t_uw           = def_type( name(uw) ); | ||||
| Code t_uw           = def_type( name(usize) ); | ||||
| Code t_allocator    = def_type( name(allocator) ); | ||||
| Code t_string_const = def_type( name(char), def_specifiers( args( ESpecifier::Const, ESpecifier::Ptr ) )); | ||||
|  | ||||
| @@ -90,8 +90,8 @@ Validation through ast construction. | ||||
| Code header = parse_struct( code( | ||||
|     struct ArrayHeader | ||||
|     { | ||||
|         uw        Num; | ||||
|         uw        Capacity; | ||||
|         usize        Num; | ||||
|         usize        Capacity; | ||||
|         allocator Allocator; | ||||
|     }; | ||||
| )); | ||||
| @@ -106,8 +106,8 @@ No validation, just glorified text injection. | ||||
| Code header = code_str( | ||||
|     struct ArrayHeader | ||||
|     { | ||||
|         uw        Num; | ||||
|         uw        Capacity; | ||||
|         usize        Num; | ||||
|         usize        Capacity; | ||||
|         allocator Allocator; | ||||
|     }; | ||||
| ); | ||||
| @@ -123,8 +123,8 @@ All three constrcuton interfaces will generate the following C code: | ||||
| ```cpp | ||||
| struct ArrayHeader | ||||
| { | ||||
|     uw        Num; | ||||
|     uw        Capacity; | ||||
|     usize        Num; | ||||
|     usize        Capacity; | ||||
|     allocator Allocator; | ||||
| }; | ||||
| ``` | ||||
|   | ||||
| @@ -552,7 +552,7 @@ Serialization: | ||||
| Fields: | ||||
|  | ||||
| ```cpp | ||||
| SpecifierT     ArrSpecs[ AST::ArrSpecs_Cap ]; | ||||
| SpecifierT     ArrSpecs[ AST_ArrSpecs_Cap ]; | ||||
| CodeSpecifiers NextSpecs; | ||||
| Code           Prev; | ||||
| Code           Next; | ||||
|   | ||||
| @@ -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: | ||||
| @@ -99,7 +101,7 @@ union { | ||||
|     }; | ||||
|     StringCached  Content;          // Attributes, Comment, Execution, Include | ||||
|     struct { | ||||
|         SpecifierT ArrSpecs[AST::ArrSpecs_Cap]; // Specifiers | ||||
|         SpecifierT ArrSpecs[AST_ArrSpecs_Cap]; // Specifiers | ||||
|         AST*       NextSpecs;                   // Specifiers | ||||
|     }; | ||||
| }; | ||||
| @@ -136,7 +138,7 @@ The width dictates how much the static array can hold before it must give way to | ||||
|  | ||||
| ```cpp | ||||
| constexpr static | ||||
| uw ArrSpecs_Cap = | ||||
| usize ArrSpecs_Cap = | ||||
| ( | ||||
|     AST_POD_Size | ||||
|     - sizeof(AST*) * 3 | ||||
| @@ -158,7 +160,7 @@ Data Notes: | ||||
|   * Most of the work is just defining the allocation procedure: | ||||
|  | ||||
| ```cpp | ||||
|     void* ( void* allocator_data, AllocType type, sw size, sw alignment, void* old_memory, sw old_size, u64 flags ); | ||||
|     void* ( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ); | ||||
| ``` | ||||
|  | ||||
| * ASTs are wrapped for the user in a Code struct which is a wrapper for a AST* type. | ||||
|   | ||||
							
								
								
									
										454
									
								
								gen_c_library/c_library.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										454
									
								
								gen_c_library/c_library.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,454 @@ | ||||
| #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 "helpers/push_container_defines.inline.hpp" | ||||
| #include "dependencies/parsing.cpp" | ||||
| #include "helpers/pop_container_defines.inline.hpp" | ||||
| 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_strc_from_c_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(); | ||||
|  | ||||
| 	PreprocessorDefines.append(txt("GEN_API_C_BEGIN")); | ||||
| 	PreprocessorDefines.append(txt("GEN_API_C_END")); | ||||
| 	PreprocessorDefines.append(txt("HashTable(")); | ||||
|  | ||||
| 	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 ); | ||||
|  | ||||
| #pragma region Scan, Parse, and Generate Components | ||||
| 		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(); | ||||
| #pragma endregion Scan, Parse, and Generate Components | ||||
|  | ||||
| #pragma region Scan, Parse, and Generate Dependencies | ||||
| 		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" ); | ||||
| 		Code string_ops   = scan_file( project_dir "dependencies/string_ops.hpp" ); | ||||
| 		Code hashing      = scan_file( project_dir "dependencies/hashing.hpp" ); | ||||
| 		Code filesystem   = scan_file( project_dir "dependencies/filesystem.hpp" ); | ||||
| 		Code timing       = scan_file( project_dir "dependencies/timing.hpp" ); | ||||
|  | ||||
| 		CodeBody parsed_memory = parse_file( project_dir "dependencies/memory.hpp" ); | ||||
| 		CodeBody memory        = def_body(CT_Global_Body); | ||||
| 		for ( Code entry = parsed_memory.begin(); entry != parsed_memory.end(); ++ entry ) | ||||
| 		{ | ||||
| 			switch (entry->Type) | ||||
| 			{ | ||||
| 				case CT_Using: | ||||
| 				{ | ||||
| 					log_fmt("REPLACE THIS MANUALLY: %SC\n", entry->Name); | ||||
| 					CodeUsing   using_ver   = cast(CodeUsing, entry); | ||||
| 					CodeTypedef typedef_ver = def_typedef(using_ver->Name, using_ver->UnderlyingType); | ||||
|  | ||||
| 					memory.append(typedef_ver); | ||||
| 				} | ||||
| 				break; | ||||
| 				case CT_Function_Fwd: | ||||
| 				{ | ||||
| 					CodeFn fn = cast(CodeFn, entry); | ||||
| 					// for ( StrC id : to_rename ) if (fn->Name.is_equal(id)) { | ||||
| 					// 	rename_function_to_unique_symbol(fn); | ||||
| 					// } | ||||
| 					memory.append(fn); | ||||
| 				} | ||||
| 				break; | ||||
| 				case CT_Function: | ||||
| 				{ | ||||
| 					CodeFn fn = cast(CodeFn, entry); | ||||
| 					s32 constexpr_found = fn->Specs.remove( Spec_Constexpr ); | ||||
| 					if (constexpr_found > -1) { | ||||
| 						log_fmt("Found constexpr: %S\n", entry.to_string()); | ||||
| 						fn->Specs.append(Spec_Inline); | ||||
| 					} | ||||
| 					// for ( StrC id : to_rename ) if (fn->Name.is_equal(id)) { | ||||
| 					// 	Array(CodeFn) list = * needs_selectors.get(id); | ||||
| 					// 	list.append(rename_function_to_unique_symbol(fn)); | ||||
| 					// } | ||||
| 					memory.append(fn); | ||||
| 				} | ||||
| 				break; | ||||
| 				case CT_Template: | ||||
| 				{ | ||||
| 					CodeTemplate tmpl = cast(CodeTemplate, entry); | ||||
| 					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 CT_Class: | ||||
| 				case CT_Struct: | ||||
| 				{ | ||||
| 					CodeBody body     = cast(CodeBody, entry->Body); | ||||
| 					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 CT_Preprocess_If: | ||||
| 						{ | ||||
| 							ignore_preprocess_cond_block(txt("GEN_SUPPORT_CPP_MEMBER_FEATURES"), body_entry, body, new_body ); | ||||
| 						} | ||||
| 						break; | ||||
|  | ||||
| 						default: | ||||
| 							new_body.append(body_entry); | ||||
| 						break; | ||||
| 					} | ||||
|  | ||||
| 					entry->Body = new_body; | ||||
| 					memory.append(entry); | ||||
| 				} | ||||
| 				break; | ||||
| 				case CT_Preprocess_If: | ||||
| 				{ | ||||
| 					b32 found = ignore_preprocess_cond_block(txt("GEN_SUPPORT_CPP_MEMBER_FEATURES"), entry, parsed_memory, memory ); | ||||
| 					if (found) break; | ||||
|  | ||||
| 					found = ignore_preprocess_cond_block(txt("GEN_SUPPORT_CPP_REFERENCES"), entry, parsed_memory, memory ); | ||||
| 					if (found) break; | ||||
|  | ||||
| 					memory.append(entry); | ||||
| 				} | ||||
| 				break; | ||||
| 				case CT_Preprocess_IfDef: | ||||
| 				{ | ||||
| 					b32 found = ignore_preprocess_cond_block(txt("GEN_INTELLISENSE_DIRECTIVES"), entry, parsed_memory, memory ); | ||||
| 					if (found) break; | ||||
|  | ||||
| 					memory.append(entry); | ||||
| 				} | ||||
| 				break; | ||||
| 				case CT_Preprocess_Pragma: | ||||
| 				{ | ||||
| 					CodePragma pragma = cast(CodePragma, entry); | ||||
| 					// if (pragma->Content.starts_with(txt("region Memory"))) { | ||||
| 					// 	memory.append(generic_test); | ||||
| 					// 	break; | ||||
| 					// } | ||||
|  | ||||
| 					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; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		CodeBody printing_parsed = parse_file( project_dir "dependencies/printing.hpp" ); | ||||
| 		CodeBody printing        = def_body(CT_Global_Body); | ||||
| 		for ( Code entry = printing_parsed.begin(); entry != printing_parsed.end(); ++ entry ) | ||||
| 		{ | ||||
| 			switch (entry->Type) | ||||
| 			{ | ||||
| 				case CT_Preprocess_IfDef: | ||||
| 				{ | ||||
| 					b32 found = ignore_preprocess_cond_block(txt("GEN_INTELLISENSE_DIRECTIVES"), entry, printing_parsed, printing ); | ||||
| 					if (found) break; | ||||
|  | ||||
| 					printing.append(entry); | ||||
| 				} | ||||
| 				break; | ||||
| 				case CT_Variable: | ||||
| 				{ | ||||
| 					if ( strc_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; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		CodeBody parsed_strings = parse_file( project_dir "dependencies/strings.hpp" ); | ||||
| 		CodeBody strings        = def_body(CT_Global_Body); | ||||
| 		for ( Code entry = parsed_strings.begin(); entry != parsed_strings.end(); ++ entry ) | ||||
| 		{ | ||||
| 			switch (entry->Type) | ||||
| 			{ | ||||
| 				case CT_Preprocess_If: | ||||
| 				{ | ||||
| 					CodePreprocessCond cond = cast(CodePreprocessCond, entry); | ||||
| 					if (cond->Content.starts_with(txt("GEN_COMPILER_C || ! GEN_SUPPORT_CPP_MEMBER_FEATURES"))) | ||||
| 					{ | ||||
| 						for (; entry != end(parsed_strings) && entry->Type != CT_Typedef; ++ entry) {} | ||||
| 						strings.append(entry); | ||||
| 						strings.append(fmt_newline); | ||||
|  | ||||
| 						for (; entry != end(parsed_strings) && entry->Type != CT_Preprocess_EndIf; ++ entry) {} | ||||
| 						++ entry; | ||||
| 						break; | ||||
| 					} | ||||
|  | ||||
| 					bool found = ignore_preprocess_cond_block(txt("GEN_COMPILER_CPP"), entry, parsed_strings, strings); | ||||
| 					if (found) break; | ||||
|  | ||||
| 					found = ignore_preprocess_cond_block(txt("GEN_SUPPORT_CPP_REFERENCES"), entry, parsed_strings, strings ); | ||||
| 				} | ||||
| 				break; | ||||
|  | ||||
| 				case CT_Preprocess_IfDef: | ||||
| 				{ | ||||
| 					ignore_preprocess_cond_block(txt("GEN_INTELLISENSE_DIRECTIVES"), entry, parsed_strings, strings ); | ||||
| 				} | ||||
| 				break; | ||||
|  | ||||
| 				case CT_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 CT_Struct: | ||||
| 				{ | ||||
| 					CodeBody body     = cast(CodeBody, entry->Body); | ||||
| 					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 CT_Preprocess_If: | ||||
| 						{ | ||||
| 							b32 found = ignore_preprocess_cond_block(txt("GEN_COMPILER_CPP"), body_entry, body, new_body ); | ||||
| 							if (found) break; | ||||
|  | ||||
| 							new_body.append(body_entry); | ||||
| 						} | ||||
| 						break; | ||||
| 						default: | ||||
| 							new_body.append(body_entry); | ||||
| 						break; | ||||
| 					} | ||||
| 					entry->Body = new_body; | ||||
| 					strings.append(entry); | ||||
| 				} | ||||
| 				break; | ||||
|  | ||||
| 				case CT_Typedef: | ||||
| 				{ | ||||
| 					StrC name_string_table = txt("StringTable"); | ||||
|  | ||||
| 					CodeTypedef td = cast(CodeTypedef, entry); | ||||
| 					if (td->Name.contains(name_string_table)) | ||||
| 					{ | ||||
| 						CodeBody ht = gen_hashtable(txt("StrC"), name_string_table); | ||||
| 						strings.append(ht); | ||||
| 						break; | ||||
| 					} | ||||
| 					strings.append(td); | ||||
| 				} | ||||
| 				break; | ||||
|  | ||||
| 				default: | ||||
| 					strings.append(entry); | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		CodeBody containers = def_body(CT_Global_Body); | ||||
| 		{ | ||||
| 			CodeBody array_ssize = gen_array(txt("ssize"), txt("Array_ssize")); | ||||
|  | ||||
| 			containers.append( def_pragma(code(region Containers))); | ||||
|  | ||||
| 			// At this point all arrays required should have been defined so its safe to generate the generic selectors. | ||||
| 			containers.append( gen_array_base() ); | ||||
| 			containers.append( gen_array_generic_selection_interface()); | ||||
| 			containers.append( gen_hashtable_base() ); | ||||
|  | ||||
| 			containers.append(fmt_newline); | ||||
| 			containers.append(array_ssize); | ||||
|  | ||||
| 			containers.append( def_pragma(code(endregion Containers))); | ||||
| 			containers.append(fmt_newline); | ||||
| 		} | ||||
| #pragma endregion Scan, Parse, and Generate Dependencies | ||||
|  | ||||
| #pragma region Print Dependencies | ||||
| 		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 ); | ||||
| 		header.print( dump_to_scratch_and_retireve(memory) ); | ||||
| 		header.print( dump_to_scratch_and_retireve(printing)); | ||||
| 		header.print( string_ops ); | ||||
| 		header.print( dump_to_scratch_and_retireve(containers)); | ||||
| 		header.print( hashing ); | ||||
| 		header.print( dump_to_scratch_and_retireve(strings)); | ||||
| 		// header.print( filesystem ); | ||||
| 		// header.print( timing ); | ||||
| 		header.print_fmt( "\nGEN_NS_END\n" ); | ||||
| 		header.print_fmt( roll_own_dependencies_guard_end ); | ||||
| #pragma endregion Print Dependencies | ||||
|  | ||||
|  | ||||
| #if 0 | ||||
| #region region Print Components | ||||
| 		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"); | ||||
| #pragma endregion Print Compoennts | ||||
| #endif | ||||
| 	} | ||||
|  | ||||
| 	header.print( pop_ignores ); | ||||
| 	header.write(); | ||||
|  | ||||
| 	// format_file( "gen/gen.h" ); | ||||
|  | ||||
| 	gen::deinit(); | ||||
| 	return 0; | ||||
| #undef project_dir | ||||
| } | ||||
							
								
								
									
										401
									
								
								gen_c_library/components/containers.array.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										401
									
								
								gen_c_library/components/containers.array.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,401 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "../project/gen.hpp" | ||||
|  | ||||
| using namespace gen; | ||||
|  | ||||
| // Used to know what slot the array will be for generic selection | ||||
| global s32 ArrayDefinitionCounter = 0; | ||||
|  | ||||
| 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 array_grow_formula( value ) ( 2 * value + 8 )\n" )); | ||||
| 	Code get_header   = untyped_str( txt( "#define array_get_header( self ) ( (ArrayHeader*)( self ) - 1)\n" )); | ||||
|  | ||||
| 	return def_global_body( args( fmt_newline, td_header, header, grow_formula, 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" ) | ||||
| #pragma push_macro( "rcast" ) | ||||
| #pragma push_macro( "cast" ) | ||||
| #undef GEN_ASSERT | ||||
| #undef rcast | ||||
| #undef cast | ||||
| 	CodeBody result = parse_global_body( token_fmt( "array_type", (StrC)array_type, "fn", (StrC)fn, "type", (StrC)type | ||||
| 	, stringize( | ||||
| 		typedef <type>* <array_type>; | ||||
|  | ||||
| 		void         <fn>_init           ( <array_type>*  self, AllocatorInfo allocator ); | ||||
| 		void         <fn>_init_reserve   ( <array_type>*  self, AllocatorInfo allocator, usize capacity ); | ||||
| 		bool         <fn>_append_array   ( <array_type>*  self, <array_type> other ); | ||||
| 		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 ); | ||||
| 		void         <fn>_remove_at      ( <array_type>   self, usize idx ); | ||||
| 		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 ); | ||||
|  | ||||
| 		void <fn>_init( <array_type>* self, AllocatorInfo allocator ) | ||||
| 		{ | ||||
| 			size_t initial_size = array_grow_formula(0); | ||||
| 			array_init_reserve( * self, allocator, initial_size ); | ||||
| 		} | ||||
|  | ||||
| 		void <fn>_init_reserve( <array_type>* self, AllocatorInfo allocator, usize capacity ) | ||||
| 		{ | ||||
| 			ArrayHeader* header = rcast(ArrayHeader*, alloc(allocator, sizeof(ArrayHeader) + sizeof(<type>) * capacity)); | ||||
|  | ||||
| 			if (header == nullptr) | ||||
| 				self = nullptr; | ||||
|  | ||||
| 			header->Allocator = allocator; | ||||
| 			header->Capacity  = capacity; | ||||
| 			header->Num       = 0; | ||||
|  | ||||
| 			self = rcast(<array_type>*, header + 1); | ||||
| 		} | ||||
|  | ||||
| 		bool <fn>_append_array( <array_type>* self, <array_type> other ) | ||||
| 		{ | ||||
| 			return array_append_items( * self, (<array_type>)other, <fn>_num(other)); | ||||
| 		} | ||||
|  | ||||
| 		bool <fn>_append( <array_type>* self, <type> value ) | ||||
| 		{ | ||||
| 			ArrayHeader* header = array_get_header( * self ); | ||||
|  | ||||
| 			if ( header->Num == header->Capacity ) | ||||
| 			{ | ||||
| 				if ( ! array_grow( self, header->Capacity)) | ||||
| 					return false; | ||||
|  | ||||
| 				header = array_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 = array_get_header( * self ); | ||||
|  | ||||
| 			if ( header->Num + item_num > header->Capacity ) | ||||
| 			{ | ||||
| 				if ( ! array_grow( self, header->Capacity + item_num )) | ||||
| 					return false; | ||||
|  | ||||
| 				header = array_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 = array_get_header( * self ); | ||||
|  | ||||
| 			if ( idx >= header->Num ) | ||||
| 				idx = header->Num - 1; | ||||
|  | ||||
| 			if ( idx < 0 ) | ||||
| 				idx = 0; | ||||
|  | ||||
| 			if ( header->Capacity < header->Num + 1 ) | ||||
| 			{ | ||||
| 				if ( ! array_grow( self, header->Capacity + 1 ) ) | ||||
| 					return false; | ||||
|  | ||||
| 				header = array_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 = array_get_header( * self ); | ||||
|  | ||||
| 			if ( idx >= header->Num ) | ||||
| 			{ | ||||
| 				return array_append_items( * self, items, item_num ); | ||||
| 			} | ||||
|  | ||||
| 			if ( item_num > header->Capacity ) | ||||
| 			{ | ||||
| 				if ( ! array_grow( self, item_num + header->Capacity ) ) | ||||
| 					return false; | ||||
|  | ||||
| 				header = array_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 = array_get_header( self ); | ||||
|  | ||||
| 			if ( header->Num == 0 ) | ||||
| 				return NULL; | ||||
|  | ||||
| 			return self + header->Num - 1; | ||||
| 		} | ||||
|  | ||||
| 		void <fn>_clear( <array_type> self ) | ||||
| 		{ | ||||
| 			ArrayHeader* header = array_get_header( self ); | ||||
| 			header->Num = 0; | ||||
| 		} | ||||
|  | ||||
| 		bool <fn>_fill( <array_type> self, usize begin, usize end, <type> value ) | ||||
| 		{ | ||||
| 			ArrayHeader* header = array_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 = array_get_header( * self ); | ||||
| 			allocator_free( header->Allocator, header ); | ||||
| 			self = NULL; | ||||
| 		} | ||||
|  | ||||
| 		bool <fn>_grow( <array_type>* self, usize min_capacity ) | ||||
| 		{ | ||||
| 			ArrayHeader* header      = array_get_header( *self ); | ||||
| 			usize       new_capacity = array_grow_formula( header->Capacity ); | ||||
|  | ||||
| 			if ( new_capacity < min_capacity ) | ||||
| 				new_capacity = min_capacity; | ||||
|  | ||||
| 			return array_set_capacity( self, new_capacity ); | ||||
| 		} | ||||
|  | ||||
| 		usize <fn>_num( <array_type> self ) | ||||
| 		{ | ||||
| 			return array_get_header(self)->Num; | ||||
| 		} | ||||
|  | ||||
| 		<type> <fn>_pop( <array_type> self ) | ||||
| 		{ | ||||
| 			ArrayHeader* header = array_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 = array_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 = array_get_header( * self ); | ||||
|  | ||||
| 			if ( header->Capacity < new_capacity ) | ||||
| 				return array_set_capacity( self, new_capacity ); | ||||
|  | ||||
| 			return true; | ||||
| 		} | ||||
|  | ||||
| 		bool <fn>_resize( <array_type>* self, usize num ) | ||||
| 		{ | ||||
| 			ArrayHeader* header = array_get_header( * self ); | ||||
|  | ||||
| 			if ( header->Capacity < num ) | ||||
| 			{ | ||||
| 				if ( ! array_grow( self, num ) ) | ||||
| 					return false; | ||||
|  | ||||
| 				header = array_get_header( * self ); | ||||
| 			} | ||||
|  | ||||
| 			header->Num = num; | ||||
| 			return true; | ||||
| 		} | ||||
|  | ||||
| 		bool <fn>_set_capacity( <array_type>* self, usize new_capacity ) | ||||
| 		{ | ||||
| 			ArrayHeader* header = array_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 ); | ||||
| 			allocator_free( header->Allocator, & header ); | ||||
|  | ||||
| 			new_header->Capacity = new_capacity; | ||||
| 			* self = cast( <type>*, new_header + 1 ); | ||||
| 			return true; | ||||
| 		} | ||||
| 	))); | ||||
| #pragma pop_macro( "GEN_ASSERT" ) | ||||
| #pragma pop_macro( "rcast" ) | ||||
| #pragma pop_macro( "cast" ) | ||||
|  | ||||
| 	++ ArrayDefinitionCounter; | ||||
| 	StrC slot_str = String::fmt_buf(GlobalAllocator, "%d", ArrayDefinitionCounter).to_strc(); | ||||
|  | ||||
| 	Code generic_interface_slot = untyped_str(token_fmt( "type_delimiter", (StrC)array_type, "slot", (StrC)slot_str, | ||||
| R"(#define GENERIC_SLOT_<slot>__array_init         <type_delimiter>,  <type_delimiter>_init | ||||
| #define GENERIC_SLOT_<slot>__array_init_reserve    <type_delimiter>,  <type_delimiter>_init_reserve | ||||
| #define GENERIC_SLOT_<slot>__array_append          <type_delimiter>,  <type_delimiter>_append | ||||
| #define GENERIC_SLOT_<slot>__array_append_items    <type_delimiter>,  <type_delimiter>_append_items | ||||
| #define GENERIC_SLOT_<slot>__array_append_at       <type_delimiter>,  <type_delimiter>_append_at | ||||
| #define GENERIC_SLOT_<slot>__array_append_items_at <type_delimiter>,  <type_delimiter>_append_items_at | ||||
| #define GENERIC_SLOT_<slot>__array_back            <type_delimiter>,  <type_delimiter>_back | ||||
| #define GENERIC_SLOT_<slot>__array_clear           <type_delimiter>,  <type_delimiter>_clear | ||||
| #define GENERIC_SLOT_<slot>__array_fill            <type_delimiter>,  <type_delimiter>_fill | ||||
| #define GENERIC_SLOT_<slot>__array_free            <type_delimiter>,  <type_delimiter>_free | ||||
| #define GENERIC_SLOT_<slot>__array_grow            <type_delimiter>*, <type_delimiter>_grow | ||||
| #define GENERIC_SLOT_<slot>__array_num             <type_delimiter>,  <type_delimiter>_num | ||||
| #define GENERIC_SLOT_<slot>__array_pop             <type_delimiter>,  <type_delimiter>_pop | ||||
| #define GENERIC_SLOT_<slot>__array_remove_at       <type_delimiter>,  <type_delimiter>_remove_at | ||||
| #define GENERIC_SLOT_<slot>__array_reserve         <type_delimiter>,  <type_delimiter>_reserve | ||||
| #define GENERIC_SLOT_<slot>__array_resize          <type_delimiter>,  <type_delimiter>_resize | ||||
| #define GENERIC_SLOT_<slot>__array_set_capacity    <type_delimiter>*, <type_delimiter>_set_capacity | ||||
| )" | ||||
| 	)); | ||||
|  | ||||
| 	return def_global_body( args( | ||||
| 		def_pragma( string_to_strc( string_fmt_buf( GlobalAllocator, "region %S", array_type ))), | ||||
| 		fmt_newline, | ||||
| 		generic_interface_slot, | ||||
| 		fmt_newline, | ||||
| 		result, | ||||
| 		fmt_newline, | ||||
| 		def_pragma( string_to_strc(string_fmt_buf( GlobalAllocator, "endregion %S", array_type ))), | ||||
| 		fmt_newline | ||||
| 	)); | ||||
| }; | ||||
|  | ||||
| constexpr bool array_by_ref = true; | ||||
| Code gen_array_generic_selection_function_macro( StrC macro_name, bool by_ref = false ) | ||||
| { | ||||
| 	local_persist | ||||
| 	String define_builder = String::make_reserve(GlobalAllocator, kilobytes(64)); | ||||
| 	define_builder.clear(); | ||||
|  | ||||
| 	StrC macro_begin = token_fmt( "macro_name", (StrC)macro_name, | ||||
| R"(#define <macro_name>(selector_arg, ...) _Generic( \ | ||||
| 	(selector_arg), /* Select Via Expression*/       \ | ||||
| 		/* Extendibility slots: */                   \ | ||||
| )" | ||||
| 	); | ||||
| 	define_builder.append(macro_begin); | ||||
|  | ||||
| 	for ( s32 slot = 1; slot <= ArrayDefinitionCounter; ++ slot ) | ||||
| 	{ | ||||
| 		StrC slot_str = String::fmt_buf(GlobalAllocator, "%d", slot).to_strc(); | ||||
| 		if (slot == ArrayDefinitionCounter) | ||||
| 		{ | ||||
| 			define_builder.append( token_fmt( "macro_name", macro_name, "slot", slot_str, | ||||
| R"(		GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT_LAST(  GENERIC_SLOT_<slot>__<macro_name> ) \ | ||||
| )" | ||||
| 			)); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		define_builder.append( token_fmt( "macro_name", macro_name, "slot", slot_str, | ||||
| R"(		GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( GENERIC_SLOT_<slot>__<macro_name> ) \ | ||||
| )" | ||||
| 		)); | ||||
| 	} | ||||
|  | ||||
| 	if (by_ref) | ||||
| 		define_builder.append(txt(")\tGEN_RESOLVED_FUNCTION_CALL( & selector_arg, __VA_ARGS__ )")); | ||||
| 	else | ||||
| 		define_builder.append(txt(")\tGEN_RESOLVED_FUNCTION_CALL( selector_arg, __VA_ARGS__ )")); | ||||
|  | ||||
| 	// Add gap for next definition | ||||
| 	define_builder.append(txt("\n\n")); | ||||
|  | ||||
| 	Code macro = untyped_str(define_builder.to_strc()); | ||||
| 	return macro; | ||||
| } | ||||
|  | ||||
| CodeBody gen_array_generic_selection_interface() | ||||
| { | ||||
| 	CodeBody interface_defines = def_body(CT_Global_Body); | ||||
| 	interface_defines.append( gen_array_generic_selection_function_macro(txt("array_init"), array_by_ref) ); | ||||
| 	interface_defines.append( gen_array_generic_selection_function_macro(txt("array_init_reserve"), array_by_ref) ); | ||||
| 	interface_defines.append( gen_array_generic_selection_function_macro(txt("array_append"), array_by_ref) ); | ||||
| 	interface_defines.append( gen_array_generic_selection_function_macro(txt("array_append_items"), array_by_ref) ); | ||||
| 	interface_defines.append( gen_array_generic_selection_function_macro(txt("array_back")) ); | ||||
| 	interface_defines.append( gen_array_generic_selection_function_macro(txt("array_clear")) ); | ||||
| 	interface_defines.append( gen_array_generic_selection_function_macro(txt("array_fill")) ); | ||||
| 	interface_defines.append( gen_array_generic_selection_function_macro(txt("array_free"), array_by_ref) ); | ||||
| 	interface_defines.append( gen_array_generic_selection_function_macro(txt("array_grow")) ); | ||||
| 	interface_defines.append( gen_array_generic_selection_function_macro(txt("array_num")) ); | ||||
| 	interface_defines.append( gen_array_generic_selection_function_macro(txt("arary_pop")) ); | ||||
| 	interface_defines.append( gen_array_generic_selection_function_macro(txt("array_remove_at")) ); | ||||
| 	interface_defines.append( gen_array_generic_selection_function_macro(txt("arary_reserve"), array_by_ref) ); | ||||
| 	interface_defines.append( gen_array_generic_selection_function_macro(txt("array_set_capacity")) ); | ||||
| 	return interface_defines; | ||||
| } | ||||
							
								
								
									
										357
									
								
								gen_c_library/components/containers.hashtable.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										357
									
								
								gen_c_library/components/containers.hashtable.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,357 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "../project/gen.hpp" | ||||
| #include "containers.array.hpp" | ||||
|  | ||||
| using namespace gen; | ||||
|  | ||||
| CodeBody gen_hashtable_base() | ||||
| { | ||||
| 	CodeBody struct_def = parse_global_body( code( | ||||
| 		typedef struct HT_FindResult HT_FindResult; | ||||
| 		struct HT_FindResult | ||||
| 		{ | ||||
| 			ssize HashIndex; | ||||
| 			ssize PrevIndex; | ||||
| 			ssize EntryIndex; | ||||
| 		}; | ||||
| 	)); | ||||
|  | ||||
| 	Code define_type = untyped_str(txt( | ||||
| R"(#define HashTable(_type) struct _type | ||||
| )" | ||||
| 	)); | ||||
|  | ||||
| 	return def_global_body(args(struct_def, define_type)); | ||||
| } | ||||
|  | ||||
| CodeBody gen_hashtable( StrC type, StrC hashtable_name ) | ||||
| { | ||||
|  | ||||
| 	String tbl_type = {(char*) hashtable_name.duplicate(GlobalAllocator).Ptr}; | ||||
| 	String fn       = tbl_type.duplicate(GlobalAllocator); | ||||
| 	// str_to_lower(fn.Data); | ||||
|  | ||||
| 	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 HashTable_<type> <tbl_type>; | ||||
| 		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( | ||||
| 		struct HashTable_<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 }; | ||||
| 			array_init(result.Hashes, allocator ); | ||||
| 			array_init(result.Entries, allocator ); | ||||
|  | ||||
| 			return result; | ||||
| 		} | ||||
|  | ||||
| 		<tbl_type> <fn>_make_reserve( AllocatorInfo allocator, ssize num ) | ||||
| 		{ | ||||
| 			<tbl_type> | ||||
| 			result         = { NULL, NULL }; | ||||
| 			array_init_reserve(result.Hashes, allocator, num ); | ||||
| 			array_init_reserve(result.Entries, allocator, num ); | ||||
|  | ||||
| 			return result; | ||||
| 		} | ||||
|  | ||||
| 		void <fn>_clear( <tbl_type> self ) | ||||
| 		{ | ||||
| 			for ( ssize idx = 0; idx < array_get_header( self.Hashes )->Num; idx++ ) | ||||
| 				self.Hashes[idx] = -1; | ||||
|  | ||||
| 			array_clear( self.Hashes ); | ||||
| 			array_clear( self.Entries ); | ||||
| 		} | ||||
|  | ||||
| 		void <fn>_destroy( <tbl_type> self ) | ||||
| 		{ | ||||
| 			if ( self.Hashes && self.Entries ) | ||||
| 			{ | ||||
| 				array_free( self.Hashes ); | ||||
| 				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_get_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_get_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_get_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_get_header( self->Hashes ); | ||||
| 			ArrayHeader* old_entries_header = array_get_header( self->Entries ); | ||||
|  | ||||
| 			<tbl_type> new_tbl = <fn>_make_reserve( old_hash_header->Allocator, old_hash_header->Num ); | ||||
|  | ||||
| 			ArrayHeader* new_hash_header = array_get_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_get_header( self.Entries )->Num; idx++ ) | ||||
| 				self.Entries[ idx ].Next = -1; | ||||
|  | ||||
| 			for ( idx = 0; idx < array_get_header( self.Hashes )->Num; idx++ ) | ||||
| 				self.Hashes[ idx ] = -1; | ||||
|  | ||||
| 			for ( idx = 0; idx < array_get_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 ) | ||||
| 			{ | ||||
| 				array_remove_at( self.Entries, find_result.EntryIndex ); | ||||
| 				<fn>_rehash_fast( self ); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		void <fn>_remove_entry( <tbl_type> self, ssize idx ) | ||||
| 		{ | ||||
| 			array_remove_at( self.Entries, idx ); | ||||
| 		} | ||||
|  | ||||
| 		void <fn>_set( <tbl_type>* self, u64 key, <type> value ) | ||||
| 		{ | ||||
| 			ssize         idx; | ||||
| 			HT_FindResult find_result; | ||||
|  | ||||
| 			if ( array_get_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_get_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_get_header( self.Entries )->Num; | ||||
| 			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_get_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_get_header( self.Hashes ); | ||||
| 			ArrayHeader* entries_header = array_get_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( string_to_strc( string_fmt_buf( GlobalAllocator, "region %S", tbl_type ))), | ||||
| 		fmt_newline, | ||||
| 		hashtable_types, | ||||
| 		fmt_newline, | ||||
| 		entry_array, | ||||
| 		hashtable_def, | ||||
| 		fmt_newline, | ||||
| 		def_pragma( string_to_strc( string_fmt_buf( GlobalAllocator, "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 | ||||
							
								
								
									
										128
									
								
								gen_c_library/components/memory.fixed_arena.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								gen_c_library/components/memory.fixed_arena.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,128 @@ | ||||
| #pragma once | ||||
| #include "../project/gen.hpp" | ||||
|  | ||||
| using namespace gen; | ||||
|  | ||||
| CodeBody gen_fixed_arenas() | ||||
| { | ||||
| 	CodeBody result = def_body(CT_Global_Body); | ||||
| 	result.append(def_pragma(txt("region FixedArena"))); | ||||
|  | ||||
| 	char const* template_struct = stringize( | ||||
| 		struct FixedArena_<Name>_Def | ||||
| 		{ | ||||
| 			char  memory[<Size>]; | ||||
| 			Arena arena; | ||||
| 		}; | ||||
| 		typedef struct FixedArena_<Name>_Def FixedArena_<Name>; | ||||
| 	); | ||||
|  | ||||
| 	char const* template_interface = stringize( | ||||
| 		inline | ||||
| 		void fixed_arena_init_<Name>(FixedArena_<Name>* result) | ||||
| 		{ | ||||
| 			result->arena = arena_init_from_memory(& result->memory[0], <Size>); | ||||
| 		} | ||||
|  | ||||
| 		inline | ||||
| 		ssize fixed_arena_size_remaining_<Name>(FixedArena_<Name>* fixed_arena, ssize alignment) | ||||
| 		{ | ||||
| 			return arena_size_remaining( & fixed_arena->arena, alignment); | ||||
| 		} | ||||
| 	); | ||||
|  | ||||
| 	CodeBody arena_struct_1kb   = parse_global_body( token_fmt_impl( 3, "Name", txt("1KB"),   "Size", txt("kilobytes(1)"),   template_struct )); | ||||
| 	CodeBody arena_struct_4kb   = parse_global_body( token_fmt_impl( 3, "Name", txt("4KB"),   "Size", txt("kilobytes(4)"),   template_struct )); | ||||
| 	CodeBody arena_struct_8kb   = parse_global_body( token_fmt_impl( 3, "Name", txt("8KB"),   "Size", txt("kilobytes(8)"),   template_struct )); | ||||
| 	CodeBody arena_struct_16kb  = parse_global_body( token_fmt_impl( 3, "Name", txt("16KB"),  "Size", txt("kilobytes(16)"),  template_struct )); | ||||
| 	CodeBody arena_struct_32kb  = parse_global_body( token_fmt_impl( 3, "Name", txt("32KB"),  "Size", txt("kilobytes(32)"),  template_struct )); | ||||
| 	CodeBody arena_struct_64kb  = parse_global_body( token_fmt_impl( 3, "Name", txt("64KB"),  "Size", txt("kilobytes(64)"),  template_struct )); | ||||
| 	CodeBody arena_struct_128kb = parse_global_body( token_fmt_impl( 3, "Name", txt("128KB"), "Size", txt("kilobytes(128)"), template_struct )); | ||||
| 	CodeBody arena_struct_256kb = parse_global_body( token_fmt_impl( 3, "Name", txt("256KB"), "Size", txt("kilobytes(256)"), template_struct )); | ||||
| 	CodeBody arena_struct_512kb = parse_global_body( token_fmt_impl( 3, "Name", txt("512KB"), "Size", txt("kilobytes(512)"), template_struct )); | ||||
| 	CodeBody arena_struct_1mb   = parse_global_body( token_fmt_impl( 3, "Name", txt("1MB"),   "Size", txt("megabytes(1)"),   template_struct )); | ||||
| 	CodeBody arena_struct_2mb   = parse_global_body( token_fmt_impl( 3, "Name", txt("2MB"),   "Size", txt("megabytes(2)"),   template_struct )); | ||||
| 	CodeBody arena_struct_4mb   = parse_global_body( 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_64kb); | ||||
| 	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_64kb); | ||||
| 	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(fmt_newline); | ||||
|  | ||||
| 	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    \ | ||||
| ) GEN_RESOLVED_FUNCTION_CALL(& 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               \ | ||||
| )	GEN_RESOLVED_FUNCTION_CALL(& expr, alignment) | ||||
| )" | ||||
| 	))); | ||||
|  | ||||
| 	result.append(fmt_newline); | ||||
| 	result.append(def_pragma(txt("endregion FixedArena"))); | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
							
								
								
									
										156
									
								
								gen_c_library/components/misc.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								gen_c_library/components/misc.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,156 @@ | ||||
| // #pragma once | ||||
| // #include "../project/gen.hpp" | ||||
|  | ||||
| // using namespace gen; | ||||
|  | ||||
|  | ||||
|  | ||||
| b32 ignore_preprocess_cond_block( StrC cond_sig, Code& entry_iter, CodeBody& parsed_body, CodeBody& body ) | ||||
| { | ||||
| 	b32 found = false; | ||||
| 	CodePreprocessCond cond = cast(CodePreprocessCond, entry_iter); | ||||
| 	if ( cond->Content.contains(cond_sig) ) | ||||
| 	{ | ||||
| 		log_fmt("Preprocess cond found: %SC\n", cond->Content); | ||||
| 		found = true; | ||||
|  | ||||
| 		s32 depth = 1; | ||||
| 		++ entry_iter; | ||||
| 		for(b32 continue_for = true; continue_for && entry_iter != parsed_body.end(); ) switch | ||||
| 		(entry_iter->Type) { | ||||
| 			case CT_Preprocess_If: | ||||
| 			case CT_Preprocess_IfDef: | ||||
| 			case CT_Preprocess_IfNotDef: | ||||
| 				++ depth; | ||||
| 		 		++ entry_iter; | ||||
| 			break; | ||||
|  | ||||
| 			case CT_Preprocess_Else: | ||||
| 				++ entry_iter; | ||||
| 				for(; continue_for && entry_iter != parsed_body.end(); ++ entry_iter) | ||||
| 				{ | ||||
| 					if (entry_iter->Type == CT_Preprocess_EndIf) | ||||
| 					{ | ||||
| 						continue_for = false; | ||||
| 						break; | ||||
| 					} | ||||
| 					body.append(entry_iter); | ||||
| 				} | ||||
| 			break; | ||||
|  | ||||
| 			case CT_Preprocess_EndIf: | ||||
| 			{ | ||||
| 				depth --; | ||||
| 				if (depth == 0) { | ||||
| 					continue_for = false; | ||||
| 					break; | ||||
| 				} | ||||
| 				++ entry_iter; | ||||
| 			} | ||||
| 			break; | ||||
| 			default: | ||||
| 				++ entry_iter; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return found; | ||||
| } | ||||
|  | ||||
| CodeFn rename_function_to_unique_symbol(CodeFn fn, StrC optional_prefix = txt("")) | ||||
| { | ||||
|     // Get basic components for the name | ||||
|     StrC old_name = fn->Name; | ||||
|     String new_name; | ||||
|  | ||||
|     // Add prefix if provided | ||||
|     if (optional_prefix.Len) | ||||
|         new_name = string_fmt_buf(GlobalAllocator, "%SC_%SC_", optional_prefix, old_name); | ||||
|     else | ||||
|         new_name = string_fmt_buf(GlobalAllocator, "%SC_", old_name); | ||||
|  | ||||
|     // Add return type to the signature | ||||
|     if (fn->ReturnType) | ||||
|         new_name.append_fmt("_%SC", fn->ReturnType->Name); | ||||
|  | ||||
|     // Add parameter types to create a unique signature | ||||
|     bool first_param = true; | ||||
|     for (CodeParam param = fn->Params; param.ast; param = param->Next) | ||||
|     { | ||||
|         if (param->ValueType) | ||||
|         { | ||||
|             // Add separator for readability | ||||
|             if (first_param) | ||||
|             { | ||||
|                 new_name.append("_P_"); | ||||
|                 first_param = false; | ||||
|             } | ||||
|             else | ||||
|                 new_name.append("_"); | ||||
|  | ||||
|             // Add parameter type, handle any specifiers | ||||
|             if (param->ValueType->Specs && param->ValueType->Specs->NumEntries > 0) | ||||
|             { | ||||
|                 // Add specifiers (const, volatile, etc) | ||||
|                 for (Specifier spec : param->ValueType->Specs) | ||||
|                 { | ||||
| 					if (spec == Spec_Ptr) { | ||||
| 						new_name.append("ptr_"); | ||||
| 						continue; | ||||
| 					} | ||||
|  | ||||
|                     new_name.append_fmt("%SC_", to_str(spec)); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             new_name.append_fmt("%SC", param->ValueType->Name); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // Handle function specifiers if present | ||||
|     if (fn->Specs && fn->Specs->NumEntries > 0) | ||||
|     { | ||||
|         new_name.append("_S_"); | ||||
|         for (Specifier* spec = begin(fn->Specs);  | ||||
|              spec != end(fn->Specs);  | ||||
|              ++spec) | ||||
|         { | ||||
|             new_name.append_fmt("%SC_", to_str(*spec)); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn->Name = new_name; | ||||
|     return fn; | ||||
| } | ||||
|  | ||||
| using SwapContentProc = CodeBody(void); | ||||
| bool swap_pragma_region_implementation( StrC region_name, SwapContentProc* swap_content, Code& entry_iter, CodeBody& body ) | ||||
| { | ||||
| 	bool found = false; | ||||
| 	CodePragma possible_region = cast(CodePragma, entry_iter); | ||||
|  | ||||
| 	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 CT_Preprocess_Pragma: | ||||
| 			{ | ||||
| 				CodePragma possible_end_region = cast(CodePragma, entry_iter); | ||||
| 				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 | ||||
| 
 | ||||
| @@ -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" | ||||
| @@ -14,6 +16,8 @@ GEN_NS_END | ||||
| #include "auxillary/builder.cpp" | ||||
| #include "auxillary/scanner.hpp" | ||||
| 
 | ||||
| #include <cstdlib>   // for system()
 | ||||
| 
 | ||||
| using namespace gen; | ||||
| 
 | ||||
| constexpr char const* generation_notice = | ||||
| @@ -35,7 +39,6 @@ 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"( | ||||
| @@ -48,6 +51,42 @@ global bool generate_builder = true; | ||||
| global bool generate_editor  = true; | ||||
| global bool generate_scanner = true; | ||||
| 
 | ||||
| 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; | ||||
| } | ||||
| 
 | ||||
| int gen_main() | ||||
| { | ||||
| #define project_dir "../project/" | ||||
| @@ -69,7 +108,7 @@ int gen_main() | ||||
| 
 | ||||
| 		if ( generate_gen_dep ) | ||||
| 		{ | ||||
| 			Code header_start = scan_file( project_dir "dependencies/header_start.hpp" ); | ||||
| 			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" ); | ||||
| @@ -83,7 +122,7 @@ int gen_main() | ||||
| 			Code timing       = scan_file( project_dir "dependencies/timing.hpp" ); | ||||
| 
 | ||||
| 			header.print_fmt( roll_own_dependencies_guard_start ); | ||||
| 			header.print( header_start ); | ||||
| 			header.print( platform ); | ||||
| 			header.print_fmt( "\nGEN_NS_BEGIN\n" ); | ||||
| 
 | ||||
| 			header.print( macros ); | ||||
| @@ -127,9 +166,13 @@ int gen_main() | ||||
| 
 | ||||
| 		header.print_fmt("#pragma region Types\n"); | ||||
| 		header.print( types ); | ||||
| 		header.print( ecode ); | ||||
| 		header.print( eoperator ); | ||||
| 		header.print( especifier ); | ||||
| 		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"); | ||||
| 
 | ||||
| 		header.print_fmt("#pragma region AST\n"); | ||||
| @@ -142,7 +185,8 @@ int gen_main() | ||||
| 
 | ||||
| 		header.print_fmt( "\n#pragma region Inlines\n" ); | ||||
| 		header.print( inlines ); | ||||
| 		header.print( ast_inlines ); | ||||
| 		header.print( dump_to_scratch_and_retireve( ast_inlines )); | ||||
| 		header.print( fmt_newline ); | ||||
| 		header.print_fmt( "#pragma endregion Inlines\n" ); | ||||
| 
 | ||||
| 		header.print( header_end ); | ||||
| @@ -209,7 +253,7 @@ int gen_main() | ||||
| 		Code untyped           = scan_file( project_dir "components/interface.untyped.cpp" ); | ||||
| 
 | ||||
| 		CodeBody etoktype      = gen_etoktype( project_dir "enums/ETokType.csv", project_dir "enums/AttributeTokens.csv" ); | ||||
| 		CodeNS   parser_nspace = def_namespace( name(Parser), def_namespace_body( args(etoktype)) ); | ||||
| 		CodeNS   parser_nspace = def_namespace( name(parser), def_namespace_body( args(etoktype)) ); | ||||
| 
 | ||||
| 		header.print_fmt( "\nGEN_NS_BEGIN\n"); | ||||
| 		header.print( static_data ); | ||||
| @@ -224,7 +268,7 @@ int gen_main() | ||||
| 		header.print( interface ); | ||||
| 		header.print( upfront ); | ||||
| 		header.print_fmt( "\n#pragma region Parsing\n\n" ); | ||||
| 		header.print( parser_nspace ); | ||||
| 		header.print( dump_to_scratch_and_retireve(parser_nspace) ); | ||||
| 		header.print( lexer ); | ||||
| 		header.print( parser ); | ||||
| 		header.print( parsing_interface ); | ||||
							
								
								
									
										3
									
								
								gen_unreal_engine/Readme.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								gen_unreal_engine/Readme.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| # Unreal Engine Version Generator | ||||
|  | ||||
| This generates a variant of gencpp thats compatiable with use as a thirdparty module within a plugin or module of an Unreal Project or the Engine itself. | ||||
							
								
								
									
										31
									
								
								gen_unreal_engine/components/header_start.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								gen_unreal_engine/components/header_start.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| /* | ||||
| 	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 variant intended for use with Unreal Engine 5 | ||||
| */ | ||||
| #if ! defined(GEN_DONT_ENFORCE_GEN_TIME_GUARD) && ! defined(GEN_TIME) | ||||
| #	error Gen.hpp : GEN_TIME not defined | ||||
| #endif | ||||
|  | ||||
| //! 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 | ||||
| #	include "gen.dep.hpp" | ||||
| #endif | ||||
|  | ||||
| #ifndef GEN_NS_BEGIN | ||||
| #	ifdef GEN_DONT_USE_NAMESPACE | ||||
| #		define GEN_NS | ||||
| #		define GEN_NS_BEGIN | ||||
| #		define GEN_NS_END | ||||
| #	else | ||||
| #		define GEN_NS       gen:: | ||||
| #		define GEN_NS_BEGIN namespace gen { | ||||
| #		define GEN_NS_END   } | ||||
| #	endif | ||||
| #endif | ||||
							
								
								
									
										5
									
								
								gen_unreal_engine/components/src_start.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								gen_unreal_engine/components/src_start.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| #if ! defined(GEN_DONT_ENFORCE_GEN_TIME_GUARD) && ! defined(GEN_TIME) | ||||
| #	error Gen.hpp : GEN_TIME not defined | ||||
| #endif | ||||
|  | ||||
| #include "gen.hpp" | ||||
							
								
								
									
										7
									
								
								gen_unreal_engine/enums/AttributeTokens.csv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								gen_unreal_engine/enums/AttributeTokens.csv
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| API_Export,            GEN_API_Export_Code | ||||
| API_Import,            GEN_API_Import_Code | ||||
| COREUOBJECT_API,       COREUOBJECT_API | ||||
| ENGINE_API,            ENGINE_API | ||||
| GAMEPLAYABILITIES_API, GAMEPLAYABILITIES_API | ||||
| UMG_API,               UMG_API | ||||
| UE_DEPRECATED,         UE_DEPRECATED | ||||
| 
 | 
							
								
								
									
										397
									
								
								gen_unreal_engine/unreal.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										397
									
								
								gen_unreal_engine/unreal.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,397 @@ | ||||
| #define GEN_DEFINE_LIBRARY_CODE_CONSTANTS | ||||
| #define GEN_ENFORCE_STRONG_CODE_TYPES | ||||
| #define GEN_EXPOSE_BACKEND | ||||
| #include "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() | ||||
|  | ||||
| using namespace gen; | ||||
|  | ||||
| constexpr char const* generation_notice = | ||||
| "// This file was generated automatially by gencpp's unreal.cpp " | ||||
| "(See: https://github.com/Ed94/gencpp)\n\n"; | ||||
|  | ||||
| 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 | ||||
| )"); | ||||
|  | ||||
| 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 | ||||
| )"); | ||||
|  | ||||
| global bool generate_gen_dep = true; | ||||
| global bool generate_builder = true; | ||||
| global bool generate_editor  = true; | ||||
| global bool generate_scanner = true; | ||||
|  | ||||
| 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; | ||||
| } | ||||
|  | ||||
| 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 ue_forceinline = code_str(FORCEINLINE); | ||||
| 	// Code | ||||
|  | ||||
| 	// gen_dep.hpp | ||||
| 	{ | ||||
| 		CodeBody macros = def_body( CodeT::Global_Body ); | ||||
| 		{ | ||||
| 			FileContents content    = file_read_contents( GlobalAllocator, true, project_dir "dependencies/macros.hpp" ); | ||||
| 			CodeBody     ori_macros = parse_global_body( StrC { content.size, (char const*)content.data }); | ||||
|  | ||||
| 			for (Code	code =  ori_macros.begin(); | ||||
| 						code != ori_macros.end(); | ||||
| 						++ code ) | ||||
| 			{ | ||||
| 				switch (code->Type) | ||||
| 				{ | ||||
| 					using namespace ECode; | ||||
| 					case Preprocess_Define: | ||||
| 					{ | ||||
| 						CodeDefine define = code.cast<CodeDefine>(); | ||||
| 						if ( define->Name.starts_with(txt("global")) ) | ||||
| 						{ | ||||
| 							macros.append(parse_global_body(txt("#define global // Global variables"))); | ||||
| 							continue; | ||||
| 						} | ||||
|  | ||||
| 						macros.append(define); | ||||
| 					} | ||||
| 					break; | ||||
|  | ||||
| 					default: | ||||
| 						macros.append(code); | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		Code platform     = scan_file( project_dir "dependencies/platform.hpp" ); | ||||
| 		Code basic_types  = scan_file( project_dir "dependencies/basic_types.hpp" ); | ||||
| 		Code debug        = scan_file( project_dir "dependencies/debug.hpp" ); | ||||
| 		Code memory	      = scan_file( project_dir "dependencies/memory.hpp" ); | ||||
| 		Code string_ops   = scan_file( project_dir "dependencies/string_ops.hpp" ); | ||||
| 		Code printing     = scan_file( project_dir "dependencies/printing.hpp" ); | ||||
| 		Code containers   = scan_file( project_dir "dependencies/containers.hpp" ); | ||||
| 		Code hashing 	  = scan_file( project_dir "dependencies/hashing.hpp" ); | ||||
| 		Code strings      = scan_file( project_dir "dependencies/strings.hpp" ); | ||||
| 		Code filesystem   = scan_file( project_dir "dependencies/filesystem.hpp" ); | ||||
| 		Code timing       = scan_file( project_dir "dependencies/timing.hpp" ); | ||||
|  | ||||
| 		Builder | ||||
| 		header = Builder::open("gen/gen.dep.hpp"); | ||||
| 		header.print_fmt( generation_notice ); | ||||
| 		header.print( pragma_once ); | ||||
| 		header.print( push_ignores ); | ||||
| 		header.print( platform ); | ||||
| 		header.print_fmt( "\nGEN_NS_BEGIN\n" ); | ||||
|  | ||||
| 		header.print( fmt_newline); | ||||
| 		header.print( dump_to_scratch_and_retireve(macros) ); | ||||
| 		header.print( basic_types ); | ||||
| 		header.print( debug ); | ||||
| 		header.print( memory ); | ||||
| 		header.print( string_ops ); | ||||
| 		header.print( printing ); | ||||
| 		header.print( containers ); | ||||
| 		header.print( hashing ); | ||||
| 		header.print( strings ); | ||||
| 		header.print( filesystem ); | ||||
| 		header.print( timing ); | ||||
|  | ||||
| 		header.print_fmt( "\nGEN_NS_END\n" ); | ||||
| 		header.print( fmt_newline ); | ||||
| 		header.print( pop_ignores ); | ||||
| 		header.write(); | ||||
| 	} | ||||
|  | ||||
| 	// gen_dep.cpp | ||||
| 	{ | ||||
| 		Code src_start  = scan_file( project_dir "dependencies/src_start.cpp" ); | ||||
| 		Code debug      = scan_file( project_dir "dependencies/debug.cpp" ); | ||||
| 		Code string_ops = scan_file( project_dir "dependencies/string_ops.cpp" ); | ||||
| 		Code printing   = scan_file( project_dir "dependencies/printing.cpp" ); | ||||
| 		Code memory     = scan_file( project_dir "dependencies/memory.cpp" ); | ||||
| 		Code hashing    = scan_file( project_dir "dependencies/hashing.cpp" ); | ||||
| 		Code strings    = scan_file( project_dir "dependencies/strings.cpp" ); | ||||
| 		Code filesystem = scan_file( project_dir "dependencies/filesystem.cpp" ); | ||||
| 		Code timing     = scan_file( project_dir "dependencies/timing.cpp" ); | ||||
|  | ||||
| 		Builder | ||||
| 		src = Builder::open( "gen/gen.dep.cpp" ); | ||||
| 		src.print_fmt( generation_notice ); | ||||
| 		src.print( def_include(txt("gen.dep.hpp"))); | ||||
| 		src.print( fmt_newline ); | ||||
| 		src.print( push_ignores ); | ||||
| 		src.print( src_start ); | ||||
| 		src.print_fmt( "\nGEN_NS_BEGIN\n" ); | ||||
|  | ||||
| 		src.print( debug ); | ||||
| 		src.print( string_ops ); | ||||
| 		src.print( printing ); | ||||
| 		src.print( hashing ); | ||||
| 		src.print( memory ); | ||||
| 		src.print( strings ); | ||||
| 		src.print( filesystem ); | ||||
| 		src.print( timing ); | ||||
|  | ||||
| 		src.print_fmt( "\nGEN_NS_END\n" ); | ||||
| 		src.print( fmt_newline ); | ||||
| 		src.print( pop_ignores ); | ||||
| 		src.write(); | ||||
| 	} | ||||
|  | ||||
| 	// gen.hpp | ||||
| 	{ | ||||
| 		Code header_start = scan_file(             "components/header_start.hpp" ); | ||||
| 		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(); | ||||
|  | ||||
| 		Builder | ||||
| 		header = Builder::open( "gen/gen.hpp" ); | ||||
| 		header.print_fmt( generation_notice ); | ||||
| 		header.print_fmt( "#pragma once\n\n" ); | ||||
| 		header.print( push_ignores ); | ||||
| 		header.print( fmt_newline ); | ||||
| 		header.print( header_start ); | ||||
| 		header.print_fmt( "\nGEN_NS_BEGIN\n\n" ); | ||||
|  | ||||
| 		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" ); | ||||
|  | ||||
| 		header.print_fmt( "#pragma region AST\n" ); | ||||
| 		header.print( ast ); | ||||
| 		header.print( code_types ); | ||||
| 		header.print( ast_types ); | ||||
| 		header.print_fmt( "\n#pragma endregion AST\n" ); | ||||
|  | ||||
| 		header.print( interface ); | ||||
|  | ||||
| 		header.print_fmt( "\n#pragma region Inlines\n" ); | ||||
| 		header.print( inlines ); | ||||
| 		header.print( fmt_newline ); | ||||
| 		header.print( dump_to_scratch_and_retireve(ast_inlines) ); | ||||
| 		header.print( fmt_newline ); | ||||
| 		header.print_fmt( "#pragma endregion Inlines\n" ); | ||||
|  | ||||
| 		header.print( header_end ); | ||||
| 		header.print_fmt( "GEN_NS_END\n\n" ); | ||||
| 		header.print( pop_ignores ); | ||||
| 		header.write(); | ||||
| 	} | ||||
|  | ||||
| 	// gen.cpp | ||||
| 	{ | ||||
| 		Code        src_start          = scan_file(             "components/src_start.cpp" ); | ||||
| 		Code        static_data 	   = scan_file( project_dir "components/static_data.cpp" ); | ||||
| 		Code        ast_case_macros    = scan_file( project_dir "components/ast_case_macros.cpp" ); | ||||
| 		Code        ast			       = scan_file( project_dir "components/ast.cpp" ); | ||||
| 		Code        code_serialization = scan_file( project_dir "components/code_serialization.cpp" ); | ||||
| 		Code        interface	       = scan_file( project_dir "components/interface.cpp" ); | ||||
| 		Code        upfront 	       = scan_file( project_dir "components/interface.upfront.cpp" ); | ||||
| 		Code        lexer              = scan_file( project_dir "components/lexer.cpp" ); | ||||
| 		Code        parser             = scan_file( project_dir "components/parser.cpp" ); | ||||
| 		Code 	    parsing_interface  = scan_file( project_dir "components/interface.parsing.cpp" ); | ||||
| 		Code        untyped 	       = scan_file( project_dir "components/interface.untyped.cpp" ); | ||||
|  | ||||
| 		// Note(Ed): The Attribute tokens need to be expanded and regenerated on a per-project/installation of this library for a specific codebase of Unreal. | ||||
| 		// We can support an arbitrary set of modules or plugin apis for parsing | ||||
| 		// but its up to the user to define them all (This will just provide whats I've used up till now). | ||||
| 		CodeBody etoktype         = gen_etoktype( project_dir "enums/ETokType.csv", "enums/AttributeTokens.csv" ); | ||||
| 		CodeNS   nspaced_etoktype = def_namespace( name(parser), def_namespace_body( args(etoktype)) ); | ||||
|  | ||||
| 		Builder | ||||
| 		src = Builder::open( "gen/gen.cpp" ); | ||||
| 		src.print_fmt( generation_notice ); | ||||
| 		src.print( push_ignores ); | ||||
| 		src.print( fmt_newline ); | ||||
| 		src.print( src_start ); | ||||
| 		src.print( fmt_newline ); | ||||
| 		src.print_fmt( "GEN_NS_BEGIN\n"); | ||||
|  | ||||
| 		src.print( static_data ); | ||||
|  | ||||
| 		src.print_fmt( "\n#pragma region AST\n\n" ); | ||||
| 		src.print( ast_case_macros ); | ||||
| 		src.print( ast ); | ||||
| 		src.print( code_serialization ); | ||||
| 		src.print_fmt( "\n#pragma endregion AST\n" ); | ||||
|  | ||||
| 		src.print_fmt( "\n#pragma region Interface\n" ); | ||||
| 		src.print( interface ); | ||||
| 		src.print( upfront ); | ||||
| 		src.print_fmt( "\n#pragma region Parsing\n\n" ); | ||||
| 		src.print( dump_to_scratch_and_retireve(nspaced_etoktype) ); | ||||
| 		src.print( lexer ); | ||||
| 		src.print( parser ); | ||||
| 		src.print( parsing_interface ); | ||||
| 		src.print( untyped ); | ||||
| 		src.print_fmt( "\n#pragma endregion Parsing\n\n" ); | ||||
| 		src.print_fmt( "#pragma endregion Interface\n\n" ); | ||||
|  | ||||
| 		src.print_fmt( "GEN_NS_END\n\n"); | ||||
| 		src.print( pop_ignores ); | ||||
| 		src.write(); | ||||
| 	} | ||||
|  | ||||
| 	// gen_builder.hpp | ||||
| 	{ | ||||
| 		Code builder = scan_file( project_dir "auxillary/builder.hpp" ); | ||||
|  | ||||
| 		Builder | ||||
| 		header = Builder::open( "gen/gen.builder.hpp" ); | ||||
| 		header.print_fmt( generation_notice ); | ||||
| 		header.print( push_ignores ); | ||||
| 		header.print( fmt_newline ); | ||||
| 		header.print_fmt( "#pragma once\n\n" ); | ||||
| 		header.print( def_include( txt("gen.hpp") )); | ||||
| 		header.print_fmt( "\nGEN_NS_BEGIN\n" ); | ||||
| 		header.print( builder ); | ||||
| 		header.print_fmt( "GEN_NS_END\n" ); | ||||
| 		header.print( fmt_newline ); | ||||
| 		header.print( pop_ignores ); | ||||
| 		header.write(); | ||||
| 	} | ||||
|  | ||||
| 	// gen_builder.cpp | ||||
| 	{ | ||||
| 		Code builder = scan_file( project_dir "auxillary/builder.cpp" ); | ||||
|  | ||||
| 		Builder | ||||
| 		src = Builder::open( "gen/gen.builder.cpp" ); | ||||
| 		src.print_fmt( generation_notice ); | ||||
| 		src.print( push_ignores ); | ||||
| 		src.print( fmt_newline ); | ||||
| 		src.print( def_include( txt("gen.builder.hpp") ) ); | ||||
| 		src.print_fmt( "\nGEN_NS_BEGIN\n" ); | ||||
| 		src.print( builder ); | ||||
| 		src.print_fmt( "\nGEN_NS_END\n" ); | ||||
| 		src.print( fmt_newline ); | ||||
| 		src.print( pop_ignores ); | ||||
| 		src.write(); | ||||
| 	} | ||||
|  | ||||
| 	// gen_scanner.hpp | ||||
| 	{ | ||||
| 		Code parsing = scan_file( project_dir "dependencies/parsing.hpp" ); | ||||
| 		Code scanner = scan_file( project_dir "auxillary/scanner.hpp" ); | ||||
|  | ||||
| 		Builder | ||||
| 		header = Builder::open( "gen/gen.scanner.hpp" ); | ||||
| 		header.print_fmt( generation_notice ); | ||||
| 		header.print_fmt( "#pragma once\n\n" ); | ||||
| 		header.print( push_ignores ); | ||||
| 		header.print( fmt_newline ); | ||||
| 		header.print( def_include( txt("gen.hpp") ) ); | ||||
| 		header.print_fmt( "\nGEN_NS_BEGIN\n" ); | ||||
| 		header.print( parsing ); | ||||
| 		header.print( scanner ); | ||||
| 		header.print_fmt( "GEN_NS_END\n" ); | ||||
| 		header.print( fmt_newline ); | ||||
| 		header.print( pop_ignores ); | ||||
| 		header.write(); | ||||
| 	} | ||||
|  | ||||
| 	// gen.scanner.cpp | ||||
| 	{ | ||||
| 		Code parsing = scan_file( project_dir "dependencies/parsing.cpp" ); | ||||
| 		Code scanner = scan_file( project_dir "auxillary/scanner.cpp" ); | ||||
|  | ||||
| 		Builder | ||||
| 		src = Builder::open( "gen/gen.scanner.cpp" ); | ||||
| 		src.print_fmt( generation_notice ); | ||||
| 		src.print( push_ignores ); | ||||
| 		src.print( fmt_newline ); | ||||
| 		src.print( def_include( txt("gen.scanner.hpp") ) ); | ||||
| 		src.print_fmt( "\nGEN_NS_BEGIN\n" ); | ||||
| 		src.print( parsing ); | ||||
| 		// src.print( scanner ); | ||||
| 		src.print_fmt( "GEN_NS_END\n" ); | ||||
| 		src.print( fmt_newline ); | ||||
| 		src.print( pop_ignores ); | ||||
| 		src.write(); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										10
									
								
								gencpp.10x
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								gencpp.10x
									
									
									
									
									
								
							| @@ -6,6 +6,7 @@ | ||||
| 		<SyncFiles>true</SyncFiles> | ||||
| 		<Recursive>true</Recursive> | ||||
| 		<ShowEmptyFolders>true</ShowEmptyFolders> | ||||
| 		<IncludeFilesWithoutExt>false</IncludeFilesWithoutExt> | ||||
| 		<IsVirtual>false</IsVirtual> | ||||
| 		<IsFolder>false</IsFolder> | ||||
| 		<BuildCommand>pwsh ./scripts/build.ps1 msvc debug bootstrap</BuildCommand> | ||||
| @@ -14,12 +15,13 @@ | ||||
| 		<CleanCommand>pwsh ./scripts/clean.ps1</CleanCommand> | ||||
| 		<BuildWorkingDirectory></BuildWorkingDirectory> | ||||
| 		<CancelBuild></CancelBuild> | ||||
| 		<RunCommand>./test/gen/build/gencpp.exe</RunCommand> | ||||
| 		<RunCommandWorkingDirectory></RunCommandWorkingDirectory> | ||||
| 		<Exe>./test/gen/build/gencpp.exe</Exe> | ||||
| 		<Args></Args> | ||||
| 		<WorkingDirectory></WorkingDirectory> | ||||
| 		<DebugCommand>pwsh ./scripts/build.ps1</DebugCommand> | ||||
| 		<ExePathCommand>./test/gen/build/gencpp.exe</ExePathCommand> | ||||
| 		<DebugSln></DebugSln> | ||||
| 		<UseVisualStudioEnvBat>true</UseVisualStudioEnvBat> | ||||
| 		<CaptureExeOutput>false</CaptureExeOutput> | ||||
| 		<Configurations> | ||||
| 			<Configuration>Debug</Configuration> | ||||
| 			<Configuration>Release</Configuration> | ||||
| @@ -44,6 +46,8 @@ | ||||
| 			<Define>GEN_SYSTEM_WINDOWS</Define> | ||||
| 			<Define>GEN_INTELLISENSE_DIRECTIVES</Define> | ||||
| 			<Define>GEN_EXECUTION_EXPRESSION_SUPPORT</Define> | ||||
| 			<Define>GEN_BENCHMARK</Define> | ||||
| 			<Define>GEN_COMPILER_MSVC</Define> | ||||
| 		</Defines> | ||||
| 		<ConfigProperties> | ||||
| 			<ConfigAndPlatform> | ||||
|   | ||||
| @@ -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,20 +21,20 @@ Builder Builder::open( char const* path ) | ||||
|  | ||||
| void Builder::pad_lines( s32 num ) | ||||
| { | ||||
| 	Buffer.append( "\n" ); | ||||
| 	string_append_strc( & Buffer, txt("\n") ); | ||||
| } | ||||
|  | ||||
| void Builder::print( Code code ) | ||||
| { | ||||
| 	String   str = code->to_string(); | ||||
| 	// const sw len = str.length(); | ||||
| 	String   str = to_string(code); | ||||
| 	// const ssize len = str.length(); | ||||
| 	// log_fmt( "%s - print: %.*s\n", File.filename, len > 80 ? 80 : len, str.Data ); | ||||
| 	Buffer.append( str ); | ||||
| 	string_append_string( & Buffer, str ); | ||||
| } | ||||
|  | ||||
| void Builder::print_fmt( char const* fmt, ... ) | ||||
| { | ||||
| 	sw   res; | ||||
| 	ssize   res; | ||||
| 	char buf[ GEN_PRINTF_MAXLEN ] = { 0 }; | ||||
|  | ||||
| 	va_list va; | ||||
| @@ -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 ); | ||||
| 	string_append_c_str_len( (String*) & Buffer, (char const*)buf, res); | ||||
| } | ||||
|  | ||||
| void Builder::write() | ||||
| { | ||||
| 	bool result = file_write( & File, Buffer, Buffer.length() ); | ||||
| 	b32 result = file_write( & File, Buffer, string_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(); | ||||
| 	string_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 ); | ||||
| @@ -1,3 +1,5 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	include "scanner.hpp" | ||||
| #endif | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -6,6 +6,7 @@ | ||||
| // This is a simple file reader that reads the entire file into memory. | ||||
| // It has an extra option to skip the first few lines for undesired includes. | ||||
| // This is done so that includes can be kept in dependency and component files so that intellisense works. | ||||
| inline | ||||
| Code scan_file( char const* path ) | ||||
| { | ||||
| 	FileInfo file; | ||||
| @@ -16,15 +17,15 @@ Code scan_file( char const* path ) | ||||
| 		GEN_FATAL( "scan_file: Could not open: %s", path ); | ||||
| 	} | ||||
|  | ||||
| 	sw fsize = file_size( & file ); | ||||
| 	ssize fsize = file_size( & file ); | ||||
| 	if ( fsize <= 0 ) | ||||
| 	{ | ||||
| 		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; | ||||
| 		string_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. | ||||
| @@ -38,7 +39,7 @@ Code scan_file( char const* path ) | ||||
| 		const StrC def_intellisense = txt("GEN_INTELLISENSE_DIRECTIVES" ); | ||||
|  | ||||
| 		bool        found_directive = false; | ||||
| 		char const* scanner         = str.Data; | ||||
| 		char const* scanner         = (char const*)str; | ||||
| 		s32         left            = fsize; | ||||
| 		while ( left ) | ||||
| 		{ | ||||
| @@ -51,7 +52,7 @@ Code scan_file( char const* path ) | ||||
|  | ||||
| 				if ( ! found_directive ) | ||||
| 				{ | ||||
| 					if ( left && str_compare( scanner, directive_start.Ptr, directive_start.Len ) == matched ) | ||||
| 					if ( left && str_compare_len( scanner, directive_start.Ptr, directive_start.Len ) == matched ) | ||||
| 					{ | ||||
| 						scanner += directive_start.Len; | ||||
| 						left    -= directive_start.Len; | ||||
| @@ -59,7 +60,7 @@ Code scan_file( char const* path ) | ||||
| 						while ( left && char_is_space( current ) ) | ||||
| 							move_fwd(); | ||||
|  | ||||
| 						if ( left && str_compare( scanner, def_intellisense.Ptr, def_intellisense.Len ) == matched ) | ||||
| 						if ( left && str_compare_len( scanner, def_intellisense.Ptr, def_intellisense.Len ) == matched ) | ||||
| 						{ | ||||
| 							scanner += def_intellisense.Len; | ||||
| 							left    -= def_intellisense.Len; | ||||
| @@ -79,7 +80,7 @@ Code scan_file( char const* path ) | ||||
| 					continue; | ||||
| 				} | ||||
|  | ||||
| 				if ( left && str_compare( scanner, directive_end.Ptr, directive_end.Len ) == matched ) | ||||
| 				if ( left && str_compare_len( scanner, directive_end.Ptr, directive_end.Len ) == matched ) | ||||
| 				{ | ||||
| 					scanner += directive_end.Len; | ||||
| 					left    -= directive_end.Len; | ||||
| @@ -93,19 +94,18 @@ Code scan_file( char const* path ) | ||||
| 						move_fwd(); | ||||
|  | ||||
| 					// sptr skip_size = fsize - left; | ||||
| 					if ( (scanner + 2) >= ( str.Data + fsize ) ) | ||||
| 					if ( (scanner + 2) >= ( (char const*) str + fsize ) ) | ||||
| 					{ | ||||
| 						mem_move( str, scanner, left ); | ||||
| 						str.get_header().Length = left; | ||||
| 						string_get_header(str)->Length = left; | ||||
| 						break; | ||||
| 					} | ||||
|  | ||||
| 					mem_move( str, scanner, left ); | ||||
| 					str.get_header().Length = left; | ||||
| 					string_get_header(str)->Length = left; | ||||
|  | ||||
| 					break; | ||||
| 				} | ||||
|  | ||||
| 			} | ||||
|  | ||||
| 			move_fwd(); | ||||
| @@ -116,7 +116,7 @@ Code scan_file( char const* path ) | ||||
| 	} | ||||
|  | ||||
| 	file_close( & file ); | ||||
| 	return untyped_str( str ); | ||||
| 	return untyped_str( string_to_strc(str) ); | ||||
| } | ||||
|  | ||||
| #if 0 | ||||
|   | ||||
| @@ -1,126 +0,0 @@ | ||||
| Clear-Host | ||||
|  | ||||
| $path_root     = git rev-parse --show-toplevel | ||||
| $path_scripts  = Join-Path $path_root 'scripts' | ||||
|  | ||||
| $target_arch        = Join-Path $path_scripts 'helpers/target_arch.psm1' | ||||
| $devshell           = Join-Path $path_scripts 'helpers/devshell.ps1' | ||||
| $format_cpp	        = Join-Path $path_scripts 'helpers/format_cpp.psm1' | ||||
| $incremental_checks = Join-Path $path_scripts 'helpers/incremental_checks.ps1' | ||||
| $vendor_toolchain   = Join-Path $path_scripts 'helpers/vendor_toolchain.ps1' | ||||
|  | ||||
| $path_project  = Join-Path $path_root     'project' | ||||
| $path_aux      = Join-Path $path_project  'auxillary' | ||||
| $path_vis_root = Join-Path $path_aux      'vis_ast' | ||||
| $path_binaries = Join-Path $path_vis_root 'binaries' | ||||
| $path_build    = Join-Path $path_vis_root 'build' | ||||
| $path_code     = Join-Path $path_vis_root 'code' | ||||
| $path_deps     = Join-Path $path_vis_root 'dependencies' | ||||
| $path_win32    = Join-Path $path_code     'win32' | ||||
|  | ||||
| Import-Module $target_arch | ||||
| Import-Module $format_cpp | ||||
|  | ||||
| #region Arguments | ||||
| $vendor           = $null | ||||
| $optimize         = $null | ||||
| $debug 	          = $null | ||||
| $analysis	      = $false | ||||
| $dev              = $false | ||||
| $verbose          = $null | ||||
| $platform         = $null | ||||
| $module_specified = $false | ||||
|  | ||||
| [array] $vendors = @( "clang", "msvc" ) | ||||
|  | ||||
| # This is a really lazy way of parsing the args, could use actual params down the line... | ||||
|  | ||||
| if ( $args ) { $args | ForEach-Object { | ||||
| switch ($_){ | ||||
|  { $_ -in $vendors }   { $vendor    = $_; break } | ||||
|  "optimize"            { $optimize  = $true } | ||||
|  "debug"               { $debug     = $true } | ||||
|  "analysis"            { $analysis  = $true } | ||||
|  "dev"                 { $dev       = $true } | ||||
|  "verbose"             { $verbose   = $true } | ||||
|  "platform"            { $platform  = $true; $module_specified = $true } | ||||
| } | ||||
| }} | ||||
| #endregion Argument | ||||
|  | ||||
| if ( -not $module_specified ) | ||||
| { | ||||
| 	$platform = $true | ||||
| } | ||||
|  | ||||
| # Load up toolchain configuraion | ||||
| . $vendor_toolchain | ||||
| . $incremental_checks | ||||
|  | ||||
| write-host "Building Vis AST with $vendor" | ||||
|  | ||||
| if ( (Test-Path $path_build) -eq $false ) { | ||||
| 	New-Item $path_build -ItemType Directory | ||||
| } | ||||
|  | ||||
| if ( (Test-Path $path_binaries) -eq $false ) { | ||||
| 	New-Item $path_binaries -ItemType Directory | ||||
| } | ||||
|  | ||||
| $path_raylib     = join-path $path_deps   'raylib' | ||||
| $path_raylib_inc = join-path $path_raylib 'include' | ||||
| $path_raylib_lib = join-path $path_raylib 'lib' | ||||
|  | ||||
| $path_raylib_dll     = join-path $path_raylib_lib 'raylib.dll' | ||||
| $path_raylib_dll_bin = join-path $path_binaries   'raylib.dll' | ||||
|  | ||||
| Copy-Item $path_raylib_dll $path_raylib_dll_bin -Force | ||||
|  | ||||
| $includes = @( | ||||
| 	$path_code, | ||||
| 	$path_deps | ||||
| ) | ||||
|  | ||||
| write-host $path_code | ||||
|  | ||||
| foreach ( $include in $includes ) { | ||||
| 	Write-Host 'include: ' $include | ||||
| } | ||||
|  | ||||
| # Microsoft | ||||
| $lib_gdi32  = 'Gdi32.lib' | ||||
| $lib_xinput = 'Xinput.lib' | ||||
| $lib_user32 = 'User32.lib' | ||||
| $lib_winmm  = 'Winmm.lib' | ||||
|  | ||||
| $stack_size = 1024 * 1024 * 4 | ||||
|  | ||||
| $compiler_args = @( | ||||
| 	( $flag_define + 'UNICODE'), | ||||
| 	( $flag_define + '_UNICODE') | ||||
| 	( $flag_define + 'INTELLISENSE_DIRECTIVES=0'), | ||||
| 	( $flag_define + 'RL_USE_LIBTYPE_SHARED') | ||||
| 	# ($flag_set_stack_size + $stack_size) | ||||
| 	$flag_wall | ||||
| 	$flag_warnings_as_errors | ||||
| 	$flag_optimize_intrinsics | ||||
| ) | ||||
|  | ||||
| if ( $dev ) { | ||||
| 	$compiler_args += ( $flag_define + 'Build_Development=1' ) | ||||
| } | ||||
| else { | ||||
| 	$compiler_args += ( $flag_define + 'Build_Development=0' ) | ||||
| } | ||||
|  | ||||
| $linker_args = @( | ||||
| 	$flag_link_win_subsystem_windows, | ||||
| 	$flag_link_optiiize_references, | ||||
|  | ||||
| 	( join-path $path_raylib_lib 'raylib.lib' ) | ||||
| ) | ||||
|  | ||||
| $unit       = join-path $path_code     'vis_ast_windows.cpp' | ||||
| $executable = join-path $path_binaries 'vis_ast.exe' | ||||
|  | ||||
| $build_result = build-simple $path_build $includes $compiler_args $linker_args $unit $executable | ||||
| @@ -1,22 +0,0 @@ | ||||
| $path_root     = git rev-parse --show-toplevel | ||||
| $path_scripts  = Join-Path $path_root 'scripts' | ||||
|  | ||||
| $target_arch        = Join-Path $path_scripts 'helpers/target_arch.psm1' | ||||
| $devshell           = Join-Path $path_scripts 'helpers/devshell.ps1' | ||||
| $format_cpp	        = Join-Path $path_scripts 'helpers/format_cpp.psm1' | ||||
| $incremental_checks = Join-Path $path_scripts 'helpers/incremental_checks.ps1' | ||||
| $vendor_toolchain   = Join-Path $path_scripts 'helpers/vendor_toolchain.ps1' | ||||
|  | ||||
| $path_project  = Join-Path $path_root     'project' | ||||
| $path_aux      = Join-Path $path_project  'auxillary' | ||||
| $path_vis_root = Join-Path $path_aux      'vis_ast' | ||||
| $path_binaries = Join-Path $path_vis_root 'binaries' | ||||
| $path_build    = Join-Path $path_vis_root 'build' | ||||
|  | ||||
| if ( test-path $path_build ) { | ||||
| 	remove-item $path_build -Recurse | ||||
| } | ||||
|  | ||||
| if ( test-path $path_binaries ) { | ||||
| 	remove-item $path_binaries -recurse | ||||
| } | ||||
| @@ -1,25 +0,0 @@ | ||||
| #pragma once | ||||
| #if INTELLISENSE_DIRECTIVES | ||||
| #include "vendor/compiler.hpp" | ||||
| #endif | ||||
|  | ||||
| #define global        static // Global variables | ||||
| #define internal      static // Internal linkage | ||||
| #define local_persist static // Local Persisting variables | ||||
|  | ||||
| #define api_c extern "C" | ||||
|  | ||||
| #define ccast( type, value ) ( const_cast< type >( (value) ) ) | ||||
| #define pcast( type, value ) ( * reinterpret_cast< type* >( & ( value ) ) ) | ||||
| #define rcast( type, value ) reinterpret_cast< type >( value ) | ||||
| #define scast( type, value ) static_cast< type >( value ) | ||||
|  | ||||
| #define do_once()   for ( local_persist b32 once = true; once; once = false ) | ||||
| #define stmt( ... ) do { __VA_ARGS__; } while ( 0 ) | ||||
|  | ||||
| #define array_count( array ) ( sizeof( array ) / sizeof( ( array )[0] ) ) | ||||
|  | ||||
| #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 ) ) | ||||
| @@ -1,10 +0,0 @@ | ||||
| // Platform architecture | ||||
| #pragma once | ||||
|  | ||||
| #if defined( _WIN64 ) || defined( __x86_64__ ) || defined( _M_X64 ) || defined( __64BIT__ ) || defined( __powerpc64__ ) || defined( __ppc64__ ) || defined( __aarch64__ ) | ||||
| #	ifndef ARCH_64_BIT | ||||
| #		define ARCH_64_BIT 1 | ||||
| #	endif | ||||
| #else | ||||
| #	error A 32-bit architecture is not supported | ||||
| #endif | ||||
| @@ -1,22 +0,0 @@ | ||||
| // Platform compiler | ||||
| #pragma once | ||||
|  | ||||
| #if defined( _MSC_VER ) | ||||
| #	define Compiler_MSVC 1 | ||||
| #elif defined( __clang__ ) | ||||
| #	define Compiler_Clang 1 | ||||
| #else | ||||
| #	error "Unknown compiler" | ||||
| #endif | ||||
|  | ||||
| #if defined( __has_attribute ) | ||||
| #	define HAS_ATTRIBUTE( attribute ) __has_attribute( attribute ) | ||||
| #else | ||||
| #	define HAS_ATTRIBUTE( attribute ) ( 0 ) | ||||
| #endif | ||||
|  | ||||
| #ifdef Compiler_Clang | ||||
| #	define compiler_decorated_func_name __PRETTY_NAME__ | ||||
| #elif defined(Compiler_MSVC) | ||||
| #	define compiler_decorated_func_name __FUNCDNAME__ | ||||
| #endif | ||||
| @@ -1,34 +0,0 @@ | ||||
| #pragma once | ||||
| #if INTELLISENSE_DIRECTIVES | ||||
| #include "compiler.hpp" | ||||
| #endif | ||||
|  | ||||
| #ifdef Compiler_MSVC | ||||
| #pragma warning( disable: 4201 ) // Support for non-standard nameless struct or union extesnion | ||||
| #pragma warning( disable: 4100 ) // Support for unreferenced formal parameters | ||||
| #pragma warning( disable: 4800 ) // Support implicit conversion to bools | ||||
| #pragma warning( disable: 4365 ) // Support for signed/unsigned mismatch auto-conversion | ||||
| #pragma warning( disable: 4189 ) // Support for unused variables | ||||
| #pragma warning( disable: 4514 ) // Support for unused inline functions | ||||
| #pragma warning( disable: 4505 ) // Support for unused static functions | ||||
| #pragma warning( disable: 5045 ) // Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified | ||||
| #pragma warning( disable: 5264 ) // Support for 'const' variables unused | ||||
| #pragma warning( disable: 4820 ) // Support auto-adding padding to structs | ||||
| #pragma warning( disable: 4711 ) // Support automatic inline expansion | ||||
| #pragma warning( disable: 4710 ) // Support automatic inline expansion | ||||
| #pragma warning( disable: 4805 ) // Support comparisons of s32 to bool. | ||||
| #pragma warning( disable: 5246 ) // Support for initialization of subobject without braces. | ||||
| #endif | ||||
|  | ||||
| #ifdef Compiler_Clang | ||||
| #pragma clang diagnostic push | ||||
| #pragma clang diagnostic ignored "-Wunused-const-variable" | ||||
| #pragma clang diagnostic ignored "-Wswitch" | ||||
| #pragma clang diagnostic ignored "-Wunused-variable" | ||||
| #pragma clang diagnostic ignored "-Wunused-local-typedef" | ||||
| #pragma clang diagnostic ignored "-Wunknown-pragmas" | ||||
| #pragma clang diagnostic ignored "-Wvarargs" | ||||
| #pragma clang diagnostic ignored "-Wunused-function" | ||||
| #pragma clang diagnostic ignored "-Wunused-but-set-variable" | ||||
| #pragma clang diagnostic ignored "-Wmissing-braces" | ||||
| #endif | ||||
| @@ -1,22 +0,0 @@ | ||||
| // Platform OS detection | ||||
| #pragma once | ||||
|  | ||||
| #if defined( _WIN32 ) || defined( _WIN64 ) | ||||
| #	ifndef System_Windows | ||||
| #		define System_Windows 1 | ||||
| #	endif | ||||
| #elif defined( __APPLE__ ) && defined( __MACH__ ) | ||||
| #	ifndef System_MacOS | ||||
| #		define System_MacOS 1 | ||||
| #	endif | ||||
| #elif defined( __unix__ ) | ||||
| #	if defined( __linux__ ) | ||||
| #		ifndef System_Linux | ||||
| #			define System_linux 1 | ||||
| #		endif | ||||
| #	else | ||||
| #		error This UNIX operating system is not supported | ||||
| #	endif | ||||
| #else | ||||
| #	error This operating system is not supported | ||||
| #endif | ||||
| @@ -1,45 +0,0 @@ | ||||
| #if INTELLISENSE_DIRECTIVES | ||||
| #include "win32.hpp" | ||||
| #include "raylib/include/raylib.h" | ||||
| #endif | ||||
|  | ||||
| int __stdcall WinMain( HINSTANCE instance, HINSTANCE prev_instance, char* commandline, int num_cmd_show) | ||||
| { | ||||
|     // Initialization | ||||
|     //-------------------------------------------------------------------------------------- | ||||
|     const int screenWidth = 800; | ||||
|     const int screenHeight = 450; | ||||
|  | ||||
|     rl::init_window(screenWidth, screenHeight, "raylib [core] example - basic window"); | ||||
|  | ||||
|     rl::set_target_fps(60);               // Set our game to run at 60 frames-per-second | ||||
|     //-------------------------------------------------------------------------------------- | ||||
|  | ||||
|     // Main game loop | ||||
|     while (!rl::window_should_close())    // Detect window close button or ESC key | ||||
|     { | ||||
|         // Update | ||||
|         //---------------------------------------------------------------------------------- | ||||
|         // TODO: Update your variables here | ||||
|         //---------------------------------------------------------------------------------- | ||||
|  | ||||
|         // Draw | ||||
|         //---------------------------------------------------------------------------------- | ||||
|         rl::begin_drawing(); | ||||
|  | ||||
|             rl::clear_background(RL_RAYWHITE); | ||||
|  | ||||
|             rl::draw_text("Congrats! You created your first window!", 190, 200, 20, RL_LIGHTGRAY); | ||||
|  | ||||
|         rl::end_drawing(); | ||||
|         //---------------------------------------------------------------------------------- | ||||
|     } | ||||
|  | ||||
|     // De-Initialization | ||||
|     //-------------------------------------------------------------------------------------- | ||||
|     rl::close_window();        // Close window and OpenGL context | ||||
|     //-------------------------------------------------------------------------------------- | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| @@ -1,3 +0,0 @@ | ||||
| #pragma once | ||||
|  | ||||
| using HINSTANCE = void*; | ||||
| @@ -1,14 +0,0 @@ | ||||
|  | ||||
|  | ||||
| #include "platform/vendor/arch.hpp" | ||||
| #include "platform/vendor/compiler.hpp" | ||||
| #include "platform/vendor/compiler_ignores.hpp" | ||||
| #include "platform/vendor/os.hpp" | ||||
|  | ||||
| #include "platform/macros.hpp" | ||||
|  | ||||
| #include "platform/win32/types.hpp" | ||||
|  | ||||
| #include "raylib/include/raylib.h" | ||||
|  | ||||
| #include "platform/win32/launch.cpp" | ||||
| @@ -1,285 +0,0 @@ | ||||
| /********************************************************************************************** | ||||
| * | ||||
| *   raylib configuration flags | ||||
| * | ||||
| *   This file defines all the configuration flags for the different raylib modules | ||||
| * | ||||
| *   LICENSE: zlib/libpng | ||||
| * | ||||
| *   Copyright (c) 2018-2023 Ahmad Fatoum & Ramon Santamaria (@raysan5) | ||||
| * | ||||
| *   This software is provided "as-is", without any express or implied warranty. In no event | ||||
| *   will the authors be held liable for any damages arising from the use of this software. | ||||
| * | ||||
| *   Permission is granted to anyone to use this software for any purpose, including commercial | ||||
| *   applications, and to alter it and redistribute it freely, subject to the following restrictions: | ||||
| * | ||||
| *     1. The origin of this software must not be misrepresented; you must not claim that you | ||||
| *     wrote the original software. If you use this software in a product, an acknowledgment | ||||
| *     in the product documentation would be appreciated but is not required. | ||||
| * | ||||
| *     2. Altered source versions must be plainly marked as such, and must not be misrepresented | ||||
| *     as being the original software. | ||||
| * | ||||
| *     3. This notice may not be removed or altered from any source distribution. | ||||
| * | ||||
| **********************************************************************************************/ | ||||
|  | ||||
| #ifndef CONFIG_H | ||||
| #define CONFIG_H | ||||
|  | ||||
| //------------------------------------------------------------------------------------ | ||||
| // Module selection - Some modules could be avoided | ||||
| // Mandatory modules: rcore, rlgl, utils | ||||
| //------------------------------------------------------------------------------------ | ||||
| #define RL_SUPPORT_MODULE_RSHAPES          1 | ||||
| #define RL_SUPPORT_MODULE_RTEXTURES        1 | ||||
| #define RL_SUPPORT_MODULE_RTEXT            1       // WARNING: It requires RL_SUPPORT_MODULE_RTEXTURES to load sprite font textures | ||||
| #define RL_SUPPORT_MODULE_RMODELS          1 | ||||
| #define RL_SUPPORT_MODULE_RAUDIO           1 | ||||
|  | ||||
| //------------------------------------------------------------------------------------ | ||||
| // Module: rcore - Configuration Flags | ||||
| //------------------------------------------------------------------------------------ | ||||
| // Camera module is included (rcamera.h) and multiple predefined cameras are available: free, 1st/3rd person, orbital | ||||
| #define RL_SUPPORT_CAMERA_SYSTEM           1 | ||||
| // Gestures module is included (rgestures.h) to support gestures detection: tap, hold, swipe, drag | ||||
| #define RL_SUPPORT_GESTURES_SYSTEM         1 | ||||
| // Include pseudo-random numbers generator (rprand.h), based on Xoshiro128** and SplitMix64 | ||||
| #define RL_SUPPORT_RPRAND_GENERATOR        1 | ||||
| // Mouse gestures are directly mapped like touches and processed by gestures system | ||||
| #define RL_SUPPORT_MOUSE_GESTURES          1 | ||||
| // Reconfigure standard input to receive key inputs, works with SSH connection. | ||||
| #define RL_SUPPORT_SSH_KEYBOARD_RPI        1 | ||||
| // Setting a higher resolution can improve the accuracy of time-out intervals in wait functions. | ||||
| // However, it can also reduce overall system performance, because the thread scheduler switches tasks more often. | ||||
| #define RL_SUPPORT_WINMM_HIGHRES_TIMER     1 | ||||
| // Use busy wait loop for timing sync, if not defined, a high-resolution timer is set up and used | ||||
| //#define RL_SUPPORT_BUSY_WAIT_LOOP          1 | ||||
| // Use a partial-busy wait loop, in this case frame sleeps for most of the time, but then runs a busy loop at the end for accuracy | ||||
| #define RL_SUPPORT_PARTIALBUSY_WAIT_LOOP    1 | ||||
| // Allow automatic screen capture of current screen pressing F12, defined in KeyCallback() | ||||
| #define RL_SUPPORT_SCREEN_CAPTURE          1 | ||||
| // Allow automatic gif recording of current screen pressing CTRL+F12, defined in KeyCallback() | ||||
| #define RL_SUPPORT_GIF_RECORDING           1 | ||||
| // Support CompressData() and DecompressData() functions | ||||
| #define RL_SUPPORT_COMPRESSION_API         1 | ||||
| // Support automatic generated events, loading and recording of those events when required | ||||
| #define RL_SUPPORT_AUTOMATION_EVENTS       1 | ||||
| // Support custom frame control, only for advance users | ||||
| // By default end_drawing() does this job: draws everything + swap_screen_buffer() + manage frame timing + poll_input_events() | ||||
| // Enabling this flag allows manual control of the frame processes, use at your own risk | ||||
| //#define RL_SUPPORT_CUSTOM_FRAME_CONTROL    1 | ||||
|  | ||||
| // rcore: Configuration values | ||||
| //------------------------------------------------------------------------------------ | ||||
| #define RL_MAX_FILEPATH_CAPACITY        8192       // Maximum file paths capacity | ||||
| #define RL_MAX_FILEPATH_LENGTH          4096       // Maximum length for filepaths (Linux PATH_MAX default value) | ||||
|  | ||||
| #define RL_MAX_KEYBOARD_KEYS             512       // Maximum number of keyboard keys supported | ||||
| #define RL_MAX_MOUSE_BUTTONS               8       // Maximum number of mouse buttons supported | ||||
| #define RL_MAX_GAMEPADS                    4       // Maximum number of gamepads supported | ||||
| #define RL_MAX_GAMEPAD_AXIS                8       // Maximum number of axis supported (per gamepad) | ||||
| #define RL_MAX_GAMEPAD_BUTTONS            32       // Maximum number of buttons supported (per gamepad) | ||||
| #define RL_MAX_TOUCH_POINTS                8       // Maximum number of touch points supported | ||||
| #define RL_MAX_KEY_PRESSED_QUEUE          16       // Maximum number of keys in the key input queue | ||||
| #define RL_MAX_CHAR_PRESSED_QUEUE         16       // Maximum number of characters in the char input queue | ||||
|  | ||||
| #define RL_MAX_DECOMPRESSION_SIZE         64       // Max size allocated for decompression in MB | ||||
|  | ||||
| #define RL_MAX_AUTOMATION_EVENTS       16384       // Maximum number of automation events to record | ||||
|  | ||||
| //------------------------------------------------------------------------------------ | ||||
| // Module: rlgl - Configuration values | ||||
| //------------------------------------------------------------------------------------ | ||||
|  | ||||
| // Enable OpenGL Debug Context (only available on OpenGL 4.3) | ||||
| //#define RLGL_ENABLE_OPENGL_DEBUG_CONTEXT       1 | ||||
|  | ||||
| // Show OpenGL extensions and capabilities detailed logs on init | ||||
| //#define RLGL_SHOW_GL_DETAILS_INFO              1 | ||||
|  | ||||
| //#define RL_DEFAULT_BATCH_BUFFER_ELEMENTS    4096    // Default internal render batch elements limits | ||||
| #define RL_DEFAULT_BATCH_BUFFERS               1      // Default number of batch buffers (multi-buffering) | ||||
| #define RL_DEFAULT_BATCH_DRAWCALLS           256      // Default number of batch draw calls (by state changes: mode, texture) | ||||
| #define RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS     4      // Maximum number of textures units that can be activated on batch drawing (set_shader_value_texture()) | ||||
|  | ||||
| #define RL_MAX_MATRIX_STACK_SIZE              32      // Maximum size of internal Matrix stack | ||||
|  | ||||
| #define RL_MAX_SHADER_LOCATIONS               32      // Maximum number of shader locations supported | ||||
|  | ||||
| #define RL_CULL_DISTANCE_NEAR               0.01      // Default projection matrix near cull distance | ||||
| #define RL_CULL_DISTANCE_FAR              1000.0      // Default projection matrix far cull distance | ||||
|  | ||||
| // Default shader vertex attribute names to set location points | ||||
| // NOTE: When a new shader is loaded, the following locations are tried to be set for convenience | ||||
| #define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION     "vertexPosition"    // Bound by default to shader location: 0 | ||||
| #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD     "vertexTexCoord"    // Bound by default to shader location: 1 | ||||
| #define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL       "vertexNormal"      // Bound by default to shader location: 2 | ||||
| #define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR        "vertexColor"       // Bound by default to shader location: 3 | ||||
| #define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT      "vertexTangent"     // Bound by default to shader location: 4 | ||||
| #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2    "vertexTexCoord2"   // Bound by default to shader location: 5 | ||||
|  | ||||
| #define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP         "mvp"               // model-view-projection matrix | ||||
| #define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW        "matView"           // view matrix | ||||
| #define RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION  "matProjection"     // projection matrix | ||||
| #define RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL       "matModel"          // model matrix | ||||
| #define RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL      "matNormal"         // normal matrix (transpose(inverse(matModelView)) | ||||
| #define RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR       "colDiffuse"        // color diffuse (base tint color, multiplied by texture color) | ||||
| #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0  "texture0"          // texture0 (texture slot active 0) | ||||
| #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1  "texture1"          // texture1 (texture slot active 1) | ||||
| #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2  "texture2"          // texture2 (texture slot active 2) | ||||
|  | ||||
|  | ||||
| //------------------------------------------------------------------------------------ | ||||
| // Module: rshapes - Configuration Flags | ||||
| //------------------------------------------------------------------------------------ | ||||
| // Use QUADS instead of TRIANGLES for drawing when possible | ||||
| // Some lines-based shapes could still use lines | ||||
| #define RL_SUPPORT_QUADS_DRAW_MODE         1 | ||||
|  | ||||
| // rshapes: Configuration values | ||||
| //------------------------------------------------------------------------------------ | ||||
| #define SPLINE_SEGMENT_DIVISIONS       24       // Spline segments subdivisions | ||||
|  | ||||
|  | ||||
| //------------------------------------------------------------------------------------ | ||||
| // Module: rtextures - Configuration Flags | ||||
| //------------------------------------------------------------------------------------ | ||||
| // Selecte desired fileformats to be supported for image data loading | ||||
| #define RL_SUPPORT_FILEFORMAT_PNG      1 | ||||
| //#define RL_SUPPORT_FILEFORMAT_BMP      1 | ||||
| //#define RL_SUPPORT_FILEFORMAT_TGA      1 | ||||
| //#define RL_SUPPORT_FILEFORMAT_JPG      1 | ||||
| #define RL_SUPPORT_FILEFORMAT_GIF      1 | ||||
| #define RL_SUPPORT_FILEFORMAT_QOI      1 | ||||
| //#define RL_SUPPORT_FILEFORMAT_PSD      1 | ||||
| #define RL_SUPPORT_FILEFORMAT_DDS      1 | ||||
| //#define RL_SUPPORT_FILEFORMAT_HDR      1 | ||||
| //#define RL_SUPPORT_FILEFORMAT_PIC          1 | ||||
| //#define RL_SUPPORT_FILEFORMAT_KTX      1 | ||||
| //#define RL_SUPPORT_FILEFORMAT_ASTC     1 | ||||
| //#define RL_SUPPORT_FILEFORMAT_PKM      1 | ||||
| //#define RL_SUPPORT_FILEFORMAT_PVR      1 | ||||
| //#define RL_SUPPORT_FILEFORMAT_SVG      1 | ||||
|  | ||||
| // Support image export functionality (.png, .bmp, .tga, .jpg, .qoi) | ||||
| #define RL_SUPPORT_IMAGE_EXPORT            1 | ||||
| // Support procedural image generation functionality (gradient, spot, perlin-noise, cellular) | ||||
| #define RL_SUPPORT_IMAGE_GENERATION        1 | ||||
| // Support multiple image editing functions to scale, adjust colors, flip, draw on images, crop... | ||||
| // If not defined, still some functions are supported: image_format(), image_crop(), image_to_pot() | ||||
| #define RL_SUPPORT_IMAGE_MANIPULATION      1 | ||||
|  | ||||
|  | ||||
| //------------------------------------------------------------------------------------ | ||||
| // Module: rtext - Configuration Flags | ||||
| //------------------------------------------------------------------------------------ | ||||
| // Default font is loaded on window initialization to be available for the user to render simple text | ||||
| // NOTE: If enabled, uses external module functions to load default raylib font | ||||
| #define RL_SUPPORT_DEFAULT_FONT            1 | ||||
| // Selected desired font fileformats to be supported for loading | ||||
| #define RL_SUPPORT_FILEFORMAT_FNT          1 | ||||
| #define RL_SUPPORT_FILEFORMAT_TTF          1 | ||||
|  | ||||
| // Support text management functions | ||||
| // If not defined, still some functions are supported: text_length(), TextFormat() | ||||
| #define RL_SUPPORT_TEXT_MANIPULATION       1 | ||||
|  | ||||
| // On font atlas image generation [gen_image_font_atlas()], add a 3x3 pixels white rectangle | ||||
| // at the bottom-right corner of the atlas. It can be useful to for shapes drawing, to allow | ||||
| // drawing text and shapes with a single draw call [set_shapes_texture()]. | ||||
| #define RL_SUPPORT_FONT_ATLAS_WHITE_REC    1 | ||||
|  | ||||
| // rtext: Configuration values | ||||
| //------------------------------------------------------------------------------------ | ||||
| #define RL_MAX_TEXT_BUFFER_LENGTH       1024       // Size of internal static buffers used on some functions: | ||||
|                                                 // TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal(), TextSplit() | ||||
| #define RL_MAX_TEXTSPLIT_COUNT           128       // Maximum number of substrings to split: TextSplit() | ||||
|  | ||||
|  | ||||
| //------------------------------------------------------------------------------------ | ||||
| // Module: rmodels - Configuration Flags | ||||
| //------------------------------------------------------------------------------------ | ||||
| // Selected desired model fileformats to be supported for loading | ||||
| #define RL_SUPPORT_FILEFORMAT_OBJ          1 | ||||
| #define RL_SUPPORT_FILEFORMAT_MTL          1 | ||||
| #define RL_SUPPORT_FILEFORMAT_IQM          1 | ||||
| #define RL_SUPPORT_FILEFORMAT_GLTF         1 | ||||
| #define RL_SUPPORT_FILEFORMAT_VOX          1 | ||||
| #define RL_SUPPORT_FILEFORMAT_M3D          1 | ||||
| // Support procedural mesh generation functions, uses external par_shapes.h library | ||||
| // NOTE: Some generated meshes DO NOT include generated texture coordinates | ||||
| #define RL_SUPPORT_MESH_GENERATION         1 | ||||
|  | ||||
| // rmodels: Configuration values | ||||
| //------------------------------------------------------------------------------------ | ||||
| #define RL_MAX_MATERIAL_MAPS              12       // Maximum number of shader maps supported | ||||
| #define RL_MAX_MESH_VERTEX_BUFFERS         7       // Maximum vertex buffers (VBO) per mesh | ||||
|  | ||||
| //------------------------------------------------------------------------------------ | ||||
| // Module: raudio - Configuration Flags | ||||
| //------------------------------------------------------------------------------------ | ||||
| // Desired audio fileformats to be supported for loading | ||||
| #define RL_SUPPORT_FILEFORMAT_WAV          1 | ||||
| #define RL_SUPPORT_FILEFORMAT_OGG          1 | ||||
| #define RL_SUPPORT_FILEFORMAT_MP3          1 | ||||
| #define RL_SUPPORT_FILEFORMAT_QOA          1 | ||||
| //#define RL_SUPPORT_FILEFORMAT_FLAC         1 | ||||
| #define RL_SUPPORT_FILEFORMAT_XM           1 | ||||
| #define RL_SUPPORT_FILEFORMAT_MOD          1 | ||||
|  | ||||
| // raudio: Configuration values | ||||
| //------------------------------------------------------------------------------------ | ||||
| #define RL_AUDIO_DEVICE_FORMAT    ma_format_f32    // Device output format (miniaudio: float-32bit) | ||||
| #define RL_AUDIO_DEVICE_CHANNELS              2    // Device output channels: stereo | ||||
| #define RL_AUDIO_DEVICE_SAMPLE_RATE           0    // Device sample rate (device default) | ||||
|  | ||||
| #define RL_MAX_AUDIO_BUFFER_POOL_CHANNELS    16    // Maximum number of audio pool channels | ||||
|  | ||||
| //------------------------------------------------------------------------------------ | ||||
| // Module: utils - Configuration Flags | ||||
| //------------------------------------------------------------------------------------ | ||||
| // Standard file io library (stdio.h) included | ||||
| #define RL_SUPPORT_STANDARD_FILEIO         1 | ||||
| // Show RL_TRACELOG() output messages | ||||
| // NOTE: By default LOG_DEBUG traces not shown | ||||
| #define RL_SUPPORT_TRACELOG                1 | ||||
| //#define RL_SUPPORT_TRACELOG_DEBUG          1 | ||||
|  | ||||
| // utils: Configuration values | ||||
| //------------------------------------------------------------------------------------ | ||||
| #define RL_MAX_TRACELOG_MSG_LENGTH       256       // Max length of one trace-log message | ||||
|  | ||||
| #endif // CONFIG_H | ||||
|  | ||||
| // Indicates of raylib has been refactored | ||||
| #ifndef RL_REFACTORED_CPP | ||||
| #define RL_REFACTORED_CPP | ||||
| #endif | ||||
|  | ||||
| #define RL_USE_CPP_NAMESPACE 1 | ||||
| #define RL_USE_CPP_MANGLING  1 | ||||
|  | ||||
| #if RL_USE_CPP_NAMESPACE && defined(__cplusplus) | ||||
|     #pragma message("USING CPP NAMESPACE") | ||||
|     #define RL_NS_BEGIN namespace rl { | ||||
|     #define RL_NS_END } | ||||
| #else | ||||
|     #define RL_NS_BEGIN | ||||
|     #define RL_NS_END | ||||
| #endif | ||||
|  | ||||
| #if RL_USE_CPP_MANGLING && defined(__cplusplus) | ||||
|     #pragma message("USING CPP MANGLING") | ||||
|     #define RL_EXTERN_C_BEGIN | ||||
|     #define RL_EXTERN_C_END | ||||
| #else | ||||
|     #ifdef __cplusplus | ||||
|         #define RL_EXTERN_C_BEGIN extern "C" { | ||||
|         #define RL_EXTERN_C_END   } | ||||
|     #else | ||||
|         #define RL_EXTERN_C_BEGIN | ||||
|         #define RL_EXTERN_C_END | ||||
|     #endif | ||||
| #endif | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,562 +0,0 @@ | ||||
| /******************************************************************************************* | ||||
| * | ||||
| *   rcamera - Basic camera system with support for multiple camera modes | ||||
| * | ||||
| *   CONFIGURATION: | ||||
| *       #define RCAMERA_IMPLEMENTATION | ||||
| *           Generates the implementation of the library into the included file. | ||||
| *           If not defined, the library is in header only mode and can be included in other headers | ||||
| *           or source files without problems. But only ONE file should hold the implementation. | ||||
| * | ||||
| *       #define RCAMERA_STANDALONE | ||||
| *           If defined, the library can be used as standalone as a camera system but some | ||||
| *           functions must be redefined to manage inputs accordingly. | ||||
| * | ||||
| *   CONTRIBUTORS: | ||||
| *       Ramon Santamaria:   Supervision, review, update and maintenance | ||||
| *       Christoph Wagner:   Complete redesign, using raymath (2022) | ||||
| *       Marc Palau:         Initial implementation (2014) | ||||
| * | ||||
| * | ||||
| *   LICENSE: zlib/libpng | ||||
| * | ||||
| *   Copyright (c) 2022-2023 Christoph Wagner (@Crydsch) & Ramon Santamaria (@raysan5) | ||||
| * | ||||
| *   This software is provided "as-is", without any express or implied warranty. In no event | ||||
| *   will the authors be held liable for any damages arising from the use of this software. | ||||
| * | ||||
| *   Permission is granted to anyone to use this software for any purpose, including commercial | ||||
| *   applications, and to alter it and redistribute it freely, subject to the following restrictions: | ||||
| * | ||||
| *     1. The origin of this software must not be misrepresented; you must not claim that you | ||||
| *     wrote the original software. If you use this software in a product, an acknowledgment | ||||
| *     in the product documentation would be appreciated but is not required. | ||||
| * | ||||
| *     2. Altered source versions must be plainly marked as such, and must not be misrepresented | ||||
| *     as being the original software. | ||||
| * | ||||
| *     3. This notice may not be removed or altered from any source distribution. | ||||
| * | ||||
| **********************************************************************************************/ | ||||
|  | ||||
| #ifndef RCAMERA_H | ||||
| #define RCAMERA_H | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Defines and Macros | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Function specifiers definition | ||||
|  | ||||
| // Function specifiers in case library is build/used as a shared library (Windows) | ||||
| // NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll | ||||
| #if defined(_WIN32) | ||||
| #if defined(RL_BUILD_LIBTYPE_SHARED) | ||||
| #if defined(__TINYC__) | ||||
| #define __declspec(x) __attribute__((x)) | ||||
| #endif | ||||
| #define RLAPI __declspec(dllexport)     // We are building the library as a Win32 shared library (.dll) | ||||
| #elif defined(RL_USE_LIBTYPE_SHARED) | ||||
| #define RLAPI __declspec(dllimport)     // We are using the library as a Win32 shared library (.dll) | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #ifndef RLAPI | ||||
|     #define RLAPI       // Functions defined as 'extern' by default (implicit specifiers) | ||||
| #endif | ||||
|  | ||||
| #if defined(RCAMERA_STANDALONE) | ||||
|     #define RL_CAMERA_CULL_DISTANCE_NEAR      0.01 | ||||
|     #define RL_CAMERA_CULL_DISTANCE_FAR    1000.0 | ||||
| #else | ||||
|     #define RL_CAMERA_CULL_DISTANCE_NEAR   RL_CULL_DISTANCE_NEAR | ||||
|     #define RL_CAMERA_CULL_DISTANCE_FAR    RL_CULL_DISTANCE_FAR | ||||
| #endif | ||||
|  | ||||
| RL_NS_BEGIN | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Types and Structures Definition | ||||
| // NOTE: Below types are required for standalone usage | ||||
| //---------------------------------------------------------------------------------- | ||||
| #if defined(RCAMERA_STANDALONE) | ||||
|     // Vector2, 2 components | ||||
|     typedef struct Vector2 { | ||||
|         float x;                // Vector x component | ||||
|         float y;                // Vector y component | ||||
|     } Vector2; | ||||
|  | ||||
|     // Vector3, 3 components | ||||
|     typedef struct Vector3 { | ||||
|         float x;                // Vector x component | ||||
|         float y;                // Vector y component | ||||
|         float z;                // Vector z component | ||||
|     } Vector3; | ||||
|  | ||||
|     // Matrix, 4x4 components, column major, OpenGL style, right-handed | ||||
|     typedef struct Matrix { | ||||
|         float m0, m4, m8, m12;  // Matrix first row (4 components) | ||||
|         float m1, m5, m9, m13;  // Matrix second row (4 components) | ||||
|         float m2, m6, m10, m14; // Matrix third row (4 components) | ||||
|         float m3, m7, m11, m15; // Matrix fourth row (4 components) | ||||
|     } Matrix; | ||||
|  | ||||
|     // Camera type, defines a camera position/orientation in 3d space | ||||
|     typedef struct Camera3D { | ||||
|         Vector3 position;       // Camera position | ||||
|         Vector3 target;         // Camera target it looks-at | ||||
|         Vector3 up;             // Camera up vector (rotation over its axis) | ||||
|         float fovy;             // Camera field-of-view apperture in Y (degrees) in perspective, used as near plane width in orthographic | ||||
|         int projection;         // Camera projection type: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC | ||||
|     } Camera3D; | ||||
|  | ||||
|     typedef Camera3D Camera;    // Camera type fallback, defaults to Camera3D | ||||
|  | ||||
|     // Camera projection | ||||
|     typedef enum { | ||||
|         CAMERA_PERSPECTIVE = 0, // Perspective projection | ||||
|         CAMERA_ORTHOGRAPHIC     // Orthographic projection | ||||
|     } CameraProjection; | ||||
|  | ||||
|     // Camera system modes | ||||
|     typedef enum { | ||||
|         CAMERA_CUSTOM = 0,      // Camera custom, controlled by user (update_camera() does nothing) | ||||
|         CAMERA_FREE,            // Camera free mode | ||||
|         CAMERA_ORBITAL,         // Camera orbital, around target, zoom supported | ||||
|         CAMERA_FIRST_PERSON,    // Camera first person | ||||
|         CAMERA_THIRD_PERSON     // Camera third person | ||||
|     } CameraMode; | ||||
| #endif | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Global Variables Definition | ||||
| //---------------------------------------------------------------------------------- | ||||
| //... | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Module Functions Declaration | ||||
| //---------------------------------------------------------------------------------- | ||||
|  | ||||
| RL_EXTERN_C_BEGIN | ||||
|  | ||||
| RLAPI Vector3 get_camera_forward(Camera *camera); | ||||
| RLAPI Vector3 get_camera_up(Camera *camera); | ||||
| RLAPI Vector3 get_camera_right(Camera *camera); | ||||
|  | ||||
| // Camera movement | ||||
| RLAPI void camera_move_forward(Camera *camera, float distance, bool moveInWorldPlane); | ||||
| RLAPI void camera_move_up(Camera *camera, float distance); | ||||
| RLAPI void camera_move_right(Camera *camera, float distance, bool moveInWorldPlane); | ||||
| RLAPI void camera_move_to_target(Camera *camera, float delta); | ||||
|  | ||||
| // Camera rotation | ||||
| RLAPI void camera_yaw(Camera *camera, float angle, bool rotateAroundTarget); | ||||
| RLAPI void camera_pitch(Camera *camera, float angle, bool lockView, bool rotateAroundTarget, bool rotateUp); | ||||
| RLAPI void camera_roll(Camera *camera, float angle); | ||||
|  | ||||
| RLAPI Matrix get_camera_view_matrix(Camera *camera); | ||||
| RLAPI Matrix get_camera_projection_matrix(Camera* camera, float aspect); | ||||
|  | ||||
| RL_EXTERN_C_END | ||||
|  | ||||
| RL_NS_END | ||||
|  | ||||
| #endif // RCAMERA_H | ||||
|  | ||||
|  | ||||
| /*********************************************************************************** | ||||
| * | ||||
| *   CAMERA IMPLEMENTATION | ||||
| * | ||||
| ************************************************************************************/ | ||||
|  | ||||
| #if defined(RCAMERA_IMPLEMENTATION) | ||||
|  | ||||
| #include "raymath.h"        // Required for vector maths: | ||||
|                             // vector3_add() | ||||
|                             // vector3_subtract() | ||||
|                             // vector3_scale() | ||||
|                             // vector3_normalize() | ||||
|                             // vector3_distance() | ||||
|                             // vector3_cross_product() | ||||
|                             // vector3_rotate_by_axis_angle() | ||||
|                             // vector3_angle() | ||||
|                             // vector3_negate() | ||||
|                             // matrix_look_at() | ||||
|                             // matrix_perspective() | ||||
|                             // matrix_ortho() | ||||
|                             // matrix_identity() | ||||
|  | ||||
| // raylib required functionality: | ||||
|                             // get_mouse_delta() | ||||
|                             // get_mouse_wheel_move() | ||||
|                             // is_key_down() | ||||
|                             // is_key_pressed() | ||||
|                             // get_frame_time() | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Defines and Macros | ||||
| //---------------------------------------------------------------------------------- | ||||
| #define CAMERA_MOVE_SPEED                               0.09f | ||||
| #define CAMERA_ROTATION_SPEED                           0.03f | ||||
| #define CAMERA_PAN_SPEED                                0.2f | ||||
|  | ||||
| // Camera mouse movement sensitivity | ||||
| #define CAMERA_MOUSE_MOVE_SENSITIVITY                   0.003f     // TODO: it should be independant of framerate | ||||
| #define CAMERA_MOUSE_SCROLL_SENSITIVITY                 1.5f | ||||
|  | ||||
| #define CAMERA_ORBITAL_SPEED                            0.5f       // Radians per second | ||||
|  | ||||
|  | ||||
| #define CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER  8.0f | ||||
| #define CAMERA_FIRST_PERSON_STEP_DIVIDER                30.0f | ||||
| #define CAMERA_FIRST_PERSON_WAVING_DIVIDER              200.0f | ||||
|  | ||||
| // PLAYER (used by camera) | ||||
| #define PLAYER_MOVEMENT_SENSITIVITY                     20.0f | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Types and Structures Definition | ||||
| //---------------------------------------------------------------------------------- | ||||
| //... | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Global Variables Definition | ||||
| //---------------------------------------------------------------------------------- | ||||
| //... | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Module specific Functions Declaration | ||||
| //---------------------------------------------------------------------------------- | ||||
| //... | ||||
|  | ||||
| RL_NS_BEGIN | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Module Functions Definition | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Returns the cameras forward vector (normalized) | ||||
| Vector3 get_camera_forward(Camera *camera) | ||||
| { | ||||
|     return vector3_normalize(vector3_subtract(camera->target, camera->position)); | ||||
| } | ||||
|  | ||||
| // Returns the cameras up vector (normalized) | ||||
| // Note: The up vector might not be perpendicular to the forward vector | ||||
| Vector3 get_camera_up(Camera *camera) | ||||
| { | ||||
|     return vector3_normalize(camera->up); | ||||
| } | ||||
|  | ||||
| // Returns the cameras right vector (normalized) | ||||
| Vector3 get_camera_right(Camera *camera) | ||||
| { | ||||
|     Vector3 forward = get_camera_forward(camera); | ||||
|     Vector3 up = get_camera_up(camera); | ||||
|  | ||||
|     return vector3_cross_product(forward, up); | ||||
| } | ||||
|  | ||||
| // Moves the camera in its forward direction | ||||
| void camera_move_forward(Camera *camera, float distance, bool moveInWorldPlane) | ||||
| { | ||||
|     Vector3 forward = get_camera_forward(camera); | ||||
|  | ||||
|     if (moveInWorldPlane) | ||||
|     { | ||||
|         // Project vector onto world plane | ||||
|         forward.y = 0; | ||||
|         forward = vector3_normalize(forward); | ||||
|     } | ||||
|  | ||||
|     // Scale by distance | ||||
|     forward = vector3_scale(forward, distance); | ||||
|  | ||||
|     // Move position and target | ||||
|     camera->position = vector3_add(camera->position, forward); | ||||
|     camera->target = vector3_add(camera->target, forward); | ||||
| } | ||||
|  | ||||
| // Moves the camera in its up direction | ||||
| void camera_move_up(Camera *camera, float distance) | ||||
| { | ||||
|     Vector3 up = get_camera_up(camera); | ||||
|  | ||||
|     // Scale by distance | ||||
|     up = vector3_scale(up, distance); | ||||
|  | ||||
|     // Move position and target | ||||
|     camera->position = vector3_add(camera->position, up); | ||||
|     camera->target = vector3_add(camera->target, up); | ||||
| } | ||||
|  | ||||
| // Moves the camera target in its current right direction | ||||
| void camera_move_right(Camera *camera, float distance, bool moveInWorldPlane) | ||||
| { | ||||
|     Vector3 right = get_camera_right(camera); | ||||
|  | ||||
|     if (moveInWorldPlane) | ||||
|     { | ||||
|         // Project vector onto world plane | ||||
|         right.y = 0; | ||||
|         right = vector3_normalize(right); | ||||
|     } | ||||
|  | ||||
|     // Scale by distance | ||||
|     right = vector3_scale(right, distance); | ||||
|  | ||||
|     // Move position and target | ||||
|     camera->position = vector3_add(camera->position, right); | ||||
|     camera->target = vector3_add(camera->target, right); | ||||
| } | ||||
|  | ||||
| // Moves the camera position closer/farther to/from the camera target | ||||
| void camera_move_to_target(Camera *camera, float delta) | ||||
| { | ||||
|     float distance = vector3_distance(camera->position, camera->target); | ||||
|  | ||||
|     // Apply delta | ||||
|     distance += delta; | ||||
|  | ||||
|     // Distance must be greater than 0 | ||||
|     if (distance <= 0) distance = 0.001f; | ||||
|  | ||||
|     // Set new distance by moving the position along the forward vector | ||||
|     Vector3 forward = get_camera_forward(camera); | ||||
|     camera->position = vector3_add(camera->target, vector3_scale(forward, -distance)); | ||||
| } | ||||
|  | ||||
| // Rotates the camera around its up vector | ||||
| // Yaw is "looking left and right" | ||||
| // If rotateAroundTarget is false, the camera rotates around its position | ||||
| // Note: angle must be provided in radians | ||||
| void camera_yaw(Camera *camera, float angle, bool rotateAroundTarget) | ||||
| { | ||||
|     // Rotation axis | ||||
|     Vector3 up = get_camera_up(camera); | ||||
|  | ||||
|     // View vector | ||||
|     Vector3 targetPosition = vector3_subtract(camera->target, camera->position); | ||||
|  | ||||
|     // Rotate view vector around up axis | ||||
|     targetPosition = vector3_rotate_by_axis_angle(targetPosition, up, angle); | ||||
|  | ||||
|     if (rotateAroundTarget) | ||||
|     { | ||||
|         // Move position relative to target | ||||
|         camera->position = vector3_subtract(camera->target, targetPosition); | ||||
|     } | ||||
|     else // rotate around camera.position | ||||
|     { | ||||
|         // Move target relative to position | ||||
|         camera->target = vector3_add(camera->position, targetPosition); | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Rotates the camera around its right vector, pitch is "looking up and down" | ||||
| //  - lockView prevents camera overrotation (aka "somersaults") | ||||
| //  - rotateAroundTarget defines if rotation is around target or around its position | ||||
| //  - rotateUp rotates the up direction as well (typically only usefull in CAMERA_FREE) | ||||
| // NOTE: angle must be provided in radians | ||||
| void camera_pitch(Camera *camera, float angle, bool lockView, bool rotateAroundTarget, bool rotateUp) | ||||
| { | ||||
|     // Up direction | ||||
|     Vector3 up = get_camera_up(camera); | ||||
|  | ||||
|     // View vector | ||||
|     Vector3 targetPosition = vector3_subtract(camera->target, camera->position); | ||||
|  | ||||
|     if (lockView) | ||||
|     { | ||||
|         // In these camera modes we clamp the Pitch angle | ||||
|         // to allow only viewing straight up or down. | ||||
|  | ||||
|         // clamp view up | ||||
|         float maxAngleUp = vector3_angle(up, targetPosition); | ||||
|         maxAngleUp -= 0.001f; // avoid numerical errors | ||||
|         if (angle > maxAngleUp) angle = maxAngleUp; | ||||
|  | ||||
|         // clamp view down | ||||
|         float maxAngleDown = vector3_angle(vector3_negate(up), targetPosition); | ||||
|         maxAngleDown *= -1.0f; // downwards angle is negative | ||||
|         maxAngleDown += 0.001f; // avoid numerical errors | ||||
|         if (angle < maxAngleDown) angle = maxAngleDown; | ||||
|     } | ||||
|  | ||||
|     // Rotation axis | ||||
|     Vector3 right = get_camera_right(camera); | ||||
|  | ||||
|     // Rotate view vector around right axis | ||||
|     targetPosition = vector3_rotate_by_axis_angle(targetPosition, right, angle); | ||||
|  | ||||
|     if (rotateAroundTarget) | ||||
|     { | ||||
|         // Move position relative to target | ||||
|         camera->position = vector3_subtract(camera->target, targetPosition); | ||||
|     } | ||||
|     else // rotate around camera.position | ||||
|     { | ||||
|         // Move target relative to position | ||||
|         camera->target = vector3_add(camera->position, targetPosition); | ||||
|     } | ||||
|  | ||||
|     if (rotateUp) | ||||
|     { | ||||
|         // Rotate up direction around right axis | ||||
|         camera->up = vector3_rotate_by_axis_angle(camera->up, right, angle); | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Rotates the camera around its forward vector | ||||
| // Roll is "turning your head sideways to the left or right" | ||||
| // Note: angle must be provided in radians | ||||
| void camera_roll(Camera *camera, float angle) | ||||
| { | ||||
|     // Rotation axis | ||||
|     Vector3 forward = get_camera_forward(camera); | ||||
|  | ||||
|     // Rotate up direction around forward axis | ||||
|     camera->up = vector3_rotate_by_axis_angle(camera->up, forward, angle); | ||||
| } | ||||
|  | ||||
| // Returns the camera view matrix | ||||
| Matrix get_camera_view_matrix(Camera *camera) | ||||
| { | ||||
|     return matrix_look_at(camera->position, camera->target, camera->up); | ||||
| } | ||||
|  | ||||
| // Returns the camera projection matrix | ||||
| Matrix get_camera_projection_matrix(Camera *camera, float aspect) | ||||
| { | ||||
|     if (camera->projection == CAMERA_PERSPECTIVE) | ||||
|     { | ||||
|         return matrix_perspective(camera->fovy*RL_DEG2RAD, aspect, RL_CAMERA_CULL_DISTANCE_NEAR, RL_CAMERA_CULL_DISTANCE_FAR); | ||||
|     } | ||||
|     else if (camera->projection == CAMERA_ORTHOGRAPHIC) | ||||
|     { | ||||
|         double top = camera->fovy/2.0; | ||||
|         double right = top*aspect; | ||||
|  | ||||
|         return matrix_ortho(-right, right, -top, top, RL_CAMERA_CULL_DISTANCE_NEAR, RL_CAMERA_CULL_DISTANCE_FAR); | ||||
|     } | ||||
|  | ||||
|     return matrix_identity(); | ||||
| } | ||||
|  | ||||
| #if !defined(RCAMERA_STANDALONE) | ||||
| // Update camera position for selected mode | ||||
| // Camera mode: CAMERA_FREE, CAMERA_FIRST_PERSON, CAMERA_THIRD_PERSON, CAMERA_ORBITAL or CUSTOM | ||||
| void update_camera(Camera *camera, int mode) | ||||
| { | ||||
|     Vector2 mousePositionDelta = get_mouse_delta(); | ||||
|  | ||||
|     bool moveInWorldPlane = ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON)); | ||||
|     bool rotateAroundTarget = ((mode == CAMERA_THIRD_PERSON) || (mode == CAMERA_ORBITAL)); | ||||
|     bool lockView = ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON) || (mode == CAMERA_ORBITAL)); | ||||
|     bool rotateUp = false; | ||||
|  | ||||
|     if (mode == CAMERA_ORBITAL) | ||||
|     { | ||||
|         // Orbital can just orbit | ||||
|         Matrix rotation = matrix_rotate(get_camera_up(camera), CAMERA_ORBITAL_SPEED*get_frame_time()); | ||||
|         Vector3 view = vector3_subtract(camera->position, camera->target); | ||||
|         view = vector3_transform(view, rotation); | ||||
|         camera->position = vector3_add(camera->target, view); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         // Camera rotation | ||||
|         if (is_key_down(KEY_DOWN)) camera_pitch(camera, -CAMERA_ROTATION_SPEED, lockView, rotateAroundTarget, rotateUp); | ||||
|         if (is_key_down(KEY_UP)) camera_pitch(camera, CAMERA_ROTATION_SPEED, lockView, rotateAroundTarget, rotateUp); | ||||
|         if (is_key_down(KEY_RIGHT)) camera_yaw(camera, -CAMERA_ROTATION_SPEED, rotateAroundTarget); | ||||
|         if (is_key_down(KEY_LEFT)) camera_yaw(camera, CAMERA_ROTATION_SPEED, rotateAroundTarget); | ||||
|         if (is_key_down(KEY_Q)) camera_roll(camera, -CAMERA_ROTATION_SPEED); | ||||
|         if (is_key_down(KEY_E)) camera_roll(camera, CAMERA_ROTATION_SPEED); | ||||
|  | ||||
|         // Camera movement | ||||
|         if (!is_gamepad_available(0)) | ||||
|         { | ||||
|             // Camera pan (for CAMERA_FREE) | ||||
|             if ((mode == CAMERA_FREE) && (is_mouse_button_down(MOUSE_BUTTON_MIDDLE))) | ||||
|             { | ||||
|                 const Vector2 mouseDelta = get_mouse_delta(); | ||||
|                 if (mouseDelta.x > 0.0f) camera_move_right(camera, CAMERA_PAN_SPEED, moveInWorldPlane); | ||||
|                 if (mouseDelta.x < 0.0f) camera_move_right(camera, -CAMERA_PAN_SPEED, moveInWorldPlane); | ||||
|                 if (mouseDelta.y > 0.0f) camera_move_up(camera, -CAMERA_PAN_SPEED); | ||||
|                 if (mouseDelta.y < 0.0f) camera_move_up(camera, CAMERA_PAN_SPEED); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 // Mouse support | ||||
|                 camera_yaw(camera, -mousePositionDelta.x*CAMERA_MOUSE_MOVE_SENSITIVITY, rotateAroundTarget); | ||||
|                 camera_pitch(camera, -mousePositionDelta.y*CAMERA_MOUSE_MOVE_SENSITIVITY, lockView, rotateAroundTarget, rotateUp); | ||||
|             } | ||||
|  | ||||
|             // Keyboard support | ||||
|             if (is_key_down(KEY_W)) camera_move_forward(camera, CAMERA_MOVE_SPEED, moveInWorldPlane); | ||||
|             if (is_key_down(KEY_A)) camera_move_right(camera, -CAMERA_MOVE_SPEED, moveInWorldPlane); | ||||
|             if (is_key_down(KEY_S)) camera_move_forward(camera, -CAMERA_MOVE_SPEED, moveInWorldPlane); | ||||
|             if (is_key_down(KEY_D)) camera_move_right(camera, CAMERA_MOVE_SPEED, moveInWorldPlane); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             // Gamepad controller support | ||||
|             camera_yaw(camera, -(get_gamepad_axis_movement(0, GAMEPAD_AXIS_RIGHT_X) * 2)*CAMERA_MOUSE_MOVE_SENSITIVITY, rotateAroundTarget); | ||||
|             camera_pitch(camera, -(get_gamepad_axis_movement(0, GAMEPAD_AXIS_RIGHT_Y) * 2)*CAMERA_MOUSE_MOVE_SENSITIVITY, lockView, rotateAroundTarget, rotateUp); | ||||
|  | ||||
|             if (get_gamepad_axis_movement(0, GAMEPAD_AXIS_LEFT_Y) <= -0.25f) camera_move_forward(camera, CAMERA_MOVE_SPEED, moveInWorldPlane); | ||||
|             if (get_gamepad_axis_movement(0, GAMEPAD_AXIS_LEFT_X) <= -0.25f) camera_move_right(camera, -CAMERA_MOVE_SPEED, moveInWorldPlane); | ||||
|             if (get_gamepad_axis_movement(0, GAMEPAD_AXIS_LEFT_Y) >= 0.25f) camera_move_forward(camera, -CAMERA_MOVE_SPEED, moveInWorldPlane); | ||||
|             if (get_gamepad_axis_movement(0, GAMEPAD_AXIS_LEFT_X) >= 0.25f) camera_move_right(camera, CAMERA_MOVE_SPEED, moveInWorldPlane); | ||||
|         } | ||||
|  | ||||
|         if (mode == CAMERA_FREE) | ||||
|         { | ||||
|             if (is_key_down(KEY_SPACE)) camera_move_up(camera, CAMERA_MOVE_SPEED); | ||||
|             if (is_key_down(KEY_LEFT_CONTROL)) camera_move_up(camera, -CAMERA_MOVE_SPEED); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if ((mode == CAMERA_THIRD_PERSON) || (mode == CAMERA_ORBITAL) || (mode == CAMERA_FREE)) | ||||
|     { | ||||
|         // Zoom target distance | ||||
|         camera_move_to_target(camera, -get_mouse_wheel_move()); | ||||
|         if (is_key_pressed(KEY_KP_SUBTRACT)) camera_move_to_target(camera, 2.0f); | ||||
|         if (is_key_pressed(KEY_KP_ADD)) camera_move_to_target(camera, -2.0f); | ||||
|     } | ||||
| } | ||||
| #endif // !RCAMERA_STANDALONE | ||||
|  | ||||
| // Update camera movement, movement/rotation values should be provided by user | ||||
| void update_camera_pro(Camera *camera, Vector3 movement, Vector3 rotation, float zoom) | ||||
| { | ||||
|     // Required values | ||||
|     // movement.x - Move forward/backward | ||||
|     // movement.y - Move right/left | ||||
|     // movement.z - Move up/down | ||||
|     // rotation.x - yaw | ||||
|     // rotation.y - pitch | ||||
|     // rotation.z - roll | ||||
|     // zoom - Move towards target | ||||
|  | ||||
|     bool lockView = true; | ||||
|     bool rotateAroundTarget = false; | ||||
|     bool rotateUp = false; | ||||
|     bool moveInWorldPlane = true; | ||||
|  | ||||
|     // Camera rotation | ||||
|     camera_pitch(camera, -rotation.y*RL_DEG2RAD, lockView, rotateAroundTarget, rotateUp); | ||||
|     camera_yaw(camera, -rotation.x*RL_DEG2RAD, rotateAroundTarget); | ||||
|     camera_roll(camera, rotation.z*RL_DEG2RAD); | ||||
|  | ||||
|     // Camera movement | ||||
|     camera_move_forward(camera, movement.x, moveInWorldPlane); | ||||
|     camera_move_right(camera, movement.y, moveInWorldPlane); | ||||
|     camera_move_up(camera, movement.z); | ||||
|  | ||||
|     // Zoom target distance | ||||
|     camera_move_to_target(camera, zoom); | ||||
| } | ||||
|  | ||||
| RL_NS_END | ||||
|  | ||||
| #endif // RCAMERA_IMPLEMENTATION | ||||
| @@ -1,579 +0,0 @@ | ||||
| /********************************************************************************************** | ||||
| * | ||||
| *   rgestures - Gestures system, gestures processing based on input events (touch/mouse) | ||||
| * | ||||
| *   CONFIGURATION: | ||||
| *       #define RGESTURES_IMPLEMENTATION | ||||
| *           Generates the implementation of the library into the included file. | ||||
| *           If not defined, the library is in header only mode and can be included in other headers | ||||
| *           or source files without problems. But only ONE file should hold the implementation. | ||||
| * | ||||
| *       #define RGESTURES_STANDALONE | ||||
| *           If defined, the library can be used as standalone to process gesture events with | ||||
| *           no external dependencies. | ||||
| * | ||||
| *   CONTRIBUTORS: | ||||
| *       Marc Palau:         Initial implementation (2014) | ||||
| *       Albert Martos:      Complete redesign and testing (2015) | ||||
| *       Ian Eito:           Complete redesign and testing (2015) | ||||
| *       Ramon Santamaria:   Supervision, review, update and maintenance | ||||
| * | ||||
| * | ||||
| *   LICENSE: zlib/libpng | ||||
| * | ||||
| *   Copyright (c) 2014-2023 Ramon Santamaria (@raysan5) | ||||
| * | ||||
| *   This software is provided "as-is", without any express or implied warranty. In no event | ||||
| *   will the authors be held liable for any damages arising from the use of this software. | ||||
| * | ||||
| *   Permission is granted to anyone to use this software for any purpose, including commercial | ||||
| *   applications, and to alter it and redistribute it freely, subject to the following restrictions: | ||||
| * | ||||
| *     1. The origin of this software must not be misrepresented; you must not claim that you | ||||
| *     wrote the original software. If you use this software in a product, an acknowledgment | ||||
| *     in the product documentation would be appreciated but is not required. | ||||
| * | ||||
| *     2. Altered source versions must be plainly marked as such, and must not be misrepresented | ||||
| *     as being the original software. | ||||
| * | ||||
| *     3. This notice may not be removed or altered from any source distribution. | ||||
| * | ||||
| **********************************************************************************************/ | ||||
|  | ||||
| #ifndef RGESTURES_H | ||||
| #define RGESTURES_H | ||||
|  | ||||
| #ifndef RL_PI | ||||
|     #define RL_PI 3.14159265358979323846 | ||||
| #endif | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Defines and Macros | ||||
| //---------------------------------------------------------------------------------- | ||||
| #ifndef RL_MAX_TOUCH_POINTS | ||||
|     #define RL_MAX_TOUCH_POINTS        8        // Maximum number of touch points supported | ||||
| #endif | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Types and Structures Definition | ||||
| // NOTE: Below types are required for standalone usage | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Boolean type | ||||
| #if (defined(__STDC__) && __STDC_VERSION__ >= 199901L) || (defined(_MSC_VER) && _MSC_VER >= 1800) | ||||
|     #include <stdbool.h> | ||||
| #elif !defined(__cplusplus) && !defined(bool) && !defined(RL_BOOL_TYPE) | ||||
|     typedef enum bool { false = 0, true = !false } bool; | ||||
| #endif | ||||
|  | ||||
| #include "config.h" | ||||
|  | ||||
| RL_NS_BEGIN | ||||
|  | ||||
| #if !defined(RL_VECTOR2_TYPE) | ||||
| // Vector2 type | ||||
| typedef struct Vector2 { | ||||
|     float x; | ||||
|     float y; | ||||
| } Vector2; | ||||
| #endif | ||||
|  | ||||
| #if defined(RGESTURES_STANDALONE) | ||||
| // Gestures type | ||||
| // NOTE: It could be used as flags to enable only some gestures | ||||
| typedef enum { | ||||
|     GESTURE_NONE        = 0, | ||||
|     GESTURE_TAP         = 1, | ||||
|     GESTURE_DOUBLETAP   = 2, | ||||
|     GESTURE_HOLD        = 4, | ||||
|     GESTURE_DRAG        = 8, | ||||
|     GESTURE_SWIPE_RIGHT = 16, | ||||
|     GESTURE_SWIPE_LEFT  = 32, | ||||
|     GESTURE_SWIPE_UP    = 64, | ||||
|     GESTURE_SWIPE_DOWN  = 128, | ||||
|     GESTURE_PINCH_IN    = 256, | ||||
|     GESTURE_PINCH_OUT   = 512 | ||||
| } Gesture; | ||||
| #endif | ||||
|  | ||||
| typedef enum { | ||||
|     TOUCH_ACTION_UP = 0, | ||||
|     TOUCH_ACTION_DOWN, | ||||
|     TOUCH_ACTION_MOVE, | ||||
|     TOUCH_ACTION_CANCEL | ||||
| } TouchAction; | ||||
|  | ||||
| // Gesture event | ||||
| typedef struct { | ||||
|     int touchAction; | ||||
|     int pointCount; | ||||
|     int pointId[RL_MAX_TOUCH_POINTS]; | ||||
|     Vector2 position[RL_MAX_TOUCH_POINTS]; | ||||
| } GestureEvent; | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Global Variables Definition | ||||
| //---------------------------------------------------------------------------------- | ||||
| //... | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Module Functions Declaration | ||||
| //---------------------------------------------------------------------------------- | ||||
|  | ||||
| RL_EXTERN_C_BEGIN | ||||
|  | ||||
| void process_gesture_event(GestureEvent event);           // Process gesture event and translate it into gestures | ||||
| void update_gestures(void);                              // Update gestures detected (must be called every frame) | ||||
|  | ||||
| #if defined(RGESTURES_STANDALONE) | ||||
| void set_gestures_enabled(unsigned int flags);            // Enable a set of gestures using flags | ||||
| bool is_gesture_detected(int gesture);                    // Check if a gesture have been detected | ||||
| int get_gesture_detected(void);                           // Get latest detected gesture | ||||
|  | ||||
| float get_gesture_hold_duration(void);                     // Get gesture hold time in seconds | ||||
| Vector2 get_gesture_drag_vector(void);                     // Get gesture drag vector | ||||
| float get_gesture_drag_angle(void);                        // Get gesture drag angle | ||||
| Vector2 get_gesture_pinch_vector(void);                    // Get gesture pinch delta | ||||
| float get_gesture_pinch_angle(void);                       // Get gesture pinch angle | ||||
| #endif | ||||
|  | ||||
| RL_EXTERN_C_END | ||||
|  | ||||
| RL_NS_END | ||||
|  | ||||
| #endif // RGESTURES_H | ||||
|  | ||||
| /*********************************************************************************** | ||||
| * | ||||
| *   RGESTURES IMPLEMENTATION | ||||
| * | ||||
| ************************************************************************************/ | ||||
|  | ||||
| #if defined(RGESTURES_IMPLEMENTATION) | ||||
|  | ||||
| #if defined(RGESTURES_STANDALONE) | ||||
| #if defined(_WIN32) | ||||
|     #if defined(__cplusplus) | ||||
|     extern "C" {        // Prevents name mangling of functions | ||||
|     #endif | ||||
|     // Functions required to query time on Windows | ||||
|     int __stdcall query_performance_counter(unsigned long long int *lpPerformanceCount); | ||||
|     int __stdcall query_performance_frequency(unsigned long long int *lpFrequency); | ||||
|     #if defined(__cplusplus) | ||||
|     } | ||||
|     #endif | ||||
| #elif defined(__linux__) | ||||
|     #if _POSIX_C_SOURCE < 199309L | ||||
|         #undef _POSIX_C_SOURCE | ||||
|         #define _POSIX_C_SOURCE 199309L // Required for CLOCK_MONOTONIC if compiled with c99 without gnu ext. | ||||
|     #endif | ||||
|     #include <sys/time.h>               // Required for: timespec | ||||
|     #include <time.h>                   // Required for: clock_gettime() | ||||
|  | ||||
|     #include <math.h>                   // Required for: sqrtf(), atan2f() | ||||
| #endif | ||||
| #if defined(__APPLE__)                  // macOS also defines __MACH__ | ||||
|     #include <mach/clock.h>             // Required for: clock_get_time() | ||||
|     #include <mach/mach.h>              // Required for: mach_timespec_t | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Defines and Macros | ||||
| //---------------------------------------------------------------------------------- | ||||
| #define RL_FORCE_TO_SWIPE      0.2f        // Swipe force, measured in normalized screen units/time | ||||
| #define RL_MINIMUM_DRAG        0.015f      // Drag minimum force, measured in normalized screen units (0.0f to 1.0f) | ||||
| #define RL_DRAG_TIMEOUT        0.3f        // Drag minimum time for web, measured in seconds | ||||
| #define RL_MINIMUM_PINCH       0.005f      // Pinch minimum force, measured in normalized screen units (0.0f to 1.0f) | ||||
| #define RL_TAP_TIMEOUT         0.3f        // Tap minimum time, measured in seconds | ||||
| #define RL_PINCH_TIMEOUT       0.3f        // Pinch minimum time, measured in seconds | ||||
| #define RL_DOUBLETAP_RANGE     0.03f       // DoubleTap range, measured in normalized screen units (0.0f to 1.0f) | ||||
|  | ||||
| RL_NS_BEGIN | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Types and Structures Definition | ||||
| //---------------------------------------------------------------------------------- | ||||
|  | ||||
| // Gestures module state context [136 bytes] | ||||
| typedef struct { | ||||
|     unsigned int current;               // Current detected gesture | ||||
|     unsigned int enabledFlags;          // Enabled gestures flags | ||||
|     struct { | ||||
|         int firstId;                    // Touch id for first touch point | ||||
|         int pointCount;                 // Touch points counter | ||||
|         double eventTime;               // Time stamp when an event happened | ||||
|         Vector2 upPosition;             // Touch up position | ||||
|         Vector2 downPositionA;          // First touch down position | ||||
|         Vector2 downPositionB;          // Second touch down position | ||||
|         Vector2 downDragPosition;       // Touch drag position | ||||
|         Vector2 moveDownPositionA;      // First touch down position on move | ||||
|         Vector2 moveDownPositionB;      // Second touch down position on move | ||||
|         Vector2 previousPositionA;      // Previous position A to compare for pinch gestures | ||||
|         Vector2 previousPositionB;      // Previous position B to compare for pinch gestures | ||||
|         int tapCounter;                 // TAP counter (one tap implies TOUCH_ACTION_DOWN and TOUCH_ACTION_UP actions) | ||||
|     } Touch; | ||||
|     struct { | ||||
|         bool resetRequired;             // HOLD reset to get first touch point again | ||||
|         double timeDuration;            // HOLD duration in seconds | ||||
|     } Hold; | ||||
|     struct { | ||||
|         Vector2 vector;                 // DRAG vector (between initial and current position) | ||||
|         float angle;                    // DRAG angle (relative to x-axis) | ||||
|         float distance;                 // DRAG distance (from initial touch point to final) (normalized [0..1]) | ||||
|         float intensity;                // DRAG intensity, how far why did the DRAG (pixels per frame) | ||||
|     } Drag; | ||||
|     struct { | ||||
|         double startTime;               // SWIPE start time to calculate drag intensity | ||||
|     } Swipe; | ||||
|     struct { | ||||
|         Vector2 vector;                 // PINCH vector (between first and second touch points) | ||||
|         float angle;                    // PINCH angle (relative to x-axis) | ||||
|         float distance;                 // PINCH displacement distance (normalized [0..1]) | ||||
|     } Pinch; | ||||
| } GesturesData; | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Global Variables Definition | ||||
| //---------------------------------------------------------------------------------- | ||||
| static GesturesData GESTURES = { | ||||
| #ifdef __cplusplus | ||||
|     (unsigned int)-1, | ||||
|     GESTURE_NONE, | ||||
|     0b0000001111111111 | ||||
| #else | ||||
|     .Touch.firstId = -1, | ||||
|     .current = GESTURE_NONE,        // No current gesture detected | ||||
|     .enabledFlags = 0b0000001111111111  // All gestures supported by default | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Module specific Functions Declaration | ||||
| //---------------------------------------------------------------------------------- | ||||
| static float rg_vector2_angle(Vector2 initialPosition, Vector2 finalPosition); | ||||
| static float rg_vector2_distance(Vector2 v1, Vector2 v2); | ||||
| static double rg_get_current_time(void); | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Module Functions Definition | ||||
| //---------------------------------------------------------------------------------- | ||||
|  | ||||
| // Enable only desired gestures to be detected | ||||
| void set_gestures_enabled(unsigned int flags) | ||||
| { | ||||
|     GESTURES.enabledFlags = flags; | ||||
| } | ||||
|  | ||||
| // Check if a gesture have been detected | ||||
| bool is_gesture_detected(unsigned int gesture) | ||||
| { | ||||
|     if ((GESTURES.enabledFlags & GESTURES.current) == gesture) return true; | ||||
|     else return false; | ||||
| } | ||||
|  | ||||
| // Process gesture event and translate it into gestures | ||||
| void process_gesture_event(GestureEvent event) | ||||
| { | ||||
|     // Reset required variables | ||||
|     GESTURES.Touch.pointCount = event.pointCount;      // Required on update_gestures() | ||||
|  | ||||
|     if (GESTURES.Touch.pointCount == 1)     // One touch point | ||||
|     { | ||||
|         if (event.touchAction == TOUCH_ACTION_DOWN) | ||||
|         { | ||||
|             GESTURES.Touch.tapCounter++;    // Tap counter | ||||
|  | ||||
|             // Detect GESTURE_DOUBLE_TAP | ||||
|             if ((GESTURES.current == GESTURE_NONE) && (GESTURES.Touch.tapCounter >= 2) && ((rg_get_current_time() - GESTURES.Touch.eventTime) < RL_TAP_TIMEOUT) && (rg_vector2_distance(GESTURES.Touch.downPositionA, event.position[0]) < RL_DOUBLETAP_RANGE)) | ||||
|             { | ||||
|                 GESTURES.current = GESTURE_DOUBLETAP; | ||||
|                 GESTURES.Touch.tapCounter = 0; | ||||
|             } | ||||
|             else    // Detect GESTURE_TAP | ||||
|             { | ||||
|                 GESTURES.Touch.tapCounter = 1; | ||||
|                 GESTURES.current = GESTURE_TAP; | ||||
|             } | ||||
|  | ||||
|             GESTURES.Touch.downPositionA = event.position[0]; | ||||
|             GESTURES.Touch.downDragPosition = event.position[0]; | ||||
|  | ||||
|             GESTURES.Touch.upPosition = GESTURES.Touch.downPositionA; | ||||
|             GESTURES.Touch.eventTime = rg_get_current_time(); | ||||
|  | ||||
|             GESTURES.Swipe.startTime = rg_get_current_time(); | ||||
|  | ||||
|         #ifdef __cplusplus | ||||
|             GESTURES.Drag.vector = Vector2{ 0.0f, 0.0f }; | ||||
|         #else | ||||
|             GESTURES.Drag.vector = (Vector2){ 0.0f, 0.0f }; | ||||
|         #endif | ||||
|         } | ||||
|         else if (event.touchAction == TOUCH_ACTION_UP) | ||||
|         { | ||||
|             // A swipe can happen while the current gesture is drag, but (specially for web) also hold, so set upPosition for both cases | ||||
|             if (GESTURES.current == GESTURE_DRAG || GESTURES.current == GESTURE_HOLD) GESTURES.Touch.upPosition = event.position[0]; | ||||
|  | ||||
|             // NOTE: GESTURES.Drag.intensity dependent on the resolution of the screen | ||||
|             GESTURES.Drag.distance = rg_vector2_distance(GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition); | ||||
|             GESTURES.Drag.intensity = GESTURES.Drag.distance/(float)((rg_get_current_time() - GESTURES.Swipe.startTime)); | ||||
|  | ||||
|             // Detect GESTURE_SWIPE | ||||
|             if ((GESTURES.Drag.intensity > RL_FORCE_TO_SWIPE) && (GESTURES.current != GESTURE_DRAG)) | ||||
|             { | ||||
|                 // NOTE: Angle should be inverted in Y | ||||
|                 GESTURES.Drag.angle = 360.0f - rg_vector2_angle(GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition); | ||||
|  | ||||
|                 if ((GESTURES.Drag.angle < 30) || (GESTURES.Drag.angle > 330)) GESTURES.current = GESTURE_SWIPE_RIGHT;          // Right | ||||
|                 else if ((GESTURES.Drag.angle >= 30) && (GESTURES.Drag.angle <= 150)) GESTURES.current = GESTURE_SWIPE_UP;      // Up | ||||
|                 else if ((GESTURES.Drag.angle > 150) && (GESTURES.Drag.angle < 210)) GESTURES.current = GESTURE_SWIPE_LEFT;     // Left | ||||
|                 else if ((GESTURES.Drag.angle >= 210) && (GESTURES.Drag.angle <= 330)) GESTURES.current = GESTURE_SWIPE_DOWN;   // Down | ||||
|                 else GESTURES.current = GESTURE_NONE; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 GESTURES.Drag.distance = 0.0f; | ||||
|                 GESTURES.Drag.intensity = 0.0f; | ||||
|                 GESTURES.Drag.angle = 0.0f; | ||||
|  | ||||
|                 GESTURES.current = GESTURE_NONE; | ||||
|             } | ||||
|  | ||||
|         #if __cplusplus | ||||
|             GESTURES.Touch.downDragPosition = Vector2{ 0.0f, 0.0f }; | ||||
|         #else | ||||
|             GESTURES.Touch.downDragPosition = (Vector2){ 0.0f, 0.0f }; | ||||
|         #endif | ||||
|             GESTURES.Touch.pointCount = 0; | ||||
|         } | ||||
|         else if (event.touchAction == TOUCH_ACTION_MOVE) | ||||
|         { | ||||
|             GESTURES.Touch.moveDownPositionA = event.position[0]; | ||||
|  | ||||
|             if (GESTURES.current == GESTURE_HOLD) | ||||
|             { | ||||
|                 if (GESTURES.Hold.resetRequired) GESTURES.Touch.downPositionA = event.position[0]; | ||||
|  | ||||
|                 GESTURES.Hold.resetRequired = false; | ||||
|  | ||||
|                 // Detect GESTURE_DRAG | ||||
|                 if ((rg_get_current_time() - GESTURES.Touch.eventTime) > RL_DRAG_TIMEOUT) | ||||
|                 { | ||||
|                     GESTURES.Touch.eventTime = rg_get_current_time(); | ||||
|                     GESTURES.current = GESTURE_DRAG; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             GESTURES.Drag.vector.x = GESTURES.Touch.moveDownPositionA.x - GESTURES.Touch.downDragPosition.x; | ||||
|             GESTURES.Drag.vector.y = GESTURES.Touch.moveDownPositionA.y - GESTURES.Touch.downDragPosition.y; | ||||
|         } | ||||
|     } | ||||
|     else if (GESTURES.Touch.pointCount == 2)    // Two touch points | ||||
|     { | ||||
|         if (event.touchAction == TOUCH_ACTION_DOWN) | ||||
|         { | ||||
|             GESTURES.Touch.downPositionA = event.position[0]; | ||||
|             GESTURES.Touch.downPositionB = event.position[1]; | ||||
|  | ||||
|             GESTURES.Touch.previousPositionA = GESTURES.Touch.downPositionA; | ||||
|             GESTURES.Touch.previousPositionB = GESTURES.Touch.downPositionB; | ||||
|  | ||||
|             //GESTURES.Pinch.distance = rg_vector2_distance(GESTURES.Touch.downPositionA, GESTURES.Touch.downPositionB); | ||||
|  | ||||
|             GESTURES.Pinch.vector.x = GESTURES.Touch.downPositionB.x - GESTURES.Touch.downPositionA.x; | ||||
|             GESTURES.Pinch.vector.y = GESTURES.Touch.downPositionB.y - GESTURES.Touch.downPositionA.y; | ||||
|  | ||||
|             GESTURES.current = GESTURE_HOLD; | ||||
|             GESTURES.Hold.timeDuration = rg_get_current_time(); | ||||
|         } | ||||
|         else if (event.touchAction == TOUCH_ACTION_MOVE) | ||||
|         { | ||||
|             GESTURES.Pinch.distance = rg_vector2_distance(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB); | ||||
|  | ||||
|             GESTURES.Touch.moveDownPositionA = event.position[0]; | ||||
|             GESTURES.Touch.moveDownPositionB = event.position[1]; | ||||
|  | ||||
|             GESTURES.Pinch.vector.x = GESTURES.Touch.moveDownPositionB.x - GESTURES.Touch.moveDownPositionA.x; | ||||
|             GESTURES.Pinch.vector.y = GESTURES.Touch.moveDownPositionB.y - GESTURES.Touch.moveDownPositionA.y; | ||||
|  | ||||
|             if ((rg_vector2_distance(GESTURES.Touch.previousPositionA, GESTURES.Touch.moveDownPositionA) >= RL_MINIMUM_PINCH) || (rg_vector2_distance(GESTURES.Touch.previousPositionB, GESTURES.Touch.moveDownPositionB) >= RL_MINIMUM_PINCH)) | ||||
|             { | ||||
|                 if ( rg_vector2_distance(GESTURES.Touch.previousPositionA, GESTURES.Touch.previousPositionB) > rg_vector2_distance(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB) ) GESTURES.current = GESTURE_PINCH_IN; | ||||
|                 else GESTURES.current = GESTURE_PINCH_OUT; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 GESTURES.current = GESTURE_HOLD; | ||||
|                 GESTURES.Hold.timeDuration = rg_get_current_time(); | ||||
|             } | ||||
|  | ||||
|             // NOTE: Angle should be inverted in Y | ||||
|             GESTURES.Pinch.angle = 360.0f - rg_vector2_angle(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB); | ||||
|         } | ||||
|         else if (event.touchAction == TOUCH_ACTION_UP) | ||||
|         { | ||||
|             GESTURES.Pinch.distance = 0.0f; | ||||
|             GESTURES.Pinch.angle = 0.0f; | ||||
|         #if __cplusplus | ||||
|             GESTURES.Pinch.vector = Vector2{ 0.0f, 0.0f }; | ||||
|         #else | ||||
|             GESTURES.Pinch.vector = (Vector2){ 0.0f, 0.0f }; | ||||
|         #endif | ||||
|             GESTURES.Touch.pointCount = 0; | ||||
|  | ||||
|             GESTURES.current = GESTURE_NONE; | ||||
|         } | ||||
|     } | ||||
|     else if (GESTURES.Touch.pointCount > 2)     // More than two touch points | ||||
|     { | ||||
|         // TODO: Process gesture events for more than two points | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Update gestures detected (must be called every frame) | ||||
| void update_gestures(void) | ||||
| { | ||||
|     // NOTE: Gestures are processed through system callbacks on touch events | ||||
|  | ||||
|     // Detect GESTURE_HOLD | ||||
|     if (((GESTURES.current == GESTURE_TAP) || (GESTURES.current == GESTURE_DOUBLETAP)) && (GESTURES.Touch.pointCount < 2)) | ||||
|     { | ||||
|         GESTURES.current = GESTURE_HOLD; | ||||
|         GESTURES.Hold.timeDuration = rg_get_current_time(); | ||||
|     } | ||||
|  | ||||
|     // Detect GESTURE_NONE | ||||
|     if ((GESTURES.current == GESTURE_SWIPE_RIGHT) || (GESTURES.current == GESTURE_SWIPE_UP) || (GESTURES.current == GESTURE_SWIPE_LEFT) || (GESTURES.current == GESTURE_SWIPE_DOWN)) | ||||
|     { | ||||
|         GESTURES.current = GESTURE_NONE; | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Get latest detected gesture | ||||
| int get_gesture_detected(void) | ||||
| { | ||||
|     // Get current gesture only if enabled | ||||
|     return (GESTURES.enabledFlags & GESTURES.current); | ||||
| } | ||||
|  | ||||
| // Hold time measured in ms | ||||
| float get_gesture_hold_duration(void) | ||||
| { | ||||
|     // NOTE: time is calculated on current gesture HOLD | ||||
|  | ||||
|     double time = 0.0; | ||||
|  | ||||
|     if (GESTURES.current == GESTURE_HOLD) time = rg_get_current_time() - GESTURES.Hold.timeDuration; | ||||
|  | ||||
|     return (float)time; | ||||
| } | ||||
|  | ||||
| // Get drag vector (between initial touch point to current) | ||||
| Vector2 get_gesture_drag_vector(void) | ||||
| { | ||||
|     // NOTE: drag vector is calculated on one touch points TOUCH_ACTION_MOVE | ||||
|  | ||||
|     return GESTURES.Drag.vector; | ||||
| } | ||||
|  | ||||
| // Get drag angle | ||||
| // NOTE: Angle in degrees, horizontal-right is 0, counterclockwise | ||||
| float get_gesture_drag_angle(void) | ||||
| { | ||||
|     // NOTE: drag angle is calculated on one touch points TOUCH_ACTION_UP | ||||
|  | ||||
|     return GESTURES.Drag.angle; | ||||
| } | ||||
|  | ||||
| // Get distance between two pinch points | ||||
| Vector2 get_gesture_pinch_vector(void) | ||||
| { | ||||
|     // NOTE: Pinch distance is calculated on two touch points TOUCH_ACTION_MOVE | ||||
|  | ||||
|     return GESTURES.Pinch.vector; | ||||
| } | ||||
|  | ||||
| // Get angle between two pinch points | ||||
| // NOTE: Angle in degrees, horizontal-right is 0, counterclockwise | ||||
| float get_gesture_pinch_angle(void) | ||||
| { | ||||
|     // NOTE: pinch angle is calculated on two touch points TOUCH_ACTION_MOVE | ||||
|  | ||||
|     return GESTURES.Pinch.angle; | ||||
| } | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Module specific Functions Definition | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Get angle from two-points vector with X-axis | ||||
| static float rg_vector2_angle(Vector2 v1, Vector2 v2) | ||||
| { | ||||
|     float angle = atan2f(v2.y - v1.y, v2.x - v1.x)*(180.0f/RL_PI); | ||||
|  | ||||
|     if (angle < 0) angle += 360.0f; | ||||
|  | ||||
|     return angle; | ||||
| } | ||||
|  | ||||
| // Calculate distance between two Vector2 | ||||
| static float rg_vector2_distance(Vector2 v1, Vector2 v2) | ||||
| { | ||||
|     float result; | ||||
|  | ||||
|     float dx = v2.x - v1.x; | ||||
|     float dy = v2.y - v1.y; | ||||
|  | ||||
|     result = (float)sqrt(dx*dx + dy*dy); | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| // Time measure returned are seconds | ||||
| static double rg_get_current_time(void) | ||||
| { | ||||
|     double time = 0; | ||||
|  | ||||
| #if !defined(RGESTURES_STANDALONE) | ||||
|     time = get_time(); | ||||
| #else | ||||
| #if defined(_WIN32) | ||||
|     unsigned long long int clockFrequency, currentTime; | ||||
|  | ||||
|     query_performance_frequency(&clockFrequency);     // BE CAREFUL: Costly operation! | ||||
|     query_performance_counter(¤tTime); | ||||
|  | ||||
|     time = (double)currentTime/clockFrequency;  // Time in seconds | ||||
| #endif | ||||
|  | ||||
| #if defined(__linux__) | ||||
|     // NOTE: Only for Linux-based systems | ||||
|     struct timespec now; | ||||
|     clock_gettime(CLOCK_MONOTONIC, &now); | ||||
|     unsigned long long int nowTime = (unsigned long long int)now.tv_sec*1000000000LLU + (unsigned long long int)now.tv_nsec;     // Time in nanoseconds | ||||
|  | ||||
|     time = ((double)nowTime*1e-9);     // Time in seconds | ||||
| #endif | ||||
|  | ||||
| #if defined(__APPLE__) | ||||
|     //#define CLOCK_REALTIME  CALENDAR_CLOCK    // returns UTC time since 1970-01-01 | ||||
|     //#define CLOCK_MONOTONIC SYSTEM_CLOCK      // returns the time since boot time | ||||
|  | ||||
|     clock_serv_t cclock; | ||||
|     mach_timespec_t now; | ||||
|     host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock); | ||||
|  | ||||
|     // NOTE: OS X does not have clock_gettime(), using clock_get_time() | ||||
|     clock_get_time(cclock, &now); | ||||
|     mach_port_deallocate(mach_task_self(), cclock); | ||||
|     unsigned long long int nowTime = (unsigned long long int)now.tv_sec*1000000000LLU + (unsigned long long int)now.tv_nsec;     // Time in nanoseconds | ||||
|  | ||||
|     time = ((double)nowTime*1e-9);     // Time in seconds | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
|     return time; | ||||
| } | ||||
|  | ||||
| RL_NS_END | ||||
|  | ||||
| #endif // RGESTURES_IMPLEMENTATION | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,81 +0,0 @@ | ||||
| /********************************************************************************************** | ||||
| * | ||||
| *   raylib.utils - Some common utility functions | ||||
| * | ||||
| * | ||||
| *   LICENSE: zlib/libpng | ||||
| * | ||||
| *   Copyright (c) 2014-2023 Ramon Santamaria (@raysan5) | ||||
| * | ||||
| *   This software is provided "as-is", without any express or implied warranty. In no event | ||||
| *   will the authors be held liable for any damages arising from the use of this software. | ||||
| * | ||||
| *   Permission is granted to anyone to use this software for any purpose, including commercial | ||||
| *   applications, and to alter it and redistribute it freely, subject to the following restrictions: | ||||
| * | ||||
| *     1. The origin of this software must not be misrepresented; you must not claim that you | ||||
| *     wrote the original software. If you use this software in a product, an acknowledgment | ||||
| *     in the product documentation would be appreciated but is not required. | ||||
| * | ||||
| *     2. Altered source versions must be plainly marked as such, and must not be misrepresented | ||||
| *     as being the original software. | ||||
| * | ||||
| *     3. This notice may not be removed or altered from any source distribution. | ||||
| * | ||||
| **********************************************************************************************/ | ||||
|  | ||||
| #ifndef UTILS_H | ||||
| #define UTILS_H | ||||
|  | ||||
| #if defined(PLATFORM_ANDROID) | ||||
|     #include <stdio.h>                      // Required for: FILE | ||||
|     #include <android/asset_manager.h>      // Required for: AAssetManager | ||||
| #endif | ||||
|  | ||||
| #if defined(RL_SUPPORT_TRACELOG) | ||||
|     #define RL_TRACELOG(level, ...) RL_NS(trace_log)(level, __VA_ARGS__) | ||||
|  | ||||
|     #if defined(RL_SUPPORT_TRACELOG_DEBUG) | ||||
|         #define TRACELOGD(...) RL_NS(trace_log)(LOG_DEBUG, __VA_ARGS__) | ||||
|     #else | ||||
|         #define TRACELOGD(...) (void)0 | ||||
|     #endif | ||||
| #else | ||||
|     #define RL_TRACELOG(level, ...) (void)0 | ||||
|     #define TRACELOGD(...) (void)0 | ||||
| #endif | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Some basic Defines | ||||
| //---------------------------------------------------------------------------------- | ||||
| #if defined(PLATFORM_ANDROID) | ||||
|     #define fopen(name, mode) android_fopen(name, mode) | ||||
| #endif | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Types and Structures Definition | ||||
| //---------------------------------------------------------------------------------- | ||||
| //... | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Global Variables Definition | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Nop... | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Module Functions Declaration | ||||
| //---------------------------------------------------------------------------------- | ||||
| #if defined(__cplusplus) | ||||
| extern "C" {            // Prevents name mangling of functions | ||||
| #endif | ||||
|  | ||||
| #if defined(PLATFORM_ANDROID) | ||||
| void init_asset_manager(AAssetManager *manager, const char *dataPath);   // Initialize asset manager from android app | ||||
| FILE *android_fopen(const char *fileName, const char *mode);           // Replacement for fopen() -> Read-only! | ||||
| #endif | ||||
|  | ||||
| #if defined(__cplusplus) | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #endif // UTILS_H | ||||
										
											Binary file not shown.
										
									
								
							| @@ -1,8 +0,0 @@ | ||||
| #include "raudio.c" | ||||
| #include "rcore.c" | ||||
| #include "rglfw.c" | ||||
| #include "rmodels.c" | ||||
| #include "rshapes.c" | ||||
| #include "rtext.c" | ||||
| #include "rtextures.c" | ||||
| #include "rutils.c" | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,242 +0,0 @@ | ||||
| // rlgl.h | ||||
|  | ||||
| word RL_NOT_REFACTORED, RL_REFACTORED_CPP | ||||
|  | ||||
| namespace rl_, | ||||
| namespace rl, | ||||
| namespace rlgl, | ||||
| not word  rl | ||||
| not word  rlgl | ||||
|  | ||||
| namespace RL_LOG_,         LOG_ | ||||
| namespace RL_PIXELFORMAT_, PIXELFORMAT_ | ||||
| namespace RL_TEXTURE_,     TEXTURE_ | ||||
| namespace RL_SHADER_,      SHADER_ | ||||
| namespace RL_BLEND_,       BLEND_ | ||||
| namespace RL_ATTACHMENT_,  ATTACHMENT_ | ||||
| namespace RL_CULL_,        CULL_ | ||||
|  | ||||
| not include rlgl.h | ||||
|  | ||||
| word TRACELOG, RL_TRACELOG | ||||
|  | ||||
| word RLGL, GLOBAL_DATA | ||||
|  | ||||
| word Vector2,             Vector2 | ||||
| word Vector3,             Vector3 | ||||
| word Vector4,             Vector4 | ||||
| word Quaternion,          Quaternion | ||||
| word Matrix,              Matrix | ||||
| word Color,               Color | ||||
| word Rectangle,           Rectangle | ||||
| word Image,               Image | ||||
| word Texture,             Texture | ||||
| word Texture2D,           Texture2d | ||||
| word TextureCubemap,      Texture_Cubemap | ||||
| word RenderTexture,       Render_Texture | ||||
| word RenderTexture2D,     Render_Texture2D | ||||
| word NPatchInfo,          N_Patch_Info | ||||
| word GlyphInfo,           Glyph_Info | ||||
| word Font,                Font | ||||
| word Camera3D,            Camera3D | ||||
| word Camera,              Camera | ||||
| word Camera2D,            Camera2D | ||||
| word Mesh,                Mesh | ||||
| word Shader,              Shader | ||||
| word MaterialMap,         Material_Map | ||||
| word Material,            Material | ||||
| word Transform,           Transform | ||||
| word BoneInfo,            Bone_Info | ||||
| word Model,               Model | ||||
| word ModelAnimation,      Model_Animation | ||||
| word Ray,                 Ray | ||||
| word RayCollision,        Ray_Collision | ||||
| word BoundingBox,         Bounding_box | ||||
| word Wave,                Wave | ||||
| word rAudioBuffer,        Audio_Buffer | ||||
| word rAudioProcessor,     Audio_Processor | ||||
| word AudioStream,         Audio_Stream | ||||
| word Sound,               Sound | ||||
| word Music,               Music | ||||
| word VrDeviceInfo,        VR_Device_Info | ||||
| word VrStereoConfig,      VR_Stereo_Config | ||||
| word FilePathList,        File_Path_List | ||||
| word AutomationEvent,     Automation_Event | ||||
| word AutomationEventList, Automation_Event_List | ||||
| word Matrix,              Matrix | ||||
|  | ||||
| word rlVertexBuffer,                 vertex_buffer | ||||
| word rlDrawCall,                     draw_call | ||||
| word rlRenderBatch,                  render_batch | ||||
| word rlGlVersion,                    gl_version | ||||
| word rlTraceLogLevel,                trace_log_level | ||||
| word rlPixelFormat,                  pixel_format | ||||
| word rlTextureFilter,                texture_filter | ||||
| word rlShaderLocationIndex,          shader_location_index | ||||
| word rlShaderUniformDataType,        shader_uniform_data_type | ||||
| word rlShaderAttributeDataType,      shader_attribute_data_type | ||||
| word rlBlendMode,                    blend_mode | ||||
| word rlFramebufferAttachType,        framebuffer_attach_type | ||||
| word rlFramebufferAttachTextureType, framebuffer_attach_texture_type | ||||
| word rlCullMode,                     cull_mode | ||||
|  | ||||
| word get_pixel_data_size, gpu_get_pixel_data_size | ||||
|  | ||||
| word rlMatrixMode,                       matrix_mode | ||||
| word rlPushMatrix,                       push_matrix | ||||
| word rlPopMatrix,                        pop_matrix | ||||
| word rlLoadIdentity,                     load_identity | ||||
| word rlTranslatef,                       translatef | ||||
| word rlRotatef,                          rotatef | ||||
| word rlScalef,                           scalef | ||||
| word rlMultMatrixf,                      mult_matrixf | ||||
| word rlFrustum,                          frustum | ||||
| word rlOrtho,                            ortho | ||||
| word rlViewport,                         viewport | ||||
| word rlBegin,                            begin | ||||
| word rlEnd,                              end | ||||
| word rlVertex2i,                         vertex2i | ||||
| word rlVertex2f,                         vertex2f | ||||
| word rlVertex3f,                         vertex3f | ||||
| word rlTexCoord2f,                       tex_coord2f | ||||
| word rlNormal3f,                         normal3f | ||||
| word rlColor4ub,                         color4ub | ||||
| word rlColor3f,                          color3f | ||||
| word rlColor4f,                          color4f | ||||
| word rlEnableVertexArray,                enable_vertex_array | ||||
| word rlDisableVertexArray,               disable_vertex_array | ||||
| word rlEnableVertexBuffer,               enable_vertex_buffer | ||||
| word rlDisableVertexBuffer,              disable_vertex_buffer | ||||
| word rlEnableVertexBufferElement,        enable_vertex_buffer_element | ||||
| word rlDisableVertexBufferElement,       disable_vertex_buffer_element | ||||
| word rlEnableVertexAttribute,            enable_vertex_attribute | ||||
| word rlDisableVertexAttribute,           disable_vertex_attribute | ||||
| word rlEnableStatePointer,               enable_state_pointer | ||||
| word rlDisableStatePointer,              disable_state_pointer | ||||
| word rlActiveTextureSlot,                active_texture_slot | ||||
| word rlEnableTexture,                    enable_texture | ||||
| word rlDisableTexture,                   disable_texture | ||||
| word rlEnableTextureCubemap,             enable_texture_cubemap | ||||
| word rlDisableTextureCubemap,            disable_texture_cubemap | ||||
| word rlTextureParameters,                texture_parameters | ||||
| word rlCubemapParameters,                cubemap_parameters | ||||
| word rlEnableShader,                     enable_shader | ||||
| word rlDisableShader,                    disable_shader | ||||
| word rlEnableFramebuffer,                enable_framebuffer | ||||
| word rlDisableFramebuffer,               disable_framebuffer | ||||
| word rlActiveDrawBuffers,                active_draw_buffers | ||||
| word rlBlitFramebuffer,                  blit_framebuffer | ||||
| word rlEnableColorBlend,                 enable_color_blend | ||||
| word rlDisableColorBlend,                disable_color_blend | ||||
| word rlEnableDepthTest,                  enable_depth_test | ||||
| word rlDisableDepthTest,                 disable_depth_test | ||||
| word rlEnableDepthMask,                  enable_depth_mask | ||||
| word rlDisableDepthMask,                 disable_depth_mask | ||||
| word rlEnableBackfaceCulling,            enable_backface_culling | ||||
| word rlDisableBackfaceCulling,           disable_backface_culling | ||||
| word rlSetCullFace,                      set_cull_face | ||||
| word rlEnableScissorTest,                enable_scissor_test | ||||
| word rlDisableScissorTest,               disable_scissor_test | ||||
| word rlScissor,                          scissor | ||||
| word rlEnableWireMode,                   enable_wire_mode | ||||
| word rlEnablePointMode,                  enable_point_mode | ||||
| word rlDisableWireMode,                  disable_wire_mode | ||||
| word rlSetLineWidth,                     set_line_width | ||||
| word rlGetLineWidth,                     get_line_width | ||||
| word rlEnableSmoothLines,                enable_smooth_lines | ||||
| word rlDisableSmoothLines,               disable_smooth_lines | ||||
| word rlEnableStereoRender,               enable_stereo_render | ||||
| word rlDisableStereoRender,              disable_stereo_render | ||||
| word rlIsStereoRenderEnabled,            is_stereo_render_enabled | ||||
| word rlClearColor,                       clear_color | ||||
| word rlClearScreenBuffers,               clear_screen_buffers | ||||
| word rlCheckErrors,                      check_errors | ||||
| word rlSetBlendMode,                     set_blend_mode | ||||
| word rlSetBlendFactors,                  set_blend_factors | ||||
| word rlSetBlendFactorsSeparate,          set_blend_factors_separate | ||||
| word rlglInit,                           init | ||||
| word rlglClose,                          close | ||||
| word rlLoadExtensions,                   load_extensions | ||||
| word rlGetVersion,                       get_version | ||||
| word rlSetFramebufferWidth,              set_framebuffer_width | ||||
| word rlGetFramebufferWidth,              get_framebuffer_width | ||||
| word rlSetFramebufferHeight,             set_framebuffer_height | ||||
| word rlGetFramebufferHeight,             get_framebuffer_height | ||||
| word rlGetTextureIdDefault,              get_texture_id_default | ||||
| word rlGetShaderIdDefault,               get_shader_id_default | ||||
| word rlLoadRenderBatch,                  load_render_batch | ||||
| word rlUnloadRenderBatch,                unload_render_batch | ||||
| word rlDrawRenderBatch,                  draw_render_batch | ||||
| word rlSetRenderBatchActive,             set_render_batch_active | ||||
| word rlDrawRenderBatchActive,            draw_render_batch_active | ||||
| word rlCheckRenderBatchLimit,            check_render_batch_limit | ||||
| word rlSetTexture,                       set_texture | ||||
| word rlLoadVertexArray,                  load_vertex_array | ||||
| word rlLoadVertexBuffer,                 load_vertex_buffer | ||||
| word rlLoadVertexBufferElement,          load_vertex_buffer_element | ||||
| word rlUpdateVertexBuffer,               update_vertex_buffer | ||||
| word rlUpdateVertexBufferElements,       update_vertex_buffer_elements | ||||
| word rlUnloadVertexArray,                unload_vertex_array | ||||
| word rlUnloadVertexBuffer,               unload_vertex_buffer | ||||
| word rlSetVertexAttribute,               set_vertex_attribute | ||||
| word rlSetVertexAttributeDivisor,        set_vertex_attribute_divisor | ||||
| word rlSetVertexAttributeDefault,        set_vertex_attribute_default | ||||
| word rlDrawVertexArray,                  draw_vertex_array | ||||
| word rlDrawVertexArrayElements,          draw_vertex_array_elements | ||||
| word rlDrawVertexArrayInstanced,         draw_vertex_array_instanced | ||||
| word rlDrawVertexArrayElementsInstanced, draw_vertex_array_elements_instanced | ||||
| word rlLoadTexture,                      load_texture | ||||
| word rlLoadTextureDepth,                 load_texture_depth | ||||
| word rlLoadTextureCubemap,               load_texture_cubemap | ||||
| word rlUpdateTexture,                    update_texture | ||||
| word rlGetGlTextureFormats,              get_gl_texture_formats | ||||
| word rlUnloadTexture,                    unload_texture | ||||
| word rlGenTextureMipmaps,                gen_texture_mipmaps | ||||
| word rlLoadFramebuffer,                  load_framebuffer | ||||
| word rlFramebufferAttach,                framebuffer_attach | ||||
| word rlFramebufferComplete,              framebuffer_complete | ||||
| word rlUnloadFramebuffer,                unload_framebuffer | ||||
| word rlLoadShaderCode,                   load_shader_code | ||||
| word rlCompileShader,                    compile_shader | ||||
| word rlLoadShaderProgram,                load_shader_program | ||||
| word rlUnloadShaderProgram,              unload_shader_program | ||||
| word rlGetLocationUniform,               get_location_uniform | ||||
| word rlGetLocationAttrib,                get_location_attrib | ||||
| word rlSetUniform,                       set_uniform | ||||
| word rlSetUniformMatrix,                 set_uniform_matrix | ||||
| word rlSetUniformSampler,                set_uniform_sampler | ||||
| word rlSetShader,                        set_shader | ||||
| word rlLoadComputeShaderProgram,         load_compute_shader_program | ||||
| word rlComputeShaderDispatch,            compute_shader_dispatch | ||||
| word rlLoadShaderBuffer,                 load_shader_buffer | ||||
| word rlUnloadShaderBuffer,               unload_shader_buffer | ||||
| word rlUpdateShaderBuffer,               update_shader_buffer | ||||
| word rlBindShaderBuffer,                 bind_shader_buffer | ||||
| word rlReadShaderBuffer,                 read_shader_buffer | ||||
| word rlCopyShaderBuffer,                 copy_shader_buffer | ||||
| word rlGetShaderBufferSize,              get_shader_buffer_size | ||||
| word rlBindImageTexture,                 bind_image_texture | ||||
| word rlGetMatrixModelview,               get_matrix_modelview | ||||
| word rlGetMatrixProjection,              get_matrix_projection | ||||
| word rlGetMatrixTransform,               get_matrix_transform | ||||
| word rlGetMatrixProjectionStereo,        get_matrix_projection_stereo | ||||
| word rlGetMatrixViewOffsetStereo,        get_matrix_view_offset_stereo | ||||
| word rlSetMatrixProjection,              set_matrix_projection | ||||
| word rlSetMatrixModelview,               set_matrix_modelview | ||||
| word rlSetMatrixProjectionStereo,        set_matrix_projection_stereo | ||||
| word rlSetMatrixViewOffsetStereo,        set_matrix_view_offset_stereo | ||||
| word rlLoadDrawCube,                     load_draw_cube | ||||
| word rlLoadDrawQuad,                     load_draw_quad | ||||
| word rlLoadShaderDefault,                load_shader_default | ||||
| word rlUnloadShaderDefault,              unload_shader_default | ||||
| word rlGetPixelDataSize,                 internal_get_pixel_data_size | ||||
| word rlMatrixIdentity,                   internal_matrix_identity | ||||
| word rlMatrixMultiply,                   internal_matrix_multiply | ||||
| word rlCheckRenderBatchLimit,            check_render_batch_limit | ||||
| word rlLoadShaderDefault,                load_shader_default | ||||
| word rlSetMatrixProjection,              set_matrix_projection | ||||
| word rlUnloadFramebuffer,                unload_framebuffer | ||||
| word rlReadScreenPixels,                 read_screen_pixels | ||||
| word rlReadTexturePixels,                read_texture_pixels | ||||
| word rlGetShaderLocsDefault,             get_shader_locs_default | ||||
| word rlGetPixelFormatName,               get_pixel_format_name | ||||
| @@ -1,322 +0,0 @@ | ||||
| #define GEN_DEFINE_LIBRARY_CODE_CONSTANTS | ||||
| #define GEN_BENCHMARK | ||||
| #define GEN_ENFORCE_STRONG_CODE_TYPES | ||||
| // #define GEN_IMPLEMENTATION | ||||
| #include "gen.cpp" | ||||
| #include "gen.builder.cpp" | ||||
|  | ||||
|  | ||||
| constexpr char const* path_config_h    = "config.h"; | ||||
| constexpr char const* path_raylib_h    = "raylib.h"; | ||||
| constexpr char const* path_raymath_h   = "raymath.h"; | ||||
| constexpr char const* path_rcamera_h   = "rcamera.h"; | ||||
| constexpr char const* path_rcore_h     = "rcore.h"; | ||||
| constexpr char const* path_rgestures_h = "rgestures.h"; | ||||
| constexpr char const* path_rgl_h       = "rgl.h"; | ||||
| constexpr char const* path_rtext_h     = "rtext.h"; | ||||
|  | ||||
| constexpr char const* path_rcore_desktop_c = "rcore_desktop.c"; | ||||
|  | ||||
| constexpr char const* path_raudio_c    = "raudio.c"; | ||||
| constexpr char const* path_rcore_c     = "rcore.c"; | ||||
| constexpr char const* path_rglfw_c     = "rglfw.c"; | ||||
| constexpr char const* path_rmodels_c   = "rmodels.c"; | ||||
| constexpr char const* path_rtext_c     = "rtext.c"; | ||||
| constexpr char const* path_rtextures_c = "rtextures.c"; | ||||
| constexpr char const* path_rutils_c    = "rutils.c"; | ||||
|  | ||||
| using namespace gen; | ||||
|  | ||||
| StringCached upper_snake_to_mixed_snake(StringCached str) | ||||
| { | ||||
|     local_persist String scratch = String::make_reserve(GlobalAllocator, kilobytes(1)); | ||||
|     scratch.clear(); | ||||
|  | ||||
|     bool capitalizeNext = true; | ||||
|  | ||||
|     for (s32 index = 0; index < str.length(); ++index) | ||||
|     { | ||||
|         char c = str[index]; | ||||
|  | ||||
|         if (c == '_') | ||||
|         { | ||||
|             scratch.append(c); | ||||
|             capitalizeNext = true; | ||||
|         } | ||||
|         else if (capitalizeNext) | ||||
|         { | ||||
|             if (c >= 'a' && c <= 'z') | ||||
|             { | ||||
|                 scratch.append(c - 32); // Convert to uppercase | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 scratch.append(c); | ||||
|             } | ||||
|             capitalizeNext = false; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             if (c >= 'A' && c <= 'Z') | ||||
|             { | ||||
|                 scratch.append(c + 32); // Convert to lowercase | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 scratch.append(c); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     StringCached result = get_cached_string(scratch); | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| StringCached pascal_to_lower_snake(StringCached str) | ||||
| { | ||||
|     local_persist String scratch = String::make_reserve(GlobalAllocator, kilobytes(1)); | ||||
|     scratch.clear(); | ||||
|  | ||||
|     for (s32 index = 0; index < str.length(); ++index) | ||||
|     { | ||||
|         char c = str[index]; | ||||
|         char next = (index + 1 < str.length()) ? str[index + 1] : '\0'; // Ensure we don't go out of bounds | ||||
|  | ||||
|         // Whitelist check for "2D" and "3D" | ||||
|         if ((c == '2' || c == '3' | c == '4') && (next == 'D' || next == 'd')) | ||||
|         { | ||||
|             if (index > 0) // If it's not the start of the string, append an underscore | ||||
|             { | ||||
|                 char* prev = str.Data + index - 1; | ||||
|                 if (*prev != '_') // Avoid double underscores | ||||
|                 { | ||||
|                     scratch.append('_'); | ||||
|                 } | ||||
|             } | ||||
|             scratch.append(c); | ||||
|             scratch.append('d'); // Convert to lowercase | ||||
|             index++; // Skip the next character since we've already processed it | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         if (c >= 'A' && c <= 'Z') | ||||
|         { | ||||
|             char* prev = (index > 0) ? str.Data + index - 1 : nullptr; | ||||
|  | ||||
|             if ((index > 0 && prev && *prev >= 'a' && *prev <= 'z') ||  | ||||
|                 (prev && char_is_digit(*prev) && (next >= 'A' && next <= 'Z'))) | ||||
|             { | ||||
|                 scratch.append('_'); | ||||
|             } | ||||
|  | ||||
|             scratch.append(c + 32); | ||||
|         } | ||||
|         else if (char_is_digit(c) && (next >= 'A' && next <= 'Z')) // Check for a number followed by an uppercase letter | ||||
|         { | ||||
|             scratch.append(c); | ||||
|             scratch.append('_'); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             scratch.append(c); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     StringCached result = get_cached_string(scratch); | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| void refactor_define( CodeDefine& code ) | ||||
| { | ||||
| 	local_persist String name_scratch = String::make_reserve( GlobalAllocator, kilobytes(1) ); | ||||
|  | ||||
| 	if ( str_compare( elem->Name, txt("RL"), 2 ) == 0 || str_compare( elem->Name, txt("RAYLIB"), 6 ) == 0 ) | ||||
| 		continue; | ||||
|  | ||||
| 	name_scratch.append_fmt( "%RL_%S", elem->Name ); | ||||
| 	elem->Name = get_cached_string( name_scratch ); | ||||
| 	name_scratch.clear(); | ||||
| } | ||||
|  | ||||
| void refactor_enum( CodeEnum& code ) | ||||
| { | ||||
| 	for ( Code elem : code->Body ) | ||||
| 	{ | ||||
| 		if ( elem->Type == ECode::Untyped ) | ||||
| 		{ | ||||
| 			elem->Content = upper_snake_to_mixed_snake( elem->Content ); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void refactor_typename( CodeType& type ) | ||||
| { | ||||
| 	local_persist CodeType t_unsigned_char      = parse_type( code(unsigned char) ); | ||||
| 	local_persist CodeType t_unsigned_char_ptr  = parse_type( code(unsigned char*) ); | ||||
| 	local_persist CodeType t_unsigned_short_ptr	= parse_type( code(unsigned short*) ); | ||||
| 	local_persist CodeType t_int                = parse_type( code(int) ); | ||||
| 	local_persist CodeType t_int_ptr 		    = parse_type( code(int*) ); | ||||
| 	local_persist CodeType t_unsigned_int       = parse_type( code(unsigned int) ); | ||||
| 	local_persist CodeType t_float 	            = parse_type( code(float) ); | ||||
| 	local_persist CodeType t_float_ptr          = parse_type( code(float*) ); | ||||
|  | ||||
| 	local_persist CodeType t_f32_ptr = parse_type( code(f32*) ); | ||||
| 	local_persist CodeType t_u8_ptr  = parse_type( code(u8*) ); | ||||
| 	local_persist CodeType t_s32_ptr = parse_type( code(s32*) ); | ||||
|  | ||||
| 	String type_str = type.to_string(); | ||||
|  | ||||
| 	if ( str_compare( type_str, t_unsigned_char.to_string() ) == 0 ) | ||||
| 	{ | ||||
| 		type.ast = t_u8.ast; | ||||
| 	} | ||||
| 	if ( str_compare( type_str, t_unsigned_char_ptr.to_string() ) == 0 ) | ||||
| 	{ | ||||
| 		type.ast = t_u8_ptr.ast; | ||||
| 	} | ||||
| 	if ( str_compare( type_str, t_unsigned_short_ptr.to_string() ) == 0 ) | ||||
| 	{ | ||||
| 		type.ast = t_u8_ptr.ast; | ||||
| 	} | ||||
| 	if ( str_compare( type_str, t_int.to_string() ) == 0 ) | ||||
| 	{ | ||||
| 		type.ast = t_s32.ast; | ||||
| 	} | ||||
| 	if ( str_compare( type_str, t_int_ptr.to_string() ) == 0 ) | ||||
| 	{ | ||||
| 		type.ast = t_s32_ptr.ast; | ||||
| 	} | ||||
| 	if ( str_compare( type_str, t_unsigned_int.to_string() ) == 0 ) | ||||
| 	{ | ||||
| 		type.ast = t_u32.ast; | ||||
| 	} | ||||
| 	if ( str_compare( type_str, t_float.to_string() ) == 0 ) | ||||
| 	{ | ||||
| 		type.ast = t_f32.ast; | ||||
| 	} | ||||
| 	if ( str_compare( type_str, t_float_ptr.to_string() ) == 0 ) | ||||
| 	{ | ||||
| 		type.ast = t_f32_ptr.ast; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void refactor_fn( CodeFn& fn ) | ||||
| { | ||||
| 	StringCached original_name = fn->Name; | ||||
| 	fn->Name = pascal_to_lower_snake( fn->Name ); | ||||
|  | ||||
| 	log_fmt( "%S", "Proc ID: %S -> %S", original_name, fn->Name ); | ||||
|  | ||||
| 	for ( CodeParam param : fn->Params ) | ||||
| 	{ | ||||
| 		refactor_typename( param->ValueType ); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void refactor_struct( CodeStruct& code ) | ||||
| { | ||||
| 	for ( Code field : code->Body ) | ||||
| 	{ | ||||
| 		if ( field->Type == ECode::Variable ) | ||||
| 		{ | ||||
| 			CodeVar var = field.cast<CodeVar>(); | ||||
| 			refactor_typename( var->ValueType ); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void refactor_file( char const* path ) | ||||
| { | ||||
| 	FileContents contents = file_read_contents( GlobalAllocator, true, path ); | ||||
| 	CodeBody     code     = parse_global_body( { contents.size, rcast(char const*, contents.data) } ); | ||||
|  | ||||
| 	local_perist String name_scratch = String::make_reserve( GlobalAllocator, kilobytes(1) ); | ||||
|  | ||||
| 	// CodeBody includes | ||||
| 	// CodeBody nspace_body = def_body( ECode::Namespace ); | ||||
| 	CodeBody new_code = def_body( ECode::Global_Body ); | ||||
|  | ||||
| 	for ( Code elem : code ) | ||||
| 	{ | ||||
| 		if ( elem->Type == ECode::Preprocess_Define ) | ||||
| 		{ | ||||
| 			refactor_define( elem.cast<CodeDefine>() ); | ||||
| 		} | ||||
|  | ||||
| 		if ( elem->Type == ECode::Enum ) | ||||
| 		{ | ||||
| 			refactor_enum( elem.cast<CodeEnum>() ); | ||||
| 		} | ||||
|  | ||||
| 		if ( elem->Type == ECode::Typedef ) | ||||
| 		{ | ||||
| 			CodeTypedef td = elem.cast<CodeTypedef>(); | ||||
| 			if ( td->UnderlyingType->Type == ECode::Enum ) | ||||
| 			{ | ||||
| 				CodeEnum code = td->UnderlyingType.cast<CodeEnum>(); | ||||
| 				refactor_enum( code ); | ||||
| 			} | ||||
| 			if ( td->UnderlyingType->Type == ECode::Struct ) | ||||
| 			{ | ||||
| 				CodeStruct code = td->UnderlyingType.cast<CodeStruct>(); | ||||
| 				refactor_struct( code ); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if ( elem->Type == ECode::Struct ) | ||||
| 		{ | ||||
| 			refactor_struct( elem.cast<CodeStruct>() ); | ||||
| 		} | ||||
|  | ||||
| 		if ( elem->Type == ECode::Function || elem->Type == ECode::Function_Fwd ) | ||||
| 		{ | ||||
| 			refactor_fn( elem.cast<CodeFn>() ); | ||||
| 		} | ||||
|  | ||||
| 		if ( elem->Type == ECode::Extern_Linkage ) | ||||
| 		{ | ||||
| 			CodeBody body = elem.cast<CodeExtern>()->Body; | ||||
| 			for ( Code elem : body ) | ||||
| 			{ | ||||
| 				if ( elem->Type == ECode::Function || elem->Type == ECode::Function_Fwd ) | ||||
| 				{ | ||||
| 					refactor_fn( elem.cast<CodeFn>() ); | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			Code nspace = def_namespace( txt("raylib"), def_namespace_body( args(elem) ) ); | ||||
| 			elem = nspace; | ||||
| 		} | ||||
|  | ||||
| 		new_code.append( elem ); | ||||
| 	} | ||||
|  | ||||
| 	Builder builder = Builder::open( path ); | ||||
| 	builder.print( new_code ); | ||||
| 	builder.write(); | ||||
|  | ||||
| 	name_scratch.clear(); | ||||
| } | ||||
|  | ||||
| int gen_main() | ||||
| { | ||||
| 	gen::init(); | ||||
|  | ||||
| 	refactor_file( path_config_h ); | ||||
| 	refactor_file( path_raylib_h ); | ||||
| 	refactor_file( path_rcamera_h ); | ||||
| 	refactor_file( path_raymath_h ); | ||||
| 	refactor_file( path_rcore_h ); | ||||
| 	refactor_file( path_rgl_h ); | ||||
| 	refactor_file( path_rtext_h ); | ||||
|  | ||||
| 	refactor_file( path_rcore_desktop_c ); | ||||
| 	refactor_file( path_raudio_c ); | ||||
| 	refactor_file( path_rcore_c ); | ||||
| 	refactor_file( path_rglfw_c ); | ||||
| 	refactor_file( path_rmodels_c ); | ||||
| 	refactor_file( path_rtext_c ); | ||||
| 	refactor_file( path_rutils_c ); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
| @@ -1,10 +0,0 @@ | ||||
| # Vis AST | ||||
|  | ||||
| AST visualizer for gencpp | ||||
|  | ||||
| This is a early start to creating frontend tooling for c/c++ using gencpp as a core component.   | ||||
| I'll be exploring creating an AST explorer for this library with raylib as the graphical & general platform vendor for dependencies that go beyond the scope of gencpp. | ||||
|  | ||||
| For now I'll have its build script in this file, however it will heavily rely on gencpp's helper scripts. | ||||
|  | ||||
| Whatever sort of UX tooling I setup for this will be reused for the other tools I'll be creating for gencpp. | ||||
| @@ -1,256 +0,0 @@ | ||||
| Clear-Host | ||||
|  | ||||
| $path_root     = git rev-parse --show-toplevel | ||||
| $path_scripts  = Join-Path $path_root 'scripts' | ||||
|  | ||||
| $target_arch        = Join-Path $path_scripts 'helpers/target_arch.psm1' | ||||
| $devshell           = Join-Path $path_scripts 'helpers/devshell.ps1' | ||||
| $format_cpp	        = Join-Path $path_scripts 'helpers/format_cpp.psm1' | ||||
| $incremental_checks = Join-Path $path_scripts 'helpers/incremental_checks.ps1' | ||||
| $vendor_toolchain   = Join-Path $path_scripts 'helpers/vendor_toolchain.ps1' | ||||
|  | ||||
| $path_project  = Join-Path $path_root     'project' | ||||
| $path_aux      = Join-Path $path_project  'auxillary' | ||||
| $path_vis_root = Join-Path $path_aux      'vis_ast' | ||||
| $path_binaries = Join-Path $path_vis_root 'binaries' | ||||
|  | ||||
| $path_deps = Join-Path $path_vis_root 'dependencies' | ||||
| $path_temp = Join-Path $path_deps     'temp' | ||||
|  | ||||
| Import-Module $target_arch | ||||
| Import-Module $format_cpp | ||||
|  | ||||
| #region Arguments | ||||
| $vendor           = $null | ||||
| $optimize         = $null | ||||
| $debug 	          = $null | ||||
| $analysis	      = $false | ||||
| $dev              = $false | ||||
| $verbose          = $null | ||||
|  | ||||
| [array] $vendors = @( "clang", "msvc" ) | ||||
|  | ||||
| # This is a really lazy way of parsing the args, could use actual params down the line... | ||||
|  | ||||
| if ( $args ) { $args | ForEach-Object { | ||||
| switch ($_){ | ||||
|  { $_ -in $vendors }   { $vendor    = $_; break } | ||||
|  "optimize"            { $optimize  = $true } | ||||
|  "debug"               { $debug     = $true } | ||||
|  "analysis"            { $analysis  = $true } | ||||
|  "dev"                 { $dev       = $true } | ||||
|  "verbose"             { $verbose   = $true } | ||||
| } | ||||
| }} | ||||
| #endregion Argument | ||||
|  | ||||
| # Load up toolchain configuraion | ||||
| . $vendor_toolchain | ||||
| . $incremental_checks | ||||
|  | ||||
| # Clear out the current content first | ||||
| if ( test-path $path_temp) { | ||||
| 	remove-item $path_temp -Recurse | ||||
| } | ||||
| New-Item -ItemType Directory -Path $path_temp | ||||
|  | ||||
| if ( -not (Test-Path $path_binaries) ) { | ||||
| 	New-Item -ItemType Directory -Path $path_binaries | ||||
| } | ||||
|  | ||||
| function setup-raylib { | ||||
| 	$path_raylib     = join-path $path_deps   'raylib' | ||||
| 	$path_raylib_inc = join-path $path_raylib 'include' | ||||
| 	$path_raylib_lib = join-path $path_raylib 'lib' | ||||
| 	if ( test-path $path_raylib_inc ) { | ||||
| 		remove-item $path_raylib_inc -recurse | ||||
| 		remove-item $path_raylib_lib -recurse | ||||
| 	} | ||||
| 	new-item -path $path_raylib_inc -ItemType Directory | ||||
| 	new-item -path $path_raylib_lib -ItemType Directory | ||||
|  | ||||
| 	$url_raylib_zip  = 'https://github.com/Ed94/raylib_refactored/archive/refs/heads/refactor-support.zip' | ||||
| 	$path_raylib_zip = join-path $path_temp 'raylib.zip' | ||||
|  | ||||
| 	$path_raylib_master      = join-path $path_temp          'raylib_refactored-refactor-support' | ||||
| 	$path_raylib_src         = join-path $path_raylib_master 'src' | ||||
| 	$path_raylib_platforms   = join-path $path_raylib_src    'platforms' | ||||
| 	$path_raylib_glfw_inc    = join-path $path_raylib_src    'external/glfw/include' | ||||
| 	$path_raylib_gputex      = join-path $path_raylib_src    'external/rl_gputex.h' | ||||
|  | ||||
| 	if ( test-path $path_raylib_master ) { | ||||
| 		remove-item $path_raylib_master -Recurse | ||||
| 	} | ||||
| 	invoke-webrequest -uri $url_raylib_zip   -outfile $path_raylib_zip | ||||
| 	expand-archive    -path $path_raylib_zip -destinationpath $path_temp | ||||
|  | ||||
| 	write-host "Building raylib with $vendor" | ||||
|  | ||||
| 	$path_build = Join-Path $path_raylib 'build' | ||||
| 	if ( (Test-Path $path_build) -eq $false ) { | ||||
| 		New-Item $path_build -ItemType Directory | ||||
| 	} | ||||
|  | ||||
| 	$raylib_headers  = Get-ChildItem -Path $path_raylib_src -Filter '*.h' -File | ||||
| 	$raylib_modules  = get-childitem -path $path_raylib_src -filter '*.c' -file | ||||
|  | ||||
| 	# Refactor with refactor.exe | ||||
| 	if ( $true ) { | ||||
| 		$path_refactor      = join-path $path_raylib 'raylib_cpp.refactor' | ||||
| 		$path_refactor_rlgl = join-path $path_raylib 'raylib_cpp_gl.refactor' | ||||
|  | ||||
| 		$files = @() | ||||
| 		foreach ( $header in $raylib_headers ) { | ||||
| 			$file_name = split-path $header -leaf | ||||
|  | ||||
| 			if ( -not $file_name.Equals('rlgl.h' ) ) { | ||||
| 				$files += "$header" | ||||
| 			} | ||||
| 		} | ||||
| 		foreach ( $module in $raylib_modules ) { | ||||
| 			$files += "$module" | ||||
| 		} | ||||
|  | ||||
| 		$files += "$path_raylib_gputex" | ||||
|  | ||||
| 		$platform_modules = @() | ||||
| 		foreach ( $module in (get-childitem -path $path_raylib_platforms -filter '*.c' -file) ) { | ||||
| 			$platform_modules += "$module" | ||||
| 		} | ||||
|  | ||||
| 		$path_rlgl = join-path $path_raylib_src 'rlgl.h' | ||||
|  | ||||
| 		Push-Location $path_raylib_src | ||||
| 			write-host "Beginning refactor...`n" | ||||
| 			$refactors = @(@()) | ||||
| 			$refactorParams = @( | ||||
| 				# "-debug", | ||||
| 				"-num=$($files.Count)" | ||||
| 				"-src=$($files)", | ||||
| 				"-spec=$($path_refactor)" | ||||
| 			) | ||||
| 			& refactor $refactorParams | ||||
| 			Write-Host "`nRefactoring complete`n`n" | ||||
| 		Pop-Location | ||||
|  | ||||
| 		Push-Location $path_raylib_platforms | ||||
| 		write-host "Beginning refactor...`n" | ||||
| 			$refactors = @(@()) | ||||
| 			$refactorParams = @( | ||||
| 				# "-debug", | ||||
| 				"-num=$($platform_modules.Count)" | ||||
| 				"-src=$($platform_modules)", | ||||
| 				"-spec=$($path_refactor)" | ||||
| 			) | ||||
| 			& refactor $refactorParams | ||||
| 			Write-Host "`nRefactoring complete`n`n" | ||||
| 		Pop-Location | ||||
|  | ||||
| 		Push-Location $path_raylib_src | ||||
| 			$gl_modules = @( "$path_rlgl", "$path_raylib_gputex" ) | ||||
|  | ||||
| 			write-host "Beginning refactor just for rlgl.h...`n" | ||||
| 			$refactors = @(@()) | ||||
| 			$refactorParams = @( | ||||
| 				# "-debug", | ||||
| 				"-num=$($gl_modules.Count)" | ||||
| 				"-src=$($gl_modules)", | ||||
| 				"-spec=$($path_refactor_rlgl)" | ||||
| 			) | ||||
| 			& refactor $refactorParams | ||||
| 			Write-Host "`nRefactoring complete`n`n" | ||||
| 		Pop-Location | ||||
| 	} | ||||
|  | ||||
| 	# Refactor raylib with gencpp | ||||
| 	if ( $false ) { | ||||
| 	# if ( $false ) { | ||||
| 		$path_gencpp = join-path $path_root 'project/gen' | ||||
|  | ||||
| 		$includes = @( | ||||
| 			$path_gencpp | ||||
| 		) | ||||
|  | ||||
| 		$compiler_args = @( | ||||
| 			($flag_define + 'GEN_TIME') | ||||
| 		) | ||||
|  | ||||
| 		$linker_args = @( | ||||
|  | ||||
| 		) | ||||
|  | ||||
| 		$unit       = join-path $path_raylib 'raylib_refactor.cpp' | ||||
| 		$executable = join-path $path_build  'raylib_refactor.exe' | ||||
|  | ||||
| 		$build_result = build-simple $path_build $includes $compiler_args $linker_args $unit $executable | ||||
| 		Push-Location $path_raylib_src | ||||
| 			if ( Test-Path( $executable ) ) { | ||||
| 				Measure-Command { & $executable | ||||
| 						| ForEach-Object { | ||||
| 							write-host `t $_ -ForegroundColor Green | ||||
| 						} | ||||
| 					} | ||||
| 			} | ||||
| 		Pop-Location | ||||
|  | ||||
| 		push-location $path_scripts | ||||
| 		# Time to format | ||||
| 		$fmt_includes = @() | ||||
| 		foreach ( $header in $raylib_headers ) { | ||||
| 			$fmt_includes +=  split-path $header -leaf | ||||
| 		} | ||||
| 		foreach ( $module in $raylib_modules ) { | ||||
| 			$fmt_includes +=  split-path $module -leaf | ||||
| 		} | ||||
| 		format-cpp $path_raylib_src $fmt_includes $null | ||||
| 		pop-location | ||||
| 	} | ||||
|  | ||||
| 	# Build raylib | ||||
| 	if ( $true ) { | ||||
| 		# Microsoft | ||||
| 		$lib_gdi32   = 'Gdi32.lib' | ||||
| 		$lib_shell32 = 'Shell32.lib' | ||||
| 		$lib_xinput  = 'Xinput.lib' | ||||
| 		$lib_user32  = 'User32.lib' | ||||
| 		$lib_winmm   = 'Winmm.lib' | ||||
|  | ||||
| 		$includes = @( | ||||
| 			$path_raylib_src, | ||||
| 			$path_raylib_glfw_inc | ||||
| 		) | ||||
| 		foreach ($include in $includes) { | ||||
| 			write-host $include | ||||
| 		} | ||||
|  | ||||
| 		$compiler_args = @( | ||||
| 			($flag_define + 'PLATFORM_DESKTOP'), | ||||
| 			($flag_define + 'RL_BUILD_LIBTYPE_SHARED'), | ||||
| 			$flag_all_cpp | ||||
| 		) | ||||
| 		$linker_args   = @( | ||||
| 			$flag_link_dll, | ||||
|  | ||||
| 			# $lib_xinput, | ||||
| 			$lib_gdi32, | ||||
| 			$lib_shell32, | ||||
| 			$lib_user32, | ||||
| 			$lib_winmm | ||||
| 		) | ||||
|  | ||||
| 		# $unit = join-path $path_raylib     'raylib.c' | ||||
| 		$dll  = join-path $path_raylib_lib 'raylib.dll' | ||||
| 		# $build_result = build-simple $path_build $includes $compiler_args $linker_args $unit $dll | ||||
|  | ||||
| 		$build_result = build $path_build $includes $compiler_args $linker_args $raylib_modules $dll | ||||
| 	} | ||||
|  | ||||
| 	# Move headers to used include | ||||
| 	foreach ($header in $raylib_headers) { | ||||
| 		Copy-Item -Path $header -Destination (join-path $path_raylib_inc (split-path $header -Leaf)) | ||||
| 	} | ||||
|  | ||||
| 	# Don't want to remove as it hampers debugging. | ||||
| 	# remove-item -path $path_temp -Recurse | ||||
| } | ||||
| setup-raylib | ||||
| @@ -1,13 +1,17 @@ | ||||
| #define GEN_DEFINE_LIBRARY_CODE_CONSTANTS | ||||
| #define GEN_ENFORCE_STRONG_CODE_TYPES | ||||
| #define GEN_EXPOSE_BACKEND | ||||
| #define GEN_SUPPORT_CPP_MEMBER_FEATURES 0 | ||||
| #define GEN_SUPPORT_CPP_REFERENCES      0 | ||||
| #include "gen.cpp" | ||||
|  | ||||
| #include "helpers/push_ignores.inline.hpp" | ||||
| #include "helpers/helper.hpp" | ||||
|  | ||||
| GEN_NS_BEGIN | ||||
| #include "helpers/push_container_defines.inline.hpp" | ||||
| #include "dependencies/parsing.cpp" | ||||
| #include "helpers/pop_container_defines.inline.hpp" | ||||
| GEN_NS_END | ||||
|  | ||||
| #include "auxillary/builder.hpp" | ||||
| @@ -20,16 +24,56 @@ constexpr char const* generation_notice = | ||||
| "// This file was generated automatially by gencpp's bootstrap.cpp " | ||||
| "(See: https://github.com/Ed94/gencpp)\n\n"; | ||||
|  | ||||
| #include <cstdlib>   // for system() | ||||
|  | ||||
| void format_file( char const* path ) | ||||
| { | ||||
| 	String resolved_path = string_make_strc(GlobalAllocator, to_strc_from_c_str(path)); | ||||
|  | ||||
| 	String style_arg = string_make_strc(GlobalAllocator, txt("-style=file:")); | ||||
| 	string_append_strc( & style_arg, txt("../scripts/.clang-format ")); | ||||
|  | ||||
| 	// Need to execute clang format on the generated file to get it to match the original. | ||||
| 	#define clang_format      txt("clang-format ") | ||||
| 	#define cf_format_inplace txt("-i ") | ||||
| 	#define cf_verbose        txt("-verbose ") | ||||
| 	String command = string_make_strc( GlobalAllocator, clang_format ); | ||||
| 	string_append_strc( & command, cf_format_inplace ); | ||||
| 	string_append_strc( & command, cf_verbose ); | ||||
| 	string_append_string( & command, style_arg ); | ||||
| 	string_append_string( & command, 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; | ||||
| } | ||||
|  | ||||
| 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" ); | ||||
|  | ||||
| 	// gen_dep.hpp | ||||
| 	{ | ||||
| 		Code header_start = scan_file( "dependencies/header_start.hpp" ); | ||||
| 		Code platform     = scan_file( "dependencies/platform.hpp" ); | ||||
| 		Code macros 	  = scan_file( "dependencies/macros.hpp" ); | ||||
| 		Code basic_types  = scan_file( "dependencies/basic_types.hpp" ); | ||||
| 		Code debug        = scan_file( "dependencies/debug.hpp" ); | ||||
| @@ -45,8 +89,8 @@ int gen_main() | ||||
| 		Builder | ||||
| 		header = Builder::open("gen/gen.dep.hpp"); | ||||
| 		header.print_fmt( generation_notice ); | ||||
| 		header.print_fmt( "// This file is intended to be included within gen.hpp (There is no pragma diagnostic ignores)\n\n" ); | ||||
| 		header.print( header_start ); | ||||
| 		header.print_fmt( "// This file is intended to be included within gen.hpp (There is no pragma diagnostic ignores)\n" ); | ||||
| 		header.print( platform ); | ||||
| 		header.print_fmt( "\nGEN_NS_BEGIN\n" ); | ||||
|  | ||||
| 		header.print( macros ); | ||||
| @@ -80,7 +124,7 @@ int gen_main() | ||||
| 		Builder | ||||
| 		src = Builder::open( "gen/gen.dep.cpp" ); | ||||
| 		src.print_fmt( generation_notice ); | ||||
| 		src.print_fmt( "// This file is intended to be included within gen.cpp (There is no pragma diagnostic ignores)\n\n" ); | ||||
| 		src.print_fmt( "// This file is intended to be included within gen.cpp (There is no pragma diagnostic ignores)\n" ); | ||||
| 		src.print( src_start ); | ||||
| 		src.print_fmt( "\nGEN_NS_BEGIN\n" ); | ||||
|  | ||||
| @@ -103,7 +147,7 @@ int gen_main() | ||||
| 		def_include(txt("components/types.hpp")), | ||||
| 		preprocess_endif, | ||||
| 		fmt_newline, | ||||
| 		untyped_str( to_str(generation_notice) ) | ||||
| 		untyped_str( to_strc_from_c_str(generation_notice) ) | ||||
| 	)); | ||||
|  | ||||
| 	// gen.hpp | ||||
| @@ -132,9 +176,13 @@ int gen_main() | ||||
|  | ||||
| 		header.print_fmt( "#pragma region Types\n" ); | ||||
| 		header.print( types ); | ||||
| 		header.print( ecode ); | ||||
| 		header.print( eoperator ); | ||||
| 		header.print( especifier ); | ||||
| 		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" ); | ||||
|  | ||||
| 		header.print_fmt( "#pragma region AST\n" ); | ||||
| @@ -148,7 +196,8 @@ int gen_main() | ||||
| 		header.print_fmt( "\n#pragma region Inlines\n" ); | ||||
| 		header.print( inlines ); | ||||
| 		header.print( fmt_newline ); | ||||
| 		header.print( ast_inlines ); | ||||
| 		header.print( dump_to_scratch_and_retireve(ast_inlines) ); | ||||
| 		header.print( fmt_newline ); | ||||
| 		header.print_fmt( "#pragma endregion Inlines\n" ); | ||||
|  | ||||
| 		header.print( header_end ); | ||||
| @@ -196,14 +245,19 @@ int gen_main() | ||||
| 		Code        untyped 	       = scan_file( "components/interface.untyped.cpp" ); | ||||
|  | ||||
| 		CodeBody etoktype         = gen_etoktype( "enums/ETokType.csv", "enums/AttributeTokens.csv" ); | ||||
| 		CodeNS   nspaced_etoktype = def_namespace( name(parser), def_namespace_body( args(etoktype)) ); | ||||
| 		//CodeNS   nspaced_etoktype = def_namespace( name(parser), def_namespace_body( args(etoktype)) ); | ||||
| 		CodeBody nspaced_etoktype = def_global_body( args( | ||||
| 			untyped_str(txt("GEN_NS_PARSER_BEGIN\n")), | ||||
| 			etoktype, | ||||
| 			untyped_str(txt("GEN_NS_PARSER_END\n")) | ||||
| 		)); | ||||
|  | ||||
| 		Builder | ||||
| 		src = Builder::open( "gen/gen.cpp" ); | ||||
| 		src.print_fmt( generation_notice ); | ||||
| 		src.print( push_ignores ); | ||||
| 		src.print( src_start ); | ||||
| 		src.print_fmt( "GEN_NS_BEGIN\n"); | ||||
| 		src.print_fmt( "\nGEN_NS_BEGIN\n"); | ||||
|  | ||||
| 		src.print( static_data ); | ||||
|  | ||||
| @@ -217,7 +271,7 @@ int gen_main() | ||||
| 		src.print( interface ); | ||||
| 		src.print( upfront ); | ||||
| 		src.print_fmt( "\n#pragma region Parsing\n\n" ); | ||||
| 		src.print( nspaced_etoktype ); | ||||
| 		src.print( dump_to_scratch_and_retireve(nspaced_etoktype) ); | ||||
| 		src.print( lexer ); | ||||
| 		src.print( parser ); | ||||
| 		src.print( parsing_interface ); | ||||
| @@ -278,7 +332,7 @@ int gen_main() | ||||
| 		header.print_fmt( "\nGEN_NS_BEGIN\n" ); | ||||
| 		header.print( parsing ); | ||||
| 		header.print( scanner ); | ||||
| 		header.print_fmt( "GEN_NS_END\n" ); | ||||
| 		header.print_fmt( "\nGEN_NS_END\n" ); | ||||
| 		header.write(); | ||||
| 	} | ||||
|  | ||||
| @@ -293,7 +347,7 @@ int gen_main() | ||||
| 		src.print( def_include( txt("gen.scanner.hpp") ) ); | ||||
| 		src.print_fmt( "\nGEN_NS_BEGIN\n" ); | ||||
| 		src.print( parsing ); | ||||
| 		src.print( scanner ); | ||||
| 		// src.print( scanner ); | ||||
| 		src.print_fmt( "GEN_NS_END\n" ); | ||||
| 		src.write(); | ||||
| 	} | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -67,85 +67,116 @@ struct AST_Stmt_While; | ||||
|  | ||||
| struct AST_Struct; | ||||
| struct AST_Template; | ||||
| struct AST_Type; | ||||
| struct AST_Typename; | ||||
| struct AST_Typedef; | ||||
| struct AST_Union; | ||||
| struct AST_Using; | ||||
| struct AST_Var; | ||||
|  | ||||
| struct Code; | ||||
| struct CodeBody; | ||||
| // These are to offer ease of use and optionally strong type safety for the AST. | ||||
| struct CodeAttributes; | ||||
| // struct CodeBaseClass; | ||||
| struct CodeComment; | ||||
| struct CodeClass; | ||||
| struct CodeConstructor; | ||||
| struct CodeDefine; | ||||
| struct CodeDestructor; | ||||
| struct CodeEnum; | ||||
| struct CodeExec; | ||||
| struct CodeExtern; | ||||
| struct CodeInclude; | ||||
| struct CodeFriend; | ||||
| struct CodeFn; | ||||
| struct CodeModule; | ||||
| struct CodeNS; | ||||
| struct CodeOperator; | ||||
| struct CodeOpCast; | ||||
| struct CodeParam; | ||||
| struct CodePreprocessCond; | ||||
| struct CodePragma; | ||||
| struct CodeSpecifiers; | ||||
|  | ||||
| #if GEN_EXECUTION_EXPRESSION_SUPPORT | ||||
| struct CodeExpr; | ||||
| struct CodeExpr_Assign; | ||||
| struct CodeExpr_Alignof; | ||||
| struct CodeExpr_Binary; | ||||
| struct CodeExpr_CStyleCast; | ||||
| struct CodeExpr_FunctionalCast; | ||||
| struct CodeExpr_CppCast; | ||||
| struct CodeExpr_Element; | ||||
| struct CodeExpr_ProcCall; | ||||
| struct CodeExpr_Decltype; | ||||
| struct CodeExpr_Comma; | ||||
| struct CodeExpr_AMS; // Access Member Symbol | ||||
| struct CodeExpr_Sizeof; | ||||
| struct CodeExpr_Subscript; | ||||
| struct CodeExpr_Ternary; | ||||
| struct CodeExpr_UnaryPrefix; | ||||
| struct CodeExpr_UnaryPostfix; | ||||
|  | ||||
| struct CodeStmt; | ||||
| struct CodeStmt_Break; | ||||
| struct CodeStmt_Case; | ||||
| struct CodeStmt_Continue; | ||||
| struct CodeStmt_Decl; | ||||
| struct CodeStmt_Do; | ||||
| struct CodeStmt_Expr; | ||||
| struct CodeStmt_Else; | ||||
| struct CodeStmt_If; | ||||
| struct CodeStmt_For; | ||||
| struct CodeStmt_Goto; | ||||
| struct CodeStmt_Label; | ||||
| struct CodeStmt_Switch; | ||||
| struct CodeStmt_While; | ||||
| #if GEN_COMPILER_C | ||||
| #define Define_Code(Type) typedef AST_##Type* Code##Type | ||||
| #else | ||||
| #define Define_Code(Type) struct Code##Type | ||||
| #endif | ||||
|  | ||||
| struct CodeStruct; | ||||
| struct CodeTemplate; | ||||
| struct CodeType; | ||||
| struct CodeTypedef; | ||||
| struct CodeUnion; | ||||
| struct CodeUsing; | ||||
| struct CodeVar; | ||||
| #if GEN_COMPILER_C | ||||
| typedef AST* code; | ||||
| #else | ||||
| struct Code; | ||||
| #endif | ||||
| Define_Code(Body); | ||||
| // These are to offer ease of use and optionally strong type safety for the AST. | ||||
| Define_Code(Attributes); | ||||
| // struct CodeBaseClass; | ||||
| Define_Code(Comment); | ||||
| Define_Code(Class); | ||||
| Define_Code(Constructor); | ||||
| Define_Code(Define); | ||||
| Define_Code(Destructor); | ||||
| Define_Code(Enum); | ||||
| Define_Code(Exec); | ||||
| Define_Code(Extern); | ||||
| Define_Code(Include); | ||||
| Define_Code(Friend); | ||||
| Define_Code(Fn); | ||||
| Define_Code(Module); | ||||
| Define_Code(NS); | ||||
| Define_Code(Operator); | ||||
| Define_Code(OpCast); | ||||
| Define_Code(Param); | ||||
| Define_Code(PreprocessCond); | ||||
| Define_Code(Pragma); | ||||
| Define_Code(Specifiers); | ||||
|  | ||||
| namespace parser | ||||
| { | ||||
| #if GEN_EXECUTION_EXPRESSION_SUPPORT | ||||
| Define_Code(Expr); | ||||
| Define_Code(Expr_Assign); | ||||
| Define_Code(Expr_Alignof); | ||||
| Define_Code(Expr_Binary); | ||||
| Define_Code(Expr_CStyleCast); | ||||
| Define_Code(Expr_FunctionalCast); | ||||
| Define_Code(Expr_CppCast); | ||||
| Define_Code(Expr_Element); | ||||
| Define_Code(Expr_ProcCall); | ||||
| Define_Code(Expr_Decltype); | ||||
| Define_Code(Expr_Comma); | ||||
| Define_Code(Expr_AMS); // Access Member Symbol | ||||
| Define_Code(Expr_Sizeof); | ||||
| Define_Code(Expr_Subscript); | ||||
| Define_Code(Expr_Ternary); | ||||
| Define_Code(Expr_UnaryPrefix); | ||||
| Define_Code(Expr_UnaryPostfix); | ||||
|  | ||||
| Define_Code(Stmt); | ||||
| Define_Code(Stmt_Break); | ||||
| Define_Code(Stmt_Case); | ||||
| Define_Code(Stmt_Continue); | ||||
| Define_Code(Stmt_Decl); | ||||
| Define_Code(Stmt_Do); | ||||
| Define_Code(Stmt_Expr); | ||||
| Define_Code(Stmt_Else); | ||||
| Define_Code(Stmt_If); | ||||
| Define_Code(Stmt_For); | ||||
| Define_Code(Stmt_Goto); | ||||
| Define_Code(Stmt_Label); | ||||
| Define_Code(Stmt_Switch); | ||||
| Define_Code(Stmt_While); | ||||
| #endif | ||||
|  | ||||
| Define_Code(Struct); | ||||
| Define_Code(Template); | ||||
| Define_Code(Typename); | ||||
| Define_Code(Typedef); | ||||
| Define_Code(Union); | ||||
| Define_Code(Using); | ||||
| Define_Code(Var); | ||||
| #undef Define_Code | ||||
|  | ||||
| GEN_NS_PARSER_BEGIN | ||||
| struct Token; | ||||
| } | ||||
| GEN_NS_PARSER_END | ||||
|  | ||||
| #if ! GEN_COMPILER_C | ||||
| template< class Type> forceinline Type tmpl_cast( Code self ) { return * rcast( Type*, & self ); } | ||||
| #endif | ||||
|  | ||||
| #pragma region Code Interface | ||||
| void        append       (Code code, Code other ); | ||||
| char const* debug_str    (Code code); | ||||
| Code        duplicate    (Code code); | ||||
| Code*       entry        (Code code, u32 idx ); | ||||
| bool        has_entries  (Code code); | ||||
| bool        is_body      (Code code); | ||||
| bool        is_equal     (Code code, Code other); | ||||
| bool        is_valid     (Code code); | ||||
| void        set_global   (Code code); | ||||
| String      to_string    (Code self ); | ||||
| void        to_string    (Code self, String* result ); | ||||
| char const* type_str     (Code self ); | ||||
| bool        validate_body(Code self ); | ||||
| #pragma endregion Code Interface | ||||
|  | ||||
| #if ! GEN_COMPILER_C | ||||
| /* | ||||
| 	AST* wrapper | ||||
| 	- Not constantly have to append the '*' as this is written often.. | ||||
| @@ -153,39 +184,36 @@ 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();              \ | ||||
| 	String      to_string();               \ | ||||
| 	Typename&   operator = ( AST* other ); \ | ||||
| 	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); } | ||||
|  | ||||
| #	define Using_CodeOps( Typename )                                         \ | ||||
| 	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(); | ||||
|  | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| 	Using_Code( Code ); | ||||
| 	void        append(Code other)        { return GEN_NS append(* this, other); } | ||||
| 	Code*       entry(u32 idx)            { return GEN_NS entry(* this, idx); } | ||||
| 	bool        has_entries()             { return GEN_NS has_entries(* this); } | ||||
| 	String      to_string()               { return GEN_NS to_string(* this); } | ||||
| 	void        to_string(String& result) { return GEN_NS to_string(* this, & result); } | ||||
| 	char const* type_str()                { return GEN_NS type_str(* this); } | ||||
| 	bool        validate_body()           { return GEN_NS validate_body(*this); } | ||||
| #endif | ||||
|  | ||||
| 	template< class Type > | ||||
| 	forceinline Type cast() | ||||
| 	{ | ||||
| 		return * rcast( Type*, this ); | ||||
| 	} | ||||
| 	Using_CodeOps( Code ); | ||||
|  | ||||
| 	AST* operator ->() | ||||
| 	{ | ||||
| 		return ast; | ||||
| 	} | ||||
| 	AST* operator ->() { return ast; } | ||||
| 	Code& operator ++(); | ||||
|  | ||||
| 	// TODO(Ed) : Remove this overload. | ||||
| @@ -200,7 +228,10 @@ struct Code | ||||
| 		return *this; | ||||
| 	} | ||||
|  | ||||
| 	AST* ast; | ||||
| 	       bool operator==(std::nullptr_t) const            { return ast == nullptr; } | ||||
| 	       bool operator!=(std::nullptr_t) const            { return ast != nullptr; } | ||||
| 	friend bool operator==(std::nullptr_t, const Code code) { return code.ast == nullptr; } | ||||
| 	friend bool operator!=(std::nullptr_t, const Code code) { return code.ast != nullptr; } | ||||
|  | ||||
| #ifdef GEN_ENFORCE_STRONG_CODE_TYPES | ||||
| #	define operator explicit operator | ||||
| @@ -229,228 +260,122 @@ struct Code | ||||
| 	operator CodeSpecifiers() const; | ||||
| 	operator CodeStruct() const; | ||||
| 	operator CodeTemplate() const; | ||||
| 	operator CodeType() const; | ||||
| 	operator CodeTypename() const; | ||||
| 	operator CodeTypedef() const; | ||||
| 	operator CodeUnion() const; | ||||
| 	operator CodeUsing() const; | ||||
| 	operator CodeVar() const; | ||||
| 	#undef operator | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| #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; | ||||
| }; | ||||
|  | ||||
| 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; | ||||
|  | ||||
| /* | ||||
| 	Simple AST POD with functionality to seralize into C++ syntax. | ||||
| */ | ||||
| struct AST | ||||
| { | ||||
| #	pragma region Member Functions | ||||
| 	void        append     ( AST* other ); | ||||
| 	char const* debug_str  (); | ||||
| 	AST*        duplicate  (); | ||||
| 	Code&       entry      ( u32 idx ); | ||||
| 	bool        has_entries(); | ||||
| 	bool        is_equal   ( AST* other ); | ||||
| 	char const* type_str(); | ||||
| 	bool        validate_body(); | ||||
|  | ||||
| 	String to_string(); | ||||
|  | ||||
| 	neverinline | ||||
| 	void to_string( String& result ); | ||||
|  | ||||
| 	template< class Type > | ||||
| 	forceinline Type cast() | ||||
| 	{ | ||||
| 		return * this; | ||||
| 	} | ||||
|  | ||||
| 	operator Code(); | ||||
| 	operator CodeBody(); | ||||
| 	operator CodeAttributes(); | ||||
| 	// operator CodeBaseClass(); | ||||
| 	operator CodeComment(); | ||||
| 	operator CodeConstructor(); | ||||
| 	operator CodeDestructor(); | ||||
| 	operator CodeClass(); | ||||
| 	operator CodeDefine(); | ||||
| 	operator CodeEnum(); | ||||
| 	operator CodeExec(); | ||||
| 	operator CodeExtern(); | ||||
| 	operator CodeInclude(); | ||||
| 	operator CodeFriend(); | ||||
| 	operator CodeFn(); | ||||
| 	operator CodeModule(); | ||||
| 	operator CodeNS(); | ||||
| 	operator CodeOperator(); | ||||
| 	operator CodeOpCast(); | ||||
| 	operator CodeParam(); | ||||
| 	operator CodePragma(); | ||||
| 	operator CodePreprocessCond(); | ||||
| 	operator CodeSpecifiers(); | ||||
| 	operator CodeStruct(); | ||||
| 	operator CodeTemplate(); | ||||
| 	operator CodeType(); | ||||
| 	operator CodeTypedef(); | ||||
| 	operator CodeUnion(); | ||||
| 	operator CodeUsing(); | ||||
| 	operator CodeVar(); | ||||
| #	pragma endregion Member Functions | ||||
|  | ||||
| constexpr static | ||||
| 	int ArrSpecs_Cap = | ||||
| int AST_ArrSpecs_Cap = | ||||
| ( | ||||
| 		AST_POD_Size | ||||
| 		- sizeof(AST*) * 3 | ||||
| 		- sizeof(parser::Token*) | ||||
| 		- sizeof(AST*) | ||||
| 		- sizeof(StringCached) | ||||
| 			- sizeof(CodeT) | ||||
| 		- sizeof(CodeType) | ||||
| 		- sizeof(ModuleFlag) | ||||
| 		- sizeof(int) | ||||
| ) | ||||
| / sizeof(int) - 1; // -1 for 4 extra bytes | ||||
|  | ||||
| /* | ||||
| 	Simple AST POD with functionality to seralize into C++ syntax. | ||||
| */ | ||||
| struct AST | ||||
| { | ||||
| 	union { | ||||
| 		struct | ||||
| 		{ | ||||
| 			AST*      InlineCmt;       // Class, Constructor, Destructor, Enum, Friend, Functon, Operator, OpCast, Struct, Typedef, Using, Variable | ||||
| 			AST*      Attributes;      // Class, Enum, Function, Struct, Typedef, Union, Using, Variable | ||||
| 			AST*      Specs;           // Destructor, Function, Operator, Typename, Variable | ||||
| 			Code      InlineCmt;       // Class, Constructor, Destructor, Enum, Friend, Functon, Operator, OpCast, Struct, Typedef, Using, Variable | ||||
| 			Code      Attributes;      // Class, Enum, Function, Struct, Typedef, Union, Using, Variable | ||||
| 			Code      Specs;           // Destructor, Function, Operator, Typename, Variable | ||||
| 			union { | ||||
| 				AST*  InitializerList; // Constructor | ||||
| 				AST*  ParentType;      // Class, Struct, ParentType->Next has a possible list of interfaces. | ||||
| 				AST*  ReturnType;      // Function, Operator, Typename | ||||
| 				AST*  UnderlyingType;  // Enum, Typedef | ||||
| 				AST*  ValueType;       // Parameter, Variable | ||||
| 				Code  InitializerList; // Constructor | ||||
| 				Code  ParentType;      // Class, Struct, ParentType->Next has a possible list of interfaces. | ||||
| 				Code  ReturnType;      // Function, Operator, Typename | ||||
| 				Code  UnderlyingType;  // Enum, Typedef | ||||
| 				Code  ValueType;       // Parameter, Variable | ||||
| 			}; | ||||
| 			union { | ||||
| 				AST*  Macro;           // Parameter | ||||
| 				AST*  BitfieldSize;    // Variable (Class/Struct Data Member) | ||||
| 				AST*  Params;          // Constructor, Function, Operator, Template, Typename | ||||
| 				Code  Macro;           // Parameter | ||||
| 				Code  BitfieldSize;    // Variable (Class/Struct Data Member) | ||||
| 				Code  Params;          // Constructor, Function, Operator, Template, Typename | ||||
| 			}; | ||||
| 			union { | ||||
| 				AST*  ArrExpr;          // Typename | ||||
| 				AST*  Body;             // Class, Constructr, Destructor, Enum, Friend, Function, Namespace, Struct, Union | ||||
| 				AST*  Declaration;      // Friend, Template | ||||
| 				AST*  Value;            // Parameter, Variable | ||||
| 				Code  ArrExpr;          // Typename | ||||
| 				Code  Body;             // Class, Constructor, Destructor, Enum, Friend, Function, Namespace, Struct, Union | ||||
| 				Code  Declaration;      // Friend, Template | ||||
| 				Code  Value;            // Parameter, Variable | ||||
| 			}; | ||||
| 			union { | ||||
| 				AST*  NextVar;          // Variable; Possible way to handle comma separated variables declarations. ( , NextVar->Specs NextVar->Name NextVar->ArrExpr = NextVar->Value ) | ||||
| 				AST*  SuffixSpecs;      // Only used with typenames, to store the function suffix if typename is function signature. ( May not be needed ) | ||||
| 				Code  NextVar;          // Variable; Possible way to handle comma separated variables declarations. ( , NextVar->Specs NextVar->Name NextVar->ArrExpr = NextVar->Value ) | ||||
| 				Code  SuffixSpecs;      // Only used with typenames, to store the function suffix if typename is function signature. ( May not be needed ) | ||||
| 				Code  PostNameMacro;     // Only used with parameters for specifically UE_REQUIRES (Thanks Unreal) | ||||
| 			}; | ||||
| 		}; | ||||
| 		StringCached  Content;          // Attributes, Comment, Execution, Include | ||||
| 		struct { | ||||
| 			SpecifierT ArrSpecs[ArrSpecs_Cap]; // Specifiers | ||||
| 			AST*       NextSpecs;              // Specifiers; If ArrSpecs is full, then NextSpecs is used. | ||||
| 			Specifier  ArrSpecs[AST_ArrSpecs_Cap]; // Specifiers | ||||
| 			Code       NextSpecs;              // Specifiers; If ArrSpecs is full, then NextSpecs is used. | ||||
| 		}; | ||||
| 	}; | ||||
| 	union { | ||||
| 		AST* Prev; | ||||
| 		AST* Front; | ||||
| 		AST* Last; | ||||
| 		Code Prev; | ||||
| 		Code Front; | ||||
| 		Code Last; | ||||
| 	}; | ||||
| 	union { | ||||
| 		AST* Next; | ||||
| 		AST* Back; | ||||
| 		Code Next; | ||||
| 		Code Back; | ||||
| 	}; | ||||
| 	parser::Token*    Token; // Reference to starting token, only avaialble if it was derived from parsing. | ||||
| 	AST*              Parent; | ||||
| 	Code              Parent; | ||||
| 	StringCached      Name; | ||||
| 	CodeT             Type; | ||||
| 	CodeType          Type; | ||||
| //	CodeFlag          CodeFlags; | ||||
| 	ModuleFlag        ModuleFlags; | ||||
| 	union { | ||||
| 		b32           IsFunction;  // Used by typedef to not serialize the name field. | ||||
| 		b32           IsParamPack; // Used by typename to know if type should be considered a parameter pack. | ||||
| 		OperatorT     Op; | ||||
| 		Operator      Op; | ||||
| 		AccessSpec    ParentAccess; | ||||
| 		s32           NumEntries; | ||||
| 		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 | ||||
| 	}; | ||||
| }; | ||||
| static_assert( sizeof(AST) == AST_POD_Size, "ERROR: AST POD is not size of AST_POD_Size" ); | ||||
|  | ||||
| struct AST_POD | ||||
| { | ||||
| 	union { | ||||
| 		struct | ||||
| 		{ | ||||
| 			AST*      InlineCmt;       // Class, Constructor, Destructor, Enum, Friend, Functon, Operator, OpCast, Struct, Typedef, Using, Variable | ||||
| 			AST*      Attributes;      // Class, Enum, Function, Struct, Typedef, Union, Using, Variable | ||||
| 			AST*      Specs;           // Destructor, Function, Operator, Typename, Variable | ||||
| 			union { | ||||
| 				AST*  InitializerList; // Constructor | ||||
| 				AST*  ParentType;      // Class, Struct, ParentType->Next has a possible list of interfaces. | ||||
| 				AST*  ReturnType;      // Function, Operator, Typename | ||||
| 				AST*  UnderlyingType;  // Enum, Typedef | ||||
| 				AST*  ValueType;       // Parameter, Variable | ||||
| 			}; | ||||
| 			union { | ||||
| 				AST*  Macro;           // Parameter | ||||
| 				AST*  BitfieldSize;    // Variable (Class/Struct Data Member) | ||||
| 				AST*  Params;          // Constructor, Function, Operator, Template, Typename | ||||
| 			}; | ||||
| 			union { | ||||
| 				AST*  ArrExpr;          // Typename | ||||
| 				AST*  Body;             // Class, Constructr, Destructor, Enum, Friend, Function, Namespace, Struct, Union | ||||
| 				AST*  Declaration;      // Friend, Template | ||||
| 				AST*  Value;            // Parameter, Variable | ||||
| 			}; | ||||
| 			union { | ||||
| 				AST*  NextVar;          // Variable; Possible way to handle comma separated variables declarations. ( , NextVar->Specs NextVar->Name NextVar->ArrExpr = NextVar->Value ) | ||||
| 				AST*  SuffixSpecs;      // Only used with typenames, to store the function suffix if typename is function signature. ( May not be needed ) | ||||
| 			}; | ||||
| 		}; | ||||
| 		StringCached  Content;          // Attributes, Comment, Execution, Include | ||||
| 		struct { | ||||
| 			SpecifierT ArrSpecs[AST::ArrSpecs_Cap]; // Specifiers | ||||
| 			AST*       NextSpecs;                   // Specifiers; If ArrSpecs is full, then NextSpecs is used. | ||||
| 		}; | ||||
| 	}; | ||||
| 	union { | ||||
| 		AST* Prev; | ||||
| 		AST* Front; | ||||
| 		AST* Last; | ||||
| 	}; | ||||
| 	union { | ||||
| 		AST* Next; | ||||
| 		AST* Back; | ||||
| 	}; | ||||
| 	parser::Token*    Token; // Reference to starting token, only avaialble if it was derived from parsing. | ||||
| 	AST*              Parent; | ||||
| 	StringCached      Name; | ||||
| 	CodeT             Type; | ||||
| 	CodeFlag          CodeFlags; | ||||
| 	ModuleFlag        ModuleFlags; | ||||
| 	union { | ||||
| 		b32           IsFunction;  // Used by typedef to not serialize the name field. | ||||
| 		b32           IsParamPack; // Used by typename to know if type should be considered a parameter pack. | ||||
| 		OperatorT     Op; | ||||
| 		AccessSpec    ParentAccess; | ||||
| 		s32           NumEntries; | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| struct test { | ||||
| 	SpecifierT ArrSpecs[AST::ArrSpecs_Cap]; // Specifiers | ||||
| 	AST* NextSpecs;                         // Specifiers; If ArrSpecs is full, then NextSpecs is used. | ||||
| }; | ||||
|  | ||||
| constexpr int pls = sizeof(test); | ||||
|  | ||||
| // Its intended for the AST to have equivalent size to its POD. | ||||
| // All extra functionality within the AST namespace should just be syntatic sugar. | ||||
| static_assert( sizeof(AST)     == sizeof(AST_POD), "ERROR: AST IS NOT POD" ); | ||||
| static_assert( sizeof(AST_POD) == AST_POD_Size,    "ERROR: AST POD is not size of AST_POD_Size" ); | ||||
| #if ! GEN_COMPILER_C | ||||
| // Uses an implicitly overloaded cast from the AST to the desired code type. | ||||
| // Necessary if the user wants GEN_ENFORCE_STRONG_CODE_TYPES | ||||
| struct  InvalidCode_ImplictCaster; | ||||
| #define InvalidCode (InvalidCode_ImplictCaster{}) | ||||
| #else | ||||
| #define InvalidCode Code_Invalid | ||||
| #endif | ||||
|  | ||||
| // 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 NullCode    { nullptr } | ||||
|   | ||||
| @@ -1,78 +1,78 @@ | ||||
| #	define GEN_AST_BODY_CLASS_UNALLOWED_TYPES \ | ||||
| 	case PlatformAttributes:                  \ | ||||
| 	case Class_Body:                          \ | ||||
| 	case Enum_Body:                           \ | ||||
| 	case Extern_Linkage:                      \ | ||||
| 	case Function_Body:                       \ | ||||
| 	case Function_Fwd:                        \ | ||||
| 	case Global_Body:                         \ | ||||
| 	case Namespace:                           \ | ||||
| 	case Namespace_Body:                      \ | ||||
| 	case Operator:                            \ | ||||
| 	case Operator_Fwd:                        \ | ||||
| 	case Parameters:                          \ | ||||
| 	case Specifiers:                          \ | ||||
| 	case Struct_Body:                         \ | ||||
| 	case Typename: | ||||
| 	case CT_PlatformAttributes:                  \ | ||||
| 	case CT_Class_Body:                          \ | ||||
| 	case CT_Enum_Body:                           \ | ||||
| 	case CT_Extern_Linkage:                      \ | ||||
| 	case CT_Function_Body:                       \ | ||||
| 	case CT_Function_Fwd:                        \ | ||||
| 	case CT_Global_Body:                         \ | ||||
| 	case CT_Namespace:                           \ | ||||
| 	case CT_Namespace_Body:                      \ | ||||
| 	case CT_Operator:                            \ | ||||
| 	case CT_Operator_Fwd:                        \ | ||||
| 	case CT_Parameters:                          \ | ||||
| 	case CT_Specifiers:                          \ | ||||
| 	case CT_Struct_Body:                         \ | ||||
| 	case CT_Typename: | ||||
| #	define GEN_AST_BODY_STRUCT_UNALLOWED_TYPES GEN_AST_BODY_CLASS_UNALLOWED_TYPES | ||||
|  | ||||
| #	define GEN_AST_BODY_FUNCTION_UNALLOWED_TYPES \ | ||||
| 	case Access_Public:                          \ | ||||
| 	case Access_Protected:                       \ | ||||
| 	case Access_Private:                         \ | ||||
| 	case PlatformAttributes:                     \ | ||||
| 	case Class_Body:                             \ | ||||
| 	case Enum_Body:                              \ | ||||
| 	case Extern_Linkage:                         \ | ||||
| 	case Friend:                                 \ | ||||
| 	case Function_Body:                          \ | ||||
| 	case Function_Fwd:                           \ | ||||
| 	case Global_Body:                            \ | ||||
| 	case Namespace:                              \ | ||||
| 	case Namespace_Body:                         \ | ||||
| 	case Operator:                               \ | ||||
| 	case Operator_Fwd:                           \ | ||||
| 	case Operator_Member:                        \ | ||||
| 	case Operator_Member_Fwd:                    \ | ||||
| 	case Parameters:                             \ | ||||
| 	case Specifiers:                             \ | ||||
| 	case Struct_Body:                            \ | ||||
| 	case Typename: | ||||
| 	case CT_Access_Public:                          \ | ||||
| 	case CT_Access_Protected:                       \ | ||||
| 	case CT_Access_Private:                         \ | ||||
| 	case CT_PlatformAttributes:                     \ | ||||
| 	case CT_Class_Body:                             \ | ||||
| 	case CT_Enum_Body:                              \ | ||||
| 	case CT_Extern_Linkage:                         \ | ||||
| 	case CT_Friend:                                 \ | ||||
| 	case CT_Function_Body:                          \ | ||||
| 	case CT_Function_Fwd:                           \ | ||||
| 	case CT_Global_Body:                            \ | ||||
| 	case CT_Namespace:                              \ | ||||
| 	case CT_Namespace_Body:                         \ | ||||
| 	case CT_Operator:                               \ | ||||
| 	case CT_Operator_Fwd:                           \ | ||||
| 	case CT_Operator_Member:                        \ | ||||
| 	case CT_Operator_Member_Fwd:                    \ | ||||
| 	case CT_Parameters:                             \ | ||||
| 	case CT_Specifiers:                             \ | ||||
| 	case CT_Struct_Body:                            \ | ||||
| 	case CT_Typename: | ||||
|  | ||||
| #	define GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES     \ | ||||
| 	case Access_Public: 				       \ | ||||
| 	case Access_Protected: 				       \ | ||||
| 	case Access_Private: 				       \ | ||||
| 	case PlatformAttributes:                   \ | ||||
| 	case Class_Body: 					       \ | ||||
| 	case Enum_Body: 					       \ | ||||
| 	case Execution: 					       \ | ||||
| 	case Friend: 						       \ | ||||
| 	case Function_Body: 				       \ | ||||
| 	case Namespace_Body: 				       \ | ||||
| 	case Operator_Member: 				       \ | ||||
| 	case Operator_Member_Fwd: 			       \ | ||||
| 	case Parameters: 					       \ | ||||
| 	case Specifiers: 					       \ | ||||
| 	case Struct_Body: 					       \ | ||||
| 	case Typename: | ||||
| 	case CT_Access_Public:                         \ | ||||
| 	case CT_Access_Protected:                      \ | ||||
| 	case CT_Access_Private:                        \ | ||||
| 	case CT_PlatformAttributes:                    \ | ||||
| 	case CT_Class_Body:                            \ | ||||
| 	case CT_Enum_Body:                             \ | ||||
| 	case CT_Execution:                             \ | ||||
| 	case CT_Friend:                                \ | ||||
| 	case CT_Function_Body:                         \ | ||||
| 	case CT_Namespace_Body:                        \ | ||||
| 	case CT_Operator_Member:                       \ | ||||
| 	case CT_Operator_Member_Fwd:                   \ | ||||
| 	case CT_Parameters:                            \ | ||||
| 	case CT_Specifiers:                            \ | ||||
| 	case CT_Struct_Body:                           \ | ||||
| 	case CT_Typename: | ||||
| #	define GEN_AST_BODY_EXPORT_UNALLOWED_TYPES         GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES | ||||
| #	define GEN_AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES | ||||
|  | ||||
| #	define GEN_AST_BODY_NAMESPACE_UNALLOWED_TYPES \ | ||||
| 	case Access_Public: 				          \ | ||||
| 	case Access_Protected: 				          \ | ||||
| 	case Access_Private: 				          \ | ||||
| 	case PlatformAttributes:                      \ | ||||
| 	case Class_Body: 					          \ | ||||
| 	case Enum_Body: 					          \ | ||||
| 	case Execution: 					          \ | ||||
| 	case Friend: 						          \ | ||||
| 	case Function_Body: 				          \ | ||||
| 	case Namespace_Body: 				          \ | ||||
| 	case Operator_Member: 				          \ | ||||
| 	case Operator_Member_Fwd: 			          \ | ||||
| 	case Parameters: 					          \ | ||||
| 	case Specifiers: 					          \ | ||||
| 	case Struct_Body: 					          \ | ||||
| 	case Typename: | ||||
| 	case CT_Access_Public:                        \ | ||||
| 	case CT_Access_Protected:                     \ | ||||
| 	case CT_Access_Private:                       \ | ||||
| 	case CT_PlatformAttributes:                   \ | ||||
| 	case CT_Class_Body:                           \ | ||||
| 	case CT_Enum_Body:                            \ | ||||
| 	case CT_Execution:                            \ | ||||
| 	case CT_Friend:                               \ | ||||
| 	case CT_Function_Body:                        \ | ||||
| 	case CT_Namespace_Body:                       \ | ||||
| 	case CT_Operator_Member:                      \ | ||||
| 	case CT_Operator_Member_Fwd:                  \ | ||||
| 	case CT_Parameters:                           \ | ||||
| 	case CT_Specifiers:                           \ | ||||
| 	case CT_Struct_Body:                          \ | ||||
| 	case CT_Typename: | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -3,75 +3,168 @@ | ||||
| #include "ast.hpp" | ||||
| #endif | ||||
|  | ||||
| #pragma region Code Type Interface | ||||
| void   append           ( CodeBody body, Code     other ); | ||||
| void   append           ( CodeBody body, CodeBody other ); | ||||
| String to_string        ( CodeBody body ); | ||||
| void   to_string        ( CodeBody body, String* result ); | ||||
| void   to_string_export ( CodeBody body, String* result ); | ||||
|  | ||||
| Code begin( CodeBody body); | ||||
| Code end  ( CodeBody body ); | ||||
|  | ||||
| void   add_interface( CodeClass self, CodeType interface ); | ||||
| String to_string    ( CodeClass self ); | ||||
| void   to_string_def( CodeClass self, String* result ); | ||||
| void   to_string_fwd( CodeClass self, String* result ); | ||||
|  | ||||
| void      append     (CodeParam params, CodeParam param ); | ||||
| CodeParam get        (CodeParam params, s32 idx); | ||||
| bool      has_entries(CodeParam params ); | ||||
| String    to_string  (CodeParam params ); | ||||
| void      to_string  (CodeParam params, String* result ); | ||||
|  | ||||
| CodeParam begin(CodeParam params); | ||||
| CodeParam end  (CodeParam params); | ||||
|  | ||||
| bool   append   (CodeSpecifiers specifiers, Specifier spec); | ||||
| s32    has      (CodeSpecifiers specifiers, Specifier spec); | ||||
| s32    remove   (CodeSpecifiers specifiers, Specifier to_remove ); | ||||
| String to_string(CodeSpecifiers specifiers); | ||||
| void   to_string(CodeSpecifiers specifiers, String* result); | ||||
|  | ||||
| Specifier* begin(CodeSpecifiers specifiers ); | ||||
| Specifier* end  (CodeSpecifiers specifiers); | ||||
|  | ||||
| void   add_interface(CodeStruct self, CodeType interface); | ||||
| String to_string    (CodeStruct self); | ||||
| void   to_string_fwd(CodeStruct self, String* result); | ||||
| void   to_string_def(CodeStruct self, String* result); | ||||
|  | ||||
| String to_string(CodeAttributes attributes); | ||||
| String to_string(CodeComment    comment ); | ||||
|  | ||||
| String to_string    (CodeConstructor constructor); | ||||
| void   to_string_def(CodeConstructor constructor, String* result ); | ||||
| void   to_string_fwd(CodeConstructor constructor, String* result ); | ||||
|  | ||||
| String to_string(CodeDefine define); | ||||
| void   to_string(CodeDefine define, String* result); | ||||
|  | ||||
| String to_string    (CodeDestructor destructor); | ||||
| void   to_string_def(CodeDestructor destructor, String* result ); | ||||
| void   to_string_fwd(CodeDestructor destructor, String* result ); | ||||
|  | ||||
| String to_string          (CodeEnum self); | ||||
| void   to_string_def      (CodeEnum self, String* result ); | ||||
| void   to_string_fwd      (CodeEnum self, String* result ); | ||||
| void   to_string_class_def(CodeEnum self, String* result ); | ||||
| void   to_string_class_fwd(CodeEnum self, String* result ); | ||||
|  | ||||
| String to_string(CodeExec exec); | ||||
|  | ||||
| void to_string(CodeExtern self, String* result); | ||||
|  | ||||
| String to_string(CodeInclude include); | ||||
| void   to_string(CodeInclude include, String* result); | ||||
|  | ||||
| String to_string(CodeFriend self); | ||||
| void   to_string(CodeFriend self, String* result); | ||||
|  | ||||
| String to_string    (CodeFn self); | ||||
| void   to_string_def(CodeFn self, String* result); | ||||
| void   to_string_fwd(CodeFn self, String* result); | ||||
|  | ||||
| String to_string(CodeModule self); | ||||
| void   to_string(CodeModule self, String* result); | ||||
|  | ||||
| String to_string(CodeNS self); | ||||
| void   to_string(CodeNS self, String* result); | ||||
|  | ||||
| String to_string    (CodeOperator self); | ||||
| void   to_string_fwd(CodeOperator self, String* result ); | ||||
| void   to_string_def(CodeOperator self, String* result ); | ||||
|  | ||||
| String to_string    (CodeOpCast op_cast ); | ||||
| void   to_string_def(CodeOpCast op_cast, String* result ); | ||||
| void   to_string_fwd(CodeOpCast op_cast, String* result ); | ||||
|  | ||||
| String to_string(CodePragma self); | ||||
| void   to_string(CodePragma self, String* result); | ||||
|  | ||||
| String to_string       (CodePreprocessCond cond); | ||||
| void   to_string_if    (CodePreprocessCond cond, String* result ); | ||||
| void   to_string_ifdef (CodePreprocessCond cond, String* result ); | ||||
| void   to_string_ifndef(CodePreprocessCond cond, String* result ); | ||||
| void   to_string_elif  (CodePreprocessCond cond, String* result ); | ||||
| void   to_string_else  (CodePreprocessCond cond, String* result ); | ||||
| void   to_string_endif (CodePreprocessCond cond, String* result ); | ||||
|  | ||||
| String to_string(CodeTemplate self); | ||||
| void   to_string(CodeTemplate self, String* result); | ||||
|  | ||||
| String to_string(CodeTypename self); | ||||
| void   to_string(CodeTypename self, String* result); | ||||
|  | ||||
| String to_string(CodeTypedef self); | ||||
| void   to_string(CodeTypedef self, String* result); | ||||
|  | ||||
| String to_string(CodeUnion self); | ||||
| void   to_string(CodeUnion self, String* result); | ||||
|  | ||||
| String to_string   (CodeUsing op_cast ); | ||||
| void   to_string   (CodeUsing op_cast, String* result ); | ||||
| void   to_string_ns(CodeUsing op_cast, String* result ); | ||||
|  | ||||
| String to_string(CodeVar self); | ||||
| void   to_string(CodeVar self, String* result); | ||||
| #pragma endregion Code Type Interface | ||||
|  | ||||
| #pragma region Code Types | ||||
| // These structs are not used at all by the C vairant. | ||||
| #if ! GEN_COMPILER_C | ||||
| // stati_assert( GEN_COMPILER_C, "This should not be compiled with the C-library" ); | ||||
|  | ||||
| #define Verify_POD(Type) static_assert(size_of(Code##Type) == size_of(AST_##Type), "ERROR: Code##Type is not a POD") | ||||
|  | ||||
| struct CodeBody | ||||
| { | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| 	Using_Code( CodeBody ); | ||||
|  | ||||
| 	void append( Code other ) | ||||
| 	{ | ||||
| 		raw()->append( other.ast ); | ||||
| 	} | ||||
| 	void append( CodeBody body ) | ||||
| 	{ | ||||
| 		for ( Code entry : body ) | ||||
| 		{ | ||||
| 			append( entry ); | ||||
| 		} | ||||
| 	} | ||||
| 	bool has_entries() | ||||
| 	{ | ||||
| 		return rcast( AST*, ast )->has_entries(); | ||||
| 	} | ||||
| 	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 ); | ||||
| 	} | ||||
| #pragma region Iterator | ||||
| 	Code begin() | ||||
| 	{ | ||||
| 		if ( ast ) | ||||
| 			return { rcast( AST*, ast)->Front }; | ||||
| 	void append( Code other )    { return GEN_NS append( *this, other ); } | ||||
| 	void append( CodeBody body ) { return GEN_NS append(*this, body); } | ||||
| 	bool has_entries()           { return GEN_NS has_entries(* this); } | ||||
|  | ||||
| 		return { nullptr }; | ||||
| 	} | ||||
| 	Code end() | ||||
| 	{ | ||||
| 		return { rcast(AST*, ast)->Back->Next }; | ||||
| 	} | ||||
| #pragma endregion Iterator | ||||
| 	String to_string()                        { return GEN_NS to_string(* this); } | ||||
| 	void   to_string( String& result )        { return GEN_NS to_string(* this, & result ); } | ||||
| 	void   to_string_export( String& result ) { return GEN_NS to_string_export(* this, & result); } | ||||
|  | ||||
| 	Code begin() { return GEN_NS begin(* this); } | ||||
| 	Code end()   { return GEN_NS end(* this); } | ||||
| #endif | ||||
|  | ||||
| 	Using_CodeOps( CodeBody ); | ||||
| 	operator Code() { return * rcast( Code*, this ); } | ||||
| 	AST_Body* operator->() { return ast; } | ||||
|  | ||||
| 	AST_Body* ast; | ||||
| }; | ||||
|  | ||||
| struct CodeClass | ||||
| { | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| 	Using_Code( CodeClass ); | ||||
|  | ||||
| 	void add_interface( CodeType interface ); | ||||
|  | ||||
| 	String to_string(); | ||||
| 	void   to_string_def( String& result ); | ||||
| 	void   to_string_fwd( String& result ); | ||||
| #endif | ||||
|  | ||||
| 	AST* raw() | ||||
| 	{ | ||||
| 		return rcast( AST*, ast ); | ||||
| 	} | ||||
| 	operator Code() | ||||
| 	{ | ||||
| 		return * rcast( Code*, this ); | ||||
| 	} | ||||
| 	Using_CodeOps( CodeClass ); | ||||
| 	operator Code() { return * rcast( Code*, this ); } | ||||
| 	AST_Class* operator->() | ||||
| 	{ | ||||
| 		if ( ast == nullptr ) | ||||
| @@ -86,17 +179,17 @@ struct CodeClass | ||||
|  | ||||
| struct CodeParam | ||||
| { | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| 	Using_Code( CodeParam ); | ||||
|  | ||||
| 	void      append( CodeParam other ); | ||||
|  | ||||
| 	CodeParam get( s32 idx ); | ||||
| 	bool      has_entries(); | ||||
| 	String    to_string(); | ||||
| 	void      to_string( String& result ); | ||||
| 	AST* raw() | ||||
| 	{ | ||||
| 		return rcast( AST*, ast ); | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| 	Using_CodeOps( CodeParam ); | ||||
| 	AST_Param* operator->() | ||||
| 	{ | ||||
| 		if ( ast == nullptr ) | ||||
| @@ -106,70 +199,27 @@ struct CodeParam | ||||
| 		} | ||||
| 		return ast; | ||||
| 	} | ||||
| 	operator Code() | ||||
| 	{ | ||||
| 		return { (AST*)ast }; | ||||
| 	} | ||||
| #pragma region Iterator | ||||
| 	CodeParam begin() | ||||
| 	{ | ||||
| 		if ( ast ) | ||||
| 			return { ast }; | ||||
|  | ||||
| 		return { nullptr }; | ||||
| 	} | ||||
| 	CodeParam end() | ||||
| 	{ | ||||
| 		// return { (AST_Param*) rcast( AST*, ast)->Last }; | ||||
| 		return { nullptr }; | ||||
| 	} | ||||
| 	operator Code()       { return { (AST*)ast }; } | ||||
| 	CodeParam operator*() { return * this; } | ||||
| 	CodeParam& operator++(); | ||||
| 	CodeParam operator*() | ||||
| 	{ | ||||
| 		return * this; | ||||
| 	} | ||||
| #pragma endregion Iterator | ||||
|  | ||||
| 	AST_Param* ast; | ||||
| }; | ||||
|  | ||||
| struct CodeSpecifiers | ||||
| { | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| 	Using_Code( CodeSpecifiers ); | ||||
|  | ||||
| 	bool append( SpecifierT spec ) | ||||
| 	{ | ||||
| 		if ( ast == nullptr ) | ||||
| 		{ | ||||
| 			log_failure("CodeSpecifiers: Attempted to append to a null specifiers AST!"); | ||||
| 			return false; | ||||
| 		} | ||||
| 	bool   append( Specifier spec )       { return GEN_NS append(* this, spec); } | ||||
| 	s32    has( Specifier spec )          { return GEN_NS has(* this, spec); } | ||||
| 	s32    remove( Specifier to_remove )  { return GEN_NS remove(* this, to_remove); } | ||||
| 	String to_string()                    { return GEN_NS to_string(* this ); } | ||||
| 	void   to_string( String& result )    { return GEN_NS to_string(* this, & result); } | ||||
| #endif | ||||
|  | ||||
| 		if ( raw()->NumEntries == AST::ArrSpecs_Cap ) | ||||
| 		{ | ||||
| 			log_failure("CodeSpecifiers: Attempted to append over %d specifiers to a specifiers AST!", AST::ArrSpecs_Cap ); | ||||
| 			return false; | ||||
| 		} | ||||
|  | ||||
| 		raw()->ArrSpecs[ raw()->NumEntries ] = spec; | ||||
| 		raw()->NumEntries++; | ||||
| 		return true; | ||||
| 	} | ||||
| 	s32 has( SpecifierT spec ) | ||||
| 	{ | ||||
| 		for ( s32 idx = 0; idx < raw()->NumEntries; idx++ ) | ||||
| 		{ | ||||
| 			if ( raw()->ArrSpecs[ idx ] == spec ) | ||||
| 				return idx; | ||||
| 		} | ||||
|  | ||||
| 		return -1; | ||||
| 	} | ||||
| 	void to_string( String& result ); | ||||
| 	AST* raw() | ||||
| 	{ | ||||
| 		return rcast( AST*, ast ); | ||||
| 	} | ||||
| 	Using_CodeOps(CodeSpecifiers); | ||||
| 	operator Code() { return { (AST*) ast }; } | ||||
| 	AST_Specifiers* operator->() | ||||
| 	{ | ||||
| 		if ( ast == nullptr ) | ||||
| @@ -179,44 +229,24 @@ struct CodeSpecifiers | ||||
| 		} | ||||
| 		return ast; | ||||
| 	} | ||||
| 	operator Code() | ||||
| 	{ | ||||
| 		return { (AST*) ast }; | ||||
| 	} | ||||
| #pragma region Iterator | ||||
| 	SpecifierT* begin() | ||||
| 	{ | ||||
| 		if ( ast ) | ||||
| 			return & raw()->ArrSpecs[0]; | ||||
|  | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	SpecifierT* end() | ||||
| 	{ | ||||
| 		return raw()->ArrSpecs + raw()->NumEntries; | ||||
| 	} | ||||
| #pragma endregion Iterator | ||||
|  | ||||
| 	AST_Specifiers* ast; | ||||
| }; | ||||
|  | ||||
| struct CodeStruct | ||||
| { | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| 	Using_Code( CodeStruct ); | ||||
|  | ||||
| 	void add_interface( CodeType interface ); | ||||
|  | ||||
| 	void to_string_def( String& result ); | ||||
| 	String to_string(); | ||||
| 	void   to_string_fwd( String& result ); | ||||
| 	void   to_string_def( String& result ); | ||||
| #endif | ||||
|  | ||||
| 	AST* raw() | ||||
| 	{ | ||||
| 		return rcast( AST*, ast ); | ||||
| 	} | ||||
| 	operator Code() | ||||
| 	{ | ||||
| 		return * rcast( Code*, this ); | ||||
| 	} | ||||
| 	Using_CodeOps( CodeStruct ); | ||||
| 	operator Code() { return * rcast( Code*, this ); } | ||||
| 	AST_Struct* operator->() | ||||
| 	{ | ||||
| 		if ( ast == nullptr ) | ||||
| @@ -229,28 +259,45 @@ struct CodeStruct | ||||
| 	AST_Struct* ast; | ||||
| }; | ||||
|  | ||||
| #define Define_CodeType( Typename )     \ | ||||
| 	struct Code##Typename               \ | ||||
| 	{                                   \ | ||||
| 		Using_Code( Code ## Typename ); \ | ||||
| 		AST*            raw();          \ | ||||
| 		operator        Code();         \ | ||||
| 		AST_##Typename* operator->();   \ | ||||
| 		AST_##Typename* ast;            \ | ||||
| 	} | ||||
| struct CodeAttributes | ||||
| { | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| 	Using_Code(CodeAttributes); | ||||
| 	String to_string(); | ||||
| #endif | ||||
|  | ||||
| 	Using_CodeOps(CodeAttributes); | ||||
| 	operator Code(); | ||||
| 	AST_Attributes *operator->(); | ||||
| 	AST_Attributes *ast; | ||||
| }; | ||||
|  | ||||
| Define_CodeType( Attributes ); | ||||
| // Define_CodeType( BaseClass ); | ||||
| Define_CodeType( Comment ); | ||||
|  | ||||
| struct CodeComment | ||||
| { | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| 	Using_Code(CodeComment); | ||||
| 	String to_string() { return GEN_NS to_string(* this); } | ||||
| #endif | ||||
|  | ||||
| 	Using_CodeOps(CodeComment); | ||||
| 	operator Code(); | ||||
| 	AST_Comment *operator->(); | ||||
| 	AST_Comment *ast; | ||||
| }; | ||||
|  | ||||
| struct CodeConstructor | ||||
| { | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| 	Using_Code( CodeConstructor ); | ||||
|  | ||||
| 	void to_string_def( String& result ); | ||||
| 	void to_string_fwd( String& result ); | ||||
| 	String to_string()                     { return GEN_NS to_string(* this); } | ||||
| 	void   to_string_def( String& result ) { return GEN_NS to_string_def(* this, & result); } | ||||
| 	void   to_string_fwd( String& result ) { return GEN_NS to_string_fwd(* this, & result); } | ||||
| #endif | ||||
|  | ||||
| 	AST*             raw(); | ||||
| 	Using_CodeOps(CodeConstructor); | ||||
| 	operator         Code(); | ||||
| 	AST_Constructor* operator->(); | ||||
| 	AST_Constructor* ast; | ||||
| @@ -258,11 +305,14 @@ struct CodeConstructor | ||||
|  | ||||
| struct CodeDefine | ||||
| { | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| 	Using_Code( CodeDefine ); | ||||
|  | ||||
| 	void to_string( String& result ); | ||||
| 	String to_string()                 { return GEN_NS to_string(* this); } | ||||
| 	void   to_string( String& result ) { return GEN_NS to_string(* this, & result); } | ||||
| #endif | ||||
|  | ||||
| 	AST*        raw(); | ||||
| 	Using_CodeOps(CodeDefine); | ||||
| 	operator    Code(); | ||||
| 	AST_Define* operator->(); | ||||
| 	AST_Define* ast; | ||||
| @@ -270,12 +320,15 @@ struct CodeDefine | ||||
|  | ||||
| struct CodeDestructor | ||||
| { | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| 	Using_Code( CodeDestructor ); | ||||
|  | ||||
| 	void to_string_def( String& result ); | ||||
| 	void to_string_fwd( String& result ); | ||||
| 	String to_string()                     { return GEN_NS to_string(* this); } | ||||
| 	void   to_string_def( String& result ) { return GEN_NS to_string_def(* this, & result); } | ||||
| 	void   to_string_fwd( String& result ) { return GEN_NS to_string_fwd(* this, & result); } | ||||
| #endif | ||||
|  | ||||
| 	AST*             raw(); | ||||
| 	Using_CodeOps(CodeDestructor); | ||||
| 	operator         Code(); | ||||
| 	AST_Destructor* operator->(); | ||||
| 	AST_Destructor* ast; | ||||
| @@ -283,20 +336,34 @@ struct CodeDestructor | ||||
|  | ||||
| struct CodeEnum | ||||
| { | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| 	Using_Code( CodeEnum ); | ||||
|  | ||||
| 	void to_string_def( String& result ); | ||||
| 	void to_string_fwd( String& result ); | ||||
| 	void to_string_class_def( String& result ); | ||||
| 	void to_string_class_fwd( String& result ); | ||||
| 	String to_string()                            { return GEN_NS to_string(* this); } | ||||
| 	void   to_string_def( String& result )        { return GEN_NS to_string_def(* this, & result); } | ||||
| 	void   to_string_fwd( String& result )        { return GEN_NS to_string_fwd(* this, & result); } | ||||
| 	void   to_string_class_def( String& result )  { return GEN_NS to_string_class_def(* this, & result); } | ||||
| 	void   to_string_class_fwd( String& result )  { return GEN_NS to_string_class_fwd(* this, & result); } | ||||
| #endif | ||||
|  | ||||
| 	AST*      raw(); | ||||
| 	Using_CodeOps(CodeEnum); | ||||
| 	operator  Code(); | ||||
| 	AST_Enum* operator->(); | ||||
| 	AST_Enum* ast; | ||||
| }; | ||||
|  | ||||
| Define_CodeType( Exec ); | ||||
| struct CodeExec | ||||
| { | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| 	Using_Code(CodeExec); | ||||
| 	String to_string() { return GEN_NS to_string(* this); } | ||||
| #endif | ||||
|  | ||||
| 	Using_CodeOps(CodeExec); | ||||
| 	operator Code(); | ||||
| 	AST_Exec *operator->(); | ||||
| 	AST_Exec *ast; | ||||
| }; | ||||
|  | ||||
| #if GEN_EXECUTION_EXPRESSION_SUPPORT | ||||
| struct CodeExpr | ||||
| @@ -506,11 +573,13 @@ struct CodeExpr_UnaryPostfix | ||||
|  | ||||
| struct CodeExtern | ||||
| { | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| 	Using_Code( CodeExtern ); | ||||
|  | ||||
| 	void to_string( String& result ); | ||||
| 	void to_string( String& result ) { return GEN_NS to_string(* this, & result); } | ||||
| #endif | ||||
|  | ||||
| 	AST*        raw(); | ||||
| 	Using_CodeOps(CodeExtern); | ||||
| 	operator    Code(); | ||||
| 	AST_Extern* operator->(); | ||||
| 	AST_Extern* ast; | ||||
| @@ -518,11 +587,14 @@ struct CodeExtern | ||||
|  | ||||
| struct CodeInclude | ||||
| { | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| 	Using_Code( CodeInclude ); | ||||
|  | ||||
| 	void to_string( String& result ); | ||||
| 	String to_string()                  { return GEN_NS to_string(* this); } | ||||
| 	void   to_string( String& result )  { return GEN_NS to_string(* this, & result); } | ||||
| #endif | ||||
|  | ||||
| 	AST*         raw(); | ||||
| 	Using_CodeOps(CodeInclude); | ||||
| 	operator     Code(); | ||||
| 	AST_Include* operator->(); | ||||
| 	AST_Include* ast; | ||||
| @@ -530,11 +602,14 @@ struct CodeInclude | ||||
|  | ||||
| struct CodeFriend | ||||
| { | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| 	Using_Code( CodeFriend ); | ||||
|  | ||||
| 	void to_string( String& result ); | ||||
| 	String to_string()                 { return GEN_NS to_string(* this); } | ||||
| 	void   to_string( String& result ) { return GEN_NS to_string(* this, & result); } | ||||
| #endif | ||||
|  | ||||
| 	AST*        raw(); | ||||
| 	Using_CodeOps(CodeFriend); | ||||
| 	operator    Code(); | ||||
| 	AST_Friend* operator->(); | ||||
| 	AST_Friend* ast; | ||||
| @@ -542,12 +617,15 @@ struct CodeFriend | ||||
|  | ||||
| struct CodeFn | ||||
| { | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| 	Using_Code( CodeFn ); | ||||
|  | ||||
| 	void to_string_def( String& result ); | ||||
| 	void to_string_fwd( String& result ); | ||||
| 	String to_string()                     { return GEN_NS to_string(* this); } | ||||
| 	void   to_string_def( String& result ) { return GEN_NS to_string_def(* this, & result); } | ||||
| 	void   to_string_fwd( String& result ) { return GEN_NS to_string_fwd(* this, & result); } | ||||
| #endif | ||||
|  | ||||
| 	AST*     raw(); | ||||
| 	Using_CodeOps(CodeFn); | ||||
| 	operator Code(); | ||||
| 	AST_Fn*  operator->(); | ||||
| 	AST_Fn*  ast; | ||||
| @@ -555,11 +633,14 @@ struct CodeFn | ||||
|  | ||||
| struct CodeModule | ||||
| { | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| 	Using_Code( CodeModule ); | ||||
|  | ||||
| 	void to_string( String& result ); | ||||
| 	String to_string()                 { return GEN_NS to_string(* this); } | ||||
| 	void   to_string( String& result ) { return GEN_NS to_string(* this, & result); } | ||||
| #endif | ||||
|  | ||||
| 	AST*        raw(); | ||||
| 	Using_CodeOps(CodeModule); | ||||
| 	operator    Code(); | ||||
| 	AST_Module* operator->(); | ||||
| 	AST_Module* ast; | ||||
| @@ -567,11 +648,14 @@ struct CodeModule | ||||
|  | ||||
| struct CodeNS | ||||
| { | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| 	Using_Code( CodeNS ); | ||||
|  | ||||
| 	void to_string( String& result ); | ||||
| 	String to_string()                 { return GEN_NS to_string(* this); } | ||||
| 	void   to_string( String& result ) { return GEN_NS to_string(* this, & result); } | ||||
| #endif | ||||
|  | ||||
| 	AST*     raw(); | ||||
| 	Using_CodeOps(CodeNS); | ||||
| 	operator Code(); | ||||
| 	AST_NS*  operator->(); | ||||
| 	AST_NS*  ast; | ||||
| @@ -579,12 +663,15 @@ struct CodeNS | ||||
|  | ||||
| struct CodeOperator | ||||
| { | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| 	Using_Code( CodeOperator ); | ||||
|  | ||||
| 	void to_string_def( String& result ); | ||||
| 	void to_string_fwd( String& result ); | ||||
| 	String to_string()                     { return GEN_NS to_string(* this); } | ||||
| 	void   to_string_def( String& result ) { return GEN_NS to_string_def(* this, & result); } | ||||
| 	void   to_string_fwd( String& result ) { return GEN_NS to_string_fwd(* this, & result); } | ||||
| #endif | ||||
|  | ||||
| 	AST*          raw(); | ||||
| 	Using_CodeOps(CodeOperator); | ||||
| 	operator      Code(); | ||||
| 	AST_Operator* operator->(); | ||||
| 	AST_Operator* ast; | ||||
| @@ -592,12 +679,15 @@ struct CodeOperator | ||||
|  | ||||
| struct CodeOpCast | ||||
| { | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| 	Using_Code( CodeOpCast ); | ||||
|  | ||||
| 	void to_string_def( String& result ); | ||||
| 	void to_string_fwd( String& result ); | ||||
| 	String to_string()                     { return GEN_NS to_string(* this); } | ||||
| 	void   to_string_def( String& result ) { return GEN_NS to_string_def(* this, & result); } | ||||
| 	void   to_string_fwd( String& result ) { return GEN_NS to_string_fwd(* this, & result); } | ||||
| #endif | ||||
|  | ||||
| 	AST*        raw(); | ||||
| 	Using_CodeOps(CodeOpCast); | ||||
| 	operator    Code(); | ||||
| 	AST_OpCast* operator->(); | ||||
| 	AST_OpCast* ast; | ||||
| @@ -605,11 +695,14 @@ struct CodeOpCast | ||||
|  | ||||
| struct CodePragma | ||||
| { | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES || 1 | ||||
| 	Using_Code( CodePragma ); | ||||
|  | ||||
| 	void to_string( String& result ); | ||||
| 	String to_string()                 { return GEN_NS to_string(* this); } | ||||
| 	void   to_string( String& result ) { return GEN_NS to_string(* this, & result); } | ||||
| #endif | ||||
|  | ||||
| 	AST*        raw(); | ||||
| 	Using_CodeOps( CodePragma ); | ||||
| 	operator    Code(); | ||||
| 	AST_Pragma* operator->(); | ||||
| 	AST_Pragma* ast; | ||||
| @@ -617,16 +710,19 @@ struct CodePragma | ||||
|  | ||||
| struct CodePreprocessCond | ||||
| { | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| 	Using_Code( CodePreprocessCond ); | ||||
|  | ||||
| 	void to_string_if( String& result ); | ||||
| 	void to_string_ifdef( String& result ); | ||||
| 	void to_string_ifndef( String& result ); | ||||
| 	void to_string_elif( String& result ); | ||||
| 	void to_string_else( String& result ); | ||||
| 	void to_string_endif( String& result ); | ||||
| 	String to_string()                        { return GEN_NS to_string(* this); } | ||||
| 	void   to_string_if( String& result )     { return GEN_NS to_string_if(* this, & result); } | ||||
| 	void   to_string_ifdef( String& result )  { return GEN_NS to_string_ifdef(* this, & result); } | ||||
| 	void   to_string_ifndef( String& result ) { return GEN_NS to_string_ifndef(* this, & result); } | ||||
| 	void   to_string_elif( String& result )   { return GEN_NS to_string_elif(* this, & result); } | ||||
| 	void   to_string_else( String& result )   { return GEN_NS to_string_else(* this, & result); } | ||||
| 	void   to_string_endif( String& result )  { return GEN_NS to_string_endif(* this, & result); } | ||||
| #endif | ||||
|  | ||||
| 	AST*                raw(); | ||||
| 	Using_CodeOps( CodePreprocessCond ); | ||||
| 	operator            Code(); | ||||
| 	AST_PreprocessCond* operator->(); | ||||
| 	AST_PreprocessCond* ast; | ||||
| @@ -637,6 +733,7 @@ struct CodeStmt | ||||
| { | ||||
| 	Using_Code( CodeStmt ); | ||||
|  | ||||
| 	String to_string(); | ||||
| 	void   to_string( String& result ); | ||||
|  | ||||
| 	AST*      raw(); | ||||
| @@ -649,6 +746,7 @@ struct CodeStmt_Break | ||||
| { | ||||
| 	Using_Code( CodeStmt_Break ); | ||||
|  | ||||
| 	String to_string(); | ||||
| 	void   to_string( String& result ); | ||||
|  | ||||
| 	AST*            raw(); | ||||
| @@ -661,6 +759,7 @@ struct CodeStmt_Case | ||||
| { | ||||
| 	Using_Code( CodeStmt_Case ); | ||||
|  | ||||
| 	String to_string(); | ||||
| 	void   to_string( String& result ); | ||||
|  | ||||
| 	AST*           raw(); | ||||
| @@ -673,6 +772,7 @@ struct CodeStmt_Continue | ||||
| { | ||||
| 	Using_Code( CodeStmt_Continue ); | ||||
|  | ||||
| 	String to_string(); | ||||
| 	void   to_string( String& result ); | ||||
|  | ||||
| 	AST*               raw(); | ||||
| @@ -685,6 +785,7 @@ struct CodeStmt_Decl | ||||
| { | ||||
| 	Using_Code( CodeStmt_Decl ); | ||||
|  | ||||
| 	String to_string(); | ||||
| 	void   to_string( String& result ); | ||||
|  | ||||
| 	AST*           raw(); | ||||
| @@ -697,6 +798,7 @@ struct CodeStmt_Do | ||||
| { | ||||
| 	Using_Code( CodeStmt_Do ); | ||||
|  | ||||
| 	String to_string(); | ||||
| 	void   to_string( String& result ); | ||||
|  | ||||
| 	AST*         raw(); | ||||
| @@ -709,6 +811,7 @@ struct CodeStmt_Expr | ||||
| { | ||||
| 	Using_Code( CodeStmt_Expr ); | ||||
|  | ||||
| 	String to_string(); | ||||
| 	void   to_string( String& result ); | ||||
|  | ||||
| 	AST*           raw(); | ||||
| @@ -721,6 +824,7 @@ struct CodeStmt_Else | ||||
| { | ||||
| 	Using_Code( CodeStmt_Else ); | ||||
|  | ||||
| 	String to_string(); | ||||
| 	void   to_string( String& result ); | ||||
|  | ||||
| 	AST*           raw(); | ||||
| @@ -733,6 +837,7 @@ struct CodeStmt_If | ||||
| { | ||||
| 	Using_Code( CodeStmt_If ); | ||||
|  | ||||
| 	String to_string(); | ||||
| 	void   to_string( String& result ); | ||||
|  | ||||
| 	AST*         raw(); | ||||
| @@ -745,6 +850,7 @@ struct CodeStmt_For | ||||
| { | ||||
| 	Using_Code( CodeStmt_For ); | ||||
|  | ||||
| 	String to_string(); | ||||
| 	void   to_string( String& result ); | ||||
|  | ||||
| 	AST*          raw(); | ||||
| @@ -757,6 +863,7 @@ struct CodeStmt_Goto | ||||
| { | ||||
| 	Using_Code( CodeStmt_Goto ); | ||||
|  | ||||
| 	String to_string(); | ||||
| 	void   to_string( String& result ); | ||||
|  | ||||
| 	AST*           raw(); | ||||
| @@ -769,6 +876,7 @@ struct CodeStmt_Label | ||||
| { | ||||
| 	Using_Code( CodeStmt_Label ); | ||||
|  | ||||
| 	String to_string(); | ||||
| 	void   to_string( String& result ); | ||||
|  | ||||
| 	AST*            raw(); | ||||
| @@ -781,6 +889,7 @@ struct CodeStmt_Switch | ||||
| { | ||||
| 	Using_Code( CodeStmt_Switch ); | ||||
|  | ||||
| 	String to_string(); | ||||
| 	void   to_string( String& result ); | ||||
|  | ||||
| 	AST*           raw(); | ||||
| @@ -793,6 +902,7 @@ struct CodeStmt_While | ||||
| { | ||||
| 	Using_Code( CodeStmt_While ); | ||||
|  | ||||
| 	String to_string(); | ||||
| 	void   to_string( String& result ); | ||||
|  | ||||
| 	AST*           raw(); | ||||
| @@ -804,35 +914,44 @@ struct CodeStmt_While | ||||
|  | ||||
| struct CodeTemplate | ||||
| { | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| 	Using_Code( CodeTemplate ); | ||||
|  | ||||
| 	void to_string( String& result ); | ||||
| 	String to_string()                 { return GEN_NS to_string(* this); } | ||||
| 	void   to_string( String& result ) { return GEN_NS to_string(* this, & result); } | ||||
| #endif | ||||
|  | ||||
| 	AST*          raw(); | ||||
| 	Using_CodeOps( CodeTemplate ); | ||||
| 	operator      Code(); | ||||
| 	AST_Template* operator->(); | ||||
| 	AST_Template* ast; | ||||
| }; | ||||
|  | ||||
| struct CodeType | ||||
| struct CodeTypename | ||||
| { | ||||
| 	Using_Code( CodeType ); | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| 	Using_Code( CodeTypename ); | ||||
|  | ||||
| 	void to_string( String& result ); | ||||
| 	String to_string()                 { return GEN_NS to_string(* this); } | ||||
| 	void   to_string( String& result ) { return GEN_NS to_string(* this, & result); } | ||||
| #endif | ||||
|  | ||||
| 	AST*      raw(); | ||||
| 	Using_CodeOps( CodeTypename ); | ||||
| 	operator      Code(); | ||||
| 	AST_Type* operator->(); | ||||
| 	AST_Type* ast; | ||||
| 	AST_Typename* operator->(); | ||||
| 	AST_Typename* ast; | ||||
| }; | ||||
|  | ||||
| struct CodeTypedef | ||||
| { | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| 	Using_Code( CodeTypedef ); | ||||
|  | ||||
| 	void to_string( String& result ); | ||||
| 	String to_string()                 { return GEN_NS to_string(* this); } | ||||
| 	void   to_string( String& result ) { return GEN_NS to_string(* this, & result); } | ||||
| #endif | ||||
|  | ||||
| 	AST*         raw(); | ||||
| 	Using_CodeOps( CodeTypedef ); | ||||
| 	operator     Code(); | ||||
| 	AST_Typedef* operator->(); | ||||
| 	AST_Typedef* ast; | ||||
| @@ -840,11 +959,14 @@ struct CodeTypedef | ||||
|  | ||||
| struct CodeUnion | ||||
| { | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| 	Using_Code( CodeUnion ); | ||||
|  | ||||
| 	void to_string( String& result ); | ||||
| 	String to_string()                 { return GEN_NS to_string(* this); } | ||||
| 	void   to_string( String& result ) { return GEN_NS to_string(* this, & result); } | ||||
| #endif | ||||
|  | ||||
| 	AST*       raw(); | ||||
| 	Using_CodeOps(CodeUnion); | ||||
| 	operator   Code(); | ||||
| 	AST_Union* operator->(); | ||||
| 	AST_Union* ast; | ||||
| @@ -852,12 +974,15 @@ struct CodeUnion | ||||
|  | ||||
| struct CodeUsing | ||||
| { | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| 	Using_Code( CodeUsing ); | ||||
|  | ||||
| 	void to_string( String& result ); | ||||
| 	void to_string_ns( String& result ); | ||||
| 	String to_string()                    { return GEN_NS to_string(* this); } | ||||
| 	void   to_string( String& result )    { return GEN_NS to_string(* this, & result); } | ||||
| 	void   to_string_ns( String& result ) { return GEN_NS to_string_ns(* this, & result); } | ||||
| #endif | ||||
|  | ||||
| 	AST*       raw(); | ||||
| 	Using_CodeOps(CodeUsing); | ||||
| 	operator   Code(); | ||||
| 	AST_Using* operator->(); | ||||
| 	AST_Using* ast; | ||||
| @@ -865,11 +990,14 @@ struct CodeUsing | ||||
|  | ||||
| struct CodeVar | ||||
| { | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| 	Using_Code( CodeVar ); | ||||
|  | ||||
| 	void to_string( String& result ); | ||||
| 	String to_string()                 { return GEN_NS to_string(* this); } | ||||
| 	void   to_string( String& result ) { return GEN_NS to_string(* this, & result); } | ||||
| #endif | ||||
|  | ||||
| 	AST*     raw(); | ||||
| 	Using_CodeOps(CodeVar); | ||||
| 	operator Code(); | ||||
| 	AST_Var* operator->(); | ||||
| 	AST_Var* ast; | ||||
| @@ -877,5 +1005,48 @@ struct CodeVar | ||||
|  | ||||
| #undef Define_CodeType | ||||
| #undef Using_Code | ||||
| #undef Using_CodeOps | ||||
|  | ||||
| #if GEN_SUPPORT_CPP_REFERENCES | ||||
| void to_string_export( CodeBody body, String& result ) { return to_string_export(body, & result); }; | ||||
| #endif | ||||
|  | ||||
| #undef Verify_POD | ||||
|  | ||||
| struct InvalidCode_ImplictCaster | ||||
| { | ||||
| 	// operator CodeBaseClass() const; | ||||
|     operator Code              () const { return Code_Invalid; } | ||||
|     operator CodeBody          () const { return cast(CodeBody,           Code_Invalid); } | ||||
|     operator CodeAttributes    () const { return cast(CodeAttributes,     Code_Invalid); } | ||||
|     operator CodeComment       () const { return cast(CodeComment,        Code_Invalid); } | ||||
|     operator CodeClass         () const { return cast(CodeClass,          Code_Invalid); } | ||||
|     operator CodeConstructor   () const { return cast(CodeConstructor,    Code_Invalid); } | ||||
|     operator CodeDefine        () const { return cast(CodeDefine,         Code_Invalid); } | ||||
|     operator CodeDestructor    () const { return cast(CodeDestructor,     Code_Invalid); } | ||||
|     operator CodeExec          () const { return cast(CodeExec,           Code_Invalid); } | ||||
|     operator CodeEnum          () const { return cast(CodeEnum,           Code_Invalid); } | ||||
|     operator CodeExtern        () const { return cast(CodeExtern,         Code_Invalid); } | ||||
|     operator CodeInclude       () const { return cast(CodeInclude,        Code_Invalid); } | ||||
|     operator CodeFriend        () const { return cast(CodeFriend,         Code_Invalid); } | ||||
|     operator CodeFn            () const { return cast(CodeFn,             Code_Invalid); } | ||||
|     operator CodeModule        () const { return cast(CodeModule,         Code_Invalid); } | ||||
|     operator CodeNS            () const { return cast(CodeNS,             Code_Invalid); } | ||||
|     operator CodeOperator      () const { return cast(CodeOperator,       Code_Invalid); } | ||||
|     operator CodeOpCast        () const { return cast(CodeOpCast,         Code_Invalid); } | ||||
|     operator CodeParam         () const { return cast(CodeParam,          Code_Invalid); } | ||||
|     operator CodePragma        () const { return cast(CodePragma,         Code_Invalid); } | ||||
|     operator CodePreprocessCond() const { return cast(CodePreprocessCond, Code_Invalid); } | ||||
|     operator CodeSpecifiers    () const { return cast(CodeSpecifiers,     Code_Invalid); } | ||||
|     operator CodeStruct        () const { return cast(CodeStruct,         Code_Invalid); } | ||||
|     operator CodeTemplate      () const { return cast(CodeTemplate,       Code_Invalid); } | ||||
|     operator CodeTypename      () const { return cast(CodeTypename,       Code_Invalid); } | ||||
|     operator CodeTypedef       () const { return cast(CodeTypedef,        Code_Invalid); } | ||||
|     operator CodeUnion         () const { return cast(CodeUnion,          Code_Invalid); } | ||||
|     operator CodeUsing         () const { return cast(CodeUsing,          Code_Invalid); } | ||||
|     operator CodeVar           () const { return cast(CodeVar,            Code_Invalid); } | ||||
| }; | ||||
|  | ||||
| #endif //if ! GEN_COMPILER_C | ||||
|  | ||||
| #pragma endregion Code Types | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -5,74 +5,73 @@ | ||||
|  | ||||
| // This file was generated automatially by gencpp's bootstrap.cpp (See: https://github.com/Ed94/gencpp) | ||||
|  | ||||
| namespace ECode | ||||
| enum CodeType_Def : u32 | ||||
| { | ||||
| 	enum Type : u32 | ||||
| 	{ | ||||
| 		Invalid, | ||||
| 		Untyped, | ||||
| 		NewLine, | ||||
| 		Comment, | ||||
| 		Access_Private, | ||||
| 		Access_Protected, | ||||
| 		Access_Public, | ||||
| 		PlatformAttributes, | ||||
| 		Class, | ||||
| 		Class_Fwd, | ||||
| 		Class_Body, | ||||
| 		Constructor, | ||||
| 		Constructor_Fwd, | ||||
| 		Destructor, | ||||
| 		Destructor_Fwd, | ||||
| 		Enum, | ||||
| 		Enum_Fwd, | ||||
| 		Enum_Body, | ||||
| 		Enum_Class, | ||||
| 		Enum_Class_Fwd, | ||||
| 		Execution, | ||||
| 		Export_Body, | ||||
| 		Extern_Linkage, | ||||
| 		Extern_Linkage_Body, | ||||
| 		Friend, | ||||
| 		Function, | ||||
| 		Function_Fwd, | ||||
| 		Function_Body, | ||||
| 		Global_Body, | ||||
| 		Module, | ||||
| 		Namespace, | ||||
| 		Namespace_Body, | ||||
| 		Operator, | ||||
| 		Operator_Fwd, | ||||
| 		Operator_Member, | ||||
| 		Operator_Member_Fwd, | ||||
| 		Operator_Cast, | ||||
| 		Operator_Cast_Fwd, | ||||
| 		Parameters, | ||||
| 		Preprocess_Define, | ||||
| 		Preprocess_Include, | ||||
| 		Preprocess_If, | ||||
| 		Preprocess_IfDef, | ||||
| 		Preprocess_IfNotDef, | ||||
| 		Preprocess_ElIf, | ||||
| 		Preprocess_Else, | ||||
| 		Preprocess_EndIf, | ||||
| 		Preprocess_Pragma, | ||||
| 		Specifiers, | ||||
| 		Struct, | ||||
| 		Struct_Fwd, | ||||
| 		Struct_Body, | ||||
| 		Template, | ||||
| 		Typedef, | ||||
| 		Typename, | ||||
| 		Union, | ||||
| 		Union_Body, | ||||
| 		Using, | ||||
| 		Using_Namespace, | ||||
| 		Variable, | ||||
| 		NumTypes | ||||
| 	CT_Invalid, | ||||
| 	CT_Untyped, | ||||
| 	CT_NewLine, | ||||
| 	CT_Comment, | ||||
| 	CT_Access_Private, | ||||
| 	CT_Access_Protected, | ||||
| 	CT_Access_Public, | ||||
| 	CT_PlatformAttributes, | ||||
| 	CT_Class, | ||||
| 	CT_Class_Fwd, | ||||
| 	CT_Class_Body, | ||||
| 	CT_Constructor, | ||||
| 	CT_Constructor_Fwd, | ||||
| 	CT_Destructor, | ||||
| 	CT_Destructor_Fwd, | ||||
| 	CT_Enum, | ||||
| 	CT_Enum_Fwd, | ||||
| 	CT_Enum_Body, | ||||
| 	CT_Enum_Class, | ||||
| 	CT_Enum_Class_Fwd, | ||||
| 	CT_Execution, | ||||
| 	CT_Export_Body, | ||||
| 	CT_Extern_Linkage, | ||||
| 	CT_Extern_Linkage_Body, | ||||
| 	CT_Friend, | ||||
| 	CT_Function, | ||||
| 	CT_Function_Fwd, | ||||
| 	CT_Function_Body, | ||||
| 	CT_Global_Body, | ||||
| 	CT_Module, | ||||
| 	CT_Namespace, | ||||
| 	CT_Namespace_Body, | ||||
| 	CT_Operator, | ||||
| 	CT_Operator_Fwd, | ||||
| 	CT_Operator_Member, | ||||
| 	CT_Operator_Member_Fwd, | ||||
| 	CT_Operator_Cast, | ||||
| 	CT_Operator_Cast_Fwd, | ||||
| 	CT_Parameters, | ||||
| 	CT_Preprocess_Define, | ||||
| 	CT_Preprocess_Include, | ||||
| 	CT_Preprocess_If, | ||||
| 	CT_Preprocess_IfDef, | ||||
| 	CT_Preprocess_IfNotDef, | ||||
| 	CT_Preprocess_ElIf, | ||||
| 	CT_Preprocess_Else, | ||||
| 	CT_Preprocess_EndIf, | ||||
| 	CT_Preprocess_Pragma, | ||||
| 	CT_Specifiers, | ||||
| 	CT_Struct, | ||||
| 	CT_Struct_Fwd, | ||||
| 	CT_Struct_Body, | ||||
| 	CT_Template, | ||||
| 	CT_Typedef, | ||||
| 	CT_Typename, | ||||
| 	CT_Union, | ||||
| 	CT_Union_Body, | ||||
| 	CT_Using, | ||||
| 	CT_Using_Namespace, | ||||
| 	CT_Variable, | ||||
| 	CT_NumTypes | ||||
| }; | ||||
| typedef enum CodeType_Def CodeType; | ||||
|  | ||||
| 	StrC to_str( Type type ) | ||||
| inline StrC to_str( CodeType type ) | ||||
| { | ||||
| 	local_persist StrC lookup[] { | ||||
| 		{ sizeof( "Invalid" ),             "Invalid"             }, | ||||
| @@ -138,7 +137,3 @@ namespace ECode | ||||
| 	}; | ||||
| 	return lookup[type]; | ||||
| } | ||||
|  | ||||
| }    // namespace ECode | ||||
|  | ||||
| using CodeT = ECode::Type; | ||||
|   | ||||
| @@ -5,61 +5,60 @@ | ||||
|  | ||||
| // This file was generated automatially by gencpp's bootstrap.cpp (See: https://github.com/Ed94/gencpp) | ||||
|  | ||||
| namespace EOperator | ||||
| enum Operator_Def : u32 | ||||
| { | ||||
| 	enum Type : u32 | ||||
| 	{ | ||||
| 		Invalid, | ||||
| 		Assign, | ||||
| 		Assign_Add, | ||||
| 		Assign_Subtract, | ||||
| 		Assign_Multiply, | ||||
| 		Assign_Divide, | ||||
| 		Assign_Modulo, | ||||
| 		Assign_BAnd, | ||||
| 		Assign_BOr, | ||||
| 		Assign_BXOr, | ||||
| 		Assign_LShift, | ||||
| 		Assign_RShift, | ||||
| 		Increment, | ||||
| 		Decrement, | ||||
| 		Unary_Plus, | ||||
| 		Unary_Minus, | ||||
| 		UnaryNot, | ||||
| 		Add, | ||||
| 		Subtract, | ||||
| 		Multiply, | ||||
| 		Divide, | ||||
| 		Modulo, | ||||
| 		BNot, | ||||
| 		BAnd, | ||||
| 		BOr, | ||||
| 		BXOr, | ||||
| 		LShift, | ||||
| 		RShift, | ||||
| 		LAnd, | ||||
| 		LOr, | ||||
| 		LEqual, | ||||
| 		LNot, | ||||
| 		Lesser, | ||||
| 		Greater, | ||||
| 		LesserEqual, | ||||
| 		GreaterEqual, | ||||
| 		Subscript, | ||||
| 		Indirection, | ||||
| 		AddressOf, | ||||
| 		MemberOfPointer, | ||||
| 		PtrToMemOfPtr, | ||||
| 		FunctionCall, | ||||
| 		Comma, | ||||
| 		New, | ||||
| 		NewArray, | ||||
| 		Delete, | ||||
| 		DeleteArray, | ||||
| 	Op_Invalid, | ||||
| 	Op_Assign, | ||||
| 	Op_Assign_Add, | ||||
| 	Op_Assign_Subtract, | ||||
| 	Op_Assign_Multiply, | ||||
| 	Op_Assign_Divide, | ||||
| 	Op_Assign_Modulo, | ||||
| 	Op_Assign_BAnd, | ||||
| 	Op_Assign_BOr, | ||||
| 	Op_Assign_BXOr, | ||||
| 	Op_Assign_LShift, | ||||
| 	Op_Assign_RShift, | ||||
| 	Op_Increment, | ||||
| 	Op_Decrement, | ||||
| 	Op_Unary_Plus, | ||||
| 	Op_Unary_Minus, | ||||
| 	Op_UnaryNot, | ||||
| 	Op_Add, | ||||
| 	Op_Subtract, | ||||
| 	Op_Multiply, | ||||
| 	Op_Divide, | ||||
| 	Op_Modulo, | ||||
| 	Op_BNot, | ||||
| 	Op_BAnd, | ||||
| 	Op_BOr, | ||||
| 	Op_BXOr, | ||||
| 	Op_LShift, | ||||
| 	Op_RShift, | ||||
| 	Op_LAnd, | ||||
| 	Op_LOr, | ||||
| 	Op_LEqual, | ||||
| 	Op_LNot, | ||||
| 	Op_Lesser, | ||||
| 	Op_Greater, | ||||
| 	Op_LesserEqual, | ||||
| 	Op_GreaterEqual, | ||||
| 	Op_Subscript, | ||||
| 	Op_Indirection, | ||||
| 	Op_AddressOf, | ||||
| 	Op_MemberOfPointer, | ||||
| 	Op_PtrToMemOfPtr, | ||||
| 	Op_FunctionCall, | ||||
| 	Op_Comma, | ||||
| 	Op_New, | ||||
| 	Op_NewArray, | ||||
| 	Op_Delete, | ||||
| 	Op_DeleteArray, | ||||
| 	NumOps | ||||
| }; | ||||
| typedef enum Operator_Def Operator; | ||||
|  | ||||
| 	StrC to_str( Type op ) | ||||
| inline StrC to_str( Operator op ) | ||||
| { | ||||
| 	local_persist StrC lookup[] { | ||||
| 		{ sizeof( "INVALID" ),  "INVALID"  }, | ||||
| @@ -112,7 +111,3 @@ namespace EOperator | ||||
| 	}; | ||||
| 	return lookup[op]; | ||||
| } | ||||
|  | ||||
| }    // namespace EOperator | ||||
|  | ||||
| using OperatorT = EOperator::Type; | ||||
|   | ||||
| @@ -5,45 +5,44 @@ | ||||
|  | ||||
| // This file was generated automatially by gencpp's bootstrap.cpp (See: https://github.com/Ed94/gencpp) | ||||
|  | ||||
| namespace ESpecifier | ||||
| enum Specifier_Def : u32 | ||||
| { | ||||
| 	enum Type : u32 | ||||
| 	{ | ||||
| 		Invalid, | ||||
| 		Consteval, | ||||
| 		Constexpr, | ||||
| 		Constinit, | ||||
| 		Explicit, | ||||
| 		External_Linkage, | ||||
| 		ForceInline, | ||||
| 		Global, | ||||
| 		Inline, | ||||
| 		Internal_Linkage, | ||||
| 		Local_Persist, | ||||
| 		Mutable, | ||||
| 		NeverInline, | ||||
| 		Ptr, | ||||
| 		Ref, | ||||
| 		Register, | ||||
| 		RValue, | ||||
| 		Static, | ||||
| 		Thread_Local, | ||||
| 		Virtual, | ||||
| 		Const, | ||||
| 		Final, | ||||
| 		NoExceptions, | ||||
| 		Override, | ||||
| 		Pure, | ||||
| 		Volatile, | ||||
| 		NumSpecifiers | ||||
| 	Spec_Invalid, | ||||
| 	Spec_Consteval, | ||||
| 	Spec_Constexpr, | ||||
| 	Spec_Constinit, | ||||
| 	Spec_Explicit, | ||||
| 	Spec_External_Linkage, | ||||
| 	Spec_ForceInline, | ||||
| 	Spec_Global, | ||||
| 	Spec_Inline, | ||||
| 	Spec_Internal_Linkage, | ||||
| 	Spec_Local_Persist, | ||||
| 	Spec_Mutable, | ||||
| 	Spec_NeverInline, | ||||
| 	Spec_Ptr, | ||||
| 	Spec_Ref, | ||||
| 	Spec_Register, | ||||
| 	Spec_RValue, | ||||
| 	Spec_Static, | ||||
| 	Spec_Thread_Local, | ||||
| 	Spec_Virtual, | ||||
| 	Spec_Const, | ||||
| 	Spec_Final, | ||||
| 	Spec_NoExceptions, | ||||
| 	Spec_Override, | ||||
| 	Spec_Pure, | ||||
| 	Spec_Volatile, | ||||
| 	Spec_NumSpecifiers | ||||
| }; | ||||
| typedef enum Specifier_Def Specifier; | ||||
|  | ||||
| 	bool is_trailing( Type specifier ) | ||||
| inline bool is_trailing( Specifier specifier ) | ||||
| { | ||||
| 		return specifier > Virtual; | ||||
| 	return specifier > Spec_Virtual; | ||||
| } | ||||
|  | ||||
| 	StrC to_str( Type type ) | ||||
| inline StrC to_str( Specifier type ) | ||||
| { | ||||
| 	local_persist StrC lookup[] { | ||||
| 		{ sizeof( "INVALID" ),       "INVALID"       }, | ||||
| @@ -76,23 +75,19 @@ namespace ESpecifier | ||||
| 	return lookup[type]; | ||||
| } | ||||
|  | ||||
| 	Type to_type( StrC str ) | ||||
| inline Specifier to_specifier( StrC str ) | ||||
| { | ||||
| 		local_persist u32 keymap[NumSpecifiers]; | ||||
| 		do_once_start for ( u32 index = 0; index < NumSpecifiers; index++ ) | ||||
| 	local_persist u32 keymap[Spec_NumSpecifiers]; | ||||
| 	do_once_start for ( u32 index = 0; index < Spec_NumSpecifiers; index++ ) | ||||
| 	{ | ||||
| 			StrC enum_str = to_str( (Type)index ); | ||||
| 		StrC enum_str = to_str( (Specifier)index ); | ||||
| 		keymap[index] = crc32( enum_str.Ptr, enum_str.Len - 1 ); | ||||
| 	} | ||||
| 	do_once_end u32 hash = crc32( str.Ptr, str.Len ); | ||||
| 		for ( u32 index = 0; index < NumSpecifiers; index++ ) | ||||
| 	for ( u32 index = 0; index < Spec_NumSpecifiers; index++ ) | ||||
| 	{ | ||||
| 		if ( keymap[index] == hash ) | ||||
| 				return (Type)index; | ||||
| 			return (Specifier)index; | ||||
| 	} | ||||
| 		return Invalid; | ||||
| 	return Spec_Invalid; | ||||
| } | ||||
|  | ||||
| }    // namespace ESpecifier | ||||
|  | ||||
| using SpecifierT = ESpecifier::Type; | ||||
|   | ||||
| @@ -5,115 +5,113 @@ | ||||
|  | ||||
| // This file was generated automatially by gencpp's bootstrap.cpp (See: https://github.com/Ed94/gencpp) | ||||
|  | ||||
| namespace parser | ||||
| { | ||||
| 	namespace ETokType | ||||
| 	{ | ||||
| #define GEN_DEFINE_ATTRIBUTE_TOKENS Entry( Attribute_API_Export, "GEN_API_Export_Code" ) Entry( Attribute_API_Import, "GEN_API_Import_Code" ) | ||||
| GEN_NS_PARSER_BEGIN | ||||
| #define GEN_DEFINE_ATTRIBUTE_TOKENS Entry( Tok_Attribute_API_Export, "GEN_API_Export_Code" ) Entry( Tok_Attribute_API_Import, "GEN_API_Import_Code" ) | ||||
|  | ||||
| 		enum Type : u32 | ||||
| enum TokType_Def : u32 | ||||
| { | ||||
| 			Invalid, | ||||
| 			Access_Private, | ||||
| 			Access_Protected, | ||||
| 			Access_Public, | ||||
| 			Access_MemberSymbol, | ||||
| 			Access_StaticSymbol, | ||||
| 			Ampersand, | ||||
| 			Ampersand_DBL, | ||||
| 			Assign_Classifer, | ||||
| 			Attribute_Open, | ||||
| 			Attribute_Close, | ||||
| 			BraceCurly_Open, | ||||
| 			BraceCurly_Close, | ||||
| 			BraceSquare_Open, | ||||
| 			BraceSquare_Close, | ||||
| 			Capture_Start, | ||||
| 			Capture_End, | ||||
| 			Comment, | ||||
| 			Comment_End, | ||||
| 			Comment_Start, | ||||
| 			Char, | ||||
| 			Comma, | ||||
| 			Decl_Class, | ||||
| 			Decl_GNU_Attribute, | ||||
| 			Decl_MSVC_Attribute, | ||||
| 			Decl_Enum, | ||||
| 			Decl_Extern_Linkage, | ||||
| 			Decl_Friend, | ||||
| 			Decl_Module, | ||||
| 			Decl_Namespace, | ||||
| 			Decl_Operator, | ||||
| 			Decl_Struct, | ||||
| 			Decl_Template, | ||||
| 			Decl_Typedef, | ||||
| 			Decl_Using, | ||||
| 			Decl_Union, | ||||
| 			Identifier, | ||||
| 			Module_Import, | ||||
| 			Module_Export, | ||||
| 			NewLine, | ||||
| 			Number, | ||||
| 			Operator, | ||||
| 			Preprocess_Hash, | ||||
| 			Preprocess_Define, | ||||
| 			Preprocess_If, | ||||
| 			Preprocess_IfDef, | ||||
| 			Preprocess_IfNotDef, | ||||
| 			Preprocess_ElIf, | ||||
| 			Preprocess_Else, | ||||
| 			Preprocess_EndIf, | ||||
| 			Preprocess_Include, | ||||
| 			Preprocess_Pragma, | ||||
| 			Preprocess_Content, | ||||
| 			Preprocess_Macro, | ||||
| 			Preprocess_Unsupported, | ||||
| 			Spec_Alignas, | ||||
| 			Spec_Const, | ||||
| 			Spec_Consteval, | ||||
| 			Spec_Constexpr, | ||||
| 			Spec_Constinit, | ||||
| 			Spec_Explicit, | ||||
| 			Spec_Extern, | ||||
| 			Spec_Final, | ||||
| 			Spec_ForceInline, | ||||
| 			Spec_Global, | ||||
| 			Spec_Inline, | ||||
| 			Spec_Internal_Linkage, | ||||
| 			Spec_LocalPersist, | ||||
| 			Spec_Mutable, | ||||
| 			Spec_NeverInline, | ||||
| 			Spec_Override, | ||||
| 			Spec_Static, | ||||
| 			Spec_ThreadLocal, | ||||
| 			Spec_Volatile, | ||||
| 			Spec_Virtual, | ||||
| 			Star, | ||||
| 			Statement_End, | ||||
| 			StaticAssert, | ||||
| 			String, | ||||
| 			Type_Typename, | ||||
| 			Type_Unsigned, | ||||
| 			Type_Signed, | ||||
| 			Type_Short, | ||||
| 			Type_Long, | ||||
| 			Type_bool, | ||||
| 			Type_char, | ||||
| 			Type_int, | ||||
| 			Type_double, | ||||
| 			Type_MS_int8, | ||||
| 			Type_MS_int16, | ||||
| 			Type_MS_int32, | ||||
| 			Type_MS_int64, | ||||
| 			Type_MS_W64, | ||||
| 			Varadic_Argument, | ||||
| 			__Attributes_Start, | ||||
| 			Attribute_API_Export, | ||||
| 			Attribute_API_Import, | ||||
| 			NumTokens | ||||
| 	Tok_Invalid, | ||||
| 	Tok_Access_Private, | ||||
| 	Tok_Access_Protected, | ||||
| 	Tok_Access_Public, | ||||
| 	Tok_Access_MemberSymbol, | ||||
| 	Tok_Access_StaticSymbol, | ||||
| 	Tok_Ampersand, | ||||
| 	Tok_Ampersand_DBL, | ||||
| 	Tok_Assign_Classifer, | ||||
| 	Tok_Attribute_Open, | ||||
| 	Tok_Attribute_Close, | ||||
| 	Tok_BraceCurly_Open, | ||||
| 	Tok_BraceCurly_Close, | ||||
| 	Tok_BraceSquare_Open, | ||||
| 	Tok_BraceSquare_Close, | ||||
| 	Tok_Capture_Start, | ||||
| 	Tok_Capture_End, | ||||
| 	Tok_Comment, | ||||
| 	Tok_Comment_End, | ||||
| 	Tok_Comment_Start, | ||||
| 	Tok_Char, | ||||
| 	Tok_Comma, | ||||
| 	Tok_Decl_Class, | ||||
| 	Tok_Decl_GNU_Attribute, | ||||
| 	Tok_Decl_MSVC_Attribute, | ||||
| 	Tok_Decl_Enum, | ||||
| 	Tok_Decl_Extern_Linkage, | ||||
| 	Tok_Decl_Friend, | ||||
| 	Tok_Decl_Module, | ||||
| 	Tok_Decl_Namespace, | ||||
| 	Tok_Decl_Operator, | ||||
| 	Tok_Decl_Struct, | ||||
| 	Tok_Decl_Template, | ||||
| 	Tok_Decl_Typedef, | ||||
| 	Tok_Decl_Using, | ||||
| 	Tok_Decl_Union, | ||||
| 	Tok_Identifier, | ||||
| 	Tok_Module_Import, | ||||
| 	Tok_Module_Export, | ||||
| 	Tok_NewLine, | ||||
| 	Tok_Number, | ||||
| 	Tok_Operator, | ||||
| 	Tok_Preprocess_Hash, | ||||
| 	Tok_Preprocess_Define, | ||||
| 	Tok_Preprocess_If, | ||||
| 	Tok_Preprocess_IfDef, | ||||
| 	Tok_Preprocess_IfNotDef, | ||||
| 	Tok_Preprocess_ElIf, | ||||
| 	Tok_Preprocess_Else, | ||||
| 	Tok_Preprocess_EndIf, | ||||
| 	Tok_Preprocess_Include, | ||||
| 	Tok_Preprocess_Pragma, | ||||
| 	Tok_Preprocess_Content, | ||||
| 	Tok_Preprocess_Macro, | ||||
| 	Tok_Preprocess_Unsupported, | ||||
| 	Tok_Spec_Alignas, | ||||
| 	Tok_Spec_Const, | ||||
| 	Tok_Spec_Consteval, | ||||
| 	Tok_Spec_Constexpr, | ||||
| 	Tok_Spec_Constinit, | ||||
| 	Tok_Spec_Explicit, | ||||
| 	Tok_Spec_Extern, | ||||
| 	Tok_Spec_Final, | ||||
| 	Tok_Spec_ForceInline, | ||||
| 	Tok_Spec_Global, | ||||
| 	Tok_Spec_Inline, | ||||
| 	Tok_Spec_Internal_Linkage, | ||||
| 	Tok_Spec_LocalPersist, | ||||
| 	Tok_Spec_Mutable, | ||||
| 	Tok_Spec_NeverInline, | ||||
| 	Tok_Spec_Override, | ||||
| 	Tok_Spec_Static, | ||||
| 	Tok_Spec_ThreadLocal, | ||||
| 	Tok_Spec_Volatile, | ||||
| 	Tok_Spec_Virtual, | ||||
| 	Tok_Star, | ||||
| 	Tok_Statement_End, | ||||
| 	Tok_StaticAssert, | ||||
| 	Tok_String, | ||||
| 	Tok_Type_Typename, | ||||
| 	Tok_Type_Unsigned, | ||||
| 	Tok_Type_Signed, | ||||
| 	Tok_Type_Short, | ||||
| 	Tok_Type_Long, | ||||
| 	Tok_Type_bool, | ||||
| 	Tok_Type_char, | ||||
| 	Tok_Type_int, | ||||
| 	Tok_Type_double, | ||||
| 	Tok_Type_MS_int8, | ||||
| 	Tok_Type_MS_int16, | ||||
| 	Tok_Type_MS_int32, | ||||
| 	Tok_Type_MS_int64, | ||||
| 	Tok_Type_MS_W64, | ||||
| 	Tok_Varadic_Argument, | ||||
| 	Tok___Attributes_Start, | ||||
| 	Tok_Attribute_API_Export, | ||||
| 	Tok_Attribute_API_Import, | ||||
| 	Tok_NumTokens | ||||
| }; | ||||
| typedef enum TokType_Def TokType; | ||||
|  | ||||
| 		StrC to_str( Type type ) | ||||
| inline StrC to_str( TokType type ) | ||||
| { | ||||
| 	local_persist StrC lookup[] { | ||||
| 		{ sizeof( "__invalid__" ),         "__invalid__"         }, | ||||
| @@ -217,25 +215,21 @@ namespace parser | ||||
| 	return lookup[type]; | ||||
| } | ||||
|  | ||||
| 		Type to_type( StrC str ) | ||||
| inline TokType to_toktype( StrC str ) | ||||
| { | ||||
| 			local_persist u32 keymap[NumTokens]; | ||||
| 			do_once_start for ( u32 index = 0; index < NumTokens; index++ ) | ||||
| 	local_persist u32 keymap[Tok_NumTokens]; | ||||
| 	do_once_start for ( u32 index = 0; index < Tok_NumTokens; index++ ) | ||||
| 	{ | ||||
| 				StrC enum_str = to_str( (Type)index ); | ||||
| 		StrC enum_str = to_str( (TokType)index ); | ||||
| 		keymap[index] = crc32( enum_str.Ptr, enum_str.Len - 1 ); | ||||
| 	} | ||||
| 	do_once_end u32 hash = crc32( str.Ptr, str.Len ); | ||||
| 			for ( u32 index = 0; index < NumTokens; index++ ) | ||||
| 	for ( u32 index = 0; index < Tok_NumTokens; index++ ) | ||||
| 	{ | ||||
| 		if ( keymap[index] == hash ) | ||||
| 					return (Type)index; | ||||
| 			return (TokType)index; | ||||
| 	} | ||||
| 			return Invalid; | ||||
| 	return Tok_Invalid; | ||||
| } | ||||
|  | ||||
| 	}    // namespace ETokType | ||||
|  | ||||
| 	using TokType = ETokType::Type; | ||||
|  | ||||
| }    // namespace parser | ||||
| GEN_NS_PARSER_END | ||||
|   | ||||
| @@ -42,7 +42,7 @@ constexpr s32 InitSize_DataArrays = 16; | ||||
|  | ||||
| // NOTE: This limits the maximum size of an allocation | ||||
| // If you are generating a string larger than this, increase the size of the bucket here. | ||||
| constexpr uw  Global_BucketSize         = GEN_GLOBAL_BUCKET_SIZE; | ||||
| constexpr usize  Global_BucketSize         = GEN_GLOBAL_BUCKET_SIZE; | ||||
| constexpr s32 CodePool_NumBlocks        = GEN_CODEPOOL_NUM_BLOCKS; | ||||
| constexpr s32 SizePer_StringArena       = GEN_SIZE_PER_STRING_ARENA; | ||||
|  | ||||
| @@ -63,7 +63,6 @@ extern CodeAttributes attrib_api_import; | ||||
| extern Code module_global_fragment; | ||||
| extern Code module_private_fragment; | ||||
|  | ||||
| // Exposed, but this is really used for parsing. | ||||
| extern Code fmt_newline; | ||||
|  | ||||
| extern CodePragma pragma_once; | ||||
| @@ -98,45 +97,46 @@ extern CodeSpecifiers spec_thread_local; | ||||
| extern CodeSpecifiers spec_virtual; | ||||
| extern CodeSpecifiers spec_volatile; | ||||
|  | ||||
| extern CodeType t_empty; // Used with varaidc parameters. (Exposing just in case its useful for another circumstance) | ||||
| extern CodeType t_auto; | ||||
| extern CodeType t_void; | ||||
| extern CodeType t_int; | ||||
| extern CodeType t_bool; | ||||
| extern CodeType t_char; | ||||
| extern CodeType t_wchar_t; | ||||
| extern CodeType t_class; | ||||
| extern CodeType t_typename; | ||||
| extern CodeTypename t_empty; // Used with varaidc parameters. (Exposing just in case its useful for another circumstance) | ||||
| extern CodeTypename t_auto; | ||||
| extern CodeTypename t_void; | ||||
| extern CodeTypename t_int; | ||||
| extern CodeTypename t_bool; | ||||
| extern CodeTypename t_char; | ||||
| extern CodeTypename t_wchar_t; | ||||
| extern CodeTypename t_class; | ||||
| extern CodeTypename t_typename; | ||||
|  | ||||
| #ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS | ||||
| 	// Predefined typename codes. Are set to readonly and are setup during gen::init() | ||||
|  | ||||
| 	extern CodeType t_b32; | ||||
| 	extern CodeTypename t_b32; | ||||
|  | ||||
| 	extern CodeType t_s8; | ||||
| 	extern CodeType t_s16; | ||||
| 	extern CodeType t_s32; | ||||
| 	extern CodeType t_s64; | ||||
| 	extern CodeTypename t_s8; | ||||
| 	extern CodeTypename t_s16; | ||||
| 	extern CodeTypename t_s32; | ||||
| 	extern CodeTypename t_s64; | ||||
|  | ||||
| 	extern CodeType t_u8; | ||||
| 	extern CodeType t_u16; | ||||
| 	extern CodeType t_u32; | ||||
| 	extern CodeType t_u64; | ||||
| 	extern CodeTypename t_u8; | ||||
| 	extern CodeTypename t_u16; | ||||
| 	extern CodeTypename t_u32; | ||||
| 	extern CodeTypename t_u64; | ||||
|  | ||||
| 	extern CodeType t_sw; | ||||
| 	extern CodeType t_uw; | ||||
| 	extern CodeTypename t_ssize; | ||||
| 	extern CodeTypename t_usize; | ||||
|  | ||||
| 	extern CodeType t_f32; | ||||
| 	extern CodeType t_f64; | ||||
| 	extern CodeTypename t_f32; | ||||
| 	extern CodeTypename t_f64; | ||||
| #endif | ||||
|  | ||||
| #pragma endregion Constants | ||||
|  | ||||
| #pragma region Macros | ||||
|  | ||||
| #ifndef token_fmt | ||||
| #	define gen_main main | ||||
|  | ||||
| #	define __ NoCode | ||||
| #	define __ NullCode | ||||
|  | ||||
| 	//	Convienence for defining any name used with the gen api. | ||||
| 	//  Lets you provide the length and string literal to the functions without the need for the DSL. | ||||
| @@ -152,22 +152,23 @@ 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 | ||||
|  | ||||
| // Used by the lexer to persistently treat all these identifiers as preprocessor defines. | ||||
| // Populate with strings via gen::get_cached_string. | ||||
| // Functional defines must have format: id( ;at minimum to indicate that the define is only valid with arguments. | ||||
| extern Array< StringCached > PreprocessorDefines; | ||||
| extern Array(StringCached) PreprocessorDefines; | ||||
|  | ||||
| #ifdef GEN_EXPOSE_BACKEND | ||||
|  | ||||
| 	// Global allocator used for data with process lifetime. | ||||
| 	extern AllocatorInfo  GlobalAllocator; | ||||
| 	extern Array< Arena > Global_AllocatorBuckets; | ||||
| 	extern Array(Arena) Global_AllocatorBuckets; | ||||
|  | ||||
| 	extern Array< Pool >  CodePools; | ||||
| 	extern Array< Arena > StringArenas; | ||||
| 	extern Array(Pool)  CodePools; | ||||
| 	extern Array(Arena) StringArenas; | ||||
|  | ||||
| 	extern StringTable StringCache; | ||||
|  | ||||
|   | ||||
| @@ -17,15 +17,3 @@ | ||||
| #ifndef GEN_ROLL_OWN_DEPENDENCIES | ||||
| #	include "gen.dep.hpp" | ||||
| #endif | ||||
|  | ||||
| #ifndef GEN_NS_BEGIN | ||||
| #	ifdef GEN_DONT_USE_NAMESPACE | ||||
| #		define GEN_NS | ||||
| #		define GEN_NS_BEGIN | ||||
| #		define GEN_NS_END | ||||
| #	else | ||||
| #		define GEN_NS       gen:: | ||||
| #		define GEN_NS_BEGIN namespace gen { | ||||
| #		define GEN_NS_END   } | ||||
| #	endif | ||||
| #endif | ||||
|   | ||||
| @@ -3,94 +3,174 @@ | ||||
| #include "interface.hpp" | ||||
| #endif | ||||
|  | ||||
| void AST::append( AST* other ) | ||||
| #pragma region Code | ||||
| inline | ||||
| void append( Code self, Code other ) | ||||
| { | ||||
| 	GEN_ASSERT(self.ast  != nullptr); | ||||
| 	GEN_ASSERT(other.ast != 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; | ||||
| 	Code | ||||
| 	Current       = self->Back; | ||||
| 	Current->Next = other; | ||||
| 	other->Prev   = Current; | ||||
| 	Back          = other; | ||||
| 	NumEntries++; | ||||
| 	self->Back    = other; | ||||
| 	self->NumEntries++; | ||||
| } | ||||
|  | ||||
| Code& AST::entry( u32 idx ) | ||||
| inline | ||||
| bool is_body(Code self) | ||||
| { | ||||
| 	AST** current = & Front; | ||||
| 	GEN_ASSERT(self != nullptr); | ||||
| 	switch (self->Type) | ||||
| 	{ | ||||
| 		case CT_Enum_Body: | ||||
| 		case CT_Class_Body: | ||||
| 		case CT_Union_Body: | ||||
| 		case CT_Export_Body: | ||||
| 		case CT_Global_Body: | ||||
| 		case CT_Struct_Body: | ||||
| 		case CT_Function_Body: | ||||
| 		case CT_Namespace_Body: | ||||
| 		case CT_Extern_Linkage_Body: | ||||
| 			return true; | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
| inline | ||||
| Code* entry( Code self, u32 idx ) | ||||
| { | ||||
| 	GEN_ASSERT(self.ast != nullptr); | ||||
| 	Code* 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); | ||||
| } | ||||
|  | ||||
| bool AST::has_entries() | ||||
| inline | ||||
| bool is_valid(Code self) | ||||
| { | ||||
| 	return NumEntries; | ||||
| 	return self.ast != nullptr && self.ast->Type != CT_Invalid; | ||||
| } | ||||
|  | ||||
| char const* AST::type_str() | ||||
| inline | ||||
| bool has_entries(AST* self) | ||||
| { | ||||
| 	return ECode::to_str( Type ); | ||||
| 	GEN_ASSERT(self != nullptr); | ||||
| 	return self->NumEntries > 0; | ||||
| } | ||||
|  | ||||
| AST::operator Code() | ||||
| inline | ||||
| void set_global(Code self) | ||||
| { | ||||
| 	return { this }; | ||||
| 	if ( self.ast == nullptr ) | ||||
| 	{ | ||||
| 		log_failure("Code::set_global: Cannot set code as global, AST is null!"); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	self->Parent.ast = Code_Global.ast; | ||||
| } | ||||
| inline | ||||
| Code& Code::operator ++() | ||||
| { | ||||
| 	if ( ast ) | ||||
| 		ast = ast->Next; | ||||
| 		ast = ast->Next.ast; | ||||
|  | ||||
| 	return * this; | ||||
| } | ||||
|  | ||||
| void CodeClass::add_interface( CodeType type ) | ||||
| inline | ||||
| char const* type_str(Code self) | ||||
| { | ||||
| 	CodeType possible_slot = ast->ParentType; | ||||
| 	GEN_ASSERT(self != nullptr); | ||||
| 	return to_str( self->Type ); | ||||
| } | ||||
| #pragma endregion Code | ||||
|  | ||||
| #pragma region CodeBody | ||||
| inline | ||||
| void append( CodeBody self, Code other ) | ||||
| { | ||||
| 	GEN_ASSERT(other.ast != nullptr); | ||||
|  | ||||
| 	if (is_body(other)) { | ||||
| 		append( self, cast(CodeBody, other) ); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	append( cast(Code, self), other ); | ||||
| } | ||||
| inline | ||||
| void append( CodeBody self, CodeBody body ) | ||||
| { | ||||
| 	GEN_ASSERT(self.ast != nullptr); | ||||
|  | ||||
| 	for ( Code entry : body ) { | ||||
| 		append( self, entry ); | ||||
| 	} | ||||
| } | ||||
| inline | ||||
| Code begin( CodeBody body) { | ||||
| 	if ( body.ast ) | ||||
| 		return { rcast( AST*, body.ast)->Front }; | ||||
| 	return { nullptr }; | ||||
| } | ||||
| inline | ||||
| Code end(CodeBody body ){ | ||||
| 	return { rcast(AST*, body.ast)->Back->Next }; | ||||
| } | ||||
| #pragma endregion CodeBody | ||||
|  | ||||
| #pragma region CodeClass | ||||
| inline | ||||
| void add_interface( CodeClass self, CodeTypename type ) | ||||
| { | ||||
| 	GEN_ASSERT(self.ast !=nullptr); | ||||
| 	CodeTypename possible_slot = self->ParentType; | ||||
| 	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; | ||||
| 		self->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. | ||||
| 	} | ||||
|  | ||||
| 	while ( possible_slot.ast != nullptr ) | ||||
| 	{ | ||||
| 		possible_slot.ast = (AST_Type*) possible_slot->Next.ast; | ||||
| 		possible_slot.ast = (AST_Typename*) possible_slot->Next.ast; | ||||
| 	} | ||||
|  | ||||
| 	possible_slot.ast = type.ast; | ||||
| } | ||||
| #pragma endregion CodeClass | ||||
|  | ||||
| void CodeParam::append( CodeParam other ) | ||||
| #pragma region CodeParam | ||||
| inline | ||||
| void append( CodeParam appendee, CodeParam other ) | ||||
| { | ||||
| 	AST* self  = (AST*) ast; | ||||
| 	AST* entry = (AST*) other.ast; | ||||
| 	GEN_ASSERT(appendee.ast != nullptr); | ||||
| 	Code self  = cast(Code, appendee); | ||||
| 	Code entry = cast(Code, other); | ||||
|  | ||||
| 	if ( entry->Parent ) | ||||
| 		entry = entry->duplicate(); | ||||
| 		entry = GEN_NS duplicate( entry ); | ||||
|  | ||||
| 	entry->Parent = self; | ||||
|  | ||||
| @@ -106,71 +186,177 @@ void CodeParam::append( CodeParam other ) | ||||
| 	self->Last       = entry; | ||||
| 	self->NumEntries++; | ||||
| } | ||||
|  | ||||
| CodeParam CodeParam::get( s32 idx ) | ||||
| inline | ||||
| CodeParam get(CodeParam self, s32 idx ) | ||||
| { | ||||
| 	CodeParam param = *this; | ||||
| 	GEN_ASSERT(self.ast != nullptr); | ||||
| 	CodeParam param = * self; | ||||
| 	do | ||||
| 	{ | ||||
| 		if ( ! ++ param ) | ||||
| 			return { nullptr }; | ||||
|  | ||||
| 		return { (AST_Param*) param.raw()->Next }; | ||||
| 		param = cast(Code, param)->Next; | ||||
| 	} | ||||
| 	while ( --idx ); | ||||
|  | ||||
| 	return { nullptr }; | ||||
| 	return param; | ||||
| } | ||||
|  | ||||
| bool CodeParam::has_entries() | ||||
| inline | ||||
| bool has_entries(CodeParam self) | ||||
| { | ||||
| 	return ast->NumEntries > 0; | ||||
| 	GEN_ASSERT(self.ast != nullptr); | ||||
| 	return self->NumEntries > 0; | ||||
| } | ||||
|  | ||||
| inline | ||||
| CodeParam& CodeParam::operator ++() | ||||
| { | ||||
| 	ast = ast->Next.ast; | ||||
| 	return * this; | ||||
| } | ||||
|  | ||||
| void CodeStruct::add_interface( CodeType type ) | ||||
| inline | ||||
| CodeParam begin(CodeParam params) | ||||
| { | ||||
| 	CodeType possible_slot = ast->ParentType; | ||||
| 	if ( params.ast ) | ||||
| 		return { params.ast }; | ||||
|  | ||||
| 	return { nullptr }; | ||||
| } | ||||
| inline | ||||
| CodeParam end(CodeParam params) | ||||
| { | ||||
| 	// return { (AST_Param*) rcast( AST*, ast)->Last }; | ||||
| 	return { nullptr }; | ||||
| } | ||||
| #pragma endregion CodeParam | ||||
|  | ||||
| #pragma region CodeSpecifiers | ||||
| inline | ||||
| bool append(CodeSpecifiers self, Specifier spec ) | ||||
| { | ||||
| 	if ( self.ast == nullptr ) | ||||
| 	{ | ||||
| 		log_failure("CodeSpecifiers: Attempted to append to a null specifiers AST!"); | ||||
| 		return false; | ||||
| 	} | ||||
| 	if ( self->NumEntries == AST_ArrSpecs_Cap ) | ||||
| 	{ | ||||
| 		log_failure("CodeSpecifiers: Attempted to append over %d specifiers to a specifiers AST!", AST_ArrSpecs_Cap ); | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	self->ArrSpecs[ self->NumEntries ] = spec; | ||||
| 	self->NumEntries++; | ||||
| 	return true; | ||||
| } | ||||
| inline | ||||
| s32 has(CodeSpecifiers self, Specifier spec) | ||||
| { | ||||
| 	GEN_ASSERT(self.ast != nullptr); | ||||
| 	for ( s32 idx = 0; idx < self->NumEntries; idx++ ) { | ||||
| 		if ( self->ArrSpecs[ idx ] == spec ) | ||||
| 			return idx; | ||||
| 	} | ||||
| 	return -1; | ||||
| } | ||||
| inline | ||||
| s32 remove( CodeSpecifiers self, Specifier to_remove ) | ||||
| { | ||||
| 	AST_Specifiers* ast = self.ast; | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		log_failure("CodeSpecifiers: Attempted to append to a null specifiers AST!"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	if ( self->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 < self->NumEntries; ++ curr, ++ next) | ||||
| 	{ | ||||
| 		Specifier spec = self->ArrSpecs[next]; | ||||
| 		if (spec == to_remove) | ||||
| 		{ | ||||
| 			result = next; | ||||
|  | ||||
| 			next ++; | ||||
| 			if (next >= self->NumEntries) | ||||
| 				break; | ||||
|  | ||||
| 			spec = self->ArrSpecs[next]; | ||||
| 		} | ||||
|  | ||||
| 		self->ArrSpecs[ curr ] = spec; | ||||
| 	} | ||||
|  | ||||
| 	if (result > -1) { | ||||
| 		self->NumEntries --; | ||||
| 	} | ||||
| 	return result; | ||||
| } | ||||
| inline | ||||
| Specifier* begin(CodeSpecifiers self) | ||||
| { | ||||
| 	if ( self.ast ) | ||||
| 		return & self->ArrSpecs[0]; | ||||
|  | ||||
| 	return nullptr; | ||||
| } | ||||
| inline | ||||
| Specifier* end(CodeSpecifiers self) | ||||
| { | ||||
| 	return self->ArrSpecs + self->NumEntries; | ||||
| } | ||||
| #pragma endregion CodeSpecifiers | ||||
|  | ||||
| #pragma region CodeStruct | ||||
| inline | ||||
| void add_interface(CodeStruct self, CodeTypename type ) | ||||
| { | ||||
| 	CodeTypename possible_slot = self->ParentType; | ||||
| 	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; | ||||
| 		self->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. | ||||
| 	} | ||||
|  | ||||
| 	while ( possible_slot.ast != nullptr ) | ||||
| 	{ | ||||
| 		possible_slot.ast = (AST_Type*) possible_slot->Next.ast; | ||||
| 		possible_slot.ast = (AST_Typename*) possible_slot->Next.ast; | ||||
| 	} | ||||
|  | ||||
| 	possible_slot.ast = type.ast; | ||||
| } | ||||
| #pragma endregion Code | ||||
|  | ||||
| CodeBody def_body( CodeT type ) | ||||
| #pragma region Interface | ||||
| inline | ||||
| CodeBody def_body( CodeType type ) | ||||
| { | ||||
| 	switch ( type ) | ||||
| 	{ | ||||
| 		using namespace ECode; | ||||
| 		case Class_Body: | ||||
| 		case Enum_Body: | ||||
| 		case Export_Body: | ||||
| 		case Extern_Linkage: | ||||
| 		case Function_Body: | ||||
| 		case Global_Body: | ||||
| 		case Namespace_Body: | ||||
| 		case Struct_Body: | ||||
| 		case Union_Body: | ||||
| 		case CT_Class_Body: | ||||
| 		case CT_Enum_Body: | ||||
| 		case CT_Export_Body: | ||||
| 		case CT_Extern_Linkage: | ||||
| 		case CT_Function_Body: | ||||
| 		case CT_Global_Body: | ||||
| 		case CT_Namespace_Body: | ||||
| 		case CT_Struct_Body: | ||||
| 		case CT_Union_Body: | ||||
| 			break; | ||||
|  | ||||
| 		default: | ||||
| 			log_failure( "def_body: Invalid type %s", (char const*)ECode::to_str(type) ); | ||||
| 			return (CodeBody)Code::Invalid; | ||||
| 			log_failure( "def_body: Invalid type %s", (char const*)to_str(type) ); | ||||
| 			return (CodeBody)Code_Invalid; | ||||
| 	} | ||||
|  | ||||
| 	Code | ||||
| @@ -179,7 +365,8 @@ CodeBody def_body( CodeT type ) | ||||
| 	return (CodeBody)result; | ||||
| } | ||||
|  | ||||
| StrC token_fmt_impl( sw num, ... ) | ||||
| inline | ||||
| StrC token_fmt_impl( ssize num, ... ) | ||||
| { | ||||
| 	local_persist thread_local | ||||
| 	char buf[GEN_PRINTF_MAXLEN] = { 0 }; | ||||
| @@ -187,8 +374,9 @@ StrC token_fmt_impl( sw num, ... ) | ||||
|  | ||||
| 	va_list va; | ||||
| 	va_start(va, num ); | ||||
| 	sw result = token_fmt_va(buf, GEN_PRINTF_MAXLEN, num, va); | ||||
| 	ssize result = token_fmt_va(buf, GEN_PRINTF_MAXLEN, num, va); | ||||
| 	va_end(va); | ||||
|  | ||||
| 	return { result, buf }; | ||||
| } | ||||
| #pragma endregion Interface | ||||
|   | ||||
| @@ -9,9 +9,9 @@ internal void deinit(); | ||||
| } | ||||
|  | ||||
| internal | ||||
| void* Global_Allocator_Proc( void* allocator_data, AllocType type, sw size, sw alignment, void* old_memory, sw old_size, u64 flags ) | ||||
| void* Global_Allocator_Proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ) | ||||
| { | ||||
| 	Arena* last = & Global_AllocatorBuckets.back(); | ||||
| 	Arena* last = array_back(Global_AllocatorBuckets); | ||||
|  | ||||
| 	switch ( type ) | ||||
| 	{ | ||||
| @@ -19,18 +19,18 @@ void* Global_Allocator_Proc( void* allocator_data, AllocType type, sw size, sw a | ||||
| 		{ | ||||
| 			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 ( ! array_append( Global_AllocatorBuckets, bucket ) ) | ||||
| 					GEN_FATAL( "Failed to append bucket to Global_AllocatorBuckets"); | ||||
|  | ||||
| 				last = & Global_AllocatorBuckets.back(); | ||||
| 				last = array_back(Global_AllocatorBuckets); | ||||
| 			} | ||||
|  | ||||
| 			return alloc_align( * last, size, alignment ); | ||||
| 			return alloc_align( arena_allocator_info(last), size, alignment ); | ||||
| 		} | ||||
| 		case EAllocation_FREE: | ||||
| 		{ | ||||
| @@ -46,15 +46,15 @@ void* Global_Allocator_Proc( void* allocator_data, AllocType type, sw size, sw a | ||||
| 		{ | ||||
| 			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 ( ! array_append( Global_AllocatorBuckets, bucket ) ) | ||||
| 					GEN_FATAL( "Failed to append bucket to Global_AllocatorBuckets"); | ||||
|  | ||||
| 				last = & Global_AllocatorBuckets.back(); | ||||
| 				last = array_back(Global_AllocatorBuckets); | ||||
| 			} | ||||
|  | ||||
| 			void* result = alloc_align( last->Backing, size, alignment ); | ||||
| @@ -74,78 +74,78 @@ void* Global_Allocator_Proc( void* allocator_data, AllocType type, sw size, sw a | ||||
| 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(); | ||||
| 	Code_Global->Name    = get_cached_string( txt("Global Code") ); | ||||
| 	Code_Global->Content = Code_Global->Name; | ||||
|  | ||||
| 	Code::Invalid = make_code(); | ||||
| 	Code::Invalid.set_global(); | ||||
| 	Code_Invalid = make_code(); | ||||
| 	set_global(Code_Invalid); | ||||
|  | ||||
| 	t_empty          = (CodeType) make_code(); | ||||
| 	t_empty->Type    = ECode::Typename; | ||||
| 	t_empty       = (CodeTypename) make_code(); | ||||
| 	t_empty->Type = CT_Typename; | ||||
| 	t_empty->Name = get_cached_string( txt("") ); | ||||
| 	t_empty.set_global(); | ||||
| 	set_global(t_empty); | ||||
|  | ||||
| 	access_private       = make_code(); | ||||
| 	access_private->Type = ECode::Access_Private; | ||||
| 	access_private->Type = CT_Access_Private; | ||||
| 	access_private->Name = get_cached_string( txt("private:\n") ); | ||||
| 	access_private.set_global(); | ||||
| 	set_global(access_private); | ||||
|  | ||||
| 	access_protected       = make_code(); | ||||
| 	access_protected->Type = ECode::Access_Protected; | ||||
| 	access_protected->Type = CT_Access_Protected; | ||||
| 	access_protected->Name = get_cached_string( txt("protected:\n") ); | ||||
| 	access_protected.set_global(); | ||||
| 	set_global(access_protected); | ||||
|  | ||||
| 	access_public       = make_code(); | ||||
| 	access_public->Type = ECode::Access_Public; | ||||
| 	access_public->Type = CT_Access_Public; | ||||
| 	access_public->Name = get_cached_string( txt("public:\n") ); | ||||
| 	access_public.set_global(); | ||||
| 	set_global(access_public); | ||||
|  | ||||
| 	attrib_api_export = def_attributes( code(GEN_API_Export_Code)); | ||||
| 	attrib_api_export.set_global(); | ||||
| 	set_global(attrib_api_export); | ||||
|  | ||||
| 	attrib_api_import = def_attributes( code(GEN_API_Import_Code)); | ||||
| 	attrib_api_import.set_global(); | ||||
| 	set_global(attrib_api_import); | ||||
|  | ||||
| 	module_global_fragment          = make_code(); | ||||
| 	module_global_fragment->Type    = ECode::Untyped; | ||||
| 	module_global_fragment->Type    = CT_Untyped; | ||||
| 	module_global_fragment->Name    = get_cached_string( txt("module;") ); | ||||
| 	module_global_fragment->Content = module_global_fragment->Name; | ||||
| 	module_global_fragment.set_global(); | ||||
| 	set_global(module_global_fragment); | ||||
|  | ||||
| 	module_private_fragment          = make_code(); | ||||
| 	module_private_fragment->Type    = ECode::Untyped; | ||||
| 	module_private_fragment->Type    = CT_Untyped; | ||||
| 	module_private_fragment->Name    = get_cached_string( txt("module : private;") ); | ||||
| 	module_private_fragment->Content = module_private_fragment->Name; | ||||
| 	module_private_fragment.set_global(); | ||||
| 	set_global(module_private_fragment); | ||||
|  | ||||
| 	fmt_newline = make_code(); | ||||
| 	fmt_newline->Type = ECode::NewLine; | ||||
| 	fmt_newline.set_global(); | ||||
| 	fmt_newline->Type = CT_NewLine; | ||||
| 	set_global(fmt_newline); | ||||
|  | ||||
| 	pragma_once          = (CodePragma) make_code(); | ||||
| 	pragma_once->Type    = ECode::Preprocess_Pragma; | ||||
| 	pragma_once->Type    = CT_Preprocess_Pragma; | ||||
| 	pragma_once->Name    = get_cached_string( txt("once") ); | ||||
| 	pragma_once->Content = pragma_once->Name; | ||||
| 	pragma_once.set_global(); | ||||
| 	set_global(pragma_once); | ||||
|  | ||||
| 	param_varadic            = (CodeType) make_code(); | ||||
| 	param_varadic->Type      = ECode::Parameters; | ||||
| 	param_varadic            = (CodeTypename) make_code(); | ||||
| 	param_varadic->Type      = CT_Parameters; | ||||
| 	param_varadic->Name      = get_cached_string( txt("...") ); | ||||
| 	param_varadic->ValueType = t_empty; | ||||
| 	param_varadic.set_global(); | ||||
| 	set_global(param_varadic); | ||||
|  | ||||
| 	preprocess_else = (CodePreprocessCond) make_code(); | ||||
| 	preprocess_else->Type = ECode::Preprocess_Else; | ||||
| 	preprocess_else.set_global(); | ||||
| 	preprocess_else->Type = CT_Preprocess_Else; | ||||
| 	set_global(preprocess_else); | ||||
|  | ||||
| 	preprocess_endif = (CodePreprocessCond) make_code(); | ||||
| 	preprocess_endif->Type = ECode::Preprocess_EndIf; | ||||
| 	preprocess_endif.set_global(); | ||||
| 	preprocess_endif->Type = CT_Preprocess_EndIf; | ||||
| 	set_global(preprocess_endif); | ||||
|  | ||||
| #	define def_constant_code_type( Type_ )   \ | ||||
| 		t_##Type_ = def_type( name(Type_) ); \ | ||||
| 		t_##Type_.set_global(); | ||||
| 		set_global(t_##Type_); | ||||
|  | ||||
| 	def_constant_code_type( auto ); | ||||
| 	def_constant_code_type( void ); | ||||
| @@ -169,8 +169,8 @@ void define_constants() | ||||
| 	def_constant_code_type( u32 ); | ||||
| 	def_constant_code_type( u64 ); | ||||
|  | ||||
| 	def_constant_code_type( sw ); | ||||
| 	def_constant_code_type( uw ); | ||||
| 	def_constant_code_type( ssize ); | ||||
| 	def_constant_code_type( usize ); | ||||
|  | ||||
| 	def_constant_code_type( f32 ); | ||||
| 	def_constant_code_type( f64 ); | ||||
| @@ -180,7 +180,7 @@ void define_constants() | ||||
|  | ||||
| #	define def_constant_spec( Type_, ... )                                  \ | ||||
| 		spec_##Type_ = def_specifiers( num_args(__VA_ARGS__), __VA_ARGS__); \ | ||||
| 		spec_##Type_.set_global(); | ||||
| 		set_global(spec_##Type_); | ||||
|  | ||||
| #	pragma push_macro("forceinline") | ||||
| #	pragma push_macro("global") | ||||
| @@ -192,33 +192,33 @@ void define_constants() | ||||
| #	undef internal | ||||
| #	undef local_persist | ||||
| #	undef neverinline | ||||
| 	def_constant_spec( const,            ESpecifier::Const ); | ||||
| 	def_constant_spec( consteval,        ESpecifier::Consteval ); | ||||
| 	def_constant_spec( constexpr,        ESpecifier::Constexpr ); | ||||
| 	def_constant_spec( constinit,        ESpecifier::Constinit ); | ||||
| 	def_constant_spec( extern_linkage,   ESpecifier::External_Linkage ); | ||||
| 	def_constant_spec( final, 		     ESpecifier::Final ); | ||||
| 	def_constant_spec( forceinline,      ESpecifier::ForceInline ); | ||||
| 	def_constant_spec( global,           ESpecifier::Global ); | ||||
| 	def_constant_spec( inline,           ESpecifier::Inline ); | ||||
| 	def_constant_spec( internal_linkage, ESpecifier::Internal_Linkage ); | ||||
| 	def_constant_spec( local_persist,    ESpecifier::Local_Persist ); | ||||
| 	def_constant_spec( mutable,          ESpecifier::Mutable ); | ||||
| 	def_constant_spec( neverinline,      ESpecifier::NeverInline ); | ||||
| 	def_constant_spec( noexcept,         ESpecifier::NoExceptions ); | ||||
| 	def_constant_spec( override,         ESpecifier::Override ); | ||||
| 	def_constant_spec( ptr,              ESpecifier::Ptr ); | ||||
| 	def_constant_spec( pure,             ESpecifier::Pure ) | ||||
| 	def_constant_spec( ref,              ESpecifier::Ref ); | ||||
| 	def_constant_spec( register,         ESpecifier::Register ); | ||||
| 	def_constant_spec( rvalue,           ESpecifier::RValue ); | ||||
| 	def_constant_spec( static_member,    ESpecifier::Static ); | ||||
| 	def_constant_spec( thread_local,     ESpecifier::Thread_Local ); | ||||
| 	def_constant_spec( virtual, 		 ESpecifier::Virtual ); | ||||
| 	def_constant_spec( volatile, 	     ESpecifier::Volatile) | ||||
| 	def_constant_spec( const,            Spec_Const ); | ||||
| 	def_constant_spec( consteval,        Spec_Consteval ); | ||||
| 	def_constant_spec( constexpr,        Spec_Constexpr ); | ||||
| 	def_constant_spec( constinit,        Spec_Constinit ); | ||||
| 	def_constant_spec( extern_linkage,   Spec_External_Linkage ); | ||||
| 	def_constant_spec( final, 		     Spec_Final ); | ||||
| 	def_constant_spec( forceinline,      Spec_ForceInline ); | ||||
| 	def_constant_spec( global,           Spec_Global ); | ||||
| 	def_constant_spec( inline,           Spec_Inline ); | ||||
| 	def_constant_spec( internal_linkage, Spec_Internal_Linkage ); | ||||
| 	def_constant_spec( local_persist,    Spec_Local_Persist ); | ||||
| 	def_constant_spec( mutable,          Spec_Mutable ); | ||||
| 	def_constant_spec( neverinline,      Spec_NeverInline ); | ||||
| 	def_constant_spec( noexcept,         Spec_NoExceptions ); | ||||
| 	def_constant_spec( override,         Spec_Override ); | ||||
| 	def_constant_spec( ptr,              Spec_Ptr ); | ||||
| 	def_constant_spec( pure,             Spec_Pure ) | ||||
| 	def_constant_spec( ref,              Spec_Ref ); | ||||
| 	def_constant_spec( register,         Spec_Register ); | ||||
| 	def_constant_spec( rvalue,           Spec_RValue ); | ||||
| 	def_constant_spec( static_member,    Spec_Static ); | ||||
| 	def_constant_spec( thread_local,     Spec_Thread_Local ); | ||||
| 	def_constant_spec( virtual, 		 Spec_Virtual ); | ||||
| 	def_constant_spec( volatile, 	     Spec_Volatile) | ||||
|  | ||||
| 	spec_local_persist = def_specifiers( 1, ESpecifier::Local_Persist ); | ||||
| 	spec_local_persist.set_global(); | ||||
| 	spec_local_persist = def_specifiers( 1, Spec_Local_Persist ); | ||||
| 	set_global(spec_local_persist); | ||||
|  | ||||
| #	pragma pop_macro("forceinline") | ||||
| #	pragma pop_macro("global") | ||||
| @@ -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 ); | ||||
|  | ||||
| 		array_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,97 +267,97 @@ 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 ); | ||||
| 		array_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 ); | ||||
| 		array_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(); | ||||
| 	GEN_NS_PARSER init(); | ||||
| } | ||||
|  | ||||
| void deinit() | ||||
| { | ||||
| 	uw index = 0; | ||||
| 	uw left  = CodePools.num(); | ||||
| 	usize index = 0; | ||||
| 	usize left  = array_num(CodePools); | ||||
| 	do | ||||
| 	{ | ||||
| 		Pool* code_pool = & CodePools[index]; | ||||
| 		code_pool->free(); | ||||
| 		pool_free(code_pool); | ||||
| 		index++; | ||||
| 	} | ||||
| 	while ( left--, left ); | ||||
|  | ||||
| 	index = 0; | ||||
| 	left  = StringArenas.num(); | ||||
| 	left  = array_num(StringArenas); | ||||
| 	do | ||||
| 	{ | ||||
| 		Arena* string_arena = & StringArenas[index]; | ||||
| 		string_arena->free(); | ||||
| 		arena_free(string_arena); | ||||
| 		index++; | ||||
| 	} | ||||
| 	while ( left--, left ); | ||||
|  | ||||
| 	StringCache.destroy(); | ||||
| 	hashtable_destroy(StringCache); | ||||
|  | ||||
| 	CodePools.free(); | ||||
| 	StringArenas.free(); | ||||
| 	array_free( CodePools); | ||||
| 	array_free( StringArenas); | ||||
|  | ||||
| 	LexArena.free(); | ||||
| 	arena_free(& LexArena); | ||||
|  | ||||
| 	PreprocessorDefines.free(); | ||||
| 	array_free(PreprocessorDefines); | ||||
|  | ||||
| 	index = 0; | ||||
| 	left  = Global_AllocatorBuckets.num(); | ||||
| 	left  = array_num(Global_AllocatorBuckets); | ||||
| 	do | ||||
| 	{ | ||||
| 		Arena* bucket = & Global_AllocatorBuckets[ index ]; | ||||
| 		bucket->free(); | ||||
| 		arena_free(bucket); | ||||
| 		index++; | ||||
| 	} | ||||
| 	while ( left--, left ); | ||||
|  | ||||
| 	Global_AllocatorBuckets.free(); | ||||
| 	parser::deinit(); | ||||
| 	array_free(Global_AllocatorBuckets); | ||||
| 	GEN_NS_PARSER deinit(); | ||||
| } | ||||
|  | ||||
| void reset() | ||||
| { | ||||
| 	s32 index = 0; | ||||
| 	s32 left  = CodePools.num(); | ||||
| 	s32 left  = array_num(CodePools); | ||||
| 	do | ||||
| 	{ | ||||
| 		Pool* code_pool = & CodePools[index]; | ||||
| 		code_pool->clear(); | ||||
| 		pool_clear(code_pool); | ||||
| 		index++; | ||||
| 	} | ||||
| 	while ( left--, left ); | ||||
|  | ||||
| 	index = 0; | ||||
| 	left  = StringArenas.num(); | ||||
| 	left  = array_num(StringArenas); | ||||
| 	do | ||||
| 	{ | ||||
| 		Arena* string_arena = & StringArenas[index]; | ||||
| @@ -363,28 +366,28 @@ void reset() | ||||
| 	} | ||||
| 	while ( left--, left ); | ||||
|  | ||||
| 	StringCache.clear(); | ||||
| 	hashtable_clear(StringCache); | ||||
|  | ||||
| 	define_constants(); | ||||
| } | ||||
|  | ||||
| AllocatorInfo get_string_allocator( s32 str_length ) | ||||
| { | ||||
| 	Arena* last = & StringArenas.back(); | ||||
| 	Arena* last = array_back(StringArenas); | ||||
|  | ||||
| 	uw size_req = str_length + sizeof(String::Header) + sizeof(char*); | ||||
| 	usize size_req = str_length + sizeof(StringHeader) + sizeof(char*); | ||||
|  | ||||
| 	if ( last->TotalUsed + size_req > last->TotalSize ) | ||||
| 	if ( last->TotalUsed + ssize(size_req) > last->TotalSize ) | ||||
| 	{ | ||||
| 		Arena new_arena = Arena::init_from_allocator( Allocator_StringArena, SizePer_StringArena ); | ||||
| 		Arena new_arena = arena_init_from_allocator( Allocator_StringArena, SizePer_StringArena ); | ||||
|  | ||||
| 		if ( ! StringArenas.append( new_arena ) ) | ||||
| 		if ( ! array_append( StringArenas, new_arena ) ) | ||||
| 			GEN_FATAL( "gen::get_string_allocator: Failed to allocate a new string arena" ); | ||||
|  | ||||
| 		last = & StringArenas.back(); | ||||
| 		last = array_back(StringArenas); | ||||
| 	} | ||||
|  | ||||
| 	return * last; | ||||
| 	return arena_allocator_info(last); | ||||
| } | ||||
|  | ||||
| // Will either make or retrive a code string. | ||||
| @@ -393,36 +396,36 @@ 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 = hashtable_get(StringCache, key ); | ||||
|  | ||||
| 		if ( result ) | ||||
| 			return * result; | ||||
| 	} | ||||
|  | ||||
| 	String result = String::make( get_string_allocator( str.Len ), str ); | ||||
| 	StringCache.set( key, result ); | ||||
| 	StrC result = string_to_strc( string_make_strc( get_string_allocator( str.Len ), str )); | ||||
| 	hashtable_set(StringCache, key, result ); | ||||
|  | ||||
| 	return result; | ||||
| 	return { str.Len, result }; | ||||
| } | ||||
|  | ||||
| // Used internally to retireve a Code object form the CodePool. | ||||
| Code make_code() | ||||
| { | ||||
| 	Pool* allocator = & CodePools.back(); | ||||
| 	Pool* allocator = array_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 ( ! array_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 = array_back( CodePools); | ||||
| 	} | ||||
|  | ||||
| 	Code result { rcast( AST*, alloc( * allocator, sizeof(AST) )) }; | ||||
| 	Code result { rcast( AST*, alloc( pool_allocator_info(allocator), sizeof(AST) )) }; | ||||
| 	mem_set( result.ast, 0, sizeof(AST) ); | ||||
| 	// result->Type = ECode::Invalid; | ||||
|  | ||||
|   | ||||
| @@ -42,77 +42,129 @@ void set_allocator_type_table  ( AllocatorInfo type_reg_allocator ); | ||||
| CodeAttributes def_attributes( StrC content ); | ||||
| CodeComment    def_comment   ( StrC content ); | ||||
|  | ||||
| CodeClass def_class( StrC name | ||||
| 	, Code           body         = NoCode | ||||
| 	, CodeType       parent       = NoCode, AccessSpec access = AccessSpec::Default | ||||
| 	, CodeAttributes attributes   = NoCode | ||||
| 	, ModuleFlag     mflags       = ModuleFlag::None | ||||
| 	, CodeType*      interfaces   = nullptr, s32 num_interfaces = 0 ); | ||||
| struct Opts_def_struct { | ||||
| 	Code           body; | ||||
| 	CodeTypename   parent; | ||||
| 	AccessSpec     parent_access; | ||||
| 	CodeAttributes attributes; | ||||
| 	ModuleFlag     mflags; | ||||
| 	CodeTypename*  interfaces; | ||||
| 	s32            num_interfaces; | ||||
| }; | ||||
| CodeClass def_class( StrC name, Opts_def_struct otps GEN_PARAM_DEFAULT ); | ||||
|  | ||||
| CodeConstructor def_constructor( CodeParam params = NoCode, Code initializer_list = NoCode, Code body = NoCode ); | ||||
| struct Opts_def_constructor { | ||||
| 	CodeParam params; | ||||
| 	Code      initializer_list; | ||||
| 	Code      body; | ||||
| }; | ||||
| CodeConstructor def_constructor( Opts_def_constructor opts GEN_PARAM_DEFAULT ); | ||||
|  | ||||
| CodeDefine def_define( StrC name, StrC content ); | ||||
|  | ||||
| CodeDestructor def_destructor( Code body = NoCode, CodeSpecifiers specifiers = NoCode ); | ||||
| struct Opts_def_destructor { | ||||
| 	Code           body; | ||||
| 	CodeSpecifiers specifiers; | ||||
| }; | ||||
| CodeDestructor def_destructor( Opts_def_destructor opts GEN_PARAM_DEFAULT ); | ||||
|  | ||||
| CodeEnum def_enum( StrC name | ||||
| 	, Code         body      = NoCode,      CodeType       type       = NoCode | ||||
| 	, EnumT        specifier = EnumRegular, CodeAttributes attributes = NoCode | ||||
| 	, ModuleFlag   mflags    = ModuleFlag::None ); | ||||
| struct Opts_def_enum { | ||||
| 	Code           body; | ||||
| 	CodeTypename   type; | ||||
| 	EnumT          specifier; | ||||
| 	CodeAttributes attributes; | ||||
| 	ModuleFlag     mflags; | ||||
| }; | ||||
| CodeEnum def_enum( StrC name, Opts_def_enum opts GEN_PARAM_DEFAULT ); | ||||
|  | ||||
| CodeExec   def_execution  ( StrC content ); | ||||
| CodeExtern def_extern_link( StrC name, Code body ); | ||||
| 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 ); | ||||
| struct Opts_def_function { | ||||
| 	CodeParam       params; | ||||
| 	CodeTypename    ret_type; | ||||
| 	Code            body; | ||||
| 	CodeSpecifiers  specs; | ||||
| 	CodeAttributes  attrs; | ||||
| 	ModuleFlag      mflags; | ||||
| }; | ||||
| CodeFn def_function( StrC name, Opts_def_function opts GEN_PARAM_DEFAULT ); | ||||
|  | ||||
| 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 ); | ||||
| struct Opts_def_include   { b32        foreign; }; | ||||
| struct Opts_def_module    { ModuleFlag mflags;  }; | ||||
| struct Opts_def_namespace { ModuleFlag mflags;  }; | ||||
| CodeInclude def_include  ( StrC content,         Opts_def_include   opts GEN_PARAM_DEFAULT ); | ||||
| CodeModule  def_module   ( StrC name,            Opts_def_module    opts GEN_PARAM_DEFAULT ); | ||||
| CodeNS      def_namespace( StrC name, Code body, Opts_def_namespace opts GEN_PARAM_DEFAULT ); | ||||
|  | ||||
| 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 ); | ||||
| struct Opts_def_operator { | ||||
| 	CodeParam       params; | ||||
| 	CodeTypename    ret_type; | ||||
| 	Code            body; | ||||
| 	CodeSpecifiers  specifiers; | ||||
| 	CodeAttributes  attributes; | ||||
| 	ModuleFlag      mflags; | ||||
| }; | ||||
| CodeOperator def_operator( Operator op, StrC nspace, Opts_def_operator opts GEN_PARAM_DEFAULT ); | ||||
|  | ||||
| CodeOpCast def_operator_cast( CodeType type, Code body = NoCode, CodeSpecifiers specs = NoCode ); | ||||
| struct Opts_def_operator_cast { | ||||
| 	Code           body; | ||||
| 	CodeSpecifiers specs; | ||||
| }; | ||||
| CodeOpCast def_operator_cast( CodeTypename type, Opts_def_operator_cast opts GEN_PARAM_DEFAULT ); | ||||
|  | ||||
| CodeParam  def_param ( CodeType type, StrC name, Code value = NoCode ); | ||||
| struct Opts_def_param { Code value; }; | ||||
| CodeParam  def_param ( CodeTypename type, StrC name, Opts_def_param opts GEN_PARAM_DEFAULT ); | ||||
| CodePragma def_pragma( StrC directive ); | ||||
|  | ||||
| CodePreprocessCond def_preprocess_cond( EPreprocessCond type, StrC content ); | ||||
|  | ||||
| CodeSpecifiers def_specifier( SpecifierT specifier ); | ||||
| CodeSpecifiers def_specifier( Specifier specifier ); | ||||
|  | ||||
| CodeStruct def_struct( StrC name | ||||
| 	, Code           body       = NoCode | ||||
| 	, CodeType       parent     = NoCode, AccessSpec access = AccessSpec::Default | ||||
| 	, CodeAttributes attributes = NoCode | ||||
| 	, ModuleFlag     mflags     = ModuleFlag::None | ||||
| 	, CodeType*      interfaces = nullptr, s32 num_interfaces = 0 ); | ||||
| CodeStruct def_struct( StrC name, Opts_def_struct opts GEN_PARAM_DEFAULT ); | ||||
|  | ||||
| CodeTemplate def_template( CodeParam params, Code definition, ModuleFlag mflags = ModuleFlag::None ); | ||||
| struct Opts_def_template { ModuleFlag mflags; }; | ||||
| CodeTemplate def_template( CodeParam params, Code definition, Opts_def_template opts GEN_PARAM_DEFAULT ); | ||||
|  | ||||
| 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 ); | ||||
| struct Opts_def_type { | ||||
| 	Code           arrayexpr; | ||||
| 	CodeSpecifiers specifiers; | ||||
| 	CodeAttributes attributes; | ||||
| }; | ||||
| CodeTypename def_type( StrC name, Opts_def_type opts GEN_PARAM_DEFAULT ); | ||||
|  | ||||
| CodeUnion def_union( StrC name, Code body, CodeAttributes attributes = NoCode, ModuleFlag mflags = ModuleFlag::None ); | ||||
| struct Opts_def_typedef { | ||||
| 	CodeAttributes attributes; | ||||
| 	ModuleFlag     mflags; | ||||
| }; | ||||
| CodeTypedef def_typedef( StrC name, Code type, Opts_def_typedef opts GEN_PARAM_DEFAULT ); | ||||
|  | ||||
| CodeUsing def_using( StrC name, CodeType type = NoCode | ||||
| 	, CodeAttributes attributess = NoCode | ||||
| 	, ModuleFlag     mflags      = ModuleFlag::None ); | ||||
| struct Opts_def_union { | ||||
| 	CodeAttributes attributes; | ||||
| 	ModuleFlag     mflags; | ||||
| }; | ||||
| CodeUnion def_union( StrC name, Code body, Opts_def_union opts GEN_PARAM_DEFAULT ); | ||||
|  | ||||
| struct Opts_def_using { | ||||
| 	CodeAttributes attributes; | ||||
| 	ModuleFlag     mflags; | ||||
| }; | ||||
| CodeUsing def_using( StrC name, Code type, Opts_def_using opts GEN_PARAM_DEFAULT ); | ||||
|  | ||||
| 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 ); | ||||
| struct Opts_def_variable | ||||
| { | ||||
| 	Code           value; | ||||
| 	CodeSpecifiers specifiers; | ||||
| 	CodeAttributes attributes; | ||||
| 	ModuleFlag     mflags; | ||||
| }; | ||||
| CodeVar def_variable( CodeTypename type, StrC name, Opts_def_variable opts GEN_PARAM_DEFAULT );  | ||||
|  | ||||
| // Constructs an empty body. Use AST::validate_body() to check if the body is was has valid entries. | ||||
| CodeBody def_body( CodeT type ); | ||||
| CodeBody def_body( CodeTypename type ); | ||||
|  | ||||
| // There are two options for defining a struct body, either varadically provided with the args macro to auto-deduce the arg num, | ||||
| /// or provide as an array of Code objects. | ||||
| @@ -134,7 +186,7 @@ CodeBody       def_namespace_body  ( s32 num, Code* codes ); | ||||
| CodeParam      def_params          ( s32 num, ... ); | ||||
| CodeParam      def_params          ( s32 num, CodeParam* params ); | ||||
| CodeSpecifiers def_specifiers      ( s32 num, ... ); | ||||
| CodeSpecifiers def_specifiers      ( s32 num, SpecifierT* specs ); | ||||
| CodeSpecifiers def_specifiers      ( s32 num, Specifier* specs ); | ||||
| CodeBody       def_struct_body     ( s32 num, ... ); | ||||
| CodeBody       def_struct_body     ( s32 num, Code* codes ); | ||||
| CodeBody       def_union_body      ( s32 num, ... ); | ||||
| @@ -166,7 +218,7 @@ namespace parser { | ||||
| } | ||||
|  | ||||
| struct ParseInfo | ||||
|  | ||||
| { | ||||
| 	Arena FileMem; | ||||
| 	Arena TokMem; | ||||
| 	Arena CodeMem; | ||||
| @@ -175,7 +227,7 @@ struct ParseInfo | ||||
| 	Array<parser::Token> Tokens; | ||||
| 	Array<parser::Error> Errors; | ||||
| 	// Errors are allocated to a dedicated general arena. | ||||
| ; | ||||
| }; | ||||
|  | ||||
| CodeBody parse_file( StrC path ); | ||||
| #endif | ||||
| @@ -194,7 +246,7 @@ CodeOperator    parse_operator     ( StrC operator_def    ); | ||||
| CodeOpCast      parse_operator_cast( StrC operator_def    ); | ||||
| CodeStruct      parse_struct       ( StrC struct_def      ); | ||||
| CodeTemplate    parse_template     ( StrC template_def    ); | ||||
| CodeType        parse_type         ( StrC type_def        ); | ||||
| CodeTypename    parse_type         ( StrC type_def        ); | ||||
| CodeTypedef     parse_typedef      ( StrC typedef_def     ); | ||||
| CodeUnion       parse_union        ( StrC union_def       ); | ||||
| CodeUsing       parse_using        ( StrC using_def       ); | ||||
| @@ -204,9 +256,9 @@ CodeVar         parse_variable     ( StrC var_def         ); | ||||
|  | ||||
| #pragma region Untyped text | ||||
|  | ||||
| sw   token_fmt_va( char* buf, uw buf_size, s32 num_tokens, va_list va ); | ||||
| ssize   token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va ); | ||||
| //! Do not use directly. Use the token_fmt macro instead. | ||||
| StrC token_fmt_impl( sw, ... ); | ||||
| StrC token_fmt_impl( ssize, ... ); | ||||
|  | ||||
| Code untyped_str      ( StrC content); | ||||
| Code untyped_fmt      ( char const* fmt, ... ); | ||||
|   | ||||
| @@ -10,58 +10,58 @@ | ||||
|  | ||||
| CodeClass parse_class( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
| 	using namespace parser; | ||||
| 	 | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	push_scope(); | ||||
| 	CodeClass result = (CodeClass) parse_class_struct( TokType::Decl_Class ); | ||||
| 	Context.pop(); | ||||
| 	CodeClass result = (CodeClass) parse_class_struct( Tok_Decl_Class ); | ||||
| 	pop(& Context); | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| CodeConstructor parse_constructor( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
| 	using namespace parser; | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	// TODO(Ed): Constructors can have prefix attributes | ||||
|  | ||||
| 	CodeSpecifiers specifiers; | ||||
| 	SpecifierT     specs_found[ 16 ] { ESpecifier::NumSpecifiers }; | ||||
| 	Specifier      specs_found[ 16 ] { Spec_NumSpecifiers }; | ||||
| 	s32            NumSpecifiers = 0; | ||||
|  | ||||
| 	while ( left && currtok.is_specifier() ) | ||||
| 	while ( left && is_specifier(currtok) ) | ||||
| 	{ | ||||
| 		SpecifierT spec = ESpecifier::to_type( currtok ); | ||||
| 		Specifier spec = to_specifier( to_str(currtok) ); | ||||
|  | ||||
| 		b32 ignore_spec = false; | ||||
|  | ||||
| 		switch ( spec ) | ||||
| 		{ | ||||
| 			case ESpecifier::Constexpr : | ||||
| 			case ESpecifier::Explicit: | ||||
| 			case ESpecifier::Inline : | ||||
| 			case ESpecifier::ForceInline : | ||||
| 			case ESpecifier::NeverInline : | ||||
| 			case Spec_Constexpr : | ||||
| 			case Spec_Explicit: | ||||
| 			case Spec_Inline : | ||||
| 			case Spec_ForceInline : | ||||
| 			case Spec_NeverInline : | ||||
| 				break; | ||||
|  | ||||
| 			case ESpecifier::Const : | ||||
| 			case Spec_Const : | ||||
| 				ignore_spec = true; | ||||
| 				break; | ||||
|  | ||||
| 			default : | ||||
| 				log_failure( "Invalid specifier %s for variable\n%s", ESpecifier::to_str( spec ), Context.to_string() ); | ||||
| 				Context.pop(); | ||||
| 				return CodeInvalid; | ||||
| 				log_failure( "Invalid specifier %s for variable\n%s", to_str( spec ), to_string(Context) ); | ||||
| 				pop(& Context); | ||||
| 				return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		// Every specifier after would be considered part of the type type signature | ||||
| @@ -86,12 +86,12 @@ CodeConstructor parse_constructor( StrC def ) | ||||
|  | ||||
| CodeDestructor parse_destructor( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
| 	using namespace parser; | ||||
|  | ||||
| 	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 | ||||
| @@ -103,14 +103,14 @@ CodeDestructor parse_destructor( StrC def ) | ||||
|  | ||||
| CodeEnum parse_enum( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
| 	using namespace parser; | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 	{ | ||||
| 		Context.pop(); | ||||
| 		return CodeInvalid; | ||||
| 		pop(& Context); | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| @@ -119,12 +119,12 @@ CodeEnum parse_enum( StrC def ) | ||||
|  | ||||
| CodeBody parse_export_body( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
| 	using namespace parser; | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parse_export_body(); | ||||
| @@ -132,12 +132,12 @@ CodeBody parse_export_body( StrC def ) | ||||
|  | ||||
| CodeExtern parse_extern_link( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
| 	using namespace parser; | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parse_extern_link(); | ||||
| @@ -145,12 +145,12 @@ CodeExtern parse_extern_link( StrC def ) | ||||
|  | ||||
| CodeFriend parse_friend( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
| 	using namespace parser; | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parse_friend(); | ||||
| @@ -158,12 +158,12 @@ CodeFriend parse_friend( StrC def ) | ||||
|  | ||||
| CodeFn parse_function( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
| 	using namespace parser; | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return (CodeFn) parse_function(); | ||||
| @@ -171,28 +171,28 @@ CodeFn parse_function( StrC def ) | ||||
|  | ||||
| CodeBody parse_global_body( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
| 	using namespace parser; | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	push_scope(); | ||||
| 	CodeBody result = parse_global_nspace( ECode::Global_Body ); | ||||
| 	Context.pop(); | ||||
| 	CodeBody result = parse_global_nspace( CT_Global_Body ); | ||||
| 	pop(& Context); | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| CodeNS parse_namespace( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
| 	using namespace parser; | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parse_namespace(); | ||||
| @@ -200,12 +200,12 @@ CodeNS parse_namespace( StrC def ) | ||||
|  | ||||
| CodeOperator parse_operator( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
| 	using namespace parser; | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return (CodeOperator) parse_operator(); | ||||
| @@ -213,12 +213,12 @@ CodeOperator parse_operator( StrC def ) | ||||
|  | ||||
| CodeOpCast parse_operator_cast( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
| 	using namespace parser; | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parse_operator_cast(); | ||||
| @@ -226,41 +226,41 @@ CodeOpCast parse_operator_cast( StrC def ) | ||||
|  | ||||
| CodeStruct parse_struct( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
| 	using namespace parser; | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	push_scope(); | ||||
| 	CodeStruct result = (CodeStruct) parse_class_struct( TokType::Decl_Struct ); | ||||
| 	Context.pop(); | ||||
| 	CodeStruct result = (CodeStruct) parse_class_struct( Tok_Decl_Struct ); | ||||
| 	pop(& Context); | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| CodeTemplate parse_template( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
| 	using namespace parser; | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parse_template(); | ||||
| } | ||||
|  | ||||
| CodeType parse_type( StrC def ) | ||||
| CodeTypename parse_type( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
| 	using namespace parser; | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parse_type(); | ||||
| @@ -268,12 +268,12 @@ CodeType parse_type( StrC def ) | ||||
|  | ||||
| CodeTypedef parse_typedef( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
| 	using namespace parser; | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parse_typedef(); | ||||
| @@ -281,12 +281,12 @@ CodeTypedef parse_typedef( StrC def ) | ||||
|  | ||||
| CodeUnion parse_union( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
| 	using namespace parser; | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parse_union(); | ||||
| @@ -294,12 +294,12 @@ CodeUnion parse_union( StrC def ) | ||||
|  | ||||
| CodeUsing parse_using( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
| 	using namespace parser; | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parse_using(); | ||||
| @@ -307,12 +307,12 @@ CodeUsing parse_using( StrC def ) | ||||
|  | ||||
| CodeVar parse_variable( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
| 	using namespace parser; | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parse_variable(); | ||||
|   | ||||
| @@ -3,21 +3,19 @@ | ||||
| #include "interface.parsing.cpp" | ||||
| #endif | ||||
|  | ||||
| sw token_fmt_va( char* buf, uw buf_size, s32 num_tokens, va_list va ) | ||||
| ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va ) | ||||
| { | ||||
| 	char const* buf_begin = buf; | ||||
| 	sw          remaining = buf_size; | ||||
| 	ssize       remaining = buf_size; | ||||
|  | ||||
| 	local_persist | ||||
| 	Arena tok_map_arena; | ||||
| 	FixedArena<TokenFmt_TokenMap_MemSize> tok_map_arena; | ||||
| 	fixed_arena_init( & tok_map_arena); | ||||
|  | ||||
| 	HashTable<StrC> tok_map; | ||||
| 	local_persist | ||||
| 	HashTable(StrC) tok_map; | ||||
| 	{ | ||||
| 		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 = hashtable_init(StrC, fixed_arena_allocator_info(& tok_map_arena) ); | ||||
|  | ||||
| 		s32 left = num_tokens - 1; | ||||
|  | ||||
| @@ -27,8 +25,7 @@ sw token_fmt_va( char* buf, uw 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 ); | ||||
| 			hashtable_set( tok_map, key, value ); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @@ -37,7 +34,7 @@ sw token_fmt_va( char* buf, uw buf_size, s32 num_tokens, va_list va ) | ||||
|  | ||||
| 	while ( current ) | ||||
| 	{ | ||||
| 		sw len = 0; | ||||
| 		ssize len = 0; | ||||
|  | ||||
| 		while ( current && current != '<' && remaining ) | ||||
| 		{ | ||||
| @@ -64,11 +61,11 @@ sw token_fmt_va( char* buf, uw 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 = hashtable_get(tok_map, key ); | ||||
|  | ||||
| 			if ( value ) | ||||
| 			{ | ||||
| 				sw          left = value->Len; | ||||
| 				ssize          left = value->Len; | ||||
| 				char const* str  = value->Ptr; | ||||
|  | ||||
| 				while ( left-- ) | ||||
| @@ -94,10 +91,10 @@ sw token_fmt_va( char* buf, uw buf_size, s32 num_tokens, va_list va ) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	tok_map.clear(); | ||||
| 	tok_map_arena.free(); | ||||
| 	hashtable_clear(tok_map); | ||||
| 	fixed_arena_free(& tok_map_arena); | ||||
|  | ||||
| 	sw result = buf_size - remaining; | ||||
| 	ssize result = buf_size - remaining; | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
| @@ -107,19 +104,19 @@ Code untyped_str( StrC content ) | ||||
| 	if ( content.Len == 0 ) | ||||
| 	{ | ||||
| 		log_failure( "untyped_str: empty string" ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	Code | ||||
| 	result          = make_code(); | ||||
| 	result->Name    = get_cached_string( content ); | ||||
| 	result->Type    = ECode::Untyped; | ||||
| 	result->Type    = CT_Untyped; | ||||
| 	result->Content = result->Name; | ||||
|  | ||||
| 	if ( result->Name == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "untyped_str: could not cache string" ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	return result; | ||||
| @@ -130,7 +127,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 | ||||
| @@ -138,19 +135,19 @@ Code untyped_fmt( char const* fmt, ...) | ||||
|  | ||||
| 	va_list va; | ||||
| 	va_start(va, fmt); | ||||
| 	sw length = str_fmt_va(buf, GEN_PRINTF_MAXLEN, fmt, va); | ||||
| 	ssize length = str_fmt_va(buf, GEN_PRINTF_MAXLEN, fmt, va); | ||||
| 	va_end(va); | ||||
|  | ||||
| 	Code | ||||
| 	result          = make_code(); | ||||
| 	result->Name    = get_cached_string( { str_len(fmt, MaxNameLength), fmt } ); | ||||
| 	result->Type    = ECode::Untyped; | ||||
| 	result->Name    = get_cached_string( { str_len_capped(fmt, MaxNameLength), fmt } ); | ||||
| 	result->Type    = CT_Untyped; | ||||
| 	result->Content = get_cached_string( { length, buf } ); | ||||
|  | ||||
| 	if ( result->Name == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "untyped_fmt: could not cache string" ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	return result; | ||||
| @@ -161,7 +158,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 | ||||
| @@ -169,19 +166,19 @@ Code untyped_token_fmt( s32 num_tokens, ... ) | ||||
|  | ||||
| 	va_list va; | ||||
| 	va_start(va, num_tokens); | ||||
| 	sw length = token_fmt_va(buf, GEN_PRINTF_MAXLEN, num_tokens, va); | ||||
| 	ssize length = token_fmt_va(buf, GEN_PRINTF_MAXLEN, num_tokens, va); | ||||
| 	va_end(va); | ||||
|  | ||||
| 	Code | ||||
| 	result          = make_code(); | ||||
| 	result->Name    = get_cached_string( { length, buf } ); | ||||
| 	result->Type    = ECode::Untyped; | ||||
| 	result->Type    = CT_Untyped; | ||||
| 	result->Content = result->Name; | ||||
|  | ||||
| 	if ( result->Name == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "untyped_fmt: could not cache string" ); | ||||
| 		return CodeInvalid; | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	return result; | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -9,4 +9,3 @@ | ||||
| #ifndef GEN_ROLL_OWN_DEPENDENCIES | ||||
| #	include "gen.dep.cpp" | ||||
| #endif | ||||
|  | ||||
|   | ||||
| @@ -72,36 +72,36 @@ global CodeSpecifiers spec_thread_local; | ||||
| global CodeSpecifiers spec_virtual; | ||||
| global CodeSpecifiers spec_volatile; | ||||
|  | ||||
| global CodeType t_empty; | ||||
| global CodeType t_auto; | ||||
| global CodeType t_void; | ||||
| global CodeType t_int; | ||||
| global CodeType t_bool; | ||||
| global CodeType t_char; | ||||
| global CodeType t_wchar_t; | ||||
| global CodeType t_class; | ||||
| global CodeType t_typename; | ||||
| global CodeTypename t_empty; | ||||
| global CodeTypename t_auto; | ||||
| global CodeTypename t_void; | ||||
| global CodeTypename t_int; | ||||
| global CodeTypename t_bool; | ||||
| global CodeTypename t_char; | ||||
| global CodeTypename t_wchar_t; | ||||
| global CodeTypename t_class; | ||||
| global CodeTypename t_typename; | ||||
|  | ||||
| global Array< StringCached > PreprocessorDefines; | ||||
| global Array(StringCached) PreprocessorDefines; | ||||
|  | ||||
| #ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS | ||||
| global CodeType t_b32; | ||||
| global CodeTypename t_b32; | ||||
|  | ||||
| global CodeType t_s8; | ||||
| global CodeType t_s16; | ||||
| global CodeType t_s32; | ||||
| global CodeType t_s64; | ||||
| global CodeTypename t_s8; | ||||
| global CodeTypename t_s16; | ||||
| global CodeTypename t_s32; | ||||
| global CodeTypename t_s64; | ||||
|  | ||||
| global CodeType t_u8; | ||||
| global CodeType t_u16; | ||||
| global CodeType t_u32; | ||||
| global CodeType t_u64; | ||||
| global CodeTypename t_u8; | ||||
| global CodeTypename t_u16; | ||||
| global CodeTypename t_u32; | ||||
| global CodeTypename t_u64; | ||||
|  | ||||
| global CodeType t_sw; | ||||
| global CodeType t_uw; | ||||
| global CodeTypename t_ssize; | ||||
| global CodeTypename t_usize; | ||||
|  | ||||
| global CodeType t_f32; | ||||
| global CodeType t_f64; | ||||
| global CodeTypename t_f32; | ||||
| global CodeTypename t_f64; | ||||
| #endif | ||||
|  | ||||
| #pragma endregion Constants | ||||
|   | ||||
| @@ -3,7 +3,7 @@ | ||||
| #include "header_start.hpp" | ||||
| #endif | ||||
|  | ||||
| using LogFailType = sw(*)(char const*, ...); | ||||
| using LogFailType = ssize(*)(char const*, ...); | ||||
|  | ||||
| // By default this library will either crash or exit if an error is detected while generating codes. | ||||
| // Even if set to not use GEN_FATAL, GEN_FATAL will still be used for memory failures as the library is unusable when they occur. | ||||
| @@ -13,64 +13,73 @@ using LogFailType = sw(*)(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 ) | ||||
| { | ||||
| 	local_persist | ||||
| @@ -80,26 +89,25 @@ StrC to_str( ModuleFlag flag ) | ||||
| 		{ sizeof("import"), "import" }, | ||||
| 	}; | ||||
|  | ||||
| 	if ( flag > ModuleFlag::Import ) | ||||
| 	if ( flag > ModuleFlag_Import ) | ||||
| 		return { sizeof("invalid"), "invalid" }; | ||||
|  | ||||
| 	return lookup[ (u32)flag ]; | ||||
| } | ||||
|  | ||||
| inline | ||||
| 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,9 +1,11 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	pragma once | ||||
| #	include "platform.hpp" | ||||
| #	include "macros.hpp" | ||||
| #endif | ||||
|  | ||||
| #pragma region Basic Types | ||||
| GEN_API_C_BEGIN | ||||
|  | ||||
| #define GEN_U8_MIN 0u | ||||
| #define GEN_U8_MAX 0xffu | ||||
| @@ -85,10 +87,10 @@ static_assert( sizeof( u16 ) == 2, "sizeof(u16) != 2" ); | ||||
| static_assert( sizeof( u32 ) == 4, "sizeof(u32) != 4" ); | ||||
| static_assert( sizeof( u64 ) == 8, "sizeof(u64) != 8" ); | ||||
|  | ||||
| typedef size_t    uw; | ||||
| typedef ptrdiff_t sw; | ||||
| typedef size_t    usize; | ||||
| typedef ptrdiff_t ssize; | ||||
|  | ||||
| static_assert( sizeof( uw ) == sizeof( sw ), "sizeof(uw) != sizeof(sw)" ); | ||||
| static_assert( sizeof( usize ) == sizeof( ssize ), "sizeof(usize) != sizeof(ssize)" ); | ||||
|  | ||||
| // NOTE: (u)zpl_intptr is only here for semantic reasons really as this library will only support 32/64 bit OSes. | ||||
| #if defined( _WIN64 ) | ||||
| @@ -122,4 +124,24 @@ typedef s8  b8; | ||||
| typedef s16 b16; | ||||
| typedef s32 b32; | ||||
|  | ||||
| typedef void*       mem_ptr; | ||||
| typedef void const* mem_ptr_const ; | ||||
|  | ||||
| #if ! GEN_COMPILER_C | ||||
| GEN_API_C_END | ||||
| 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; } | ||||
| GEN_API_C_BEGIN | ||||
| #else | ||||
| #define to_uptr( ptr ) ((uptr)(ptr)) | ||||
| #define to_sptr( ptr ) ((sptr)(ptr)) | ||||
|  | ||||
| #define to_mem_ptr( ptr)       ((mem_ptr)ptr) | ||||
| #define to_mem_ptr_const( ptr) ((mem_ptr)ptr) | ||||
| #endif | ||||
|  | ||||
| GEN_API_C_END | ||||
| #pragma endregion Basic Types | ||||
|   | ||||
| @@ -8,31 +8,132 @@ | ||||
| template<class TType>             struct RemoveConst                    { typedef TType Type;       }; | ||||
| template<class TType>             struct RemoveConst<const TType>       { typedef TType Type;       }; | ||||
| template<class TType>             struct RemoveConst<const TType[]>     { typedef TType Type[];     }; | ||||
| template<class TType, uw Size> struct RemoveConst<const TType[Size]> { typedef TType Type[Size]; }; | ||||
| template<class TType, usize Size> struct RemoveConst<const TType[Size]> { typedef TType Type[Size]; }; | ||||
|  | ||||
| template<class TType> | ||||
| using TRemoveConst = typename RemoveConst<TType>::Type; | ||||
| template<class TType> using TRemoveConst = typename RemoveConst<TType>::Type; | ||||
|  | ||||
| template <class TType> struct RemovePtr         { typedef TType Type; }; | ||||
| template <class TType> struct RemovePtr<TType*> { typedef TType Type; }; | ||||
|  | ||||
| template <class TType> using TRemovePtr = typename RemovePtr<TType>::Type; | ||||
|  | ||||
|  | ||||
| #pragma region Array | ||||
| #define Array(Type) Array<Type> | ||||
|  | ||||
| // #define array_init(Type, ...)         array_init        <Type>(__VA_ARGS__) | ||||
| // #define array_init_reserve(Type, ...) array_init_reserve<Type>(__VA_ARGS__) | ||||
|  | ||||
| struct ArrayHeader; | ||||
|  | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| 	template<class Type> struct Array; | ||||
| #	define get_array_underlying_type(array) typename TRemovePtr<typeof(array)>:: DataType | ||||
| #else | ||||
| 	template<class Type> using Array = Type*; | ||||
| #	define get_array_underlying_type(array) TRemovePtr<typeof(array)> | ||||
| #endif | ||||
|  | ||||
| usize array_grow_formula(ssize value); | ||||
|  | ||||
| template<class Type> Array<Type>  array_init           (AllocatorInfo allocator); | ||||
| template<class Type> Array<Type>  array_init_reserve   (AllocatorInfo allocator, ssize capacity); | ||||
| template<class Type> bool         array_append_array   (Array<Type>* array, Array<Type> other); | ||||
| template<class Type> bool         array_append         (Array<Type>* array, Type value); | ||||
| template<class Type> bool         array_append_items   (Array<Type>* array, Type* items, usize item_num); | ||||
| template<class Type> bool         array_append_at      (Array<Type>* array, Type item, usize idx); | ||||
| template<class Type> bool         array_append_items_at(Array<Type>* array, Type* items, usize item_num, usize idx); | ||||
| template<class Type> Type*        array_back           (Array<Type>  array); | ||||
| template<class Type> void         array_clear          (Array<Type>  array); | ||||
| template<class Type> bool         array_fill           (Array<Type>  array, usize begin, usize end, Type value); | ||||
| template<class Type> void         array_free           (Array<Type>* array); | ||||
| template<class Type> bool         arary_grow           (Array<Type>* array, usize min_capacity); | ||||
| template<class Type> usize        array_num            (Array<Type>  array); | ||||
| template<class Type> void         arary_pop            (Array<Type>  array); | ||||
| template<class Type> void         arary_remove_at      (Array<Type>  array, usize idx); | ||||
| template<class Type> bool         arary_reserve        (Array<Type>* array, usize new_capacity); | ||||
| template<class Type> bool         arary_resize         (Array<Type>* array, usize num); | ||||
| template<class Type> bool         arary_set_capacity   (Array<Type>* array, usize new_capacity); | ||||
| template<class Type> ArrayHeader* arary_get_header     (Array<Type>  array); | ||||
|  | ||||
| struct ArrayHeader { | ||||
| 	AllocatorInfo Allocator; | ||||
| 	usize         Capacity; | ||||
| 	usize         Num; | ||||
| }; | ||||
|  | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| template<class Type> | ||||
| struct Array | ||||
| { | ||||
| 	struct Header | ||||
| 	{ | ||||
| 		AllocatorInfo Allocator; | ||||
| 		uw            Capacity; | ||||
| 		uw            Num; | ||||
| 	}; | ||||
| 	Type* Data; | ||||
|  | ||||
| 	static | ||||
| 	Array init( AllocatorInfo allocator ) | ||||
| 	{ | ||||
| 		return init_reserve( allocator, grow_formula(0) ); | ||||
| #pragma region Member Mapping | ||||
| 	forceinline static Array  init(AllocatorInfo allocator)                         { return GEN_NS array_init<Type>(allocator); } | ||||
| 	forceinline static Array  init_reserve(AllocatorInfo allocator, ssize capacity) { return GEN_NS array_init_reserve<Type>(allocator, capacity); } | ||||
| 	forceinline static usize  grow_formula(ssize value)                             { return GEN_NS array_grow_formula<Type>(value); } | ||||
|  | ||||
| 	forceinline bool         append(Array other)                               { return GEN_NS array_append_array<Type>(this, other); } | ||||
| 	forceinline bool         append(Type value)                                { return GEN_NS array_append<Type>(this, value); } | ||||
| 	forceinline bool         append(Type* items, usize item_num)               { return GEN_NS array_append_items<Type>(this, items, item_num); } | ||||
| 	forceinline bool         append_at(Type item, usize idx)                   { return GEN_NS array_append_at<Type>(this, item, idx); } | ||||
| 	forceinline bool         append_at(Type* items, usize item_num, usize idx) { return GEN_NS array_append_items_at<Type>(this, items, item_num, idx); } | ||||
| 	forceinline Type*        back()                                            { return GEN_NS array_back<Type>(* this); } | ||||
| 	forceinline void         clear()                                           {        GEN_NS array_clear<Type>(* this); } | ||||
| 	forceinline bool         fill(usize begin, usize end, Type value)          { return GEN_NS array_fill<Type>(* this, begin, end, value); } | ||||
| 	forceinline void         free()                                            {        GEN_NS array_free<Type>(this); } | ||||
| 	forceinline ArrayHeader* get_header()                                      { return GEN_NS array_get_header<Type>(* this); } | ||||
| 	forceinline bool         grow(usize min_capacity)                          { return GEN_NS array_grow<Type>(this, min_capacity); } | ||||
| 	forceinline usize        num()                                             { return GEN_NS array_num<Type>(*this); } | ||||
| 	forceinline void         pop()                                             {        GEN_NS array_pop<Type>(* this); } | ||||
| 	forceinline void         remove_at(usize idx)                              {        GEN_NS array_remove_at<Type>(* this, idx); } | ||||
| 	forceinline bool         reserve(usize new_capacity)                       { return GEN_NS array_reserve<Type>(this, new_capacity); } | ||||
| 	forceinline bool         resize(usize num)                                 { return GEN_NS array_resize<Type>(this, num); } | ||||
| 	forceinline bool         set_capacity(usize new_capacity)                  { return GEN_NS array_set_capacity<Type>(this, new_capacity); } | ||||
| #pragma endregion Member Mapping | ||||
|  | ||||
| 	forceinline operator Type*()             { return Data; } | ||||
| 	forceinline operator Type const*() const { return Data; } | ||||
| 	forceinline Type* begin()                { return Data; } | ||||
| 	forceinline Type* end()                  { return Data + get_header()->Num; } | ||||
|  | ||||
| 	forceinline Type&       operator[](ssize index)       { return Data[index]; } | ||||
| 	forceinline Type const& operator[](ssize index) const { return Data[index]; } | ||||
|  | ||||
| 	using DataType = Type; | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| #if GEN_SUPPORT_CPP_REFERENCES | ||||
| template<class Type> bool         append(Array<Type>& array, Array<Type> other)                         { return GEN_NS append( & array, other ); } | ||||
| template<class Type> bool         append(Array<Type>& array, Type value)                                { return GEN_NS append( & array, value ); } | ||||
| template<class Type> bool         append(Array<Type>& array, Type* items, usize item_num)               { return GEN_NS append( & array, items, item_num ); } | ||||
| template<class Type> bool         append_at(Array<Type>& array, Type item, usize idx)                   { return GEN_NS append_at( & array, item, idx ); } | ||||
| template<class Type> bool         append_at(Array<Type>& array, Type* items, usize item_num, usize idx) { return GEN_NS append_at( & array, items, item_num, idx ); } | ||||
| template<class Type> void         free(Array<Type>& array)                                              { return GEN_NS free( & array ); } | ||||
| template<class Type> bool         grow(Array<Type>& array, usize min_capacity)                          { return GEN_NS grow( & array, min_capacity); } | ||||
| template<class Type> bool         reserve(Array<Type>& array, usize new_capacity)                       { return GEN_NS reserve( & array, new_capacity); } | ||||
| template<class Type> bool         resize(Array<Type>& array, usize num)                                 { return GEN_NS resize( & array, num); } | ||||
| template<class Type> bool         set_capacity(Array<Type>& array, usize new_capacity)                  { return GEN_NS set_capacity( & array, new_capacity); } | ||||
|  | ||||
| template<class Type> forceinline Type* begin(Array<Type>& array)             { return array;      } | ||||
| template<class Type> forceinline Type* end(Array<Type>& array)               { return array + array_get_header(array)->Num; } | ||||
| template<class Type> forceinline Type* next(Array<Type>& array, Type* entry) { return entry + 1; } | ||||
| #endif | ||||
|  | ||||
| template<class Type> forceinline Type* array_begin(Array<Type> array)             { return array;      } | ||||
| template<class Type> forceinline Type* array_end(Array<Type> array)               { return array + array_get_header(array)->Num; } | ||||
| template<class Type> forceinline Type* array_next(Array<Type> array, Type* entry) { return ++ entry; } | ||||
|  | ||||
| template<class Type> inline | ||||
| Array<Type> array_init(AllocatorInfo allocator) { | ||||
| 	return array_init_reserve<Type>(allocator, array_grow_formula(0)); | ||||
| } | ||||
|  | ||||
| 	static | ||||
| 	Array init_reserve( AllocatorInfo allocator, sw capacity ) | ||||
| template<class Type> inline | ||||
| Array<Type> array_init_reserve(AllocatorInfo allocator, ssize capacity) | ||||
| { | ||||
| 		Header* header = rcast( Header*, alloc( allocator, sizeof(Header) + sizeof(Type) * capacity )); | ||||
| 	ArrayHeader* header = rcast(ArrayHeader*, alloc(allocator, sizeof(ArrayHeader) + sizeof(Type) * capacity)); | ||||
|  | ||||
| 	if (header == nullptr) | ||||
|  		return {nullptr}; | ||||
| @@ -44,93 +145,101 @@ struct Array | ||||
| 	return {rcast(Type*, header + 1)}; | ||||
| } | ||||
|  | ||||
| 	static | ||||
| 	uw grow_formula( uw value ) | ||||
| 	{ | ||||
| usize array_grow_formula(ssize value) { | ||||
| 	return 2 * value + 8; | ||||
| } | ||||
|  | ||||
| 	bool append( Type value ) | ||||
| template<class Type> inline | ||||
| bool array_append_array(Array<Type>* array, Array<Type> other) { | ||||
| 	return array_append_items(array, (Type*)other, num(other)); | ||||
| } | ||||
|  | ||||
| template<class Type> inline | ||||
| bool array_append(Array<Type>* array, Type value) | ||||
| { | ||||
| 		Header* header = get_header(); | ||||
| 	ArrayHeader* header = array_get_header(* array); | ||||
|  | ||||
| 	if (header->Num == header->Capacity) | ||||
| 	{ | ||||
| 			if ( ! grow( header->Capacity )) | ||||
| 		if ( ! array_grow(array, header->Capacity)) | ||||
| 			return false; | ||||
|  | ||||
| 			header = get_header(); | ||||
| 		header = array_get_header(* array); | ||||
| 	} | ||||
|  | ||||
| 		Data[ header->Num ] = value; | ||||
| 	(*array)[ header->Num] = value; | ||||
| 	header->Num++; | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| 	bool append( Type* items, uw item_num ) | ||||
| template<class Type> inline | ||||
| bool array_append_items(Array<Type>* array, Type* items, usize item_num) | ||||
| { | ||||
| 		Header* header = get_header(); | ||||
| 	ArrayHeader* header = array_get_header(array); | ||||
|  | ||||
| 	if (header->Num + item_num > header->Capacity) | ||||
| 	{ | ||||
| 			if ( ! grow( header->Capacity + item_num )) | ||||
| 		if ( ! grow(array, header->Capacity + item_num)) | ||||
| 			return false; | ||||
|  | ||||
| 			header = get_header(); | ||||
| 		header = array_get_header(array); | ||||
| 	} | ||||
|  | ||||
| 		mem_copy( Data + header->Num, items, item_num * sizeof(Type) ); | ||||
| 	mem_copy((Type*)array + header->Num, items, item_num * sizeof(Type)); | ||||
| 	header->Num += item_num; | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| 	bool append_at( Type item, uw idx ) | ||||
| template<class Type> inline | ||||
| bool array_append_at(Array<Type>* array, Type item, usize idx) | ||||
| { | ||||
| 		Header* header = get_header(); | ||||
| 	ArrayHeader* header = array_get_header(* array); | ||||
|  | ||||
| 		if ( idx >= header->Num ) | ||||
| 			idx = header->Num - 1; | ||||
| 	ssize slot = idx; | ||||
| 	if (slot >= header->Num) | ||||
| 	 	slot = header->Num - 1; | ||||
|  | ||||
| 		if ( idx < 0 ) | ||||
| 			idx = 0; | ||||
| 	if (slot < 0) | ||||
|  		slot = 0; | ||||
|  | ||||
| 	if (header->Capacity < header->Num + 1) | ||||
| 	{ | ||||
| 			if ( ! grow( header->Capacity + 1 )) | ||||
| 		if ( ! array_grow(array, header->Capacity + 1)) | ||||
| 			return false; | ||||
|  | ||||
| 			header = get_header(); | ||||
| 		header = array_get_header(* array); | ||||
| 	} | ||||
|  | ||||
| 		Type* target = Data + idx; | ||||
| 	Type* target = &(*array)[slot]; | ||||
|  | ||||
| 		mem_move( target + 1, target, (header->Num - idx) * sizeof(Type) ); | ||||
| 	mem_move(target + 1, target, (header->Num - slot) * sizeof(Type)); | ||||
| 	header->Num++; | ||||
|  | ||||
| 	header = array_get_header(* array); | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| 	bool append_at( Type* items, uw item_num, uw idx ) | ||||
| template<class Type> inline | ||||
| bool array_append_items_at(Array<Type>* array, Type* items, usize item_num, usize idx) | ||||
| { | ||||
| 		Header* header = get_header(); | ||||
| 	ArrayHeader* header = get_header(array); | ||||
|  | ||||
| 	if (idx >= header->Num) | ||||
| 	{ | ||||
| 			return append( items, item_num ); | ||||
| 		return append(array, items, item_num); | ||||
|  	} | ||||
|  | ||||
| 	if (item_num > header->Capacity) | ||||
| 	{ | ||||
| 			if ( ! grow( header->Capacity + item_num ) ) | ||||
| 		if (! grow(array, header->Capacity + item_num)) | ||||
| 			return false; | ||||
|  | ||||
| 			header = get_header(); | ||||
| 		header = get_header(array); | ||||
| 	} | ||||
|  | ||||
| 		Type* target = Data + idx + item_num; | ||||
| 		Type* src    = Data + idx; | ||||
| 	Type* target = array.Data + idx + item_num; | ||||
| 	Type* src    = array.Data + idx; | ||||
|  | ||||
| 	mem_move(target, src, (header->Num - idx) * sizeof(Type)); | ||||
| 	mem_copy(src, items, item_num * sizeof(Type)); | ||||
| @@ -139,268 +248,337 @@ struct Array | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| 	Type& back( void ) | ||||
| template<class Type> inline | ||||
| Type* array_back(Array<Type> array) | ||||
| { | ||||
| 		Header& header = * get_header(); | ||||
| 		return Data[ header.Num - 1 ]; | ||||
| 	GEN_ASSERT(array != nullptr); | ||||
|  | ||||
| 	ArrayHeader* header = array_get_header(array); | ||||
| 	if (header->Num <= 0) | ||||
| 		return nullptr; | ||||
|  | ||||
| 	return & (array)[header->Num - 1]; | ||||
| } | ||||
|  | ||||
| 	void clear( void ) | ||||
| 	{ | ||||
| 		Header& header = * get_header(); | ||||
| 		header.Num     = 0; | ||||
| template<class Type> inline | ||||
| void array_clear(Array<Type> array) { | ||||
| 	ArrayHeader* header = array_get_header(array); | ||||
| 	header->Num = 0; | ||||
| } | ||||
|  | ||||
| 	bool fill( uw begin, uw end, Type value ) | ||||
| template<class Type> inline | ||||
| bool array_fill(Array<Type> array, usize begin, usize end, Type value) | ||||
| { | ||||
| 		Header& header = * get_header(); | ||||
| 	ArrayHeader* header = array_get_header(array); | ||||
|  | ||||
| 		if ( begin < 0 || end > header.Num ) | ||||
| 	if (begin < 0 || end > header->Num) | ||||
| 	return false; | ||||
|  | ||||
| 		for ( sw idx = begin; idx < end; idx++ ) | ||||
| 	for (ssize idx = ssize(begin); idx < ssize(end); idx++) | ||||
| 	{ | ||||
| 			Data[ idx ] = value; | ||||
| 		array[idx] = value; | ||||
| 	} | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| 	void free( void ) | ||||
| 	{ | ||||
| 		Header& header = * get_header(); | ||||
| 		gen::free( header.Allocator, &header ); | ||||
| 		Data = nullptr; | ||||
| template<class Type> inline | ||||
| void array_free(Array<Type>* array) { | ||||
| 	GEN_ASSERT(array != nullptr); | ||||
| 	ArrayHeader* header = array_get_header(* array); | ||||
| 	allocator_free(header->Allocator, header); | ||||
| 	Type** Data = (Type**)array; | ||||
| 	*Data = nullptr; | ||||
| } | ||||
|  | ||||
| 	Header* get_header( void ) | ||||
| 	{ | ||||
| template<class Type> forceinline | ||||
| ArrayHeader* array_get_header(Array<Type> array) { | ||||
|     Type* Data = array; | ||||
|  | ||||
| 	using NonConstType = TRemoveConst<Type>; | ||||
| 		return rcast( Header*, const_cast<NonConstType*>(Data) ) - 1 ; | ||||
|     return rcast(ArrayHeader*, const_cast<NonConstType*>(Data)) - 1; | ||||
| } | ||||
|  | ||||
| 	bool grow( uw min_capacity ) | ||||
| template<class Type> inline | ||||
| bool array_grow(Array<Type>* array, usize min_capacity) | ||||
| { | ||||
| 		Header& header       = * get_header(); | ||||
| 		uw      new_capacity = grow_formula( header.Capacity ); | ||||
| 	ArrayHeader* header       = array_get_header(* array); | ||||
| 	usize        new_capacity = array_grow_formula(header->Capacity); | ||||
|  | ||||
| 	if (new_capacity < min_capacity) | ||||
| 		new_capacity = min_capacity; | ||||
|  | ||||
| 		return set_capacity( new_capacity ); | ||||
| 	return array_set_capacity(array, new_capacity); | ||||
| } | ||||
|  | ||||
| 	uw num( void ) | ||||
| 	{ | ||||
| 		return get_header()->Num; | ||||
| template<class Type> inline | ||||
| usize array_num(Array<Type> array) { | ||||
| 	return array_get_header(array)->Num; | ||||
| } | ||||
|  | ||||
| 	void pop( void ) | ||||
| 	{ | ||||
| 		Header& header = * get_header(); | ||||
|  | ||||
| 		GEN_ASSERT( header.Num > 0 ); | ||||
| 		header.Num--; | ||||
| 	} | ||||
|  | ||||
| 	void remove_at( uw idx ) | ||||
| 	{ | ||||
| 		Header* header = get_header(); | ||||
| 		GEN_ASSERT( idx < header->Num ); | ||||
|  | ||||
| 		mem_move( header + idx, header + idx + 1, sizeof( Type ) * ( header->Num - idx - 1 ) ); | ||||
| template<class Type> inline | ||||
| void array_pop(Array<Type> array) { | ||||
| 	ArrayHeader* header = array_get_header(array); | ||||
| 	GEN_ASSERT(header->Num > 0); | ||||
| 	header->Num--; | ||||
| } | ||||
|  | ||||
| 	bool reserve( uw new_capacity ) | ||||
| template<class Type> inline | ||||
| void array_remove_at(Array<Type> array, usize idx) | ||||
| { | ||||
| 		Header& header = * get_header(); | ||||
| 	ArrayHeader* header = array_get_header(array); | ||||
| 	GEN_ASSERT(idx < header->Num); | ||||
|  | ||||
| 		if ( header.Capacity < new_capacity ) | ||||
| 			return set_capacity( new_capacity ); | ||||
| 	mem_move(array + idx, array + idx + 1, sizeof(Type) * (header->Num - idx - 1)); | ||||
| 	header->Num--; | ||||
| } | ||||
|  | ||||
| template<class Type> inline | ||||
| bool array_reserve(Array<Type>* array, usize new_capacity) | ||||
| { | ||||
| 	ArrayHeader* header = array_get_header(array); | ||||
|  | ||||
| 	if (header->Capacity < new_capacity) | ||||
|  		return set_capacity(array, new_capacity); | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| 	bool resize( uw num ) | ||||
| template<class Type> inline | ||||
| bool array_resize(Array<Type>* array, usize num) | ||||
| { | ||||
| 		Header* header = get_header(); | ||||
| 	ArrayHeader* header = array_get_header(* array); | ||||
|  | ||||
| 		if ( header->Capacity < num ) | ||||
| 		{ | ||||
| 			if ( ! grow( num ) ) | ||||
| 	if (header->Capacity < num) { | ||||
| 		if (! array_grow( array, num)) | ||||
| 			return false; | ||||
|  | ||||
| 			header = get_header(); | ||||
| 		header = array_get_header(* array); | ||||
| 	} | ||||
|  | ||||
| 	header->Num = num; | ||||
|  	return true; | ||||
| } | ||||
|  | ||||
| 	bool set_capacity( uw new_capacity ) | ||||
| template<class Type> inline | ||||
| bool array_set_capacity(Array<Type>* array, usize new_capacity) | ||||
| { | ||||
| 		Header& header = * get_header(); | ||||
| 	ArrayHeader* header = array_get_header(* array); | ||||
|  | ||||
| 		if ( new_capacity == header.Capacity ) | ||||
| 	if (new_capacity == header->Capacity) | ||||
| 	return true; | ||||
|  | ||||
| 		if ( new_capacity < header.Num ) | ||||
| 	if (new_capacity < header->Num) | ||||
| 	{ | ||||
| 			// Already have the memory, mine as well keep it. | ||||
| 			header.Num = new_capacity; | ||||
| 		header->Num = new_capacity; | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 		sw      size       = sizeof( Header ) + sizeof( Type ) * new_capacity; | ||||
| 		Header* new_header = rcast( Header*, alloc( header.Allocator, size ) ); | ||||
| 	ssize        size       = sizeof(ArrayHeader) + sizeof(Type) * new_capacity; | ||||
| 	ArrayHeader* new_header = rcast(ArrayHeader*, alloc(header->Allocator, size)); | ||||
|  | ||||
| 	if (new_header == nullptr) | ||||
| 		return false; | ||||
|  | ||||
| 		mem_move( new_header, &header, sizeof( Header ) + sizeof( Type ) * header.Num ); | ||||
| 	mem_move(new_header, header, sizeof(ArrayHeader) + sizeof(Type) * header->Num); | ||||
|  | ||||
| 	new_header->Capacity = new_capacity; | ||||
|  | ||||
| 		gen::free( header.Allocator, &header ); | ||||
| 	allocator_free(header->Allocator, header); | ||||
|  | ||||
| 		Data = rcast( Type*, new_header + 1); | ||||
| 	Type** Data = (Type**)array; | ||||
| 	* Data = rcast(Type*, new_header + 1); | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| 	Type* Data; | ||||
| // These are intended for use in the base library of gencpp and the C-variant of the library | ||||
| // It provides a interoperability between the C++ and C implementation of arrays. (not letting these do any crazy substiution though) | ||||
| // They are undefined in gen.hpp and gen.cpp at the end of the files. | ||||
| // We cpp library expects the user to use the regular calls as they can resolve the type fine. | ||||
|  | ||||
| 	operator Type*() | ||||
| 	{ | ||||
| 		return Data; | ||||
| 	} | ||||
| #define array_init(type, allocator)                        array_init           <type>                               (allocator ) | ||||
| #define array_init_reserve(type, allocator, cap)           array_init_reserve   <type>                               (allocator, cap) | ||||
| #define array_append_array(array, other)                   array_append_array   < get_array_underlying_type(array) > (& array, other ) | ||||
| #define array_append(array, value)                         array_append         < get_array_underlying_type(array) > (& array, value ) | ||||
| #define array_append_items(array, items, item_num)         array_append_items   < get_array_underlying_type(array) > (& array, items, item_num ) | ||||
| #define array_append_at(array, item, idx )                 array_append_at      < get_array_underlying_type(array) > (& array, item, idx ) | ||||
| #define array_append_at_items(array, items, item_num, idx) array_append_at_items< get_array_underlying_type(array) > (& items, item_num, idx ) | ||||
| #define array_back(array)                                  array_back           < get_array_underlying_type(array) > (array ) | ||||
| #define array_clear(array)                                 array_clear          < get_array_underlying_type(array) > (array ) | ||||
| #define array_fill(array, begin, end, value)               array_fill           < get_array_underlying_type(array) > (array, begin, end, value ) | ||||
| #define array_free(array)                                  array_free           < get_array_underlying_type(array) > (& array ) | ||||
| #define arary_grow(array, min_capacity)                    arary_grow           < get_array_underlying_type(array) > (& array, min_capacity) | ||||
| #define array_num(array)                                   array_num            < get_array_underlying_type(array) > (array ) | ||||
| #define arary_pop(array)                                   arary_pop            < get_array_underlying_type(array) > (array ) | ||||
| #define arary_remove_at(array, idx)                        arary_remove_at      < get_array_underlying_type(array) > (idx) | ||||
| #define arary_reserve(array, new_capacity)                 arary_reserve        < get_array_underlying_type(array) > (& array, new_capacity ) | ||||
| #define arary_resize(array, num)                           arary_resize         < get_array_underlying_type(array) > (& array, num) | ||||
| #define arary_set_capacity(new_capacity)                   arary_set_capacity   < get_array_underlying_type(array) > (& array, new_capacity ) | ||||
| #define arary_get_header(array)                            arary_get_header     < get_array_underlying_type(array) > (array ) | ||||
|  | ||||
| 	operator Type const*() const | ||||
| 	{ | ||||
| 		return Data; | ||||
| 	} | ||||
|  | ||||
| 	// For-range based support | ||||
|  | ||||
| 	Type* begin() | ||||
| 	{ | ||||
| 		return Data; | ||||
| 	} | ||||
|  | ||||
| 	Type* end() | ||||
| 	{ | ||||
| 		return Data + get_header()->Num; | ||||
| 	} | ||||
| }; | ||||
| #pragma endregion Array | ||||
|  | ||||
| // TODO(Ed) : This thing needs ALOT of work. | ||||
|  | ||||
| #pragma region HashTable | ||||
| #define HashTable(Type) HashTable<Type> | ||||
|  | ||||
| template<class Type> struct HashTable; | ||||
|  | ||||
| #ifndef get_hashtable_underlying_type | ||||
| #define get_hashtable_underlying_type(table) typename TRemovePtr<typeof(table)>:: DataType | ||||
| #endif | ||||
|  | ||||
| struct HashTableFindResult { | ||||
| 	ssize HashIndex; | ||||
| 	ssize PrevIndex; | ||||
| 	ssize EntryIndex; | ||||
| }; | ||||
|  | ||||
| template<class Type> | ||||
| struct HashTableEntry { | ||||
| 	u64   Key; | ||||
| 	ssize Next; | ||||
| 	Type  Value; | ||||
| }; | ||||
|  | ||||
| #define HashTableEntry(Type) HashTableEntry<Type> | ||||
|  | ||||
| template<class Type> HashTable<Type>       hashtable_init        (AllocatorInfo allocator); | ||||
| template<class Type> HashTable<Type>       hashtable_init_reserve(AllocatorInfo allocator, usize num); | ||||
| template<class Type> void                  hashtable_clear       (HashTable<Type>  table); | ||||
| template<class Type> void                  hashtable_destroy     (HashTable<Type>* table); | ||||
| template<class Type> Type*                 hashtable_get         (HashTable<Type>  table, u64 key); | ||||
| template<class Type> void                  hashtable_grow        (HashTable<Type>* table); | ||||
| template<class Type> void                  hashtable_rehash      (HashTable<Type>* table, ssize new_num); | ||||
| template<class Type> void                  hashtable_rehash_fast (HashTable<Type>  table); | ||||
| template<class Type> void                  hashtable_remove      (HashTable<Type>  table, u64 key); | ||||
| template<class Type> void                  hashtable_remove_entry(HashTable<Type>  table, ssize idx); | ||||
| template<class Type> void                  hashtable_set         (HashTable<Type>* table, u64 key, Type value); | ||||
| template<class Type> ssize                 hashtable_slot        (HashTable<Type>  table, u64 key); | ||||
| template<class Type> ssize                 hashtable_add_entry   (HashTable<Type>* table, u64 key); | ||||
| template<class Type> HashTableFindResult   hashtable_find        (HashTable<Type>  table, u64 key); | ||||
| template<class Type> bool                  hashtable_full        (HashTable<Type>  table); | ||||
| template<class Type> void                  hashtable_map         (HashTable<Type>  table, void (*map_proc)(u64 key, Type value)); | ||||
| template<class Type> void                  hashtable_map_mut     (HashTable<Type>  table, void (*map_proc)(u64 key, Type* value)); | ||||
|  | ||||
| static constexpr f32 HashTable_CriticalLoadScale = 0.7f; | ||||
|  | ||||
| template<typename Type> | ||||
| struct HashTable | ||||
| { | ||||
| 	struct FindResult | ||||
| 	{ | ||||
| 		sw HashIndex; | ||||
| 		sw PrevIndex; | ||||
| 		sw EntryIndex; | ||||
| 	Array<ssize>                Hashes; | ||||
| 	Array<HashTableEntry<Type>> Entries; | ||||
|  | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| #pragma region Member Mapping | ||||
| 	forceinline static HashTable init(AllocatorInfo allocator)                    { return GEN_NS hashtable_init<Type>(allocator); } | ||||
| 	forceinline static HashTable init_reserve(AllocatorInfo allocator, usize num) { return GEN_NS hashtable_init_reserve<Type>(allocator, num); } | ||||
|  | ||||
| 	forceinline void  clear()                           { GEN_NS clear<Type>(*this); } | ||||
| 	forceinline void  destroy()                         { GEN_NS destroy<Type>(*this); } | ||||
| 	forceinline Type* get(u64 key)                      { return GEN_NS get<Type>(*this, key); } | ||||
| 	forceinline void  grow()                            { GEN_NS grow<Type>(*this); } | ||||
| 	forceinline void  rehash(ssize new_num)             { GEN_NS rehash<Type>(*this, new_num); } | ||||
| 	forceinline void  rehash_fast()                     { GEN_NS rehash_fast<Type>(*this); } | ||||
| 	forceinline void  remove(u64 key)                   { GEN_NS remove<Type>(*this, key); } | ||||
| 	forceinline void  remove_entry(ssize idx)           { GEN_NS remove_entry<Type>(*this, idx); } | ||||
| 	forceinline void  set(u64 key, Type value)          { GEN_NS set<Type>(*this, key, value); } | ||||
| 	forceinline ssize slot(u64 key)                     { return GEN_NS slot<Type>(*this, key); } | ||||
| 	forceinline void  map(void (*proc)(u64, Type))      { GEN_NS map<Type>(*this, proc); } | ||||
| 	forceinline void  map_mut(void (*proc)(u64, Type*)) { GEN_NS map_mut<Type>(*this, proc); } | ||||
| #pragma endregion Member Mapping | ||||
| #endif | ||||
|  | ||||
| 	using DataType = Type; | ||||
| }; | ||||
|  | ||||
| 	struct Entry | ||||
| 	{ | ||||
| 		u64  Key; | ||||
| 		sw   Next; | ||||
| 		Type Value; | ||||
| 	}; | ||||
| #if GEN_SUPPORT_CPP_REFERENCES | ||||
| template<class Type> void  destroy  (HashTable<Type>& table)                      { destroy(& table); } | ||||
| template<class Type> void  grow     (HashTable<Type>& table)                      { grow(& table); } | ||||
| template<class Type> void  rehash   (HashTable<Type>& table, ssize new_num)       { rehash(& table, new_num); } | ||||
| template<class Type> void  set      (HashTable<Type>& table, u64 key, Type value) { set(& table, key, value); } | ||||
| template<class Type> ssize add_entry(HashTable<Type>& table, u64 key)             { add_entry(& table, key); } | ||||
| #endif | ||||
|  | ||||
| 	static constexpr f32 CriticalLoadScale = 0.7f; | ||||
|  | ||||
| 	static | ||||
| 	HashTable init( AllocatorInfo allocator ) | ||||
| 	{ | ||||
| 		HashTable<Type> result = init_reserve(allocator, 8); | ||||
| template<typename Type> inline | ||||
| HashTable<Type> hashtable_init(AllocatorInfo allocator) { | ||||
| 	HashTable<Type> result = hashtable_init_reserve<Type>(allocator, 8); | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| 	static | ||||
| 	HashTable init_reserve( AllocatorInfo allocator, uw num ) | ||||
| template<typename Type> inline | ||||
| HashTable<Type> hashtable_init_reserve(AllocatorInfo allocator, usize num) | ||||
| { | ||||
| 	HashTable<Type> result = { { nullptr }, { nullptr } }; | ||||
|  | ||||
| 		result.Hashes  = Array<sw>::init_reserve( allocator, num ); | ||||
| 		result.Hashes.get_header()->Num = num; | ||||
| 		result.Hashes.resize( num ); | ||||
| 		result.Hashes.fill( 0, num, -1); | ||||
| 	result.Hashes = array_init_reserve<ssize>(allocator, num); | ||||
| 	array_get_header(result.Hashes)->Num = num; | ||||
| 	array_resize(& result.Hashes, num); | ||||
| 	array_fill<ssize>(result.Hashes, 0, num, -1); | ||||
|  | ||||
| 		result.Entries = Array<Entry>::init_reserve( allocator, num ); | ||||
| 	result.Entries = array_init_reserve<HashTableEntry<Type>>(allocator, num); | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| 	void clear( void ) | ||||
| 	{ | ||||
| 		Entries.clear(); | ||||
| 		Hashes.fill( 0, Hashes.num(), -1); | ||||
| template<typename Type> inline | ||||
| void hashtable_clear(HashTable<Type> table) { | ||||
| 	array_clear(table.Entries); | ||||
| 	array_fill(table.Hashes, 0, array_num(table.Hashes), (ssize)-1); | ||||
| } | ||||
|  | ||||
| 	void destroy( void ) | ||||
| 	{ | ||||
| 		if ( Hashes && Hashes.get_header()->Capacity ) | ||||
| 		{ | ||||
| 			Hashes.free(); | ||||
| 			Entries.free(); | ||||
| template<typename Type> inline | ||||
| void hashtable_destroy(HashTable<Type>* table) { | ||||
| 	if (table->Hashes && array_get_header(table->Hashes)->Capacity) { | ||||
| 		array_free(table->Hashes); | ||||
| 		array_free(table->Entries); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| 	Type* get( u64 key ) | ||||
| 	{ | ||||
| 		sw idx = find( key ).EntryIndex; | ||||
| template<typename Type> inline | ||||
| Type* hashtable_get(HashTable<Type> table, u64 key) { | ||||
| 	ssize idx = hashtable_find(table, key).EntryIndex; | ||||
| 	if (idx >= 0) | ||||
| 			return & Entries[ idx ].Value; | ||||
| 		return & table.Entries[idx].Value; | ||||
|  | ||||
| 	return nullptr; | ||||
| } | ||||
|  | ||||
| 	using MapProc = void (*)( u64 key, Type  value ); | ||||
|  | ||||
| 	void map( MapProc map_proc ) | ||||
| 	{ | ||||
| template<typename Type> inline | ||||
| void hashtable_map(HashTable<Type> table, void (*map_proc)(u64 key, Type value)) { | ||||
| 	GEN_ASSERT_NOT_NULL(map_proc); | ||||
|  | ||||
| 		for ( sw idx = 0; idx < Entries.num(); idx++ ) | ||||
| 		{ | ||||
| 			map_proc( Entries[ idx ].Key, Entries[ idx ].Value ); | ||||
| 	for (ssize idx = 0; idx < ssize(num(table.Entries)); ++idx) { | ||||
| 		map_proc(table.Entries[idx].Key, table.Entries[idx].Value); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| 	using MapMutProc = void (*)( u64 key, Type* value ); | ||||
|  | ||||
| 	void map_mut( MapMutProc map_proc ) | ||||
| 	{ | ||||
| template<typename Type> inline | ||||
| void hashtable_map_mut(HashTable<Type> table, void (*map_proc)(u64 key, Type* value)) { | ||||
| 	GEN_ASSERT_NOT_NULL(map_proc); | ||||
|  | ||||
| 		for ( sw idx = 0; idx < Entries.num(); idx++ ) | ||||
| 		{ | ||||
| 			map_proc( Entries[ idx ].Key, & Entries[ idx ].Value ); | ||||
| 	for (ssize idx = 0; idx < ssize(num(table.Entries)); ++idx) { | ||||
| 		map_proc(table.Entries[idx].Key, & table.Entries[idx].Value); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| 	void grow() | ||||
| 	{ | ||||
| 		sw new_num = Array<Entry>::grow_formula( Entries.num() ); | ||||
| 		rehash( new_num ); | ||||
| template<typename Type> inline | ||||
| void hashtable_grow(HashTable<Type>* table) { | ||||
| 	ssize new_num = array_grow_formula( array_num(table->Entries)); | ||||
| 	hashtable_rehash(table, new_num); | ||||
| } | ||||
|  | ||||
| 	void rehash( sw new_num ) | ||||
| template<typename Type> inline | ||||
| void hashtable_rehash(HashTable<Type>* table, ssize new_num) | ||||
| { | ||||
| 		sw last_added_index; | ||||
| 	ssize last_added_index; | ||||
| 	HashTable<Type> new_ht = hashtable_init_reserve<Type>( array_get_header(table->Hashes)->Allocator, new_num); | ||||
|  | ||||
| 		HashTable<Type> new_ht = init_reserve( Hashes.get_header()->Allocator, new_num ); | ||||
| 		for ( sw idx = 0; idx < Entries.num(); ++idx ) | ||||
| 	for (ssize idx = 0; idx < ssize( array_num(table->Entries)); ++idx) | ||||
| 	{ | ||||
| 			FindResult find_result; | ||||
| 		HashTableFindResult find_result; | ||||
| 		HashTableEntry<Type>& entry = table->Entries[idx]; | ||||
|  | ||||
| 			Entry& entry     = Entries[ idx ]; | ||||
| 			find_result      = new_ht.find( entry.Key ); | ||||
| 			last_added_index = new_ht.add_entry( entry.Key ); | ||||
| 		find_result = hashtable_find(new_ht, entry.Key); | ||||
| 		last_added_index = hashtable_add_entry(& new_ht, entry.Key); | ||||
|  | ||||
| 		if (find_result.PrevIndex < 0) | ||||
| 			new_ht.Hashes[find_result.HashIndex] = last_added_index; | ||||
| @@ -411,136 +589,149 @@ struct HashTable | ||||
| 		new_ht.Entries[last_added_index].Value = entry.Value; | ||||
| 	} | ||||
|  | ||||
| 		destroy(); | ||||
| 		*this = new_ht; | ||||
| 	hashtable_destroy(table); | ||||
| 	* table = new_ht; | ||||
| } | ||||
|  | ||||
| 	void rehash_fast() | ||||
| template<typename Type> inline | ||||
| void hashtable_rehash_fast(HashTable<Type> table) | ||||
| { | ||||
| 		sw idx; | ||||
| 	ssize idx; | ||||
|  | ||||
| 		for ( idx = 0; idx < Entries.num(); idx++ ) | ||||
| 			Entries[ idx ].Next = -1; | ||||
| 	for (idx = 0; idx < ssize(num(table.Entries)); idx++) | ||||
| 		table.Entries[idx].Next = -1; | ||||
|  | ||||
| 		for ( idx = 0; idx < Hashes.num(); idx++ ) | ||||
| 			Hashes[ idx ] = -1; | ||||
| 	for (idx = 0; idx < ssize(num(table.Hashes)); idx++) | ||||
| 		table.Hashes[idx] = -1; | ||||
|  | ||||
| 		for ( idx = 0; idx < Entries.num(); idx++ ) | ||||
| 	for (idx = 0; idx < ssize(num(table.Entries)); idx++) | ||||
| 	{ | ||||
| 			Entry*     entry; | ||||
| 			FindResult find_result; | ||||
| 		HashTableEntry<Type>* entry; | ||||
| 		HashTableFindResult find_result; | ||||
|  | ||||
| 			entry       = & Entries[ idx ]; | ||||
| 			find_result = find( entry->Key ); | ||||
| 		entry = &table.Entries[idx]; | ||||
| 		find_result = find(table, entry->Key); | ||||
|  | ||||
| 		if (find_result.PrevIndex < 0) | ||||
| 				Hashes[ find_result.HashIndex ] = idx; | ||||
| 			table.Hashes[find_result.HashIndex] = idx; | ||||
| 		else | ||||
| 				Entries[ find_result.PrevIndex ].Next = idx; | ||||
| 			table.Entries[find_result.PrevIndex].Next = idx; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| 	void remove( u64 key ) | ||||
| 	{ | ||||
| 		FindResult find_result = find( key); | ||||
| template<typename Type> inline | ||||
| void hashtable_remove(HashTable<Type> table, u64 key) { | ||||
| 	HashTableFindResult find_result = find(table, key); | ||||
|  | ||||
| 		if ( find_result.EntryIndex >= 0 ) | ||||
| 		{ | ||||
| 			Entries.remove_at( find_result.EntryIndex ); | ||||
| 			rehash_fast(); | ||||
| 	if (find_result.EntryIndex >= 0) { | ||||
| 		remove_at(table.Entries, find_result.EntryIndex); | ||||
| 		rehash_fast(table); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| 	void remove_entry( sw idx ) | ||||
| 	{ | ||||
| 		Entries.remove_at( idx ); | ||||
| template<typename Type> inline | ||||
| void hashtable_remove_entry(HashTable<Type> table, ssize idx) { | ||||
| 	remove_at(table.Entries, idx); | ||||
| } | ||||
|  | ||||
| 	void set( u64 key, Type value ) | ||||
| template<typename Type> inline | ||||
| void hashtable_set(HashTable<Type>* table, u64 key, Type value) | ||||
| { | ||||
| 		sw idx; | ||||
| 		FindResult find_result; | ||||
| 	ssize idx; | ||||
| 	HashTableFindResult find_result; | ||||
|  | ||||
| 		if ( full() ) | ||||
| 			grow(); | ||||
| 	if (hashtable_full(* table)) | ||||
| 		hashtable_grow(table); | ||||
|  | ||||
| 		find_result = find( key ); | ||||
| 		if ( find_result.EntryIndex >= 0 ) | ||||
| 		{ | ||||
| 	find_result = hashtable_find(* table, key); | ||||
| 	if (find_result.EntryIndex >= 0) { | ||||
| 		idx = find_result.EntryIndex; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 			idx = add_entry( key ); | ||||
| 		idx = hashtable_add_entry(table, key); | ||||
|  | ||||
| 			if ( find_result.PrevIndex >= 0 ) | ||||
| 			{ | ||||
| 				Entries[ find_result.PrevIndex ].Next = idx; | ||||
| 		if (find_result.PrevIndex >= 0) { | ||||
| 			table->Entries[find_result.PrevIndex].Next = idx; | ||||
| 		} | ||||
| 			else | ||||
| 			{ | ||||
| 				Hashes[ find_result.HashIndex ] = idx; | ||||
| 		else { | ||||
| 			table->Hashes[find_result.HashIndex] = idx; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 		Entries[ idx ].Value = value; | ||||
| 	table->Entries[idx].Value = value; | ||||
|  | ||||
| 		if ( full() ) | ||||
| 			grow(); | ||||
| 	if (hashtable_full(* table)) | ||||
| 		hashtable_grow(table); | ||||
| } | ||||
|  | ||||
| 	sw slot( u64 key ) | ||||
| 	{ | ||||
| 		for ( sw idx = 0; idx < Hashes.num(); ++idx ) | ||||
| 			if ( Hashes[ idx ] == key ) | ||||
| template<typename Type> inline | ||||
| ssize hashtable_slot(HashTable<Type> table, u64 key) { | ||||
| 	for (ssize idx = 0; idx < ssize(num(table.Hashes)); ++idx) | ||||
| 		if (table.Hashes[idx] == key) | ||||
| 			return idx; | ||||
|  | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| 	Array< sw>    Hashes; | ||||
| 	Array< Entry> Entries; | ||||
| template<typename Type> inline | ||||
| ssize hashtable_add_entry(HashTable<Type>* table, u64 key) { | ||||
| 	ssize idx; | ||||
| 	HashTableEntry<Type> entry = { key, -1 }; | ||||
|  | ||||
| protected: | ||||
|  | ||||
| 	sw add_entry( u64 key ) | ||||
| 	{ | ||||
| 		sw idx; | ||||
| 		Entry entry = { key, -1 }; | ||||
|  | ||||
| 		idx = Entries.num(); | ||||
| 		Entries.append( entry ); | ||||
| 	idx = array_num(table->Entries); | ||||
| 	array_append( table->Entries, entry); | ||||
| 	return idx; | ||||
| } | ||||
|  | ||||
| 	FindResult find( u64 key ) | ||||
| template<typename Type> inline | ||||
| HashTableFindResult hashtable_find(HashTable<Type> table, u64 key) | ||||
| { | ||||
| 		FindResult result = { -1, -1, -1 }; | ||||
| 	HashTableFindResult result = { -1, -1, -1 }; | ||||
|  | ||||
| 		if ( Hashes.num() > 0 ) | ||||
| 	if (array_num(table.Hashes) > 0) | ||||
| 	{ | ||||
| 			result.HashIndex    = key % Hashes.num(); | ||||
| 			result.EntryIndex  = Hashes[ result.HashIndex ]; | ||||
| 		result.HashIndex = key % array_num(table.Hashes); | ||||
| 		result.EntryIndex = table.Hashes[result.HashIndex]; | ||||
|  | ||||
| 		while (result.EntryIndex >= 0) | ||||
| 		{ | ||||
| 				if ( Entries[ result.EntryIndex ].Key == key ) | ||||
| 			if (table.Entries[result.EntryIndex].Key == key) | ||||
| 				break; | ||||
|  | ||||
| 			result.PrevIndex = result.EntryIndex; | ||||
| 				result.EntryIndex = Entries[ result.EntryIndex ].Next; | ||||
| 			result.EntryIndex = table.Entries[result.EntryIndex].Next; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| 	b32 full() | ||||
| 	{ | ||||
| 		uw critical_load = uw( CriticalLoadScale * f32(Hashes.num()) ); | ||||
| 		b32 result = Entries.num() > critical_load; | ||||
| template<typename Type> inline | ||||
| bool hashtable_full(HashTable<Type> table) { | ||||
| 	usize critical_load = usize(HashTable_CriticalLoadScale * f32(array_num(table.Hashes))); | ||||
| 	b32 result = array_num(table.Entries) > critical_load; | ||||
| 	return result; | ||||
| } | ||||
| }; | ||||
|  | ||||
| #define hashtable_init(type, allocator)              hashtable_init        <type              >(allocator) | ||||
| #define hashtable_init_reserve(type, allocator, num) hashtable_init_reserve<type              >(allocator, num) | ||||
| #define hashtable_clear(table)                       hashtable_clear       < get_hashtable_underlying_type(table) >(table) | ||||
| #define hashtable_destroy(table)                     hashtable_destroy     < get_hashtable_underlying_type(table) >(& table) | ||||
| #define hashtable_get(table, key)                    hashtable_get         < get_hashtable_underlying_type(table) >(table, key) | ||||
| #define hashtable_grow(table)                        hashtable_grow        < get_hashtable_underlying_type(table) >(& table) | ||||
| #define hashtable_rehash(table, new_num)             hashtable_rehash      < get_hashtable_underlying_type(table) >(& table, new_num) | ||||
| #define hashtable_rehash_fast(table)                 hashtable_rehash_fast < get_hashtable_underlying_type(table) >(table) | ||||
| #define hashtable_remove(table, key)                 hashtable_remove      < get_hashtable_underlying_type(table) >(table, key) | ||||
| #define hashtable_remove_entry(table, idx)           hashtable_remove_entry< get_hashtable_underlying_type(table) >(table, idx) | ||||
| #define hashtable_set(table, key, value)             hashtable_set         < get_hashtable_underlying_type(table) >(& table, key, value) | ||||
| #define hashtable_slot(table, key)                   hashtable_slot        < get_hashtable_underlying_type(table) >(table, key) | ||||
| #define hashtable_add_entry(table, key)              hashtable_add_entry   < get_hashtable_underlying_type(table) >(& table, key) | ||||
| #define hashtable_find(table, key)                   hashtable_find        < get_hashtable_underlying_type(table) >(table, key) | ||||
| #define hashtable_full(table)                        hashtable_full        < get_hashtable_underlying_type(table) >(table) | ||||
| #define hashtable_map(table, map_proc)               hashtable_map         < get_hashtable_underlying_type(table) >(table, map_proc) | ||||
| #define hashtable_map_mut(table, map_proc)           hashtable_map_mut     < get_hashtable_underlying_type(table) >(table, map_proc) | ||||
|  | ||||
| #pragma endregion HashTable | ||||
|  | ||||
| #pragma endregion Containers | ||||
|   | ||||
| @@ -6,6 +6,7 @@ | ||||
| #endif | ||||
|  | ||||
| #pragma region Debug | ||||
| GEN_API_C_BEGIN | ||||
|  | ||||
| void assert_handler( char const* condition, char const* file, s32 line, char const* msg, ... ) | ||||
| { | ||||
| @@ -45,4 +46,5 @@ s32 assert_crash( char const* condition ) | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| GEN_API_C_END | ||||
| #pragma endregion Debug | ||||
|   | ||||
| @@ -24,7 +24,7 @@ | ||||
| 	{                                                                                        \ | ||||
| 		if ( ! ( cond ) )                                                                    \ | ||||
| 		{                                                                                    \ | ||||
| 			assert_handler( #cond, __FILE__, zpl_cast( s64 ) __LINE__, msg, ##__VA_ARGS__ ); \ | ||||
| 			assert_handler( #cond, __FILE__, scast( s64, __LINE__ ), msg, ##__VA_ARGS__ );   \ | ||||
| 			GEN_DEBUG_TRAP();                                                                \ | ||||
| 		}                                                                                    \ | ||||
| 	} while ( 0 ) | ||||
| @@ -34,10 +34,6 @@ | ||||
| // NOTE: Things that shouldn't happen with a message! | ||||
| #define GEN_PANIC( msg, ... ) GEN_ASSERT_MSG( 0, msg, ##__VA_ARGS__ ) | ||||
|  | ||||
| void assert_handler( char const* condition, char const* file, s32 line, char const* msg, ... ); | ||||
| s32  assert_crash( char const* condition ); | ||||
| void process_exit( u32 code ); | ||||
|  | ||||
| #if Build_Debug | ||||
| 	#define GEN_FATAL( ... )                               \ | ||||
| 	do                                                     \ | ||||
| @@ -60,4 +56,10 @@ void process_exit( u32 code ); | ||||
| 	while (0) | ||||
| #endif | ||||
|  | ||||
| GEN_API_C_BEGIN | ||||
| void assert_handler( char const* condition, char const* file, s32 line, char const* msg, ... ); | ||||
| s32  assert_crash( char const* condition ); | ||||
| void process_exit( u32 code ); | ||||
| GEN_API_C_END | ||||
|  | ||||
| #pragma endregion Debug | ||||
|   | ||||
| @@ -4,13 +4,15 @@ | ||||
| #endif | ||||
|  | ||||
| #pragma region File Handling | ||||
| GEN_API_C_BEGIN | ||||
|  | ||||
| #if defined( GEN_SYSTEM_WINDOWS ) || defined( GEN_SYSTEM_CYGWIN ) | ||||
|  | ||||
| internal wchar_t* _alloc_utf8_to_ucs2( AllocatorInfo a, char const* text, sw* w_len_ ) | ||||
| internal | ||||
| wchar_t* _alloc_utf8_to_ucs2( AllocatorInfo a, char const* text, ssize* w_len_ ) | ||||
| { | ||||
| 	wchar_t* w_text = NULL; | ||||
| 	sw       len = 0, w_len = 0, w_len1 = 0; | ||||
| 	ssize       len = 0, w_len = 0, w_len1 = 0; | ||||
| 	if ( text == NULL ) | ||||
| 	{ | ||||
| 		if ( w_len_ ) | ||||
| @@ -24,7 +26,7 @@ internal wchar_t* _alloc_utf8_to_ucs2( AllocatorInfo a, char const* text, sw* w_ | ||||
| 			*w_len_ = w_len; | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	w_len = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, text, zpl_cast( int ) len, NULL, 0 ); | ||||
| 	w_len = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, text, scast( int, len), NULL, 0 ); | ||||
| 	if ( w_len == 0 ) | ||||
| 	{ | ||||
| 		if ( w_len_ ) | ||||
| @@ -32,10 +34,10 @@ internal wchar_t* _alloc_utf8_to_ucs2( AllocatorInfo a, char const* text, sw* w_ | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	w_text = alloc_array( a, wchar_t, w_len + 1 ); | ||||
| 	w_len1 = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, text, zpl_cast( int ) len, w_text, zpl_cast( int ) w_len ); | ||||
| 	w_len1 = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, text, scast( int, len), w_text, scast( int, w_len) ); | ||||
| 	if ( w_len1 == 0 ) | ||||
| 	{ | ||||
| 		free( a, w_text ); | ||||
| 		allocator_free( a, w_text ); | ||||
| 		if ( w_len_ ) | ||||
| 			*w_len_ = 0; | ||||
| 		return NULL; | ||||
| @@ -46,7 +48,8 @@ internal wchar_t* _alloc_utf8_to_ucs2( AllocatorInfo a, char const* text, sw* w_ | ||||
| 	return w_text; | ||||
| } | ||||
|  | ||||
| internal GEN_FILE_SEEK_PROC( _win32_file_seek ) | ||||
| internal | ||||
| GEN_FILE_SEEK_PROC( _win32_file_seek ) | ||||
| { | ||||
| 	LARGE_INTEGER li_offset; | ||||
| 	li_offset.QuadPart = offset; | ||||
| @@ -60,12 +63,13 @@ internal GEN_FILE_SEEK_PROC( _win32_file_seek ) | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| internal GEN_FILE_READ_AT_PROC( _win32_file_read ) | ||||
| internal | ||||
| GEN_FILE_READ_AT_PROC( _win32_file_read ) | ||||
| { | ||||
| 	// unused( stop_at_newline ); | ||||
| 	b32 result = false; | ||||
| 	_win32_file_seek( fd, offset, ESeekWhence_BEGIN, NULL ); | ||||
| 	DWORD size_ = zpl_cast( DWORD )( size > GEN_I32_MAX ? GEN_I32_MAX : size ); | ||||
| 	DWORD size_ = scast( DWORD, ( size > GEN_I32_MAX ? GEN_I32_MAX : size )); | ||||
| 	DWORD bytes_read_; | ||||
| 	if ( ReadFile( fd.p, buffer, size_, &bytes_read_, NULL ) ) | ||||
| 	{ | ||||
| @@ -77,9 +81,10 @@ internal GEN_FILE_READ_AT_PROC( _win32_file_read ) | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| internal GEN_FILE_WRITE_AT_PROC( _win32_file_write ) | ||||
| internal | ||||
| GEN_FILE_WRITE_AT_PROC( _win32_file_write ) | ||||
| { | ||||
| 	DWORD size_ = zpl_cast( DWORD )( size > GEN_I32_MAX ? GEN_I32_MAX : size ); | ||||
| 	DWORD size_ = scast( DWORD, ( size > GEN_I32_MAX ? GEN_I32_MAX : size )); | ||||
| 	DWORD bytes_written_; | ||||
| 	_win32_file_seek( fd, offset, ESeekWhence_BEGIN, NULL ); | ||||
| 	if ( WriteFile( fd.p, buffer, size_, &bytes_written_, NULL ) ) | ||||
| @@ -91,14 +96,16 @@ internal GEN_FILE_WRITE_AT_PROC( _win32_file_write ) | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| internal GEN_FILE_CLOSE_PROC( _win32_file_close ) | ||||
| internal | ||||
| GEN_FILE_CLOSE_PROC( _win32_file_close ) | ||||
| { | ||||
| 	CloseHandle( fd.p ); | ||||
| } | ||||
|  | ||||
| FileOperations const default_file_operations = { _win32_file_read, _win32_file_write, _win32_file_seek, _win32_file_close }; | ||||
|  | ||||
| neverinline GEN_FILE_OPEN_PROC( _win32_file_open ) | ||||
| neverinline | ||||
| GEN_FILE_OPEN_PROC( _win32_file_open ) | ||||
| { | ||||
| 	DWORD    desired_access; | ||||
| 	DWORD    creation_disposition; | ||||
| @@ -139,7 +146,7 @@ neverinline GEN_FILE_OPEN_PROC( _win32_file_open ) | ||||
| 	w_text = _alloc_utf8_to_ucs2( heap(), filename, NULL ); | ||||
| 	handle = CreateFileW( w_text, desired_access, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, creation_disposition, FILE_ATTRIBUTE_NORMAL, NULL ); | ||||
|  | ||||
| 	free( heap(), w_text ); | ||||
| 	allocator_free( heap(), w_text ); | ||||
|  | ||||
| 	if ( handle == INVALID_HANDLE_VALUE ) | ||||
| 	{ | ||||
| @@ -176,7 +183,8 @@ neverinline GEN_FILE_OPEN_PROC( _win32_file_open ) | ||||
| #else    // POSIX | ||||
| #	include <fcntl.h> | ||||
|  | ||||
| internal GEN_FILE_SEEK_PROC( _posix_file_seek ) | ||||
| internal | ||||
| GEN_FILE_SEEK_PROC( _posix_file_seek ) | ||||
| { | ||||
| #	if defined( GEN_SYSTEM_OSX ) | ||||
| 	s64 res = lseek( fd.i, offset, whence ); | ||||
| @@ -190,10 +198,11 @@ internal GEN_FILE_SEEK_PROC( _posix_file_seek ) | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| internal GEN_FILE_READ_AT_PROC( _posix_file_read ) | ||||
| internal | ||||
| GEN_FILE_READ_AT_PROC( _posix_file_read ) | ||||
| { | ||||
| 	unused( stop_at_newline ); | ||||
| 	sw res = pread( fd.i, buffer, size, offset ); | ||||
| 	ssize res = pread( fd.i, buffer, size, offset ); | ||||
| 	if ( res < 0 ) | ||||
| 		return false; | ||||
| 	if ( bytes_read ) | ||||
| @@ -201,19 +210,20 @@ internal GEN_FILE_READ_AT_PROC( _posix_file_read ) | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| internal GEN_FILE_WRITE_AT_PROC( _posix_file_write ) | ||||
| internal | ||||
| GEN_FILE_WRITE_AT_PROC( _posix_file_write ) | ||||
| { | ||||
| 	sw  res; | ||||
| 	ssize  res; | ||||
| 	s64 curr_offset = 0; | ||||
| 	_posix_file_seek( fd, 0, ESeekWhence_CURRENT, &curr_offset ); | ||||
| 	if ( curr_offset == offset ) | ||||
| 	{ | ||||
| 		// NOTE: Writing to stdout et al. doesn't like pwrite for numerous reasons | ||||
| 		res = write( zpl_cast( int ) fd.i, buffer, size ); | ||||
| 		res = write( scast( int, fd.i), buffer, size ); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		res = pwrite( zpl_cast( int ) fd.i, buffer, size, offset ); | ||||
| 		res = pwrite( scast( int, fd.i), buffer, size, offset ); | ||||
| 	} | ||||
| 	if ( res < 0 ) | ||||
| 		return false; | ||||
| @@ -222,14 +232,16 @@ internal GEN_FILE_WRITE_AT_PROC( _posix_file_write ) | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| internal GEN_FILE_CLOSE_PROC( _posix_file_close ) | ||||
| internal | ||||
| GEN_FILE_CLOSE_PROC( _posix_file_close ) | ||||
| { | ||||
| 	close( fd.i ); | ||||
| } | ||||
|  | ||||
| FileOperations const default_file_operations = { _posix_file_read, _posix_file_write, _posix_file_seek, _posix_file_close }; | ||||
|  | ||||
| neverinline GEN_FILE_OPEN_PROC( _posix_file_open ) | ||||
| neverinline | ||||
| GEN_FILE_OPEN_PROC( _posix_file_open ) | ||||
| { | ||||
| 	s32 os_mode; | ||||
| 	switch ( mode & GEN_FILE_MODES ) | ||||
| @@ -329,7 +341,7 @@ FileError file_close( FileInfo* f ) | ||||
| 		return EFileError_INVALID; | ||||
|  | ||||
| 	if ( f->filename ) | ||||
| 		free( heap(), zpl_cast( char* ) f->filename ); | ||||
| 		allocator_free( heap(), ccast( char*, f->filename )); | ||||
|  | ||||
| #if defined( GEN_SYSTEM_WINDOWS ) | ||||
| 	if ( f->fd.p == INVALID_HANDLE_VALUE ) | ||||
| @@ -364,14 +376,14 @@ FileError file_close( FileInfo* f ) | ||||
| FileError file_new( FileInfo* f, FileDescriptor fd, FileOperations ops, char const* filename ) | ||||
| { | ||||
| 	FileError err = EFileError_NONE; | ||||
| 	sw        len = str_len( filename ); | ||||
| 	ssize        len = str_len( filename ); | ||||
|  | ||||
| 	f->ops             = ops; | ||||
| 	f->fd              = fd; | ||||
| 	f->dir             = nullptr; | ||||
| 	f->last_write_time = 0; | ||||
| 	f->filename        = alloc_array( heap(), char, len + 1 ); | ||||
| 	mem_copy( zpl_cast( char* ) f->filename, zpl_cast( char* ) filename, len + 1 ); | ||||
| 	mem_copy( ccast( char*, f->filename), ccast( char*, filename), len + 1 ); | ||||
|  | ||||
| 	return err; | ||||
| } | ||||
| @@ -430,7 +442,7 @@ FileContents file_read_contents( AllocatorInfo a, b32 zero_terminate, char const | ||||
|  | ||||
| 	if ( file_open( &file, filepath ) == EFileError_NONE ) | ||||
| 	{ | ||||
| 		sw fsize = zpl_cast( sw ) file_size( &file ); | ||||
| 		ssize fsize = scast( ssize , file_size( &file )); | ||||
| 		if ( fsize > 0 ) | ||||
| 		{ | ||||
| 			result.data = alloc( a, zero_terminate ? fsize + 1 : fsize ); | ||||
| @@ -438,7 +450,7 @@ FileContents file_read_contents( AllocatorInfo a, b32 zero_terminate, char const | ||||
| 			file_read_at( &file, result.data, result.size, 0 ); | ||||
| 			if ( zero_terminate ) | ||||
| 			{ | ||||
| 				u8* str      = zpl_cast( u8* ) result.data; | ||||
| 				u8* str      = rcast( u8*, result.data); | ||||
| 				str[ fsize ] = '\0'; | ||||
| 			} | ||||
| 		} | ||||
| @@ -452,26 +464,28 @@ struct _memory_fd | ||||
| { | ||||
| 	u8            magic; | ||||
| 	u8*           buf;    //< zpl_array OR plain buffer if we can't write | ||||
| 	sw            cursor; | ||||
| 	ssize         cursor; | ||||
| 	AllocatorInfo allocator; | ||||
|  | ||||
| 	FileStreamFlags flags; | ||||
| 	sw              cap; | ||||
| 	ssize           cap; | ||||
| }; | ||||
|  | ||||
| #define GEN__FILE_STREAM_FD_MAGIC 37 | ||||
|  | ||||
| GEN_DEF_INLINE FileDescriptor _file_stream_fd_make( _memory_fd* d ); | ||||
| GEN_DEF_INLINE _memory_fd*    _file_stream_from_fd( FileDescriptor fd ); | ||||
| FileDescriptor _file_stream_fd_make( _memory_fd* d ); | ||||
| _memory_fd*    _file_stream_from_fd( FileDescriptor fd ); | ||||
|  | ||||
| GEN_IMPL_INLINE FileDescriptor _file_stream_fd_make( _memory_fd* d ) | ||||
| inline | ||||
| FileDescriptor _file_stream_fd_make( _memory_fd* d ) | ||||
| { | ||||
| 	FileDescriptor fd = { 0 }; | ||||
| 	fd.p              = ( void* )d; | ||||
| 	return fd; | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE _memory_fd* _file_stream_from_fd( FileDescriptor fd ) | ||||
| inline | ||||
| _memory_fd* _file_stream_from_fd( FileDescriptor fd ) | ||||
| { | ||||
| 	_memory_fd* d = ( _memory_fd* )fd.p; | ||||
| 	GEN_ASSERT( d->magic == GEN__FILE_STREAM_FD_MAGIC ); | ||||
| @@ -492,7 +506,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; | ||||
| @@ -506,7 +520,7 @@ b8 file_stream_new( FileInfo* file, AllocatorInfo allocator ) | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| b8 file_stream_open( FileInfo* file, AllocatorInfo allocator, u8* buffer, sw size, FileStreamFlags flags ) | ||||
| b8 file_stream_open( FileInfo* file, AllocatorInfo allocator, u8* buffer, ssize size, FileStreamFlags flags ) | ||||
| { | ||||
| 	GEN_ASSERT_NOT_NULL( file ); | ||||
| 	_memory_fd* d = ( _memory_fd* )alloc( allocator, size_of( _memory_fd ) ); | ||||
| @@ -518,7 +532,7 @@ b8 file_stream_open( FileInfo* file, AllocatorInfo allocator, u8* buffer, sw siz | ||||
| 	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 ) | ||||
| @@ -527,7 +541,7 @@ b8 file_stream_open( FileInfo* file, AllocatorInfo allocator, u8* buffer, sw siz | ||||
| 		mem_copy( d->buf, buffer, size ); | ||||
| 		d->cap = size; | ||||
|  | ||||
| 		arr.get_header()->Num = size; | ||||
| 		array_get_header(arr)->Num = size; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| @@ -543,7 +557,7 @@ b8 file_stream_open( FileInfo* file, AllocatorInfo allocator, u8* buffer, sw siz | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| u8* file_stream_buf( FileInfo* file, sw* size ) | ||||
| u8* file_stream_buf( FileInfo* file, ssize* size ) | ||||
| { | ||||
| 	GEN_ASSERT_NOT_NULL( file ); | ||||
| 	_memory_fd* d = _file_stream_from_fd( file->fd ); | ||||
| @@ -552,10 +566,11 @@ u8* file_stream_buf( FileInfo* file, sw* size ) | ||||
| 	return d->buf; | ||||
| } | ||||
|  | ||||
| internal GEN_FILE_SEEK_PROC( _memory_file_seek ) | ||||
| internal | ||||
| GEN_FILE_SEEK_PROC( _memory_file_seek ) | ||||
| { | ||||
| 	_memory_fd* d      = _file_stream_from_fd( fd ); | ||||
| 	sw          buflen = d->cap; | ||||
| 	ssize          buflen = d->cap; | ||||
|  | ||||
| 	if ( whence == ESeekWhence_BEGIN ) | ||||
| 		d->cursor = 0; | ||||
| @@ -568,7 +583,8 @@ internal GEN_FILE_SEEK_PROC( _memory_file_seek ) | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| internal GEN_FILE_READ_AT_PROC( _memory_file_read ) | ||||
| internal | ||||
| GEN_FILE_READ_AT_PROC( _memory_file_read ) | ||||
| { | ||||
| 	// unused( stop_at_newline ); | ||||
| 	_memory_fd* d = _file_stream_from_fd( fd ); | ||||
| @@ -578,25 +594,26 @@ internal GEN_FILE_READ_AT_PROC( _memory_file_read ) | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| internal GEN_FILE_WRITE_AT_PROC( _memory_file_write ) | ||||
| internal | ||||
| GEN_FILE_WRITE_AT_PROC( _memory_file_write ) | ||||
| { | ||||
| 	_memory_fd* d = _file_stream_from_fd( fd ); | ||||
|  | ||||
| 	if ( ! ( d->flags & ( EFileStream_CLONE_WRITABLE | EFileStream_WRITABLE ) ) ) | ||||
| 		return false; | ||||
|  | ||||
| 	sw buflen   = d->cap; | ||||
| 	sw extralen = max( 0, size - ( buflen - offset ) ); | ||||
| 	sw rwlen    = size - extralen; | ||||
| 	sw new_cap  = buflen + extralen; | ||||
| 	ssize buflen   = d->cap; | ||||
| 	ssize extralen = max( 0, size - ( buflen - offset ) ); | ||||
| 	ssize rwlen    = size - extralen; | ||||
| 	ssize new_cap  = buflen + extralen; | ||||
|  | ||||
| 	if ( d->flags & EFileStream_CLONE_WRITABLE ) | ||||
| 	{ | ||||
| 		Array<u8> arr = { d->buf }; | ||||
|  | ||||
| 		if ( arr.get_header()->Capacity < new_cap ) | ||||
| 		if ( array_get_header(arr)->Capacity < usize(new_cap) ) | ||||
| 		{ | ||||
| 			if ( ! arr.grow( ( s64 )( new_cap ) ) ) | ||||
| 			if ( ! array_grow( & arr, ( s64 )( new_cap ) ) ) | ||||
| 				return false; | ||||
| 			d->buf = arr; | ||||
| 		} | ||||
| @@ -610,7 +627,7 @@ internal 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; | ||||
| 		array_get_header(arr)->Capacity = new_cap; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| @@ -622,7 +639,8 @@ internal GEN_FILE_WRITE_AT_PROC( _memory_file_write ) | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| internal GEN_FILE_CLOSE_PROC( _memory_file_close ) | ||||
| internal | ||||
| GEN_FILE_CLOSE_PROC( _memory_file_close ) | ||||
| { | ||||
| 	_memory_fd*   d         = _file_stream_from_fd( fd ); | ||||
| 	AllocatorInfo allocator = d->allocator; | ||||
| @@ -630,12 +648,13 @@ internal GEN_FILE_CLOSE_PROC( _memory_file_close ) | ||||
| 	if ( d->flags & EFileStream_CLONE_WRITABLE ) | ||||
| 	{ | ||||
| 		Array<u8> arr = { d->buf }; | ||||
| 		arr.free(); | ||||
| 		array_free(arr); | ||||
| 	} | ||||
|  | ||||
| 	free( allocator, d ); | ||||
| 	allocator_free( allocator, d ); | ||||
| } | ||||
|  | ||||
| FileOperations const memory_file_operations = { _memory_file_read, _memory_file_write, _memory_file_seek, _memory_file_close }; | ||||
|  | ||||
| GEN_API_C_END | ||||
| #pragma endregion File Handling | ||||
|   | ||||
| @@ -4,10 +4,11 @@ | ||||
| #endif | ||||
|  | ||||
| #pragma region File Handling | ||||
| GEN_API_C_BEGIN | ||||
|  | ||||
| typedef u32 FileMode; | ||||
|  | ||||
| enum FileModeFlag | ||||
| enum FileModeFlag_Def | ||||
| { | ||||
| 	EFileMode_READ   = bit( 0 ), | ||||
| 	EFileMode_WRITE  = bit( 1 ), | ||||
| @@ -15,16 +16,18 @@ enum FileModeFlag | ||||
| 	EFileMode_RW     = bit( 3 ), | ||||
| 	GEN_FILE_MODES   = EFileMode_READ | EFileMode_WRITE | EFileMode_APPEND | EFileMode_RW, | ||||
| }; | ||||
| typedef enum FileModeFlag_Def FileModeFlag; | ||||
|  | ||||
| // NOTE: Only used internally and for the file operations | ||||
| enum SeekWhenceType | ||||
| enum SeekWhenceType_Def | ||||
| { | ||||
| 	ESeekWhence_BEGIN   = 0, | ||||
| 	ESeekWhence_CURRENT = 1, | ||||
| 	ESeekWhence_END     = 2, | ||||
| }; | ||||
| typedef enum SeekWhenceType_Def SeekWhenceType; | ||||
|  | ||||
| enum FileError | ||||
| enum FileError_Def | ||||
| { | ||||
| 	EFileError_NONE, | ||||
| 	EFileError_INVALID, | ||||
| @@ -37,19 +40,21 @@ enum FileError | ||||
| 	EFileError_NAME_TOO_LONG, | ||||
| 	EFileError_UNKNOWN, | ||||
| }; | ||||
| typedef enum FileError_Def FileError; | ||||
|  | ||||
| union FileDescriptor | ||||
| union FileDescriptor_Def | ||||
| { | ||||
| 	void* p; | ||||
| 	sptr  i; | ||||
| 	uptr  u; | ||||
| }; | ||||
| typedef union FileDescriptor_Def FileDescriptor; | ||||
|  | ||||
| typedef struct FileOperations FileOperations; | ||||
| typedef struct FileOperations_Def FileOperations; | ||||
|  | ||||
| #define GEN_FILE_OPEN_PROC( name )     FileError name( FileDescriptor* fd, FileOperations* ops, FileMode mode, char const* filename ) | ||||
| #define GEN_FILE_READ_AT_PROC( name )  b32 name( FileDescriptor fd, void* buffer, sw size, s64 offset, sw* bytes_read, b32 stop_at_newline ) | ||||
| #define GEN_FILE_WRITE_AT_PROC( name ) b32 name( FileDescriptor fd, void const* buffer, sw size, s64 offset, sw* bytes_written ) | ||||
| #define GEN_FILE_READ_AT_PROC( name )  b32 name( FileDescriptor fd, void* buffer, ssize size, s64 offset, ssize* bytes_read, b32 stop_at_newline ) | ||||
| #define GEN_FILE_WRITE_AT_PROC( name ) b32 name( FileDescriptor fd, mem_ptr_const buffer, ssize size, s64 offset, ssize* bytes_written ) | ||||
| #define GEN_FILE_SEEK_PROC( name )     b32 name( FileDescriptor fd, s64 offset, SeekWhenceType whence, s64* new_offset ) | ||||
| #define GEN_FILE_CLOSE_PROC( name )    void name( FileDescriptor fd ) | ||||
|  | ||||
| @@ -59,35 +64,39 @@ typedef GEN_FILE_WRITE_AT_PROC( FileWriteProc ); | ||||
| typedef GEN_FILE_SEEK_PROC( FileSeekProc ); | ||||
| typedef GEN_FILE_CLOSE_PROC( FileCloseProc ); | ||||
|  | ||||
| struct FileOperations | ||||
| struct FileOperations_Def | ||||
| { | ||||
| 	FileReadProc*  read_at; | ||||
| 	FileWriteProc* write_at; | ||||
| 	FileSeekProc*  seek; | ||||
| 	FileCloseProc* close; | ||||
| }; | ||||
| typedef struct FileOperations_Def FileOperations; | ||||
|  | ||||
| extern FileOperations const default_file_operations; | ||||
|  | ||||
| typedef u64 FileTime; | ||||
|  | ||||
| enum DirType | ||||
| enum DirType_Def | ||||
| { | ||||
| 	GEN_DIR_TYPE_FILE, | ||||
| 	GEN_DIR_TYPE_FOLDER, | ||||
| 	GEN_DIR_TYPE_UNKNOWN, | ||||
| }; | ||||
| typedef enum DirType_Def DirType; | ||||
|  | ||||
| struct DirInfo; | ||||
| struct DirInfo_Def; | ||||
| typedef struct DirInfo_Def DirInfo; | ||||
|  | ||||
| struct DirEntry | ||||
| struct DirEntry_Def | ||||
| { | ||||
| 	char const* filename; | ||||
| 	struct DirInfo* dir_info; | ||||
| 	DirInfo*    dir_info; | ||||
| 	u8          type; | ||||
| }; | ||||
| typedef struct DirEntry_Def DirEntry; | ||||
|  | ||||
| struct DirInfo | ||||
| struct DirInfo_Def | ||||
| { | ||||
| 	char const* fullpath; | ||||
| 	DirEntry*   entries;    // zpl_array | ||||
| @@ -97,7 +106,7 @@ struct DirInfo | ||||
| 	String buf; | ||||
| }; | ||||
|  | ||||
| struct FileInfo | ||||
| struct FileInfo_Def | ||||
| { | ||||
| 	FileOperations ops; | ||||
| 	FileDescriptor fd; | ||||
| @@ -107,8 +116,9 @@ struct FileInfo | ||||
| 	FileTime    last_write_time; | ||||
| 	DirEntry*   dir; | ||||
| }; | ||||
| typedef struct FileInfo_Def FileInfo; | ||||
|  | ||||
| enum FileStandardType | ||||
| enum FileStandardType_Def | ||||
| { | ||||
| 	EFileStandard_INPUT, | ||||
| 	EFileStandard_OUTPUT, | ||||
| @@ -116,6 +126,7 @@ enum FileStandardType | ||||
|  | ||||
| 	EFileStandard_COUNT, | ||||
| }; | ||||
| typedef enum FileStandardType_Def FileStandardType; | ||||
|  | ||||
| /** | ||||
| 	* Get standard file I/O. | ||||
| @@ -161,7 +172,7 @@ FileError file_open_mode( FileInfo* file, FileMode mode, char const* filename ); | ||||
| 	* @param  buffer Buffer to read to | ||||
| 	* @param  size   Size to read | ||||
| 	*/ | ||||
| GEN_DEF_INLINE b32 file_read( FileInfo* file, void* buffer, sw size ); | ||||
| b32 file_read( FileInfo* file, void* buffer, ssize size ); | ||||
|  | ||||
| /** | ||||
| 	* Reads file at a specific offset | ||||
| @@ -171,7 +182,7 @@ GEN_DEF_INLINE b32 file_read( FileInfo* file, void* buffer, sw size ); | ||||
| 	* @param  offset     Offset to read from | ||||
| 	* @param  bytes_read How much data we've actually read | ||||
| 	*/ | ||||
| GEN_DEF_INLINE b32 file_read_at( FileInfo* file, void* buffer, sw size, s64 offset ); | ||||
| b32 file_read_at( FileInfo* file, void* buffer, ssize size, s64 offset ); | ||||
|  | ||||
| /** | ||||
| 	* Reads file safely | ||||
| @@ -181,13 +192,13 @@ GEN_DEF_INLINE b32 file_read_at( FileInfo* file, void* buffer, sw size, s64 offs | ||||
| 	* @param  offset     Offset to read from | ||||
| 	* @param  bytes_read How much data we've actually read | ||||
| 	*/ | ||||
| GEN_DEF_INLINE b32 file_read_at_check( FileInfo* file, void* buffer, sw size, s64 offset, sw* bytes_read ); | ||||
| b32 file_read_at_check( FileInfo* file, void* buffer, ssize size, s64 offset, ssize* bytes_read ); | ||||
|  | ||||
| struct FileContents | ||||
| { | ||||
| 	AllocatorInfo allocator; | ||||
| 	void*         data; | ||||
| 	sw            size; | ||||
| 	ssize            size; | ||||
| }; | ||||
|  | ||||
| constexpr b32 zero_terminate    = true; | ||||
| @@ -214,20 +225,20 @@ s64 file_size( FileInfo* file ); | ||||
| 	* @param  file | ||||
| 	* @param  offset Offset to seek to | ||||
| 	*/ | ||||
| GEN_DEF_INLINE s64 file_seek( FileInfo* file, s64 offset ); | ||||
| s64 file_seek( FileInfo* file, s64 offset ); | ||||
|  | ||||
| /** | ||||
| 	* Seeks the file cursor to the end of the file | ||||
| 	* @param  file | ||||
| 	*/ | ||||
| GEN_DEF_INLINE s64 file_seek_to_end( FileInfo* file ); | ||||
| s64 file_seek_to_end( FileInfo* file ); | ||||
|  | ||||
| /** | ||||
| 	* Returns the length from the beginning of the file we've read so far | ||||
| 	* @param  file | ||||
| 	* @return      Our current position in file | ||||
| 	*/ | ||||
| GEN_DEF_INLINE s64 file_tell( FileInfo* file ); | ||||
| s64 file_tell( FileInfo* file ); | ||||
|  | ||||
| /** | ||||
| 	* Writes to a file | ||||
| @@ -235,7 +246,7 @@ GEN_DEF_INLINE s64 file_tell( FileInfo* file ); | ||||
| 	* @param  buffer Buffer to read from | ||||
| 	* @param  size   Size to read | ||||
| 	*/ | ||||
| GEN_DEF_INLINE b32 file_write( FileInfo* file, void const* buffer, sw size ); | ||||
| b32 file_write( FileInfo* file, void const* buffer, ssize size ); | ||||
|  | ||||
| /** | ||||
| 	* Writes to file at a specific offset | ||||
| @@ -245,7 +256,7 @@ GEN_DEF_INLINE b32 file_write( FileInfo* file, void const* buffer, sw size ); | ||||
| 	* @param  offset        Offset to write to | ||||
| 	* @param  bytes_written How much data we've actually written | ||||
| 	*/ | ||||
| GEN_DEF_INLINE b32 file_write_at( FileInfo* file, void const* buffer, sw size, s64 offset ); | ||||
| b32 file_write_at( FileInfo* file, void const* buffer, ssize size, s64 offset ); | ||||
|  | ||||
| /** | ||||
| 	* Writes to file safely | ||||
| @@ -255,88 +266,9 @@ GEN_DEF_INLINE b32 file_write_at( FileInfo* file, void const* buffer, sw size, s | ||||
| 	* @param  offset        Offset to write to | ||||
| 	* @param  bytes_written How much data we've actually written | ||||
| 	*/ | ||||
| GEN_DEF_INLINE b32 file_write_at_check( FileInfo* file, void const* buffer, sw size, s64 offset, sw* bytes_written ); | ||||
| b32 file_write_at_check( FileInfo* file, void const* buffer, ssize size, s64 offset, ssize* bytes_written ); | ||||
|  | ||||
| GEN_IMPL_INLINE s64 file_seek( FileInfo* f, s64 offset ) | ||||
| { | ||||
| 	s64 new_offset = 0; | ||||
|  | ||||
| 	if ( ! f->ops.read_at ) | ||||
| 		f->ops = default_file_operations; | ||||
|  | ||||
| 	f->ops.seek( f->fd, offset, ESeekWhence_BEGIN, &new_offset ); | ||||
|  | ||||
| 	return new_offset; | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE s64 file_seek_to_end( FileInfo* f ) | ||||
| { | ||||
| 	s64 new_offset = 0; | ||||
|  | ||||
| 	if ( ! f->ops.read_at ) | ||||
| 		f->ops = default_file_operations; | ||||
|  | ||||
| 	f->ops.seek( f->fd, 0, ESeekWhence_END, &new_offset ); | ||||
|  | ||||
| 	return new_offset; | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE s64 file_tell( FileInfo* f ) | ||||
| { | ||||
| 	s64 new_offset = 0; | ||||
|  | ||||
| 	if ( ! f->ops.read_at ) | ||||
| 		f->ops = default_file_operations; | ||||
|  | ||||
| 	f->ops.seek( f->fd, 0, ESeekWhence_CURRENT, &new_offset ); | ||||
|  | ||||
| 	return new_offset; | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE b32 file_read( FileInfo* f, void* buffer, sw size ) | ||||
| { | ||||
| 	s64 cur_offset = file_tell( f ); | ||||
| 	b32 result     = file_read_at( f, buffer, size, file_tell( f ) ); | ||||
| 	file_seek( f, cur_offset + size ); | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE b32 file_read_at( FileInfo* f, void* buffer, sw size, s64 offset ) | ||||
| { | ||||
| 	return file_read_at_check( f, buffer, size, offset, NULL ); | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE b32 file_read_at_check( FileInfo* f, void* buffer, sw size, s64 offset, sw* bytes_read ) | ||||
| { | ||||
| 	if ( ! f->ops.read_at ) | ||||
| 		f->ops = default_file_operations; | ||||
| 	return f->ops.read_at( f->fd, buffer, size, offset, bytes_read, false ); | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE b32 file_write( FileInfo* f, void const* buffer, sw size ) | ||||
| { | ||||
| 	s64 cur_offset = file_tell( f ); | ||||
| 	b32 result     = file_write_at( f, buffer, size, file_tell( f ) ); | ||||
|  | ||||
| 	file_seek( f, cur_offset + size ); | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE b32 file_write_at( FileInfo* f, void const* buffer, sw size, s64 offset ) | ||||
| { | ||||
| 	return file_write_at_check( f, buffer, size, offset, NULL ); | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE b32 file_write_at_check( FileInfo* f, void const* buffer, sw size, s64 offset, sw* bytes_written ) | ||||
| { | ||||
| 	if ( ! f->ops.read_at ) | ||||
| 		f->ops = default_file_operations; | ||||
|  | ||||
| 	return f->ops.write_at( f->fd, buffer, size, offset, bytes_written ); | ||||
| } | ||||
|  | ||||
| enum FileStreamFlags : u32 | ||||
| enum FileStreamFlags_Def enum_underlying(u32) | ||||
| { | ||||
| 	/* Allows us to write to the buffer directly. Beware: you can not append a new data! */ | ||||
| 	EFileStream_WRITABLE = bit( 0 ), | ||||
| @@ -344,7 +276,10 @@ enum FileStreamFlags : u32 | ||||
| 	/* Clones the input buffer so you can write (zpl_file_write*) data into it. */ | ||||
| 	/* Since we work with a clone, the buffer size can dynamically grow as well. */ | ||||
| 	EFileStream_CLONE_WRITABLE = bit( 1 ), | ||||
|  | ||||
| 	EFileStream_UNDERLYING = GEN_U32_MAX, | ||||
| }; | ||||
| typedef enum FileStreamFlags_Def FileStreamFlags; | ||||
|  | ||||
| /** | ||||
| 	* Opens a new memory stream | ||||
| @@ -361,15 +296,104 @@ b8 file_stream_new( FileInfo* file, AllocatorInfo allocator ); | ||||
| 	* @param  size     Buffer's size | ||||
| 	* @param  flags | ||||
| 	*/ | ||||
| b8 file_stream_open( FileInfo* file, AllocatorInfo allocator, u8* buffer, sw size, FileStreamFlags flags ); | ||||
| b8 file_stream_open( FileInfo* file, AllocatorInfo allocator, u8* buffer, ssize size, FileStreamFlags flags ); | ||||
|  | ||||
| /** | ||||
| 	* Retrieves the stream's underlying buffer and buffer size. | ||||
| 	* @param file memory stream | ||||
| 	* @param size (Optional) buffer size | ||||
| 	*/ | ||||
| u8* file_stream_buf( FileInfo* file, sw* size ); | ||||
| u8* file_stream_buf( FileInfo* file, ssize* size ); | ||||
|  | ||||
| extern FileOperations const memory_file_operations; | ||||
|  | ||||
| inline | ||||
| s64 file_seek( FileInfo* f, s64 offset ) | ||||
| { | ||||
| 	s64 new_offset = 0; | ||||
|  | ||||
| 	if ( ! f->ops.read_at ) | ||||
| 		f->ops = default_file_operations; | ||||
|  | ||||
| 	f->ops.seek( f->fd, offset, ESeekWhence_BEGIN, &new_offset ); | ||||
|  | ||||
| 	return new_offset; | ||||
| } | ||||
|  | ||||
| inline | ||||
| s64 file_seek_to_end( FileInfo* f ) | ||||
| { | ||||
| 	s64 new_offset = 0; | ||||
|  | ||||
| 	if ( ! f->ops.read_at ) | ||||
| 		f->ops = default_file_operations; | ||||
|  | ||||
| 	f->ops.seek( f->fd, 0, ESeekWhence_END, &new_offset ); | ||||
|  | ||||
| 	return new_offset; | ||||
| } | ||||
|  | ||||
| inline | ||||
| s64 file_tell( FileInfo* f ) | ||||
| { | ||||
| 	s64 new_offset = 0; | ||||
|  | ||||
| 	if ( ! f->ops.read_at ) | ||||
| 		f->ops = default_file_operations; | ||||
|  | ||||
| 	f->ops.seek( f->fd, 0, ESeekWhence_CURRENT, &new_offset ); | ||||
|  | ||||
| 	return new_offset; | ||||
| } | ||||
|  | ||||
| inline | ||||
| b32 file_read( FileInfo* f, void* buffer, ssize size ) | ||||
| { | ||||
| 	s64 cur_offset = file_tell( f ); | ||||
| 	b32 result     = file_read_at( f, buffer, size, file_tell( f ) ); | ||||
| 	file_seek( f, cur_offset + size ); | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| inline | ||||
| b32 file_read_at( FileInfo* f, void* buffer, ssize size, s64 offset ) | ||||
| { | ||||
| 	return file_read_at_check( f, buffer, size, offset, NULL ); | ||||
| } | ||||
|  | ||||
| inline | ||||
| b32 file_read_at_check( FileInfo* f, void* buffer, ssize size, s64 offset, ssize* bytes_read ) | ||||
| { | ||||
| 	if ( ! f->ops.read_at ) | ||||
| 		f->ops = default_file_operations; | ||||
| 	return f->ops.read_at( f->fd, buffer, size, offset, bytes_read, false ); | ||||
| } | ||||
|  | ||||
| inline | ||||
| b32 file_write( FileInfo* f, void const* buffer, ssize size ) | ||||
| { | ||||
| 	s64 cur_offset = file_tell( f ); | ||||
| 	b32 result     = file_write_at( f, buffer, size, file_tell( f ) ); | ||||
|  | ||||
| 	file_seek( f, cur_offset + size ); | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| inline | ||||
| b32 file_write_at( FileInfo* f, void const* buffer, ssize size, s64 offset ) | ||||
| { | ||||
| 	return file_write_at_check( f, buffer, size, offset, NULL ); | ||||
| } | ||||
|  | ||||
| inline | ||||
| b32 file_write_at_check( FileInfo* f, void const* buffer, ssize size, s64 offset, ssize* bytes_written ) | ||||
| { | ||||
| 	if ( ! f->ops.read_at ) | ||||
| 		f->ops = default_file_operations; | ||||
|  | ||||
| 	return f->ops.write_at( f->fd, buffer, size, offset, bytes_written ); | ||||
| } | ||||
|  | ||||
| GEN_API_C_END | ||||
| #pragma endregion File Handling | ||||
|   | ||||
| @@ -4,6 +4,7 @@ | ||||
| #endif | ||||
|  | ||||
| #pragma region Hashing | ||||
| GEN_API_C_BEGIN | ||||
|  | ||||
| global u32 const _crc32_table[ 256 ] = { | ||||
| 	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, | ||||
| @@ -27,11 +28,11 @@ global u32 const _crc32_table[ 256 ] = { | ||||
| 	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, | ||||
| }; | ||||
|  | ||||
| u32 crc32( void const* data, sw len ) | ||||
| u32 crc32( void const* data, ssize len ) | ||||
| { | ||||
| 	sw        remaining; | ||||
| 	u32       result = ~( zpl_cast( u32 ) 0 ); | ||||
| 	u8 const* c      = zpl_cast( u8 const* ) data; | ||||
| 	ssize        remaining; | ||||
| 	u32       result = ~( scast( u32, 0) ); | ||||
| 	u8 const* c      = rcast( u8 const*, data); | ||||
| 	for ( remaining = len; remaining--; c++ ) | ||||
| 		result = ( result >> 8 ) ^ ( _crc32_table[ ( result ^ *c ) & 0xff ] ); | ||||
| 	return ~result; | ||||
| @@ -77,14 +78,15 @@ global u64 const _crc64_table[ 256 ] = { | ||||
| 	0xa6df411fbfb21ca3ull, 0xdc0731d78f8795daull, 0x536fa08fdfd90e51ull, 0x29b7d047efec8728ull, | ||||
| }; | ||||
|  | ||||
| u64 crc64( void const* data, sw len ) | ||||
| u64 crc64( void const* data, ssize len ) | ||||
| { | ||||
| 	sw        remaining; | ||||
| 	u64       result = ( zpl_cast( u64 ) 0 ); | ||||
| 	u8 const* c      = zpl_cast( u8 const* ) data; | ||||
| 	ssize        remaining; | ||||
| 	u64       result = ( scast( u64, 0) ); | ||||
| 	u8 const* c      = rcast( u8 const*, data); | ||||
| 	for ( remaining = len; remaining--; c++ ) | ||||
| 		result = ( result >> 8 ) ^ ( _crc64_table[ ( result ^ *c ) & 0xff ] ); | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| GEN_API_C_END | ||||
| #pragma endregion Hashing | ||||
|   | ||||
| @@ -4,8 +4,10 @@ | ||||
| #endif | ||||
|  | ||||
| #pragma region Hashing | ||||
| GEN_API_C_BEGIN | ||||
|  | ||||
| u32 crc32( void const* data, sw len ); | ||||
| u64 crc64( void const* data, sw len ); | ||||
| u32 crc32( void const* data, ssize len ); | ||||
| u64 crc64( void const* data, ssize len ); | ||||
|  | ||||
| GEN_API_C_END | ||||
| #pragma endregion Hashing | ||||
|   | ||||
| @@ -1,52 +1,98 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #   pragma once | ||||
| #	include "header_start.hpp" | ||||
| #endif | ||||
|  | ||||
| #pragma region Macros | ||||
|  | ||||
| #define zpl_cast( Type ) ( Type ) | ||||
|  | ||||
| // Keywords | ||||
|  | ||||
| #ifndef global | ||||
| #define global        static    // Global variables | ||||
| #endif | ||||
| #ifndef internal | ||||
| #define internal      static    // Internal linkage | ||||
| #endif | ||||
| #ifndef local_persist | ||||
| #define local_persist static    // Local Persisting variables | ||||
|  | ||||
| #ifdef GEN_COMPILER_MSVC | ||||
| #	define forceinline __forceinline | ||||
| #	define neverinline __declspec( noinline ) | ||||
| #elif defined(GEN_COMPILER_GCC) | ||||
| #	define forceinline inline __attribute__((__always_inline__)) | ||||
| #	define neverinline __attribute__( ( __noinline__ ) ) | ||||
| #elif defined(GEN_COMPILER_CLANG) | ||||
| #if __has_attribute(__always_inline__) | ||||
| #	define forceinline inline __attribute__((__always_inline__)) | ||||
| #	define neverinline __attribute__( ( __noinline__ ) ) | ||||
| #else | ||||
| #	define forceinline | ||||
| #	define neverinline | ||||
| #endif | ||||
| #else | ||||
| #	define forceinline | ||||
| #	define neverinline | ||||
| #endif | ||||
|  | ||||
| // Bits | ||||
|  | ||||
| #ifndef bit | ||||
| #define bit( Value )                             ( 1 << Value ) | ||||
| #define bitfield_is_equal( Type, Field, Mask ) ( (Type(Mask) & Type(Field)) == Type(Mask) ) | ||||
| #endif | ||||
|  | ||||
| // Casting | ||||
| #if GEN_COMPILER_CPP | ||||
| #	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 | ||||
|  | ||||
| #define ccast( Type, Value ) ( * const_cast< Type* >( & (Value) ) ) | ||||
| #define pcast( Type, Value ) ( * reinterpret_cast< Type* >( & ( Value ) ) ) | ||||
| #define rcast( Type, Value ) reinterpret_cast< Type >( Value ) | ||||
| #define scast( Type, Value ) static_cast< Type >( Value ) | ||||
| #ifndef stringize | ||||
| #define stringize_va( ... ) #__VA_ARGS__ | ||||
| #define stringize( ... )    stringize_va( __VA_ARGS__ ) | ||||
| #endif | ||||
|  | ||||
| #ifndef do_once | ||||
| #define do_once( statement ) for ( local_persist b32 once = true; once; once = false, (statement) ) | ||||
|  | ||||
| #define do_once_start      \ | ||||
| 	do                     \ | ||||
| 	{                      \ | ||||
| 		local_persist      \ | ||||
| 		bool done = false; \ | ||||
| 		if ( done )        \ | ||||
| 			break;         \ | ||||
| 		done = true; | ||||
|  | ||||
| #define do_once_end        \ | ||||
| 	}                      \ | ||||
| 	while(0); | ||||
| #endif | ||||
|  | ||||
| #ifndef labeled_scope_start | ||||
| #define labeled_scope_start if ( false ) { | ||||
| #define labeled_scope_end   } | ||||
| #endif | ||||
|  | ||||
| #ifndef         compiler_decorated_func_name | ||||
| #   ifdef COMPILER_CLANG | ||||
| #       define  compiler_decorated_func_name __PRETTY_NAME__ | ||||
| #   elif defined(COMPILER_MSVC) | ||||
| #   	define compiler_decorated_func_name __FUNCDNAME__ | ||||
| #   endif | ||||
| #endif | ||||
|  | ||||
| #ifndef num_args_impl | ||||
|  | ||||
| // This is essentially an arg couneter version of GEN_SELECT_ARG macros | ||||
| // See section : _Generic function overloading for that usage (explains this heavier case) | ||||
|  | ||||
| // Num Arguments (Varadics) | ||||
| // #if defined(__GNUC__) || defined(__clang__) | ||||
| // Supports 0-50 arguments | ||||
| #define num_args_impl( _0,                                 \ | ||||
| 		_1,  _2,  _3,  _4,  _5,  _6,  _7,  _8,  _9, _10,   \ | ||||
| 		_11, _12, _13, _14, _15, _16, _17, _18, _19, _20,  \ | ||||
| @@ -76,93 +122,245 @@ | ||||
| 		 10,  9,  8,  7,  6,  5,  4,  3,  2,  1, \ | ||||
| 		 0                                       \ | ||||
| 	) | ||||
| #endif | ||||
|  | ||||
| // #else | ||||
| // This doesn't work on latest msvc so I had to use /Zc:preprocessor flag. | ||||
|  | ||||
| // Supports 1-50 arguments | ||||
| // #define num_args_impl(                                  \ | ||||
| // 		_1,  _2,  _3,  _4,  _5,  _6,  _7,  _8,  _9, _10,   \ | ||||
| // 		_11, _12, _13, _14, _15, _16, _17, _18, _19, _20,  \ | ||||
| // 		_21, _22, _23, _24, _25, _26, _27, _28, _29, _30,  \ | ||||
| // 		_31, _32, _33, _34, _35, _36, _37, _38, _39, _40,  \ | ||||
| // 		_41, _42, _43, _44, _45, _46, _47, _48, _49, _50,  \ | ||||
| // 		_51, _52, _53, _54, _55, _56, _57, _58, _59, _60,  \ | ||||
| // 		_61, _62, _63, _64, _65, _66, _67, _68, _69, _70,  \ | ||||
| // 		_71, _72, _73, _74, _75, _76, _77, _78, _79, _80,  \ | ||||
| // 		_81, _82, _83, _84, _85, _86, _87, _88, _89, _90,  \ | ||||
| // 		_91, _92, _93, _94, _95, _96, _97, _98, _99, _100, \ | ||||
| // 		N, ...                                             \ | ||||
| // 	) N | ||||
|  | ||||
| // #define num_args(...)                         \ | ||||
| // 	num_args_impl( __VA_ARGS__,                  \ | ||||
| // 		100, 99, 98, 97, 96, 95, 94, 93, 92, 91, \ | ||||
| // 		 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, \ | ||||
| // 		 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, \ | ||||
| // 		 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, \ | ||||
| // 		 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, \ | ||||
| // 		 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, \ | ||||
| // 		 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, \ | ||||
| // 		 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, \ | ||||
| // 		 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, \ | ||||
| // 		 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, \ | ||||
| // 		 10,  9,  8,  7,  6,  5,  4,  3,  2,  1  \ | ||||
| // 	) | ||||
| // #endif | ||||
|  | ||||
| // Stringizing | ||||
| #define stringize_va( ... ) #__VA_ARGS__ | ||||
| #define stringize( ... )    stringize_va( __VA_ARGS__ ) | ||||
|  | ||||
| // Function do once | ||||
|  | ||||
| #define do_once()          \ | ||||
| 	do                     \ | ||||
| 	{                      \ | ||||
| 		static             \ | ||||
| 		bool Done = false; \ | ||||
| 		if ( Done )        \ | ||||
| 			return;        \ | ||||
| 		Done = true;       \ | ||||
| 	}                      \ | ||||
| 	while(0) | ||||
|  | ||||
| #define do_once_start      \ | ||||
| 	do                     \ | ||||
| 	{                      \ | ||||
| 		static             \ | ||||
| 		bool Done = false; \ | ||||
| 		if ( Done )        \ | ||||
| 			break;         \ | ||||
| 		Done = true; | ||||
|  | ||||
| #define do_once_end        \ | ||||
| 	}                      \ | ||||
| 	while(0); | ||||
|  | ||||
| #define labeled_scope_start if ( false ) { | ||||
| #define labeled_scope_end   } | ||||
|  | ||||
| #ifndef clamp | ||||
| #define clamp( x, lower, upper )      min( max( ( x ), ( lower ) ), ( upper ) ) | ||||
| #define count_of( x )                 ( ( size_of( x ) / size_of( 0 [ x ] ) ) / ( ( sw )( ! ( size_of( x ) % size_of( 0 [ x ] ) ) ) ) ) | ||||
| #endif | ||||
| #ifndef count_of | ||||
| #define count_of( x )                 ( ( size_of( x ) / size_of( 0 [ x ] ) ) / ( ( ssize )( ! ( size_of( x ) % size_of( 0 [ x ] ) ) ) ) ) | ||||
| #endif | ||||
| #ifndef is_between | ||||
| #define is_between( x, lower, upper ) ( ( ( lower ) <= ( x ) ) && ( ( x ) <= ( upper ) ) ) | ||||
| #define max( a, b )                   ( ( a ) > ( b ) ? ( a ) : ( b ) ) | ||||
| #define min( a, b )                   ( ( a ) < ( b ) ? ( a ) : ( b ) ) | ||||
| #define size_of( x )                  ( sw )( sizeof( x ) ) | ||||
| #endif | ||||
| #ifndef size_of | ||||
| #define size_of( x )                  ( ssize )( sizeof( x ) ) | ||||
| #endif | ||||
|  | ||||
| #if defined( _MSC_VER ) || defined( GEN_COMPILER_TINYC ) | ||||
| #	define offset_of( Type, element ) ( ( GEN_NS( gen_sw ) ) & ( ( ( Type* )0 )->element ) ) | ||||
| #ifndef max | ||||
| #define max( a, b ) ( (a > b) ? (a) : (b) ) | ||||
| #endif | ||||
| #ifndef min | ||||
| #define min( a, b ) ( (a < b) ? (a) : (b) ) | ||||
| #endif | ||||
|  | ||||
| #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 | ||||
|  | ||||
| template< class Type > | ||||
| void swap( Type& a, Type& b ) | ||||
| { | ||||
| 	Type tmp = a; | ||||
| 	a = b; | ||||
| 	b = tmp; | ||||
| } | ||||
| #ifndef        forceinline | ||||
| #	if GEN_COMPILER_MSVC | ||||
| #		define forceinline __forceinline | ||||
| #		define neverinline __declspec( noinline ) | ||||
| #	elif GEN_COMPILER_GCC | ||||
| #		define forceinline inline __attribute__((__always_inline__)) | ||||
| #		define neverinline __attribute__( ( __noinline__ ) ) | ||||
| #	elif GEN_COMPILER_CLANG | ||||
| #	if __has_attribute(__always_inline__) | ||||
| #		define forceinline inline __attribute__((__always_inline__)) | ||||
| #		define neverinline __attribute__( ( __noinline__ ) ) | ||||
| #	else | ||||
| #		define forceinline | ||||
| #		define neverinline | ||||
| #	endif | ||||
| #	else | ||||
| #		define forceinline | ||||
| #		define neverinline | ||||
| #	endif | ||||
| #endif | ||||
|  | ||||
| #ifndef        neverinline | ||||
| #	if GEN_COMPILER_MSVC | ||||
| #		define neverinline __declspec( noinline ) | ||||
| #	elif GEN_COMPILER_GCC | ||||
| #		define neverinline __attribute__( ( __noinline__ ) ) | ||||
| #	elif GEN_COMPILER_CLANG | ||||
| #	if __has_attribute(__always_inline__) | ||||
| #		define neverinline __attribute__( ( __noinline__ ) ) | ||||
| #	else | ||||
| #		define neverinline | ||||
| #	endif | ||||
| #	else | ||||
| #		define neverinline | ||||
| #	endif | ||||
| #endif | ||||
|  | ||||
| #if GEN_COMPILER_CPP | ||||
| // Already Defined | ||||
| #elif GEN_COMPILER_C && __STDC_VERSION__ >= 201112L | ||||
| #	define thread_local _Thread_local | ||||
| #elif GEN_COMPILER_MSVC | ||||
| #	define thread_local __declspec(thread) | ||||
| #elif GEN_COMPILER_CLANG | ||||
| #	define thread_local __thread | ||||
| #else | ||||
| #	error "No thread local support" | ||||
| #endif | ||||
|  | ||||
| #if !defined(GEN_SUPPORT_CPP_REFERENCES) | ||||
| #	define   GEN_SUPPORT_CPP_REFERENCES 1 | ||||
| #endif | ||||
| #if GEN_COMPILER_C && defined(GEN_SUPPORT_CPP_REFERENCES) | ||||
| #	undef  GEN_SUPPORT_CPP_REFERENCES | ||||
| #	define GEN_SUPPORT_CPP_REFERENCES 0 | ||||
| #endif | ||||
|  | ||||
| #if !defined(GEN_SUPPORT_CPP_MEMBER_FEATURES) | ||||
| #	define   GEN_SUPPORT_CPP_MEMBER_FEATURES 1 | ||||
| #endif | ||||
| #if GEN_COMPILER_C && defined(GEN_SUPPORT_CPP_MEMBER_FEATURES) | ||||
| #	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 | ||||
|  | ||||
| #ifndef GEN_API_C_BEGIN | ||||
| #	if GEN_COMPILER_C || (GEN_COMPILER_CPP && GEN_SUPPORT_CPP_REFERENCES) | ||||
| #		define GEN_API_C_BEGIN | ||||
| #		define GEN_API_C_END | ||||
| #	else | ||||
| #		define GEN_API_C_BEGIN extern "C" { | ||||
| #		define GEN_API_C_END } | ||||
| #	endif | ||||
| #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 | ||||
|  | ||||
| #	ifndef GEN_REMOVE_PTR | ||||
| #		define GEN_REMOVE_PTR(type) typeof(* ( (type) NULL) ) | ||||
| #	endif | ||||
| #endif | ||||
|  | ||||
| #if ! defined(GEN_PARAM_DEFAULT) && GEN_COMPILER_CPP | ||||
| #	define GEN_PARAM_DEFAULT = {} | ||||
| #else | ||||
| #	define GEN_PARAM_DEFAULT | ||||
| #endif | ||||
|  | ||||
| #if GEN_COMPILER_CPP | ||||
|     #define struct_init(type, value) {value} | ||||
| #else | ||||
|     #define struct_init(type, value) {value} | ||||
| #endif | ||||
|  | ||||
| // ------------------------ _Generic function overloading ----------------------------------------- | ||||
| #if GEN_COMPILER_C | ||||
| // This implemnents macros for utilizing "The Naive Extendible _Generic Macro" explained in: | ||||
| // https://github.com/JacksonAllan/CC/blob/main/articles/Better_C_Generics_Part_1_The_Extendible_Generic.md | ||||
| // Since gencpp is used to generate the c-library, it was choosen over the more novel implementations to keep the macros as easy to understand and unopaque as possible. | ||||
| // Extensive effort was put in below to make this as easy as possible to understand what is going on with this mess of a preoprocessor. | ||||
|  | ||||
| #define GEN_COMMA_OPERATOR , // The comma operator is used by preprocessor macros to delimit arguments, so we have to represent it via a macro to prevent parsing incorrectly. | ||||
|  | ||||
| // Helper macros for argument selection | ||||
| #define GEN_SELECT_ARG_1( _1, ... ) _1 // <-- Of all th args passed pick _1. | ||||
| #define GEN_SELECT_ARG_2( _1, _2, ... ) _2 // <-- Of all the args passed pick _2. | ||||
| #define GEN_SELECT_ARG_3( _1, _2, _3, ... ) _3 // etc.. (by induction until _8, which we don't support any more beyond) | ||||
| // #define GEN_SELECT_ARG_4( _1, _2, _3, _4, ... ) _4 | ||||
| // #define GEN_SELECT_ARG_5( _1, _2, _3, _4, _5, ... ) _5 | ||||
| // #define GEN_SELECT_ARG_6( _1, _2, _3, _4, _5, _6, ... ) _6 | ||||
| // #define GEN_SELECT_ARG_7( _1, _2, _3, _4, _5, _6, _7, ... ) _7 | ||||
| // #define GEN_SELECT_ARG_8( _1, _2, _3, _4, _5, _6, _7, _8, ... ) _8 | ||||
|  | ||||
| #define GEN_GENERIC_SEL_ENTRY_TYPE             GEN_SELECT_ARG_1 // Use the arg expansion macro to select arg 1 which should have the type. | ||||
| #define GEN_GENERIC_SEL_ENTRY_FUNCTION         GEN_SELECT_ARG_2 // Use the arg expansion macro to select arg 2 which should have the function. | ||||
| #define GEN_GENERIC_SEL_ENTRY_COMMA_DELIMITER  GEN_SELECT_ARG_3 // Use the arg expansion macro to select arg 3 which should have the comma delimiter ','. | ||||
|  | ||||
| #define GEN_RESOLVED_FUNCTION_CALL // Just used to indicate where the call "occurs" | ||||
|  | ||||
| // ---------------------------------------------------------------------------------------------------------------------------------- | ||||
| // GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( macro ) includes a _Generic slot only if the specified macro is defined (as type, function_name). | ||||
| // It takes advantage of the fact that if the macro is defined, then the expanded text will contain a comma. | ||||
| // Expands to ',' if it can find (type): (function) <comma_operator: ',' > | ||||
| // Where GEN_GENERIC_SEL_ENTRY_COMMA_DELIMITER is specifically looking for that <comma> , | ||||
| #define GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( slot_exp ) GEN_SELECT_ARG_3( slot_exp, GEN_SELECT_ARG_1( slot_exp, ): GEN_SELECT_ARG_2( slot_exp, ) GEN_COMMA_OPERATOR, , ) | ||||
| //       ^Selects the comma                               ^ is the type                             ^ is the function                                    ^ comma delimiter to select                ^ Insert a comma | ||||
| // The slot won't exist if that comma is not found. | ||||
| //                                                                                                                                                                                                    | | ||||
| // This  is the same as above but it does not insert a comma                                                                                                                                          V no comma here. | ||||
| #define GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT_LAST( slot_exp ) GEN_GENERIC_SEL_ENTRY_COMMA_DELIMITER( slot_exp, GEN_GENERIC_SEL_ENTRY_TYPE( slot_exp, ): GEN_GENERIC_SEL_ENTRY_FUNCTION( slot_exp, ), , ) | ||||
| // Needed for the last slot as they don't allow trailing commas. | ||||
| // ---------------------------------------------------------------------------------------------------------------------------------- | ||||
|  | ||||
| // Below are generated on demand for a generated function | ||||
| // ---------------------------------------------------------------------------------------------------------------------------------- | ||||
| #define GEN_FUNCTION_GENERIC_EXAMPLE( function_arguments ) _Generic(   \ | ||||
| (function_arguments), /* Select Via Expression*/                       \ | ||||
|   /* Extendibility slots: */                                           \ | ||||
|   GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( FunctionID__ARGS_SIG_1 )     \ | ||||
|   GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( FunctionID__ARGS_SIG_1 )     \ | ||||
|   GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( FunctionID__ARGS_SIG_1 )     \ | ||||
|   GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( FunctionID__ARGS_SIG_1 )     \ | ||||
|   GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( FunctionID__ARGS_SIG_1 )     \ | ||||
|   GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( FunctionID__ARGS_SIG_1 )     \ | ||||
|   GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( FunctionID__ARGS_SIG_1 )     \ | ||||
|   GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT_LAST FunctionID__ARGS_SIG_1 ) \ | ||||
| ) GEN_RESOLVED_FUNCTION_CALL( function_arguments ) | ||||
| // ---------------------------------------------------------------------------------------------------------------------------------- | ||||
|  | ||||
| // Then each definiton of a function has an associated define: | ||||
| // #define <function_id_macro> GEN_GENERIC_FUNCTION_ARG_SIGNATURE( <function_id>, <arguments> ) | ||||
| #define GEN_GENERIC_FUNCTION_ARG_SIGNATURE( name_of_function, type_delimiter ) type_delimiter name_of_function | ||||
|  | ||||
| // Then somehwere later on | ||||
| // <etc> <return_type> <function_id> ( <arguments> ) { <implementation> } | ||||
|  | ||||
| // Concrete example: | ||||
| #define ENABLE_GENERIC_EXAMPLE 0 | ||||
| #if ENABLE_GENERIC_EXAMPLE | ||||
|  | ||||
| // To add support for long: | ||||
| #define HASH__ARGS_SIG_1 GEN_GENERIC_FUNCTION_ARG_SIGNATURE( hash__P_long, long long ) | ||||
| size_t hash__P_long    ( long val ) { return val * 2654435761ull; } | ||||
|  | ||||
| // To add support for long long: | ||||
| #define HASH__ARGS_SIG_2 GEN_GENERIC_FUNCTION_ARG_SIGNATURE( hash__P_long_long, long long ) | ||||
| size_t hash__P_long_long( long long val ) { return val * 2654435761ull; } | ||||
|  | ||||
| // If using an Editor with support for syntax hightlighting macros: HASH__ARGS_SIG_1 and HASH_ARGS_SIG_2 should show color highlighting indicating the slot is enabled, | ||||
| // or, "defined" for usage during the compilation pass that handles the _Generic instrinsic. | ||||
| #define hash( function_arguments ) _Generic(                      \ | ||||
| (function_arguments), /* Select Via Expression*/                  \ | ||||
|   /* Extendibility slots: */                                      \ | ||||
|   GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( HASH__ARGS_SIG_1 )      \ | ||||
|   GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( HASH__ARGS_SIG_2 )      \ | ||||
|   GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( HASH__ARGS_SIG_3 )      \ | ||||
|   GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( HASH__ARGS_SIG_4 )      \ | ||||
|   GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( HASH__ARGS_SIG_5 )      \ | ||||
|   GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( HASH__ARGS_SIG_6 )      \ | ||||
|   GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( HASH__ARGS_SIG_7 )      \ | ||||
|   GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT_LAST( HASH__ARGS_SIG_8 ) \ | ||||
| ) GEN_RESOLVED_FUNCTION_CALL( function_arguments ) | ||||
|  | ||||
| #endif // ENABLE_GENERIC_EXAMPLE | ||||
|  | ||||
| // END OF ------------------------ _Generic function overloading ----------------------------------------- END OF | ||||
| #endif | ||||
|  | ||||
| #pragma endregion Macros | ||||
|   | ||||
| @@ -4,8 +4,9 @@ | ||||
| #endif | ||||
|  | ||||
| #pragma region Memory | ||||
| GEN_API_C_BEGIN | ||||
|  | ||||
| void* mem_copy( void* dest, void const* source, sw n ) | ||||
| void* mem_copy( void* dest, void const* source, ssize n ) | ||||
| { | ||||
| 	if ( dest == NULL ) | ||||
| 	{ | ||||
| @@ -15,25 +16,25 @@ void* mem_copy( void* dest, void const* source, sw n ) | ||||
| 	return memcpy( dest, source, n ); | ||||
| } | ||||
|  | ||||
| void const* mem_find( void const* data, u8 c, sw n ) | ||||
| void const* mem_find( void const* data, u8 c, ssize n ) | ||||
| { | ||||
| 	u8 const* s = zpl_cast( u8 const* ) data; | ||||
| 	while ( ( zpl_cast( uptr ) s & ( sizeof( uw ) - 1 ) ) && n && *s != c ) | ||||
| 	u8 const* s = rcast( u8 const*, data); | ||||
| 	while ( ( rcast( uptr, s) & ( sizeof( usize ) - 1 ) ) && n && *s != c ) | ||||
| 	{ | ||||
| 		s++; | ||||
| 		n--; | ||||
| 	} | ||||
| 	if ( n && *s != c ) | ||||
| 	{ | ||||
| 		sw const* w; | ||||
| 		sw        k = GEN__ONES * c; | ||||
| 		w           = zpl_cast( sw const* ) s; | ||||
| 		while ( n >= size_of( sw ) && ! GEN__HAS_ZERO( *w ^ k ) ) | ||||
| 		ssize const* w; | ||||
| 		ssize        k = GEN__ONES * c; | ||||
| 		w           = rcast( ssize const*, s); | ||||
| 		while ( n >= size_of( ssize ) && ! GEN__HAS_ZERO( *w ^ k ) ) | ||||
| 		{ | ||||
| 			w++; | ||||
| 			n -= size_of( sw ); | ||||
| 			n -= size_of( ssize ); | ||||
| 		} | ||||
| 		s = zpl_cast( u8 const* ) w; | ||||
| 		s = rcast( u8 const*, w); | ||||
| 		while ( n && *s != c ) | ||||
| 		{ | ||||
| 			s++; | ||||
| @@ -41,7 +42,7 @@ void const* mem_find( void const* data, u8 c, sw n ) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return n ? zpl_cast( void const* ) s : NULL; | ||||
| 	return n ? rcast( void const*, s ) : NULL; | ||||
| } | ||||
|  | ||||
| #define GEN_HEAP_STATS_MAGIC 0xDEADC0DE | ||||
| @@ -49,8 +50,8 @@ void const* mem_find( void const* data, u8 c, sw n ) | ||||
| struct _heap_stats | ||||
| { | ||||
| 	u32 magic; | ||||
| 	sw  used_memory; | ||||
| 	sw  alloc_count; | ||||
| 	ssize  used_memory; | ||||
| 	ssize  alloc_count; | ||||
| }; | ||||
|  | ||||
| global _heap_stats _heap_stats_info; | ||||
| @@ -61,13 +62,13 @@ void heap_stats_init( void ) | ||||
| 	_heap_stats_info.magic = GEN_HEAP_STATS_MAGIC; | ||||
| } | ||||
|  | ||||
| sw heap_stats_used_memory( void ) | ||||
| ssize heap_stats_used_memory( void ) | ||||
| { | ||||
| 	GEN_ASSERT_MSG( _heap_stats_info.magic == GEN_HEAP_STATS_MAGIC, "heap_stats is not initialised yet, call heap_stats_init first!" ); | ||||
| 	return _heap_stats_info.used_memory; | ||||
| } | ||||
|  | ||||
| sw heap_stats_alloc_count( void ) | ||||
| ssize heap_stats_alloc_count( void ) | ||||
| { | ||||
| 	GEN_ASSERT_MSG( _heap_stats_info.magic == GEN_HEAP_STATS_MAGIC, "heap_stats is not initialised yet, call heap_stats_init first!" ); | ||||
| 	return _heap_stats_info.alloc_count; | ||||
| @@ -82,11 +83,11 @@ void heap_stats_check( void ) | ||||
|  | ||||
| struct _heap_alloc_info | ||||
| { | ||||
| 	sw    size; | ||||
| 	ssize    size; | ||||
| 	void* physical_start; | ||||
| }; | ||||
|  | ||||
| void* heap_allocator_proc( void* allocator_data, AllocType type, sw size, sw alignment, void* old_memory, sw old_size, u64 flags ) | ||||
| void* heap_allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ) | ||||
| { | ||||
| 	void* ptr = NULL; | ||||
| 	// unused( allocator_data ); | ||||
| @@ -95,16 +96,16 @@ void* heap_allocator_proc( void* allocator_data, AllocType type, sw size, sw ali | ||||
| 		alignment = GEN_DEFAULT_MEMORY_ALIGNMENT; | ||||
|  | ||||
| #ifdef GEN_HEAP_ANALYSIS | ||||
| 	sw alloc_info_size      = size_of( _heap_alloc_info ); | ||||
| 	sw alloc_info_remainder = ( alloc_info_size % alignment ); | ||||
| 	sw track_size           = max( alloc_info_size, alignment ) + alloc_info_remainder; | ||||
| 	ssize alloc_info_size      = size_of( _heap_alloc_info ); | ||||
| 	ssize alloc_info_remainder = ( alloc_info_size % alignment ); | ||||
| 	ssize track_size           = max( alloc_info_size, alignment ) + alloc_info_remainder; | ||||
| 	switch ( type ) | ||||
| 	{ | ||||
| 		case EAllocation_FREE : | ||||
| 			{ | ||||
| 				if ( ! old_memory ) | ||||
| 					break; | ||||
| 				_heap_alloc_info* alloc_info  = zpl_cast( _heap_alloc_info* ) old_memory - 1; | ||||
| 				_heap_alloc_info* alloc_info  = rcast( _heap_alloc_info*, old_memory) - 1; | ||||
| 				_heap_stats_info.used_memory -= alloc_info->size; | ||||
| 				_heap_stats_info.alloc_count--; | ||||
| 				old_memory = alloc_info->physical_start; | ||||
| @@ -195,11 +196,11 @@ void* heap_allocator_proc( void* allocator_data, AllocType type, sw size, sw ali | ||||
| #ifdef GEN_HEAP_ANALYSIS | ||||
| 	if ( type == EAllocation_ALLOC ) | ||||
| 	{ | ||||
| 		_heap_alloc_info* alloc_info = zpl_cast( _heap_alloc_info* )( zpl_cast( char* ) ptr + alloc_info_remainder ); | ||||
| 		_heap_alloc_info* alloc_info = rcast( _heap_alloc_info*, rcast( char*, ptr) + alloc_info_remainder ); | ||||
| 		zero_item( alloc_info ); | ||||
| 		alloc_info->size              = size - track_size; | ||||
| 		alloc_info->physical_start    = ptr; | ||||
| 		ptr                           = zpl_cast( void* )( alloc_info + 1 ); | ||||
| 		ptr                           = rcast( void*, alloc_info + 1 ); | ||||
| 		_heap_stats_info.used_memory += alloc_info->size; | ||||
| 		_heap_stats_info.alloc_count++; | ||||
| 	} | ||||
| @@ -209,7 +210,7 @@ void* heap_allocator_proc( void* allocator_data, AllocType type, sw size, sw ali | ||||
| } | ||||
|  | ||||
| #pragma region VirtualMemory | ||||
| VirtualMemory vm_from_memory( void* data, sw size ) | ||||
| VirtualMemory vm_from_memory( void* data, ssize size ) | ||||
| { | ||||
| 	VirtualMemory vm; | ||||
| 	vm.data = data; | ||||
| @@ -218,7 +219,7 @@ VirtualMemory vm_from_memory( void* data, sw size ) | ||||
| } | ||||
|  | ||||
| #if defined( GEN_SYSTEM_WINDOWS ) | ||||
| VirtualMemory vm_alloc( void* addr, sw size ) | ||||
| VirtualMemory vm_alloc( void* addr, ssize size ) | ||||
| { | ||||
| 	VirtualMemory vm; | ||||
| 	GEN_ASSERT( size > 0 ); | ||||
| @@ -234,7 +235,7 @@ b32 vm_free( VirtualMemory vm ) | ||||
| 	{ | ||||
| 		if ( VirtualQuery( vm.data, &info, size_of( info ) ) == 0 ) | ||||
| 			return false; | ||||
| 		if ( info.BaseAddress != vm.data || info.AllocationBase != vm.data || info.State != MEM_COMMIT || info.RegionSize > zpl_cast( uw ) vm.size ) | ||||
| 		if ( info.BaseAddress != vm.data || info.AllocationBase != vm.data || info.State != MEM_COMMIT || info.RegionSize > scast( usize, vm.size) ) | ||||
| 		{ | ||||
| 			return false; | ||||
| 		} | ||||
| @@ -246,7 +247,7 @@ b32 vm_free( VirtualMemory vm ) | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| VirtualMemory vm_trim( VirtualMemory vm, sw lead_size, sw size ) | ||||
| VirtualMemory vm_trim( VirtualMemory vm, ssize lead_size, ssize size ) | ||||
| { | ||||
| 	VirtualMemory new_vm = { 0 }; | ||||
| 	void*             ptr; | ||||
| @@ -270,7 +271,7 @@ b32 vm_purge( VirtualMemory vm ) | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| sw virtual_memory_page_size( sw* alignment_out ) | ||||
| ssize virtual_memory_page_size( ssize* alignment_out ) | ||||
| { | ||||
| 	SYSTEM_INFO info; | ||||
| 	GetSystemInfo( &info ); | ||||
| @@ -285,7 +286,7 @@ sw virtual_memory_page_size( sw* alignment_out ) | ||||
| #	ifndef MAP_ANONYMOUS | ||||
| #		define MAP_ANONYMOUS MAP_ANON | ||||
| #	endif | ||||
| VirtualMemory vm_alloc( void* addr, sw size ) | ||||
| VirtualMemory vm_alloc( void* addr, ssize size ) | ||||
| { | ||||
| 	VirtualMemory vm; | ||||
| 	GEN_ASSERT( size > 0 ); | ||||
| @@ -300,10 +301,10 @@ b32 vm_free( VirtualMemory vm ) | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| VirtualMemory vm_trim( VirtualMemory vm, sw lead_size, sw size ) | ||||
| VirtualMemory vm_trim( VirtualMemory vm, ssize lead_size, ssize size ) | ||||
| { | ||||
| 	void*  ptr; | ||||
| 	sw trail_size; | ||||
| 	ssize trail_size; | ||||
| 	GEN_ASSERT( vm.size >= lead_size + size ); | ||||
|  | ||||
| 	ptr        = pointer_add( vm.data, lead_size ); | ||||
| @@ -322,10 +323,10 @@ b32 vm_purge( VirtualMemory vm ) | ||||
| 	return err != 0; | ||||
| } | ||||
|  | ||||
| sw virtual_memory_page_size( sw* alignment_out ) | ||||
| ssize virtual_memory_page_size( ssize* alignment_out ) | ||||
| { | ||||
| 	// TODO: Is this always true? | ||||
| 	sw result = zpl_cast( sw ) sysconf( _SC_PAGE_SIZE ); | ||||
| 	ssize result = scast( ssize, sysconf( _SC_PAGE_SIZE )); | ||||
| 	if ( alignment_out ) | ||||
| 		*alignment_out = result; | ||||
| 	return result; | ||||
| @@ -334,7 +335,7 @@ sw virtual_memory_page_size( sw* alignment_out ) | ||||
|  | ||||
| #pragma endregion VirtualMemory | ||||
|  | ||||
| void* Arena::allocator_proc( void* allocator_data, AllocType type, sw size, sw alignment, void* old_memory, sw 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; | ||||
| @@ -346,10 +347,10 @@ void* Arena::allocator_proc( void* allocator_data, AllocType type, sw size, sw a | ||||
| 		case EAllocation_ALLOC : | ||||
| 			{ | ||||
| 				void* end        = pointer_add( arena->PhysicalStart, arena->TotalUsed ); | ||||
| 				sw    total_size = align_forward_i64( size, alignment ); | ||||
| 				ssize total_size = align_forward_s64( size, alignment ); | ||||
|  | ||||
| 				// NOTE: Out of memory | ||||
| 				if ( arena->TotalUsed + total_size > (sw) arena->TotalSize ) | ||||
| 				if ( arena->TotalUsed + total_size > (ssize) arena->TotalSize ) | ||||
| 				{ | ||||
| 					// zpl__printf_err("%s", "Arena out of memory\n"); | ||||
| 					GEN_FATAL("Arena out of memory! (Possibly could not fit for the largest size Arena!!)"); | ||||
| @@ -384,9 +385,9 @@ void* Arena::allocator_proc( void* allocator_data, AllocType type, sw size, sw a | ||||
| 	return ptr; | ||||
| } | ||||
|  | ||||
| void* Pool::allocator_proc( void* allocator_data, AllocType type, sw size, sw alignment, void* old_memory, sw 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 = zpl_cast( Pool* ) allocator_data; | ||||
| 	Pool* pool = rcast( Pool*, allocator_data); | ||||
| 	void* ptr  = NULL; | ||||
|  | ||||
| 	// unused( old_size ); | ||||
| @@ -401,9 +402,9 @@ void* Pool::allocator_proc( void* allocator_data, AllocType type, sw size, sw al | ||||
| 				GEN_ASSERT( alignment == pool->BlockAlign ); | ||||
| 				GEN_ASSERT( pool->FreeList != NULL ); | ||||
|  | ||||
| 				next_free        = *zpl_cast( uptr* ) pool->FreeList; | ||||
| 				next_free        = * rcast( uptr*, pool->FreeList); | ||||
| 				ptr              = pool->FreeList; | ||||
| 				pool->FreeList   = zpl_cast( void* ) next_free; | ||||
| 				pool->FreeList   = rcast( void*, next_free); | ||||
| 				pool->TotalSize += pool->BlockSize; | ||||
|  | ||||
| 				if ( flags & ALLOCATOR_FLAG_CLEAR_TO_ZERO ) | ||||
| @@ -417,8 +418,8 @@ void* Pool::allocator_proc( void* allocator_data, AllocType type, sw size, sw al | ||||
| 				if ( old_memory == NULL ) | ||||
| 					return NULL; | ||||
|  | ||||
| 				next             = zpl_cast( uptr* ) old_memory; | ||||
| 				*next            = zpl_cast( uptr ) pool->FreeList; | ||||
| 				next             = rcast( uptr*, old_memory); | ||||
| 				*next            = rcast( uptr, pool->FreeList); | ||||
| 				pool->FreeList   = old_memory; | ||||
| 				pool->TotalSize -= pool->BlockSize; | ||||
| 			} | ||||
| @@ -426,7 +427,7 @@ void* Pool::allocator_proc( void* allocator_data, AllocType type, sw size, sw al | ||||
|  | ||||
| 		case EAllocation_FREE_ALL : | ||||
| 			{ | ||||
| 				sw    actual_block_size, block_index; | ||||
| 				ssize    actual_block_size, block_index; | ||||
| 				void* curr; | ||||
| 				uptr* end; | ||||
|  | ||||
| @@ -437,13 +438,13 @@ void* Pool::allocator_proc( void* allocator_data, AllocType type, sw size, sw al | ||||
| 				curr = pool->PhysicalStart; | ||||
| 				for ( block_index = 0; block_index < pool->NumBlocks - 1; block_index++ ) | ||||
| 				{ | ||||
| 					uptr* next = zpl_cast( uptr* ) curr; | ||||
| 					*next      = zpl_cast( uptr ) curr + actual_block_size; | ||||
| 					uptr* next = rcast( uptr*, curr); | ||||
| 					* next     = rcast( uptr, curr) + actual_block_size; | ||||
| 					curr       = pointer_add( curr, actual_block_size ); | ||||
| 				} | ||||
|  | ||||
| 				end            = zpl_cast( uptr* ) curr; | ||||
| 				*end           = zpl_cast( uptr ) NULL; | ||||
| 				end            = rcast( uptr*, curr); | ||||
| 				* end          = scast( uptr, NULL); | ||||
| 				pool->FreeList = pool->PhysicalStart; | ||||
| 			} | ||||
| 			break; | ||||
| @@ -457,11 +458,11 @@ void* Pool::allocator_proc( void* allocator_data, AllocType type, sw size, sw al | ||||
| 	return ptr; | ||||
| } | ||||
|  | ||||
| Pool Pool::init_align( AllocatorInfo backing, sw num_blocks, sw block_size, sw block_align ) | ||||
| Pool pool_init_align( AllocatorInfo backing, ssize num_blocks, ssize block_size, ssize block_align ) | ||||
| { | ||||
| 	Pool pool = {}; | ||||
|  | ||||
| 	sw    actual_block_size, pool_size, block_index; | ||||
| 	ssize    actual_block_size, pool_size, block_index; | ||||
| 	void *data, *curr; | ||||
| 	uptr* end; | ||||
|  | ||||
| @@ -495,16 +496,16 @@ Pool Pool::init_align( AllocatorInfo backing, sw num_blocks, sw block_size, sw b | ||||
| 	return pool; | ||||
| } | ||||
|  | ||||
| void Pool::clear() | ||||
| void pool_clear(Pool* pool) | ||||
| { | ||||
| 	sw    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 +515,8 @@ void Pool::clear() | ||||
| 	end  =  ( uptr* ) curr; | ||||
| 	*end =  ( uptr )  NULL; | ||||
|  | ||||
| 	FreeList = PhysicalStart; | ||||
| 	pool->FreeList = pool->PhysicalStart; | ||||
| } | ||||
|  | ||||
| GEN_API_C_END | ||||
| #pragma endregion Memory | ||||
|   | ||||
| @@ -10,43 +10,53 @@ | ||||
| #define gigabytes( x ) ( megabytes( x ) * ( s64 )( 1024 ) ) | ||||
| #define terabytes( x ) ( gigabytes( x ) * ( s64 )( 1024 ) ) | ||||
|  | ||||
| #define GEN__ONES          ( zpl_cast( uw ) - 1 / GEN_U8_MAX ) | ||||
| #define GEN__ONES          ( scast( GEN_NS usize, - 1) / GEN_U8_MAX ) | ||||
| #define GEN__HIGHS         ( GEN__ONES * ( GEN_U8_MAX / 2 + 1 ) ) | ||||
| #define GEN__HAS_ZERO( x ) ( ( ( x ) - GEN__ONES ) & ~( x ) & GEN__HIGHS ) | ||||
|  | ||||
| template< class Type > | ||||
| void swap( Type& a, Type& b ) | ||||
| { | ||||
| 	Type tmp = a; | ||||
| 	a = b; | ||||
| 	b = tmp; | ||||
| } | ||||
|  | ||||
| GEN_API_C_BEGIN | ||||
|  | ||||
| //! Checks if value is power of 2. | ||||
| GEN_DEF_INLINE b32 is_power_of_two( sw x ); | ||||
| b32 is_power_of_two( ssize x ); | ||||
|  | ||||
| //! Aligns address to specified alignment. | ||||
| GEN_DEF_INLINE void* align_forward( void* ptr, sw alignment ); | ||||
| void* align_forward( void* ptr, ssize alignment ); | ||||
|  | ||||
| //! Aligns value to a specified alignment. | ||||
| GEN_DEF_INLINE s64 align_forward_i64( s64 value, sw alignment ); | ||||
| s64 align_forward_by_value( s64 value, ssize alignment ); | ||||
|  | ||||
| //! Moves pointer forward by bytes. | ||||
| GEN_DEF_INLINE void* pointer_add( void* ptr, sw bytes ); | ||||
| void* pointer_add( void* ptr, ssize bytes ); | ||||
|  | ||||
| //! Moves pointer forward by bytes. | ||||
| GEN_DEF_INLINE void const* pointer_add_const( void const* ptr, sw bytes ); | ||||
| void const* pointer_add_const( void const* ptr, ssize bytes ); | ||||
|  | ||||
| //! Calculates difference between two addresses. | ||||
| GEN_DEF_INLINE sw pointer_diff( void const* begin, void const* end ); | ||||
| ssize pointer_diff( void const* begin, void const* end ); | ||||
|  | ||||
| //! Copy non-overlapping memory from source to destination. | ||||
| void* mem_copy( void* dest, void const* source, sw size ); | ||||
| void* mem_copy( void* dest, void const* source, ssize size ); | ||||
|  | ||||
| //! Search for a constant value within the size limit at memory location. | ||||
| void const* mem_find( void const* data, u8 byte_value, sw size ); | ||||
| void const* mem_find( void const* data, u8 byte_value, ssize size ); | ||||
|  | ||||
| //! Copy memory from source to destination. | ||||
| GEN_DEF_INLINE void* mem_move( void* dest, void const* source, sw size ); | ||||
| void* mem_move( void* dest, void const* source, ssize size ); | ||||
|  | ||||
| //! Set constant value at memory location with specified size. | ||||
| GEN_DEF_INLINE void* mem_set( void* data, u8 byte_value, sw size ); | ||||
| void* mem_set( void* data, u8 byte_value, ssize size ); | ||||
|  | ||||
| //! @param ptr Memory location to clear up. | ||||
| //! @param size The size to clear up with. | ||||
| GEN_DEF_INLINE void zero_size( void* ptr, sw size ); | ||||
| void zero_size( void* ptr, ssize size ); | ||||
|  | ||||
| //! Clears up an item. | ||||
| #define zero_item( t ) zero_size( ( t ), size_of( *( t ) ) )    // NOTE: Pass pointer of struct | ||||
| @@ -54,24 +64,23 @@ GEN_DEF_INLINE void zero_size( void* ptr, sw 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 | ||||
| 	, sw size, sw alignment | ||||
| 	, void* old_memory, sw 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 | ||||
| { | ||||
| @@ -87,22 +96,22 @@ enum AllocFlag | ||||
| #endif | ||||
|  | ||||
| //! Allocate memory with default alignment. | ||||
| GEN_DEF_INLINE void* alloc( AllocatorInfo a, sw size ); | ||||
| void* alloc( AllocatorInfo a, ssize size ); | ||||
|  | ||||
| //! Allocate memory with specified alignment. | ||||
| GEN_DEF_INLINE void* alloc_align( AllocatorInfo a, sw size, sw alignment ); | ||||
| void* alloc_align( AllocatorInfo a, ssize size, ssize alignment ); | ||||
|  | ||||
| //! Free allocated memory. | ||||
| GEN_DEF_INLINE void free( AllocatorInfo a, void* ptr ); | ||||
| void allocator_free( AllocatorInfo a, void* ptr ); | ||||
|  | ||||
| //! Free all memory allocated by an allocator. | ||||
| GEN_DEF_INLINE void free_all( AllocatorInfo a ); | ||||
| void free_all( AllocatorInfo a ); | ||||
|  | ||||
| //! Resize an allocated memory. | ||||
| GEN_DEF_INLINE void* resize( AllocatorInfo a, void* ptr, sw old_size, sw new_size ); | ||||
| void* resize( AllocatorInfo a, void* ptr, ssize old_size, ssize new_size ); | ||||
|  | ||||
| //! Resize an allocated memory with specified alignment. | ||||
| GEN_DEF_INLINE void* resize_align( AllocatorInfo a, void* ptr, sw old_size, sw new_size, sw alignment ); | ||||
| void* resize_align( AllocatorInfo a, void* ptr, ssize old_size, ssize new_size, ssize alignment ); | ||||
|  | ||||
| //! Allocate memory for an item. | ||||
| #define alloc_item( allocator_, Type ) ( Type* )alloc( allocator_, size_of( Type ) ) | ||||
| @@ -115,19 +124,19 @@ GEN_DEF_INLINE void* resize_align( AllocatorInfo a, void* ptr, sw old_size, sw n | ||||
| /* call zpl_heap_stats_init at the beginning of the entry point */ | ||||
| /* you can call zpl_heap_stats_check near the end of the execution to validate any possible leaks */ | ||||
| void  heap_stats_init( void ); | ||||
| sw   heap_stats_used_memory( void ); | ||||
| sw   heap_stats_alloc_count( void ); | ||||
| ssize heap_stats_used_memory( void ); | ||||
| ssize heap_stats_alloc_count( void ); | ||||
| void  heap_stats_check( void ); | ||||
|  | ||||
| //! Allocate/Resize memory using default options. | ||||
|  | ||||
| //! Use this if you don't need a "fancy" resize allocation | ||||
| GEN_DEF_INLINE void* default_resize_align( AllocatorInfo a, void* ptr, sw old_size, sw new_size, sw alignment ); | ||||
| void* default_resize_align( AllocatorInfo a, void* ptr, ssize old_size, ssize new_size, ssize alignment ); | ||||
|  | ||||
| void* heap_allocator_proc( void* allocator_data, AllocType type, sw size, sw alignment, void* old_memory, sw old_size, u64 flags ); | ||||
| 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 ) | ||||
| @@ -135,210 +144,519 @@ constexpr AllocatorInfo heap( void ) { return { heap_allocator_proc, nullptr }; | ||||
| //! Helper to free memory allocated by heap allocator. | ||||
| #define mfree( ptr ) free( heap(), ptr ) | ||||
|  | ||||
| GEN_IMPL_INLINE b32 is_power_of_two( sw x ) | ||||
| struct VirtualMemory_Def | ||||
| { | ||||
| 	void*  data; | ||||
| 	ssize size; | ||||
| }; | ||||
| typedef struct VirtualMemory_Def VirtualMemory; | ||||
|  | ||||
| //! Initialize virtual memory from existing data. | ||||
| VirtualMemory vm_from_memory( void* data, ssize size ); | ||||
|  | ||||
| //! Allocate virtual memory at address with size. | ||||
|  | ||||
| //! @param addr The starting address of the region to reserve. If NULL, it lets operating system to decide where to allocate it. | ||||
| //! @param size The size to serve. | ||||
| VirtualMemory vm_alloc( void* addr, ssize size ); | ||||
|  | ||||
| //! Release the virtual memory. | ||||
| b32 vm_free( VirtualMemory vm ); | ||||
|  | ||||
| //! Trim virtual memory. | ||||
| VirtualMemory vm_trim( VirtualMemory vm, ssize lead_size, ssize size ); | ||||
|  | ||||
| //! Purge virtual memory. | ||||
| b32 vm_purge( VirtualMemory vm ); | ||||
|  | ||||
| //! Retrieve VM's page size and alignment. | ||||
| ssize virtual_memory_page_size( ssize* alignment_out ); | ||||
|  | ||||
| #pragma region Arena | ||||
| struct Arena_Def; | ||||
| typedef struct Arena_Def Arena; | ||||
|  | ||||
| AllocatorInfo arena_allocator_info( Arena* arena ); | ||||
|  | ||||
| // Remove static keyword and rename allocator_proc | ||||
| void* arena_allocator_proc(void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags); | ||||
|  | ||||
| // Add these declarations after the Arena struct | ||||
| Arena arena_init_from_allocator(AllocatorInfo backing, ssize size); | ||||
| Arena arena_init_from_memory   ( void* start, ssize size ); | ||||
|  | ||||
| Arena arena_init_sub      (Arena* parent, ssize size); | ||||
| ssize arena_alignment_of  (Arena* arena, ssize alignment); | ||||
| void  arena_check         (Arena* arena); | ||||
| void  arena_free          (Arena* arena); | ||||
| ssize arena_size_remaining(Arena* arena, ssize alignment); | ||||
|  | ||||
| struct Arena_Def | ||||
| { | ||||
| 	AllocatorInfo Backing; | ||||
| 	void*         PhysicalStart; | ||||
| 	ssize         TotalSize; | ||||
| 	ssize         TotalUsed; | ||||
| 	ssize         TempCount; | ||||
|  | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| #pragma region Member Mapping | ||||
| 	forceinline operator AllocatorInfo() { return GEN_NS arena_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 arena_alignment_of(this, alignment); } | ||||
| 	forceinline        void  free()                                                                                                                           { return GEN_NS arena_free(this);  } | ||||
| 	forceinline        ssize size_remaining( ssize alignment )                                                                                                { return GEN_NS arena_size_remaining(this, alignment); } | ||||
|  | ||||
| // This id is defined by Unreal for asserts | ||||
| #pragma push_macro("check") | ||||
| #undef check | ||||
| 	forceinline void check() { GEN_NS arena_check(this); } | ||||
| #pragma pop_macro("check") | ||||
|  | ||||
| #pragma endregion Member Mapping | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| #if GEN_SUPPORT_CPP_REFERENCES | ||||
| GEN_API_C_END | ||||
| forceinline AllocatorInfo allocator_info(Arena& arena )                 { return arena_allocator_info(& arena); } | ||||
| forceinline Arena         init_sub      (Arena& parent, ssize size)     { return arena_init_sub( & parent, size); } | ||||
| forceinline ssize         alignment_of  (Arena& arena, ssize alignment) { return arena_alignment_of( & arena, alignment); } | ||||
| forceinline void          free          (Arena& arena)                  { return arena_free(& arena); } | ||||
| forceinline ssize         size_remaining(Arena& arena, ssize alignment) { return arena_size_remaining(& arena, alignment); } | ||||
|  | ||||
| // This id is defined by Unreal for asserts | ||||
| #pragma push_macro("check") | ||||
| #undef check | ||||
| forceinline void check(Arena& arena) { return arena_check(& arena); }; | ||||
| #pragma pop_macro("check") | ||||
| GEN_API_C_BEGIN | ||||
| #endif | ||||
|  | ||||
|  | ||||
| inline | ||||
| AllocatorInfo arena_allocator_info( Arena* arena ) { | ||||
| 	GEN_ASSERT(arena != nullptr); | ||||
| 	AllocatorInfo info = { arena_allocator_proc, arena }; | ||||
| 	return info; | ||||
| } | ||||
|  | ||||
| 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 arena_init_sub(Arena* parent, ssize size) { | ||||
| 	GEN_ASSERT(parent != nullptr); | ||||
| 	return arena_init_from_allocator(parent->Backing, size); | ||||
| } | ||||
|  | ||||
| inline | ||||
| ssize arena_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; | ||||
| } | ||||
|  | ||||
| inline | ||||
| void arena_check(Arena* arena) | ||||
| { | ||||
|     GEN_ASSERT(arena != nullptr ); | ||||
|     GEN_ASSERT(arena->TempCount == 0); | ||||
| } | ||||
|  | ||||
| inline | ||||
| void arena_free(Arena* arena) | ||||
| { | ||||
| 	GEN_ASSERT(arena != nullptr); | ||||
| 	if (arena->Backing.Proc) | ||||
| 	{ | ||||
| 		allocator_free(arena->Backing, arena->PhysicalStart); | ||||
| 		arena->PhysicalStart = nullptr; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| inline | ||||
| ssize arena_size_remaining(Arena* arena, ssize alignment) | ||||
| { | ||||
| 	GEN_ASSERT(arena != nullptr); | ||||
| 	ssize result = arena->TotalSize - (arena->TotalUsed + arena_alignment_of(arena, alignment)); | ||||
| 	return result; | ||||
| } | ||||
| #pragma endregion Arena | ||||
|  | ||||
| GEN_API_C_END | ||||
|  | ||||
| #pragma region FixedArena | ||||
| template<s32 Size> | ||||
| struct FixedArena; | ||||
|  | ||||
| template<s32 Size> FixedArena<Size> fixed_arena_init(); | ||||
| template<s32 Size> AllocatorInfo    fixed_arena_allocator_info(FixedArena<Size>* fixed_arena ); | ||||
| template<s32 Size> ssize            fixed_arena_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 | ||||
| { | ||||
| 	char  memory[Size]; | ||||
| 	Arena arena; | ||||
|  | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| #pragma region Member Mapping | ||||
| 	forceinline operator AllocatorInfo() { return GEN_NS allocator_info(this); } | ||||
|  | ||||
| 	forceinline static FixedArena init()                          { FixedArena result; GEN_NS fixed_arena_init<Size>(result); return result; } | ||||
| 	forceinline ssize             size_remaining(ssize alignment) { GEN_NS size_remaining(this, alignment); } | ||||
| #pragma endregion Member Mapping | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| template<s32 Size> inline | ||||
| AllocatorInfo fixed_arena_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 | ||||
| void fixed_arena_free(FixedArena<Size>* fixed_arena) { | ||||
| 	arena_free( & fixed_arena->arena); | ||||
| } | ||||
|  | ||||
| template<s32 Size> inline | ||||
| ssize fixed_arena_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 ) >; | ||||
| using Arena_16KB  = FixedArena< kilobytes( 16 ) >; | ||||
| using Arena_32KB  = FixedArena< kilobytes( 32 ) >; | ||||
| using Arena_64KB  = FixedArena< kilobytes( 64 ) >; | ||||
| using Arena_128KB = FixedArena< kilobytes( 128 ) >; | ||||
| using Arena_256KB = FixedArena< kilobytes( 256 ) >; | ||||
| 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 | ||||
|  | ||||
| GEN_API_C_BEGIN | ||||
|  | ||||
| #pragma region Pool | ||||
| struct Pool_Def; | ||||
| typedef struct Pool_Def 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 pool_allocator_info(Pool* pool); | ||||
| void          pool_clear(Pool* pool); | ||||
| void          pool_free(Pool* pool); | ||||
|  | ||||
| #if GEN_SUPPORT_CPP_REFERENCES | ||||
| GEN_API_C_END | ||||
| AllocatorInfo allocator_info(Pool& pool) { return pool_allocator_info(& pool); } | ||||
| void          clear(Pool& pool)          { return pool_clear(& pool); } | ||||
| void          free(Pool& pool)           { return pool_free(& pool); } | ||||
| GEN_API_C_BEGIN | ||||
| #endif | ||||
|  | ||||
| struct Pool_Def | ||||
| { | ||||
| 	AllocatorInfo Backing; | ||||
| 	void*         PhysicalStart; | ||||
| 	void*         FreeList; | ||||
| 	ssize         BlockSize; | ||||
| 	ssize         BlockAlign; | ||||
| 	ssize         TotalSize; | ||||
| 	ssize         NumBlocks; | ||||
|  | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| #pragma region Member Mapping | ||||
|     forceinline operator AllocatorInfo() { return GEN_NS pool_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 pool_clear( this); } | ||||
|     forceinline        void  free()  { GEN_NS pool_free( this); } | ||||
| #pragma endregion | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| inline | ||||
| AllocatorInfo pool_allocator_info(Pool* pool) { | ||||
| 	AllocatorInfo info = { pool_allocator_proc, pool }; | ||||
| 	return info; | ||||
| } | ||||
|  | ||||
| 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 pool_free(Pool* pool) { | ||||
|    if(pool->Backing.Proc) { | ||||
|        allocator_free(pool->Backing, pool->PhysicalStart); | ||||
|    } | ||||
| } | ||||
| #pragma endregion Pool | ||||
|  | ||||
| inline | ||||
| b32 is_power_of_two( ssize x ) { | ||||
| 	if ( x <= 0 ) | ||||
| 		return false; | ||||
| 	return ! ( x & ( x - 1 ) ); | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE void* align_forward( void* ptr, sw alignment ) | ||||
| inline | ||||
| mem_ptr align_forward( void* ptr, ssize alignment ) | ||||
| { | ||||
| 	uptr p; | ||||
|  | ||||
| 	GEN_ASSERT( is_power_of_two( alignment ) ); | ||||
| 	uptr p       = to_uptr(ptr); | ||||
| 	uptr forward = (p + ( alignment - 1 ) ) & ~( alignment - 1 ); | ||||
|  | ||||
| 	p = zpl_cast( uptr ) ptr; | ||||
| 	return zpl_cast( void* )( ( p + ( alignment - 1 ) ) & ~( alignment - 1 ) ); | ||||
| 	return to_mem_ptr(forward); | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE s64 align_forward_i64( s64 value, sw alignment ) | ||||
| { | ||||
| 	return value + ( alignment - value % alignment ) % alignment; | ||||
| inline s64 align_forward_s64( s64 value, ssize alignment ) { return value + ( alignment - value % alignment ) % alignment; } | ||||
|  | ||||
| inline void*       pointer_add      ( void*       ptr, ssize bytes ) { return rcast(void*,         rcast( u8*,        ptr) + bytes ); } | ||||
| inline void const* pointer_add_const( void const* ptr, ssize bytes ) { return rcast(void const*, rcast( u8 const*,  ptr) + bytes ); } | ||||
|  | ||||
| inline sptr pointer_diff( mem_ptr_const begin, mem_ptr_const end ) { | ||||
| 	return scast( ssize, rcast( u8 const*, end) - rcast(u8 const*, begin) ); | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE void* pointer_add( void* ptr, sw bytes ) | ||||
| inline | ||||
| void* mem_move( void* destination, void const* source, ssize byte_count ) | ||||
| { | ||||
| 	return zpl_cast( void* )( zpl_cast( u8* ) ptr + bytes ); | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE void const* pointer_add_const( void const* ptr, sw bytes ) | ||||
| { | ||||
| 	return zpl_cast( void const* )( zpl_cast( u8 const* ) ptr + bytes ); | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE sw pointer_diff( void const* begin, void const* end ) | ||||
| { | ||||
| 	return zpl_cast( sw )( zpl_cast( u8 const* ) end - zpl_cast( u8 const* ) begin ); | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE void* mem_move( void* dest, void const* source, sw n ) | ||||
| { | ||||
| 	if ( dest == NULL ) | ||||
| 	if ( destination == NULL ) | ||||
| 	{ | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	u8*       d = zpl_cast( u8* ) dest; | ||||
| 	u8 const* s = zpl_cast( u8 const* ) source; | ||||
| 	u8*       dest_ptr = rcast( u8*, destination); | ||||
| 	u8 const* src_ptr  = rcast( u8 const*, source); | ||||
|  | ||||
| 	if ( d == s ) | ||||
| 		return d; | ||||
| 	if ( s + n <= d || d + n <= s )    // NOTE: Non-overlapping | ||||
| 		return mem_copy( d, s, n ); | ||||
| 	if ( dest_ptr == src_ptr ) | ||||
| 		return dest_ptr; | ||||
|  | ||||
| 	if ( d < s ) | ||||
| 	if ( src_ptr + byte_count <= dest_ptr || dest_ptr + byte_count <= src_ptr )    // NOTE: Non-overlapping | ||||
| 		return mem_copy( dest_ptr, src_ptr, byte_count ); | ||||
|  | ||||
| 	if ( dest_ptr < src_ptr ) | ||||
| 	{ | ||||
| 		if ( zpl_cast( uptr ) s % size_of( sw ) == zpl_cast( uptr ) d % size_of( sw ) ) | ||||
| 		if ( to_uptr(src_ptr) % size_of( ssize ) == to_uptr(dest_ptr) % size_of( ssize ) ) | ||||
| 		{ | ||||
| 			while ( zpl_cast( uptr ) d % size_of( sw ) ) | ||||
| 			while ( pcast( uptr, dest_ptr) % size_of( ssize ) ) | ||||
| 			{ | ||||
| 				if ( ! n-- ) | ||||
| 					return dest; | ||||
| 				*d++ = *s++; | ||||
| 				if ( ! byte_count-- ) | ||||
| 					return destination; | ||||
|  | ||||
| 				*dest_ptr++ = *src_ptr++; | ||||
| 			} | ||||
| 			while ( n >= size_of( sw ) ) | ||||
| 			while ( byte_count >= size_of( ssize ) ) | ||||
| 			{ | ||||
| 				*zpl_cast( sw* ) d  = *zpl_cast( sw* ) s; | ||||
| 				n                  -= size_of( sw ); | ||||
| 				d                  += size_of( sw ); | ||||
| 				s                  += size_of( sw ); | ||||
| 				* rcast(ssize*, dest_ptr)  = * rcast(ssize const*, src_ptr); | ||||
| 				byte_count -= size_of( ssize ); | ||||
| 				dest_ptr   += size_of( ssize ); | ||||
| 				src_ptr    += size_of( ssize ); | ||||
| 			} | ||||
| 		} | ||||
| 		for ( ; n; n-- ) | ||||
| 			*d++ = *s++; | ||||
| 		for ( ; byte_count; byte_count-- ) | ||||
| 			*dest_ptr++ = *src_ptr++; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		if ( ( zpl_cast( uptr ) s % size_of( sw ) ) == ( zpl_cast( uptr ) d % size_of( sw ) ) ) | ||||
| 		if ( ( to_uptr(src_ptr) % size_of( ssize ) ) == ( to_uptr(dest_ptr) % size_of( ssize ) ) ) | ||||
| 		{ | ||||
| 			while ( zpl_cast( uptr )( d + n ) % size_of( sw ) ) | ||||
| 			while ( to_uptr( dest_ptr + byte_count ) % size_of( ssize ) ) | ||||
| 			{ | ||||
| 				if ( ! n-- ) | ||||
| 					return dest; | ||||
| 				d[ n ] = s[ n ]; | ||||
| 				if ( ! byte_count-- ) | ||||
| 					return destination; | ||||
|  | ||||
| 				dest_ptr[ byte_count ] = src_ptr[ byte_count ]; | ||||
| 			} | ||||
| 			while ( n >= size_of( sw ) ) | ||||
| 			while ( byte_count >= size_of( ssize ) ) | ||||
| 			{ | ||||
| 				n                         -= size_of( sw ); | ||||
| 				*zpl_cast( sw* )( d + n )  = *zpl_cast( sw* )( s + n ); | ||||
| 				byte_count                              -= size_of( ssize ); | ||||
| 				* rcast(ssize*, dest_ptr + byte_count )  = * rcast( ssize const*, src_ptr + byte_count ); | ||||
| 			} | ||||
| 		} | ||||
| 		while ( n ) | ||||
| 			n--, d[ n ] = s[ n ]; | ||||
| 		while ( byte_count ) | ||||
| 			byte_count--, dest_ptr[ byte_count ] = src_ptr[ byte_count ]; | ||||
| 	} | ||||
|  | ||||
| 	return dest; | ||||
| 	return destination; | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE void* mem_set( void* dest, u8 c, sw n ) | ||||
| inline | ||||
| void* mem_set( void* destination, u8 fill_byte, ssize byte_count ) | ||||
| { | ||||
| 	if ( dest == NULL ) | ||||
| 	if ( destination == NULL ) | ||||
| 	{ | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	u8* s = zpl_cast( u8* ) dest; | ||||
| 	sw  k; | ||||
| 	u32 c32 = ( ( u32 )-1 ) / 255 * c; | ||||
| 	ssize align_offset; | ||||
| 	u8*   dest_ptr  = rcast( u8*, destination); | ||||
| 	u32   fill_word = ( ( u32 )-1 ) / 255 * fill_byte; | ||||
|  | ||||
| 	if ( n == 0 ) | ||||
| 		return dest; | ||||
| 	s[ 0 ] = s[ n - 1 ] = c; | ||||
| 	if ( n < 3 ) | ||||
| 		return dest; | ||||
| 	s[ 1 ] = s[ n - 2 ] = c; | ||||
| 	s[ 2 ] = s[ n - 3 ] = c; | ||||
| 	if ( n < 7 ) | ||||
| 		return dest; | ||||
| 	s[ 3 ] = s[ n - 4 ] = c; | ||||
| 	if ( n < 9 ) | ||||
| 		return dest; | ||||
| 	if ( byte_count == 0 ) | ||||
| 		return destination; | ||||
|  | ||||
| 	k  = -zpl_cast( sptr ) s & 3; | ||||
| 	s += k; | ||||
| 	n -= k; | ||||
| 	n &= -4; | ||||
| 	dest_ptr[ 0 ] = dest_ptr[ byte_count - 1 ] = fill_byte; | ||||
| 	if ( byte_count < 3 ) | ||||
| 		return destination; | ||||
|  | ||||
| 	*zpl_cast( u32* )( s + 0 )     = c32; | ||||
| 	*zpl_cast( u32* )( s + n - 4 ) = c32; | ||||
| 	if ( n < 9 ) | ||||
| 		return dest; | ||||
| 	*zpl_cast( u32* )( s + 4 )      = c32; | ||||
| 	*zpl_cast( u32* )( s + 8 )      = c32; | ||||
| 	*zpl_cast( u32* )( s + n - 12 ) = c32; | ||||
| 	*zpl_cast( u32* )( s + n - 8 )  = c32; | ||||
| 	if ( n < 25 ) | ||||
| 		return dest; | ||||
| 	*zpl_cast( u32* )( s + 12 )     = c32; | ||||
| 	*zpl_cast( u32* )( s + 16 )     = c32; | ||||
| 	*zpl_cast( u32* )( s + 20 )     = c32; | ||||
| 	*zpl_cast( u32* )( s + 24 )     = c32; | ||||
| 	*zpl_cast( u32* )( s + n - 28 ) = c32; | ||||
| 	*zpl_cast( u32* )( s + n - 24 ) = c32; | ||||
| 	*zpl_cast( u32* )( s + n - 20 ) = c32; | ||||
| 	*zpl_cast( u32* )( s + n - 16 ) = c32; | ||||
| 	dest_ptr[ 1 ] = dest_ptr[ byte_count - 2 ] = fill_byte; | ||||
| 	dest_ptr[ 2 ] = dest_ptr[ byte_count - 3 ] = fill_byte; | ||||
| 	if ( byte_count < 7 ) | ||||
| 		return destination; | ||||
|  | ||||
| 	k  = 24 + ( zpl_cast( uptr ) s & 4 ); | ||||
| 	s += k; | ||||
| 	n -= k; | ||||
| 	dest_ptr[ 3 ] = dest_ptr[ byte_count - 4 ] = fill_byte; | ||||
| 	if ( byte_count < 9 ) | ||||
| 		return destination; | ||||
|  | ||||
| 	align_offset  = -to_sptr( dest_ptr ) & 3; | ||||
| 	dest_ptr     += align_offset; | ||||
| 	byte_count   -= align_offset; | ||||
| 	byte_count   &= -4; | ||||
|  | ||||
| 	* rcast( u32*, ( dest_ptr + 0              ) ) = fill_word; | ||||
| 	* rcast( u32*, ( dest_ptr + byte_count - 4 ) ) = fill_word; | ||||
| 	if ( byte_count < 9 ) | ||||
| 		return destination; | ||||
|  | ||||
| 	* rcast( u32*, dest_ptr + 4 )               = fill_word; | ||||
| 	* rcast( u32*, dest_ptr + 8 )               = fill_word; | ||||
| 	* rcast( u32*, dest_ptr + byte_count - 12 ) = fill_word; | ||||
| 	* rcast( u32*, dest_ptr + byte_count - 8 )  = fill_word; | ||||
| 	if ( byte_count < 25 ) | ||||
| 		return destination; | ||||
|  | ||||
| 	* rcast( u32*, dest_ptr + 12 )              = fill_word; | ||||
| 	* rcast( u32*, dest_ptr + 16 )              = fill_word; | ||||
| 	* rcast( u32*, dest_ptr + 20 )              = fill_word; | ||||
| 	* rcast( u32*, dest_ptr + 24 )              = fill_word; | ||||
| 	* rcast( u32*, dest_ptr + byte_count - 28 ) = fill_word; | ||||
| 	* rcast( u32*, dest_ptr + byte_count - 24 ) = fill_word; | ||||
| 	* rcast( u32*, dest_ptr + byte_count - 20 ) = fill_word; | ||||
| 	* rcast( u32*, dest_ptr + byte_count - 16 ) = fill_word; | ||||
|  | ||||
| 	align_offset  = 24 + to_uptr( dest_ptr ) & 4; | ||||
| 	dest_ptr     += align_offset; | ||||
| 	byte_count   -= align_offset; | ||||
|  | ||||
| 	{ | ||||
| 		u64 c64 = ( zpl_cast( u64 ) c32 << 32 ) | c32; | ||||
| 		while ( n > 31 ) | ||||
| 		u64 fill_doubleword = ( scast( u64, fill_word) << 32 ) | fill_word; | ||||
| 		while ( byte_count > 31 ) | ||||
| 		{ | ||||
| 			*zpl_cast( u64* )( s + 0 )  = c64; | ||||
| 			*zpl_cast( u64* )( s + 8 )  = c64; | ||||
| 			*zpl_cast( u64* )( s + 16 ) = c64; | ||||
| 			*zpl_cast( u64* )( s + 24 ) = c64; | ||||
| 			* rcast( u64*, dest_ptr + 0 )  = fill_doubleword; | ||||
| 			* rcast( u64*, dest_ptr + 8 )  = fill_doubleword; | ||||
| 			* rcast( u64*, dest_ptr + 16 ) = fill_doubleword; | ||||
| 			* rcast( u64*, dest_ptr + 24 ) = fill_doubleword; | ||||
|  | ||||
| 			n -= 32; | ||||
| 			s += 32; | ||||
| 			byte_count -= 32; | ||||
| 			dest_ptr += 32; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return dest; | ||||
| 	return destination; | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE void* alloc_align( AllocatorInfo a, sw size, sw alignment ) | ||||
| { | ||||
| inline | ||||
| void* alloc_align( AllocatorInfo a, ssize size, ssize alignment ) { | ||||
| 	return a.Proc( a.Data, EAllocation_ALLOC, size, alignment, nullptr, 0, GEN_DEFAULT_ALLOCATOR_FLAGS ); | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE void* alloc( AllocatorInfo a, sw size ) | ||||
| { | ||||
| inline | ||||
| void* alloc( AllocatorInfo a, ssize size ) { | ||||
| 	return alloc_align( a, size, GEN_DEFAULT_MEMORY_ALIGNMENT ); | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE void free( AllocatorInfo a, void* ptr ) | ||||
| { | ||||
| inline | ||||
| void allocator_free( AllocatorInfo a, void* ptr ) { | ||||
| 	if ( ptr != nullptr ) | ||||
| 		a.Proc( a.Data, EAllocation_FREE, 0, 0, ptr, 0, GEN_DEFAULT_ALLOCATOR_FLAGS ); | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE void free_all( AllocatorInfo a ) | ||||
| { | ||||
| inline | ||||
| void free_all( AllocatorInfo a ) { | ||||
| 	a.Proc( a.Data, EAllocation_FREE_ALL, 0, 0, nullptr, 0, GEN_DEFAULT_ALLOCATOR_FLAGS ); | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE void* resize( AllocatorInfo a, void* ptr, sw old_size, sw new_size ) | ||||
| { | ||||
| inline | ||||
| void* resize( AllocatorInfo a, void* ptr, ssize old_size, ssize new_size ) { | ||||
| 	return resize_align( a, ptr, old_size, new_size, GEN_DEFAULT_MEMORY_ALIGNMENT ); | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE void* resize_align( AllocatorInfo a, void* ptr, sw old_size, sw new_size, sw alignment ) | ||||
| { | ||||
| inline | ||||
| void* resize_align( AllocatorInfo a, void* ptr, ssize old_size, ssize new_size, ssize alignment ) { | ||||
| 	return a.Proc( a.Data, EAllocation_RESIZE, new_size, alignment, ptr, old_size, GEN_DEFAULT_ALLOCATOR_FLAGS ); | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE void* default_resize_align( AllocatorInfo a, void* old_memory, sw old_size, sw new_size, sw alignment ) | ||||
| inline | ||||
| void* default_resize_align( AllocatorInfo a, void* old_memory, ssize old_size, ssize new_size, ssize alignment ) | ||||
| { | ||||
| 	if ( ! old_memory ) | ||||
| 		return alloc_align( a, new_size, alignment ); | ||||
|  | ||||
| 	if ( new_size == 0 ) | ||||
| 	{ | ||||
| 		free( a, old_memory ); | ||||
| 		allocator_free( a, old_memory ); | ||||
| 		return nullptr; | ||||
| 	} | ||||
|  | ||||
| @@ -354,204 +672,18 @@ GEN_IMPL_INLINE void* default_resize_align( AllocatorInfo a, void* old_memory, s | ||||
| 		void*  new_memory = alloc_align( a, new_size, alignment ); | ||||
| 		if ( ! new_memory ) | ||||
| 			return nullptr; | ||||
|  | ||||
| 		mem_move( new_memory, old_memory, min( new_size, old_size ) ); | ||||
| 		free( a, old_memory ); | ||||
| 		allocator_free( a, old_memory ); | ||||
| 		return new_memory; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE void zero_size( void* ptr, sw size ) | ||||
| { | ||||
| inline | ||||
| void zero_size( void* ptr, ssize size ) { | ||||
| 	mem_set( ptr, 0, size ); | ||||
| } | ||||
|  | ||||
| struct VirtualMemory | ||||
| { | ||||
| 	void*  data; | ||||
| 	sw size; | ||||
| }; | ||||
|  | ||||
| //! Initialize virtual memory from existing data. | ||||
| VirtualMemory vm_from_memory( void* data, sw size ); | ||||
|  | ||||
| //! Allocate virtual memory at address with size. | ||||
|  | ||||
| //! @param addr The starting address of the region to reserve. If NULL, it lets operating system to decide where to allocate it. | ||||
| //! @param size The size to serve. | ||||
| VirtualMemory vm_alloc( void* addr, sw size ); | ||||
|  | ||||
| //! Release the virtual memory. | ||||
| b32 vm_free( VirtualMemory vm ); | ||||
|  | ||||
| //! Trim virtual memory. | ||||
| VirtualMemory vm_trim( VirtualMemory vm, sw lead_size, sw size ); | ||||
|  | ||||
| //! Purge virtual memory. | ||||
| b32 gen_vm_purge( VirtualMemory vm ); | ||||
|  | ||||
| //! Retrieve VM's page size and alignment. | ||||
| sw gen_virtual_memory_page_size( sw* alignment_out ); | ||||
|  | ||||
| struct Arena | ||||
| { | ||||
| 	static | ||||
| 	void* allocator_proc( void* allocator_data, AllocType type, sw size, sw alignment, void* old_memory, sw old_size, u64 flags ); | ||||
|  | ||||
| 	static | ||||
| 	Arena init_from_memory( void* start, sw size ) | ||||
| 	{ | ||||
| 		return | ||||
| 		{ | ||||
| 			{ nullptr, nullptr }, | ||||
| 			start, | ||||
| 			size, | ||||
| 			0, | ||||
| 			0 | ||||
| 		}; | ||||
| 	} | ||||
|  | ||||
| 	static | ||||
| 	Arena init_from_allocator( AllocatorInfo backing, sw size ) | ||||
| 	{ | ||||
| 		Arena result = | ||||
| 		{ | ||||
| 		backing, | ||||
| 		alloc( backing, size), | ||||
| 		size, | ||||
| 		0, | ||||
| 		0 | ||||
| 		}; | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	static | ||||
| 	Arena init_sub( Arena& parent, sw size ) | ||||
| 	{ | ||||
| 		return init_from_allocator( parent.Backing, size ); | ||||
| 	} | ||||
|  | ||||
| 	sw alignment_of( sw alignment ) | ||||
| 	{ | ||||
| 		sw alignment_offset, result_pointer, mask; | ||||
| 		GEN_ASSERT( is_power_of_two( alignment ) ); | ||||
|  | ||||
| 		alignment_offset = 0; | ||||
| 		result_pointer   = (sw) PhysicalStart + TotalUsed; | ||||
| 		mask             = alignment - 1; | ||||
|  | ||||
| 		if ( result_pointer & mask ) | ||||
| 			alignment_offset = alignment - ( result_pointer & mask ); | ||||
|  | ||||
| 		return alignment_offset; | ||||
| 	} | ||||
|  | ||||
| 	void check() | ||||
| 	{ | ||||
| 		GEN_ASSERT( TempCount == 0 ); | ||||
| 	} | ||||
|  | ||||
| 	void free() | ||||
| 	{ | ||||
| 		if ( Backing.Proc ) | ||||
| 		{ | ||||
| 			gen::free( Backing, PhysicalStart ); | ||||
| 			PhysicalStart = nullptr; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	sw size_remaining( sw alignment ) | ||||
| 	{ | ||||
| 		sw result = TotalSize - ( TotalUsed + alignment_of( alignment ) ); | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	AllocatorInfo Backing; | ||||
| 	void*         PhysicalStart; | ||||
| 	sw            TotalSize; | ||||
| 	sw            TotalUsed; | ||||
| 	sw            TempCount; | ||||
|  | ||||
| 	operator AllocatorInfo() | ||||
| 	{ | ||||
| 		return { allocator_proc, this }; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| // 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; | ||||
| 	} | ||||
|  | ||||
| 	sw size_remaining( sw alignment ) | ||||
| 	{ | ||||
| 		return arena.size_remaining( alignment ); | ||||
| 	} | ||||
|  | ||||
| 	operator AllocatorInfo() | ||||
| 	{ | ||||
| 		return { Arena::allocator_proc, &arena }; | ||||
| 	} | ||||
|  | ||||
| 	Arena arena; | ||||
| 	char  memory[ Size ]; | ||||
| }; | ||||
|  | ||||
| using Arena_1KB   = FixedArena< kilobytes( 1 ) >; | ||||
| using Arena_4KB   = FixedArena< kilobytes( 4 ) >; | ||||
| using Arena_8KB   = FixedArena< kilobytes( 8 ) >; | ||||
| using Arena_16KB  = FixedArena< kilobytes( 16 ) >; | ||||
| using Arena_32KB  = FixedArena< kilobytes( 32 ) >; | ||||
| using Arena_64KB  = FixedArena< kilobytes( 64 ) >; | ||||
| using Arena_128KB = FixedArena< kilobytes( 128 ) >; | ||||
| using Arena_256KB = FixedArena< kilobytes( 256 ) >; | ||||
| using Arena_512KB = FixedArena< kilobytes( 512 ) >; | ||||
| using Arena_1MB   = FixedArena< megabytes( 1 ) >; | ||||
| using Arena_2MB   = FixedArena< megabytes( 2 ) >; | ||||
| using Arena_4MB   = FixedArena< megabytes( 4 ) >; | ||||
|  | ||||
| struct Pool | ||||
| { | ||||
| 	static | ||||
| 	void* allocator_proc( void* allocator_data, AllocType type, sw size, sw alignment, void* old_memory, sw old_size, u64 flags ); | ||||
|  | ||||
| 	static | ||||
| 	Pool init( AllocatorInfo backing, sw num_blocks, sw block_size ) | ||||
| 	{ | ||||
| 		return init_align( backing, num_blocks, block_size, GEN_DEFAULT_MEMORY_ALIGNMENT ); | ||||
| 	} | ||||
|  | ||||
| 	static | ||||
| 	Pool init_align( AllocatorInfo backing, sw num_blocks, sw block_size, sw block_align ); | ||||
|  | ||||
| 	void clear(); | ||||
|  | ||||
| 	void free() | ||||
| 	{ | ||||
| 		if ( Backing.Proc ) | ||||
| 		{ | ||||
| 			gen::free( Backing, PhysicalStart ); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	AllocatorInfo Backing; | ||||
| 	void*         PhysicalStart; | ||||
| 	void*         FreeList; | ||||
| 	sw            BlockSize; | ||||
| 	sw            BlockAlign; | ||||
| 	sw            TotalSize; | ||||
| 	sw            NumBlocks; | ||||
|  | ||||
| 	operator AllocatorInfo() | ||||
| 	{ | ||||
| 		return { allocator_proc, this }; | ||||
| 	} | ||||
| }; | ||||
| GEN_API_C_END | ||||
|  | ||||
| #pragma endregion Memory | ||||
|   | ||||
| @@ -1,8 +1,10 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	pragma once | ||||
| #	include "parsing.hpp" | ||||
| #endif | ||||
|  | ||||
| #pragma region ADT | ||||
| GEN_API_C_BEGIN | ||||
|  | ||||
| #define _adt_fprintf( s_, fmt_, ... )                      \ | ||||
| 	do                                                     \ | ||||
| @@ -23,7 +25,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 +38,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 ( sw i = 0; i < node->nodes.num(); ++i ) | ||||
| 		for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); ++i ) | ||||
| 		{ | ||||
| 			adt_destroy_branch( node->nodes + i ); | ||||
| 		} | ||||
|  | ||||
| 		node->nodes.free(); | ||||
| 		array_free(node->nodes); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| @@ -66,7 +68,7 @@ ADT_Node* adt_find( ADT_Node* node, char const* name, b32 deep_search ) | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	for ( sw i = 0; i < node->nodes.num(); i++ ) | ||||
| 	for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); i++ ) | ||||
| 	{ | ||||
| 		if ( ! str_compare( node->nodes[ i ].name, name ) ) | ||||
| 		{ | ||||
| @@ -76,7 +78,7 @@ ADT_Node* adt_find( ADT_Node* node, char const* name, b32 deep_search ) | ||||
|  | ||||
| 	if ( deep_search ) | ||||
| 	{ | ||||
| 		for ( sw i = 0; i < node->nodes.num(); i++ ) | ||||
| 		for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); i++ ) | ||||
| 		{ | ||||
| 			ADT_Node* res = adt_find( node->nodes + i, name, deep_search ); | ||||
|  | ||||
| @@ -111,7 +113,7 @@ internal ADT_Node* _adt_get_value( ADT_Node* node, char const* value ) | ||||
| 				file_stream_open( &tmp, heap(), ( u8* )back, size_of( back ), EFileStream_WRITABLE ); | ||||
| 				adt_print_number( &tmp, node ); | ||||
|  | ||||
| 				sw  fsize = 0; | ||||
| 				ssize  fsize = 0; | ||||
| 				u8* buf   = file_stream_buf( &tmp, &fsize ); | ||||
|  | ||||
| 				if ( ! str_compare( ( char const* )buf, value ) ) | ||||
| @@ -132,7 +134,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 ( sw i = 0; i < node->nodes.num(); i++ ) | ||||
| 	for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); i++ ) | ||||
| 	{ | ||||
| 		if ( ! str_compare( node->nodes[ i ].name, name ) ) | ||||
| 		{ | ||||
| @@ -207,7 +209,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 ( sw i = 0; i < node->nodes.num(); i++ ) | ||||
| 				for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); i++ ) | ||||
| 				{ | ||||
| 					ADT_Node* child = &node->nodes[ i ]; | ||||
| 					if ( child->type != EADT_TYPE_OBJECT ) | ||||
| @@ -225,7 +227,7 @@ ADT_Node* adt_query( ADT_Node* node, char const* uri ) | ||||
| 		/* [value] */ | ||||
| 		else | ||||
| 		{ | ||||
| 			for ( sw i = 0; i < node->nodes.num(); i++ ) | ||||
| 			for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); i++ ) | ||||
| 			{ | ||||
| 				ADT_Node* child = &node->nodes[ i ]; | ||||
| 				if ( _adt_get_value( child, l_b2 ) ) | ||||
| @@ -256,8 +258,8 @@ ADT_Node* adt_query( ADT_Node* node, char const* uri ) | ||||
| 	/* handle array index lookup */ | ||||
| 	else | ||||
| 	{ | ||||
| 		sw idx = ( sw )str_to_i64( buf, NULL, 10 ); | ||||
| 		if ( idx >= 0 && idx < node->nodes.num() ) | ||||
| 		ssize idx = ( ssize )str_to_i64( buf, NULL, 10 ); | ||||
| 		if ( idx >= 0 && idx < scast(ssize, array_num(node->nodes)) ) | ||||
| 		{ | ||||
| 			found_node = &node->nodes[ idx ]; | ||||
|  | ||||
| @@ -272,7 +274,7 @@ ADT_Node* adt_query( ADT_Node* node, char const* uri ) | ||||
| 	return found_node; | ||||
| } | ||||
|  | ||||
| ADT_Node* adt_alloc_at( ADT_Node* parent, sw index ) | ||||
| ADT_Node* adt_alloc_at( ADT_Node* parent, ssize index ) | ||||
| { | ||||
| 	if ( ! parent || ( parent->type != EADT_TYPE_OBJECT && parent->type != EADT_TYPE_ARRAY ) ) | ||||
| 	{ | ||||
| @@ -282,15 +284,16 @@ ADT_Node* adt_alloc_at( ADT_Node* parent, sw index ) | ||||
| 	if ( ! parent->nodes ) | ||||
| 		return NULL; | ||||
|  | ||||
| 	if ( index < 0 || index > parent->nodes.num() ) | ||||
| 	if ( index < 0 || index > scast(ssize, array_num(parent->nodes)) ) | ||||
| 		return NULL; | ||||
|  | ||||
| 	ADT_Node o = { 0 }; | ||||
| 	o.parent   = parent; | ||||
| 	if ( ! parent->nodes.append_at( o, index ) ) | ||||
| 	if ( ! array_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 +306,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, array_num(parent->nodes) ); | ||||
| } | ||||
|  | ||||
| b8 adt_set_obj( ADT_Node* obj, char const* name, AllocatorInfo backing ) | ||||
| @@ -337,7 +340,7 @@ b8 adt_set_int( ADT_Node* obj, char const* name, s64 value ) | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| ADT_Node* adt_move_node_at( ADT_Node* node, ADT_Node* new_parent, sw index ) | ||||
| ADT_Node* adt_move_node_at( ADT_Node* node, ADT_Node* new_parent, ssize index ) | ||||
| { | ||||
| 	GEN_ASSERT_NOT_NULL( node ); | ||||
| 	GEN_ASSERT_NOT_NULL( new_parent ); | ||||
| @@ -357,7 +360,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, array_num(new_parent->nodes) ); | ||||
| } | ||||
|  | ||||
| void adt_swap_nodes( ADT_Node* node, ADT_Node* other_node ) | ||||
| @@ -366,8 +369,8 @@ void adt_swap_nodes( ADT_Node* node, ADT_Node* other_node ) | ||||
| 	GEN_ASSERT_NOT_NULL( other_node ); | ||||
| 	ADT_Node* parent                     = node->parent; | ||||
| 	ADT_Node* other_parent               = other_node->parent; | ||||
| 	sw        index                      = ( pointer_diff( parent->nodes, node ) / size_of( ADT_Node ) ); | ||||
| 	sw        index2                     = ( pointer_diff( other_parent->nodes, other_node ) / size_of( ADT_Node ) ); | ||||
| 	ssize        index                      = ( pointer_diff( parent->nodes, node ) / size_of( ADT_Node ) ); | ||||
| 	ssize        index2                     = ( pointer_diff( other_parent->nodes, other_node ) / size_of( ADT_Node ) ); | ||||
| 	ADT_Node  temp                       = parent->nodes[ index ]; | ||||
| 	temp.parent                          = other_parent; | ||||
| 	other_parent->nodes[ index2 ].parent = parent; | ||||
| @@ -380,8 +383,8 @@ void adt_remove_node( ADT_Node* node ) | ||||
| 	GEN_ASSERT_NOT_NULL( node ); | ||||
| 	GEN_ASSERT_NOT_NULL( node->parent ); | ||||
| 	ADT_Node* parent = node->parent; | ||||
| 	sw        index  = ( pointer_diff( parent->nodes, node ) / size_of( ADT_Node ) ); | ||||
| 	parent->nodes.remove_at( index ); | ||||
| 	ssize        index  = ( pointer_diff( parent->nodes, node ) / size_of( ADT_Node ) ); | ||||
| 	array_remove_at( parent->nodes, index ); | ||||
| } | ||||
|  | ||||
| ADT_Node* adt_append_obj( ADT_Node* parent, char const* name ) | ||||
| @@ -389,7 +392,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, array_get_header(parent->nodes)->Allocator ) ) | ||||
| 	{ | ||||
| 		adt_remove_node( o ); | ||||
| 		return NULL; | ||||
| @@ -402,7 +405,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 = array_get_header(parent->nodes); | ||||
| 	if ( adt_set_arr( o, name, node_header->Allocator ) ) | ||||
| 	{ | ||||
| 		adt_remove_node( o ); | ||||
| 		return NULL; | ||||
| @@ -447,7 +452,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 +481,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; | ||||
| 	} | ||||
| @@ -484,7 +489,7 @@ char* adt_parse_number( ADT_Node* node, char* base_str ) | ||||
| 	node_type = EADT_TYPE_INTEGER; | ||||
| 	neg_zero  = false; | ||||
|  | ||||
| 	sw   ib        = 0; | ||||
| 	ssize   ib        = 0; | ||||
| 	char buf[ 48 ] = { 0 }; | ||||
|  | ||||
| 	if ( *e == '+' ) | ||||
| @@ -507,7 +512,7 @@ char* adt_parse_number( ADT_Node* node, char* base_str ) | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		if ( ! str_compare( e, "0x", 2 ) || ! str_compare( e, "0X", 2 ) ) | ||||
| 		if ( ! str_compare_len( e, "0x", 2 ) || ! str_compare_len( e, "0X", 2 ) ) | ||||
| 		{ | ||||
| 			node_props = EADT_PROPS_IS_HEX; | ||||
| 		} | ||||
| @@ -550,9 +555,9 @@ char* adt_parse_number( ADT_Node* node, char* base_str ) | ||||
|  | ||||
| 	f32  eb          = 10; | ||||
| 	char expbuf[ 6 ] = { 0 }; | ||||
| 	sw   expi        = 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 ) ) | ||||
| @@ -595,7 +600,7 @@ char* adt_parse_number( ADT_Node* node, char* base_str ) | ||||
|  | ||||
| #ifndef GEN_PARSER_DISABLE_ANALYSIS | ||||
| 		char *q = buf, *base_string = q, *base_string2 = q; | ||||
| 		base_string           = zpl_cast( char* ) str_skip( base_string, '.' ); | ||||
| 		base_string           = ccast( char*, str_skip( base_string, '.' )); | ||||
| 		*base_string          = '\0'; | ||||
| 		base_string2          = base_string + 1; | ||||
| 		char* base_string_off = base_string2; | ||||
| @@ -748,7 +753,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++; | ||||
| @@ -816,13 +821,13 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b | ||||
| 	char* beginChar; | ||||
| 	char* endChar; | ||||
|  | ||||
| 	sw columnIndex       = 0; | ||||
| 	sw totalColumnIndex = 0; | ||||
| 	ssize columnIndex       = 0; | ||||
| 	ssize totalColumnIndex = 0; | ||||
|  | ||||
| 	do | ||||
| 	{ | ||||
| 		char delimiter = 0; | ||||
| 		currentChar = zpl_cast( char* ) str_trim( currentChar, false ); | ||||
| 		currentChar = ccast( char*, str_trim( currentChar, false )); | ||||
|  | ||||
| 		if ( *currentChar == 0 ) | ||||
| 			break; | ||||
| @@ -846,7 +851,7 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b | ||||
| 		#endif | ||||
| 			do | ||||
| 			{ | ||||
| 				endChar = zpl_cast( char* ) str_skip( endChar, '"' ); | ||||
| 				endChar = ccast( char*, str_skip( endChar, '"' )); | ||||
|  | ||||
| 				if ( *endChar && *( endChar + 1 ) == '"' ) | ||||
| 				{ | ||||
| @@ -865,7 +870,7 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b | ||||
| 			} | ||||
|  | ||||
| 			*endChar    = 0; | ||||
| 			currentChar = zpl_cast( char* ) str_trim( endChar + 1, true ); | ||||
| 			currentChar = ccast( char*, str_trim( endChar + 1, true )); | ||||
| 			delimiter   = * currentChar; | ||||
|  | ||||
| 			/* unescape escaped quotes (so that unescaped text escapes :) */ | ||||
| @@ -902,7 +907,7 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b | ||||
|  | ||||
| 			if ( * endChar ) | ||||
| 			{ | ||||
| 				currentChar = zpl_cast( char* ) str_trim( endChar, true ); | ||||
| 				currentChar = ccast( char*, str_trim( endChar, true )); | ||||
|  | ||||
| 				while ( char_is_space( *( endChar - 1 ) ) ) | ||||
| 				{ | ||||
| @@ -946,12 +951,12 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if ( columnIndex >= root->nodes.num() ) | ||||
| 		if ( columnIndex >= scast(ssize, array_num(root->nodes)) ) | ||||
| 		{ | ||||
| 			adt_append_arr( root, NULL ); | ||||
| 		} | ||||
|  | ||||
| 		root->nodes[ columnIndex ].nodes.append( rowItem ); | ||||
| 		array_append( root->nodes[ columnIndex ].nodes, rowItem ); | ||||
|  | ||||
| 		if ( delimiter == delim ) | ||||
| 		{ | ||||
| @@ -979,7 +984,7 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b | ||||
| 	} | ||||
| 	while ( *currentChar ); | ||||
|  | ||||
| 	if ( root->nodes.num() == 0 ) | ||||
| 	if (array_num( root->nodes) == 0 ) | ||||
| 	{ | ||||
| 		GEN_CSV_ASSERT( "unexpected end of input. stream is empty." ); | ||||
| 		error = ECSV_Error__UNEXPECTED_END_OF_INPUT; | ||||
| @@ -989,12 +994,12 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b | ||||
| 	/* consider first row as a header. */ | ||||
| 	if ( has_header ) | ||||
| 	{ | ||||
| 		for ( sw i = 0; i < root->nodes.num(); i++ ) | ||||
| 		for ( ssize i = 0; i < scast(ssize, array_num(root->nodes)); i++ ) | ||||
| 		{ | ||||
| 			CSV_Object* col = root->nodes + i; | ||||
| 			CSV_Object* hdr = col->nodes; | ||||
| 			col->name       = hdr->string; | ||||
| 			col->nodes.remove_at( 0 ); | ||||
| 			array_remove_at(col->nodes, 0 ); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @@ -1057,11 +1062,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 ); | ||||
| 	sw cols = obj->nodes.num(); | ||||
| 	ssize cols = array_num(obj->nodes); | ||||
| 	if ( cols == 0 ) | ||||
| 		return; | ||||
|  | ||||
| 	sw rows = obj->nodes[ 0 ].nodes.num(); | ||||
| 	ssize rows = array_num(obj->nodes[ 0 ].nodes); | ||||
| 	if ( rows == 0 ) | ||||
| 		return; | ||||
|  | ||||
| @@ -1069,7 +1074,7 @@ void csv_write_delimiter( FileInfo* file, CSV_Object* obj, char delimiter ) | ||||
|  | ||||
| 	if ( has_headers ) | ||||
| 	{ | ||||
| 		for ( sw i = 0; i < cols; i++ ) | ||||
| 		for ( ssize i = 0; i < cols; i++ ) | ||||
| 		{ | ||||
| 			_csv_write_header( file, &obj->nodes[ i ] ); | ||||
| 			if ( i + 1 != cols ) | ||||
| @@ -1080,9 +1085,9 @@ void csv_write_delimiter( FileInfo* file, CSV_Object* obj, char delimiter ) | ||||
| 		str_fmt_file( file, "\n" ); | ||||
| 	} | ||||
|  | ||||
| 	for ( sw r = 0; r < rows; r++ ) | ||||
| 	for ( ssize r = 0; r < rows; r++ ) | ||||
| 	{ | ||||
| 		for ( sw i = 0; i < cols; i++ ) | ||||
| 		for ( ssize i = 0; i < cols; i++ ) | ||||
| 		{ | ||||
| 			_csv_write_record( file, &obj->nodes[ i ].nodes[ r ] ); | ||||
| 			if ( i + 1 != cols ) | ||||
| @@ -1099,12 +1104,13 @@ 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 ); | ||||
| 	sw     fsize; | ||||
|  | ||||
| 	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; | ||||
| } | ||||
|  | ||||
| GEN_API_C_END | ||||
| #pragma endregion CSV | ||||
|  | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
| #endif | ||||
|  | ||||
| #pragma region ADT | ||||
| GEN_API_C_BEGIN | ||||
|  | ||||
| enum ADT_Type : u32 | ||||
| { | ||||
| @@ -83,7 +84,7 @@ struct ADT_Node | ||||
| 	union | ||||
| 	{ | ||||
| 		char const*     string; | ||||
| 		Array<ADT_Node> nodes;    ///< zpl_array | ||||
| 		Array(ADT_Node) nodes;    ///< zpl_array | ||||
|  | ||||
| 		struct | ||||
| 		{ | ||||
| @@ -178,7 +179,7 @@ ADT_Node* adt_find( ADT_Node* node, char const* name, b32 deep_search ); | ||||
| 	* @param index | ||||
| 	* @return zpl_adt_node * node | ||||
| 	*/ | ||||
| ADT_Node* adt_alloc_at( ADT_Node* parent, sw index ); | ||||
| ADT_Node* adt_alloc_at( ADT_Node* parent, ssize index ); | ||||
|  | ||||
| /** | ||||
| 	* @brief Allocate an unitialised node within a container. | ||||
| @@ -196,7 +197,7 @@ ADT_Node* adt_alloc( ADT_Node* parent ); | ||||
| 	* @param index | ||||
| 	* @return zpl_adt_node * node | ||||
| 	*/ | ||||
| ADT_Node* adt_move_node_at( ADT_Node* node, ADT_Node* new_parent, sw index ); | ||||
| ADT_Node* adt_move_node_at( ADT_Node* node, ADT_Node* new_parent, ssize index ); | ||||
|  | ||||
| /** | ||||
| 	* @brief Move an existing node to a new container. | ||||
| @@ -400,31 +401,34 @@ enum CSV_Error : u32 | ||||
|  | ||||
| typedef ADT_Node CSV_Object; | ||||
|  | ||||
| GEN_DEF_INLINE u8 csv_parse( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header ); | ||||
| u8   csv_parse( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header ); | ||||
| u8   csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header, char delim ); | ||||
| void csv_free( CSV_Object* obj ); | ||||
|  | ||||
| GEN_DEF_INLINE void   csv_write( FileInfo* file, CSV_Object* obj ); | ||||
| GEN_DEF_INLINE String csv_write_string( AllocatorInfo a, CSV_Object* obj ); | ||||
| void   csv_write( FileInfo* file, CSV_Object* obj ); | ||||
| String csv_write_string( AllocatorInfo a, CSV_Object* obj ); | ||||
| void   csv_write_delimiter( FileInfo* file, CSV_Object* obj, char delim ); | ||||
| String csv_write_string_delimiter( AllocatorInfo a, CSV_Object* obj, char delim ); | ||||
|  | ||||
| /* inline */ | ||||
|  | ||||
| GEN_IMPL_INLINE u8 csv_parse( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header ) | ||||
| inline | ||||
| u8 csv_parse( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header ) | ||||
| { | ||||
| 	return csv_parse_delimiter( root, text, allocator, has_header, ',' ); | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE void csv_write( FileInfo* file, CSV_Object* obj ) | ||||
| inline | ||||
| void csv_write( FileInfo* file, CSV_Object* obj ) | ||||
| { | ||||
| 	csv_write_delimiter( file, obj, ',' ); | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE String csv_write_string( AllocatorInfo a, CSV_Object* obj ) | ||||
| inline | ||||
| String csv_write_string( AllocatorInfo a, CSV_Object* obj ) | ||||
| { | ||||
| 	return csv_write_string_delimiter( a, obj, ',' ); | ||||
| } | ||||
|  | ||||
| GEN_API_C_END | ||||
| #pragma endregion CSV | ||||
|  | ||||
|   | ||||
| @@ -1,4 +1,6 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	pragma once | ||||
| #endif | ||||
| 
 | ||||
| #pragma region Platform Detection | ||||
| 
 | ||||
| @@ -74,13 +76,18 @@ | ||||
| /* Platform compiler */ | ||||
| 
 | ||||
| #if defined( _MSC_VER ) | ||||
| #	define GEN_COMPILER_CLANG 0 | ||||
| #	define GEN_COMPILER_MSVC  1 | ||||
| #	define GEN_COMPILER_GCC   0 | ||||
| #elif defined( __GNUC__ ) | ||||
| #	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 | ||||
| 
 | ||||
| @@ -99,8 +106,25 @@ | ||||
| #  define GEN_GCC_VERSION_CHECK(major,minor,patch) (0) | ||||
| #endif | ||||
| 
 | ||||
| #define GEN_DEF_INLINE  static | ||||
| #define GEN_IMPL_INLINE static inline | ||||
| #if !defined(GEN_COMPILER_C) | ||||
| #	ifdef __cplusplus | ||||
| #		define GEN_COMPILER_C   0 | ||||
| #		define GEN_COMPILER_CPP 1 | ||||
| #	else | ||||
| #		if defined(__STDC__) | ||||
| #			define GEN_COMPILER_C   1 | ||||
| #		    define GEN_COMPILER_CPP 0 | ||||
| #		else | ||||
|             // Fallback for very old C compilers
 | ||||
| #			define GEN_COMPILER_C   1 | ||||
| #		    define GEN_COMPILER_CPP 0 | ||||
| #		endif | ||||
| #   endif | ||||
| #endif | ||||
| 
 | ||||
| #if GEN_COMPILER_C | ||||
| #pragma message("Detected C") | ||||
| #endif | ||||
| 
 | ||||
| #pragma endregion Platform Detection | ||||
| 
 | ||||
| @@ -113,13 +137,36 @@ | ||||
| #		include <intrin.h> | ||||
| #	endif | ||||
| 
 | ||||
| #if GEN_COMPILER_C | ||||
| #include <assert.h> | ||||
| #include <stdbool.h> | ||||
| #endif | ||||
| 
 | ||||
| #pragma endregion Mandatory Includes | ||||
| 
 | ||||
| #ifdef GEN_DONT_USE_NAMESPACE | ||||
| #if GEN_DONT_USE_NAMESPACE || GEN_COMPILER_C | ||||
| #	if GEN_COMPILER_C | ||||
| #		define GEN_NS_PARSER_BEGIN | ||||
| #		define GEN_NS_PARSER_END | ||||
| #		define GEN_USING_NS_PARSER | ||||
| #		define GEN_NS_PARSER | ||||
| #		define GEN_NS | ||||
| #		define GEN_NS_BEGIN | ||||
| #		define GEN_NS_END | ||||
| #	else | ||||
| #		define GEN_NS_PARSER_BEGIN namespace parser { | ||||
| #		define GEN_NS_PARSER_END   } | ||||
| #		define GEN_USING_NS_PARSER using namespace parser | ||||
| #		define GEN_NS_PARSER       parser:: | ||||
| #		define GEN_NS              :: | ||||
| #		define GEN_NS_BEGIN | ||||
| #		define GEN_NS_END | ||||
| #	endif | ||||
| #else | ||||
| #	define GEN_NS_PARSER_BEGIN namespace parser { | ||||
| #	define GEN_NS_PARSER_END   } | ||||
| #	define GEN_NS_PARSER       parser:: | ||||
| #	define GEN_USING_NS_PARSER using namespace parser | ||||
| #	define GEN_NS              gen:: | ||||
| #	define GEN_NS_BEGIN        namespace gen { | ||||
| #	define GEN_NS_END          } | ||||
| @@ -6,6 +6,7 @@ | ||||
| #endif | ||||
|  | ||||
| #pragma region Printing | ||||
| GEN_API_C_BEGIN | ||||
|  | ||||
| enum | ||||
| { | ||||
| @@ -41,10 +42,10 @@ struct _format_info | ||||
| 	s32 precision; | ||||
| }; | ||||
|  | ||||
| internal sw _print_string( char* text, sw max_len, _format_info* info, char const* str ) | ||||
| internal ssize _print_string( char* text, ssize max_len, _format_info* info, char const* str ) | ||||
| { | ||||
| 	sw    res = 0, len = 0; | ||||
| 	sw    remaining = max_len; | ||||
| 	ssize res = 0, len = 0; | ||||
| 	ssize remaining = max_len; | ||||
| 	char* begin     = text; | ||||
|  | ||||
| 	if ( str == NULL && max_len >= 6 ) | ||||
| @@ -75,7 +76,7 @@ internal sw _print_string( char* text, sw max_len, _format_info* info, char cons | ||||
|  | ||||
| 		if ( info->width > res ) | ||||
| 		{ | ||||
| 			sw padding = info->width - len; | ||||
| 			ssize padding = info->width - len; | ||||
|  | ||||
| 			char pad = ( info->flags & GEN_FMT_ZERO ) ? '0' : ' '; | ||||
| 			while ( padding-- > 0 && remaining-- > 0 ) | ||||
| @@ -86,7 +87,7 @@ internal sw _print_string( char* text, sw max_len, _format_info* info, char cons | ||||
| 	{ | ||||
| 		if ( info && ( info->width > res ) ) | ||||
| 		{ | ||||
| 			sw   padding = info->width - len; | ||||
| 			ssize   padding = info->width - len; | ||||
| 			char pad     = ( info->flags & GEN_FMT_ZERO ) ? '0' : ' '; | ||||
| 			while ( padding-- > 0 && remaining-- > 0 ) | ||||
| 				*text++ = pad, res++; | ||||
| @@ -108,16 +109,16 @@ internal sw _print_string( char* text, sw max_len, _format_info* info, char cons | ||||
| 	return res; | ||||
| } | ||||
|  | ||||
| internal sw _print_char( char* text, sw max_len, _format_info* info, char arg ) | ||||
| internal ssize _print_char( char* text, ssize max_len, _format_info* info, char arg ) | ||||
| { | ||||
| 	char str[ 2 ] = ""; | ||||
| 	str[ 0 ]      = arg; | ||||
| 	return _print_string( text, max_len, info, str ); | ||||
| } | ||||
|  | ||||
| internal sw _print_repeated_char( char* text, sw max_len, _format_info* info, char arg ) | ||||
| internal ssize _print_repeated_char( char* text, ssize max_len, _format_info* info, char arg ) | ||||
| { | ||||
| 	sw  res = 0; | ||||
| 	ssize  res = 0; | ||||
| 	s32 rem = ( info ) ? ( info->width > 0 ) ? info->width : 1 : 1; | ||||
| 	res     = rem; | ||||
| 	while ( rem-- > 0 ) | ||||
| @@ -126,24 +127,24 @@ internal sw _print_repeated_char( char* text, sw max_len, _format_info* info, ch | ||||
| 	return res; | ||||
| } | ||||
|  | ||||
| internal sw _print_i64( char* text, sw max_len, _format_info* info, s64 value ) | ||||
| internal ssize _print_i64( char* text, ssize max_len, _format_info* info, s64 value ) | ||||
| { | ||||
| 	char num[ 130 ]; | ||||
| 	i64_to_str( value, num, info ? info->base : 10 ); | ||||
| 	return _print_string( text, max_len, info, num ); | ||||
| } | ||||
|  | ||||
| internal sw _print_u64( char* text, sw max_len, _format_info* info, u64 value ) | ||||
| internal ssize _print_u64( char* text, ssize max_len, _format_info* info, u64 value ) | ||||
| { | ||||
| 	char num[ 130 ]; | ||||
| 	u64_to_str( value, num, info ? info->base : 10 ); | ||||
| 	return _print_string( text, max_len, info, num ); | ||||
| } | ||||
|  | ||||
| internal sw _print_f64( char* text, sw max_len, _format_info* info, b32 is_hexadecimal, f64 arg ) | ||||
| internal ssize _print_f64( char* text, ssize max_len, _format_info* info, b32 is_hexadecimal, f64 arg ) | ||||
| { | ||||
| 	// TODO: Handle exponent notation | ||||
| 	sw    width, len, remaining = max_len; | ||||
| 	ssize    width, len, remaining = max_len; | ||||
| 	char* text_begin = text; | ||||
|  | ||||
| 	if ( arg ) | ||||
| @@ -163,7 +164,7 @@ internal sw _print_f64( char* text, sw max_len, _format_info* info, b32 is_hexad | ||||
| 			text++; | ||||
| 		} | ||||
|  | ||||
| 		value  = zpl_cast( u64 ) arg; | ||||
| 		value  = scast( u64, arg); | ||||
| 		len    = _print_u64( text, remaining, NULL, value ); | ||||
| 		text  += len; | ||||
|  | ||||
| @@ -184,14 +185,14 @@ internal sw _print_f64( char* text, sw max_len, _format_info* info, b32 is_hexad | ||||
| 			text++; | ||||
| 			while ( info->precision-- > 0 ) | ||||
| 			{ | ||||
| 				value  = zpl_cast( u64 )( arg * mult ); | ||||
| 				value  = scast( u64, arg * mult ); | ||||
| 				len    = _print_u64( text, remaining, NULL, value ); | ||||
| 				text  += len; | ||||
| 				if ( len >= remaining ) | ||||
| 					remaining = min( remaining, 1 ); | ||||
| 				else | ||||
| 					remaining -= len; | ||||
| 				arg  -= zpl_cast( f64 ) value / mult; | ||||
| 				arg  -= scast( f64, value / mult); | ||||
| 				mult *= 10; | ||||
| 			} | ||||
| 		} | ||||
| @@ -239,15 +240,15 @@ internal sw _print_f64( char* text, sw max_len, _format_info* info, b32 is_hexad | ||||
| 	return ( text - text_begin ); | ||||
| } | ||||
|  | ||||
| neverinline sw str_fmt_va( char* text, sw max_len, char const* fmt, va_list va ) | ||||
| neverinline ssize str_fmt_va( char* text, ssize max_len, char const* fmt, va_list va ) | ||||
| { | ||||
| 	char const* text_begin = text; | ||||
| 	sw          remaining  = max_len, res; | ||||
| 	ssize          remaining  = max_len, res; | ||||
|  | ||||
| 	while ( *fmt ) | ||||
| 	{ | ||||
| 		_format_info info = { 0 }; | ||||
| 		sw           len  = 0; | ||||
| 		ssize        len  = 0; | ||||
| 		info.precision    = -1; | ||||
|  | ||||
| 		while ( *fmt && *fmt != '%' && remaining ) | ||||
| @@ -311,7 +312,7 @@ neverinline sw str_fmt_va( char* text, sw max_len, char const* fmt, va_list va ) | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			info.width = zpl_cast( s32 ) str_to_i64( fmt, zpl_cast( char** ) & fmt, 10 ); | ||||
| 			info.width = scast( s32, str_to_i64( fmt, ccast( char**, & fmt), 10 )); | ||||
| 			if ( info.width != 0 ) | ||||
| 			{ | ||||
| 				info.flags |= GEN_FMT_WIDTH; | ||||
| @@ -329,7 +330,7 @@ neverinline sw str_fmt_va( char* text, sw max_len, char const* fmt, va_list va ) | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				info.precision = zpl_cast( s32 ) str_to_i64( fmt, zpl_cast( char** ) & fmt, 10 ); | ||||
| 				info.precision = scast( s32, str_to_i64( fmt, ccast( char**, & fmt), 10 )); | ||||
| 			} | ||||
| 			info.flags &= ~GEN_FMT_ZERO; | ||||
| 		} | ||||
| @@ -411,7 +412,7 @@ neverinline sw str_fmt_va( char* text, sw max_len, char const* fmt, va_list va ) | ||||
| 				break; | ||||
|  | ||||
| 			case 'c' : | ||||
| 				len = _print_char( text, remaining, &info, zpl_cast( char ) va_arg( va, int ) ); | ||||
| 				len = _print_char( text, remaining, &info, scast( char, va_arg( va, int ) )); | ||||
| 				break; | ||||
|  | ||||
| 			case 's' : | ||||
| @@ -420,9 +421,18 @@ neverinline sw str_fmt_va( char* text, sw max_len, char const* fmt, va_list va ) | ||||
|  | ||||
| 			case 'S': | ||||
| 			{ | ||||
| 				if ( *(fmt + 1) == 'C' ) | ||||
| 				{ | ||||
| 					++ fmt; | ||||
| 					StrC gen_str   = va_arg( va, StrC); | ||||
| 					info.precision = gen_str.Len; | ||||
| 					len            = _print_string( text, remaining, &info, gen_str.Ptr ); | ||||
| 					break; | ||||
| 				} | ||||
|  | ||||
| 				String gen_str = String { va_arg( va, char*) }; | ||||
|  | ||||
| 				info.precision = gen_str.length(); | ||||
| 				info.precision = string_length(gen_str); | ||||
| 				len            = _print_string( text, remaining, &info, gen_str ); | ||||
| 			} | ||||
| 			break; | ||||
| @@ -455,25 +465,25 @@ neverinline sw str_fmt_va( char* text, sw max_len, char const* fmt, va_list va ) | ||||
| 				switch ( info.flags & GEN_FMT_INTS ) | ||||
| 				{ | ||||
| 					case GEN_FMT_CHAR : | ||||
| 						value = zpl_cast( u64 ) zpl_cast( u8 ) va_arg( va, int ); | ||||
| 						value = scast( u64, scast( u8, va_arg( va, int ))); | ||||
| 						break; | ||||
| 					case GEN_FMT_SHORT : | ||||
| 						value = zpl_cast( u64 ) zpl_cast( u16 ) va_arg( va, int ); | ||||
| 						value = scast( u64, scast( u16, va_arg( va, int ))); | ||||
| 						break; | ||||
| 					case GEN_FMT_LONG: | ||||
| 						value = zpl_cast( u64 ) va_arg( va, unsigned long ); | ||||
| 						value = scast( u64, va_arg( va, unsigned long )); | ||||
| 						break; | ||||
| 					case GEN_FMT_LLONG : | ||||
| 						value = zpl_cast( u64 ) va_arg( va, unsigned long long ); | ||||
| 						value = scast( u64, va_arg( va, unsigned long long )); | ||||
| 						break; | ||||
| 					case GEN_FMT_SIZE : | ||||
| 						value = zpl_cast( u64 ) va_arg( va, uw ); | ||||
| 						value = scast( u64, va_arg( va, usize )); | ||||
| 						break; | ||||
| 					case GEN_FMT_INTPTR : | ||||
| 						value = zpl_cast( u64 ) va_arg( va, uptr ); | ||||
| 						value = scast( u64, va_arg( va, uptr )); | ||||
| 						break; | ||||
| 					default : | ||||
| 						value = zpl_cast( u64 ) va_arg( va, unsigned int ); | ||||
| 						value = scast( u64, va_arg( va, unsigned int )); | ||||
| 						break; | ||||
| 				} | ||||
|  | ||||
| @@ -485,25 +495,25 @@ neverinline sw str_fmt_va( char* text, sw max_len, char const* fmt, va_list va ) | ||||
| 				switch ( info.flags & GEN_FMT_INTS ) | ||||
| 				{ | ||||
| 					case GEN_FMT_CHAR : | ||||
| 						value = zpl_cast( s64 ) zpl_cast( s8 ) va_arg( va, int ); | ||||
| 						value = scast( s64, scast( s8, va_arg( va, int ))); | ||||
| 						break; | ||||
| 					case GEN_FMT_SHORT : | ||||
| 						value = zpl_cast( s64 ) zpl_cast( s16 ) va_arg( va, int ); | ||||
| 						value = scast( s64, scast( s16, va_arg( va, int ))); | ||||
| 						break; | ||||
| 					case GEN_FMT_LONG : | ||||
| 						value = zpl_cast( s64 ) va_arg( va, long ); | ||||
| 						value = scast( s64, va_arg( va, long )); | ||||
| 						break; | ||||
| 					case GEN_FMT_LLONG : | ||||
| 						value = zpl_cast( s64 ) va_arg( va, long long ); | ||||
| 						value = scast( s64, va_arg( va, long long )); | ||||
| 						break; | ||||
| 					case GEN_FMT_SIZE : | ||||
| 						value = zpl_cast( s64 ) va_arg( va, uw ); | ||||
| 						value = scast( s64, va_arg( va, usize )); | ||||
| 						break; | ||||
| 					case GEN_FMT_INTPTR : | ||||
| 						value = zpl_cast( s64 ) va_arg( va, uptr ); | ||||
| 						value = scast( s64, va_arg( va, uptr )); | ||||
| 						break; | ||||
| 					default : | ||||
| 						value = zpl_cast( s64 ) va_arg( va, int ); | ||||
| 						value = scast( s64, va_arg( va, int )); | ||||
| 						break; | ||||
| 				} | ||||
|  | ||||
| @@ -540,17 +550,17 @@ char* str_fmt_buf( char const* fmt, ... ) | ||||
| 	return str; | ||||
| } | ||||
|  | ||||
| sw str_fmt_file_va( struct FileInfo* f, char const* fmt, va_list va ) | ||||
| ssize str_fmt_file_va( FileInfo* f, char const* fmt, va_list va ) | ||||
| { | ||||
| 	local_persist thread_local char buf[ GEN_PRINTF_MAXLEN ]; | ||||
| 	sw                              len = str_fmt_va( buf, size_of( buf ), fmt, va ); | ||||
| 	ssize                              len = str_fmt_va( buf, size_of( buf ), fmt, va ); | ||||
| 	b32                             res = file_write( f, buf, len - 1 );    // NOTE: prevent extra whitespace | ||||
| 	return res ? len : -1; | ||||
| } | ||||
|  | ||||
| sw str_fmt_file( struct FileInfo* f, char const* fmt, ... ) | ||||
| ssize str_fmt_file( FileInfo* f, char const* fmt, ... ) | ||||
| { | ||||
| 	sw      res; | ||||
| 	ssize      res; | ||||
| 	va_list va; | ||||
| 	va_start( va, fmt ); | ||||
| 	res = str_fmt_file_va( f, fmt, va ); | ||||
| @@ -558,9 +568,9 @@ sw str_fmt_file( struct FileInfo* f, char const* fmt, ... ) | ||||
| 	return res; | ||||
| } | ||||
|  | ||||
| sw str_fmt( char* str, sw n, char const* fmt, ... ) | ||||
| ssize str_fmt( char* str, ssize n, char const* fmt, ... ) | ||||
| { | ||||
| 	sw      res; | ||||
| 	ssize      res; | ||||
| 	va_list va; | ||||
| 	va_start( va, fmt ); | ||||
| 	res = str_fmt_va( str, n, fmt, va ); | ||||
| @@ -568,19 +578,19 @@ sw str_fmt( char* str, sw n, char const* fmt, ... ) | ||||
| 	return res; | ||||
| } | ||||
|  | ||||
| sw str_fmt_out_va( char const* fmt, va_list va ) | ||||
| ssize str_fmt_out_va( char const* fmt, va_list va ) | ||||
| { | ||||
| 	return str_fmt_file_va( file_get_standard( EFileStandard_OUTPUT ), fmt, va ); | ||||
| } | ||||
|  | ||||
| sw str_fmt_out_err_va( char const* fmt, va_list va ) | ||||
| ssize str_fmt_out_err_va( char const* fmt, va_list va ) | ||||
| { | ||||
| 	return str_fmt_file_va( file_get_standard( EFileStandard_ERROR ), fmt, va ); | ||||
| } | ||||
|  | ||||
| sw str_fmt_out_err( char const* fmt, ... ) | ||||
| ssize str_fmt_out_err( char const* fmt, ... ) | ||||
| { | ||||
| 	sw      res; | ||||
| 	ssize      res; | ||||
| 	va_list va; | ||||
| 	va_start( va, fmt ); | ||||
| 	res = str_fmt_out_err_va( fmt, va ); | ||||
| @@ -588,4 +598,5 @@ sw str_fmt_out_err( char const* fmt, ... ) | ||||
| 	return res; | ||||
| } | ||||
|  | ||||
| GEN_API_C_END | ||||
| #pragma endregion Printing | ||||
|   | ||||
| @@ -5,30 +5,33 @@ | ||||
|  | ||||
| #pragma region Printing | ||||
|  | ||||
| struct FileInfo; | ||||
| GEN_API_C_BEGIN | ||||
|  | ||||
| typedef struct FileInfo_Def FileInfo; | ||||
|  | ||||
| #ifndef GEN_PRINTF_MAXLEN | ||||
| #	define GEN_PRINTF_MAXLEN kilobytes(128) | ||||
| #endif | ||||
| typedef char PrintF_Buffer[GEN_PRINTF_MAXLEN]; | ||||
|  | ||||
| // NOTE: A locally persisting buffer is used internally | ||||
| char*  str_fmt_buf       ( char const* fmt, ... ); | ||||
| char*  str_fmt_buf_va    ( char const* fmt, va_list va ); | ||||
| sw    str_fmt           ( char* str, sw n, char const* fmt, ... ); | ||||
| sw    str_fmt_va        ( char* str, sw n, char const* fmt, va_list va ); | ||||
| sw    str_fmt_out_va    ( char const* fmt, va_list va ); | ||||
| sw    str_fmt_out_err   ( char const* fmt, ... ); | ||||
| sw    str_fmt_out_err_va( char const* fmt, va_list va ); | ||||
| sw    str_fmt_file      ( FileInfo* f, char const* fmt, ... ); | ||||
| sw    str_fmt_file_va   ( FileInfo* f, char const* fmt, va_list va ); | ||||
| ssize  str_fmt           ( char* str, ssize n, char const* fmt, ... ); | ||||
| ssize  str_fmt_va        ( char* str, ssize n, char const* fmt, va_list va ); | ||||
| ssize  str_fmt_out_va    ( char const* fmt, va_list va ); | ||||
| ssize  str_fmt_out_err   ( char const* fmt, ... ); | ||||
| ssize  str_fmt_out_err_va( char const* fmt, va_list va ); | ||||
| ssize  str_fmt_file      ( FileInfo* f, char const* fmt, ... ); | ||||
| ssize  str_fmt_file_va   ( FileInfo* f, char const* fmt, va_list va ); | ||||
|  | ||||
| constexpr | ||||
| char const* Msg_Invalid_Value = "INVALID VALUE PROVIDED"; | ||||
|  | ||||
| inline | ||||
| sw log_fmt(char const* fmt, ...) | ||||
| ssize log_fmt(char const* fmt, ...) | ||||
| { | ||||
| 	sw res; | ||||
| 	ssize res; | ||||
| 	va_list va; | ||||
|  | ||||
| 	va_start(va, fmt); | ||||
| @@ -38,4 +41,6 @@ sw log_fmt(char const* fmt, ...) | ||||
| 	return res; | ||||
| } | ||||
|  | ||||
| GEN_API_C_END | ||||
|  | ||||
| #pragma endregion Printing | ||||
|   | ||||
| @@ -5,9 +5,10 @@ | ||||
| #endif | ||||
|  | ||||
| #pragma region String Ops | ||||
| GEN_API_C_BEGIN | ||||
|  | ||||
| internal | ||||
| sw _scan_zpl_i64( const char* text, s32 base, s64* value ) | ||||
| ssize _scan_zpl_i64( const char* text, s32 base, s64* value ) | ||||
| { | ||||
| 	const char* text_begin = text; | ||||
| 	s64         result     = 0; | ||||
| @@ -19,7 +20,7 @@ sw _scan_zpl_i64( const char* text, s32 base, s64* value ) | ||||
| 		text++; | ||||
| 	} | ||||
|  | ||||
| 	if ( base == 16 && str_compare( text, "0x", 2 ) == 0 ) | ||||
| 	if ( base == 16 && str_compare_len( text, "0x", 2 ) == 0 ) | ||||
| 		text += 2; | ||||
|  | ||||
| 	for ( ;; ) | ||||
| @@ -56,12 +57,12 @@ global const char _num_to_char_table[] = | ||||
|  | ||||
| s64 str_to_i64( const char* str, char** end_ptr, s32 base ) | ||||
| { | ||||
| 	sw  len; | ||||
| 	ssize  len; | ||||
| 	s64 value; | ||||
|  | ||||
| 	if ( ! base ) | ||||
| 	{ | ||||
| 		if ( ( str_len( str ) > 2 ) && ( str_compare( str, "0x", 2 ) == 0 ) ) | ||||
| 		if ( ( str_len( str ) > 2 ) && ( str_compare_len( str, "0x", 2 ) == 0 ) ) | ||||
| 			base = 16; | ||||
| 		else | ||||
| 			base = 10; | ||||
| @@ -85,7 +86,7 @@ void i64_to_str( s64 value, char* string, s32 base ) | ||||
| 		value    = -value; | ||||
| 	} | ||||
|  | ||||
| 	v = zpl_cast( u64 ) value; | ||||
| 	v = scast( u64, value); | ||||
| 	if ( v != 0 ) | ||||
| 	{ | ||||
| 		while ( v > 0 ) | ||||
| @@ -207,9 +208,10 @@ f64 str_to_f64( const char* str, char** end_ptr ) | ||||
| 	result = sign * ( frac ? ( value / scale ) : ( value * scale ) ); | ||||
|  | ||||
| 	if ( end_ptr ) | ||||
| 		*end_ptr = zpl_cast( char* ) str; | ||||
| 		* end_ptr = rcast( char*, ccast(char*, str) ); | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| GEN_API_C_END | ||||
| #pragma endregion String Ops | ||||
|   | ||||
| @@ -5,41 +5,43 @@ | ||||
|  | ||||
| #pragma region String Ops | ||||
|  | ||||
| GEN_DEF_INLINE const char* char_first_occurence( const char* str, char c ); | ||||
| constexpr auto str_find = &char_first_occurence; | ||||
| GEN_API_C_BEGIN | ||||
|  | ||||
| GEN_DEF_INLINE b32   char_is_alpha( char c ); | ||||
| GEN_DEF_INLINE b32   char_is_alphanumeric( char c ); | ||||
| GEN_DEF_INLINE b32   char_is_digit( char c ); | ||||
| GEN_DEF_INLINE b32   char_is_hex_digit( char c ); | ||||
| GEN_DEF_INLINE b32   char_is_space( char c ); | ||||
| GEN_DEF_INLINE char  char_to_lower( char c ); | ||||
| GEN_DEF_INLINE char  char_to_upper( char c ); | ||||
| const char* char_first_occurence( const char* str, char c ); | ||||
|  | ||||
| GEN_DEF_INLINE s32  digit_to_int( char c ); | ||||
| GEN_DEF_INLINE s32  hex_digit_to_int( char c ); | ||||
| b32   char_is_alpha( char c ); | ||||
| b32   char_is_alphanumeric( char c ); | ||||
| b32   char_is_digit( char c ); | ||||
| b32   char_is_hex_digit( char c ); | ||||
| b32   char_is_space( char c ); | ||||
| char  char_to_lower( char c ); | ||||
| char  char_to_upper( char c ); | ||||
|  | ||||
| GEN_DEF_INLINE s32         str_compare( const char* s1, const char* s2 ); | ||||
| GEN_DEF_INLINE s32         str_compare( const char* s1, const char* s2, sw len ); | ||||
| GEN_DEF_INLINE char*       str_copy( char* dest, const char* source, sw len ); | ||||
| GEN_DEF_INLINE sw          str_copy_nulpad( char* dest, const char* source, sw len ); | ||||
| GEN_DEF_INLINE sw          str_len( const char* str ); | ||||
| GEN_DEF_INLINE sw          str_len( const char* str, sw max_len ); | ||||
| GEN_DEF_INLINE char*       str_reverse( char* str );    // NOTE: ASCII only | ||||
| GEN_DEF_INLINE char const* str_skip( char const* str, char c ); | ||||
| GEN_DEF_INLINE char const* str_skip_any( char const* str, char const* char_list ); | ||||
| GEN_DEF_INLINE char const* str_trim( char const* str, b32 catch_newline ); | ||||
| s32  digit_to_int( char c ); | ||||
| s32  hex_digit_to_int( char c ); | ||||
|  | ||||
| s32         str_compare( const char* s1, const char* s2 ); | ||||
| s32         str_compare_len( const char* s1, const char* s2, ssize len ); | ||||
| char*       str_copy( char* dest, const char* source, ssize len ); | ||||
| ssize       str_copy_nulpad( char* dest, const char* source, ssize len ); | ||||
| ssize       str_len( const char* str ); | ||||
| ssize       str_len_capped( const char* str, ssize max_len ); | ||||
| char*       str_reverse( char* str );    // NOTE: ASCII only | ||||
| char const* str_skip( char const* str, char c ); | ||||
| char const* str_skip_any( char const* str, char const* char_list ); | ||||
| char const* str_trim( char const* str, b32 catch_newline ); | ||||
|  | ||||
| // NOTE: ASCII only | ||||
| GEN_DEF_INLINE void str_to_lower( char* str ); | ||||
| GEN_DEF_INLINE void str_to_upper( char* str ); | ||||
| void str_to_lower( char* str ); | ||||
| void str_to_upper( char* str ); | ||||
|  | ||||
| s64  str_to_i64( const char* str, char** end_ptr, s32 base ); | ||||
| void i64_to_str( s64 value, char* string, s32 base ); | ||||
| void u64_to_str( u64 value, char* string, s32 base ); | ||||
| f64  str_to_f64( const char* str, char** end_ptr ); | ||||
|  | ||||
| GEN_IMPL_INLINE const char* char_first_occurence( const char* s, char c ) | ||||
| inline | ||||
| const char* char_first_occurence( const char* s, char c ) | ||||
| { | ||||
| 	char ch = c; | ||||
| 	for ( ; *s != ch; s++ ) | ||||
| @@ -50,59 +52,67 @@ GEN_IMPL_INLINE const char* char_first_occurence( const char* s, char c ) | ||||
| 	return s; | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE b32 char_is_alpha( char c ) | ||||
| inline | ||||
| b32 char_is_alpha( char c ) | ||||
| { | ||||
| 	if ( ( c >= 'A' && c <= 'Z' ) || ( c >= 'a' && c <= 'z' ) ) | ||||
| 		return true; | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE b32 char_is_alphanumeric( char c ) | ||||
| inline | ||||
| b32 char_is_alphanumeric( char c ) | ||||
| { | ||||
| 	return char_is_alpha( c ) || char_is_digit( c ); | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE b32 char_is_digit( char c ) | ||||
| inline | ||||
| b32 char_is_digit( char c ) | ||||
| { | ||||
| 	if ( c >= '0' && c <= '9' ) | ||||
| 		return true; | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE b32 char_is_hex_digit( char c ) | ||||
| inline | ||||
| b32 char_is_hex_digit( char c ) | ||||
| { | ||||
| 	if ( char_is_digit( c ) || ( c >= 'a' && c <= 'f' ) || ( c >= 'A' && c <= 'F' ) ) | ||||
| 		return true; | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE b32 char_is_space( char c ) | ||||
| inline | ||||
| b32 char_is_space( char c ) | ||||
| { | ||||
| 	if ( c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v' ) | ||||
| 		return true; | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE char char_to_lower( char c ) | ||||
| inline | ||||
| char char_to_lower( char c ) | ||||
| { | ||||
| 	if ( c >= 'A' && c <= 'Z' ) | ||||
| 		return 'a' + ( c - 'A' ); | ||||
| 	return c; | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE char char_to_upper( char c ) | ||||
| inline char char_to_upper( char c ) | ||||
| { | ||||
| 	if ( c >= 'a' && c <= 'z' ) | ||||
| 		return 'A' + ( c - 'a' ); | ||||
| 	return c; | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE s32 digit_to_int( char c ) | ||||
| inline | ||||
| s32 digit_to_int( char c ) | ||||
| { | ||||
| 	return char_is_digit( c ) ? c - '0' : c - 'W'; | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE s32 hex_digit_to_int( char c ) | ||||
| inline | ||||
| s32 hex_digit_to_int( char c ) | ||||
| { | ||||
| 	if ( char_is_digit( c ) ) | ||||
| 		return digit_to_int( c ); | ||||
| @@ -113,7 +123,8 @@ GEN_IMPL_INLINE s32 hex_digit_to_int( char c ) | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE s32 str_compare( const char* s1, const char* s2 ) | ||||
| inline | ||||
| s32 str_compare( const char* s1, const char* s2 ) | ||||
| { | ||||
| 	while ( *s1 && ( *s1 == *s2 ) ) | ||||
| 	{ | ||||
| @@ -122,7 +133,8 @@ GEN_IMPL_INLINE s32 str_compare( const char* s1, const char* s2 ) | ||||
| 	return *( u8* )s1 - *( u8* )s2; | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE s32 str_compare( const char* s1, const char* s2, sw len ) | ||||
| inline | ||||
| s32 str_compare_len( const char* s1, const char* s2, ssize len ) | ||||
| { | ||||
| 	for ( ; len > 0; s1++, s2++, len-- ) | ||||
| 	{ | ||||
| @@ -134,7 +146,8 @@ GEN_IMPL_INLINE s32 str_compare( const char* s1, const char* s2, sw len ) | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE char* str_copy( char* dest, const char* source, sw len ) | ||||
| inline | ||||
| char* str_copy( char* dest, const char* source, ssize len ) | ||||
| { | ||||
| 	GEN_ASSERT_NOT_NULL( dest ); | ||||
| 	if ( source ) | ||||
| @@ -154,9 +167,10 @@ GEN_IMPL_INLINE char* str_copy( char* dest, const char* source, sw len ) | ||||
| 	return dest; | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE sw str_copy_nulpad( char* dest, const char* source, sw len ) | ||||
| inline | ||||
| ssize str_copy_nulpad( char* dest, const char* source, ssize len ) | ||||
| { | ||||
| 	sw result = 0; | ||||
| 	ssize result = 0; | ||||
| 	GEN_ASSERT_NOT_NULL( dest ); | ||||
| 	if ( source ) | ||||
| 	{ | ||||
| @@ -178,7 +192,8 @@ GEN_IMPL_INLINE sw str_copy_nulpad( char* dest, const char* source, sw len ) | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE sw str_len( const char* str ) | ||||
| inline | ||||
| ssize str_len( const char* str ) | ||||
| { | ||||
| 	if ( str == NULL ) | ||||
| 	{ | ||||
| @@ -190,17 +205,19 @@ GEN_IMPL_INLINE sw str_len( const char* str ) | ||||
| 	return str - p; | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE sw str_len( const char* str, sw max_len ) | ||||
| inline | ||||
| ssize str_len_capped( const char* str, ssize max_len ) | ||||
| { | ||||
| 	const char* end = zpl_cast( const char* ) mem_find( str, 0, max_len ); | ||||
| 	const char* end = rcast(const char*, mem_find( str, 0, max_len )); | ||||
| 	if ( end ) | ||||
| 		return end - str; | ||||
| 	return max_len; | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE char* str_reverse( char* str ) | ||||
| inline | ||||
| char* str_reverse( char* str ) | ||||
| { | ||||
| 	sw    len  = str_len( str ); | ||||
| 	ssize    len  = str_len( str ); | ||||
| 	char* a    = str + 0; | ||||
| 	char* b    = str + len - 1; | ||||
| 	len       /= 2; | ||||
| @@ -212,7 +229,8 @@ GEN_IMPL_INLINE char* str_reverse( char* str ) | ||||
| 	return str; | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE char const* str_skip( char const* str, char c ) | ||||
| inline | ||||
| char const* str_skip( char const* str, char c ) | ||||
| { | ||||
| 	while ( *str && *str != c ) | ||||
| 	{ | ||||
| @@ -221,11 +239,12 @@ GEN_IMPL_INLINE char const* str_skip( char const* str, char c ) | ||||
| 	return str; | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE char const* str_skip_any( char const* str, char const* char_list ) | ||||
| inline | ||||
| char const* str_skip_any( char const* str, char const* char_list ) | ||||
| { | ||||
| 	char const* closest_ptr     = zpl_cast( char const* ) pointer_add( ( void* )str, str_len( str ) ); | ||||
| 	sw          char_list_count = str_len( char_list ); | ||||
| 	for ( sw i = 0; i < char_list_count; i++ ) | ||||
| 	char const* closest_ptr     = rcast( char const*, pointer_add_const( rcast(mem_ptr_const, str), str_len( str ) )); | ||||
| 	ssize       char_list_count = str_len( char_list ); | ||||
| 	for ( ssize i = 0; i < char_list_count; i++ ) | ||||
| 	{ | ||||
| 		char const* p = str_skip( str, char_list[ i ] ); | ||||
| 		closest_ptr   = min( closest_ptr, p ); | ||||
| @@ -233,7 +252,8 @@ GEN_IMPL_INLINE char const* str_skip_any( char const* str, char const* char_list | ||||
| 	return closest_ptr; | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE char const* str_trim( char const* str, b32 catch_newline ) | ||||
| inline | ||||
| char const* str_trim( char const* str, b32 catch_newline ) | ||||
| { | ||||
| 	while ( *str && char_is_space( *str ) && ( ! catch_newline || ( catch_newline && *str != '\n' ) ) ) | ||||
| 	{ | ||||
| @@ -242,7 +262,8 @@ GEN_IMPL_INLINE char const* str_trim( char const* str, b32 catch_newline ) | ||||
| 	return str; | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE void str_to_lower( char* str ) | ||||
| inline | ||||
| void str_to_lower( char* str ) | ||||
| { | ||||
| 	if ( ! str ) | ||||
| 		return; | ||||
| @@ -253,7 +274,8 @@ GEN_IMPL_INLINE void str_to_lower( char* str ) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| GEN_IMPL_INLINE void str_to_upper( char* str ) | ||||
| inline | ||||
| void str_to_upper( char* str ) | ||||
| { | ||||
| 	if ( ! str ) | ||||
| 		return; | ||||
| @@ -264,4 +286,6 @@ GEN_IMPL_INLINE void str_to_upper( char* str ) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| GEN_API_C_END | ||||
|  | ||||
| #pragma endregion String Ops | ||||
|   | ||||
| @@ -4,20 +4,11 @@ | ||||
| #endif | ||||
|  | ||||
| #pragma region String | ||||
| GEN_API_C_BEGIN | ||||
|  | ||||
| String String::fmt( AllocatorInfo allocator, char* buf, sw 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, sw length ) | ||||
| { | ||||
| 	constexpr sw 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 +16,8 @@ String String::make_length( AllocatorInfo allocator, char const* str, sw length | ||||
| 	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 +32,9 @@ String String::make_length( AllocatorInfo allocator, char const* str, sw length | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| String String::make_reserve( AllocatorInfo allocator, sw capacity ) | ||||
| String string_make_reserve( AllocatorInfo allocator, ssize capacity ) | ||||
| { | ||||
| 	constexpr sw 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 +44,8 @@ String String::make_reserve( AllocatorInfo allocator, sw 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; | ||||
| @@ -63,68 +54,5 @@ String String::make_reserve( AllocatorInfo allocator, sw capacity ) | ||||
| 	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, ... ) | ||||
| { | ||||
| 	sw   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, sw add_len ) | ||||
| { | ||||
| 	sw available = avail_space(); | ||||
|  | ||||
| 	// NOTE: Return if there is enough space left | ||||
| 	if ( available >= add_len ) | ||||
| 	{ | ||||
| 		return true; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		sw 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            = zpl_cast( Header* ) new_ptr; | ||||
| 		header->Allocator = allocator; | ||||
| 		header->Capacity  = new_len; | ||||
|  | ||||
| 		Data = rcast( char*, header + 1 ); | ||||
|  | ||||
| 		return str; | ||||
| 	} | ||||
| } | ||||
| GEN_API_C_END | ||||
| #pragma endregion String | ||||
|   | ||||
| @@ -5,254 +5,619 @@ | ||||
|  | ||||
| #pragma region Strings | ||||
|  | ||||
| GEN_API_C_BEGIN | ||||
|  | ||||
| struct StrC_Def; | ||||
| typedef struct StrC_Def StrC; | ||||
|  | ||||
| bool        strc_are_equal           (StrC lhs, StrC rhs); | ||||
| char const* strc_back                (StrC str); | ||||
| bool        strc_contains            (StrC str, StrC substring); | ||||
| StrC        strc_duplicate           (StrC str, AllocatorInfo allocator); | ||||
| b32         strc_starts_with         (StrC str, StrC substring); | ||||
| StrC        strc_to_str              (char const* bad_string); | ||||
| StrC        strc_visualize_whitespace(StrC str, AllocatorInfo allocator); | ||||
|  | ||||
| GEN_API_C_END | ||||
|  | ||||
| // Constant string with length. | ||||
| struct StrC | ||||
| struct StrC_Def | ||||
| { | ||||
| 	sw          Len; | ||||
| 	ssize       Len; | ||||
| 	char const* Ptr; | ||||
|  | ||||
| 	operator char const* ()            const { return Ptr; } | ||||
| 	char const& operator[]( sw index ) const { return Ptr[index]; } | ||||
| #if GEN_COMPILER_CPP | ||||
| 	forceinline operator char const* ()               const { return Ptr; } | ||||
| 	forceinline char const& operator[]( ssize index ) const { return Ptr[index]; } | ||||
|  | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| 	forceinline bool        is_equal            (StrC rhs)                const { return GEN_NS strc_are_equal(* this, rhs); } | ||||
| 	forceinline char const* back                ()                        const { return GEN_NS strc_back(* this); } | ||||
| 	forceinline bool        contains            (StrC substring)          const { return GEN_NS strc_contains(* this, substring); } | ||||
| 	forceinline StrC        duplicate           (AllocatorInfo allocator) const { return GEN_NS strc_duplicate(* this, allocator); } | ||||
| 	forceinline b32         starts_with         (StrC substring)          const { return GEN_NS strc_starts_with(* this, substring); } | ||||
| 	forceinline StrC        visualize_whitespace(AllocatorInfo allocator) const { return GEN_NS strc_visualize_whitespace(* this, allocator); } | ||||
| #endif | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| #define cast_to_strc( str ) * rcast( StrC*, (str) - sizeof(sw) ) | ||||
| #define txt( text ) StrC { sizeof( text ) - 1, ( text ) } | ||||
| #define cast_to_strc( str ) * rcast( StrC*, (str) - sizeof(ssize) ) | ||||
|  | ||||
| StrC to_str( char const* str ) | ||||
| #ifndef txt | ||||
| #	if GEN_COMPILER_CPP | ||||
| #		define txt( text )          StrC { sizeof( text ) - 1, ( text ) } | ||||
| #	else | ||||
| #		define txt( text )         (StrC){ sizeof( text ) - 1, ( text ) } | ||||
| #	endif | ||||
| #endif | ||||
|  | ||||
| GEN_API_C_BEGIN | ||||
| forceinline char const* strc_begin(StrC str)                   { return str.Ptr; } | ||||
| forceinline char const* strc_end  (StrC str)                   { return str.Ptr + str.Len; } | ||||
| forceinline char const* strc_next (StrC str, char const* iter) { return iter + 1; } | ||||
| GEN_API_C_END | ||||
|  | ||||
| #if GEN_COMPILER_CPP | ||||
| forceinline char const* begin(StrC str)                   { return str.Ptr; } | ||||
| forceinline char const* end  (StrC str)                   { return str.Ptr + str.Len; } | ||||
| forceinline char const* next (StrC str, char const* iter) { return iter + 1; } | ||||
| #endif | ||||
|  | ||||
| GEN_API_C_BEGIN | ||||
|  | ||||
| inline | ||||
| bool strc_are_equal(StrC lhs, StrC rhs) | ||||
| { | ||||
| 	return { str_len( str ), str }; | ||||
| 	if (lhs.Len != rhs.Len) | ||||
| 		return false; | ||||
|  | ||||
| 	for (ssize idx = 0; idx < lhs.Len; ++idx) | ||||
| 		if (lhs.Ptr[idx] != rhs.Ptr[idx]) | ||||
| 			return false; | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| inline | ||||
| char const* strc_back(StrC str) { | ||||
| 	return & str.Ptr[str.Len - 1]; | ||||
| } | ||||
|  | ||||
| inline | ||||
| bool strc_contains(StrC str, StrC substring) | ||||
| { | ||||
| 	if (substring.Len > str.Len) | ||||
| 		return false; | ||||
|  | ||||
| 	ssize main_len = str.Len; | ||||
| 	ssize sub_len  = substring.Len; | ||||
| 	for (ssize idx = 0; idx <= main_len - sub_len; ++idx) | ||||
| 	{ | ||||
| 		if (str_compare_len(str.Ptr + idx, substring.Ptr, sub_len) == 0) | ||||
| 			return true; | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline | ||||
| b32 strc_starts_with(StrC str, StrC substring) { | ||||
| 	if (substring.Len > str.Len) | ||||
| 		return false; | ||||
|  | ||||
| 	b32 result = str_compare_len(str.Ptr, substring.Ptr, substring.Len) == 0; | ||||
| 		return result; | ||||
| } | ||||
|  | ||||
| inline | ||||
| StrC to_strc_from_c_str( char const* bad_str ) { | ||||
| 	StrC result = { str_len( bad_str ), bad_str }; | ||||
| 	return result; | ||||
| } | ||||
| GEN_API_C_END | ||||
|  | ||||
| // Dynamic String | ||||
| // 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. | ||||
| struct String | ||||
| { | ||||
| 	struct Header | ||||
| 	{ | ||||
| #pragma region String | ||||
|         struct StringHeader_Def; | ||||
| typedef struct StringHeader_Def StringHeader; | ||||
|  | ||||
| #if GEN_COMPILER_C || ! GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| typedef char* String; | ||||
| #else | ||||
| struct String; | ||||
| #endif | ||||
|  | ||||
| GEN_API_C_BEGIN | ||||
|  | ||||
| forceinline usize string_grow_formula(usize value); | ||||
|  | ||||
| String        string_make_c_str          (AllocatorInfo allocator, char const*  str); | ||||
| String        string_make_strc           (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          string_are_equal           (String const lhs, String const rhs); | ||||
| bool          string_are_equal_strc      (String const lhs, StrC rhs); | ||||
| bool          string_make_space_for      (String*      str, char const*  to_append, ssize add_len); | ||||
| bool          string_append_char         (String*      str, char         c); | ||||
| bool          string_append_c_str        (String*      str, char const*  str_to_append); | ||||
| bool          string_append_c_str_len    (String*      str, char const*  str_to_append, ssize length); | ||||
| bool          string_append_strc         (String*      str, StrC         str_to_append); | ||||
| bool          string_append_string       (String*      str, String const other); | ||||
| bool          string_append_fmt          (String*      str, char const*  fmt, ...); | ||||
| ssize         string_avail_space         (String const str); | ||||
| char*         string_back                (String       str); | ||||
| bool          string_contains_strc       (String const str, StrC         substring); | ||||
| bool          string_contains_string     (String const str, String const substring); | ||||
| ssize         string_capacity            (String const str); | ||||
| void          string_clear               (String       str); | ||||
| String        string_duplicate           (String const str, AllocatorInfo allocator); | ||||
| void          string_free                (String*      str); | ||||
| StringHeader* string_get_header          (String       str); | ||||
| ssize         string_length              (String const str); | ||||
| b32           string_starts_with_strc    (String const str, StrC   substring); | ||||
| b32           string_starts_with_string  (String const str, String substring); | ||||
| void          string_skip_line           (String       str); | ||||
| void          string_strip_space         (String       str); | ||||
| StrC          string_to_strc             (String       str); | ||||
| void          string_trim                (String       str, char const* cut_set); | ||||
| void          string_trim_space          (String       str); | ||||
| String        string_visualize_whitespace(String const str); | ||||
|  | ||||
| GEN_API_C_END | ||||
|  | ||||
| struct StringHeader_Def { | ||||
| 	AllocatorInfo Allocator; | ||||
| 		sw            Capacity; | ||||
| 		sw            Length; | ||||
| 	ssize         Capacity; | ||||
| 	ssize         Length; | ||||
| }; | ||||
|  | ||||
| 	static | ||||
| 	uw grow_formula( uw value ) | ||||
| #if GEN_COMPILER_CPP && GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| struct String | ||||
| { | ||||
| 	char* Data; | ||||
|  | ||||
| 	forceinline operator char*()             { return Data; } | ||||
| 	forceinline operator char const*() const { return Data; } | ||||
| 	forceinline operator StrC()        const { return { string_length(* this), Data }; } | ||||
|  | ||||
| 	String const& operator=(String const& other) const { | ||||
| 		if (this == &other) | ||||
| 			return *this; | ||||
|  | ||||
| 		String* this_ = ccast(String*, this); | ||||
| 		this_->Data = other.Data; | ||||
|  | ||||
| 		return *this; | ||||
| 	} | ||||
|  | ||||
| 	forceinline char&       operator[](ssize index)       { return Data[index]; } | ||||
| 	forceinline char const& operator[](ssize index) const { return Data[index]; } | ||||
|  | ||||
| 	       forceinline bool operator==(std::nullptr_t) const             { return     Data == nullptr; } | ||||
| 	       forceinline bool operator!=(std::nullptr_t) const             { return     Data != nullptr; } | ||||
| 	friend forceinline bool operator==(std::nullptr_t, const String str) { return str.Data == nullptr; } | ||||
| 	friend forceinline bool operator!=(std::nullptr_t, const String str) { return str.Data != nullptr; } | ||||
|  | ||||
| 	forceinline char* begin() const { return Data; } | ||||
| 	forceinline char* end()   const { return Data + string_length(* this); } | ||||
|  | ||||
| #pragma region Member Mapping | ||||
| 	forceinline static String make(AllocatorInfo allocator, char const* str)                { return string_make_c_str(allocator, str); } | ||||
| 	forceinline static String make(AllocatorInfo allocator, StrC str)                       { return string_make_strc(allocator, str); } | ||||
| 	forceinline static String make_reserve(AllocatorInfo allocator, ssize cap)              { return string_make_reserve(allocator, cap); } | ||||
| 	forceinline static String make_length(AllocatorInfo a, char const* s, ssize l)          { return string_make_length(a, s, l); } | ||||
| 	forceinline static String join(AllocatorInfo a, char const** p, ssize n, char const* g) { return string_join(a, p, n, g); } | ||||
| 	forceinline static usize  grow_formula(usize value)                                     { return string_grow_formula(value); } | ||||
|  | ||||
| 	static | ||||
| 	String fmt(AllocatorInfo allocator, char* buf, ssize buf_size, char const* fmt, ...) { | ||||
| 		va_list va; | ||||
| 		va_start(va, fmt); | ||||
| 		ssize res = str_fmt_va(buf, buf_size, fmt, va) - 1; | ||||
| 		va_end(va); | ||||
| 		return string_make_length(allocator, buf, res); | ||||
| 	} | ||||
|  | ||||
| 	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); | ||||
| 		ssize res = str_fmt_va(buf, GEN_PRINTF_MAXLEN, fmt, va) - 1; | ||||
| 		va_end(va); | ||||
| 		return string_make_length(allocator, buf, res); | ||||
| 	} | ||||
|  | ||||
| 	forceinline bool          make_space_for(char const* str, ssize add_len) { return string_make_space_for(this, str, add_len); } | ||||
| 	forceinline bool          append(char c)                                 { return string_append_char(this, c); } | ||||
| 	forceinline bool          append(char const* str)                        { return string_append_c_str(this, str); } | ||||
| 	forceinline bool          append(char const* str, ssize length)          { return string_append_c_str_len(this, str, length); } | ||||
| 	forceinline bool          append(StrC str)                               { return string_append_strc(this, str); } | ||||
| 	forceinline bool          append(const String other)                     { return string_append_string(this, other); } | ||||
| 	forceinline ssize         avail_space() const                            { return string_avail_space(* this); } | ||||
| 	forceinline char*         back()                                         { return string_back(* this); } | ||||
| 	forceinline bool          contains(StrC substring) const                 { return string_contains_strc(* this, substring); } | ||||
| 	forceinline bool          contains(String const& substring) const        { return string_contains_string(* this, substring); } | ||||
| 	forceinline ssize         capacity() const                               { return string_capacity(* this); } | ||||
| 	forceinline void          clear()                                        {        string_clear(* this); } | ||||
| 	forceinline String        duplicate(AllocatorInfo allocator) const       { return string_duplicate(* this, allocator); } | ||||
| 	forceinline void          free()                                         {        string_free(this); } | ||||
| 	forceinline bool          is_equal(String const& other) const            { return string_are_equal(* this, other); } | ||||
| 	forceinline bool          is_equal(StrC other) const                     { return string_are_equal_strc(* this, other); } | ||||
| 	forceinline ssize         length() const                                 { return string_length(* this); } | ||||
| 	forceinline b32           starts_with(StrC substring) const              { return string_starts_with_strc(* this, substring); } | ||||
| 	forceinline b32           starts_with(String substring) const            { return string_starts_with_string(* this, substring); } | ||||
| 	forceinline void          skip_line()                                    {        string_skip_line(* this); } | ||||
| 	forceinline void          strip_space()                                  {        string_strip_space(* this); } | ||||
| 	forceinline StrC          to_strc()                                      { return { string_length(*this), Data}; } | ||||
| 	forceinline void          trim(char const* cut_set)                      {        string_trim(* this, cut_set); } | ||||
| 	forceinline void          trim_space()                                   {        string_trim_space(* this); } | ||||
| 	forceinline String        visualize_whitespace() const                   { return string_visualize_whitespace(* this); } | ||||
| 	forceinline StringHeader& get_header()                                   { return * string_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 string_append_c_str_len(this, buf, res); | ||||
| 	} | ||||
| #pragma endregion Member Mapping | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| GEN_API_C_BEGIN | ||||
| forceinline char* string_begin(String str)                   { return ((char*) str); } | ||||
| forceinline char* string_end  (String str)                   { return ((char*) str + string_length(str)); } | ||||
| forceinline char* string_next (String str, char const* iter) { return ((char*) iter + 1); } | ||||
| GEN_API_C_END | ||||
|  | ||||
| #if GEN_COMPILER_CPP && 0 | ||||
| forceinline char* begin(String str)             { return ((char*) str); } | ||||
| forceinline char* end  (String str)             { return ((char*) str + string_length(str)); } | ||||
| forceinline char* next (String str, char* iter) { return ((char*) iter + 1); } | ||||
| #endif | ||||
|  | ||||
| #if GEN_SUPPORT_CPP_REFERENCES | ||||
| forceinline bool  make_space_for(String& str, char const* to_append, ssize add_len); | ||||
| forceinline bool  append(String& str, char c); | ||||
| forceinline bool  append(String& str, char const* str_to_append); | ||||
| forceinline bool  append(String& str, char const* str_to_append, ssize length); | ||||
| forceinline bool  append(String& str, StrC str_to_append); | ||||
| forceinline bool  append(String& str, const String other); | ||||
| forceinline bool  append_fmt(String& str, char const* fmt, ...); | ||||
| forceinline char& back(String& str); | ||||
| forceinline void  clear(String& str); | ||||
| forceinline void  free(String& str); | ||||
| #endif | ||||
|  | ||||
| GEN_API_C_BEGIN | ||||
|  | ||||
| forceinline | ||||
| 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; | ||||
| } | ||||
|  | ||||
| 	static | ||||
| 	String make( AllocatorInfo allocator, char const* str ) | ||||
| 	{ | ||||
| 		sw length = str ? str_len( str ) : 0; | ||||
| 		return make_length( allocator, str, length ); | ||||
| forceinline | ||||
| String string_make_c_str(AllocatorInfo allocator, char const* str) { | ||||
| 	ssize length = str ? str_len(str) : 0; | ||||
| 	return string_make_length(allocator, str, length); | ||||
| } | ||||
|  | ||||
| 	static | ||||
| 	String make( AllocatorInfo allocator, StrC str ) | ||||
| 	{ | ||||
| 		return make_length( allocator, str.Ptr, str.Len ); | ||||
| forceinline | ||||
| String string_make_strc(AllocatorInfo allocator, StrC str) { | ||||
| 	return string_make_length(allocator, str.Ptr, str.Len); | ||||
| } | ||||
|  | ||||
| 	static | ||||
| 	String make_reserve( AllocatorInfo allocator, sw capacity ); | ||||
| inline | ||||
| String string_fmt(AllocatorInfo allocator, char* buf, ssize buf_size, char const* fmt, ...) { | ||||
| 	va_list va; | ||||
| 	va_start(va, fmt); | ||||
| 	ssize res = str_fmt_va(buf, buf_size, fmt, va) - 1; | ||||
| 	va_end(va); | ||||
|  | ||||
| 	static | ||||
| 	String make_length( AllocatorInfo allocator, char const* str, sw length ); | ||||
| 	return string_make_length(allocator, buf, res); | ||||
| } | ||||
|  | ||||
| 	static | ||||
| 	String fmt( AllocatorInfo allocator, char* buf, sw buf_size, char const* fmt, ... ); | ||||
|  | ||||
| 	static | ||||
| 	String fmt_buf( AllocatorInfo allocator, char const* fmt, ... ); | ||||
|  | ||||
| 	static | ||||
| 	String join( AllocatorInfo allocator, char const** parts, sw num_parts, char const* glue ) | ||||
| inline | ||||
| String string_fmt_buf(AllocatorInfo allocator, char const* fmt, ...) | ||||
| { | ||||
| 		String result = make( allocator, "" ); | ||||
| 	local_persist thread_local | ||||
| 	PrintF_Buffer buf = struct_init(PrintF_Buffer, {0}); | ||||
|  | ||||
| 		for ( sw idx = 0; idx < num_parts; ++idx ) | ||||
| 	va_list va; | ||||
| 	va_start(va, fmt); | ||||
| 	ssize res = str_fmt_va(buf, GEN_PRINTF_MAXLEN, fmt, va) -1; | ||||
| 	va_end(va); | ||||
|  | ||||
| 	return string_make_length(allocator, buf, res); | ||||
| } | ||||
|  | ||||
| inline | ||||
| String string_join(AllocatorInfo allocator, char const** parts, ssize num_parts, char const* glue) | ||||
| { | ||||
| 			result.append( parts[ idx ] ); | ||||
| 	String result = string_make_c_str(allocator, ""); | ||||
|  | ||||
| 	for (ssize idx = 0; idx < num_parts; ++idx) | ||||
| 	{ | ||||
| 		string_append_c_str(& result, parts[idx]); | ||||
|  | ||||
| 		if (idx < num_parts - 1) | ||||
| 				result.append( glue ); | ||||
| 			string_append_c_str(& result, glue); | ||||
| 	} | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| 	static | ||||
| 	bool are_equal( String lhs, String rhs ) | ||||
| forceinline | ||||
| bool string_append_char(String* str, char c) { | ||||
| 	GEN_ASSERT(str != nullptr); | ||||
| 	return string_append_c_str_len( str, (char const*)& c, (ssize)1); | ||||
| } | ||||
|  | ||||
| forceinline | ||||
| bool string_append_c_str(String* str, char const* str_to_append) { | ||||
| 	GEN_ASSERT(str != nullptr); | ||||
| 	return string_append_c_str_len(str, str_to_append, str_len(str_to_append)); | ||||
| } | ||||
|  | ||||
| inline | ||||
| bool string_append_c_str_len(String* str, char const* str_to_append, ssize append_length) | ||||
| { | ||||
| 		if ( lhs.length() != rhs.length() ) | ||||
| 	GEN_ASSERT(str != nullptr); | ||||
| 	if ( rcast(sptr, str_to_append) > 0) | ||||
| 	{ | ||||
| 		ssize curr_len = string_length(* str); | ||||
|  | ||||
| 		if ( ! string_make_space_for(str, str_to_append, append_length)) | ||||
| 			return false; | ||||
|  | ||||
| 		for ( sw idx = 0; idx < lhs.length(); ++idx ) | ||||
| 		StringHeader* header = string_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; | ||||
| } | ||||
|  | ||||
| forceinline | ||||
| bool string_append_strc(String* str, StrC str_to_append) { | ||||
| 	GEN_ASSERT(str != nullptr); | ||||
| 	return string_append_c_str_len(str, str_to_append.Ptr, str_to_append.Len); | ||||
| } | ||||
|  | ||||
| forceinline | ||||
| bool string_append_string(String* str, String const other) { | ||||
| 	GEN_ASSERT(str != nullptr); | ||||
| 	return string_append_c_str_len(str, (char const*)other, string_length(other)); | ||||
| } | ||||
|  | ||||
| bool string_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 string_append_c_str_len(str, (char const*)buf, res); | ||||
| } | ||||
|  | ||||
| inline | ||||
| bool string_are_equal_string(String const lhs, String const rhs) | ||||
| { | ||||
| 	if (string_length(lhs) != string_length(rhs)) | ||||
| 		return false; | ||||
|  | ||||
| 	for (ssize idx = 0; idx < string_length(lhs); ++idx) | ||||
| 		if (lhs[idx] != rhs[idx]) | ||||
| 			return false; | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| 	static | ||||
| 	bool are_equal( String lhs, StrC rhs ) | ||||
| inline | ||||
| bool string_are_equal_strc(String const lhs, StrC rhs) | ||||
| { | ||||
| 		if ( lhs.length() != (rhs.Len) ) | ||||
| 	if (string_length(lhs) != (rhs.Len)) | ||||
| 		return false; | ||||
|  | ||||
| 		for ( sw idx = 0; idx < lhs.length(); ++idx ) | ||||
| 			if ( lhs[idx] != rhs[idx] ) | ||||
| 	for (ssize idx = 0; idx < string_length(lhs); ++idx) | ||||
| 		if (lhs[idx] != rhs.Ptr[idx]) | ||||
| 			return false; | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| 	bool make_space_for( char const* str, sw add_len ); | ||||
|  | ||||
| 	bool append( char c ) | ||||
| 	{ | ||||
| 		return append( & c, 1 ); | ||||
| forceinline | ||||
| ssize string_avail_space(String const str) { | ||||
| 	StringHeader const* header = rcast(StringHeader const*, scast(char const*, str) - sizeof(StringHeader)); | ||||
| 	return header->Capacity - header->Length; | ||||
| } | ||||
|  | ||||
| 	bool append( char const* str ) | ||||
| 	{ | ||||
| 		return append( str, str_len( str ) ); | ||||
| forceinline | ||||
| char* string_back(String str) { | ||||
| 	return & (str)[string_length(str) - 1]; | ||||
| } | ||||
|  | ||||
| 	bool append( char const* str, sw length ) | ||||
| inline | ||||
| bool string_contains_StrC(String const str, StrC substring) | ||||
| { | ||||
| 		if ( sptr(str) > 0 ) | ||||
| 		{ | ||||
| 			sw curr_len = this->length(); | ||||
| 	StringHeader const* header = rcast(StringHeader const*, scast(char const*, str) - sizeof(StringHeader)); | ||||
|  | ||||
| 			if ( ! make_space_for( str, length ) ) | ||||
| 	if (substring.Len > header->Length) | ||||
| 		return false; | ||||
|  | ||||
| 			Header& header = get_header(); | ||||
| 	ssize main_len = header->Length; | ||||
| 	ssize sub_len  = substring.Len; | ||||
|  | ||||
| 			mem_copy( Data + curr_len, str, length ); | ||||
|  | ||||
| 			Data[ curr_len + length ] = '\0'; | ||||
|  | ||||
| 			header.Length = curr_len + length; | ||||
| 		} | ||||
| 		return str; | ||||
| 	} | ||||
|  | ||||
| 	bool append( StrC str) | ||||
| 	for (ssize idx = 0; idx <= main_len - sub_len; ++idx) | ||||
| 	{ | ||||
| 		return append( str.Ptr, str.Len ); | ||||
| 		if (str_compare_len(str + idx, substring.Ptr, sub_len) == 0) | ||||
| 			return true; | ||||
| 	} | ||||
|  | ||||
| 	bool append( const String other ) | ||||
| 	{ | ||||
| 		return append( other.Data, other.length() ); | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| 	bool append_fmt( char const* fmt, ... ); | ||||
|  | ||||
| 	sw avail_space() const | ||||
| inline | ||||
| bool string_contains_string(String const str, String const substring) | ||||
| { | ||||
| 		Header const& | ||||
| 		header = * rcast( Header const*, Data - sizeof( Header )); | ||||
| 	StringHeader const* header = rcast(StringHeader const*, scast(char const*, str) - sizeof(StringHeader)); | ||||
|  | ||||
| 		return header.Capacity - header.Length; | ||||
| 	if (string_length(substring) > header->Length) | ||||
| 		return false; | ||||
|  | ||||
| 	ssize main_len = header->Length; | ||||
| 	ssize sub_len  = string_length(substring); | ||||
|  | ||||
| 	for (ssize idx = 0; idx <= main_len - sub_len; ++idx) | ||||
| 	{ | ||||
| 		if (str_compare_len(str + idx, substring, sub_len) == 0) | ||||
| 			return true; | ||||
| 	} | ||||
|  | ||||
| 	char& back() | ||||
| 	{ | ||||
| 		return Data[ length() - 1 ]; | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| 	sw capacity() const | ||||
| 	{ | ||||
| 		Header const& | ||||
| 		header = * rcast( Header const*, Data - sizeof( Header )); | ||||
|  | ||||
| 		return header.Capacity; | ||||
| forceinline | ||||
| ssize string_capacity(String const str) { | ||||
|    StringHeader const* header = rcast(StringHeader const*, scast(char const*, str) - sizeof(StringHeader)); | ||||
|    return header->Capacity; | ||||
| } | ||||
|  | ||||
| 	void clear() | ||||
| 	{ | ||||
| 		get_header().Length = 0; | ||||
| forceinline | ||||
| void string_clear(String str) { | ||||
|    string_get_header(str)->Length = 0; | ||||
| } | ||||
|  | ||||
| 	String duplicate( AllocatorInfo allocator ) const | ||||
| 	{ | ||||
| 		return make_length( allocator, Data, length() ); | ||||
| forceinline | ||||
| String string_duplicate(String const str, AllocatorInfo allocator) { | ||||
|    return string_make_length(allocator, str, string_length(str)); | ||||
| } | ||||
|  | ||||
| 	void free() | ||||
| 	{ | ||||
| 		if ( ! Data ) | ||||
| forceinline | ||||
| void string_free(String* str) { | ||||
| 	GEN_ASSERT(str != nullptr); | ||||
| 	if (! (* str)) | ||||
| 		return; | ||||
|  | ||||
| 		Header& header = get_header(); | ||||
|  | ||||
| 		gen::free( header.Allocator, & header ); | ||||
| 	StringHeader* header = string_get_header(* str); | ||||
| 	allocator_free(header->Allocator, header); | ||||
| } | ||||
|  | ||||
| 	Header& get_header() | ||||
| 	{ | ||||
| 		return *(Header*)(Data - sizeof(Header)); | ||||
| forceinline | ||||
| StringHeader* string_get_header(String str) { | ||||
|    return (StringHeader*)(scast(char*, str) - sizeof(StringHeader)); | ||||
| } | ||||
|  | ||||
| 	sw length() const | ||||
| forceinline | ||||
| ssize string_length(String const str) | ||||
| { | ||||
| 		Header const& | ||||
| 		header = * rcast( Header const*, Data - sizeof( Header )); | ||||
|  | ||||
| 		return header.Length; | ||||
|    StringHeader const* header = rcast(StringHeader const*, scast(char const*, str) - sizeof(StringHeader)); | ||||
|    return header->Length; | ||||
| } | ||||
|  | ||||
| 	b32 starts_with( StrC substring ) const | ||||
| inline | ||||
| bool string_make_space_for(String* str, char const* to_append, ssize add_len) | ||||
| { | ||||
| 		if (substring.Len > length()) | ||||
| 	ssize available = string_avail_space(* str); | ||||
|  | ||||
| 	if (available >= add_len) { | ||||
| 		return true; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		ssize new_len, old_size, new_size; | ||||
| 		void* ptr; | ||||
| 		void* new_ptr; | ||||
|  | ||||
| 		AllocatorInfo allocator = string_get_header(* str)->Allocator; | ||||
| 		StringHeader* header    = nullptr; | ||||
|  | ||||
| 		new_len  = string_grow_formula(string_length(* str) + add_len); | ||||
| 		ptr      = string_get_header(* str); | ||||
| 		old_size = size_of(StringHeader) + string_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; | ||||
|  | ||||
| 		b32 result = str_compare(Data, substring.Ptr, substring.Len ) == 0; | ||||
| 		header = rcast(StringHeader*, new_ptr); | ||||
| 		header->Allocator = allocator; | ||||
| 		header->Capacity  = new_len; | ||||
|  | ||||
| 		char** Data = rcast(char**, str); | ||||
| 		* Data = rcast(char*, header + 1); | ||||
|  | ||||
| 		return true; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| forceinline | ||||
| b32 string_starts_with_strc(String const str, StrC substring) { | ||||
| 	if (substring.Len > string_length(str)) | ||||
| 	return false; | ||||
|  | ||||
| 	b32 result = str_compare_len(str, substring.Ptr, substring.Len) == 0; | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| 	b32 starts_with( String substring ) const | ||||
| 	{ | ||||
| 		if (substring.length() > length()) | ||||
| forceinline | ||||
| b32 string_starts_with_string(String const str, String substring) { | ||||
| 	if (string_length(substring) > string_length(str)) | ||||
| 		return false; | ||||
|  | ||||
| 		b32 result = str_compare(Data, substring, substring.length() - 1 ) == 0; | ||||
| 	b32 result = str_compare_len(str, substring, string_length(substring) - 1) == 0; | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| 	void skip_line() | ||||
| inline | ||||
| void string_skip_line(String str) | ||||
| { | ||||
| #define current (*scanner) | ||||
| 		char* scanner = Data; | ||||
| 		while ( current != '\r' && current != '\n' ) | ||||
| 		{ | ||||
| 	char* scanner = str; | ||||
| 	while (current != '\r' && current != '\n') { | ||||
|  		++scanner; | ||||
| 	} | ||||
|  | ||||
| 		s32 new_length = scanner - Data; | ||||
| 	s32 new_length = scanner - str; | ||||
|  | ||||
| 		if ( current == '\r' ) | ||||
| 		{ | ||||
| 	if (current == '\r') { | ||||
| 		new_length += 1; | ||||
| 	} | ||||
|  | ||||
| 		mem_move( Data, scanner, new_length ); | ||||
| 	mem_move((char*)str, scanner, new_length); | ||||
|  | ||||
| 		Header* header = & get_header(); | ||||
| 	StringHeader* header = string_get_header(str); | ||||
| 	header->Length = new_length; | ||||
| #undef current | ||||
| } | ||||
|  | ||||
| 	void strip_space() | ||||
| inline | ||||
| void strip_space(String str) | ||||
| { | ||||
| 		char* write_pos = Data; | ||||
| 		char* read_pos  = Data; | ||||
|    char* write_pos = str; | ||||
|    char* read_pos  = str; | ||||
|  | ||||
|    while (* read_pos) | ||||
|    { | ||||
| @@ -267,15 +632,22 @@ struct String | ||||
|    write_pos[0] = '\0';  // Null-terminate the modified string | ||||
|  | ||||
|    // Update the length if needed | ||||
| 		get_header().Length = write_pos - Data; | ||||
|    string_get_header(str)->Length = write_pos - str; | ||||
| } | ||||
|  | ||||
| 	void trim( char const* cut_set ) | ||||
| 	{ | ||||
| 		sw len = 0; | ||||
| forceinline | ||||
| StrC string_to_strc(String str) { | ||||
| 	StrC result = { string_length(str), (char const*)str }; | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| 		char* start_pos = Data; | ||||
| 		char* end_pos   = Data + length() - 1; | ||||
| inline | ||||
| void trim(String str, char const* cut_set) | ||||
| { | ||||
| 	ssize len = 0; | ||||
|  | ||||
| 	char* start_pos = str; | ||||
| 	char* end_pos   = scast(char*, str) + string_length(str) - 1; | ||||
|  | ||||
| 	while (start_pos <= end_pos && char_first_occurence(cut_set, *start_pos)) | ||||
| 	start_pos++; | ||||
| @@ -283,132 +655,108 @@ struct String | ||||
| 	while (end_pos > start_pos && char_first_occurence(cut_set, *end_pos)) | ||||
| 	end_pos--; | ||||
|  | ||||
| 		len = scast( sw, ( start_pos > end_pos ) ? 0 : ( ( end_pos - start_pos ) + 1 ) ); | ||||
| 	len = scast(ssize, (start_pos > end_pos) ? 0 : ((end_pos - start_pos) + 1)); | ||||
|  | ||||
| 		if ( Data != start_pos ) | ||||
| 			mem_move( Data, start_pos, len ); | ||||
| 	if (str != start_pos) | ||||
| 		mem_move(str, start_pos, len); | ||||
|  | ||||
| 		Data[ len ] = '\0'; | ||||
| 	str[len] = '\0'; | ||||
|  | ||||
| 		get_header().Length = len; | ||||
|    string_get_header(str)->Length = len; | ||||
| } | ||||
|  | ||||
| 	void trim_space() | ||||
| 	{ | ||||
| 		return trim( " \t\r\n\v\f" ); | ||||
| forceinline | ||||
| void trim_space(String str) { | ||||
|    trim(str, " \t\r\n\v\f"); | ||||
| } | ||||
|  | ||||
| 	// Debug function that provides a copy of the string with whitespace characters visualized. | ||||
| 	String visualize_whitespace() const | ||||
| inline | ||||
| String visualize_whitespace(String const str) | ||||
| { | ||||
| 		Header* header = (Header*)(Data - sizeof(Header)); | ||||
| 	StringHeader* header = (StringHeader*)(scast(char const*, str) - sizeof(StringHeader)); | ||||
| 	String        result = string_make_reserve(header->Allocator, string_length(str) * 2); // Assume worst case for space requirements. | ||||
|  | ||||
| 		String result = make_reserve(header->Allocator, length() * 2); // Assume worst case for space requirements. | ||||
|  | ||||
| 		for ( char c : *this ) | ||||
| 		{ | ||||
| 			switch ( c ) | ||||
| 	for (char const* c = string_begin(str); c != string_end(str); c = string_next(str, c)) | ||||
| 	switch ( * c ) | ||||
| 	{ | ||||
| 		case ' ': | ||||
| 					result.append( txt("·") ); | ||||
| 			string_append_strc(& result, txt("·")); | ||||
| 		break; | ||||
| 		case '\t': | ||||
| 					result.append( txt("→") ); | ||||
| 			string_append_strc(& result, txt("→")); | ||||
| 		break; | ||||
| 		case '\n': | ||||
| 					result.append( txt("↵") ); | ||||
| 			string_append_strc(& result, txt("↵")); | ||||
| 		break; | ||||
| 		case '\r': | ||||
| 					result.append( txt("⏎") ); | ||||
| 			string_append_strc(& result, txt("⏎")); | ||||
| 		break; | ||||
| 		case '\v': | ||||
| 					result.append( txt("⇕") ); | ||||
| 			string_append_strc(& result, txt("⇕")); | ||||
| 		break; | ||||
| 		case '\f': | ||||
| 					result.append( txt("⌂") ); | ||||
| 			string_append_strc(& result, txt("⌂")); | ||||
| 		break; | ||||
| 		default: | ||||
| 					result.append(c); | ||||
| 			string_append_char(& result, * c); | ||||
| 		break; | ||||
| 	} | ||||
| 		} | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
| #pragma endregion String | ||||
|  | ||||
| 	// 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; | ||||
| 	} | ||||
|  | ||||
| 	operator char* () | ||||
| 	{ | ||||
| 		return Data; | ||||
| 	} | ||||
|  | ||||
| 	operator char const* () const | ||||
| 	{ | ||||
| 		return Data; | ||||
| 	} | ||||
|  | ||||
| 	operator StrC() const | ||||
| 	{ | ||||
| 		return { length(), Data }; | ||||
| 	} | ||||
|  | ||||
| 	// Used with cached strings | ||||
| 	// Essentially makes the string a string view. | ||||
| 	String const& operator = ( String const& other ) const | ||||
| 	{ | ||||
| 		if ( this == & other ) | ||||
| 			return *this; | ||||
|  | ||||
| 		String& this_ = ccast( String, *this ); | ||||
|  | ||||
| 		this_.Data = other.Data; | ||||
|  | ||||
| 		return this_; | ||||
| 	} | ||||
|  | ||||
| 	char& operator [] ( sw index ) | ||||
| 	{ | ||||
| 		return Data[ index ]; | ||||
| 	} | ||||
|  | ||||
| 	char const& operator [] ( sw index ) const | ||||
| 	{ | ||||
| 		return Data[ index ]; | ||||
| 	} | ||||
|  | ||||
| 	char* Data; | ||||
| }; | ||||
|  | ||||
| struct String_POD | ||||
| { | ||||
| #if GEN_COMPILER_CPP | ||||
| struct String_POD { | ||||
| 	char* Data; | ||||
| }; | ||||
| static_assert( sizeof( String_POD ) == sizeof( String ), "String is not a POD" ); | ||||
| #endif | ||||
|  | ||||
| // Implements basic string interning. Data structure is based off the ZPL Hashtable. | ||||
| using StringTable = HashTable<String const>; | ||||
| forceinline | ||||
| StrC strc_duplicate(StrC str, AllocatorInfo allocator) { | ||||
| 	StrC result = string_to_strc( string_make_length(allocator, str.Ptr, str.Len)); | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| inline | ||||
| StrC strc_visualize_whitespace(StrC str, AllocatorInfo allocator) | ||||
| { | ||||
| 	String result = string_make_reserve(allocator, str.Len * 2); // Assume worst case for space requirements. | ||||
| 	for (char const* c = strc_begin(str); c != strc_end(str); c = strc_next(str, c))  | ||||
| 	switch ( * c ) | ||||
| 	{ | ||||
| 		case ' ': | ||||
| 			string_append_strc(& result, txt("·")); | ||||
| 		break; | ||||
| 		case '\t': | ||||
| 			string_append_strc(& result, txt("→")); | ||||
| 		break; | ||||
| 		case '\n': | ||||
| 			string_append_strc(& result, txt("↵")); | ||||
| 		break; | ||||
| 		case '\r': | ||||
| 			string_append_strc(& result, txt("⏎")); | ||||
| 		break; | ||||
| 		case '\v': | ||||
| 			string_append_strc(& result, txt("⇕")); | ||||
| 		break; | ||||
| 		case '\f': | ||||
| 			string_append_strc(& result, txt("⌂")); | ||||
| 		break; | ||||
| 		default: | ||||
| 			string_append_char(& result, * c); | ||||
| 		break; | ||||
| } | ||||
| 	return string_to_strc(result); | ||||
| } | ||||
|  | ||||
| // 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 StrC StringCached; | ||||
|  | ||||
| GEN_API_C_END | ||||
|  | ||||
| // Implements basic string interning. Data structure is based off the ZPL Hashtable. | ||||
| typedef HashTable(StringCached) StringTable; | ||||
| #pragma endregion Strings | ||||
|   | ||||
| @@ -4,6 +4,7 @@ | ||||
| #endif | ||||
|  | ||||
| #pragma region Timing | ||||
| GEN_API_C_BEGIN | ||||
|  | ||||
| #ifdef GEN_BENCHMARK | ||||
| 	#if defined( GEN_COMPILER_MSVC ) && ! defined( __clang__ ) | ||||
| @@ -23,7 +24,7 @@ | ||||
| 	{ | ||||
| 		u32 hi, lo; | ||||
| 		__asm__ __volatile__( "rdtsc" : "=a"( lo ), "=d"( hi ) ); | ||||
| 		return ( zpl_cast( u64 ) lo ) | ( ( zpl_cast( u64 ) hi ) << 32 ); | ||||
| 		return scast( u64, lo ) | ( scast( u64, hi ) << 32 ); | ||||
| 	} | ||||
| 	#elif defined( __powerpc__ ) | ||||
| 	u64 read_cpu_time_stamp_counter( void ) | ||||
| @@ -164,4 +165,5 @@ | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| GEN_API_C_END | ||||
| #pragma endregion Timing | ||||
|   | ||||
| @@ -5,6 +5,8 @@ | ||||
|  | ||||
| #pragma region Timing | ||||
|  | ||||
| GEN_API_C_BEGIN | ||||
|  | ||||
| #ifdef GEN_BENCHMARK | ||||
| //! Return CPU timestamp. | ||||
| u64 read_cpu_time_stamp_counter( void ); | ||||
| @@ -16,4 +18,6 @@ f64 time_rel( void ); | ||||
| u64 time_rel_ms( void ); | ||||
| #endif | ||||
|  | ||||
| GEN_API_C_END | ||||
|  | ||||
| #pragma endregion Timing | ||||
|   | ||||
| @@ -8,6 +8,13 @@ | ||||
|  | ||||
| #include "gen.hpp" | ||||
|  | ||||
| // These are intended for use in the base library of gencpp and the C-variant of the library | ||||
| // It provides a interoperability between the C++ and C interfacing for containers. (not letting these do any crazy substiution though) | ||||
| // They are undefined in gen.hpp and gen.cpp at the end of the files. | ||||
| // We cpp library expects the user to use the regular calls as they can resolve the type fine. | ||||
|  | ||||
| #include "helpers/push_container_defines.inline.hpp" | ||||
|  | ||||
| //! 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 | ||||
| @@ -32,4 +39,5 @@ GEN_NS_BEGIN | ||||
|  | ||||
| GEN_NS_END | ||||
|  | ||||
| #include "helpers/pop_container_defines.inline.hpp" | ||||
| #include "helpers/pop_ignores.inline.hpp" | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| // This file is intended to be included within gen.hpp (There is no pragma diagnostic ignores) | ||||
| #pragma once | ||||
|  | ||||
| #include "dependencies/header_start.hpp" | ||||
| #include "dependencies/platform.hpp" | ||||
|  | ||||
| GEN_NS_BEGIN | ||||
|  | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user