mirror of
				https://github.com/Ed94/gencpp.git
				synced 2025-10-30 22:40:54 -07:00 
			
		
		
		
	WIP: Restructuring project
This commit is contained in:
		
							
								
								
									
										68
									
								
								base/Readme.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								base/Readme.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | ||||
| # Documentation | ||||
|  | ||||
| The library is fragmented into a series of headers and source files meant to be scanned in and then generated to a standard target format, or a user's desires. | ||||
|  | ||||
| Standard formats: | ||||
|  | ||||
| * **base**: Files are in granular pieces separated into four directories: | ||||
|   * **dependencies**: Originally from the c-zpl library and modified thereafter. | ||||
|   * **components**: The essential definitions of the library. | ||||
|   * **helpers**: Contains helper functionality used by base and other libraries to regenerate or generate the other library formats. | ||||
|     * `base_codegen.hpp`: Helps with self-hosted code generation of enums, and operator overload inlines of the code types. | ||||
|     * `<push/pop>.<name>.inline.<hpp>`: macros that are meant to be injected at specific locations of the library. | ||||
|     * `misc.hpp`: | ||||
|     * `undef.macros.h`: Undefines all macros from library that original were intended to leak into user code. | ||||
|   * **auxillary**: Non-essential tooling: | ||||
|     * `Builder`: Similar conceptually to Jai programming language's *builder*, just opens a file and prepares a string buffer to serialize code into (`builder_print`, `builder_print_fmt`). Then write & close the file when completed (`builder_write`). | ||||
|     * **`Scanner`**: Interface to load up `Code` from files two basic funcctions are currently provided. | ||||
|       * `scan_file`: Used mainly by the library format generators to directly scan files into untyped `Code` (raw string content, pre-formatted no AST parsed). | ||||
|       * `parse_file`: Used to read file and then parsed to populate a `CodeBody` AST. | ||||
| * **gen_segemetned**: Dependencies go into gen.dep.{hpp/cpp} and components into gen.{hpp/cpp} | ||||
| * **gen_singleheader**: Everything into a single file: gen.hpp | ||||
| * **gen_unreal_engine**: Like gen_segemented but the library is modified slightly to compile as a thirdparty library within an Unreal Engine plugin or module. | ||||
| * **gen_c_library**: The library is heavily modifed into C11 compliant code. A segemented and single-header set of variants are generatd. | ||||
|  | ||||
|  | ||||
| Code not making up the core library is located in `auxiliary/<auxiliary_name>.<hpp/cpp>`. These are optional extensions or tools for the library. | ||||
|  | ||||
| Feature Macros: | ||||
|  | ||||
| * `GEN_DEFINE_ATTRIBUTE_TOKENS` : Allows user to define their own attribute macros for use in parsing. | ||||
|   * This is auto-generated if using the bootstrap or single-header generation | ||||
|   * *Note: The user will use the `AttributeTokens.csv` when the library is fully self-hosting.* | ||||
| * `GEN_DEFINE_LIBRARY_CORE_CONSTANTS` : Optional typename codes as they are non-standard to C/C++ and not necessary to library usage | ||||
| * `GEN_DONT_ENFORCE_GEN_TIME_GUARD` : By default, the library ( gen.hpp/ gen.cpp ) expects the macro `GEN_TIME` to be defined, this disables that. | ||||
| * `GEN_ENFORCE_STRONG_CODE_TYPES` : Enforces casts to filtered code types. | ||||
| * `GEN_EXPOSE_BACKEND` : Will expose symbols meant for internal use only. | ||||
| * `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. | ||||
| * `GEN_C_LIKE_PP` : Will prevent usage of function defnitions using references and structs with member functions. | ||||
| Structs will still have user-defined operator conversions, for-range support, and other operator overloads | ||||
|  | ||||
| *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. | ||||
|  | ||||
| ## Extending the library | ||||
|  | ||||
| This library is relatively very small (for parsing C++), and can be extended without much hassle. | ||||
|  | ||||
| The convention you'll see used throughout the interface of the library is as follows: | ||||
|  | ||||
| 1. Check name or parameters to make sure they are valid for the construction requested | ||||
| 2. Create a code object using `make_code`. | ||||
| 3. Populate immediate fields (Name, Type, ModuleFlags, etc) | ||||
| 4. Populate sub-entires using `add_entry`. If using the default serialization function `to_string`, follow the order at which entires are expected to appear (there is a strong ordering expected). | ||||
|  | ||||
| Names or Content fields are interned strings and thus showed be cached using `get_cached_string` if its desired to preserve that behavior. | ||||
|  | ||||
| `def_operator` is the most sophisticated upfront constructor as it has multiple permutations of definitions that could be created that are not trivial to determine if valid. | ||||
|  | ||||
| The parser is documented under `docs/Parsing.md` and `docs/Parser_Algo.md`. Extending it is more serious, but resolution of a parse for a given internal parse procedure is well documented. | ||||
|  | ||||
| ## A note on compilation and runtime generation speed | ||||
|  | ||||
| The library is designed to be fast to compile and generate code at runtime as fast as resonable possible on a debug build. | ||||
| Its recommended that your metaprogam be compiled using a single translation unit (unity build). | ||||
							
								
								
									
										59
									
								
								base/auxillary/builder.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								base/auxillary/builder.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	include "builder.hpp" | ||||
| #endif | ||||
|  | ||||
| #pragma region Builder | ||||
|  | ||||
| Builder builder_open( char const* path ) | ||||
| { | ||||
| 	Builder result; | ||||
|  | ||||
| 	FileError error = file_open_mode( & result.File, EFileMode_WRITE, path ); | ||||
| 	if ( error != EFileError_NONE ) | ||||
| 	{ | ||||
| 		log_failure( "gen::File::open - Could not open file: %s", path); | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	result.Buffer = string_make_reserve( GlobalAllocator, Builder_StrBufferReserve ); | ||||
|  | ||||
| 	// log_fmt("$Builder - Opened file: %s\n", result.File.filename ); | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| void builder_pad_lines( Builder* builder, s32 num ) | ||||
| { | ||||
| 	string_append_strc( & builder->Buffer, txt("\n") ); | ||||
| } | ||||
|  | ||||
| void builder_print( Builder* builder, Code code ) | ||||
| { | ||||
| 	String   str = code_to_string(code); | ||||
| 	// const ssize len = str.length(); | ||||
| 	// log_fmt( "%s - print: %.*s\n", File.filename, len > 80 ? 80 : len, str.Data ); | ||||
| 	string_append_string( & builder->Buffer, str ); | ||||
| } | ||||
|  | ||||
| void builder_print_fmt_va( Builder* builder, char const* fmt, va_list va ) | ||||
| { | ||||
| 	ssize   res; | ||||
| 	char buf[ GEN_PRINTF_MAXLEN ] = { 0 }; | ||||
|  | ||||
| 	res = str_fmt_va( buf, count_of( buf ) - 1, fmt, va ) - 1; | ||||
|  | ||||
| 	string_append_c_str_len( (String*) & (builder->Buffer), (char const*)buf, res); | ||||
| } | ||||
|  | ||||
| void builder_write(Builder* builder) | ||||
| { | ||||
| 	b32 result = file_write( & builder->File, builder->Buffer, string_length(builder->Buffer) ); | ||||
|  | ||||
| 	if ( result == false ) | ||||
| 		log_failure("gen::File::write - Failed to write to file: %s\n", file_name( & builder->File ) ); | ||||
|  | ||||
| 	log_fmt( "Generated: %s\n", builder->File.filename ); | ||||
| 	file_close( & builder->File ); | ||||
| 	string_free(& builder->Buffer); | ||||
| } | ||||
|  | ||||
| #pragma endregion Builder | ||||
							
								
								
									
										69
									
								
								base/auxillary/builder.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								base/auxillary/builder.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	pragma once | ||||
| #	include "helpers/push_ignores.inline.hpp" | ||||
| #	include "components/header_start.hpp" | ||||
| #	include "components/types.hpp" | ||||
| #	include "components/gen/ecode.hpp" | ||||
| #	include "components/gen/eoperator.hpp" | ||||
| #	include "components/gen/especifier.hpp" | ||||
| #	include "components/ast.hpp" | ||||
| #	include "components/code_types.hpp" | ||||
| #	include "components/ast_types.hpp" | ||||
| #	include "components/interface.hpp" | ||||
| #	include "components/inlines.hpp" | ||||
| #	include "components/gen/ast_inlines.hpp" | ||||
| #	include "components/header_end.hpp" | ||||
| #endif | ||||
|  | ||||
| #pragma region Builder | ||||
|  | ||||
| struct Builder; | ||||
| typedef struct Builder Builder; | ||||
|  | ||||
| Builder builder_open        ( char const* path ); | ||||
| void    builder_pad_lines   ( Builder* builder, s32 num ); | ||||
| void    builder_print       ( Builder* builder, Code code ); | ||||
| void    builder_print_fmt_va( Builder* builder, char const* fmt, va_list va ); | ||||
| void    builder_print_fmt   ( Builder* builder, char const* fmt, ... ) { | ||||
| 	va_list va; | ||||
| 	va_start( va, fmt ); | ||||
| 	builder_print_fmt_va( builder, fmt, va ); | ||||
| 	va_end( va ); | ||||
| } | ||||
| void builder_write( Builder* builder ); | ||||
|  | ||||
| struct Builder | ||||
| { | ||||
| 	FileInfo File; | ||||
| 	String   Buffer; | ||||
|  | ||||
| #if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP | ||||
| 	forceinline static Builder open( char const* path ) { return builder_open(path); } | ||||
|  | ||||
| 	forceinline void pad_lines( s32 num ) { return builder_pad_lines(this, num); } | ||||
|  | ||||
| 	forceinline void print( Code code )                { return builder_print(this, code); } | ||||
| 	forceinline void print_fmt( char const* fmt, ... ) { | ||||
| 		va_list va; | ||||
| 		va_start( va, fmt ); | ||||
| 		builder_print_fmt_va( this, fmt, va ); | ||||
| 		va_end( va ); | ||||
| 	} | ||||
|  | ||||
| 	forceinline void write() { return builder_write(this); } | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| #if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP | ||||
| void    builder_pad_lines( Builder& builder, s32 num )    { return builder_pad_lines(& builder, num); } | ||||
| void    builder_print    ( Builder& builder, Code code )  { return builder_print(& builder, code); } | ||||
| void    builder_write    ( Builder& builder )             { return builder_write(& builder ); } | ||||
| void    builder_print_fmt( Builder& builder, char const* fmt, ...) { | ||||
| 	va_list va; | ||||
| 	va_start( va, fmt ); | ||||
| 	builder_print_fmt_va( & builder, fmt, va ); | ||||
| 	va_end( va ); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #pragma endregion Builder | ||||
							
								
								
									
										35
									
								
								base/auxillary/gen_template.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								base/auxillary/gen_template.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	pragma once | ||||
| #	include "helpers/push_ignores.inline.hpp" | ||||
| #	include "components/header_start.hpp" | ||||
| #	include "components/types.hpp" | ||||
| #	include "components/gen/ecode.hpp" | ||||
| #	include "components/gen/eoperator.hpp" | ||||
| #	include "components/gen/especifier.hpp" | ||||
| #	include "components/ast.hpp" | ||||
| #	include "components/code_types.hpp" | ||||
| #	include "components/ast_types.hpp" | ||||
| #	include "components/interface.hpp" | ||||
| #	include "components/inlines.hpp" | ||||
| #	include "components/gen/ast_inlines.hpp" | ||||
| #	include "components/header_end.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 ); | ||||
							
								
								
									
										5
									
								
								base/auxillary/scanner.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								base/auxillary/scanner.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	include "scanner.hpp" | ||||
| #endif | ||||
|  | ||||
|  | ||||
							
								
								
									
										185
									
								
								base/auxillary/scanner.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										185
									
								
								base/auxillary/scanner.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,185 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	pragma once | ||||
| #	include "helpers/push_ignores.inline.hpp" | ||||
| #	include "components/header_start.hpp" | ||||
| #	include "components/types.hpp" | ||||
| #	include "components/gen/ecode.hpp" | ||||
| #	include "components/gen/eoperator.hpp" | ||||
| #	include "components/gen/especifier.hpp" | ||||
| #	include "components/ast.hpp" | ||||
| #	include "components/code_types.hpp" | ||||
| #	include "components/ast_types.hpp" | ||||
| #	include "components/interface.hpp" | ||||
| #	include "components/inlines.hpp" | ||||
| #	include "components/gen/ast_inlines.hpp" | ||||
| #	include "components/header_end.hpp" | ||||
| #endif | ||||
|  | ||||
| #pragma region Scanner | ||||
|  | ||||
| // 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; | ||||
|  | ||||
| 	FileError error = file_open_mode( & file, EFileMode_READ, path ); | ||||
| 	if ( error != EFileError_NONE ) | ||||
| 	{ | ||||
| 		GEN_FATAL( "scan_file: Could not open: %s", path ); | ||||
| 	} | ||||
|  | ||||
| 	ssize fsize = file_size( & file ); | ||||
| 	if ( fsize <= 0 ) | ||||
| 	{ | ||||
| 		GEN_FATAL("scan_file: %s is empty", path ); | ||||
| 	} | ||||
|  | ||||
| 	String str = string_make_reserve( GlobalAllocator, fsize ); | ||||
| 		file_read( & file, str, 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. | ||||
| 	// Anything that comes before it will also be omitted. | ||||
| 	{ | ||||
| 	#define current (*scanner) | ||||
| 	#define matched    0 | ||||
| 	#define move_fwd() do { ++ scanner; -- left; } while (0) | ||||
| 		const StrC directive_start = txt( "ifdef" ); | ||||
| 		const StrC directive_end   = txt( "endif" ); | ||||
| 		const StrC def_intellisense = txt("GEN_INTELLISENSE_DIRECTIVES" ); | ||||
|  | ||||
| 		bool        found_directive = false; | ||||
| 		char const* scanner         = (char const*)str; | ||||
| 		s32         left            = fsize; | ||||
| 		while ( left ) | ||||
| 		{ | ||||
| 			// Processing directive. | ||||
| 			if ( current == '#' ) | ||||
| 			{ | ||||
| 				move_fwd(); | ||||
| 				while ( left && char_is_space( current ) ) | ||||
| 					move_fwd(); | ||||
|  | ||||
| 				if ( ! found_directive ) | ||||
| 				{ | ||||
| 					if ( left && str_compare_len( scanner, directive_start.Ptr, directive_start.Len ) == matched ) | ||||
| 					{ | ||||
| 						scanner += directive_start.Len; | ||||
| 						left    -= directive_start.Len; | ||||
|  | ||||
| 						while ( left && char_is_space( current ) ) | ||||
| 							move_fwd(); | ||||
|  | ||||
| 						if ( left && str_compare_len( scanner, def_intellisense.Ptr, def_intellisense.Len ) == matched ) | ||||
| 						{ | ||||
| 							scanner += def_intellisense.Len; | ||||
| 							left    -= def_intellisense.Len; | ||||
|  | ||||
| 							found_directive = true; | ||||
| 						} | ||||
| 					} | ||||
|  | ||||
| 					// Skip to end of line | ||||
| 					while ( left && current != '\r' && current != '\n' ) | ||||
| 						move_fwd(); | ||||
| 					move_fwd(); | ||||
|  | ||||
| 					if ( left && current == '\n' ) | ||||
| 						move_fwd(); | ||||
|  | ||||
| 					continue; | ||||
| 				} | ||||
|  | ||||
| 				if ( left && str_compare_len( scanner, directive_end.Ptr, directive_end.Len ) == matched ) | ||||
| 				{ | ||||
| 					scanner += directive_end.Len; | ||||
| 					left    -= directive_end.Len; | ||||
|  | ||||
| 					// Skip to end of line | ||||
| 					while ( left && current != '\r' && current != '\n' ) | ||||
| 						move_fwd(); | ||||
| 					move_fwd(); | ||||
|  | ||||
| 					if ( left && current == '\n' ) | ||||
| 						move_fwd(); | ||||
|  | ||||
| 					// sptr skip_size = fsize - left; | ||||
| 					if ( (scanner + 2) >= ( (char const*) str + fsize ) ) | ||||
| 					{ | ||||
| 						mem_move( str, scanner, left ); | ||||
| 						string_get_header(str)->Length = left; | ||||
| 						break; | ||||
| 					} | ||||
|  | ||||
| 					mem_move( str, scanner, left ); | ||||
| 					string_get_header(str)->Length = left; | ||||
|  | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			move_fwd(); | ||||
| 		} | ||||
| 	#undef move_fwd | ||||
| 	#undef matched | ||||
| 	#undef current | ||||
| 	} | ||||
|  | ||||
| 	file_close( & file ); | ||||
| 	return untyped_str( string_to_strc(str) ); | ||||
| } | ||||
|  | ||||
| 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; | ||||
| } | ||||
|  | ||||
| // The follow is basic support for light csv parsing (use it as an example) | ||||
| // Make something robust if its more serious. | ||||
|  | ||||
| typedef struct CSV_Column CSV_Column; | ||||
| struct CSV_Column { | ||||
| 	CSV_Object Owner; | ||||
| 	Array<ADT_Node> Content; | ||||
| }; | ||||
|  | ||||
| typedef struct CSV_Columns2 CSV_Columns2; | ||||
| struct CSV_Columns2 { | ||||
| 	CSV_Object Owner; | ||||
| 	Array<ADT_Node> Col_1; | ||||
| 	Array<ADT_Node> Col_2; | ||||
| }; | ||||
|  | ||||
| CSV_Column parse_csv_one_column(AllocatorInfo allocator, char const* path) { | ||||
| 	char scratch_mem[kilobytes(32)]; | ||||
| 	Arena scratch = arena_init_from_memory( scratch_mem, sizeof(scratch_mem) ); | ||||
|  | ||||
| 	file_read_contents( arena_allocator_info( & scratch), file_zero_terminate, path ); | ||||
|  | ||||
| 	CSV_Column result; | ||||
| 	csv_parse( & result.owner, scratch_mem, allocator, false ); | ||||
| 	result.Content = csv_nodes.nodes[0].nodes; | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| CSV_Columns2 parse_csv_two_columns(AllocatorInfo allocator, char const* path) { | ||||
| 	char scratch_mem[kilobytes(32)]; | ||||
| 	Arena scratch = arena_init_from_memory( scratch_mem, sizeof(scratch_mem) ); | ||||
|  | ||||
| 	file_read_contents( arena_allocator_info( & scratch), file_zero_terminate, path ); | ||||
|  | ||||
| 	CSV_Columns2 result; | ||||
| 	csv_parse( & result.owner, scratch_mem, allocator, false ); | ||||
| 	result.Col_1 = csv_nodes.nodes[0].nodes; | ||||
| 	result.Col_2 = csv_nodes.nodes[1].nodes; | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| #pragma endregion Scanner | ||||
							
								
								
									
										56
									
								
								base/base.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								base/base.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| #define GEN_DEFINE_LIBRARY_CODE_CONSTANTS | ||||
| #define GEN_ENFORCE_STRONG_CODE_TYPES | ||||
| #define GEN_EXPOSE_BACKEND | ||||
| #define GEN_C_LIKE_CPP 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 "auxillary/misc.hpp" | ||||
|  | ||||
| using namespace gen; | ||||
|  | ||||
| constexpr char const* path_format_style = "../scripts/.clang-format"; | ||||
| constexpr char const* scratch_file      = "gen/scratch.hpp"; | ||||
|  | ||||
| Code format( Code code ) { | ||||
| 	return code_refactor_and_format(code, scratch_file, nullptr, path_format_style ); | ||||
| } | ||||
|  | ||||
| int gen_main() | ||||
| { | ||||
| 	CodeBody ecode       = gen_ecode     ( "enums/ECodeTypes.csv" ); | ||||
| 	CodeBody eoperator   = gen_eoperator ( "enums/EOperator.csv" ); | ||||
| 	CodeBody especifier  = gen_especifier( "enums/ESpecifier.csv" ); | ||||
| 	CodeBody ast_inlines = gen_ast_inlines(); | ||||
|  | ||||
| 	Builder header_ecode = builder_open( "components/gen/ecode.hpp" ); | ||||
| 	builder_print( & header_ecode, gen_component_header ); | ||||
| 	builder_print( & header_ecode, format(ecode) ); | ||||
| 	builder_write( & header_ecode); | ||||
|  | ||||
| 	Builder header_eoperator = builder_open( "components/gen/eoperator.hpp" ); | ||||
| 	builder_print( & header_eoperator, gen_component_header ); | ||||
| 	builder_print( & header_eoperator, format(eoperator) ); | ||||
| 	builder_write( & header_eoperator ); | ||||
|  | ||||
| 	Builder header_especifier = builder_open( "components/gen/especifier.hpp" ); | ||||
| 	builder_print( & header_especifier, gen_component_header ); | ||||
| 	builder_print( & header_especifier, format(especifier) ); | ||||
| 	builder_write( & header_especifier); | ||||
|  | ||||
| 	Builder header_ast_inlines = builder_open( "components/gen/ast_inlines.hpp" ); | ||||
| 	builder_print( & header_ast_inlines, gen_component_header ); | ||||
| 	builder_print( & header_ast_inlines, format(ast_inlines) ); | ||||
| 	builder_write( & header_ast_inlines); | ||||
| } | ||||
							
								
								
									
										1277
									
								
								base/components/ast.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1277
									
								
								base/components/ast.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										479
									
								
								base/components/ast.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										479
									
								
								base/components/ast.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,479 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #pragma once | ||||
| #include "types.hpp" | ||||
| #include "gen/ecode.hpp" | ||||
| #include "gen/eoperator.hpp" | ||||
| #include "gen/especifier.hpp" | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|   ______   ______  ________      __    __       ______                 __ | ||||
|  /      \ /      \|        \    |  \  |  \     /      \               |  \ | ||||
| |  ▓▓▓▓▓▓\  ▓▓▓▓▓▓\\▓▓▓▓▓▓▓▓    | ▓▓\ | ▓▓    |  ▓▓▓▓▓▓\ ______   ____| ▓▓ ______ | ||||
| | ▓▓__| ▓▓ ▓▓___\▓▓  | ▓▓       | ▓▓▓\| ▓▓    | ▓▓   \▓▓/      \ /      ▓▓/      \ | ||||
| | ▓▓    ▓▓\▓▓    \   | ▓▓       | ▓▓▓▓\ ▓▓    | ▓▓     |  ▓▓▓▓▓▓\  ▓▓▓▓▓▓▓  ▓▓▓▓▓▓\ | ||||
| | ▓▓▓▓▓▓▓▓_\▓▓▓▓▓▓\  | ▓▓       | ▓▓\▓▓ ▓▓    | ▓▓   __| ▓▓  | ▓▓ ▓▓  | ▓▓ ▓▓    ▓▓ | ||||
| | ▓▓  | ▓▓  \__| ▓▓  | ▓▓       | ▓▓ \▓▓▓▓    | ▓▓__/  \ ▓▓__/ ▓▓ ▓▓__| ▓▓ ▓▓▓▓▓▓▓▓ | ||||
| | ▓▓  | ▓▓\▓▓    ▓▓  | ▓▓       | ▓▓  \▓▓▓     \▓▓    ▓▓\▓▓    ▓▓\▓▓    ▓▓\▓▓     \ | ||||
|  \▓▓   \▓▓ \▓▓▓▓▓▓    \▓▓        \▓▓   \▓▓      \▓▓▓▓▓▓  \▓▓▓▓▓▓  \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ | ||||
| */ | ||||
|  | ||||
| struct AST; | ||||
| struct AST_Body; | ||||
| struct AST_Attributes; | ||||
| struct AST_Comment; | ||||
| struct AST_Constructor; | ||||
| // struct AST_BaseClass; | ||||
| struct AST_Class; | ||||
| struct AST_Define; | ||||
| struct AST_Destructor; | ||||
| struct AST_Enum; | ||||
| struct AST_Exec; | ||||
| struct AST_Extern; | ||||
| struct AST_Include; | ||||
| struct AST_Friend; | ||||
| struct AST_Fn; | ||||
| struct AST_Module; | ||||
| struct AST_NS; | ||||
| struct AST_Operator; | ||||
| struct AST_OpCast; | ||||
| struct AST_Param; | ||||
| struct AST_Pragma; | ||||
| struct AST_PreprocessCond; | ||||
| struct AST_Specifiers; | ||||
|  | ||||
| #if GEN_EXECUTION_EXPRESSION_SUPPORT | ||||
| struct AST_Expr; | ||||
| struct AST_Expr_Assign; | ||||
| struct AST_Expr_Alignof; | ||||
| struct AST_Expr_Binary; | ||||
| struct AST_Expr_CStyleCast; | ||||
| struct AST_Expr_FunctionalCast; | ||||
| struct AST_Expr_CppCast; | ||||
| struct AST_Expr_ProcCall; | ||||
| struct AST_Expr_Decltype; | ||||
| struct AST_Expr_Comma;  // TODO(Ed) : This is a binary op not sure if it needs its own AST... | ||||
| struct AST_Expr_AMS;    // Access Member Symbol | ||||
| struct AST_Expr_Sizeof; | ||||
| struct AST_Expr_Subscript; | ||||
| struct AST_Expr_Ternary; | ||||
| struct AST_Expr_UnaryPrefix; | ||||
| struct AST_Expr_UnaryPostfix; | ||||
| struct AST_Expr_Element; | ||||
|  | ||||
| struct AST_Stmt; | ||||
| struct AST_Stmt_Break; | ||||
| struct AST_Stmt_Case; | ||||
| struct AST_Stmt_Continue; | ||||
| struct AST_Stmt_Decl; | ||||
| struct AST_Stmt_Do; | ||||
| struct AST_Stmt_Expr;  // TODO(Ed) : Is this distinction needed? (Should it be a flag instead?) | ||||
| struct AST_Stmt_Else; | ||||
| struct AST_Stmt_If; | ||||
| struct AST_Stmt_For; | ||||
| struct AST_Stmt_Goto; | ||||
| struct AST_Stmt_Label; | ||||
| struct AST_Stmt_Switch; | ||||
| struct AST_Stmt_While; | ||||
| #endif | ||||
|  | ||||
| struct AST_Struct; | ||||
| struct AST_Template; | ||||
| struct AST_Typename; | ||||
| struct AST_Typedef; | ||||
| struct AST_Union; | ||||
| struct AST_Using; | ||||
| struct AST_Var; | ||||
|  | ||||
| #if GEN_COMPILER_C | ||||
| typedef AST* Code; | ||||
| #else | ||||
| struct Code; | ||||
| #endif | ||||
|  | ||||
| #if GEN_COMPILER_C | ||||
| typedef AST_Body*           CodeBody; | ||||
| typedef AST_Attributes*     CodeAttributes; | ||||
| typedef AST_Comment*        CodeComment; | ||||
| typedef AST_Class*          CodeClass; | ||||
| typedef AST_Constructor*    CodeConstructor; | ||||
| typedef AST_Define*         CodeDefine; | ||||
| typedef AST_Destructor*     CodeDestructor; | ||||
| typedef AST_Enum*           CodeEnum; | ||||
| typedef AST_Exec*           CodeExec; | ||||
| typedef AST_Extern*         CodeExtern; | ||||
| typedef AST_Include*        CodeInclude; | ||||
| typedef AST_Friend*         CodeFriend; | ||||
| typedef AST_Fn*             CodeFn; | ||||
| typedef AST_Module*         CodeModule; | ||||
| typedef AST_NS*             CodeNS; | ||||
| typedef AST_Operator*       CodeOperator; | ||||
| typedef AST_OpCast*         CodeOpCast; | ||||
| typedef AST_Param*          CodeParam; | ||||
| typedef AST_PreprocessCond* CodePreprocessCond; | ||||
| typedef AST_Pragma*         CodePragma; | ||||
| typedef AST_Specifiers*     CodeSpecifiers; | ||||
| #else | ||||
| struct CodeBody; | ||||
| struct CodeAttributes; | ||||
| 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; | ||||
| #endif | ||||
|  | ||||
| #if GEN_EXECUTION_EXPRESSION_SUPPORT | ||||
|  | ||||
| #if GEN_COMPILER_C | ||||
| typedef AST_Expr*                CodeExpr; | ||||
| typedef AST_Expr_Assign*         CodeExpr_Assign; | ||||
| typedef AST_Expr_Alignof*        CodeExpr_Alignof; | ||||
| typedef AST_Expr_Binary*         CodeExpr_Binary; | ||||
| typedef AST_Expr_CStyleCast*     CodeExpr_CStyleCast; | ||||
| typedef AST_Expr_FunctionalCast* CodeExpr_FunctionalCast; | ||||
| typedef AST_Expr_CppCast*        CodeExpr_CppCast; | ||||
| typedef AST_Expr_Element*        CodeExpr_Element; | ||||
| typedef AST_Expr_ProcCall*       CodeExpr_ProcCall; | ||||
| typedef AST_Expr_Decltype*       CodeExpr_Decltype; | ||||
| typedef AST_Expr_Comma*          CodeExpr_Comma; | ||||
| typedef AST_Expr_AMS*            CodeExpr_AMS; // Access Member Symbol | ||||
| typedef AST_Expr_Sizeof*         CodeExpr_Sizeof; | ||||
| typedef AST_Expr_Subscript*      CodeExpr_Subscript; | ||||
| typedef AST_Expr_Ternary*        CodeExpr_Ternary; | ||||
| typedef AST_Expr_UnaryPrefix*    CodeExpr_UnaryPrefix; | ||||
| typedef AST_Expr_UnaryPostfix*   CodeExpr_UnaryPostfix; | ||||
| #else | ||||
| 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; | ||||
| #endif | ||||
|  | ||||
| #if GEN_COMPILER_C | ||||
| typedef AST_Stmt*          CodeStmt; | ||||
| typedef AST_Stmt_Break*    CodeStmt_Break; | ||||
| typedef AST_Stmt_Case*     CodeStmt_Case; | ||||
| typedef AST_Stmt_Continue* CodeStmt_Continue; | ||||
| typedef AST_Stmt_Decl*     CodeStmt_Decl; | ||||
| typedef AST_Stmt_Do*       CodeStmt_Do; | ||||
| typedef AST_Stmt_Expr*     CodeStmt_Expr; | ||||
| typedef AST_Stmt_Else*     CodeStmt_Else; | ||||
| typedef AST_Stmt_If*       CodeStmt_If; | ||||
| typedef AST_Stmt_For*      CodeStmt_For; | ||||
| typedef AST_Stmt_Goto*     CodeStmt_Goto; | ||||
| typedef AST_Stmt_Label*    CodeStmt_Label; | ||||
| typedef AST_Stmt_Switch*   CodeStmt_Switch; | ||||
| typedef AST_Stmt_While*    CodeStmt_While; | ||||
| #else | ||||
| 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; | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
|  | ||||
| #if GEN_COMPILER_C | ||||
| typedef AST_Struct*   CodeStruct; | ||||
| typedef AST_Template* CodeTemplate; | ||||
| typedef AST_Typename* CodeTypename; | ||||
| typedef AST_Typedef*  CodeTypedef; | ||||
| typedef AST_Union*    CodeUnion; | ||||
| typedef AST_Using*    CodeUsing; | ||||
| typedef AST_Var*      CodeVar; | ||||
| #else | ||||
| struct CodeStruct; | ||||
| struct CodeTemplate; | ||||
| struct CodeTypename; | ||||
| struct CodeTypedef; | ||||
| struct CodeUnion; | ||||
| struct CodeUsing; | ||||
| struct CodeVar; | ||||
| #endif | ||||
|  | ||||
| #undef Define_Code | ||||
|  | ||||
| GEN_NS_PARSER_BEGIN | ||||
|  | ||||
| struct Token; | ||||
|  | ||||
| GEN_NS_PARSER_END | ||||
|  | ||||
| #if GEN_COMPILER_CPP | ||||
| // Note(Ed): This is to alleviate an edge case with parsing usings or typedefs where I don't really have it setup | ||||
| // to parse a 'namespace' macro or a type with a macro. | ||||
| // I have ideas for ways to pack that into the typedef/using ast, but for now just keeping it like this | ||||
| #define ParserTokenType GEN_NS_PARSER Token | ||||
| typedef ParserTokenType Token; | ||||
| #undef ParserTokenType | ||||
| #endif | ||||
|  | ||||
| #if GEN_COMPILER_CPP | ||||
| template< class Type> forceinline Type tmpl_cast( Code self ) { return * rcast( Type*, & self ); } | ||||
| #endif | ||||
|  | ||||
| #pragma region Code C-Interface | ||||
|  | ||||
| void   code_append       (Code code, Code other ); | ||||
| StrC   code_debug_str    (Code code); | ||||
| Code   code_duplicate    (Code code); | ||||
| Code*  code_entry        (Code code, u32 idx ); | ||||
| bool   code_has_entries  (Code code); | ||||
| bool   code_is_body      (Code code); | ||||
| bool   code_is_equal     (Code code, Code other); | ||||
| bool   code_is_valid     (Code code); | ||||
| void   code_set_global   (Code code); | ||||
| String code_to_string    (Code self ); | ||||
| void   code_to_string_ptr(Code self, String* result ); | ||||
| StrC   code_type_str     (Code self ); | ||||
| bool   code_validate_body(Code self ); | ||||
|  | ||||
| #pragma endregion Code C-Interface | ||||
|  | ||||
| #if GEN_COMPILER_CPP | ||||
| /* | ||||
| 	AST* wrapper | ||||
| 	- Not constantly have to append the '*' as this is written often.. | ||||
| 	- Allows for implicit conversion to any of the ASTs (raw or filtered). | ||||
| */ | ||||
| struct Code | ||||
| { | ||||
| 	AST* ast; | ||||
|  | ||||
| #	define Using_Code( Typename )                                                        \ | ||||
| 	forceinline StrC debug_str()                { return code_debug_str(* this); }       \ | ||||
| 	forceinline Code duplicate()                { return code_duplicate(* this); }	     \ | ||||
| 	forceinline bool is_equal( Code other )     { return code_is_equal(* this, other); } \ | ||||
| 	forceinline bool is_body()                  { return code_is_body(* this); }         \ | ||||
| 	forceinline bool is_valid()                 { return code_is_valid(* this); }        \ | ||||
| 	forceinline void set_global()               { return code_set_global(* this); } | ||||
|  | ||||
| #	define Using_CodeOps( Typename )                                                                           \ | ||||
| 	forceinline Typename&  operator = ( Code other );                                                          \ | ||||
| 	forceinline bool       operator ==( Code other )                        { return (AST*)ast == other.ast; } \ | ||||
| 	forceinline bool       operator !=( Code other )                        { return (AST*)ast != other.ast; } \ | ||||
| 	forceinline bool       operator ==(std::nullptr_t) const                { return ast == nullptr; }         \ | ||||
| 	forceinline bool       operator !=(std::nullptr_t) const                { return ast != nullptr;  }        \ | ||||
| 	operator bool(); | ||||
|  | ||||
| #if ! GEN_C_LIKE_CPP | ||||
| 	Using_Code( Code ); | ||||
| 	forceinline void   append(Code other)        { return code_append(* this, other); } | ||||
| 	forceinline Code*  entry(u32 idx)            { return code_entry(* this, idx); } | ||||
| 	forceinline bool   has_entries()             { return code_has_entries(* this); } | ||||
| 	forceinline String to_string()               { return code_to_string(* this); } | ||||
| 	forceinline void   to_string(String& result) { return code_to_string_ptr(* this, & result); } | ||||
| 	forceinline StrC   type_str()                { return code_type_str(* this); } | ||||
| 	forceinline bool   validate_body()           { return code_validate_body(*this); } | ||||
| #endif | ||||
|  | ||||
| 	Using_CodeOps( Code ); | ||||
| 	forceinline AST* operator ->() { return ast; } | ||||
|  | ||||
| 	Code& operator ++(); | ||||
|  | ||||
| 	// TODO(Ed) : Remove this overload. | ||||
| 	auto& operator*() | ||||
| 	{ | ||||
| 		local_persist thread_local | ||||
| 		Code NullRef = { nullptr }; | ||||
|  | ||||
| 		if ( ast == nullptr ) | ||||
| 			return NullRef; | ||||
|  | ||||
| 		return *this; | ||||
| 	} | ||||
|  | ||||
| #ifdef GEN_ENFORCE_STRONG_CODE_TYPES | ||||
| #	define operator explicit operator | ||||
| #endif | ||||
| 	operator CodeBody() const; | ||||
| 	operator CodeAttributes() const; | ||||
| 	// operator CodeBaseClass() const; | ||||
| 	operator CodeComment() const; | ||||
| 	operator CodeClass() const; | ||||
| 	operator CodeConstructor() const; | ||||
| 	operator CodeDefine() const; | ||||
| 	operator CodeDestructor() const; | ||||
| 	operator CodeExec() const; | ||||
| 	operator CodeEnum() const; | ||||
| 	operator CodeExtern() const; | ||||
| 	operator CodeInclude() const; | ||||
| 	operator CodeFriend() const; | ||||
| 	operator CodeFn() const; | ||||
| 	operator CodeModule() const; | ||||
| 	operator CodeNS() const; | ||||
| 	operator CodeOperator() const; | ||||
| 	operator CodeOpCast() const; | ||||
| 	operator CodeParam() const; | ||||
| 	operator CodePragma() const; | ||||
| 	operator CodePreprocessCond() const; | ||||
| 	operator CodeSpecifiers() const; | ||||
| 	operator CodeStruct() const; | ||||
| 	operator CodeTemplate() 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; | ||||
|  | ||||
| constexpr static | ||||
| int AST_ArrSpecs_Cap = | ||||
| ( | ||||
| 	AST_POD_Size | ||||
| 	- sizeof(Code) | ||||
| 	- sizeof(StringCached) | ||||
| 	- sizeof(Code) * 2 | ||||
| 	- sizeof(Token*) | ||||
| 	- sizeof(Code) | ||||
| 	- sizeof(CodeType) | ||||
| 	- sizeof(ModuleFlag) | ||||
| 	- sizeof(u32) | ||||
| ) | ||||
| / sizeof(Specifier) - 1; | ||||
|  | ||||
| /* | ||||
| 	Simple AST POD with functionality to seralize into C++ syntax. | ||||
| */ | ||||
| struct AST | ||||
| { | ||||
| 	union { | ||||
| 		struct | ||||
| 		{ | ||||
| 			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 { | ||||
| 				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 { | ||||
| 				Code  Macro;               // Parameter | ||||
| 				Code  BitfieldSize;        // Variable (Class/Struct Data Member) | ||||
| 				Code  Params;              // Constructor, Function, Operator, Template, Typename | ||||
| 				Code  UnderlyingTypeMacro; // Enum | ||||
| 			}; | ||||
| 			union { | ||||
| 				Code  ArrExpr;          // Typename | ||||
| 				Code  Body;             // Class, Constructor, Destructor, Enum, Friend, Function, Namespace, Struct, Union | ||||
| 				Code  Declaration;      // Friend, Template | ||||
| 				Code  Value;            // Parameter, Variable | ||||
| 			}; | ||||
| 			union { | ||||
| 				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 { | ||||
| 			Specifier  ArrSpecs[AST_ArrSpecs_Cap]; // Specifiers | ||||
| 			Code       NextSpecs;              // Specifiers; If ArrSpecs is full, then NextSpecs is used. | ||||
| 		}; | ||||
| 	}; | ||||
| 	StringCached      Name; | ||||
| 	union { | ||||
| 		Code Prev; | ||||
| 		Code Front; | ||||
| 		Code Last; | ||||
| 	}; | ||||
| 	union { | ||||
| 		Code Next; | ||||
| 		Code Back; | ||||
| 	}; | ||||
| 	Token*            Token; // Reference to starting token, only avaialble if it was derived from parsing. | ||||
| 	Code              Parent; | ||||
| 	CodeType          Type; | ||||
| //	CodeFlag          CodeFlags; | ||||
| 	ModuleFlag        ModuleFlags; | ||||
| 	union { | ||||
| 		b32           IsFunction;  // Used by typedef to not serialize the name field. | ||||
| 		struct { | ||||
| 			b16           IsParamPack;   // Used by typename to know if type should be considered a parameter pack. | ||||
| 			ETypenameTag  TypeTag;       // Used by typename to keep track of explicitly declared tags for the identifier (enum, struct, union) | ||||
| 		}; | ||||
| 		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. | ||||
| 	}; | ||||
| }; | ||||
| static_assert( sizeof(AST) == AST_POD_Size, "ERROR: AST is not size of AST_POD_Size" ); | ||||
|  | ||||
| #if GEN_COMPILER_CPP | ||||
| // 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 (void*){ (void*)Code_Invalid } | ||||
| #endif | ||||
|  | ||||
| #if GEN_COMPILER_CPP | ||||
| struct NullCode_ImplicitCaster; | ||||
| // Used when the its desired when omission is allowed in a definition. | ||||
| #define NullCode    (NullCode_ImplicitCaster{}) | ||||
| #else | ||||
| #define NullCode    nullptr | ||||
| #endif | ||||
							
								
								
									
										78
									
								
								base/components/ast_case_macros.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								base/components/ast_case_macros.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,78 @@ | ||||
| #	define GEN_AST_BODY_CLASS_UNALLOWED_TYPES \ | ||||
| 	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 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 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 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: | ||||
							
								
								
									
										1147
									
								
								base/components/ast_types.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1147
									
								
								base/components/ast_types.hpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1492
									
								
								base/components/code_serialization.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1492
									
								
								base/components/code_serialization.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1130
									
								
								base/components/code_types.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1130
									
								
								base/components/code_types.hpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										965
									
								
								base/components/gen/ast_inlines.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										965
									
								
								base/components/gen/ast_inlines.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,965 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #pragma once | ||||
| #include "components/types.hpp" | ||||
| #endif | ||||
|  | ||||
| // This file was generated automatially by gencpp's bootstrap.cpp (See: https://github.com/Ed94/gencpp) | ||||
|  | ||||
| #pragma region generated code inline implementation | ||||
|  | ||||
| inline Code& Code::operator=( Code other ) | ||||
| { | ||||
| 	if ( other.ast != nullptr && other->Parent != nullptr ) | ||||
| 	{ | ||||
| 		ast         = rcast( decltype( ast ), code_duplicate( other ).ast ); | ||||
| 		ast->Parent = { nullptr }; | ||||
| 	} | ||||
| 	ast = rcast( decltype( ast ), other.ast ); | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
| inline Code::operator bool() | ||||
| { | ||||
| 	return ast != nullptr; | ||||
| } | ||||
|  | ||||
| inline CodeBody& CodeBody::operator=( Code other ) | ||||
| { | ||||
| 	if ( other.ast != nullptr && other->Parent != nullptr ) | ||||
| 	{ | ||||
| 		ast         = rcast( decltype( ast ), code_duplicate( other ).ast ); | ||||
| 		ast->Parent = { nullptr }; | ||||
| 	} | ||||
| 	ast = rcast( decltype( ast ), other.ast ); | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
| inline CodeBody::operator bool() | ||||
| { | ||||
| 	return ast != nullptr; | ||||
| } | ||||
|  | ||||
| inline CodeAttributes& CodeAttributes::operator=( Code other ) | ||||
| { | ||||
| 	if ( other.ast != nullptr && other->Parent != nullptr ) | ||||
| 	{ | ||||
| 		ast         = rcast( decltype( ast ), code_duplicate( other ).ast ); | ||||
| 		ast->Parent = { nullptr }; | ||||
| 	} | ||||
| 	ast = rcast( decltype( ast ), other.ast ); | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
| inline CodeAttributes::operator bool() | ||||
| { | ||||
| 	return ast != nullptr; | ||||
| } | ||||
|  | ||||
| inline CodeAttributes::operator Code() | ||||
| { | ||||
| 	return *rcast( Code*, this ); | ||||
| } | ||||
|  | ||||
| inline AST_Attributes* CodeAttributes::operator->() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "Attempt to dereference a nullptr!" ); | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	return ast; | ||||
| } | ||||
|  | ||||
| inline CodeComment& CodeComment::operator=( Code other ) | ||||
| { | ||||
| 	if ( other.ast != nullptr && other->Parent != nullptr ) | ||||
| 	{ | ||||
| 		ast         = rcast( decltype( ast ), code_duplicate( other ).ast ); | ||||
| 		ast->Parent = { nullptr }; | ||||
| 	} | ||||
| 	ast = rcast( decltype( ast ), other.ast ); | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
| inline CodeComment::operator bool() | ||||
| { | ||||
| 	return ast != nullptr; | ||||
| } | ||||
|  | ||||
| inline CodeComment::operator Code() | ||||
| { | ||||
| 	return *rcast( Code*, this ); | ||||
| } | ||||
|  | ||||
| inline AST_Comment* CodeComment::operator->() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "Attempt to dereference a nullptr!" ); | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	return ast; | ||||
| } | ||||
|  | ||||
| inline CodeConstructor& CodeConstructor::operator=( Code other ) | ||||
| { | ||||
| 	if ( other.ast != nullptr && other->Parent != nullptr ) | ||||
| 	{ | ||||
| 		ast         = rcast( decltype( ast ), code_duplicate( other ).ast ); | ||||
| 		ast->Parent = { nullptr }; | ||||
| 	} | ||||
| 	ast = rcast( decltype( ast ), other.ast ); | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
| inline CodeConstructor::operator bool() | ||||
| { | ||||
| 	return ast != nullptr; | ||||
| } | ||||
|  | ||||
| inline CodeConstructor::operator Code() | ||||
| { | ||||
| 	return *rcast( Code*, this ); | ||||
| } | ||||
|  | ||||
| inline AST_Constructor* CodeConstructor::operator->() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "Attempt to dereference a nullptr!" ); | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	return ast; | ||||
| } | ||||
|  | ||||
| inline CodeClass& CodeClass::operator=( Code other ) | ||||
| { | ||||
| 	if ( other.ast != nullptr && other->Parent != nullptr ) | ||||
| 	{ | ||||
| 		ast         = rcast( decltype( ast ), code_duplicate( other ).ast ); | ||||
| 		ast->Parent = { nullptr }; | ||||
| 	} | ||||
| 	ast = rcast( decltype( ast ), other.ast ); | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
| inline CodeClass::operator bool() | ||||
| { | ||||
| 	return ast != nullptr; | ||||
| } | ||||
|  | ||||
| inline CodeDefine& CodeDefine::operator=( Code other ) | ||||
| { | ||||
| 	if ( other.ast != nullptr && other->Parent != nullptr ) | ||||
| 	{ | ||||
| 		ast         = rcast( decltype( ast ), code_duplicate( other ).ast ); | ||||
| 		ast->Parent = { nullptr }; | ||||
| 	} | ||||
| 	ast = rcast( decltype( ast ), other.ast ); | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
| inline CodeDefine::operator bool() | ||||
| { | ||||
| 	return ast != nullptr; | ||||
| } | ||||
|  | ||||
| inline CodeDefine::operator Code() | ||||
| { | ||||
| 	return *rcast( Code*, this ); | ||||
| } | ||||
|  | ||||
| inline AST_Define* CodeDefine::operator->() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "Attempt to dereference a nullptr!" ); | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	return ast; | ||||
| } | ||||
|  | ||||
| inline CodeDestructor& CodeDestructor::operator=( Code other ) | ||||
| { | ||||
| 	if ( other.ast != nullptr && other->Parent != nullptr ) | ||||
| 	{ | ||||
| 		ast         = rcast( decltype( ast ), code_duplicate( other ).ast ); | ||||
| 		ast->Parent = { nullptr }; | ||||
| 	} | ||||
| 	ast = rcast( decltype( ast ), other.ast ); | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
| inline CodeDestructor::operator bool() | ||||
| { | ||||
| 	return ast != nullptr; | ||||
| } | ||||
|  | ||||
| inline CodeDestructor::operator Code() | ||||
| { | ||||
| 	return *rcast( Code*, this ); | ||||
| } | ||||
|  | ||||
| inline AST_Destructor* CodeDestructor::operator->() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "Attempt to dereference a nullptr!" ); | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	return ast; | ||||
| } | ||||
|  | ||||
| inline CodeEnum& CodeEnum::operator=( Code other ) | ||||
| { | ||||
| 	if ( other.ast != nullptr && other->Parent != nullptr ) | ||||
| 	{ | ||||
| 		ast         = rcast( decltype( ast ), code_duplicate( other ).ast ); | ||||
| 		ast->Parent = { nullptr }; | ||||
| 	} | ||||
| 	ast = rcast( decltype( ast ), other.ast ); | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
| inline CodeEnum::operator bool() | ||||
| { | ||||
| 	return ast != nullptr; | ||||
| } | ||||
|  | ||||
| inline CodeEnum::operator Code() | ||||
| { | ||||
| 	return *rcast( Code*, this ); | ||||
| } | ||||
|  | ||||
| inline AST_Enum* CodeEnum::operator->() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "Attempt to dereference a nullptr!" ); | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	return ast; | ||||
| } | ||||
|  | ||||
| inline CodeExec& CodeExec::operator=( Code other ) | ||||
| { | ||||
| 	if ( other.ast != nullptr && other->Parent != nullptr ) | ||||
| 	{ | ||||
| 		ast         = rcast( decltype( ast ), code_duplicate( other ).ast ); | ||||
| 		ast->Parent = { nullptr }; | ||||
| 	} | ||||
| 	ast = rcast( decltype( ast ), other.ast ); | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
| inline CodeExec::operator bool() | ||||
| { | ||||
| 	return ast != nullptr; | ||||
| } | ||||
|  | ||||
| inline CodeExec::operator Code() | ||||
| { | ||||
| 	return *rcast( Code*, this ); | ||||
| } | ||||
|  | ||||
| inline AST_Exec* CodeExec::operator->() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "Attempt to dereference a nullptr!" ); | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	return ast; | ||||
| } | ||||
|  | ||||
| inline CodeExtern& CodeExtern::operator=( Code other ) | ||||
| { | ||||
| 	if ( other.ast != nullptr && other->Parent != nullptr ) | ||||
| 	{ | ||||
| 		ast         = rcast( decltype( ast ), code_duplicate( other ).ast ); | ||||
| 		ast->Parent = { nullptr }; | ||||
| 	} | ||||
| 	ast = rcast( decltype( ast ), other.ast ); | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
| inline CodeExtern::operator bool() | ||||
| { | ||||
| 	return ast != nullptr; | ||||
| } | ||||
|  | ||||
| inline CodeExtern::operator Code() | ||||
| { | ||||
| 	return *rcast( Code*, this ); | ||||
| } | ||||
|  | ||||
| inline AST_Extern* CodeExtern::operator->() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "Attempt to dereference a nullptr!" ); | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	return ast; | ||||
| } | ||||
|  | ||||
| inline CodeFriend& CodeFriend::operator=( Code other ) | ||||
| { | ||||
| 	if ( other.ast != nullptr && other->Parent != nullptr ) | ||||
| 	{ | ||||
| 		ast         = rcast( decltype( ast ), code_duplicate( other ).ast ); | ||||
| 		ast->Parent = { nullptr }; | ||||
| 	} | ||||
| 	ast = rcast( decltype( ast ), other.ast ); | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
| inline CodeFriend::operator bool() | ||||
| { | ||||
| 	return ast != nullptr; | ||||
| } | ||||
|  | ||||
| inline CodeFriend::operator Code() | ||||
| { | ||||
| 	return *rcast( Code*, this ); | ||||
| } | ||||
|  | ||||
| inline AST_Friend* CodeFriend::operator->() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "Attempt to dereference a nullptr!" ); | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	return ast; | ||||
| } | ||||
|  | ||||
| inline CodeFn& CodeFn::operator=( Code other ) | ||||
| { | ||||
| 	if ( other.ast != nullptr && other->Parent != nullptr ) | ||||
| 	{ | ||||
| 		ast         = rcast( decltype( ast ), code_duplicate( other ).ast ); | ||||
| 		ast->Parent = { nullptr }; | ||||
| 	} | ||||
| 	ast = rcast( decltype( ast ), other.ast ); | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
| inline CodeFn::operator bool() | ||||
| { | ||||
| 	return ast != nullptr; | ||||
| } | ||||
|  | ||||
| inline CodeFn::operator Code() | ||||
| { | ||||
| 	return *rcast( Code*, this ); | ||||
| } | ||||
|  | ||||
| inline AST_Fn* CodeFn::operator->() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "Attempt to dereference a nullptr!" ); | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	return ast; | ||||
| } | ||||
|  | ||||
| inline CodeInclude& CodeInclude::operator=( Code other ) | ||||
| { | ||||
| 	if ( other.ast != nullptr && other->Parent != nullptr ) | ||||
| 	{ | ||||
| 		ast         = rcast( decltype( ast ), code_duplicate( other ).ast ); | ||||
| 		ast->Parent = { nullptr }; | ||||
| 	} | ||||
| 	ast = rcast( decltype( ast ), other.ast ); | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
| inline CodeInclude::operator bool() | ||||
| { | ||||
| 	return ast != nullptr; | ||||
| } | ||||
|  | ||||
| inline CodeInclude::operator Code() | ||||
| { | ||||
| 	return *rcast( Code*, this ); | ||||
| } | ||||
|  | ||||
| inline AST_Include* CodeInclude::operator->() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "Attempt to dereference a nullptr!" ); | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	return ast; | ||||
| } | ||||
|  | ||||
| inline CodeModule& CodeModule::operator=( Code other ) | ||||
| { | ||||
| 	if ( other.ast != nullptr && other->Parent != nullptr ) | ||||
| 	{ | ||||
| 		ast         = rcast( decltype( ast ), code_duplicate( other ).ast ); | ||||
| 		ast->Parent = { nullptr }; | ||||
| 	} | ||||
| 	ast = rcast( decltype( ast ), other.ast ); | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
| inline CodeModule::operator bool() | ||||
| { | ||||
| 	return ast != nullptr; | ||||
| } | ||||
|  | ||||
| inline CodeModule::operator Code() | ||||
| { | ||||
| 	return *rcast( Code*, this ); | ||||
| } | ||||
|  | ||||
| inline AST_Module* CodeModule::operator->() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "Attempt to dereference a nullptr!" ); | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	return ast; | ||||
| } | ||||
|  | ||||
| inline CodeNS& CodeNS::operator=( Code other ) | ||||
| { | ||||
| 	if ( other.ast != nullptr && other->Parent != nullptr ) | ||||
| 	{ | ||||
| 		ast         = rcast( decltype( ast ), code_duplicate( other ).ast ); | ||||
| 		ast->Parent = { nullptr }; | ||||
| 	} | ||||
| 	ast = rcast( decltype( ast ), other.ast ); | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
| inline CodeNS::operator bool() | ||||
| { | ||||
| 	return ast != nullptr; | ||||
| } | ||||
|  | ||||
| inline CodeNS::operator Code() | ||||
| { | ||||
| 	return *rcast( Code*, this ); | ||||
| } | ||||
|  | ||||
| inline AST_NS* CodeNS::operator->() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "Attempt to dereference a nullptr!" ); | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	return ast; | ||||
| } | ||||
|  | ||||
| inline CodeOperator& CodeOperator::operator=( Code other ) | ||||
| { | ||||
| 	if ( other.ast != nullptr && other->Parent != nullptr ) | ||||
| 	{ | ||||
| 		ast         = rcast( decltype( ast ), code_duplicate( other ).ast ); | ||||
| 		ast->Parent = { nullptr }; | ||||
| 	} | ||||
| 	ast = rcast( decltype( ast ), other.ast ); | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
| inline CodeOperator::operator bool() | ||||
| { | ||||
| 	return ast != nullptr; | ||||
| } | ||||
|  | ||||
| inline CodeOperator::operator Code() | ||||
| { | ||||
| 	return *rcast( Code*, this ); | ||||
| } | ||||
|  | ||||
| inline AST_Operator* CodeOperator::operator->() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "Attempt to dereference a nullptr!" ); | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	return ast; | ||||
| } | ||||
|  | ||||
| inline CodeOpCast& CodeOpCast::operator=( Code other ) | ||||
| { | ||||
| 	if ( other.ast != nullptr && other->Parent != nullptr ) | ||||
| 	{ | ||||
| 		ast         = rcast( decltype( ast ), code_duplicate( other ).ast ); | ||||
| 		ast->Parent = { nullptr }; | ||||
| 	} | ||||
| 	ast = rcast( decltype( ast ), other.ast ); | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
| inline CodeOpCast::operator bool() | ||||
| { | ||||
| 	return ast != nullptr; | ||||
| } | ||||
|  | ||||
| inline CodeOpCast::operator Code() | ||||
| { | ||||
| 	return *rcast( Code*, this ); | ||||
| } | ||||
|  | ||||
| inline AST_OpCast* CodeOpCast::operator->() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "Attempt to dereference a nullptr!" ); | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	return ast; | ||||
| } | ||||
|  | ||||
| inline CodeParam& CodeParam::operator=( Code other ) | ||||
| { | ||||
| 	if ( other.ast != nullptr && other->Parent != nullptr ) | ||||
| 	{ | ||||
| 		ast         = rcast( decltype( ast ), code_duplicate( other ).ast ); | ||||
| 		ast->Parent = { nullptr }; | ||||
| 	} | ||||
| 	ast = rcast( decltype( ast ), other.ast ); | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
| inline CodeParam::operator bool() | ||||
| { | ||||
| 	return ast != nullptr; | ||||
| } | ||||
|  | ||||
| inline CodePragma& CodePragma::operator=( Code other ) | ||||
| { | ||||
| 	if ( other.ast != nullptr && other->Parent != nullptr ) | ||||
| 	{ | ||||
| 		ast         = rcast( decltype( ast ), code_duplicate( other ).ast ); | ||||
| 		ast->Parent = { nullptr }; | ||||
| 	} | ||||
| 	ast = rcast( decltype( ast ), other.ast ); | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
| inline CodePragma::operator bool() | ||||
| { | ||||
| 	return ast != nullptr; | ||||
| } | ||||
|  | ||||
| inline CodePragma::operator Code() | ||||
| { | ||||
| 	return *rcast( Code*, this ); | ||||
| } | ||||
|  | ||||
| inline AST_Pragma* CodePragma::operator->() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "Attempt to dereference a nullptr!" ); | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	return ast; | ||||
| } | ||||
|  | ||||
| inline CodePreprocessCond& CodePreprocessCond::operator=( Code other ) | ||||
| { | ||||
| 	if ( other.ast != nullptr && other->Parent != nullptr ) | ||||
| 	{ | ||||
| 		ast         = rcast( decltype( ast ), code_duplicate( other ).ast ); | ||||
| 		ast->Parent = { nullptr }; | ||||
| 	} | ||||
| 	ast = rcast( decltype( ast ), other.ast ); | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
| inline CodePreprocessCond::operator bool() | ||||
| { | ||||
| 	return ast != nullptr; | ||||
| } | ||||
|  | ||||
| inline CodePreprocessCond::operator Code() | ||||
| { | ||||
| 	return *rcast( Code*, this ); | ||||
| } | ||||
|  | ||||
| inline AST_PreprocessCond* CodePreprocessCond::operator->() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "Attempt to dereference a nullptr!" ); | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	return ast; | ||||
| } | ||||
|  | ||||
| inline CodeSpecifiers& CodeSpecifiers::operator=( Code other ) | ||||
| { | ||||
| 	if ( other.ast != nullptr && other->Parent != nullptr ) | ||||
| 	{ | ||||
| 		ast         = rcast( decltype( ast ), code_duplicate( other ).ast ); | ||||
| 		ast->Parent = { nullptr }; | ||||
| 	} | ||||
| 	ast = rcast( decltype( ast ), other.ast ); | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
| inline CodeSpecifiers::operator bool() | ||||
| { | ||||
| 	return ast != nullptr; | ||||
| } | ||||
|  | ||||
| inline CodeStruct& CodeStruct::operator=( Code other ) | ||||
| { | ||||
| 	if ( other.ast != nullptr && other->Parent != nullptr ) | ||||
| 	{ | ||||
| 		ast         = rcast( decltype( ast ), code_duplicate( other ).ast ); | ||||
| 		ast->Parent = { nullptr }; | ||||
| 	} | ||||
| 	ast = rcast( decltype( ast ), other.ast ); | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
| inline CodeStruct::operator bool() | ||||
| { | ||||
| 	return ast != nullptr; | ||||
| } | ||||
|  | ||||
| inline CodeTemplate& CodeTemplate::operator=( Code other ) | ||||
| { | ||||
| 	if ( other.ast != nullptr && other->Parent != nullptr ) | ||||
| 	{ | ||||
| 		ast         = rcast( decltype( ast ), code_duplicate( other ).ast ); | ||||
| 		ast->Parent = { nullptr }; | ||||
| 	} | ||||
| 	ast = rcast( decltype( ast ), other.ast ); | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
| inline CodeTemplate::operator bool() | ||||
| { | ||||
| 	return ast != nullptr; | ||||
| } | ||||
|  | ||||
| inline CodeTemplate::operator Code() | ||||
| { | ||||
| 	return *rcast( Code*, this ); | ||||
| } | ||||
|  | ||||
| inline AST_Template* CodeTemplate::operator->() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "Attempt to dereference a nullptr!" ); | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	return ast; | ||||
| } | ||||
|  | ||||
| inline CodeTypename& CodeTypename::operator=( Code other ) | ||||
| { | ||||
| 	if ( other.ast != nullptr && other->Parent != nullptr ) | ||||
| 	{ | ||||
| 		ast         = rcast( decltype( ast ), code_duplicate( other ).ast ); | ||||
| 		ast->Parent = { nullptr }; | ||||
| 	} | ||||
| 	ast = rcast( decltype( ast ), other.ast ); | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
| inline CodeTypename::operator bool() | ||||
| { | ||||
| 	return ast != nullptr; | ||||
| } | ||||
|  | ||||
| inline CodeTypename::operator Code() | ||||
| { | ||||
| 	return *rcast( Code*, this ); | ||||
| } | ||||
|  | ||||
| inline AST_Typename* CodeTypename::operator->() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "Attempt to dereference a nullptr!" ); | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	return ast; | ||||
| } | ||||
|  | ||||
| inline CodeTypedef& CodeTypedef::operator=( Code other ) | ||||
| { | ||||
| 	if ( other.ast != nullptr && other->Parent != nullptr ) | ||||
| 	{ | ||||
| 		ast         = rcast( decltype( ast ), code_duplicate( other ).ast ); | ||||
| 		ast->Parent = { nullptr }; | ||||
| 	} | ||||
| 	ast = rcast( decltype( ast ), other.ast ); | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
| inline CodeTypedef::operator bool() | ||||
| { | ||||
| 	return ast != nullptr; | ||||
| } | ||||
|  | ||||
| inline CodeTypedef::operator Code() | ||||
| { | ||||
| 	return *rcast( Code*, this ); | ||||
| } | ||||
|  | ||||
| inline AST_Typedef* CodeTypedef::operator->() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "Attempt to dereference a nullptr!" ); | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	return ast; | ||||
| } | ||||
|  | ||||
| inline CodeUnion& CodeUnion::operator=( Code other ) | ||||
| { | ||||
| 	if ( other.ast != nullptr && other->Parent != nullptr ) | ||||
| 	{ | ||||
| 		ast         = rcast( decltype( ast ), code_duplicate( other ).ast ); | ||||
| 		ast->Parent = { nullptr }; | ||||
| 	} | ||||
| 	ast = rcast( decltype( ast ), other.ast ); | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
| inline CodeUnion::operator bool() | ||||
| { | ||||
| 	return ast != nullptr; | ||||
| } | ||||
|  | ||||
| inline CodeUnion::operator Code() | ||||
| { | ||||
| 	return *rcast( Code*, this ); | ||||
| } | ||||
|  | ||||
| inline AST_Union* CodeUnion::operator->() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "Attempt to dereference a nullptr!" ); | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	return ast; | ||||
| } | ||||
|  | ||||
| inline CodeUsing& CodeUsing::operator=( Code other ) | ||||
| { | ||||
| 	if ( other.ast != nullptr && other->Parent != nullptr ) | ||||
| 	{ | ||||
| 		ast         = rcast( decltype( ast ), code_duplicate( other ).ast ); | ||||
| 		ast->Parent = { nullptr }; | ||||
| 	} | ||||
| 	ast = rcast( decltype( ast ), other.ast ); | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
| inline CodeUsing::operator bool() | ||||
| { | ||||
| 	return ast != nullptr; | ||||
| } | ||||
|  | ||||
| inline CodeUsing::operator Code() | ||||
| { | ||||
| 	return *rcast( Code*, this ); | ||||
| } | ||||
|  | ||||
| inline AST_Using* CodeUsing::operator->() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "Attempt to dereference a nullptr!" ); | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	return ast; | ||||
| } | ||||
|  | ||||
| inline CodeVar& CodeVar::operator=( Code other ) | ||||
| { | ||||
| 	if ( other.ast != nullptr && other->Parent != nullptr ) | ||||
| 	{ | ||||
| 		ast         = rcast( decltype( ast ), code_duplicate( other ).ast ); | ||||
| 		ast->Parent = { nullptr }; | ||||
| 	} | ||||
| 	ast = rcast( decltype( ast ), other.ast ); | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
| inline CodeVar::operator bool() | ||||
| { | ||||
| 	return ast != nullptr; | ||||
| } | ||||
|  | ||||
| inline CodeVar::operator Code() | ||||
| { | ||||
| 	return *rcast( Code*, this ); | ||||
| } | ||||
|  | ||||
| inline AST_Var* CodeVar::operator->() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "Attempt to dereference a nullptr!" ); | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	return ast; | ||||
| } | ||||
|  | ||||
| #pragma endregion generated code inline implementation | ||||
|  | ||||
| #pragma region generated AST/Code cast implementation | ||||
| GEN_OPTIMIZE_MAPPINGS_BEGIN | ||||
|  | ||||
| forceinline Code::operator CodeBody() const | ||||
| { | ||||
| 	return { (AST_Body*)ast }; | ||||
| } | ||||
|  | ||||
| forceinline Code::operator CodeAttributes() const | ||||
| { | ||||
| 	return { (AST_Attributes*)ast }; | ||||
| } | ||||
|  | ||||
| forceinline Code::operator CodeComment() const | ||||
| { | ||||
| 	return { (AST_Comment*)ast }; | ||||
| } | ||||
|  | ||||
| forceinline Code::operator CodeConstructor() const | ||||
| { | ||||
| 	return { (AST_Constructor*)ast }; | ||||
| } | ||||
|  | ||||
| forceinline Code::operator CodeClass() const | ||||
| { | ||||
| 	return { (AST_Class*)ast }; | ||||
| } | ||||
|  | ||||
| forceinline Code::operator CodeDefine() const | ||||
| { | ||||
| 	return { (AST_Define*)ast }; | ||||
| } | ||||
|  | ||||
| forceinline Code::operator CodeDestructor() const | ||||
| { | ||||
| 	return { (AST_Destructor*)ast }; | ||||
| } | ||||
|  | ||||
| forceinline Code::operator CodeEnum() const | ||||
| { | ||||
| 	return { (AST_Enum*)ast }; | ||||
| } | ||||
|  | ||||
| forceinline Code::operator CodeExec() const | ||||
| { | ||||
| 	return { (AST_Exec*)ast }; | ||||
| } | ||||
|  | ||||
| forceinline Code::operator CodeExtern() const | ||||
| { | ||||
| 	return { (AST_Extern*)ast }; | ||||
| } | ||||
|  | ||||
| forceinline Code::operator CodeFriend() const | ||||
| { | ||||
| 	return { (AST_Friend*)ast }; | ||||
| } | ||||
|  | ||||
| forceinline Code::operator CodeFn() const | ||||
| { | ||||
| 	return { (AST_Fn*)ast }; | ||||
| } | ||||
|  | ||||
| forceinline Code::operator CodeInclude() const | ||||
| { | ||||
| 	return { (AST_Include*)ast }; | ||||
| } | ||||
|  | ||||
| forceinline Code::operator CodeModule() const | ||||
| { | ||||
| 	return { (AST_Module*)ast }; | ||||
| } | ||||
|  | ||||
| forceinline Code::operator CodeNS() const | ||||
| { | ||||
| 	return { (AST_NS*)ast }; | ||||
| } | ||||
|  | ||||
| forceinline Code::operator CodeOperator() const | ||||
| { | ||||
| 	return { (AST_Operator*)ast }; | ||||
| } | ||||
|  | ||||
| forceinline Code::operator CodeOpCast() const | ||||
| { | ||||
| 	return { (AST_OpCast*)ast }; | ||||
| } | ||||
|  | ||||
| forceinline Code::operator CodeParam() const | ||||
| { | ||||
| 	return { (AST_Param*)ast }; | ||||
| } | ||||
|  | ||||
| forceinline Code::operator CodePragma() const | ||||
| { | ||||
| 	return { (AST_Pragma*)ast }; | ||||
| } | ||||
|  | ||||
| forceinline Code::operator CodePreprocessCond() const | ||||
| { | ||||
| 	return { (AST_PreprocessCond*)ast }; | ||||
| } | ||||
|  | ||||
| forceinline Code::operator CodeSpecifiers() const | ||||
| { | ||||
| 	return { (AST_Specifiers*)ast }; | ||||
| } | ||||
|  | ||||
| forceinline Code::operator CodeStruct() const | ||||
| { | ||||
| 	return { (AST_Struct*)ast }; | ||||
| } | ||||
|  | ||||
| forceinline Code::operator CodeTemplate() const | ||||
| { | ||||
| 	return { (AST_Template*)ast }; | ||||
| } | ||||
|  | ||||
| forceinline Code::operator CodeTypename() const | ||||
| { | ||||
| 	return { (AST_Typename*)ast }; | ||||
| } | ||||
|  | ||||
| forceinline Code::operator CodeTypedef() const | ||||
| { | ||||
| 	return { (AST_Typedef*)ast }; | ||||
| } | ||||
|  | ||||
| forceinline Code::operator CodeUnion() const | ||||
| { | ||||
| 	return { (AST_Union*)ast }; | ||||
| } | ||||
|  | ||||
| forceinline Code::operator CodeUsing() const | ||||
| { | ||||
| 	return { (AST_Using*)ast }; | ||||
| } | ||||
|  | ||||
| forceinline Code::operator CodeVar() const | ||||
| { | ||||
| 	return { (AST_Var*)ast }; | ||||
| } | ||||
|  | ||||
| GEN_OPITMIZE_MAPPINGS_END | ||||
| #pragma endregion generated AST / Code cast implementation | ||||
							
								
								
									
										219
									
								
								base/components/gen/ecode.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										219
									
								
								base/components/gen/ecode.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,219 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #pragma once | ||||
| #include "components/types.hpp" | ||||
| #endif | ||||
|  | ||||
| // This file was generated automatially by gencpp's bootstrap.cpp (See: https://github.com/Ed94/gencpp) | ||||
|  | ||||
| enum CodeType : u32 | ||||
| { | ||||
| 	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_Fwd, | ||||
| 	CT_Union_Body, | ||||
| 	CT_Using, | ||||
| 	CT_Using_Namespace, | ||||
| 	CT_Variable, | ||||
| 	CT_NumTypes, | ||||
| 	CT_UnderlyingType = GEN_U32_MAX | ||||
| }; | ||||
|  | ||||
| inline StrC codetype_to_str( CodeType type ) | ||||
| { | ||||
| 	local_persist StrC lookup[61] = { | ||||
| 		{ sizeof( "Invalid" ),             "Invalid"             }, | ||||
| 		{ sizeof( "Untyped" ),             "Untyped"             }, | ||||
| 		{ sizeof( "NewLine" ),             "NewLine"             }, | ||||
| 		{ sizeof( "Comment" ),             "Comment"             }, | ||||
| 		{ sizeof( "Access_Private" ),      "Access_Private"      }, | ||||
| 		{ sizeof( "Access_Protected" ),    "Access_Protected"    }, | ||||
| 		{ sizeof( "Access_Public" ),       "Access_Public"       }, | ||||
| 		{ sizeof( "PlatformAttributes" ),  "PlatformAttributes"  }, | ||||
| 		{ sizeof( "Class" ),               "Class"               }, | ||||
| 		{ sizeof( "Class_Fwd" ),           "Class_Fwd"           }, | ||||
| 		{ sizeof( "Class_Body" ),          "Class_Body"          }, | ||||
| 		{ sizeof( "Constructor" ),         "Constructor"         }, | ||||
| 		{ sizeof( "Constructor_Fwd" ),     "Constructor_Fwd"     }, | ||||
| 		{ sizeof( "Destructor" ),          "Destructor"          }, | ||||
| 		{ sizeof( "Destructor_Fwd" ),      "Destructor_Fwd"      }, | ||||
| 		{ sizeof( "Enum" ),                "Enum"                }, | ||||
| 		{ sizeof( "Enum_Fwd" ),            "Enum_Fwd"            }, | ||||
| 		{ sizeof( "Enum_Body" ),           "Enum_Body"           }, | ||||
| 		{ sizeof( "Enum_Class" ),          "Enum_Class"          }, | ||||
| 		{ sizeof( "Enum_Class_Fwd" ),      "Enum_Class_Fwd"      }, | ||||
| 		{ sizeof( "Execution" ),           "Execution"           }, | ||||
| 		{ sizeof( "Export_Body" ),         "Export_Body"         }, | ||||
| 		{ sizeof( "Extern_Linkage" ),      "Extern_Linkage"      }, | ||||
| 		{ sizeof( "Extern_Linkage_Body" ), "Extern_Linkage_Body" }, | ||||
| 		{ sizeof( "Friend" ),              "Friend"              }, | ||||
| 		{ sizeof( "Function" ),            "Function"            }, | ||||
| 		{ sizeof( "Function_Fwd" ),        "Function_Fwd"        }, | ||||
| 		{ sizeof( "Function_Body" ),       "Function_Body"       }, | ||||
| 		{ sizeof( "Global_Body" ),         "Global_Body"         }, | ||||
| 		{ sizeof( "Module" ),              "Module"              }, | ||||
| 		{ sizeof( "Namespace" ),           "Namespace"           }, | ||||
| 		{ sizeof( "Namespace_Body" ),      "Namespace_Body"      }, | ||||
| 		{ sizeof( "Operator" ),            "Operator"            }, | ||||
| 		{ sizeof( "Operator_Fwd" ),        "Operator_Fwd"        }, | ||||
| 		{ sizeof( "Operator_Member" ),     "Operator_Member"     }, | ||||
| 		{ sizeof( "Operator_Member_Fwd" ), "Operator_Member_Fwd" }, | ||||
| 		{ sizeof( "Operator_Cast" ),       "Operator_Cast"       }, | ||||
| 		{ sizeof( "Operator_Cast_Fwd" ),   "Operator_Cast_Fwd"   }, | ||||
| 		{ sizeof( "Parameters" ),          "Parameters"          }, | ||||
| 		{ sizeof( "Preprocess_Define" ),   "Preprocess_Define"   }, | ||||
| 		{ sizeof( "Preprocess_Include" ),  "Preprocess_Include"  }, | ||||
| 		{ sizeof( "Preprocess_If" ),       "Preprocess_If"       }, | ||||
| 		{ sizeof( "Preprocess_IfDef" ),    "Preprocess_IfDef"    }, | ||||
| 		{ sizeof( "Preprocess_IfNotDef" ), "Preprocess_IfNotDef" }, | ||||
| 		{ sizeof( "Preprocess_ElIf" ),     "Preprocess_ElIf"     }, | ||||
| 		{ sizeof( "Preprocess_Else" ),     "Preprocess_Else"     }, | ||||
| 		{ sizeof( "Preprocess_EndIf" ),    "Preprocess_EndIf"    }, | ||||
| 		{ sizeof( "Preprocess_Pragma" ),   "Preprocess_Pragma"   }, | ||||
| 		{ sizeof( "Specifiers" ),          "Specifiers"          }, | ||||
| 		{ sizeof( "Struct" ),              "Struct"              }, | ||||
| 		{ sizeof( "Struct_Fwd" ),          "Struct_Fwd"          }, | ||||
| 		{ sizeof( "Struct_Body" ),         "Struct_Body"         }, | ||||
| 		{ sizeof( "Template" ),            "Template"            }, | ||||
| 		{ sizeof( "Typedef" ),             "Typedef"             }, | ||||
| 		{ sizeof( "Typename" ),            "Typename"            }, | ||||
| 		{ sizeof( "Union" ),               "Union"               }, | ||||
| 		{ sizeof( "Union_Fwd" ),           "Union_Fwd"           }, | ||||
| 		{ sizeof( "Union_Body" ),          "Union_Body"          }, | ||||
| 		{ sizeof( "Using" ),               "Using"               }, | ||||
| 		{ sizeof( "Using_Namespace" ),     "Using_Namespace"     }, | ||||
| 		{ sizeof( "Variable" ),            "Variable"            }, | ||||
| 	}; | ||||
| 	return lookup[type]; | ||||
| } | ||||
|  | ||||
| inline StrC codetype_to_keyword_str( CodeType type ) | ||||
| { | ||||
| 	local_persist StrC lookup[61] = { | ||||
| 		{ sizeof( "__NA__" ) - 1,          "__NA__"          }, | ||||
| 		{ sizeof( "__NA__" ) - 1,          "__NA__"          }, | ||||
| 		{ sizeof( "__NA__" ) - 1,          "__NA__"          }, | ||||
| 		{ sizeof( "//" ) - 1,              "//"              }, | ||||
| 		{ sizeof( "private" ) - 1,         "private"         }, | ||||
| 		{ sizeof( "protected" ) - 1,       "protected"       }, | ||||
| 		{ sizeof( "public" ) - 1,          "public"          }, | ||||
| 		{ sizeof( "__NA__" ) - 1,          "__NA__"          }, | ||||
| 		{ sizeof( "class" ) - 1,           "class"           }, | ||||
| 		{ sizeof( "clsss" ) - 1,           "clsss"           }, | ||||
| 		{ sizeof( "__NA__" ) - 1,          "__NA__"          }, | ||||
| 		{ sizeof( "__NA__" ) - 1,          "__NA__"          }, | ||||
| 		{ sizeof( "__NA__" ) - 1,          "__NA__"          }, | ||||
| 		{ sizeof( "__NA__" ) - 1,          "__NA__"          }, | ||||
| 		{ sizeof( "__NA__" ) - 1,          "__NA__"          }, | ||||
| 		{ sizeof( "enum" ) - 1,            "enum"            }, | ||||
| 		{ sizeof( "enum" ) - 1,            "enum"            }, | ||||
| 		{ sizeof( "__NA__" ) - 1,          "__NA__"          }, | ||||
| 		{ sizeof( "enum class" ) - 1,      "enum class"      }, | ||||
| 		{ sizeof( "enum class" ) - 1,      "enum class"      }, | ||||
| 		{ sizeof( "__NA__" ) - 1,          "__NA__"          }, | ||||
| 		{ sizeof( "__NA__" ) - 1,          "__NA__"          }, | ||||
| 		{ sizeof( "extern" ) - 1,          "extern"          }, | ||||
| 		{ sizeof( "extern" ) - 1,          "extern"          }, | ||||
| 		{ sizeof( "friend" ) - 1,          "friend"          }, | ||||
| 		{ sizeof( "__NA__" ) - 1,          "__NA__"          }, | ||||
| 		{ sizeof( "__NA__" ) - 1,          "__NA__"          }, | ||||
| 		{ sizeof( "__NA__" ) - 1,          "__NA__"          }, | ||||
| 		{ sizeof( "__NA__" ) - 1,          "__NA__"          }, | ||||
| 		{ sizeof( "module" ) - 1,          "module"          }, | ||||
| 		{ sizeof( "namespace" ) - 1,       "namespace"       }, | ||||
| 		{ sizeof( "__NA__" ) - 1,          "__NA__"          }, | ||||
| 		{ sizeof( "operator" ) - 1,        "operator"        }, | ||||
| 		{ sizeof( "operator" ) - 1,        "operator"        }, | ||||
| 		{ sizeof( "operator" ) - 1,        "operator"        }, | ||||
| 		{ sizeof( "operator" ) - 1,        "operator"        }, | ||||
| 		{ sizeof( "operator" ) - 1,        "operator"        }, | ||||
| 		{ sizeof( "operator" ) - 1,        "operator"        }, | ||||
| 		{ sizeof( "__NA__" ) - 1,          "__NA__"          }, | ||||
| 		{ sizeof( "define" ) - 1,          "define"          }, | ||||
| 		{ sizeof( "include" ) - 1,         "include"         }, | ||||
| 		{ sizeof( "if" ) - 1,              "if"              }, | ||||
| 		{ sizeof( "ifdef" ) - 1,           "ifdef"           }, | ||||
| 		{ sizeof( "ifndef" ) - 1,          "ifndef"          }, | ||||
| 		{ sizeof( "elif" ) - 1,            "elif"            }, | ||||
| 		{ sizeof( "else" ) - 1,            "else"            }, | ||||
| 		{ sizeof( "endif" ) - 1,           "endif"           }, | ||||
| 		{ sizeof( "pragma" ) - 1,          "pragma"          }, | ||||
| 		{ sizeof( "__NA__" ) - 1,          "__NA__"          }, | ||||
| 		{ sizeof( "struct" ) - 1,          "struct"          }, | ||||
| 		{ sizeof( "struct" ) - 1,          "struct"          }, | ||||
| 		{ sizeof( "__NA__" ) - 1,          "__NA__"          }, | ||||
| 		{ sizeof( "template" ) - 1,        "template"        }, | ||||
| 		{ sizeof( "typedef" ) - 1,         "typedef"         }, | ||||
| 		{ sizeof( "__NA__" ) - 1,          "__NA__"          }, | ||||
| 		{ sizeof( "union" ) - 1,           "union"           }, | ||||
| 		{ sizeof( "union" ) - 1,           "union"           }, | ||||
| 		{ sizeof( "__NA__" ) - 1,          "__NA__"          }, | ||||
| 		{ sizeof( "using" ) - 1,           "using"           }, | ||||
| 		{ sizeof( "using namespace" ) - 1, "using namespace" }, | ||||
| 		{ sizeof( "__NA__" ) - 1,          "__NA__"          }, | ||||
| 	}; | ||||
| 	return lookup[type]; | ||||
| } | ||||
|  | ||||
| forceinline StrC to_str( CodeType type ) | ||||
| { | ||||
| 	return codetype_to_str( type ); | ||||
| } | ||||
|  | ||||
| forceinline StrC to_keyword_str( CodeType type ) | ||||
| { | ||||
| 	return codetype_to_keyword_str( type ); | ||||
| } | ||||
							
								
								
									
										118
									
								
								base/components/gen/eoperator.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								base/components/gen/eoperator.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,118 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #pragma once | ||||
| #include "components/types.hpp" | ||||
| #endif | ||||
|  | ||||
| // This file was generated automatially by gencpp's bootstrap.cpp (See: https://github.com/Ed94/gencpp) | ||||
|  | ||||
| enum Operator : u32 | ||||
| { | ||||
| 	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, | ||||
| 	Op_NumOps, | ||||
| 	Op_UnderlyingType = 0xffffffffu | ||||
| }; | ||||
|  | ||||
| inline StrC operator_to_str( Operator op ) | ||||
| { | ||||
| 	local_persist StrC lookup[47] = { | ||||
| 		{ sizeof( "INVALID" ),  "INVALID"  }, | ||||
| 		{ sizeof( "=" ),        "="        }, | ||||
| 		{ sizeof( "+=" ),       "+="       }, | ||||
| 		{ sizeof( "-=" ),       "-="       }, | ||||
| 		{ sizeof( "*=" ),       "*="       }, | ||||
| 		{ sizeof( "/=" ),       "/="       }, | ||||
| 		{ sizeof( "%=" ),       "%="       }, | ||||
| 		{ sizeof( "&=" ),       "&="       }, | ||||
| 		{ sizeof( "|=" ),       "|="       }, | ||||
| 		{ sizeof( "^=" ),       "^="       }, | ||||
| 		{ sizeof( "<<=" ),      "<<="      }, | ||||
| 		{ sizeof( ">>=" ),      ">>="      }, | ||||
| 		{ sizeof( "++" ),       "++"       }, | ||||
| 		{ sizeof( "--" ),       "--"       }, | ||||
| 		{ sizeof( "+" ),        "+"        }, | ||||
| 		{ sizeof( "-" ),        "-"        }, | ||||
| 		{ sizeof( "!" ),        "!"        }, | ||||
| 		{ sizeof( "+" ),        "+"        }, | ||||
| 		{ sizeof( "-" ),        "-"        }, | ||||
| 		{ sizeof( "*" ),        "*"        }, | ||||
| 		{ sizeof( "/" ),        "/"        }, | ||||
| 		{ sizeof( "%" ),        "%"        }, | ||||
| 		{ sizeof( "~" ),        "~"        }, | ||||
| 		{ sizeof( "&" ),        "&"        }, | ||||
| 		{ sizeof( "|" ),        "|"        }, | ||||
| 		{ sizeof( "^" ),        "^"        }, | ||||
| 		{ sizeof( "<<" ),       "<<"       }, | ||||
| 		{ sizeof( ">>" ),       ">>"       }, | ||||
| 		{ sizeof( "&&" ),       "&&"       }, | ||||
| 		{ sizeof( "||" ),       "||"       }, | ||||
| 		{ sizeof( "==" ),       "=="       }, | ||||
| 		{ sizeof( "!=" ),       "!="       }, | ||||
| 		{ sizeof( "<" ),        "<"        }, | ||||
| 		{ sizeof( ">" ),        ">"        }, | ||||
| 		{ sizeof( "<=" ),       "<="       }, | ||||
| 		{ sizeof( ">=" ),       ">="       }, | ||||
| 		{ sizeof( "[]" ),       "[]"       }, | ||||
| 		{ sizeof( "*" ),        "*"        }, | ||||
| 		{ sizeof( "&" ),        "&"        }, | ||||
| 		{ sizeof( "->" ),       "->"       }, | ||||
| 		{ sizeof( "->*" ),      "->*"      }, | ||||
| 		{ sizeof( "()" ),       "()"       }, | ||||
| 		{ sizeof( "," ),        ","        }, | ||||
| 		{ sizeof( "new" ),      "new"      }, | ||||
| 		{ sizeof( "new[]" ),    "new[]"    }, | ||||
| 		{ sizeof( "delete" ),   "delete"   }, | ||||
| 		{ sizeof( "delete[]" ), "delete[]" }, | ||||
| 	}; | ||||
| 	return lookup[op]; | ||||
| } | ||||
|  | ||||
| forceinline StrC to_str( Operator op ) | ||||
| { | ||||
| 	return operator_to_str( op ); | ||||
| } | ||||
							
								
								
									
										108
									
								
								base/components/gen/especifier.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								base/components/gen/especifier.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,108 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #pragma once | ||||
| #include "components/types.hpp" | ||||
| #endif | ||||
|  | ||||
| // This file was generated automatially by gencpp's bootstrap.cpp (See: https://github.com/Ed94/gencpp) | ||||
|  | ||||
| enum Specifier : u32 | ||||
| { | ||||
| 	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, | ||||
| 	Spec_UnderlyingType = 0xffffffffu | ||||
| }; | ||||
|  | ||||
| inline StrC spec_to_str( Specifier type ) | ||||
| { | ||||
| 	local_persist StrC lookup[26] = { | ||||
| 		{ sizeof( "INVALID" ),       "INVALID"       }, | ||||
| 		{ sizeof( "consteval" ),     "consteval"     }, | ||||
| 		{ sizeof( "constexpr" ),     "constexpr"     }, | ||||
| 		{ sizeof( "constinit" ),     "constinit"     }, | ||||
| 		{ sizeof( "explicit" ),      "explicit"      }, | ||||
| 		{ sizeof( "extern" ),        "extern"        }, | ||||
| 		{ sizeof( "forceinline" ),   "forceinline"   }, | ||||
| 		{ sizeof( "global" ),        "global"        }, | ||||
| 		{ sizeof( "inline" ),        "inline"        }, | ||||
| 		{ sizeof( "internal" ),      "internal"      }, | ||||
| 		{ sizeof( "local_persist" ), "local_persist" }, | ||||
| 		{ sizeof( "mutable" ),       "mutable"       }, | ||||
| 		{ sizeof( "neverinline" ),   "neverinline"   }, | ||||
| 		{ sizeof( "*" ),             "*"             }, | ||||
| 		{ sizeof( "&" ),             "&"             }, | ||||
| 		{ sizeof( "register" ),      "register"      }, | ||||
| 		{ sizeof( "&&" ),            "&&"            }, | ||||
| 		{ sizeof( "static" ),        "static"        }, | ||||
| 		{ sizeof( "thread_local" ),  "thread_local"  }, | ||||
| 		{ sizeof( "virtual" ),       "virtual"       }, | ||||
| 		{ sizeof( "const" ),         "const"         }, | ||||
| 		{ sizeof( "final" ),         "final"         }, | ||||
| 		{ sizeof( "noexcept" ),      "noexcept"      }, | ||||
| 		{ sizeof( "override" ),      "override"      }, | ||||
| 		{ sizeof( "= 0" ),           "= 0"           }, | ||||
| 		{ sizeof( "volatile" ),      "volatile"      }, | ||||
| 	}; | ||||
| 	return lookup[type]; | ||||
| } | ||||
|  | ||||
| inline bool spec_is_trailing( Specifier specifier ) | ||||
| { | ||||
| 	return specifier > Spec_Virtual; | ||||
| } | ||||
|  | ||||
| inline Specifier strc_to_specifier( StrC str ) | ||||
| { | ||||
| 	local_persist u32 keymap[Spec_NumSpecifiers]; | ||||
| 	do_once_start for ( u32 index = 0; index < Spec_NumSpecifiers; index++ ) | ||||
| 	{ | ||||
| 		StrC enum_str = spec_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 < Spec_NumSpecifiers; index++ ) | ||||
| 	{ | ||||
| 		if ( keymap[index] == hash ) | ||||
| 			return (Specifier)index; | ||||
| 	} | ||||
| 	return Spec_Invalid; | ||||
| } | ||||
|  | ||||
| forceinline StrC to_str( Specifier spec ) | ||||
| { | ||||
| 	return spec_to_str( spec ); | ||||
| } | ||||
|  | ||||
| forceinline Specifier to_type( StrC str ) | ||||
| { | ||||
| 	return strc_to_specifier( str ); | ||||
| } | ||||
|  | ||||
| forceinline bool is_trailing( Specifier specifier ) | ||||
| { | ||||
| 	return spec_is_trailing( specifier ); | ||||
| } | ||||
							
								
								
									
										235
									
								
								base/components/gen/etoktype.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										235
									
								
								base/components/gen/etoktype.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,235 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #pragma once | ||||
| #include "components/types.hpp" | ||||
| #endif | ||||
|  | ||||
| // This file was generated automatially by gencpp's bootstrap.cpp (See: https://github.com/Ed94/gencpp) | ||||
|  | ||||
| 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 TokType : u32 | ||||
| { | ||||
| 	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 | ||||
| }; | ||||
|  | ||||
| inline StrC toktype_to_str( TokType type ) | ||||
| { | ||||
| 	local_persist StrC lookup[] = { | ||||
| 		{ sizeof( "__invalid__" ),         "__invalid__"         }, | ||||
| 		{ sizeof( "private" ),             "private"             }, | ||||
| 		{ sizeof( "protected" ),           "protected"           }, | ||||
| 		{ sizeof( "public" ),              "public"              }, | ||||
| 		{ sizeof( "." ),                   "."                   }, | ||||
| 		{ sizeof( "::" ),                  "::"                  }, | ||||
| 		{ sizeof( "&" ),                   "&"                   }, | ||||
| 		{ sizeof( "&&" ),                  "&&"                  }, | ||||
| 		{ sizeof( ":" ),                   ":"                   }, | ||||
| 		{ sizeof( "[[" ),                  "[["                  }, | ||||
| 		{ sizeof( "]]" ),                  "]]"                  }, | ||||
| 		{ sizeof( "{" ),                   "{"                   }, | ||||
| 		{ sizeof( "}" ),                   "}"                   }, | ||||
| 		{ sizeof( "[" ),                   "["                   }, | ||||
| 		{ sizeof( "]" ),                   "]"                   }, | ||||
| 		{ sizeof( "(" ),                   "("                   }, | ||||
| 		{ sizeof( ")" ),                   ")"                   }, | ||||
| 		{ sizeof( "__comment__" ),         "__comment__"         }, | ||||
| 		{ sizeof( "__comment_end__" ),     "__comment_end__"     }, | ||||
| 		{ sizeof( "__comment_start__" ),   "__comment_start__"   }, | ||||
| 		{ sizeof( "__character__" ),       "__character__"       }, | ||||
| 		{ sizeof( "," ),                   ","                   }, | ||||
| 		{ sizeof( "class" ),               "class"               }, | ||||
| 		{ sizeof( "__attribute__" ),       "__attribute__"       }, | ||||
| 		{ sizeof( "__declspec" ),          "__declspec"          }, | ||||
| 		{ sizeof( "enum" ),                "enum"                }, | ||||
| 		{ sizeof( "extern" ),              "extern"              }, | ||||
| 		{ sizeof( "friend" ),              "friend"              }, | ||||
| 		{ sizeof( "module" ),              "module"              }, | ||||
| 		{ sizeof( "namespace" ),           "namespace"           }, | ||||
| 		{ sizeof( "operator" ),            "operator"            }, | ||||
| 		{ sizeof( "struct" ),              "struct"              }, | ||||
| 		{ sizeof( "template" ),            "template"            }, | ||||
| 		{ sizeof( "typedef" ),             "typedef"             }, | ||||
| 		{ sizeof( "using" ),               "using"               }, | ||||
| 		{ sizeof( "union" ),               "union"               }, | ||||
| 		{ sizeof( "__identifier__" ),      "__identifier__"      }, | ||||
| 		{ sizeof( "import" ),              "import"              }, | ||||
| 		{ sizeof( "export" ),              "export"              }, | ||||
| 		{ sizeof( "__new_line__" ),        "__new_line__"        }, | ||||
| 		{ sizeof( "__number__" ),          "__number__"          }, | ||||
| 		{ sizeof( "__operator__" ),        "__operator__"        }, | ||||
| 		{ sizeof( "#" ),                   "#"                   }, | ||||
| 		{ sizeof( "define" ),              "define"              }, | ||||
| 		{ sizeof( "if" ),                  "if"                  }, | ||||
| 		{ sizeof( "ifdef" ),               "ifdef"               }, | ||||
| 		{ sizeof( "ifndef" ),              "ifndef"              }, | ||||
| 		{ sizeof( "elif" ),                "elif"                }, | ||||
| 		{ sizeof( "else" ),                "else"                }, | ||||
| 		{ sizeof( "endif" ),               "endif"               }, | ||||
| 		{ sizeof( "include" ),             "include"             }, | ||||
| 		{ sizeof( "pragma" ),              "pragma"              }, | ||||
| 		{ sizeof( "__macro_content__" ),   "__macro_content__"   }, | ||||
| 		{ sizeof( "__macro__" ),           "__macro__"           }, | ||||
| 		{ sizeof( "__unsupported__" ),     "__unsupported__"     }, | ||||
| 		{ sizeof( "alignas" ),             "alignas"             }, | ||||
| 		{ sizeof( "const" ),               "const"               }, | ||||
| 		{ sizeof( "consteval" ),           "consteval"           }, | ||||
| 		{ sizeof( "constexpr" ),           "constexpr"           }, | ||||
| 		{ sizeof( "constinit" ),           "constinit"           }, | ||||
| 		{ sizeof( "explicit" ),            "explicit"            }, | ||||
| 		{ sizeof( "extern" ),              "extern"              }, | ||||
| 		{ sizeof( "final" ),               "final"               }, | ||||
| 		{ sizeof( "forceinline" ),         "forceinline"         }, | ||||
| 		{ sizeof( "global" ),              "global"              }, | ||||
| 		{ sizeof( "inline" ),              "inline"              }, | ||||
| 		{ sizeof( "internal" ),            "internal"            }, | ||||
| 		{ sizeof( "local_persist" ),       "local_persist"       }, | ||||
| 		{ sizeof( "mutable" ),             "mutable"             }, | ||||
| 		{ sizeof( "neverinline" ),         "neverinline"         }, | ||||
| 		{ sizeof( "override" ),            "override"            }, | ||||
| 		{ sizeof( "static" ),              "static"              }, | ||||
| 		{ sizeof( "thread_local" ),        "thread_local"        }, | ||||
| 		{ sizeof( "volatile" ),            "volatile"            }, | ||||
| 		{ sizeof( "virtual" ),             "virtual"             }, | ||||
| 		{ sizeof( "*" ),                   "*"                   }, | ||||
| 		{ sizeof( ";" ),                   ";"                   }, | ||||
| 		{ sizeof( "static_assert" ),       "static_assert"       }, | ||||
| 		{ sizeof( "__string__" ),          "__string__"          }, | ||||
| 		{ sizeof( "typename" ),            "typename"            }, | ||||
| 		{ sizeof( "unsigned" ),            "unsigned"            }, | ||||
| 		{ sizeof( "signed" ),              "signed"              }, | ||||
| 		{ sizeof( "short" ),               "short"               }, | ||||
| 		{ sizeof( "long" ),                "long"                }, | ||||
| 		{ sizeof( "bool" ),                "bool"                }, | ||||
| 		{ sizeof( "char" ),                "char"                }, | ||||
| 		{ sizeof( "int" ),                 "int"                 }, | ||||
| 		{ sizeof( "double" ),              "double"              }, | ||||
| 		{ sizeof( "__int8" ),              "__int8"              }, | ||||
| 		{ sizeof( "__int16" ),             "__int16"             }, | ||||
| 		{ sizeof( "__int32" ),             "__int32"             }, | ||||
| 		{ sizeof( "__int64" ),             "__int64"             }, | ||||
| 		{ sizeof( "_W64" ),                "_W64"                }, | ||||
| 		{ sizeof( "..." ),                 "..."                 }, | ||||
| 		{ sizeof( "__attrib_start__" ),    "__attrib_start__"    }, | ||||
| 		{ sizeof( "GEN_API_Export_Code" ), "GEN_API_Export_Code" }, | ||||
| 		{ sizeof( "GEN_API_Import_Code" ), "GEN_API_Import_Code" }, | ||||
| 	}; | ||||
| 	return lookup[type]; | ||||
| } | ||||
|  | ||||
| inline TokType strc_to_toktype( StrC str ) | ||||
| { | ||||
| 	local_persist u32 keymap[Tok_NumTokens]; | ||||
| 	do_once_start for ( u32 index = 0; index < Tok_NumTokens; index++ ) | ||||
| 	{ | ||||
| 		StrC enum_str = toktype_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 < Tok_NumTokens; index++ ) | ||||
| 	{ | ||||
| 		if ( keymap[index] == hash ) | ||||
| 			return (TokType)index; | ||||
| 	} | ||||
| 	return Tok_Invalid; | ||||
| } | ||||
|  | ||||
| GEN_NS_PARSER_END | ||||
							
								
								
									
										157
									
								
								base/components/header_end.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								base/components/header_end.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,157 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #pragma once | ||||
| #include "inlines.hpp" | ||||
| #include "gen/ast_inlines.hpp" | ||||
| #endif | ||||
|  | ||||
| #pragma region Constants | ||||
|  | ||||
| #ifndef GEN_GLOBAL_BUCKET_SIZE | ||||
| #	define GEN_GLOBAL_BUCKET_SIZE megabytes(8) | ||||
| #endif | ||||
| #ifndef GEN_CODEPOOL_NUM_BLOCKS | ||||
| #	define GEN_CODEPOOL_NUM_BLOCKS kilobytes(16) | ||||
| #endif | ||||
| #ifndef GEN_SIZE_PER_STRING_ARENA | ||||
| #	define GEN_SIZE_PER_STRING_ARENA megabytes(1) | ||||
| #endif | ||||
| #ifndef GEN_MAX_COMMENT_LINE_LENGTH | ||||
| #	define GEN_MAX_COMMENT_LINE_LENGTH 1024 | ||||
| #endif | ||||
| #ifndef GEN_MAX_NAME_LENGTH | ||||
| #	define GEN_MAX_NAME_LENGTH 128 | ||||
| #endif | ||||
| #ifndef GEN_MAX_UNTYPED_STR_LENGTH | ||||
| #	define GEN_MAX_UNTYPED_STR_LENGTH megabytes(1) | ||||
| #endif | ||||
| #ifndef TokenMap_FixedArena | ||||
| #	define TokenMap_FixedArena FixedArena_8KB | ||||
| #endif | ||||
| #ifndef GEN_LEX_ALLOCATOR_SIZE | ||||
| #	define GEN_LEX_ALLOCATOR_SIZE megabytes(4) | ||||
| #endif | ||||
| #ifndef GEN_BUILDER_STR_BUFFER_RESERVE | ||||
| #	define GEN_BUILDER_STR_BUFFER_RESERVE megabytes(2) | ||||
| #endif | ||||
|  | ||||
| // These constexprs are used for allocation behavior of data structures | ||||
| // or string handling while constructing or serializing. | ||||
| // Change them to suit your needs. | ||||
|  | ||||
| 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 usize  Global_BucketSize      = GEN_GLOBAL_BUCKET_SIZE; | ||||
| constexpr s32 CodePool_NumBlocks        = GEN_CODEPOOL_NUM_BLOCKS; | ||||
| constexpr s32 SizePer_StringArena       = GEN_SIZE_PER_STRING_ARENA; | ||||
|  | ||||
| constexpr s32 MaxCommentLineLength      = GEN_MAX_COMMENT_LINE_LENGTH; | ||||
| constexpr s32 MaxNameLength             = GEN_MAX_NAME_LENGTH; | ||||
| constexpr s32 MaxUntypedStrLength       = GEN_MAX_UNTYPED_STR_LENGTH; | ||||
| // constexpr s32 TokenFmt_TokenMap_MemSize	= GEN_TOKEN_FMT_TOKEN_MAP_MEM_SIZE; | ||||
| constexpr s32 LexAllocator_Size         = GEN_LEX_ALLOCATOR_SIZE; | ||||
| constexpr s32 Builder_StrBufferReserve  = GEN_BUILDER_STR_BUFFER_RESERVE; | ||||
|  | ||||
| extern Code access_public; | ||||
| extern Code access_protected; | ||||
| extern Code access_private; | ||||
|  | ||||
| extern CodeAttributes attrib_api_export; | ||||
| extern CodeAttributes attrib_api_import; | ||||
|  | ||||
| extern Code module_global_fragment; | ||||
| extern Code module_private_fragment; | ||||
|  | ||||
| extern Code fmt_newline; | ||||
|  | ||||
| extern CodePragma pragma_once; | ||||
|  | ||||
| extern CodeParam param_varadic; | ||||
|  | ||||
| extern CodePreprocessCond preprocess_else; | ||||
| extern CodePreprocessCond preprocess_endif; | ||||
|  | ||||
| extern CodeSpecifiers spec_const; | ||||
| extern CodeSpecifiers spec_consteval; | ||||
| extern CodeSpecifiers spec_constexpr; | ||||
| extern CodeSpecifiers spec_constinit; | ||||
| extern CodeSpecifiers spec_extern_linkage; | ||||
| extern CodeSpecifiers spec_final; | ||||
| extern CodeSpecifiers spec_forceinline; | ||||
| extern CodeSpecifiers spec_global; | ||||
| extern CodeSpecifiers spec_inline; | ||||
| extern CodeSpecifiers spec_internal_linkage; | ||||
| extern CodeSpecifiers spec_local_persist; | ||||
| extern CodeSpecifiers spec_mutable; | ||||
| extern CodeSpecifiers spec_neverinline; | ||||
| extern CodeSpecifiers spec_noexcept; | ||||
| extern CodeSpecifiers spec_override; | ||||
| extern CodeSpecifiers spec_ptr; | ||||
| extern CodeSpecifiers spec_pure; | ||||
| extern CodeSpecifiers spec_ref; | ||||
| extern CodeSpecifiers spec_register; | ||||
| extern CodeSpecifiers spec_rvalue; | ||||
| extern CodeSpecifiers spec_static_member; | ||||
| extern CodeSpecifiers spec_thread_local; | ||||
| extern CodeSpecifiers spec_virtual; | ||||
| extern CodeSpecifiers spec_volatile; | ||||
|  | ||||
| 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 CodeTypename t_b32; | ||||
|  | ||||
| 	extern CodeTypename t_s8; | ||||
| 	extern CodeTypename t_s16; | ||||
| 	extern CodeTypename t_s32; | ||||
| 	extern CodeTypename t_s64; | ||||
|  | ||||
| 	extern CodeTypename t_u8; | ||||
| 	extern CodeTypename t_u16; | ||||
| 	extern CodeTypename t_u32; | ||||
| 	extern CodeTypename t_u64; | ||||
|  | ||||
| 	extern CodeTypename t_ssize; | ||||
| 	extern CodeTypename t_usize; | ||||
|  | ||||
| 	extern CodeTypename t_f32; | ||||
| 	extern CodeTypename t_f64; | ||||
| #endif | ||||
|  | ||||
| #pragma endregion Constants | ||||
|  | ||||
| // 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; | ||||
|  | ||||
| #ifdef GEN_EXPOSE_BACKEND | ||||
| 	// Global allocator used for data with process lifetime. | ||||
| 	extern AllocatorInfo  GlobalAllocator; | ||||
| 	extern Array(Arena) Global_AllocatorBuckets; | ||||
|  | ||||
| 	extern Array(Pool)  CodePools; | ||||
| 	extern Array(Arena) StringArenas; | ||||
|  | ||||
| 	extern StringTable StringCache; | ||||
|  | ||||
| 	extern Arena LexArena; | ||||
|  | ||||
| 	extern AllocatorInfo Allocator_DataArrays; | ||||
| 	extern AllocatorInfo Allocator_CodePool; | ||||
| 	extern AllocatorInfo Allocator_Lexer; | ||||
| 	extern AllocatorInfo Allocator_StringArena; | ||||
| 	extern AllocatorInfo Allocator_StringTable; | ||||
| 	extern AllocatorInfo Allocator_TypeTable; | ||||
| #endif | ||||
							
								
								
									
										32
									
								
								base/components/header_start.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								base/components/header_start.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| #pragma once | ||||
|  | ||||
| /* | ||||
| 	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  --------------------------------------------------------------. | ||||
| 	|   _____                               _____ _                       _                        | | ||||
| 	|  / ____)                             / ____} |                     | |                       | | ||||
| 	| | / ___  ___ _ __   ___ _ __  _ __  | {___ | |__ _ _, __ _, ___  __| |                       | | ||||
| 	| | |{_  |/ _ \ '_ \ / __} '_ l| '_ l `\___ \| __/ _` |/ _` |/ _ \/ _` |                       | | ||||
| 	| | l__j | ___/ | | | {__; |+l } |+l | ____) | l| (_| | {_| | ___/ (_| |                       | | ||||
| 	|  \_____|\___}_l |_|\___} ,__/| ,__/ (_____/ \__\__/_|\__, |\___}\__,_l                       | | ||||
| 	|                        | |   | |                      __} |                                  | | ||||
| 	|                        l_l   l_l                     {___/                                   | | ||||
| 	! ----------------------------------------------------------------------- VERSION: v0.20-Alpha | | ||||
| 	! ============================================================================================ | | ||||
| 	! WARNING: THIS IS AN ALPHA VERSION OF THE LIBRARY, USE AT YOUR OWN DISCRETION                 | | ||||
| 	! NEVER DO CODE GENERATION WITHOUT AT LEAST HAVING CONTENT IN A CODEBASE UNDER VERSION CONTROL | | ||||
| 	! ============================================================================================ / | ||||
| */ | ||||
| #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 | ||||
							
								
								
									
										414
									
								
								base/components/inlines.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										414
									
								
								base/components/inlines.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,414 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #pragma once | ||||
| #include "interface.hpp" | ||||
| #endif | ||||
|  | ||||
| #pragma region Code | ||||
| inline | ||||
| void code_append( Code self, Code other ) | ||||
| { | ||||
| 	GEN_ASSERT(self); | ||||
| 	GEN_ASSERT(other); | ||||
| 	GEN_ASSERT_MSG(self != other, "Attempted to recursively append Code AST to itself."); | ||||
|  | ||||
| 	if ( other->Parent != nullptr ) | ||||
| 		other = code_duplicate(other); | ||||
|  | ||||
| 	other->Parent = self; | ||||
|  | ||||
| 	if ( self->Front == nullptr ) | ||||
| 	{ | ||||
| 		self->Front = other; | ||||
| 		self->Back  = other; | ||||
|  | ||||
| 		self->NumEntries++; | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	Code | ||||
| 	Current       = self->Back; | ||||
| 	Current->Next = other; | ||||
| 	other->Prev   = Current; | ||||
| 	self->Back    = other; | ||||
| 	self->NumEntries++; | ||||
| } | ||||
| inline | ||||
| bool code_is_body(Code self) | ||||
| { | ||||
| 	GEN_ASSERT(self); | ||||
| 	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* code_entry( Code self, u32 idx ) | ||||
| { | ||||
| 	GEN_ASSERT(self != nullptr); | ||||
| 	Code* current = & self->Front; | ||||
| 	while ( idx >= 0 && current != nullptr ) | ||||
| 	{ | ||||
| 		if ( idx == 0 ) | ||||
| 			return rcast( Code*, current); | ||||
|  | ||||
| 		current = & ( * current )->Next; | ||||
| 		idx--; | ||||
| 	} | ||||
|  | ||||
| 	return rcast( Code*, current); | ||||
| } | ||||
| forceinline | ||||
| bool code_is_valid(Code self) | ||||
| { | ||||
| 	GEN_ASSERT(self); | ||||
| 	return self != nullptr && self->Type != CT_Invalid; | ||||
| } | ||||
| forceinline | ||||
| bool code_has_entries(AST* self) | ||||
| { | ||||
| 	GEN_ASSERT(self); | ||||
| 	return self->NumEntries > 0; | ||||
| } | ||||
| forceinline | ||||
| void code_set_global(Code self) | ||||
| { | ||||
| 	if ( self == nullptr ) | ||||
| 	{ | ||||
| 		log_failure("Code::set_global: Cannot set code as global, AST is null!"); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	self->Parent = Code_Global; | ||||
| } | ||||
| #if GEN_COMPILER_CPP | ||||
| forceinline | ||||
| Code& Code::operator ++() | ||||
| { | ||||
| 	if ( ast ) | ||||
| 		ast = ast->Next.ast; | ||||
|  | ||||
| 	return * this; | ||||
| } | ||||
| #endif | ||||
| forceinline | ||||
| StrC code_type_str(Code self) | ||||
| { | ||||
| 	GEN_ASSERT(self != nullptr); | ||||
| 	return codetype_to_str( self->Type ); | ||||
| } | ||||
| #pragma endregion Code | ||||
|  | ||||
| #pragma region CodeBody | ||||
| inline | ||||
| void body_append( CodeBody self, Code other ) | ||||
| { | ||||
| 	GEN_ASSERT(self); | ||||
| 	GEN_ASSERT(other); | ||||
|  | ||||
| 	if (code_is_body(other)) { | ||||
| 		body_append_body( self, cast(CodeBody, other) ); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	code_append( cast(Code, self), other ); | ||||
| } | ||||
| inline | ||||
| void body_append_body( CodeBody self, CodeBody body ) | ||||
| { | ||||
| 	GEN_ASSERT(self); | ||||
| 	GEN_ASSERT(body); | ||||
| 	GEN_ASSERT_MSG(self != body, "Attempted to append body to itself."); | ||||
|  | ||||
| 	for ( Code entry = begin_CodeBody(body); entry != end_CodeBody(body); entry = next_CodeBody(body, entry) ) { | ||||
| 		body_append( self, entry ); | ||||
| 	} | ||||
| } | ||||
| inline | ||||
| Code begin_CodeBody( CodeBody body) { | ||||
| 	GEN_ASSERT(body); | ||||
| 	if ( body != nullptr ) | ||||
| 		return body->Front; | ||||
|  | ||||
| 	return NullCode; | ||||
| } | ||||
| forceinline | ||||
| Code end_CodeBody(CodeBody body ){ | ||||
| 	GEN_ASSERT(body); | ||||
| 	return body->Back->Next; | ||||
| } | ||||
| inline | ||||
| Code next_CodeBody(CodeBody body, Code entry) { | ||||
| 	GEN_ASSERT(body); | ||||
| 	GEN_ASSERT(entry); | ||||
| 	return entry->Next; | ||||
| } | ||||
| #pragma endregion CodeBody | ||||
|  | ||||
| #pragma region CodeClass | ||||
| inline | ||||
| void class_add_interface( CodeClass self, CodeTypename type ) | ||||
| { | ||||
| 	GEN_ASSERT(self); | ||||
| 	GEN_ASSERT(type); | ||||
| 	CodeTypename possible_slot = self->ParentType; | ||||
| 	if ( possible_slot != nullptr ) | ||||
| 	{ | ||||
| 		// Were adding an interface to parent type, so we need to make sure the parent type is 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 != nullptr ) | ||||
| 	{ | ||||
| 		possible_slot = cast(CodeTypename, possible_slot->Next); | ||||
| 	} | ||||
|  | ||||
| 	possible_slot = type; | ||||
| } | ||||
| #pragma endregion CodeClass | ||||
|  | ||||
| #pragma region CodeParam | ||||
| inline | ||||
| void params_append( CodeParam appendee, CodeParam other ) | ||||
| { | ||||
| 	GEN_ASSERT(appendee); | ||||
| 	GEN_ASSERT(other); | ||||
| 	GEN_ASSERT_MSG(appendee != other, "Attempted to append parameter to itself."); | ||||
| 	Code self  = cast(Code, appendee); | ||||
| 	Code entry = cast(Code, other); | ||||
|  | ||||
| 	if ( entry->Parent != nullptr ) | ||||
| 		entry = code_duplicate( entry ); | ||||
|  | ||||
| 	entry->Parent = self; | ||||
|  | ||||
| 	if ( self->Last == nullptr ) | ||||
| 	{ | ||||
| 		self->Last = entry; | ||||
| 		self->Next = entry; | ||||
| 		self->NumEntries++; | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	self->Last->Next = entry; | ||||
| 	self->Last       = entry; | ||||
| 	self->NumEntries++; | ||||
| } | ||||
| inline | ||||
| CodeParam params_get(CodeParam self, s32 idx ) | ||||
| { | ||||
| 	GEN_ASSERT(self); | ||||
| 	CodeParam param = self; | ||||
| 	do | ||||
| 	{ | ||||
| 		if ( ++ param != nullptr ) | ||||
| 			return NullCode; | ||||
|  | ||||
| 		param = cast(CodeParam, cast(Code, param)->Next); | ||||
| 	} | ||||
| 	while ( --idx ); | ||||
|  | ||||
| 	return param; | ||||
| } | ||||
| forceinline | ||||
| bool params_has_entries(CodeParam self) | ||||
| { | ||||
| 	GEN_ASSERT(self); | ||||
| 	return self->NumEntries > 0; | ||||
| } | ||||
| #if GEN_COMPILER_CPP | ||||
| forceinline | ||||
| CodeParam& CodeParam::operator ++() | ||||
| { | ||||
| 	* this = ast->Next; | ||||
| 	return * this; | ||||
| } | ||||
| #endif | ||||
| forceinline | ||||
| CodeParam begin_CodeParam(CodeParam params) | ||||
| { | ||||
| 	if ( params != nullptr ) | ||||
| 		return params; | ||||
|  | ||||
| 	return NullCode; | ||||
| } | ||||
| forceinline | ||||
| CodeParam end_CodeParam(CodeParam params) | ||||
| { | ||||
| 	// return { (AST_Param*) rcast( AST*, ast)->Last }; | ||||
| 	return NullCode; | ||||
| } | ||||
| forceinline | ||||
| CodeParam next_CodeParam(CodeParam params, CodeParam param_iter) | ||||
| { | ||||
| 	GEN_ASSERT(param_iter); | ||||
| 	return param_iter->Next; | ||||
| } | ||||
| #pragma endregion CodeParam | ||||
|  | ||||
| #pragma region CodeSpecifiers | ||||
| inline | ||||
| bool specifiers_append(CodeSpecifiers self, Specifier spec ) | ||||
| { | ||||
| 	if ( self == 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 specifiers_has(CodeSpecifiers self, Specifier spec) | ||||
| { | ||||
| 	GEN_ASSERT(self != nullptr); | ||||
| 	for ( s32 idx = 0; idx < self->NumEntries; idx++ ) { | ||||
| 		if ( self->ArrSpecs[ idx ] == spec ) | ||||
| 			return idx; | ||||
| 	} | ||||
| 	return -1; | ||||
| } | ||||
| inline | ||||
| s32 specifiers_remove( CodeSpecifiers self, Specifier to_remove ) | ||||
| { | ||||
| 	if ( self == 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; | ||||
| } | ||||
| forceinline | ||||
| Specifier* begin_CodeSpecifiers(CodeSpecifiers self) | ||||
| { | ||||
| 	if ( self != nullptr ) | ||||
| 		return & self->ArrSpecs[0]; | ||||
|  | ||||
| 	return nullptr; | ||||
| } | ||||
| forceinline | ||||
| Specifier* end_CodeSpecifiers(CodeSpecifiers self) | ||||
| { | ||||
| 	return self->ArrSpecs + self->NumEntries; | ||||
| } | ||||
| forceinline | ||||
| Specifier* next_CodeSpecifiers(CodeSpecifiers self, Specifier* spec_iter) | ||||
| { | ||||
| 	return spec_iter + 1; | ||||
| } | ||||
| #pragma endregion CodeSpecifiers | ||||
|  | ||||
| #pragma region CodeStruct | ||||
| inline | ||||
| void struct_add_interface(CodeStruct self, CodeTypename type ) | ||||
| { | ||||
| 	CodeTypename possible_slot = self->ParentType; | ||||
| 	if ( possible_slot != nullptr ) | ||||
| 	{ | ||||
| 		// Were adding an interface to parent type, so we need to make sure the parent type is 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 != nullptr ) | ||||
| 	{ | ||||
| 		possible_slot = cast(CodeTypename, possible_slot->Next); | ||||
| 	} | ||||
|  | ||||
| 	possible_slot = type; | ||||
| } | ||||
| #pragma endregion Code | ||||
|  | ||||
| #pragma region Interface | ||||
| inline | ||||
| CodeBody def_body( CodeType type ) | ||||
| { | ||||
| 	switch ( type ) | ||||
| 	{ | ||||
| 		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", codetype_to_str(type).Ptr ); | ||||
| 			return (CodeBody)Code_Invalid; | ||||
| 	} | ||||
|  | ||||
| 	Code | ||||
| 	result       = make_code(); | ||||
| 	result->Type = type; | ||||
| 	return (CodeBody)result; | ||||
| } | ||||
|  | ||||
| inline | ||||
| StrC token_fmt_impl( ssize num, ... ) | ||||
| { | ||||
| 	local_persist thread_local | ||||
| 	char buf[GEN_PRINTF_MAXLEN] = { 0 }; | ||||
| 	mem_set( buf, 0, GEN_PRINTF_MAXLEN ); | ||||
|  | ||||
| 	va_list va; | ||||
| 	va_start(va, num ); | ||||
| 	ssize result = token_fmt_va(buf, GEN_PRINTF_MAXLEN, num, va); | ||||
| 	va_end(va); | ||||
|  | ||||
| 	StrC str = { result, buf }; | ||||
| 	return str; | ||||
| } | ||||
| #pragma endregion Interface | ||||
							
								
								
									
										462
									
								
								base/components/interface.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										462
									
								
								base/components/interface.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,462 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #pragma once | ||||
| #include "code_serialization.cpp" | ||||
| #endif | ||||
|  | ||||
| GEN_NS_PARSER_BEGIN | ||||
| internal void parser_init(); | ||||
| internal void parser_deinit(); | ||||
| GEN_NS_PARSER_END | ||||
|  | ||||
| internal | ||||
| void* Global_Allocator_Proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ) | ||||
| { | ||||
| 	Arena* last = array_back(Global_AllocatorBuckets); | ||||
|  | ||||
| 	switch ( type ) | ||||
| 	{ | ||||
| 		case EAllocation_ALLOC: | ||||
| 		{ | ||||
| 			if ( ( last->TotalUsed + size ) > last->TotalSize ) | ||||
| 			{ | ||||
| 				Arena bucket = arena_init_from_allocator( heap(), Global_BucketSize ); | ||||
|  | ||||
| 				if ( bucket.PhysicalStart == nullptr ) | ||||
| 					GEN_FATAL( "Failed to create bucket for Global_AllocatorBuckets"); | ||||
|  | ||||
| 				if ( ! array_append( Global_AllocatorBuckets, bucket ) ) | ||||
| 					GEN_FATAL( "Failed to append bucket to Global_AllocatorBuckets"); | ||||
|  | ||||
| 				last = array_back(Global_AllocatorBuckets); | ||||
| 			} | ||||
|  | ||||
| 			return alloc_align( arena_allocator_info(last), size, alignment ); | ||||
| 		} | ||||
| 		case EAllocation_FREE: | ||||
| 		{ | ||||
| 			// Doesn't recycle. | ||||
| 		} | ||||
| 		break; | ||||
| 		case EAllocation_FREE_ALL: | ||||
| 		{ | ||||
| 			// Memory::cleanup instead. | ||||
| 		} | ||||
| 		break; | ||||
| 		case EAllocation_RESIZE: | ||||
| 		{ | ||||
| 			if ( last->TotalUsed + size > last->TotalSize ) | ||||
| 			{ | ||||
| 				Arena bucket = arena_init_from_allocator( heap(), Global_BucketSize ); | ||||
|  | ||||
| 				if ( bucket.PhysicalStart == nullptr ) | ||||
| 					GEN_FATAL( "Failed to create bucket for Global_AllocatorBuckets"); | ||||
|  | ||||
| 				if ( ! array_append( Global_AllocatorBuckets, bucket ) ) | ||||
| 					GEN_FATAL( "Failed to append bucket to Global_AllocatorBuckets"); | ||||
|  | ||||
| 				last = array_back(Global_AllocatorBuckets); | ||||
| 			} | ||||
|  | ||||
| 			void* result = alloc_align( last->Backing, size, alignment ); | ||||
|  | ||||
| 			if ( result != nullptr && old_memory != nullptr ) | ||||
| 			{ | ||||
| 				mem_copy( result, old_memory, old_size ); | ||||
| 			} | ||||
|  | ||||
| 			return result; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nullptr; | ||||
| } | ||||
|  | ||||
| internal | ||||
| void define_constants() | ||||
| { | ||||
| 	Code_Global          = make_code(); | ||||
| 	Code_Global->Name    = get_cached_string( txt("Global Code") ); | ||||
| 	Code_Global->Content = Code_Global->Name; | ||||
|  | ||||
| 	Code_Invalid = make_code(); | ||||
| 	code_set_global(Code_Invalid); | ||||
|  | ||||
| 	t_empty       = (CodeTypename) make_code(); | ||||
| 	t_empty->Type = CT_Typename; | ||||
| 	t_empty->Name = get_cached_string( txt("") ); | ||||
| 	code_set_global(cast(Code, t_empty)); | ||||
|  | ||||
| 	access_private       = make_code(); | ||||
| 	access_private->Type = CT_Access_Private; | ||||
| 	access_private->Name = get_cached_string( txt("private:\n") ); | ||||
| 	code_set_global(cast(Code, access_private)); | ||||
|  | ||||
| 	access_protected       = make_code(); | ||||
| 	access_protected->Type = CT_Access_Protected; | ||||
| 	access_protected->Name = get_cached_string( txt("protected:\n") ); | ||||
| 	code_set_global(access_protected); | ||||
|  | ||||
| 	access_public       = make_code(); | ||||
| 	access_public->Type = CT_Access_Public; | ||||
| 	access_public->Name = get_cached_string( txt("public:\n") ); | ||||
| 	code_set_global(access_public); | ||||
|  | ||||
| 	StrC api_export_str = code(GEN_API_Export_Code); | ||||
| 	attrib_api_export = def_attributes( api_export_str ); | ||||
| 	code_set_global(cast(Code, attrib_api_export)); | ||||
|  | ||||
| 	StrC api_import_str = code(GEN_API_Import_Code); | ||||
| 	attrib_api_import = def_attributes( api_import_str ); | ||||
| 	code_set_global(cast(Code, attrib_api_import)); | ||||
|  | ||||
| 	module_global_fragment          = make_code(); | ||||
| 	module_global_fragment->Type    = CT_Untyped; | ||||
| 	module_global_fragment->Name    = get_cached_string( txt("module;") ); | ||||
| 	module_global_fragment->Content = module_global_fragment->Name; | ||||
| 	code_set_global(cast(Code, module_global_fragment)); | ||||
|  | ||||
| 	module_private_fragment          = make_code(); | ||||
| 	module_private_fragment->Type    = CT_Untyped; | ||||
| 	module_private_fragment->Name    = get_cached_string( txt("module : private;") ); | ||||
| 	module_private_fragment->Content = module_private_fragment->Name; | ||||
| 	code_set_global(cast(Code, module_private_fragment)); | ||||
|  | ||||
| 	fmt_newline = make_code(); | ||||
| 	fmt_newline->Type = CT_NewLine; | ||||
| 	code_set_global((Code)fmt_newline); | ||||
|  | ||||
| 	pragma_once          = (CodePragma) make_code(); | ||||
| 	pragma_once->Type    = CT_Preprocess_Pragma; | ||||
| 	pragma_once->Name    = get_cached_string( txt("once") ); | ||||
| 	pragma_once->Content = pragma_once->Name; | ||||
| 	code_set_global((Code)pragma_once); | ||||
|  | ||||
| 	param_varadic            = (CodeParam) make_code(); | ||||
| 	param_varadic->Type      = CT_Parameters; | ||||
| 	param_varadic->Name      = get_cached_string( txt("...") ); | ||||
| 	param_varadic->ValueType = t_empty; | ||||
| 	code_set_global((Code)param_varadic); | ||||
|  | ||||
| 	preprocess_else = (CodePreprocessCond) make_code(); | ||||
| 	preprocess_else->Type = CT_Preprocess_Else; | ||||
| 	code_set_global((Code)preprocess_else); | ||||
|  | ||||
| 	preprocess_endif = (CodePreprocessCond) make_code(); | ||||
| 	preprocess_endif->Type = CT_Preprocess_EndIf; | ||||
| 	code_set_global((Code)preprocess_endif); | ||||
|  | ||||
| #	define def_constant_code_type( Type_ )           \ | ||||
| 		do                                           \ | ||||
| 		{                                            \ | ||||
| 			StrC name_str = name(Type_);             \ | ||||
| 			t_##Type_ = def_type( name_str );        \ | ||||
| 			code_set_global( cast(Code, t_##Type_)); \ | ||||
| 		} while(0) | ||||
|  | ||||
| 	def_constant_code_type( auto ); | ||||
| 	def_constant_code_type( void ); | ||||
| 	def_constant_code_type( int ); | ||||
| 	def_constant_code_type( bool ); | ||||
| 	def_constant_code_type( char ); | ||||
| 	def_constant_code_type( wchar_t ); | ||||
| 	def_constant_code_type( class ); | ||||
| 	def_constant_code_type( typename ); | ||||
|  | ||||
| #ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS | ||||
| 	t_b32 = def_type( name(b32) ); | ||||
|  | ||||
| 	def_constant_code_type( s8 ); | ||||
| 	def_constant_code_type( s16 ); | ||||
| 	def_constant_code_type( s32 ); | ||||
| 	def_constant_code_type( s64 ); | ||||
|  | ||||
| 	def_constant_code_type( u8 ); | ||||
| 	def_constant_code_type( u16 ); | ||||
| 	def_constant_code_type( u32 ); | ||||
| 	def_constant_code_type( u64 ); | ||||
|  | ||||
| 	def_constant_code_type( ssize ); | ||||
| 	def_constant_code_type( usize ); | ||||
|  | ||||
| 	def_constant_code_type( f32 ); | ||||
| 	def_constant_code_type( f64 ); | ||||
| #endif | ||||
| #	undef def_constant_code_type | ||||
|  | ||||
|  | ||||
| 	spec_const            = def_specifier( Spec_Const);            code_set_global( cast(Code, spec_const )); | ||||
| 	spec_consteval        = def_specifier( Spec_Consteval);        code_set_global( cast(Code, spec_consteval ));; | ||||
| 	spec_constexpr        = def_specifier( Spec_Constexpr);        code_set_global( cast(Code, spec_constexpr ));; | ||||
| 	spec_constinit        = def_specifier( Spec_Constinit);        code_set_global( cast(Code, spec_constinit ));; | ||||
| 	spec_extern_linkage   = def_specifier( Spec_External_Linkage); code_set_global( cast(Code, spec_extern_linkage ));; | ||||
| 	spec_final            = def_specifier( Spec_Final);            code_set_global( cast(Code, spec_final ));; | ||||
| 	spec_forceinline      = def_specifier( Spec_ForceInline);      code_set_global( cast(Code, spec_forceinline ));; | ||||
| 	spec_global           = def_specifier( Spec_Global);           code_set_global( cast(Code, spec_global ));; | ||||
| 	spec_inline           = def_specifier( Spec_Inline);           code_set_global( cast(Code, spec_inline ));; | ||||
| 	spec_internal_linkage = def_specifier( Spec_Internal_Linkage); code_set_global( cast(Code, spec_internal_linkage ));; | ||||
| 	spec_local_persist    = def_specifier( Spec_Local_Persist);    code_set_global( cast(Code, spec_local_persist ));; | ||||
| 	spec_mutable          = def_specifier( Spec_Mutable);          code_set_global( cast(Code, spec_mutable ));; | ||||
| 	spec_neverinline      = def_specifier( Spec_NeverInline);      code_set_global( cast(Code, spec_neverinline ));; | ||||
| 	spec_noexcept         = def_specifier( Spec_NoExceptions);     code_set_global( cast(Code, spec_noexcept ));; | ||||
| 	spec_override         = def_specifier( Spec_Override);         code_set_global( cast(Code, spec_override ));; | ||||
| 	spec_ptr              = def_specifier( Spec_Ptr);              code_set_global( cast(Code, spec_ptr ));; | ||||
| 	spec_pure             = def_specifier( Spec_Pure);             code_set_global( cast(Code, spec_pure )); | ||||
| 	spec_ref              = def_specifier( Spec_Ref);              code_set_global( cast(Code, spec_ref ));; | ||||
| 	spec_register         = def_specifier( Spec_Register);         code_set_global( cast(Code, spec_register ));; | ||||
| 	spec_rvalue           = def_specifier( Spec_RValue);           code_set_global( cast(Code, spec_rvalue ));; | ||||
| 	spec_static_member    = def_specifier( Spec_Static);           code_set_global( cast(Code, spec_static_member ));; | ||||
| 	spec_thread_local     = def_specifier( Spec_Thread_Local);     code_set_global( cast(Code, spec_thread_local ));; | ||||
| 	spec_virtual          = def_specifier( Spec_Virtual);          code_set_global( cast(Code, spec_virtual ));; | ||||
| 	spec_volatile         = def_specifier( Spec_Volatile);         code_set_global( cast(Code, spec_volatile )); | ||||
|  | ||||
| 	spec_local_persist = def_specifiers( 1, Spec_Local_Persist ); | ||||
| 	code_set_global(cast(Code, spec_local_persist)); | ||||
|  | ||||
| #	pragma push_macro("enum_underlying") | ||||
| 	array_append(PreprocessorDefines, txt("enum_underlying(")); | ||||
| #	pragma pop_macro("enum_underlying") | ||||
|  | ||||
| #	undef def_constant_spec | ||||
| } | ||||
|  | ||||
| void init() | ||||
| { | ||||
| 	// Setup global allocator | ||||
| 	{ | ||||
| 		AllocatorInfo becasue_C = { & Global_Allocator_Proc, nullptr }; | ||||
| 		GlobalAllocator = becasue_C; | ||||
|  | ||||
| 		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 ); | ||||
|  | ||||
| 		if ( bucket.PhysicalStart == nullptr ) | ||||
| 			GEN_FATAL( "Failed to create first bucket for Global_AllocatorBuckets"); | ||||
|  | ||||
| 		array_append( Global_AllocatorBuckets, bucket ); | ||||
| 	} | ||||
|  | ||||
| 	if (Allocator_DataArrays.Proc == nullptr) { | ||||
| 		Allocator_DataArrays = heap(); | ||||
| 	} | ||||
| 	if (Allocator_CodePool.Proc == nullptr ) { | ||||
| 		Allocator_CodePool = heap(); | ||||
| 	} | ||||
| 	if (Allocator_Lexer.Proc == nullptr) { | ||||
| 		Allocator_Lexer = heap(); | ||||
| 	} | ||||
| 	if (Allocator_StringArena.Proc == nullptr) { | ||||
| 		Allocator_StringArena = heap(); | ||||
| 	} | ||||
| 	if (Allocator_StringTable.Proc == nullptr) { | ||||
| 		Allocator_StringTable = heap(); | ||||
| 	} | ||||
| 	if (Allocator_TypeTable.Proc == nullptr) { | ||||
| 		Allocator_TypeTable = heap(); | ||||
| 	} | ||||
|  | ||||
| 	// Setup the arrays | ||||
| 	{ | ||||
| 		CodePools = array_init_reserve(Pool, Allocator_DataArrays, InitSize_DataArrays ); | ||||
|  | ||||
| 		if ( CodePools == nullptr ) | ||||
| 			GEN_FATAL( "gen::init: Failed to initialize the CodePools array" ); | ||||
|  | ||||
| 		StringArenas = array_init_reserve(Arena, Allocator_DataArrays, InitSize_DataArrays ); | ||||
|  | ||||
| 		if ( StringArenas == nullptr ) | ||||
| 			GEN_FATAL( "gen::init: Failed to initialize the StringArenas array" ); | ||||
| 	} | ||||
|  | ||||
| 	// Setup the code pool and code entries arena. | ||||
| 	{ | ||||
| 		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" ); | ||||
|  | ||||
| 		array_append( CodePools, code_pool ); | ||||
|  | ||||
| 		LexArena = arena_init_from_allocator( Allocator_Lexer, LexAllocator_Size ); | ||||
|  | ||||
| 		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" ); | ||||
|  | ||||
| 		array_append( StringArenas, string_arena ); | ||||
| 	} | ||||
|  | ||||
| 	// Setup the hash tables | ||||
| 	{ | ||||
| 		StringCache = hashtable_init(StringCached, Allocator_StringTable); | ||||
|  | ||||
| 		if ( StringCache.Entries == nullptr ) | ||||
| 			GEN_FATAL( "gen::init: Failed to initialize the StringCache"); | ||||
| 	} | ||||
|  | ||||
| 	// Preprocessor Defines | ||||
| 	PreprocessorDefines = array_init_reserve(StringCached, GlobalAllocator, kilobytes(1) ); | ||||
|  | ||||
| 	define_constants(); | ||||
| 	GEN_NS_PARSER parser_init(); | ||||
| } | ||||
|  | ||||
| void deinit() | ||||
| { | ||||
| 	usize index = 0; | ||||
| 	usize left  = array_num(CodePools); | ||||
| 	do | ||||
| 	{ | ||||
| 		Pool* code_pool = & CodePools[index]; | ||||
| 		pool_free(code_pool); | ||||
| 		index++; | ||||
| 	} | ||||
| 	while ( left--, left ); | ||||
|  | ||||
| 	index = 0; | ||||
| 	left  = array_num(StringArenas); | ||||
| 	do | ||||
| 	{ | ||||
| 		Arena* string_arena = & StringArenas[index]; | ||||
| 		arena_free(string_arena); | ||||
| 		index++; | ||||
| 	} | ||||
| 	while ( left--, left ); | ||||
|  | ||||
| 	hashtable_destroy(StringCache); | ||||
|  | ||||
| 	array_free( CodePools); | ||||
| 	array_free( StringArenas); | ||||
|  | ||||
| 	arena_free(& LexArena); | ||||
|  | ||||
| 	array_free(PreprocessorDefines); | ||||
|  | ||||
| 	index = 0; | ||||
| 	left  = array_num(Global_AllocatorBuckets); | ||||
| 	do | ||||
| 	{ | ||||
| 		Arena* bucket = & Global_AllocatorBuckets[ index ]; | ||||
| 		arena_free(bucket); | ||||
| 		index++; | ||||
| 	} | ||||
| 	while ( left--, left ); | ||||
|  | ||||
| 	array_free(Global_AllocatorBuckets); | ||||
| 	GEN_NS_PARSER parser_deinit(); | ||||
| } | ||||
|  | ||||
| void reset() | ||||
| { | ||||
| 	s32 index = 0; | ||||
| 	s32 left  = array_num(CodePools); | ||||
| 	do | ||||
| 	{ | ||||
| 		Pool* code_pool = & CodePools[index]; | ||||
| 		pool_clear(code_pool); | ||||
| 		index++; | ||||
| 	} | ||||
| 	while ( left--, left ); | ||||
|  | ||||
| 	index = 0; | ||||
| 	left  = array_num(StringArenas); | ||||
| 	do | ||||
| 	{ | ||||
| 		Arena* string_arena = & StringArenas[index]; | ||||
| 		string_arena->TotalUsed = 0;; | ||||
| 		index++; | ||||
| 	} | ||||
| 	while ( left--, left ); | ||||
|  | ||||
| 	hashtable_clear(StringCache); | ||||
|  | ||||
| 	define_constants(); | ||||
| } | ||||
|  | ||||
| AllocatorInfo get_string_allocator( s32 str_length ) | ||||
| { | ||||
| 	Arena* last = array_back(StringArenas); | ||||
|  | ||||
| 	usize size_req = str_length + sizeof(StringHeader) + sizeof(char*); | ||||
|  | ||||
| 	if ( last->TotalUsed + scast(ssize, size_req) > last->TotalSize ) | ||||
| 	{ | ||||
| 		Arena new_arena = arena_init_from_allocator( Allocator_StringArena, SizePer_StringArena ); | ||||
|  | ||||
| 		if ( ! array_append( StringArenas, new_arena ) ) | ||||
| 			GEN_FATAL( "gen::get_string_allocator: Failed to allocate a new string arena" ); | ||||
|  | ||||
| 		last = array_back(StringArenas); | ||||
| 	} | ||||
|  | ||||
| 	return arena_allocator_info(last); | ||||
| } | ||||
|  | ||||
| // Will either make or retrive a code string. | ||||
| 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 = hashtable_get(StringCache, key ); | ||||
|  | ||||
| 		if ( result ) | ||||
| 			return * result; | ||||
| 	} | ||||
|  | ||||
| 	StrC result = string_to_strc( string_make_strc( get_string_allocator( str.Len ), str )); | ||||
| 	hashtable_set(StringCache, key, result ); | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| // Used internally to retireve a Code object form the CodePool. | ||||
| Code make_code() | ||||
| { | ||||
| 	Pool* allocator = array_back( CodePools); | ||||
| 	if ( allocator->FreeList == nullptr ) | ||||
| 	{ | ||||
| 		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 ( ! array_append( CodePools, code_pool ) ) | ||||
| 			GEN_FATAL( "gen::make_code: Failed to allocate a new code pool - CodePools failed to append new pool." ); | ||||
|  | ||||
| 		allocator = array_back( CodePools); | ||||
| 	} | ||||
|  | ||||
| 	Code result = { rcast( AST*, alloc( pool_allocator_info(allocator), sizeof(AST) )) }; | ||||
| 	mem_set( rcast(void*, cast(AST*, result)), 0, sizeof(AST) ); | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| void set_allocator_data_arrays( AllocatorInfo allocator ) | ||||
| { | ||||
| 	Allocator_DataArrays = allocator; | ||||
| } | ||||
|  | ||||
| void set_allocator_code_pool( AllocatorInfo allocator ) | ||||
| { | ||||
| 	Allocator_CodePool = allocator; | ||||
| } | ||||
|  | ||||
| void set_allocator_lexer( AllocatorInfo allocator ) | ||||
| { | ||||
| 	Allocator_Lexer = allocator; | ||||
| } | ||||
|  | ||||
| void set_allocator_string_arena( AllocatorInfo allocator ) | ||||
| { | ||||
| 	Allocator_StringArena = allocator; | ||||
| } | ||||
|  | ||||
| void set_allocator_string_table( AllocatorInfo allocator ) | ||||
| { | ||||
| 	Allocator_StringArena = allocator; | ||||
| } | ||||
							
								
								
									
										343
									
								
								base/components/interface.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										343
									
								
								base/components/interface.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,343 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #pragma once | ||||
| #include "ast_types.hpp" | ||||
| #endif | ||||
|  | ||||
| #pragma region Gen Interface | ||||
| /* | ||||
|  /      \                       |      \          |  \                      /      \ | ||||
| |  ▓▓▓▓▓▓\ ______  _______       \▓▓▓▓▓▓_______  _| ▓▓_    ______   ______ |  ▓▓▓▓▓▓\ ______   _______  ______ | ||||
| | ▓▓ __\▓▓/      \|       \       | ▓▓ |       \|   ▓▓ \  /      \ /      \| ▓▓_  \▓▓|      \ /       \/      \ | ||||
| | ▓▓|    \  ▓▓▓▓▓▓\ ▓▓▓▓▓▓▓\      | ▓▓ | ▓▓▓▓▓▓▓\\▓▓▓▓▓▓ |  ▓▓▓▓▓▓\  ▓▓▓▓▓▓\ ▓▓ \     \▓▓▓▓▓▓\  ▓▓▓▓▓▓▓  ▓▓▓▓▓▓\ | ||||
| | ▓▓ \▓▓▓▓ ▓▓    ▓▓ ▓▓  | ▓▓      | ▓▓ | ▓▓  | ▓▓ | ▓▓ __| ▓▓    ▓▓ ▓▓   \▓▓ ▓▓▓▓    /      ▓▓ ▓▓     | ▓▓    ▓▓ | ||||
| | ▓▓__| ▓▓ ▓▓▓▓▓▓▓▓ ▓▓  | ▓▓     _| ▓▓_| ▓▓  | ▓▓ | ▓▓|  \ ▓▓▓▓▓▓▓▓ ▓▓     | ▓▓     |  ▓▓▓▓▓▓▓ ▓▓_____| ▓▓▓▓▓▓▓▓ | ||||
|  \▓▓    ▓▓\▓▓     \ ▓▓  | ▓▓    |   ▓▓ \ ▓▓  | ▓▓  \▓▓  ▓▓\▓▓     \ ▓▓     | ▓▓      \▓▓    ▓▓\▓▓     \\▓▓     \ | ||||
|   \▓▓▓▓▓▓  \▓▓▓▓▓▓▓\▓▓   \▓▓     \▓▓▓▓▓▓\▓▓   \▓▓   \▓▓▓▓  \▓▓▓▓▓▓▓\▓▓      \▓▓       \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ | ||||
| */ | ||||
|  | ||||
| // Initialize the library. | ||||
| void init(); | ||||
|  | ||||
| // Currently manually free's the arenas, code for checking for leaks. | ||||
| // However on Windows at least, it doesn't need to occur as the OS will clean up after the process. | ||||
| void deinit(); | ||||
|  | ||||
| // Clears the allocations, but doesn't return to the heap, the calls init() again. | ||||
| // Ease of use. | ||||
| void reset(); | ||||
|  | ||||
| // Used internally to retrive or make string allocations. | ||||
| // Strings are stored in a series of string arenas of fixed size (SizePer_StringArena) | ||||
| StringCached get_cached_string( StrC str ); | ||||
|  | ||||
| /* | ||||
| 	This provides a fresh Code AST. | ||||
| 	The gen interface use this as their method from getting a new AST object from the CodePool. | ||||
| 	Use this if you want to make your own API for formatting the supported Code Types. | ||||
| */ | ||||
| Code make_code(); | ||||
|  | ||||
| // Set these before calling gen's init() procedure. | ||||
|  | ||||
| void set_allocator_data_arrays ( AllocatorInfo data_array_allocator ); | ||||
| void set_allocator_code_pool   ( AllocatorInfo pool_allocator ); | ||||
| void set_allocator_lexer       ( AllocatorInfo lex_allocator ); | ||||
| void set_allocator_string_arena( AllocatorInfo string_allocator ); | ||||
| void set_allocator_string_table( AllocatorInfo string_allocator ); | ||||
| void set_allocator_type_table  ( AllocatorInfo type_reg_allocator ); | ||||
|  | ||||
| #pragma region Upfront | ||||
|  | ||||
| CodeAttributes def_attributes( StrC content ); | ||||
| CodeComment    def_comment   ( StrC content ); | ||||
|  | ||||
| struct Opts_def_struct { | ||||
| 	CodeBody       body; | ||||
| 	CodeTypename   parent; | ||||
| 	AccessSpec     parent_access; | ||||
| 	CodeAttributes attributes; | ||||
| 	CodeTypename*  interfaces; | ||||
| 	s32            num_interfaces; | ||||
| 	ModuleFlag     mflags; | ||||
| }; | ||||
| CodeClass def_class( StrC name, Opts_def_struct otps GEN_PARAM_DEFAULT ); | ||||
|  | ||||
| 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 ); | ||||
|  | ||||
| struct Opts_def_destructor { | ||||
| 	Code           body; | ||||
| 	CodeSpecifiers specifiers; | ||||
| }; | ||||
| CodeDestructor def_destructor( Opts_def_destructor opts GEN_PARAM_DEFAULT ); | ||||
|  | ||||
| struct Opts_def_enum { | ||||
| 	CodeBody       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, CodeBody body ); | ||||
| CodeFriend def_friend     ( Code symbol ); | ||||
|  | ||||
| struct Opts_def_function { | ||||
| 	CodeParam       params; | ||||
| 	CodeTypename    ret_type; | ||||
| 	CodeBody        body; | ||||
| 	CodeSpecifiers  specs; | ||||
| 	CodeAttributes  attrs; | ||||
| 	ModuleFlag      mflags; | ||||
| }; | ||||
| CodeFn def_function( StrC name, Opts_def_function opts GEN_PARAM_DEFAULT ); | ||||
|  | ||||
| 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, CodeBody body, Opts_def_namespace opts GEN_PARAM_DEFAULT ); | ||||
|  | ||||
| struct Opts_def_operator { | ||||
| 	CodeParam       params; | ||||
| 	CodeTypename    ret_type; | ||||
| 	CodeBody        body; | ||||
| 	CodeSpecifiers  specifiers; | ||||
| 	CodeAttributes  attributes; | ||||
| 	ModuleFlag      mflags; | ||||
| }; | ||||
| CodeOperator def_operator( Operator op, StrC nspace, Opts_def_operator opts GEN_PARAM_DEFAULT ); | ||||
|  | ||||
| struct Opts_def_operator_cast { | ||||
| 	CodeBody       body; | ||||
| 	CodeSpecifiers specs; | ||||
| }; | ||||
| CodeOpCast def_operator_cast( CodeTypename type, Opts_def_operator_cast opts GEN_PARAM_DEFAULT ); | ||||
|  | ||||
| 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( Specifier specifier ); | ||||
|  | ||||
| CodeStruct def_struct( StrC name, Opts_def_struct opts GEN_PARAM_DEFAULT ); | ||||
|  | ||||
| struct Opts_def_template { ModuleFlag mflags; }; | ||||
| CodeTemplate def_template( CodeParam params, Code definition, Opts_def_template opts GEN_PARAM_DEFAULT ); | ||||
|  | ||||
| struct Opts_def_type { | ||||
| 	ETypenameTag   type_tag; | ||||
| 	Code           arrayexpr; | ||||
| 	CodeSpecifiers specifiers; | ||||
| 	CodeAttributes attributes; | ||||
| }; | ||||
| CodeTypename def_type( StrC name, Opts_def_type opts GEN_PARAM_DEFAULT ); | ||||
|  | ||||
| struct Opts_def_typedef { | ||||
| 	CodeAttributes attributes; | ||||
| 	ModuleFlag     mflags; | ||||
| }; | ||||
| CodeTypedef def_typedef( StrC name, Code type, Opts_def_typedef opts GEN_PARAM_DEFAULT ); | ||||
|  | ||||
| struct Opts_def_union { | ||||
| 	CodeAttributes attributes; | ||||
| 	ModuleFlag     mflags; | ||||
| }; | ||||
| CodeUnion def_union( StrC name, CodeBody body, Opts_def_union opts GEN_PARAM_DEFAULT ); | ||||
|  | ||||
| struct Opts_def_using { | ||||
| 	CodeAttributes attributes; | ||||
| 	ModuleFlag     mflags; | ||||
| }; | ||||
| CodeUsing def_using( StrC name, CodeTypename type, Opts_def_using opts GEN_PARAM_DEFAULT ); | ||||
|  | ||||
| CodeUsing def_using_namespace( StrC name ); | ||||
|  | ||||
| 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( CodeType 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. | ||||
|  | ||||
| CodeBody       def_class_body      ( s32 num, ... ); | ||||
| CodeBody       def_class_body      ( s32 num, Code* codes ); | ||||
| CodeBody       def_enum_body       ( s32 num, ... ); | ||||
| CodeBody       def_enum_body       ( s32 num, Code* codes ); | ||||
| CodeBody       def_export_body     ( s32 num, ... ); | ||||
| CodeBody       def_export_body     ( s32 num, Code* codes); | ||||
| CodeBody       def_extern_link_body( s32 num, ... ); | ||||
| CodeBody       def_extern_link_body( s32 num, Code* codes ); | ||||
| CodeBody       def_function_body   ( s32 num, ... ); | ||||
| CodeBody       def_function_body   ( s32 num, Code* codes ); | ||||
| CodeBody       def_global_body     ( s32 num, ... ); | ||||
| CodeBody       def_global_body     ( s32 num, Code* codes ); | ||||
| CodeBody       def_namespace_body  ( s32 num, ... ); | ||||
| 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, Specifier* specs ); | ||||
| CodeBody       def_struct_body     ( s32 num, ... ); | ||||
| CodeBody       def_struct_body     ( s32 num, Code* codes ); | ||||
| CodeBody       def_union_body      ( s32 num, ... ); | ||||
| CodeBody       def_union_body      ( s32 num, Code* codes ); | ||||
|  | ||||
| #pragma endregion Upfront | ||||
|  | ||||
| #pragma region Parsing | ||||
|  | ||||
| // TODO(Ed) : Implmeent the new parser API design. | ||||
|  | ||||
| #if 0 | ||||
| GEN_NS_PARSER_BEGIN | ||||
| struct StackNode | ||||
| { | ||||
| 	StackNode* Prev; | ||||
|  | ||||
| 	Token Start; | ||||
| 	Token Name;       // The name of the AST node (if parsed) | ||||
| 	StrC  FailedProc; // The name of the procedure that failed | ||||
| }; | ||||
| // Stack nodes are allocated the error's allocator | ||||
|  | ||||
| struct Error | ||||
| { | ||||
| 	String     message; | ||||
| 	StackNode* context_stack; | ||||
| }; | ||||
| GEN_NS_PARSER_END | ||||
|  | ||||
| struct ParseInfo | ||||
| { | ||||
| 	Arena FileMem; | ||||
| 	Arena TokMem; | ||||
| 	Arena CodeMem; | ||||
|  | ||||
| 	FileContents FileContent; | ||||
| 	Array<Token> Tokens; | ||||
| 	Array<Error> Errors; | ||||
| 	// Errors are allocated to a dedicated general arena. | ||||
| }; | ||||
|  | ||||
| CodeBody parse_file( StrC path ); | ||||
| #endif | ||||
|  | ||||
| CodeClass       parse_class        ( StrC class_def       ); | ||||
| CodeConstructor parse_constructor  ( StrC constructor_def ); | ||||
| CodeDestructor  parse_destructor   ( StrC destructor_def  ); | ||||
| CodeEnum        parse_enum         ( StrC enum_def        ); | ||||
| CodeBody        parse_export_body  ( StrC export_def      ); | ||||
| CodeExtern      parse_extern_link  ( StrC exten_link_def  ); | ||||
| CodeFriend      parse_friend       ( StrC friend_def      ); | ||||
| CodeFn          parse_function     ( StrC fn_def          ); | ||||
| CodeBody        parse_global_body  ( StrC body_def        ); | ||||
| CodeNS          parse_namespace    ( StrC namespace_def   ); | ||||
| 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    ); | ||||
| CodeTypename    parse_type         ( StrC type_def        ); | ||||
| CodeTypedef     parse_typedef      ( StrC typedef_def     ); | ||||
| CodeUnion       parse_union        ( StrC union_def       ); | ||||
| CodeUsing       parse_using        ( StrC using_def       ); | ||||
| CodeVar         parse_variable     ( StrC var_def         ); | ||||
|  | ||||
| #pragma endregion Parsing | ||||
|  | ||||
| #pragma region Untyped text | ||||
|  | ||||
| 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( ssize, ... ); | ||||
|  | ||||
| Code untyped_str      ( StrC content); | ||||
| Code untyped_fmt      ( char const* fmt, ... ); | ||||
| Code untyped_token_fmt( s32 num_tokens, char const* fmt, ... ); | ||||
|  | ||||
| #pragma endregion Untyped text | ||||
|  | ||||
| #pragma region Macros | ||||
|  | ||||
| #ifndef gen_main | ||||
| #define gen_main main | ||||
| #endif | ||||
|  | ||||
| #ifndef name | ||||
| //	Convienence for defining any name used with the gen api. | ||||
| //  Lets you provide the length and string literal to the functions without the need for the DSL. | ||||
| #define name( Id_ )   { sizeof(stringize( Id_ )) - 1, stringize(Id_) } | ||||
| #endif | ||||
|  | ||||
| #ifndef code | ||||
| //  Same as name just used to indicate intention of literal for code instead of names. | ||||
| #define code( ... ) { sizeof(stringize(__VA_ARGS__)) - 1, stringize( __VA_ARGS__ ) } | ||||
| #endif | ||||
|  | ||||
| #ifndef args | ||||
| // Provides the number of arguments while passing args inplace. | ||||
| #define args( ... ) num_args( __VA_ARGS__ ), __VA_ARGS__ | ||||
| #endif | ||||
|  | ||||
| #ifndef code_str | ||||
| // Just wrappers over common untyped code definition constructions. | ||||
| #define code_str( ... ) GEN_NS untyped_str( code( __VA_ARGS__ ) ) | ||||
| #endif | ||||
|  | ||||
| #ifndef code_fmt | ||||
| #define code_fmt( ... ) GEN_NS untyped_str( token_fmt( __VA_ARGS__ ) ) | ||||
| #endif | ||||
|  | ||||
| #ifndef parse_fmt | ||||
| #define parse_fmt( type, ... ) GEN_NS parse_##type( token_fmt( __VA_ARGS__ ) ) | ||||
| #endif | ||||
|  | ||||
| #ifndef token_fmt | ||||
| /* | ||||
| Takes a format string (char const*) and a list of tokens (StrC) and returns a StrC of the formatted string. | ||||
| Tokens are provided in '<'identifier'>' format where '<' '>' are just angle brackets (you can change it in token_fmt_va) | ||||
| --------------------------------------------------------- | ||||
| 	Example - A string with: | ||||
| 		typedef <type> <name> <name>; | ||||
| 	Will have a token_fmt arguments populated with: | ||||
| 		"type", strc_for_type, | ||||
| 		"name", strc_for_name, | ||||
| 	and: | ||||
| 		stringize( typedef <type> <name> <name>; ) | ||||
| ----------------------------------------------------------- | ||||
| So the full call for this example would be: | ||||
| 	token_fmt( | ||||
| 		"type", strc_for_type | ||||
| 	,	"name", strc_for_name | ||||
| 	,	stringize( | ||||
| 		typedef <type> <name> <name> | ||||
| 	)); | ||||
| !---------------------------------------------------------- | ||||
| ! Note: token_fmt_va is whitespace sensitive for the tokens. | ||||
| ! This can be alleviated by skipping whitespace between brackets but it was choosen to not have that implementation by default. | ||||
| */ | ||||
| #define token_fmt( ... ) GEN_NS token_fmt_impl( (num_args( __VA_ARGS__ ) + 1) / 2, __VA_ARGS__ ) | ||||
| #endif | ||||
|  | ||||
| #pragma endregion Macros | ||||
|  | ||||
| #pragma endregion Gen Interface | ||||
							
								
								
									
										345
									
								
								base/components/interface.parsing.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										345
									
								
								base/components/interface.parsing.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,345 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #pragma once | ||||
| #include "gen/etoktype.cpp" | ||||
| #include "interface.upfront.cpp" | ||||
| #include "lexer.cpp" | ||||
| #include "parser.cpp" | ||||
| #endif | ||||
|  | ||||
| // Publically Exposed Interface | ||||
|  | ||||
| CodeClass parse_class( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	push_scope(); | ||||
| 	CodeClass result = (CodeClass) parse_class_struct( Tok_Decl_Class, parser_not_inplace_def ); | ||||
| 	parser_pop(& Context); | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| CodeConstructor parse_constructor( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	// TODO(Ed): Constructors can have prefix attributes | ||||
|  | ||||
| 	CodeSpecifiers specifiers = NullCode; | ||||
| 	Specifier      specs_found[ 16 ] = { Spec_NumSpecifiers }; | ||||
| 	s32            NumSpecifiers = 0; | ||||
|  | ||||
| 	while ( left && tok_is_specifier(currtok) ) | ||||
| 	{ | ||||
| 		Specifier spec = strc_to_specifier( tok_to_str(currtok) ); | ||||
|  | ||||
| 		b32 ignore_spec = false; | ||||
|  | ||||
| 		switch ( spec ) | ||||
| 		{ | ||||
| 			case Spec_Constexpr : | ||||
| 			case Spec_Explicit: | ||||
| 			case Spec_Inline : | ||||
| 			case Spec_ForceInline : | ||||
| 			case Spec_NeverInline : | ||||
| 				break; | ||||
|  | ||||
| 			case Spec_Const : | ||||
| 				ignore_spec = true; | ||||
| 				break; | ||||
|  | ||||
| 			default : | ||||
| 				log_failure( "Invalid specifier %s for variable\n%s", spec_to_str( spec ), parser_to_string(Context) ); | ||||
| 				parser_pop(& Context); | ||||
| 				return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		// Every specifier after would be considered part of the type type signature | ||||
| 		if (ignore_spec) | ||||
| 			break; | ||||
|  | ||||
| 		specs_found[ NumSpecifiers ] = spec; | ||||
| 		NumSpecifiers++; | ||||
| 		eat( currtok.Type ); | ||||
| 	} | ||||
|  | ||||
| 	if ( NumSpecifiers ) | ||||
| 	{ | ||||
| 		specifiers = def_specifiers( NumSpecifiers, specs_found ); | ||||
| 		// <specifiers> ... | ||||
| 	} | ||||
|  | ||||
| 	Context.Tokens         = toks; | ||||
| 	CodeConstructor result = parser_parse_constructor( specifiers ); | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| CodeDestructor parse_destructor( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	// TODO(Ed): Destructors can have prefix attributes | ||||
| 	// TODO(Ed): Destructors can have virtual | ||||
|  | ||||
| 	Context.Tokens        = toks; | ||||
| 	CodeDestructor result = parser_parse_destructor(NullCode); | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| CodeEnum parse_enum( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 	{ | ||||
| 		parser_pop(& Context); | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parser_parse_enum( parser_not_inplace_def); | ||||
| } | ||||
|  | ||||
| CodeBody parse_export_body( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parser_parse_export_body(); | ||||
| } | ||||
|  | ||||
| CodeExtern parse_extern_link( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parser_parse_extern_link(); | ||||
| } | ||||
|  | ||||
| CodeFriend parse_friend( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parser_parse_friend(); | ||||
| } | ||||
|  | ||||
| CodeFn parse_function( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return (CodeFn) parser_parse_function(); | ||||
| } | ||||
|  | ||||
| CodeBody parse_global_body( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	push_scope(); | ||||
| 	CodeBody result = parse_global_nspace( CT_Global_Body ); | ||||
| 	parser_pop(& Context); | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| CodeNS parse_namespace( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parser_parse_namespace(); | ||||
| } | ||||
|  | ||||
| CodeOperator parse_operator( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return (CodeOperator) parser_parse_operator(); | ||||
| } | ||||
|  | ||||
| CodeOpCast parse_operator_cast( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parser_parse_operator_cast(NullCode); | ||||
| } | ||||
|  | ||||
| CodeStruct parse_struct( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	push_scope(); | ||||
| 	CodeStruct result = (CodeStruct) parse_class_struct( Tok_Decl_Struct, parser_not_inplace_def ); | ||||
| 	parser_pop(& Context); | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| CodeTemplate parse_template( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parser_parse_template(); | ||||
| } | ||||
|  | ||||
| CodeTypename parse_type( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parser_parse_type( parser_not_from_template, nullptr); | ||||
| } | ||||
|  | ||||
| CodeTypedef parse_typedef( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parser_parse_typedef(); | ||||
| } | ||||
|  | ||||
| CodeUnion parse_union( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parser_parse_union( parser_not_inplace_def); | ||||
| } | ||||
|  | ||||
| CodeUsing parse_using( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parser_parse_using(); | ||||
| } | ||||
|  | ||||
| CodeVar parse_variable( StrC def ) | ||||
| { | ||||
| 	GEN_USING_NS_PARSER; | ||||
| 	check_parse_args( def ); | ||||
|  | ||||
| 	TokArray toks = lex( def ); | ||||
| 	if ( toks.Arr == nullptr ) | ||||
| 		return InvalidCode; | ||||
|  | ||||
| 	Context.Tokens = toks; | ||||
| 	return parser_parse_variable(); | ||||
| } | ||||
|  | ||||
| // Undef helper macros | ||||
| #undef check_parse_args | ||||
| #undef currtok_noskip | ||||
| #undef currtok | ||||
| #undef peektok | ||||
| #undef prevtok | ||||
| #undef nexttok | ||||
| #undef nexttok_noskip | ||||
| #undef eat | ||||
| #undef left | ||||
| #undef check | ||||
| #undef push_scope | ||||
| #undef def_assign | ||||
|  | ||||
| // Here for C Variant | ||||
| #undef lex_dont_skip_formatting | ||||
| #undef lex_skip_formatting | ||||
|  | ||||
| #undef parser_inplace_def | ||||
| #undef parser_not_inplace_def | ||||
| #undef parser_dont_consume_braces | ||||
| #undef parser_consume_braces | ||||
| #undef parser_not_from_template | ||||
| #undef parser_use_parenthesis | ||||
| #undef parser_strip_formatting_dont_preserve_newlines | ||||
							
								
								
									
										190
									
								
								base/components/interface.untyped.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										190
									
								
								base/components/interface.untyped.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,190 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #pragma once | ||||
| #include "interface.parsing.cpp" | ||||
| #endif | ||||
|  | ||||
| ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va ) | ||||
| { | ||||
| 	char const* buf_begin = buf; | ||||
| 	ssize       remaining = buf_size; | ||||
|  | ||||
| 	local_persist | ||||
| 	TokenMap_FixedArena tok_map_arena; | ||||
| 	fixed_arena_init( & tok_map_arena); | ||||
|  | ||||
| 	local_persist | ||||
| 	StringTable tok_map; | ||||
| 	{ | ||||
| 		tok_map = hashtable_init(StrC, fixed_arena_allocator_info(& tok_map_arena) ); | ||||
|  | ||||
| 		s32 left = num_tokens - 1; | ||||
|  | ||||
| 		while ( left-- ) | ||||
| 		{ | ||||
| 			char const* token = va_arg( va, char const* ); | ||||
| 			StrC        value = va_arg( va, StrC ); | ||||
|  | ||||
| 			u32 key = crc32( token, str_len(token) ); | ||||
| 			hashtable_set( tok_map, key, value ); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	char const* fmt     = va_arg( va, char const* ); | ||||
| 	char        current = *fmt; | ||||
|  | ||||
| 	while ( current ) | ||||
| 	{ | ||||
| 		ssize len = 0; | ||||
|  | ||||
| 		while ( current && current != '<' && remaining ) | ||||
| 		{ | ||||
| 			* buf = * fmt; | ||||
| 			buf++; | ||||
| 			fmt++; | ||||
| 			remaining--; | ||||
|  | ||||
| 			current = * fmt; | ||||
| 		} | ||||
|  | ||||
| 		if ( current == '<' ) | ||||
| 		{ | ||||
| 			char const* scanner = fmt + 1; | ||||
|  | ||||
| 			s32 tok_len = 0; | ||||
|  | ||||
| 			while ( *scanner != '>' ) | ||||
| 			{ | ||||
| 				tok_len++; | ||||
| 				scanner++; | ||||
| 			} | ||||
|  | ||||
| 			char const* token = fmt + 1; | ||||
|  | ||||
| 			u32       key   = crc32( token, tok_len ); | ||||
| 			StrC*     value = hashtable_get(tok_map, key ); | ||||
|  | ||||
| 			if ( value ) | ||||
| 			{ | ||||
| 				ssize          left = value->Len; | ||||
| 				char const* str  = value->Ptr; | ||||
|  | ||||
| 				while ( left-- ) | ||||
| 				{ | ||||
| 					* buf = * str; | ||||
| 					buf++; | ||||
| 					str++; | ||||
| 					remaining--; | ||||
| 				} | ||||
|  | ||||
| 				scanner++; | ||||
| 				fmt     = scanner; | ||||
| 				current = * fmt; | ||||
| 				continue; | ||||
| 			} | ||||
|  | ||||
| 			* buf = * fmt; | ||||
| 			buf++; | ||||
| 			fmt++; | ||||
| 			remaining--; | ||||
|  | ||||
| 			current = * fmt; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	hashtable_clear(tok_map); | ||||
| 	fixed_arena_free(& tok_map_arena); | ||||
|  | ||||
| 	ssize result = buf_size - remaining; | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| Code untyped_str( StrC content ) | ||||
| { | ||||
| 	if ( content.Len == 0 ) | ||||
| 	{ | ||||
| 		log_failure( "untyped_str: empty string" ); | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	Code | ||||
| 	result          = make_code(); | ||||
| 	result->Name    = get_cached_string( content ); | ||||
| 	result->Type    = CT_Untyped; | ||||
| 	result->Content = result->Name; | ||||
|  | ||||
| 	if ( result->Name.Len == 0 ) | ||||
| 	{ | ||||
| 		log_failure( "untyped_str: could not cache string" ); | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| Code untyped_fmt( char const* fmt, ...) | ||||
| { | ||||
| 	if ( fmt == nullptr ) | ||||
| 	{ | ||||
| 		log_failure( "untyped_fmt: null format string" ); | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	local_persist thread_local | ||||
| 	char buf[GEN_PRINTF_MAXLEN] = { 0 }; | ||||
|  | ||||
| 	va_list va; | ||||
| 	va_start(va, fmt); | ||||
| 	ssize length = str_fmt_va(buf, GEN_PRINTF_MAXLEN, fmt, va); | ||||
| 	va_end(va); | ||||
|  | ||||
| 	StrC buf_str      = { str_len_capped(fmt, MaxNameLength), fmt }; | ||||
|     StrC uncapped_str = { length, buf }; | ||||
|  | ||||
| 	Code | ||||
| 	result          = make_code(); | ||||
| 	result->Name    = get_cached_string( buf_str ); | ||||
| 	result->Type    = CT_Untyped; | ||||
| 	result->Content = get_cached_string( uncapped_str ); | ||||
|  | ||||
| 	if ( result->Name.Len == 0 ) | ||||
| 	{ | ||||
| 		log_failure( "untyped_fmt: could not cache string" ); | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| Code untyped_token_fmt( s32 num_tokens, char const* fmt, ... ) | ||||
| { | ||||
| 	if ( num_tokens == 0 ) | ||||
| 	{ | ||||
| 		log_failure( "untyped_token_fmt: zero tokens" ); | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	local_persist thread_local | ||||
| 	char buf[GEN_PRINTF_MAXLEN] = { 0 }; | ||||
|  | ||||
| 	va_list va; | ||||
| 	va_start(va, fmt); | ||||
| 	ssize length = token_fmt_va(buf, GEN_PRINTF_MAXLEN, num_tokens, va); | ||||
| 	va_end(va); | ||||
|  | ||||
| 	StrC buf_str = { length, buf }; | ||||
|  | ||||
| 	Code | ||||
| 	result          = make_code(); | ||||
| 	result->Name    = get_cached_string( buf_str ); | ||||
| 	result->Type    = CT_Untyped; | ||||
| 	result->Content = result->Name; | ||||
|  | ||||
| 	if ( result->Name.Len == 0 ) | ||||
| 	{ | ||||
| 		log_failure( "untyped_fmt: could not cache string" ); | ||||
| 		return InvalidCode; | ||||
| 	} | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
							
								
								
									
										2339
									
								
								base/components/interface.upfront.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2339
									
								
								base/components/interface.upfront.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1345
									
								
								base/components/lexer.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1345
									
								
								base/components/lexer.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										5590
									
								
								base/components/parser.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5590
									
								
								base/components/parser.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										11
									
								
								base/components/src_start.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								base/components/src_start.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| #if ! defined(GEN_DONT_ENFORCE_GEN_TIME_GUARD) && ! defined(GEN_TIME) | ||||
| #	error Gen.hpp : GEN_TIME not defined | ||||
| #endif | ||||
|  | ||||
| #include "gen.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 | ||||
| #	include "gen.dep.cpp" | ||||
| #endif | ||||
							
								
								
									
										107
									
								
								base/components/static_data.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								base/components/static_data.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,107 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #pragma once | ||||
| #include "gen.hpp" | ||||
| #endif | ||||
|  | ||||
| #pragma region StaticData | ||||
|  | ||||
| // TODO : Convert global allocation strategy to use a slab allocation strategy. | ||||
| global AllocatorInfo  GlobalAllocator; | ||||
| global Array( Arena )   Global_AllocatorBuckets; | ||||
|  | ||||
| // TODO(Ed) : Make the code pool a dynamic arena | ||||
| global Array( Pool )  CodePools         = { nullptr }; | ||||
| global Array( Arena ) StringArenas      = { nullptr }; | ||||
|  | ||||
| global StringTable StringCache; | ||||
|  | ||||
| global Arena LexArena; | ||||
|  | ||||
| global AllocatorInfo Allocator_DataArrays  = {0}; | ||||
| global AllocatorInfo Allocator_CodePool    = {0}; | ||||
| global AllocatorInfo Allocator_Lexer       = {0}; | ||||
| global AllocatorInfo Allocator_StringArena = {0}; | ||||
| global AllocatorInfo Allocator_StringTable = {0}; | ||||
| global AllocatorInfo Allocator_TypeTable   = {0}; | ||||
|  | ||||
| #pragma endregion StaticData | ||||
|  | ||||
| #pragma region Constants | ||||
|  | ||||
| global Code access_public; | ||||
| global Code access_protected; | ||||
| global Code access_private; | ||||
|  | ||||
| global CodeAttributes attrib_api_export; | ||||
| global CodeAttributes attrib_api_import; | ||||
|  | ||||
| global Code module_global_fragment; | ||||
| global Code module_private_fragment; | ||||
|  | ||||
| global Code fmt_newline; | ||||
|  | ||||
| global CodeParam param_varadic; | ||||
|  | ||||
| global CodePragma pragma_once; | ||||
|  | ||||
| global CodePreprocessCond preprocess_else; | ||||
| global CodePreprocessCond preprocess_endif; | ||||
|  | ||||
| global CodeSpecifiers spec_const; | ||||
| global CodeSpecifiers spec_consteval; | ||||
| global CodeSpecifiers spec_constexpr; | ||||
| global CodeSpecifiers spec_constinit; | ||||
| global CodeSpecifiers spec_extern_linkage; | ||||
| global CodeSpecifiers spec_final; | ||||
| global CodeSpecifiers spec_forceinline; | ||||
| global CodeSpecifiers spec_global; | ||||
| global CodeSpecifiers spec_inline; | ||||
| global CodeSpecifiers spec_internal_linkage; | ||||
| global CodeSpecifiers spec_local_persist; | ||||
| global CodeSpecifiers spec_mutable; | ||||
| global CodeSpecifiers spec_noexcept; | ||||
| global CodeSpecifiers spec_neverinline; | ||||
| global CodeSpecifiers spec_override; | ||||
| global CodeSpecifiers spec_ptr; | ||||
| global CodeSpecifiers spec_pure; | ||||
| global CodeSpecifiers spec_ref; | ||||
| global CodeSpecifiers spec_register; | ||||
| global CodeSpecifiers spec_rvalue; | ||||
| global CodeSpecifiers spec_static_member; | ||||
| global CodeSpecifiers spec_thread_local; | ||||
| global CodeSpecifiers spec_virtual; | ||||
| global CodeSpecifiers spec_volatile; | ||||
|  | ||||
| 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; | ||||
|  | ||||
| #ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS | ||||
| global CodeTypename t_b32; | ||||
|  | ||||
| global CodeTypename t_s8; | ||||
| global CodeTypename t_s16; | ||||
| global CodeTypename t_s32; | ||||
| global CodeTypename t_s64; | ||||
|  | ||||
| global CodeTypename t_u8; | ||||
| global CodeTypename t_u16; | ||||
| global CodeTypename t_u32; | ||||
| global CodeTypename t_u64; | ||||
|  | ||||
| global CodeTypename t_ssize; | ||||
| global CodeTypename t_usize; | ||||
|  | ||||
| global CodeTypename t_f32; | ||||
| global CodeTypename t_f64; | ||||
| #endif | ||||
|  | ||||
| #pragma endregion Constants | ||||
							
								
								
									
										138
									
								
								base/components/types.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								base/components/types.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,138 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #pragma once | ||||
| #include "header_start.hpp" | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  ________                                              __    __      ________ | ||||
| |        \                                            |  \  |  \    |        \ | ||||
| | ▓▓▓▓▓▓▓▓_______  __    __ ______ ____   _______     | ▓▓\ | ▓▓     \▓▓▓▓▓▓▓▓__    __  ______   ______   _______ | ||||
| | ▓▓__   |       \|  \  |  \      \    \ /       \    | ▓▓▓\| ▓▓       | ▓▓  |  \  |  \/      \ /      \ /       \ | ||||
| | ▓▓  \  | ▓▓▓▓▓▓▓\ ▓▓  | ▓▓ ▓▓▓▓▓▓\▓▓▓▓\  ▓▓▓▓▓▓▓    | ▓▓▓▓\ ▓▓       | ▓▓  | ▓▓  | ▓▓  ▓▓▓▓▓▓\  ▓▓▓▓▓▓\  ▓▓▓▓▓▓▓ | ||||
| | ▓▓▓▓▓  | ▓▓  | ▓▓ ▓▓  | ▓▓ ▓▓ | ▓▓ | ▓▓\▓▓    \     | ▓▓\▓▓ ▓▓       | ▓▓  | ▓▓  | ▓▓ ▓▓  | ▓▓ ▓▓    ▓▓\▓▓    \ | ||||
| | ▓▓_____| ▓▓  | ▓▓ ▓▓__/ ▓▓ ▓▓ | ▓▓ | ▓▓_\▓▓▓▓▓▓\    | ▓▓ \▓▓▓▓       | ▓▓  | ▓▓__/ ▓▓ ▓▓__/ ▓▓ ▓▓▓▓▓▓▓▓_\▓▓▓▓▓▓\ | ||||
| | ▓▓     \ ▓▓  | ▓▓\▓▓    ▓▓ ▓▓ | ▓▓ | ▓▓       ▓▓    | ▓▓  \▓▓▓       | ▓▓   \▓▓    ▓▓ ▓▓    ▓▓\▓▓     \       ▓▓ | ||||
|  \▓▓▓▓▓▓▓▓\▓▓   \▓▓ \▓▓▓▓▓▓ \▓▓  \▓▓  \▓▓\▓▓▓▓▓▓▓      \▓▓   \▓▓        \▓▓   _\▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓  \▓▓▓▓▓▓▓\▓▓▓▓▓▓▓ | ||||
|                                                                              |  \__| ▓▓ ▓▓ | ||||
|                                                                               \▓▓    ▓▓ ▓▓ | ||||
|                                                                                \▓▓▓▓▓▓ \▓▓ | ||||
|  | ||||
| */ | ||||
|  | ||||
| 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. | ||||
| #ifdef GEN_DONT_USE_FATAL | ||||
| 	#define log_failure log_fmt | ||||
| #else | ||||
| 	#define log_failure GEN_FATAL | ||||
| #endif | ||||
|  | ||||
| enum AccessSpec : u32 | ||||
| { | ||||
| 	AccessSpec_Default, | ||||
| 	AccessSpec_Private, | ||||
| 	AccessSpec_Protected, | ||||
| 	AccessSpec_Public, | ||||
|  | ||||
| 	AccessSpec_Num_AccessSpec, | ||||
| 	AccessSpec_Invalid, | ||||
|  | ||||
| 	AccessSpec_SizeDef = GEN_U32_MAX, | ||||
| }; | ||||
| static_assert( size_of(AccessSpec) == size_of(u32), "AccessSpec not u32 size" ); | ||||
|  | ||||
| inline | ||||
| StrC access_spec_to_str( AccessSpec type ) | ||||
| { | ||||
| 	local_persist | ||||
| 	StrC lookup[ (u32)AccessSpec_Num_AccessSpec ] = { | ||||
| 		{ sizeof("") - 1,          "" }, | ||||
| 		{ sizeof("prviate") - 1,   "private" }, | ||||
| 		{ sizeof("protected") - 1, "private" }, | ||||
| 		{ sizeof("public") - 1,    "public" }, | ||||
| 	}; | ||||
|  | ||||
| 	StrC invalid = { sizeof("Invalid") - 1, "Invalid" }; | ||||
| 	if ( type > AccessSpec_Public ) | ||||
| 		return invalid; | ||||
|  | ||||
| 	return lookup[ (u32)type ]; | ||||
| } | ||||
|  | ||||
| enum CodeFlag : u32 | ||||
| { | ||||
| 	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 EnumDecl : u8 | ||||
| { | ||||
| 	EnumDecl_Regular, | ||||
| 	EnumDecl_Class, | ||||
|  | ||||
| 	EnumT_SizeDef = GEN_U8_MAX, | ||||
| }; | ||||
| typedef u8 EnumT; | ||||
|  | ||||
| enum ModuleFlag : u32 | ||||
| { | ||||
| 	ModuleFlag_None    = 0, | ||||
| 	ModuleFlag_Export  = bit(0), | ||||
| 	ModuleFlag_Import  = bit(1), | ||||
|  | ||||
| 	Num_ModuleFlags, | ||||
| 	ModuleFlag_Invalid, | ||||
|  | ||||
| 	ModuleFlag_SizeDef = GEN_U32_MAX, | ||||
| }; | ||||
| static_assert( size_of(ModuleFlag) == size_of(u32), "ModuleFlag not u32 size" ); | ||||
|  | ||||
| inline | ||||
| StrC module_flag_to_str( ModuleFlag flag ) | ||||
| { | ||||
| 	local_persist | ||||
| 	StrC lookup[ (u32)Num_ModuleFlags ] = { | ||||
| 		{ sizeof("__none__"), "__none__" }, | ||||
| 		{ sizeof("export"), "export" }, | ||||
| 		{ sizeof("import"), "import" }, | ||||
| 	}; | ||||
|  | ||||
| 	local_persist | ||||
| 	StrC invalid_flag = { sizeof("invalid"), "invalid" }; | ||||
| 	if ( flag > ModuleFlag_Import ) | ||||
| 		return invalid_flag; | ||||
|  | ||||
| 	return lookup[ (u32)flag ]; | ||||
| } | ||||
|  | ||||
| enum EPreprocessCond : u32 | ||||
| { | ||||
| 	PreprocessCond_If, | ||||
| 	PreprocessCond_IfDef, | ||||
| 	PreprocessCond_IfNotDef, | ||||
| 	PreprocessCond_ElIf, | ||||
|  | ||||
| 	EPreprocessCond_SizeDef = GEN_U32_MAX, | ||||
| }; | ||||
| static_assert( size_of(EPreprocessCond) == size_of(u32), "EPreprocessCond not u32 size" ); | ||||
|  | ||||
| enum ETypenameTag : u16 | ||||
| { | ||||
| 	Tag_None, | ||||
| 	Tag_Class, | ||||
| 	Tag_Enum, | ||||
| 	Tag_Struct, | ||||
| 	Tag_Union, | ||||
|  | ||||
| 	Tag_UnderlyingType = GEN_U16_MAX, | ||||
| }; | ||||
| static_assert( size_of(ETypenameTag) == size_of(u16), "ETypenameTag is not u16 size"); | ||||
							
								
								
									
										143
									
								
								base/dependencies/basic_types.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								base/dependencies/basic_types.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,143 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	pragma once | ||||
| #	include "platform.hpp" | ||||
| #	include "macros.hpp" | ||||
| #endif | ||||
|  | ||||
| #pragma region Basic Types | ||||
|  | ||||
| #define GEN_U8_MIN 0u | ||||
| #define GEN_U8_MAX 0xffu | ||||
| #define GEN_I8_MIN ( -0x7f - 1 ) | ||||
| #define GEN_I8_MAX 0x7f | ||||
|  | ||||
| #define GEN_U16_MIN 0u | ||||
| #define GEN_U16_MAX 0xffffu | ||||
| #define GEN_I16_MIN ( -0x7fff - 1 ) | ||||
| #define GEN_I16_MAX 0x7fff | ||||
|  | ||||
| #define GEN_U32_MIN 0u | ||||
| #define GEN_U32_MAX 0xffffffffu | ||||
| #define GEN_I32_MIN ( -0x7fffffff - 1 ) | ||||
| #define GEN_I32_MAX 0x7fffffff | ||||
|  | ||||
| #define GEN_U64_MIN 0ull | ||||
| #define GEN_U64_MAX 0xffffffffffffffffull | ||||
| #define GEN_I64_MIN ( -0x7fffffffffffffffll - 1 ) | ||||
| #define GEN_I64_MAX 0x7fffffffffffffffll | ||||
|  | ||||
| #if defined( GEN_ARCH_32_BIT ) | ||||
| #	define GEN_USIZE_MIN GEN_U32_MIN | ||||
| #	define GEN_USIZE_MAX GEN_U32_MAX | ||||
| #	define GEN_ISIZE_MIN GEN_S32_MIN | ||||
| #	define GEN_ISIZE_MAX GEN_S32_MAX | ||||
| #elif defined( GEN_ARCH_64_BIT ) | ||||
| #	define GEN_USIZE_MIN GEN_U64_MIN | ||||
| #	define GEN_USIZE_MAX GEN_U64_MAX | ||||
| #	define GEN_ISIZE_MIN GEN_I64_MIN | ||||
| #	define GEN_ISIZE_MAX GEN_I64_MAX | ||||
| #else | ||||
| #	error Unknown architecture size. This library only supports 32 bit and 64 bit architectures. | ||||
| #endif | ||||
|  | ||||
| #define GEN_F32_MIN 1.17549435e-38f | ||||
| #define GEN_F32_MAX 3.40282347e+38f | ||||
| #define GEN_F64_MIN 2.2250738585072014e-308 | ||||
| #define GEN_F64_MAX 1.7976931348623157e+308 | ||||
|  | ||||
| #if defined( GEN_COMPILER_MSVC ) | ||||
| #	if _MSC_VER < 1300 | ||||
| typedef unsigned char  u8; | ||||
| typedef signed   char  s8; | ||||
| typedef unsigned short u16; | ||||
| typedef signed   short s16; | ||||
| typedef unsigned int   u32; | ||||
| typedef signed   int   s32; | ||||
| #    else | ||||
| typedef unsigned __int8  u8; | ||||
| typedef signed   __int8  s8; | ||||
| typedef unsigned __int16 u16; | ||||
| typedef signed   __int16 s16; | ||||
| typedef unsigned __int32 u32; | ||||
| typedef signed   __int32 s32; | ||||
| #    endif | ||||
| typedef unsigned __int64 u64; | ||||
| typedef signed   __int64 s64; | ||||
| #else | ||||
| #	include <stdint.h> | ||||
|  | ||||
| typedef uint8_t  u8; | ||||
| typedef int8_t   s8; | ||||
| typedef uint16_t u16; | ||||
| typedef int16_t  s16; | ||||
| typedef uint32_t u32; | ||||
| typedef int32_t  s32; | ||||
| typedef uint64_t u64; | ||||
| typedef int64_t  s64; | ||||
| #endif | ||||
|  | ||||
| static_assert( sizeof( u8 )  == sizeof( s8 ),  "sizeof(u8) != sizeof(s8)" ); | ||||
| static_assert( sizeof( u16 ) == sizeof( s16 ), "sizeof(u16) != sizeof(s16)" ); | ||||
| static_assert( sizeof( u32 ) == sizeof( s32 ), "sizeof(u32) != sizeof(s32)" ); | ||||
| static_assert( sizeof( u64 ) == sizeof( s64 ), "sizeof(u64) != sizeof(s64)" ); | ||||
|  | ||||
| static_assert( sizeof( u8 )  == 1, "sizeof(u8) != 1" ); | ||||
| 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    usize; | ||||
| typedef ptrdiff_t ssize; | ||||
|  | ||||
| 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 ) | ||||
| typedef signed __int64   sptr; | ||||
| typedef unsigned __int64 uptr; | ||||
| #elif defined( _WIN32 ) | ||||
| // NOTE; To mark types changing their size, e.g. zpl_intptr | ||||
| #	ifndef _W64 | ||||
| #		if ! defined( __midl ) && ( defined( _X86_ ) || defined( _M_IX86 ) ) && _MSC_VER >= 1300 | ||||
| #			define _W64 __w64 | ||||
| #		else | ||||
| #			define _W64 | ||||
| #		endif | ||||
| #	endif | ||||
| typedef _W64 signed int   sptr; | ||||
| typedef _W64 unsigned int uptr; | ||||
| #else | ||||
| typedef uintptr_t uptr; | ||||
| typedef intptr_t  sptr; | ||||
| #endif | ||||
|  | ||||
| static_assert( sizeof( uptr ) == sizeof( sptr ), "sizeof(uptr) != sizeof(sptr)" ); | ||||
|  | ||||
| typedef float  f32; | ||||
| typedef double f64; | ||||
|  | ||||
| static_assert( sizeof( f32 ) == 4, "sizeof(f32) != 4" ); | ||||
| static_assert( sizeof( f64 ) == 8, "sizeof(f64) != 8" ); | ||||
|  | ||||
| typedef s8  b8; | ||||
| typedef s16 b16; | ||||
| typedef s32 b32; | ||||
|  | ||||
| typedef void*       mem_ptr; | ||||
| typedef void const* mem_ptr_const ; | ||||
|  | ||||
| #if GEN_COMPILER_CPP | ||||
| template<typename Type> uptr to_uptr( Type* ptr ) { return (uptr)ptr; } | ||||
| template<typename Type> sptr to_sptr( Type* ptr ) { return (sptr)ptr; } | ||||
|  | ||||
| template<typename Type> mem_ptr       to_mem_ptr      ( Type ptr ) { return (mem_ptr)      ptr; } | ||||
| template<typename Type> mem_ptr_const to_mem_ptr_const( Type ptr ) { return (mem_ptr_const)ptr; } | ||||
| #else | ||||
| #define to_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 | ||||
|  | ||||
| #pragma endregion Basic Types | ||||
							
								
								
									
										797
									
								
								base/dependencies/containers.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										797
									
								
								base/dependencies/containers.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,797 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	pragma once | ||||
| #	include "printing.hpp" | ||||
| #endif | ||||
|  | ||||
| #pragma region Containers | ||||
|  | ||||
| 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, usize Size> struct RemoveConst<const TType[Size]> { typedef TType Type[Size]; }; | ||||
|  | ||||
| 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_COMPILER_CPP | ||||
| 	template<class Type> struct Array; | ||||
| #	define get_array_underlying_type(array) typename TRemovePtr<typeof(array)>:: DataType | ||||
| #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_COMPILER_CPP | ||||
| template<class Type> | ||||
| struct Array | ||||
| { | ||||
| 	Type* Data; | ||||
|  | ||||
| #pragma region Member Mapping | ||||
| 	forceinline static Array  init(AllocatorInfo allocator)                         { return array_init<Type>(allocator); } | ||||
| 	forceinline static Array  init_reserve(AllocatorInfo allocator, ssize capacity) { return array_init_reserve<Type>(allocator, capacity); } | ||||
| 	forceinline static usize  grow_formula(ssize value)                             { return array_grow_formula<Type>(value); } | ||||
|  | ||||
| 	forceinline bool         append(Array other)                               { return array_append_array<Type>(this, other); } | ||||
| 	forceinline bool         append(Type value)                                { return array_append<Type>(this, value); } | ||||
| 	forceinline bool         append(Type* items, usize item_num)               { return array_append_items<Type>(this, items, item_num); } | ||||
| 	forceinline bool         append_at(Type item, usize idx)                   { return array_append_at<Type>(this, item, idx); } | ||||
| 	forceinline bool         append_at(Type* items, usize item_num, usize idx) { return array_append_items_at<Type>(this, items, item_num, idx); } | ||||
| 	forceinline Type*        back()                                            { return array_back<Type>(* this); } | ||||
| 	forceinline void         clear()                                           {        array_clear<Type>(* this); } | ||||
| 	forceinline bool         fill(usize begin, usize end, Type value)          { return array_fill<Type>(* this, begin, end, value); } | ||||
| 	forceinline void         free()                                            {        array_free<Type>(this); } | ||||
| 	forceinline ArrayHeader* get_header()                                      { return array_get_header<Type>(* this); } | ||||
| 	forceinline bool         grow(usize min_capacity)                          { return array_grow<Type>(this, min_capacity); } | ||||
| 	forceinline usize        num()                                             { return array_num<Type>(*this); } | ||||
| 	forceinline void         pop()                                             {        array_pop<Type>(* this); } | ||||
| 	forceinline void         remove_at(usize idx)                              {        array_remove_at<Type>(* this, idx); } | ||||
| 	forceinline bool         reserve(usize new_capacity)                       { return array_reserve<Type>(this, new_capacity); } | ||||
| 	forceinline bool         resize(usize num)                                 { return array_resize<Type>(this, num); } | ||||
| 	forceinline bool         set_capacity(usize new_capacity)                  { return 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_COMPILER_CPP && 0 | ||||
| template<class Type> bool         append(Array<Type>& array, Array<Type> other)                         { return append( & array, other ); } | ||||
| template<class Type> bool         append(Array<Type>& array, Type value)                                { return append( & array, value ); } | ||||
| template<class Type> bool         append(Array<Type>& array, Type* items, usize item_num)               { return append( & array, items, item_num ); } | ||||
| template<class Type> bool         append_at(Array<Type>& array, Type item, usize idx)                   { return append_at( & array, item, idx ); } | ||||
| template<class Type> bool         append_at(Array<Type>& array, Type* items, usize item_num, usize idx) { return append_at( & array, items, item_num, idx ); } | ||||
| template<class Type> void         free(Array<Type>& array)                                              { return free( & array ); } | ||||
| template<class Type> bool         grow(Array<Type>& array, usize min_capacity)                          { return grow( & array, min_capacity); } | ||||
| template<class Type> bool         reserve(Array<Type>& array, usize new_capacity)                       { return reserve( & array, new_capacity); } | ||||
| template<class Type> bool         resize(Array<Type>& array, usize num)                                 { return resize( & array, num); } | ||||
| template<class Type> bool         set_capacity(Array<Type>& array, usize new_capacity)                  { return 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)); | ||||
| } | ||||
|  | ||||
| template<class Type> inline | ||||
| Array<Type> array_init_reserve(AllocatorInfo allocator, ssize capacity) | ||||
| { | ||||
| 	GEN_ASSERT(capacity > 0); | ||||
| 	ArrayHeader* header = rcast(ArrayHeader*, alloc(allocator, sizeof(ArrayHeader) + sizeof(Type) * capacity)); | ||||
|  | ||||
| 	if (header == nullptr) | ||||
| 		return {nullptr}; | ||||
|  | ||||
| 	header->Allocator = allocator; | ||||
| 	header->Capacity  = capacity; | ||||
| 	header->Num       = 0; | ||||
|  | ||||
| 	return {rcast(Type*, header + 1)}; | ||||
| } | ||||
|  | ||||
| usize array_grow_formula(ssize value) { | ||||
| 	return 2 * value + 8; | ||||
| } | ||||
|  | ||||
| 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) | ||||
| { | ||||
| 	GEN_ASSERT(  array != nullptr); | ||||
| 	GEN_ASSERT(* array != nullptr); | ||||
| 	ArrayHeader* header = array_get_header(* array); | ||||
|  | ||||
| 	if (header->Num == header->Capacity) | ||||
| 	{ | ||||
| 		if ( ! array_grow(array, header->Capacity)) | ||||
| 			return false; | ||||
| 		header = array_get_header(* array); | ||||
| 	} | ||||
|  | ||||
| 	(*array)[ header->Num] = value; | ||||
| 	header->Num++; | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| template<class Type> inline | ||||
| bool array_append_items(Array<Type>* array, Type* items, usize item_num) | ||||
| { | ||||
| 	GEN_ASSERT(  array != nullptr); | ||||
| 	GEN_ASSERT(* array != nullptr); | ||||
| 	GEN_ASSERT(items != nullptr); | ||||
| 	GEN_ASSERT(item_num > 0); | ||||
| 	ArrayHeader* header = array_get_header(array); | ||||
|  | ||||
| 	if (header->Num + item_num > header->Capacity) | ||||
| 	{ | ||||
| 		if ( ! grow(array, header->Capacity + item_num)) | ||||
| 			return false; | ||||
| 		header = array_get_header(array); | ||||
| 	} | ||||
|  | ||||
| 	mem_copy((Type*)array + header->Num, items, item_num * sizeof(Type)); | ||||
| 	header->Num += item_num; | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| template<class Type> inline | ||||
| bool array_append_at(Array<Type>* array, Type item, usize idx) | ||||
| { | ||||
| 	GEN_ASSERT(  array != nullptr); | ||||
| 	GEN_ASSERT(* array != nullptr); | ||||
| 	ArrayHeader* header = array_get_header(* array); | ||||
|  | ||||
| 	ssize slot = idx; | ||||
| 	if (slot >= header->Num) | ||||
| 		slot = header->Num - 1; | ||||
|  | ||||
| 	if (slot < 0) | ||||
| 		slot = 0; | ||||
|  | ||||
| 	if (header->Capacity < header->Num + 1) | ||||
| 	{ | ||||
| 		if ( ! array_grow(array, header->Capacity + 1)) | ||||
| 			return false; | ||||
|  | ||||
| 		header = array_get_header(* array); | ||||
| 	} | ||||
|  | ||||
| 	Type* target = &(*array)[slot]; | ||||
|  | ||||
| 	mem_move(target + 1, target, (header->Num - slot) * sizeof(Type)); | ||||
| 	header->Num++; | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| template<class Type> inline | ||||
| bool array_append_items_at(Array<Type>* array, Type* items, usize item_num, usize idx) | ||||
| { | ||||
| 	GEN_ASSERT(  array != nullptr); | ||||
| 	GEN_ASSERT(* array != nullptr); | ||||
| 	ArrayHeader* header = get_header(array); | ||||
|  | ||||
| 	if (idx >= header->Num) | ||||
| 	{ | ||||
| 		return array_append_items(array, items, item_num); | ||||
| 	} | ||||
|  | ||||
| 	if (item_num > header->Capacity) | ||||
| 	{ | ||||
| 		if (! grow(array, header->Capacity + item_num)) | ||||
| 			return false; | ||||
|  | ||||
| 		header = get_header(array); | ||||
| 	} | ||||
|  | ||||
| 	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)); | ||||
| 	header->Num += item_num; | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| template<class Type> inline | ||||
| Type* array_back(Array<Type> array) | ||||
| { | ||||
| 	GEN_ASSERT(array != nullptr); | ||||
|  | ||||
| 	ArrayHeader* header = array_get_header(array); | ||||
| 	if (header->Num <= 0) | ||||
| 		return nullptr; | ||||
|  | ||||
| 	return & (array)[header->Num - 1]; | ||||
| } | ||||
|  | ||||
| template<class Type> inline | ||||
| void array_clear(Array<Type> array) { | ||||
| 	GEN_ASSERT(array != nullptr); | ||||
| 	ArrayHeader* header = array_get_header(array); | ||||
| 	header->Num = 0; | ||||
| } | ||||
|  | ||||
| template<class Type> inline | ||||
| bool array_fill(Array<Type> array, usize begin, usize end, Type value) | ||||
| { | ||||
| 	GEN_ASSERT(array != nullptr); | ||||
| 	GEN_ASSERT(begin <= end); | ||||
| 	ArrayHeader* header = array_get_header(array); | ||||
|  | ||||
| 	if (begin < 0 || end > header->Num) | ||||
| 	return false; | ||||
|  | ||||
| 	for (ssize idx = ssize(begin); idx < ssize(end); idx++) | ||||
| 	{ | ||||
| 		array[idx] = value; | ||||
| 	} | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| template<class Type> forceinline | ||||
| void array_free(Array<Type>* array) { | ||||
| 	GEN_ASSERT(  array != nullptr); | ||||
| 	GEN_ASSERT(* array != nullptr); | ||||
| 	ArrayHeader* header = array_get_header(* array); | ||||
| 	allocator_free(header->Allocator, header); | ||||
| 	Type** Data = (Type**)array; | ||||
| 	*Data = nullptr; | ||||
| } | ||||
|  | ||||
| template<class Type> forceinline | ||||
| ArrayHeader* array_get_header(Array<Type> array) { | ||||
| 	GEN_ASSERT(array != nullptr); | ||||
|     Type* Data = array; | ||||
|  | ||||
| 	using NonConstType = TRemoveConst<Type>; | ||||
|     return rcast(ArrayHeader*, const_cast<NonConstType*>(Data)) - 1; | ||||
| } | ||||
| template<class Type> forceinline | ||||
| bool array_grow(Array<Type>* array, usize min_capacity) | ||||
| { | ||||
| 	GEN_ASSERT(  array != nullptr); | ||||
| 	GEN_ASSERT(* array != nullptr); | ||||
| 	GEN_ASSERT( min_capacity > 0 ); | ||||
| 	ArrayHeader* header       = array_get_header(* array); | ||||
| 	usize        new_capacity = array_grow_formula(header->Capacity); | ||||
|  | ||||
| 	if (new_capacity < min_capacity) | ||||
| 		new_capacity = min_capacity; | ||||
|  | ||||
| 	return array_set_capacity(array, new_capacity); | ||||
| } | ||||
|  | ||||
| template<class Type> forceinline | ||||
| usize array_num(Array<Type> array) { | ||||
| 	GEN_ASSERT(array != nullptr); | ||||
| 	return array_get_header(array)->Num; | ||||
| } | ||||
|  | ||||
| template<class Type> forceinline | ||||
| void array_pop(Array<Type> array) { | ||||
| 	GEN_ASSERT(array != nullptr); | ||||
| 	ArrayHeader* header = array_get_header(array); | ||||
| 	GEN_ASSERT(header->Num > 0); | ||||
| 	header->Num--; | ||||
| } | ||||
|  | ||||
| template<class Type> inline | ||||
| void array_remove_at(Array<Type> array, usize idx) | ||||
| { | ||||
| 	GEN_ASSERT(array != nullptr); | ||||
| 	ArrayHeader* header = array_get_header(array); | ||||
| 	GEN_ASSERT(idx < header->Num); | ||||
|  | ||||
| 	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) | ||||
| { | ||||
| 	GEN_ASSERT(  array != nullptr); | ||||
| 	GEN_ASSERT(* array != nullptr); | ||||
| 	GEN_ASSERT(num > 0) | ||||
| 	ArrayHeader* header = array_get_header(array); | ||||
|  | ||||
| 	if (header->Capacity < new_capacity) | ||||
| 		return set_capacity(array, new_capacity); | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| template<class Type> inline | ||||
| bool array_resize(Array<Type>* array, usize num) | ||||
| { | ||||
| 	GEN_ASSERT(  array != nullptr); | ||||
| 	GEN_ASSERT(* array != nullptr); | ||||
| 	ArrayHeader* header = array_get_header(* array); | ||||
|  | ||||
| 	if (header->Capacity < num) { | ||||
| 		if (! array_grow( array, num)) | ||||
| 			return false; | ||||
| 		header = array_get_header(* array); | ||||
| 	} | ||||
|  | ||||
| 	header->Num = num; | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| template<class Type> inline | ||||
| bool array_set_capacity(Array<Type>* array, usize new_capacity) | ||||
| { | ||||
| 	GEN_ASSERT(  array != nullptr); | ||||
| 	GEN_ASSERT(* array != nullptr); | ||||
| 	ArrayHeader* header = array_get_header(* array); | ||||
|  | ||||
| 	if (new_capacity == header->Capacity) | ||||
| 		return true; | ||||
|  | ||||
| 	if (new_capacity < header->Num) | ||||
| 	{ | ||||
| 		header->Num = new_capacity; | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	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(ArrayHeader) + sizeof(Type) * header->Num); | ||||
|  | ||||
| 	new_header->Capacity = new_capacity; | ||||
|  | ||||
| 	allocator_free(header->Allocator, header); | ||||
|  | ||||
| 	Type** Data = (Type**)array; | ||||
| 	* Data = rcast(Type*, new_header + 1); | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| // 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. | ||||
|  | ||||
| #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 ) | ||||
|  | ||||
| #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> 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)); | ||||
|  | ||||
| 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); | ||||
|  | ||||
| static constexpr f32 HashTable_CriticalLoadScale = 0.7f; | ||||
|  | ||||
| template<typename Type> | ||||
| struct HashTable | ||||
| { | ||||
| 	Array<ssize>                Hashes; | ||||
| 	Array<HashTableEntry<Type>> Entries; | ||||
|  | ||||
| #if ! GEN_C_LIKE_CPP | ||||
| #pragma region Member Mapping | ||||
| 	forceinline static HashTable init(AllocatorInfo allocator)                    { return	hashtable_init<Type>(allocator); } | ||||
| 	forceinline static HashTable init_reserve(AllocatorInfo allocator, usize num) { return	hashtable_init_reserve<Type>(allocator, num); } | ||||
|  | ||||
| 	forceinline void  clear()                           {        clear<Type>(*this); } | ||||
| 	forceinline void  destroy()                         {        destroy<Type>(*this); } | ||||
| 	forceinline Type* get(u64 key)                      { return get<Type>(*this, key); } | ||||
| 	forceinline void  grow()                            {        grow<Type>(*this); } | ||||
| 	forceinline void  rehash(ssize new_num)             {        rehash<Type>(*this, new_num); } | ||||
| 	forceinline void  rehash_fast()                     {        rehash_fast<Type>(*this); } | ||||
| 	forceinline void  remove(u64 key)                   {        remove<Type>(*this, key); } | ||||
| 	forceinline void  remove_entry(ssize idx)           {        remove_entry<Type>(*this, idx); } | ||||
| 	forceinline void  set(u64 key, Type value)          {        set<Type>(*this, key, value); } | ||||
| 	forceinline ssize slot(u64 key)                     { return slot<Type>(*this, key); } | ||||
| 	forceinline void  map(void (*proc)(u64, Type))      {        map<Type>(*this, proc); } | ||||
| 	forceinline void  map_mut(void (*proc)(u64, Type*)) {        map_mut<Type>(*this, proc); } | ||||
| #pragma endregion Member Mapping | ||||
| #endif | ||||
|  | ||||
| 	using DataType = Type; | ||||
| }; | ||||
|  | ||||
| #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 | ||||
|  | ||||
| template<typename Type> inline | ||||
| HashTable<Type> hashtable_init(AllocatorInfo allocator) { | ||||
| 	HashTable<Type> result = hashtable_init_reserve<Type>(allocator, 8); | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| template<typename Type> inline | ||||
| HashTable<Type> hashtable_init_reserve(AllocatorInfo allocator, usize num) | ||||
| { | ||||
| 	HashTable<Type> result = { { nullptr }, { nullptr } }; | ||||
|  | ||||
| 	result.Hashes = array_init_reserve<ssize>(allocator, num); | ||||
| 	array_get_header(result.Hashes)->Num = num; | ||||
| 	array_resize(& result.Hashes, num); | ||||
| 	array_fill(result.Hashes, 0, num, (ssize)-1); | ||||
|  | ||||
| 	result.Entries = array_init_reserve<HashTableEntry<Type>>(allocator, num); | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| template<typename Type> forceinline | ||||
| void hashtable_clear(HashTable<Type> table) { | ||||
| 	GEN_ASSERT_NOT_NULL(table.Hashes); | ||||
| 	GEN_ASSERT_NOT_NULL(table.Entries); | ||||
| 	array_clear(table.Entries); | ||||
| 	array_fill(table.Hashes, 0, array_num(table.Hashes), (ssize)-1); | ||||
| } | ||||
|  | ||||
| template<typename Type> forceinline | ||||
| void hashtable_destroy(HashTable<Type>* table) { | ||||
| 	GEN_ASSERT_NOT_NULL(table->Hashes); | ||||
| 	GEN_ASSERT_NOT_NULL(table->Entries); | ||||
| 	if (table->Hashes && array_get_header(table->Hashes)->Capacity) { | ||||
| 		array_free(table->Hashes); | ||||
| 		array_free(table->Entries); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| template<typename Type> forceinline | ||||
| Type* hashtable_get(HashTable<Type> table, u64 key) { | ||||
| 	GEN_ASSERT_NOT_NULL(table.Hashes); | ||||
| 	GEN_ASSERT_NOT_NULL(table.Entries); | ||||
| 	ssize idx = hashtable__find(table, key).EntryIndex; | ||||
| 	if (idx >= 0) | ||||
| 		return & table.Entries[idx].Value; | ||||
|  | ||||
| 	return nullptr; | ||||
| } | ||||
|  | ||||
| template<typename Type> forceinline | ||||
| void hashtable_map(HashTable<Type> table, void (*map_proc)(u64 key, Type value)) { | ||||
| 	GEN_ASSERT_NOT_NULL(table.Hashes); | ||||
| 	GEN_ASSERT_NOT_NULL(table.Entries); | ||||
| 	GEN_ASSERT_NOT_NULL(map_proc); | ||||
|  | ||||
| 	for (ssize idx = 0; idx < ssize(num(table.Entries)); ++idx) { | ||||
| 		map_proc(table.Entries[idx].Key, table.Entries[idx].Value); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| template<typename Type> forceinline | ||||
| void hashtable_map_mut(HashTable<Type> table, void (*map_proc)(u64 key, Type* value)) { | ||||
| 	GEN_ASSERT_NOT_NULL(table.Hashes); | ||||
| 	GEN_ASSERT_NOT_NULL(table.Entries); | ||||
| 	GEN_ASSERT_NOT_NULL(map_proc); | ||||
|  | ||||
| 	for (ssize idx = 0; idx < ssize(num(table.Entries)); ++idx) { | ||||
| 		map_proc(table.Entries[idx].Key, & table.Entries[idx].Value); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| template<typename Type> forceinline | ||||
| void hashtable_grow(HashTable<Type>* table) { | ||||
| 	GEN_ASSERT_NOT_NULL(table); | ||||
| 	GEN_ASSERT_NOT_NULL(table->Hashes); | ||||
| 	GEN_ASSERT_NOT_NULL(table->Entries); | ||||
| 	ssize new_num = array_grow_formula( array_num(table->Entries)); | ||||
| 	hashtable_rehash(table, new_num); | ||||
| } | ||||
|  | ||||
| template<typename Type> inline | ||||
| void hashtable_rehash(HashTable<Type>* table, ssize new_num) | ||||
| { | ||||
| 	GEN_ASSERT_NOT_NULL(table); | ||||
| 	GEN_ASSERT_NOT_NULL(table->Hashes); | ||||
| 	GEN_ASSERT_NOT_NULL(table->Entries); | ||||
| 	ssize last_added_index; | ||||
| 	HashTable<Type> new_ht = hashtable_init_reserve<Type>( array_get_header(table->Hashes)->Allocator, new_num); | ||||
|  | ||||
| 	for (ssize idx = 0; idx < ssize( array_num(table->Entries)); ++idx) | ||||
| 	{ | ||||
| 		HashTableFindResult find_result; | ||||
| 		HashTableEntry<Type>& entry = table->Entries[idx]; | ||||
|  | ||||
| 		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; | ||||
| 		else | ||||
| 			new_ht.Entries[find_result.PrevIndex].Next = last_added_index; | ||||
|  | ||||
| 		new_ht.Entries[last_added_index].Next = find_result.EntryIndex; | ||||
| 		new_ht.Entries[last_added_index].Value = entry.Value; | ||||
| 	} | ||||
|  | ||||
| 	hashtable_destroy(table); | ||||
| 	* table = new_ht; | ||||
| } | ||||
|  | ||||
| template<typename Type> inline | ||||
| void hashtable_rehash_fast(HashTable<Type> table) | ||||
| { | ||||
| 	GEN_ASSERT_NOT_NULL(table.Hashes); | ||||
| 	GEN_ASSERT_NOT_NULL(table.Entries); | ||||
| 	ssize idx; | ||||
|  | ||||
| 	for (idx = 0; idx < ssize(num(table.Entries)); idx++) | ||||
| 		table.Entries[idx].Next = -1; | ||||
|  | ||||
| 	for (idx = 0; idx < ssize(num(table.Hashes)); idx++) | ||||
| 		table.Hashes[idx] = -1; | ||||
|  | ||||
| 	for (idx = 0; idx < ssize(num(table.Entries)); idx++) | ||||
| 	{ | ||||
| 		HashTableEntry<Type>* entry; | ||||
| 		HashTableFindResult find_result; | ||||
|  | ||||
| 		entry = &table.Entries[idx]; | ||||
| 		find_result = find(table, entry->Key); | ||||
|  | ||||
| 		if (find_result.PrevIndex < 0) | ||||
| 			table.Hashes[find_result.HashIndex] = idx; | ||||
| 		else | ||||
| 			table.Entries[find_result.PrevIndex].Next = idx; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| template<typename Type> forceinline | ||||
| void hashtable_remove(HashTable<Type> table, u64 key) { | ||||
| 	GEN_ASSERT_NOT_NULL(table.Hashes); | ||||
| 	GEN_ASSERT_NOT_NULL(table.Entries); | ||||
| 	HashTableFindResult find_result = find(table, key); | ||||
|  | ||||
| 	if (find_result.EntryIndex >= 0) { | ||||
| 		remove_at(table.Entries, find_result.EntryIndex); | ||||
| 		rehash_fast(table); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| template<typename Type> forceinline | ||||
| void hashtable_remove_entry(HashTable<Type> table, ssize idx) { | ||||
| 	GEN_ASSERT_NOT_NULL(table.Hashes); | ||||
| 	GEN_ASSERT_NOT_NULL(table.Entries); | ||||
| 	remove_at(table.Entries, idx); | ||||
| } | ||||
|  | ||||
| template<typename Type> inline | ||||
| void hashtable_set(HashTable<Type>* table, u64 key, Type value) | ||||
| { | ||||
| 	GEN_ASSERT_NOT_NULL(table); | ||||
| 	GEN_ASSERT_NOT_NULL(table->Hashes); | ||||
| 	GEN_ASSERT_NOT_NULL(table->Entries); | ||||
| 	ssize idx; | ||||
| 	HashTableFindResult find_result; | ||||
|  | ||||
| 	if (hashtable_full(* table)) | ||||
| 		hashtable_grow(table); | ||||
|  | ||||
| 	find_result = hashtable__find(* table, key); | ||||
| 	if (find_result.EntryIndex >= 0) { | ||||
| 		idx = find_result.EntryIndex; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		idx = hashtable__add_entry(table, key); | ||||
|  | ||||
| 		if (find_result.PrevIndex >= 0) { | ||||
| 			table->Entries[find_result.PrevIndex].Next = idx; | ||||
| 		} | ||||
| 		else { | ||||
| 			table->Hashes[find_result.HashIndex] = idx; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	table->Entries[idx].Value = value; | ||||
|  | ||||
| 	if (hashtable_full(* table)) | ||||
| 		hashtable_grow(table); | ||||
| } | ||||
|  | ||||
| template<typename Type> forceinline | ||||
| ssize hashtable_slot(HashTable<Type> table, u64 key) { | ||||
| 	GEN_ASSERT_NOT_NULL(table.Hashes); | ||||
| 	GEN_ASSERT_NOT_NULL(table.Entries); | ||||
| 	for (ssize idx = 0; idx < ssize(num(table.Hashes)); ++idx) | ||||
| 		if (table.Hashes[idx] == key) | ||||
| 			return idx; | ||||
|  | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| template<typename Type> forceinline | ||||
| ssize hashtable__add_entry(HashTable<Type>* table, u64 key) { | ||||
| 	GEN_ASSERT_NOT_NULL(table); | ||||
| 	GEN_ASSERT_NOT_NULL(table->Hashes); | ||||
| 	GEN_ASSERT_NOT_NULL(table->Entries); | ||||
| 	ssize idx; | ||||
| 	HashTableEntry<Type> entry = { key, -1 }; | ||||
|  | ||||
| 	idx = array_num(table->Entries); | ||||
| 	array_append( table->Entries, entry); | ||||
| 	return idx; | ||||
| } | ||||
|  | ||||
| template<typename Type> inline | ||||
| HashTableFindResult hashtable__find(HashTable<Type> table, u64 key) | ||||
| { | ||||
| 	GEN_ASSERT_NOT_NULL(table.Hashes); | ||||
| 	GEN_ASSERT_NOT_NULL(table.Entries); | ||||
| 	HashTableFindResult result = { -1, -1, -1 }; | ||||
|  | ||||
| 	if (array_num(table.Hashes) > 0) | ||||
| 	{ | ||||
| 		result.HashIndex = key % array_num(table.Hashes); | ||||
| 		result.EntryIndex = table.Hashes[result.HashIndex]; | ||||
|  | ||||
| 		while (result.EntryIndex >= 0) | ||||
| 		{ | ||||
| 			if (table.Entries[result.EntryIndex].Key == key) | ||||
| 				break; | ||||
|  | ||||
| 			result.PrevIndex = result.EntryIndex; | ||||
| 			result.EntryIndex = table.Entries[result.EntryIndex].Next; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| template<typename Type> forceinline | ||||
| bool hashtable_full(HashTable<Type> table) { | ||||
| 	GEN_ASSERT_NOT_NULL(table.Hashes); | ||||
| 	GEN_ASSERT_NOT_NULL(table.Entries); | ||||
| 	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_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) | ||||
|  | ||||
| //#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) | ||||
|  | ||||
| #pragma endregion HashTable | ||||
|  | ||||
| #pragma endregion Containers | ||||
							
								
								
									
										48
									
								
								base/dependencies/debug.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								base/dependencies/debug.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	pragma once | ||||
| #	include "debug.hpp" | ||||
| #	include "basic_types.hpp" | ||||
| #   include "src_start.cpp" | ||||
| #endif | ||||
|  | ||||
| #pragma region Debug | ||||
|  | ||||
| void assert_handler( char const* condition, char const* file, char const* function, s32 line, char const* msg, ... ) | ||||
| { | ||||
| 	_printf_err( "%s - %s:(%d): Assert Failure: ", file, function, line ); | ||||
|  | ||||
| 	if ( condition ) | ||||
| 		_printf_err( "`%s` \n", condition ); | ||||
|  | ||||
| 	if ( msg ) | ||||
| 	{ | ||||
| 		va_list va; | ||||
| 		va_start( va, msg ); | ||||
| 		_printf_err_va( msg, va ); | ||||
| 		va_end( va ); | ||||
| 	} | ||||
|  | ||||
| 	_printf_err( "%s", "\n" ); | ||||
| } | ||||
|  | ||||
| s32 assert_crash( char const* condition ) | ||||
| { | ||||
| 	GEN_PANIC( condition ); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| #if defined( GEN_SYSTEM_WINDOWS ) | ||||
| 	void process_exit( u32 code ) | ||||
| 	{ | ||||
| 		ExitProcess( code ); | ||||
| 	} | ||||
| #else | ||||
| #	include <stdlib.h> | ||||
|  | ||||
| 	void process_exit( u32 code ) | ||||
| 	{ | ||||
| 		exit( code ); | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| #pragma endregion Debug | ||||
							
								
								
									
										63
									
								
								base/dependencies/debug.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								base/dependencies/debug.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	pragma once | ||||
| #	include "basic_types.hpp" | ||||
| #endif | ||||
|  | ||||
| #pragma region Debug | ||||
|  | ||||
| #if defined( _MSC_VER ) | ||||
| #	if _MSC_VER < 1300 | ||||
| #		define GEN_DEBUG_TRAP() __asm int 3 /* Trap to debugger! */ | ||||
| #	else | ||||
| #		define GEN_DEBUG_TRAP() __debugbreak() | ||||
| #	endif | ||||
| #elif defined( GEN_COMPILER_TINYC ) | ||||
| #	define GEN_DEBUG_TRAP() process_exit( 1 ) | ||||
| #else | ||||
| #	define GEN_DEBUG_TRAP() __builtin_trap() | ||||
| #endif | ||||
|  | ||||
| #define GEN_ASSERT( cond ) GEN_ASSERT_MSG( cond, NULL ) | ||||
|  | ||||
| #define GEN_ASSERT_MSG( cond, msg, ... )                                                              \ | ||||
| 	do                                                                                                \ | ||||
| 	{                                                                                                 \ | ||||
| 		if ( ! ( cond ) )                                                                             \ | ||||
| 		{                                                                                             \ | ||||
| 			assert_handler( #cond, __FILE__, __func__, scast( s64, __LINE__ ), msg, ##__VA_ARGS__ );  \ | ||||
| 			GEN_DEBUG_TRAP();                                                                         \ | ||||
| 		}                                                                                             \ | ||||
| 	} while ( 0 ) | ||||
|  | ||||
| #define GEN_ASSERT_NOT_NULL( ptr ) GEN_ASSERT_MSG( ( ptr ) != NULL, #ptr " must not be NULL" ) | ||||
|  | ||||
| // NOTE: Things that shouldn't happen with a message! | ||||
| #define GEN_PANIC( msg, ... ) GEN_ASSERT_MSG( 0, msg, ##__VA_ARGS__ ) | ||||
|  | ||||
| #if Build_Debug | ||||
| 	#define GEN_FATAL( ... )                               \ | ||||
| 	do                                                     \ | ||||
| 	{                                                      \ | ||||
| 		local_persist thread_local                         \ | ||||
| 		char buf[GEN_PRINTF_MAXLEN] = { 0 };               \ | ||||
| 		                                                   \ | ||||
| 		str_fmt(buf, GEN_PRINTF_MAXLEN, __VA_ARGS__);      \ | ||||
| 		GEN_PANIC(buf);                                    \ | ||||
| 	}                                                      \ | ||||
| 	while (0) | ||||
| #else | ||||
|  | ||||
| #	define GEN_FATAL( ... )                  \ | ||||
| 	do                                       \ | ||||
| 	{                                        \ | ||||
| 		str_fmt_out_err( __VA_ARGS__ );      \ | ||||
| 		process_exit(1);                     \ | ||||
| 	}                                        \ | ||||
| 	while (0) | ||||
| #endif | ||||
|  | ||||
| void assert_handler( char const* condition, char const* file, char const* function, s32 line, char const* msg, ... ); | ||||
| s32  assert_crash( char const* condition ); | ||||
| void process_exit( u32 code ); | ||||
|  | ||||
| #pragma endregion Debug | ||||
							
								
								
									
										659
									
								
								base/dependencies/filesystem.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										659
									
								
								base/dependencies/filesystem.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,659 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	pragma once | ||||
| #	include "strings.cpp" | ||||
| #endif | ||||
|  | ||||
| #pragma region File Handling | ||||
|  | ||||
| #if defined( GEN_SYSTEM_WINDOWS ) || defined( GEN_SYSTEM_CYGWIN ) | ||||
|  | ||||
| internal | ||||
| wchar_t* _alloc_utf8_to_ucs2( AllocatorInfo a, char const* text, ssize* w_len_ ) | ||||
| { | ||||
| 	wchar_t* w_text = NULL; | ||||
| 	ssize       len = 0, w_len = 0, w_len1 = 0; | ||||
| 	if ( text == NULL ) | ||||
| 	{ | ||||
| 		if ( w_len_ ) | ||||
| 			*w_len_ = w_len; | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	len = str_len( text ); | ||||
| 	if ( len == 0 ) | ||||
| 	{ | ||||
| 		if ( w_len_ ) | ||||
| 			*w_len_ = w_len; | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	w_len = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, text, scast( int, len), NULL, 0 ); | ||||
| 	if ( w_len == 0 ) | ||||
| 	{ | ||||
| 		if ( w_len_ ) | ||||
| 			*w_len_ = w_len; | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	w_text = alloc_array( a, wchar_t, w_len + 1 ); | ||||
| 	w_len1 = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, text, scast( int, len), w_text, scast( int, w_len) ); | ||||
| 	if ( w_len1 == 0 ) | ||||
| 	{ | ||||
| 		allocator_free( a, w_text ); | ||||
| 		if ( w_len_ ) | ||||
| 			*w_len_ = 0; | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	w_text[ w_len ] = 0; | ||||
| 	if ( w_len_ ) | ||||
| 		*w_len_ = w_len; | ||||
| 	return w_text; | ||||
| } | ||||
|  | ||||
| internal | ||||
| GEN_FILE_SEEK_PROC( _win32_file_seek ) | ||||
| { | ||||
| 	LARGE_INTEGER li_offset; | ||||
| 	li_offset.QuadPart = offset; | ||||
| 	if ( ! SetFilePointerEx( fd.p, li_offset, &li_offset, whence ) ) | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	if ( new_offset ) | ||||
| 		*new_offset = li_offset.QuadPart; | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| 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_ = scast( DWORD, ( size > GEN_I32_MAX ? GEN_I32_MAX : size )); | ||||
| 	DWORD bytes_read_; | ||||
| 	if ( ReadFile( fd.p, buffer, size_, &bytes_read_, NULL ) ) | ||||
| 	{ | ||||
| 		if ( bytes_read ) | ||||
| 			*bytes_read = bytes_read_; | ||||
| 		result = true; | ||||
| 	} | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| internal | ||||
| GEN_FILE_WRITE_AT_PROC( _win32_file_write ) | ||||
| { | ||||
| 	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 ) ) | ||||
| 	{ | ||||
| 		if ( bytes_written ) | ||||
| 			*bytes_written = bytes_written_; | ||||
| 		return true; | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| 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 ) | ||||
| { | ||||
| 	DWORD    desired_access; | ||||
| 	DWORD    creation_disposition; | ||||
| 	void*    handle; | ||||
| 	wchar_t* w_text; | ||||
|  | ||||
| 	switch ( mode & GEN_FILE_MODES ) | ||||
| 	{ | ||||
| 		case EFileMode_READ : | ||||
| 			desired_access       = GENERIC_READ; | ||||
| 			creation_disposition = OPEN_EXISTING; | ||||
| 			break; | ||||
| 		case EFileMode_WRITE : | ||||
| 			desired_access       = GENERIC_WRITE; | ||||
| 			creation_disposition = CREATE_ALWAYS; | ||||
| 			break; | ||||
| 		case EFileMode_APPEND : | ||||
| 			desired_access       = GENERIC_WRITE; | ||||
| 			creation_disposition = OPEN_ALWAYS; | ||||
| 			break; | ||||
| 		case EFileMode_READ | EFileMode_RW : | ||||
| 			desired_access       = GENERIC_READ | GENERIC_WRITE; | ||||
| 			creation_disposition = OPEN_EXISTING; | ||||
| 			break; | ||||
| 		case EFileMode_WRITE | EFileMode_RW : | ||||
| 			desired_access       = GENERIC_READ | GENERIC_WRITE; | ||||
| 			creation_disposition = CREATE_ALWAYS; | ||||
| 			break; | ||||
| 		case EFileMode_APPEND | EFileMode_RW : | ||||
| 			desired_access       = GENERIC_READ | GENERIC_WRITE; | ||||
| 			creation_disposition = OPEN_ALWAYS; | ||||
| 			break; | ||||
| 		default : | ||||
| 			GEN_PANIC( "Invalid file mode" ); | ||||
| 			return EFileError_INVALID; | ||||
| 	} | ||||
|  | ||||
| 	w_text = _alloc_utf8_to_ucs2( heap(), filename, NULL ); | ||||
| 	handle = CreateFileW( w_text, desired_access, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, creation_disposition, FILE_ATTRIBUTE_NORMAL, NULL ); | ||||
|  | ||||
| 	allocator_free( heap(), w_text ); | ||||
|  | ||||
| 	if ( handle == INVALID_HANDLE_VALUE ) | ||||
| 	{ | ||||
| 		DWORD err = GetLastError(); | ||||
| 		switch ( err ) | ||||
| 		{ | ||||
| 			case ERROR_FILE_NOT_FOUND : | ||||
| 				return EFileError_NOT_EXISTS; | ||||
| 			case ERROR_FILE_EXISTS : | ||||
| 				return EFileError_EXISTS; | ||||
| 			case ERROR_ALREADY_EXISTS : | ||||
| 				return EFileError_EXISTS; | ||||
| 			case ERROR_ACCESS_DENIED : | ||||
| 				return EFileError_PERMISSION; | ||||
| 		} | ||||
| 		return EFileError_INVALID; | ||||
| 	} | ||||
|  | ||||
| 	if ( mode & EFileMode_APPEND ) | ||||
| 	{ | ||||
| 		LARGE_INTEGER offset = { { 0 } }; | ||||
| 		if ( ! SetFilePointerEx( handle, offset, NULL, ESeekWhence_END ) ) | ||||
| 		{ | ||||
| 			CloseHandle( handle ); | ||||
| 			return EFileError_INVALID; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	fd->p = handle; | ||||
| 	*ops  = default_file_operations; | ||||
| 	return EFileError_NONE; | ||||
| } | ||||
|  | ||||
| #else    // POSIX | ||||
| #	include <fcntl.h> | ||||
|  | ||||
| internal | ||||
| GEN_FILE_SEEK_PROC( _posix_file_seek ) | ||||
| { | ||||
| #	if defined( GEN_SYSTEM_OSX ) | ||||
| 	s64 res = lseek( fd.i, offset, whence ); | ||||
| #	else    // TODO(ZaKlaus): @fixme lseek64 | ||||
| 	s64 res = lseek( fd.i, offset, whence ); | ||||
| #	endif | ||||
| 	if ( res < 0 ) | ||||
| 		return false; | ||||
| 	if ( new_offset ) | ||||
| 		*new_offset = res; | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| internal | ||||
| GEN_FILE_READ_AT_PROC( _posix_file_read ) | ||||
| { | ||||
| 	unused( stop_at_newline ); | ||||
| 	ssize res = pread( fd.i, buffer, size, offset ); | ||||
| 	if ( res < 0 ) | ||||
| 		return false; | ||||
| 	if ( bytes_read ) | ||||
| 		*bytes_read = res; | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| internal | ||||
| GEN_FILE_WRITE_AT_PROC( _posix_file_write ) | ||||
| { | ||||
| 	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( scast( int, fd.i), buffer, size ); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		res = pwrite( scast( int, fd.i), buffer, size, offset ); | ||||
| 	} | ||||
| 	if ( res < 0 ) | ||||
| 		return false; | ||||
| 	if ( bytes_written ) | ||||
| 		*bytes_written = res; | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| 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 ) | ||||
| { | ||||
| 	s32 os_mode; | ||||
| 	switch ( mode & GEN_FILE_MODES ) | ||||
| 	{ | ||||
| 		case EFileMode_READ : | ||||
| 			os_mode = O_RDONLY; | ||||
| 			break; | ||||
| 		case EFileMode_WRITE : | ||||
| 			os_mode = O_WRONLY | O_CREAT | O_TRUNC; | ||||
| 			break; | ||||
| 		case EFileMode_APPEND : | ||||
| 			os_mode = O_WRONLY | O_APPEND | O_CREAT; | ||||
| 			break; | ||||
| 		case EFileMode_READ | EFileMode_RW : | ||||
| 			os_mode = O_RDWR; | ||||
| 			break; | ||||
| 		case EFileMode_WRITE | EFileMode_RW : | ||||
| 			os_mode = O_RDWR | O_CREAT | O_TRUNC; | ||||
| 			break; | ||||
| 		case EFileMode_APPEND | EFileMode_RW : | ||||
| 			os_mode = O_RDWR | O_APPEND | O_CREAT; | ||||
| 			break; | ||||
| 		default : | ||||
| 			GEN_PANIC( "Invalid file mode" ); | ||||
| 			return EFileError_INVALID; | ||||
| 	} | ||||
|  | ||||
| 	fd->i = open( filename, os_mode, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ); | ||||
| 	if ( fd->i < 0 ) | ||||
| 	{ | ||||
| 		// TODO : More file errors | ||||
| 		return EFileError_INVALID; | ||||
| 	} | ||||
|  | ||||
| 	*ops = default_file_operations; | ||||
| 	return EFileError_NONE; | ||||
| } | ||||
|  | ||||
| // POSIX | ||||
| #endif | ||||
|  | ||||
| internal void _dirinfo_free_entry( DirEntry* entry ); | ||||
|  | ||||
| // TODO : Is this a bad idea? | ||||
| global b32      _std_file_set                     = false; | ||||
| global FileInfo _std_files[ EFileStandard_COUNT ] = { | ||||
| { | ||||
| 	{ nullptr, nullptr, nullptr, nullptr }, | ||||
| 	{ nullptr }, | ||||
| 	0, | ||||
| 	nullptr, | ||||
| 	0, | ||||
| 	nullptr | ||||
| } }; | ||||
|  | ||||
| #if defined( GEN_SYSTEM_WINDOWS ) || defined( GEN_SYSTEM_CYGWIN ) | ||||
|  | ||||
| FileInfo* file_get_standard( FileStandardType std ) | ||||
| { | ||||
| 	if ( ! _std_file_set ) | ||||
| 	{ | ||||
| #	define GEN__SET_STD_FILE( type, v ) \ | ||||
| 		_std_files[ type ].fd.p = v;    \ | ||||
| 		_std_files[ type ].ops  = default_file_operations | ||||
| 		GEN__SET_STD_FILE( EFileStandard_INPUT, GetStdHandle( STD_INPUT_HANDLE ) ); | ||||
| 		GEN__SET_STD_FILE( EFileStandard_OUTPUT, GetStdHandle( STD_OUTPUT_HANDLE ) ); | ||||
| 		GEN__SET_STD_FILE( EFileStandard_ERROR, GetStdHandle( STD_ERROR_HANDLE ) ); | ||||
| #	undef GEN__SET_STD_FILE | ||||
| 		_std_file_set = true; | ||||
| 	} | ||||
| 	return &_std_files[ std ]; | ||||
| } | ||||
|  | ||||
| #else    // POSIX | ||||
|  | ||||
| FileInfo* file_get_standard( FileStandardType std ) | ||||
| { | ||||
| 	if ( ! _std_file_set ) | ||||
| 	{ | ||||
| #	define GEN__SET_STD_FILE( type, v ) \ | ||||
| 		_std_files[ type ].fd.i = v;     \ | ||||
| 		_std_files[ type ].ops  = default_file_operations | ||||
| 		GEN__SET_STD_FILE( EFileStandard_INPUT, 0 ); | ||||
| 		GEN__SET_STD_FILE( EFileStandard_OUTPUT, 1 ); | ||||
| 		GEN__SET_STD_FILE( EFileStandard_ERROR, 2 ); | ||||
| #	undef GEN__SET_STD_FILE | ||||
| 		_std_file_set = true; | ||||
| 	} | ||||
| 	return &_std_files[ std ]; | ||||
| } | ||||
|  | ||||
| #endif | ||||
|  | ||||
| FileError file_close( FileInfo* f ) | ||||
| { | ||||
| 	if ( ! f ) | ||||
| 		return EFileError_INVALID; | ||||
|  | ||||
| 	if ( f->filename ) | ||||
| 		allocator_free( heap(), ccast( char*, f->filename )); | ||||
|  | ||||
| #if defined( GEN_SYSTEM_WINDOWS ) | ||||
| 	if ( f->fd.p == INVALID_HANDLE_VALUE ) | ||||
| 		return EFileError_INVALID; | ||||
| #else | ||||
| 	if ( f->fd.i < 0 ) | ||||
| 		return EFileError_INVALID; | ||||
| #endif | ||||
|  | ||||
| 	if ( f->is_temp ) | ||||
| 	{ | ||||
| 		f->ops.close( f->fd ); | ||||
| 		return EFileError_NONE; | ||||
| 	} | ||||
|  | ||||
| 	if ( ! f->ops.read_at ) | ||||
| 		f->ops = default_file_operations; | ||||
| 	f->ops.close( f->fd ); | ||||
|  | ||||
| #if 0 | ||||
| 	if ( f->Dir ) | ||||
| 	{ | ||||
| 		_dirinfo_free_entry( f->Dir ); | ||||
| 		mfree( f->Dir ); | ||||
| 		f->Dir = NULL; | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| 	return EFileError_NONE; | ||||
| } | ||||
|  | ||||
| FileError file_new( FileInfo* f, FileDescriptor fd, FileOperations ops, char const* filename ) | ||||
| { | ||||
| 	FileError err = EFileError_NONE; | ||||
| 	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( ccast( char*, f->filename), ccast( char*, filename), len + 1 ); | ||||
|  | ||||
| 	return err; | ||||
| } | ||||
|  | ||||
| FileError file_open( FileInfo* f, char const* filename ) | ||||
| { | ||||
| 	return file_open_mode( f, EFileMode_READ, filename ); | ||||
| } | ||||
|  | ||||
| FileError file_open_mode( FileInfo* f, FileMode mode, char const* filename ) | ||||
| { | ||||
| 	FileInfo file_ = | ||||
| 	{ | ||||
| 		{ nullptr, nullptr, nullptr, nullptr }, | ||||
| 		{ nullptr }, | ||||
| 		0, | ||||
| 		nullptr, | ||||
| 		0, | ||||
| 		nullptr | ||||
| 		}; | ||||
|  | ||||
| 	*f = file_; | ||||
| 	FileError err; | ||||
|  | ||||
| #if defined( GEN_SYSTEM_WINDOWS ) || defined( GEN_SYSTEM_CYGWIN ) | ||||
| 	err = _win32_file_open( &f->fd, &f->ops, mode, filename ); | ||||
| #else | ||||
| 	err = _posix_file_open( &f->fd, &f->ops, mode, filename ); | ||||
| #endif | ||||
|  | ||||
| 	if ( err == EFileError_NONE ) | ||||
| 		return file_new( f, f->fd, f->ops, filename ); | ||||
|  | ||||
| 	return err; | ||||
| } | ||||
|  | ||||
| s64 file_size( FileInfo* f ) | ||||
| { | ||||
| 	s64 size        = 0; | ||||
| 	s64 prev_offset = file_tell( f ); | ||||
|  | ||||
| 	file_seek_to_end( f ); | ||||
| 	size = file_tell( f ); | ||||
|  | ||||
| 	file_seek( f, prev_offset ); | ||||
|  | ||||
| 	return size; | ||||
| } | ||||
|  | ||||
| FileContents file_read_contents( AllocatorInfo a, b32 zero_terminate, char const* filepath ) | ||||
| { | ||||
| 	FileContents result; | ||||
| 	FileInfo     file  ; | ||||
|  | ||||
| 	result.allocator = a; | ||||
|  | ||||
| 	if ( file_open( &file, filepath ) == EFileError_NONE ) | ||||
| 	{ | ||||
| 		ssize fsize = scast( ssize , file_size( &file )); | ||||
| 		if ( fsize > 0 ) | ||||
| 		{ | ||||
| 			result.data = alloc( a, zero_terminate ? fsize + 1 : fsize ); | ||||
| 			result.size = fsize; | ||||
| 			file_read_at( &file, result.data, result.size, 0 ); | ||||
| 			if ( zero_terminate ) | ||||
| 			{ | ||||
| 				u8* str      = rcast( u8*, result.data); | ||||
| 				str[ fsize ] = '\0'; | ||||
| 			} | ||||
| 		} | ||||
| 		file_close( &file ); | ||||
| 	} | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| typedef struct _memory_fd _memory_fd; | ||||
| struct _memory_fd | ||||
| { | ||||
| 	u8            magic; | ||||
| 	u8*           buf;    //< zpl_array OR plain buffer if we can't write | ||||
| 	ssize         cursor; | ||||
| 	AllocatorInfo allocator; | ||||
|  | ||||
| 	FileStreamFlags flags; | ||||
| 	ssize           cap; | ||||
| }; | ||||
|  | ||||
| #define GEN__FILE_STREAM_FD_MAGIC 37 | ||||
|  | ||||
| FileDescriptor _file_stream_fd_make( _memory_fd* d ); | ||||
| _memory_fd*    _file_stream_from_fd( FileDescriptor fd ); | ||||
|  | ||||
| inline | ||||
| FileDescriptor _file_stream_fd_make( _memory_fd* d ) | ||||
| { | ||||
| 	FileDescriptor fd = { 0 }; | ||||
| 	fd.p              = ( void* )d; | ||||
| 	return 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 ); | ||||
| 	return d; | ||||
| } | ||||
|  | ||||
| b8 file_stream_new( FileInfo* file, AllocatorInfo allocator ) | ||||
| { | ||||
| 	GEN_ASSERT_NOT_NULL( file ); | ||||
|  | ||||
| 	_memory_fd* d = ( _memory_fd* )alloc( allocator, size_of( _memory_fd ) ); | ||||
|  | ||||
| 	if ( ! d ) | ||||
| 		return false; | ||||
|  | ||||
| 	zero_item( file ); | ||||
| 	d->magic     = GEN__FILE_STREAM_FD_MAGIC; | ||||
| 	d->allocator = allocator; | ||||
| 	d->flags     = EFileStream_CLONE_WRITABLE; | ||||
| 	d->cap       = 0; | ||||
| 	d->buf       = array_init( u8, allocator ); | ||||
|  | ||||
| 	if ( ! d->buf ) | ||||
| 		return false; | ||||
|  | ||||
| 	file->ops             = memory_file_operations; | ||||
| 	file->fd              = _file_stream_fd_make( d ); | ||||
| 	file->dir             = NULL; | ||||
| 	file->last_write_time = 0; | ||||
| 	file->filename        = NULL; | ||||
| 	file->is_temp         = true; | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| 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 ) ); | ||||
| 	if ( ! d ) | ||||
| 		return false; | ||||
| 	zero_item( file ); | ||||
| 	d->magic     = GEN__FILE_STREAM_FD_MAGIC; | ||||
| 	d->allocator = allocator; | ||||
| 	d->flags     = flags; | ||||
| 	if ( d->flags & EFileStream_CLONE_WRITABLE ) | ||||
| 	{ | ||||
| 		Array(u8) arr = array_init_reserve(u8, allocator, size ); | ||||
| 		d->buf = arr; | ||||
|  | ||||
| 		if ( ! d->buf ) | ||||
| 			return false; | ||||
|  | ||||
| 		mem_copy( d->buf, buffer, size ); | ||||
| 		d->cap = size; | ||||
|  | ||||
| 		array_get_header(arr)->Num = size; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		d->buf = buffer; | ||||
| 		d->cap = size; | ||||
| 	} | ||||
| 	file->ops             = memory_file_operations; | ||||
| 	file->fd              = _file_stream_fd_make( d ); | ||||
| 	file->dir             = NULL; | ||||
| 	file->last_write_time = 0; | ||||
| 	file->filename        = NULL; | ||||
| 	file->is_temp         = true; | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| u8* file_stream_buf( FileInfo* file, ssize* size ) | ||||
| { | ||||
| 	GEN_ASSERT_NOT_NULL( file ); | ||||
| 	_memory_fd* d = _file_stream_from_fd( file->fd ); | ||||
| 	if ( size ) | ||||
| 		*size = d->cap; | ||||
| 	return d->buf; | ||||
| } | ||||
|  | ||||
| internal | ||||
| GEN_FILE_SEEK_PROC( _memory_file_seek ) | ||||
| { | ||||
| 	_memory_fd* d      = _file_stream_from_fd( fd ); | ||||
| 	ssize          buflen = d->cap; | ||||
|  | ||||
| 	if ( whence == ESeekWhence_BEGIN ) | ||||
| 		d->cursor = 0; | ||||
| 	else if ( whence == ESeekWhence_END ) | ||||
| 		d->cursor = buflen; | ||||
|  | ||||
| 	d->cursor = max( 0, clamp( d->cursor + offset, 0, buflen ) ); | ||||
| 	if ( new_offset ) | ||||
| 		*new_offset = d->cursor; | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| internal | ||||
| GEN_FILE_READ_AT_PROC( _memory_file_read ) | ||||
| { | ||||
| 	// unused( stop_at_newline ); | ||||
| 	_memory_fd* d = _file_stream_from_fd( fd ); | ||||
| 	mem_copy( buffer, d->buf + offset, size ); | ||||
| 	if ( bytes_read ) | ||||
| 		*bytes_read = size; | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| 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; | ||||
|  | ||||
| 	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 ( array_get_header(arr)->Capacity < scast(usize, new_cap) ) | ||||
| 		{ | ||||
| 			if ( ! array_grow( & arr, ( s64 )( new_cap ) ) ) | ||||
| 				return false; | ||||
| 			d->buf = arr; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	mem_copy( d->buf + offset, buffer, rwlen ); | ||||
|  | ||||
| 	if ( ( d->flags & EFileStream_CLONE_WRITABLE ) && extralen > 0 ) | ||||
| 	{ | ||||
| 		Array(u8) arr = { d->buf }; | ||||
|  | ||||
| 		mem_copy( d->buf + offset + rwlen, pointer_add_const( buffer, rwlen ), extralen ); | ||||
| 		d->cap = new_cap; | ||||
| 		array_get_header(arr)->Capacity = new_cap; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		extralen = 0; | ||||
| 	} | ||||
|  | ||||
| 	if ( bytes_written ) | ||||
| 		*bytes_written = ( rwlen + extralen ); | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| internal | ||||
| GEN_FILE_CLOSE_PROC( _memory_file_close ) | ||||
| { | ||||
| 	_memory_fd*   d         = _file_stream_from_fd( fd ); | ||||
| 	AllocatorInfo allocator = d->allocator; | ||||
|  | ||||
| 	if ( d->flags & EFileStream_CLONE_WRITABLE ) | ||||
| 	{ | ||||
| 		Array(u8) arr = { d->buf }; | ||||
| 		array_free(arr); | ||||
| 	} | ||||
|  | ||||
| 	allocator_free( allocator, d ); | ||||
| } | ||||
|  | ||||
| FileOperations const memory_file_operations = { _memory_file_read, _memory_file_write, _memory_file_seek, _memory_file_close }; | ||||
|  | ||||
| #pragma endregion File Handling | ||||
							
								
								
									
										386
									
								
								base/dependencies/filesystem.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										386
									
								
								base/dependencies/filesystem.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,386 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	pragma once | ||||
| #	include "strings.hpp" | ||||
| #endif | ||||
|  | ||||
| #pragma region File Handling | ||||
|  | ||||
| enum FileModeFlag | ||||
| { | ||||
| 	EFileMode_READ   = bit( 0 ), | ||||
| 	EFileMode_WRITE  = bit( 1 ), | ||||
| 	EFileMode_APPEND = bit( 2 ), | ||||
| 	EFileMode_RW     = bit( 3 ), | ||||
| 	GEN_FILE_MODES   = EFileMode_READ | EFileMode_WRITE | EFileMode_APPEND | EFileMode_RW, | ||||
| }; | ||||
|  | ||||
| // NOTE: Only used internally and for the file operations | ||||
| enum SeekWhenceType | ||||
| { | ||||
| 	ESeekWhence_BEGIN   = 0, | ||||
| 	ESeekWhence_CURRENT = 1, | ||||
| 	ESeekWhence_END     = 2, | ||||
| }; | ||||
|  | ||||
| enum FileError | ||||
| { | ||||
| 	EFileError_NONE, | ||||
| 	EFileError_INVALID, | ||||
| 	EFileError_INVALID_FILENAME, | ||||
| 	EFileError_EXISTS, | ||||
| 	EFileError_NOT_EXISTS, | ||||
| 	EFileError_PERMISSION, | ||||
| 	EFileError_TRUNCATION_FAILURE, | ||||
| 	EFileError_NOT_EMPTY, | ||||
| 	EFileError_NAME_TOO_LONG, | ||||
| 	EFileError_UNKNOWN, | ||||
| }; | ||||
|  | ||||
| union FileDescriptor | ||||
| { | ||||
| 	void* p; | ||||
| 	sptr  i; | ||||
| 	uptr  u; | ||||
| }; | ||||
|  | ||||
| typedef u32                   FileMode; | ||||
| typedef struct FileOperations 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, 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 ) | ||||
|  | ||||
| typedef GEN_FILE_OPEN_PROC( file_open_proc ); | ||||
| typedef GEN_FILE_READ_AT_PROC( FileReadProc ); | ||||
| typedef GEN_FILE_WRITE_AT_PROC( FileWriteProc ); | ||||
| typedef GEN_FILE_SEEK_PROC( FileSeekProc ); | ||||
| typedef GEN_FILE_CLOSE_PROC( FileCloseProc ); | ||||
|  | ||||
| struct FileOperations | ||||
| { | ||||
| 	FileReadProc*  read_at; | ||||
| 	FileWriteProc* write_at; | ||||
| 	FileSeekProc*  seek; | ||||
| 	FileCloseProc* close; | ||||
| }; | ||||
|  | ||||
| extern FileOperations const default_file_operations; | ||||
|  | ||||
| typedef u64 FileTime; | ||||
|  | ||||
| enum DirType | ||||
| { | ||||
| 	GEN_DIR_TYPE_FILE, | ||||
| 	GEN_DIR_TYPE_FOLDER, | ||||
| 	GEN_DIR_TYPE_UNKNOWN, | ||||
| }; | ||||
|  | ||||
| struct DirInfo; | ||||
|  | ||||
| struct DirEntry | ||||
| { | ||||
| 	char const* filename; | ||||
| 	DirInfo*    dir_info; | ||||
| 	u8          type; | ||||
| }; | ||||
|  | ||||
| struct DirInfo | ||||
| { | ||||
| 	char const* fullpath; | ||||
| 	DirEntry*   entries;    // zpl_array | ||||
|  | ||||
| 	// Internals | ||||
| 	char** filenames;    // zpl_array | ||||
| 	String buf; | ||||
| }; | ||||
|  | ||||
| struct FileInfo | ||||
| { | ||||
| 	FileOperations ops; | ||||
| 	FileDescriptor fd; | ||||
| 	b32            is_temp; | ||||
|  | ||||
| 	char const* filename; | ||||
| 	FileTime    last_write_time; | ||||
| 	DirEntry*   dir; | ||||
| }; | ||||
|  | ||||
| enum FileStandardType | ||||
| { | ||||
| 	EFileStandard_INPUT, | ||||
| 	EFileStandard_OUTPUT, | ||||
| 	EFileStandard_ERROR, | ||||
|  | ||||
| 	EFileStandard_COUNT, | ||||
| }; | ||||
|  | ||||
| /** | ||||
| 	* Get standard file I/O. | ||||
| 	* @param  std Check zpl_file_standard_type | ||||
| 	* @return     File handle to standard I/O | ||||
| 	*/ | ||||
| FileInfo* file_get_standard( FileStandardType std ); | ||||
|  | ||||
| /** | ||||
| 	* Closes the file | ||||
| 	* @param  file | ||||
| 	*/ | ||||
| FileError file_close( FileInfo* file ); | ||||
|  | ||||
| /** | ||||
| 	* Returns the currently opened file's name | ||||
| 	* @param  file | ||||
| 	*/ | ||||
| inline | ||||
| 	char const* file_name( FileInfo* file ) | ||||
| { | ||||
| 	return file->filename ? file->filename : ""; | ||||
| } | ||||
|  | ||||
| /** | ||||
| 	* Opens a file | ||||
| 	* @param  file | ||||
| 	* @param  filename | ||||
| 	*/ | ||||
| FileError file_open( FileInfo* file, char const* filename ); | ||||
|  | ||||
| /** | ||||
| 	* Opens a file using a specified mode | ||||
| 	* @param  file | ||||
| 	* @param  mode     Access mode to use | ||||
| 	* @param  filename | ||||
| 	*/ | ||||
| FileError file_open_mode( FileInfo* file, FileMode mode, char const* filename ); | ||||
|  | ||||
| /** | ||||
| 	* Reads from a file | ||||
| 	* @param  file | ||||
| 	* @param  buffer Buffer to read to | ||||
| 	* @param  size   Size to read | ||||
| 	*/ | ||||
| b32 file_read( FileInfo* file, void* buffer, ssize size ); | ||||
|  | ||||
| /** | ||||
| 	* Reads file at a specific offset | ||||
| 	* @param  file | ||||
| 	* @param  buffer     Buffer to read to | ||||
| 	* @param  size       Size to read | ||||
| 	* @param  offset     Offset to read from | ||||
| 	* @param  bytes_read How much data we've actually read | ||||
| 	*/ | ||||
| b32 file_read_at( FileInfo* file, void* buffer, ssize size, s64 offset ); | ||||
|  | ||||
| /** | ||||
| 	* Reads file safely | ||||
| 	* @param  file | ||||
| 	* @param  buffer     Buffer to read to | ||||
| 	* @param  size       Size to read | ||||
| 	* @param  offset     Offset to read from | ||||
| 	* @param  bytes_read How much data we've actually read | ||||
| 	*/ | ||||
| b32 file_read_at_check( FileInfo* file, void* buffer, ssize size, s64 offset, ssize* bytes_read ); | ||||
|  | ||||
| typedef struct FileContents FileContents; | ||||
| struct FileContents | ||||
| { | ||||
| 	AllocatorInfo allocator; | ||||
| 	void*         data; | ||||
| 	ssize            size; | ||||
| }; | ||||
|  | ||||
| constexpr b32 file_zero_terminate    = true; | ||||
| constexpr b32 file_no_zero_terminate = false; | ||||
|  | ||||
| /** | ||||
| 	* Reads the whole file contents | ||||
| 	* @param  a              Allocator to use | ||||
| 	* @param  zero_terminate End the read data with null terminator | ||||
| 	* @param  filepath       Path to the file | ||||
| 	* @return                File contents data | ||||
| 	*/ | ||||
| FileContents file_read_contents( AllocatorInfo a, b32 zero_terminate, char const* filepath ); | ||||
|  | ||||
| /** | ||||
| 	* Returns a size of the file | ||||
| 	* @param  file | ||||
| 	* @return      File size | ||||
| 	*/ | ||||
| s64 file_size( FileInfo* file ); | ||||
|  | ||||
| /** | ||||
| 	* Seeks the file cursor from the beginning of file to a specific position | ||||
| 	* @param  file | ||||
| 	* @param  offset Offset to seek to | ||||
| 	*/ | ||||
| s64 file_seek( FileInfo* file, s64 offset ); | ||||
|  | ||||
| /** | ||||
| 	* Seeks the file cursor to the end of the file | ||||
| 	* @param  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 | ||||
| 	*/ | ||||
| s64 file_tell( FileInfo* file ); | ||||
|  | ||||
| /** | ||||
| 	* Writes to a file | ||||
| 	* @param  file | ||||
| 	* @param  buffer Buffer to read from | ||||
| 	* @param  size   Size to read | ||||
| 	*/ | ||||
| b32 file_write( FileInfo* file, void const* buffer, ssize size ); | ||||
|  | ||||
| /** | ||||
| 	* Writes to file at a specific offset | ||||
| 	* @param  file | ||||
| 	* @param  buffer        Buffer to read from | ||||
| 	* @param  size          Size to write | ||||
| 	* @param  offset        Offset to write to | ||||
| 	* @param  bytes_written How much data we've actually written | ||||
| 	*/ | ||||
| b32 file_write_at( FileInfo* file, void const* buffer, ssize size, s64 offset ); | ||||
|  | ||||
| /** | ||||
| 	* Writes to file safely | ||||
| 	* @param  file | ||||
| 	* @param  buffer        Buffer to read from | ||||
| 	* @param  size          Size to write | ||||
| 	* @param  offset        Offset to write to | ||||
| 	* @param  bytes_written How much data we've actually written | ||||
| 	*/ | ||||
| b32 file_write_at_check( FileInfo* file, void const* buffer, ssize size, s64 offset, ssize* bytes_written ); | ||||
|  | ||||
| enum FileStreamFlags : u32 | ||||
| { | ||||
| 	/* Allows us to write to the buffer directly. Beware: you can not append a new data! */ | ||||
| 	EFileStream_WRITABLE = bit( 0 ), | ||||
|  | ||||
| 	/* 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, | ||||
| }; | ||||
|  | ||||
| /** | ||||
| 	* Opens a new memory stream | ||||
| 	* @param file | ||||
| 	* @param allocator | ||||
| 	*/ | ||||
| b8 file_stream_new( FileInfo* file, AllocatorInfo allocator ); | ||||
|  | ||||
| /** | ||||
| 	* Opens a memory stream over an existing buffer | ||||
| 	* @param  file | ||||
| 	* @param  allocator | ||||
| 	* @param  buffer   Memory to create stream from | ||||
| 	* @param  size     Buffer's size | ||||
| 	* @param  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, 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 ); | ||||
| } | ||||
|  | ||||
| #pragma endregion File Handling | ||||
							
								
								
									
										90
									
								
								base/dependencies/hashing.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								base/dependencies/hashing.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,90 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	pragma once | ||||
| #	include "memory.cpp" | ||||
| #endif | ||||
|  | ||||
| #pragma region Hashing | ||||
|  | ||||
| global u32 const _crc32_table[ 256 ] = { | ||||
| 	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, | ||||
| 	0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, | ||||
| 	0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, | ||||
| 	0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, | ||||
| 	0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, | ||||
| 	0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, | ||||
| 	0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, | ||||
| 	0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, | ||||
| 	0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, | ||||
| 	0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, | ||||
| 	0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, | ||||
| 	0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, | ||||
| 	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, | ||||
| 	0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, | ||||
| 	0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, | ||||
| 	0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, | ||||
| 	0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, | ||||
| 	0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, | ||||
| 	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, | ||||
| }; | ||||
|  | ||||
| u32 crc32( void const* data, ssize len ) | ||||
| { | ||||
| 	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; | ||||
| } | ||||
|  | ||||
| global u64 const _crc64_table[ 256 ] = { | ||||
| 	0x0000000000000000ull, 0x7ad870c830358979ull, 0xf5b0e190606b12f2ull, 0x8f689158505e9b8bull, 0xc038e5739841b68full, 0xbae095bba8743ff6ull, 0x358804e3f82aa47dull, | ||||
| 	0x4f50742bc81f2d04ull, 0xab28ecb46814fe75ull, 0xd1f09c7c5821770cull, 0x5e980d24087fec87ull, 0x24407dec384a65feull, 0x6b1009c7f05548faull, 0x11c8790fc060c183ull, | ||||
| 	0x9ea0e857903e5a08ull, 0xe478989fa00bd371ull, 0x7d08ff3b88be6f81ull, 0x07d08ff3b88be6f8ull, 0x88b81eabe8d57d73ull, 0xf2606e63d8e0f40aull, 0xbd301a4810ffd90eull, | ||||
| 	0xc7e86a8020ca5077ull, 0x4880fbd87094cbfcull, 0x32588b1040a14285ull, 0xd620138fe0aa91f4ull, 0xacf86347d09f188dull, 0x2390f21f80c18306ull, 0x594882d7b0f40a7full, | ||||
| 	0x1618f6fc78eb277bull, 0x6cc0863448deae02ull, 0xe3a8176c18803589ull, 0x997067a428b5bcf0ull, 0xfa11fe77117cdf02ull, 0x80c98ebf2149567bull, 0x0fa11fe77117cdf0ull, | ||||
| 	0x75796f2f41224489ull, 0x3a291b04893d698dull, 0x40f16bccb908e0f4ull, 0xcf99fa94e9567b7full, 0xb5418a5cd963f206ull, 0x513912c379682177ull, 0x2be1620b495da80eull, | ||||
| 	0xa489f35319033385ull, 0xde51839b2936bafcull, 0x9101f7b0e12997f8ull, 0xebd98778d11c1e81ull, 0x64b116208142850aull, 0x1e6966e8b1770c73ull, 0x8719014c99c2b083ull, | ||||
| 	0xfdc17184a9f739faull, 0x72a9e0dcf9a9a271ull, 0x08719014c99c2b08ull, 0x4721e43f0183060cull, 0x3df994f731b68f75ull, 0xb29105af61e814feull, 0xc849756751dd9d87ull, | ||||
| 	0x2c31edf8f1d64ef6ull, 0x56e99d30c1e3c78full, 0xd9810c6891bd5c04ull, 0xa3597ca0a188d57dull, 0xec09088b6997f879ull, 0x96d1784359a27100ull, 0x19b9e91b09fcea8bull, | ||||
| 	0x636199d339c963f2ull, 0xdf7adabd7a6e2d6full, 0xa5a2aa754a5ba416ull, 0x2aca3b2d1a053f9dull, 0x50124be52a30b6e4ull, 0x1f423fcee22f9be0ull, 0x659a4f06d21a1299ull, | ||||
| 	0xeaf2de5e82448912ull, 0x902aae96b271006bull, 0x74523609127ad31aull, 0x0e8a46c1224f5a63ull, 0x81e2d7997211c1e8ull, 0xfb3aa75142244891ull, 0xb46ad37a8a3b6595ull, | ||||
| 	0xceb2a3b2ba0eececull, 0x41da32eaea507767ull, 0x3b024222da65fe1eull, 0xa2722586f2d042eeull, 0xd8aa554ec2e5cb97ull, 0x57c2c41692bb501cull, 0x2d1ab4dea28ed965ull, | ||||
| 	0x624ac0f56a91f461ull, 0x1892b03d5aa47d18ull, 0x97fa21650afae693ull, 0xed2251ad3acf6feaull, 0x095ac9329ac4bc9bull, 0x7382b9faaaf135e2ull, 0xfcea28a2faafae69ull, | ||||
| 	0x8632586aca9a2710ull, 0xc9622c4102850a14ull, 0xb3ba5c8932b0836dull, 0x3cd2cdd162ee18e6ull, 0x460abd1952db919full, 0x256b24ca6b12f26dull, 0x5fb354025b277b14ull, | ||||
| 	0xd0dbc55a0b79e09full, 0xaa03b5923b4c69e6ull, 0xe553c1b9f35344e2ull, 0x9f8bb171c366cd9bull, 0x10e3202993385610ull, 0x6a3b50e1a30ddf69ull, 0x8e43c87e03060c18ull, | ||||
| 	0xf49bb8b633338561ull, 0x7bf329ee636d1eeaull, 0x012b592653589793ull, 0x4e7b2d0d9b47ba97ull, 0x34a35dc5ab7233eeull, 0xbbcbcc9dfb2ca865ull, 0xc113bc55cb19211cull, | ||||
| 	0x5863dbf1e3ac9decull, 0x22bbab39d3991495ull, 0xadd33a6183c78f1eull, 0xd70b4aa9b3f20667ull, 0x985b3e827bed2b63ull, 0xe2834e4a4bd8a21aull, 0x6debdf121b863991ull, | ||||
| 	0x1733afda2bb3b0e8ull, 0xf34b37458bb86399ull, 0x8993478dbb8deae0ull, 0x06fbd6d5ebd3716bull, 0x7c23a61ddbe6f812ull, 0x3373d23613f9d516ull, 0x49aba2fe23cc5c6full, | ||||
| 	0xc6c333a67392c7e4ull, 0xbc1b436e43a74e9dull, 0x95ac9329ac4bc9b5ull, 0xef74e3e19c7e40ccull, 0x601c72b9cc20db47ull, 0x1ac40271fc15523eull, 0x5594765a340a7f3aull, | ||||
| 	0x2f4c0692043ff643ull, 0xa02497ca54616dc8ull, 0xdafce7026454e4b1ull, 0x3e847f9dc45f37c0ull, 0x445c0f55f46abeb9ull, 0xcb349e0da4342532ull, 0xb1eceec59401ac4bull, | ||||
| 	0xfebc9aee5c1e814full, 0x8464ea266c2b0836ull, 0x0b0c7b7e3c7593bdull, 0x71d40bb60c401ac4ull, 0xe8a46c1224f5a634ull, 0x927c1cda14c02f4dull, 0x1d148d82449eb4c6ull, | ||||
| 	0x67ccfd4a74ab3dbfull, 0x289c8961bcb410bbull, 0x5244f9a98c8199c2ull, 0xdd2c68f1dcdf0249ull, 0xa7f41839ecea8b30ull, 0x438c80a64ce15841ull, 0x3954f06e7cd4d138ull, | ||||
| 	0xb63c61362c8a4ab3ull, 0xcce411fe1cbfc3caull, 0x83b465d5d4a0eeceull, 0xf96c151de49567b7ull, 0x76048445b4cbfc3cull, 0x0cdcf48d84fe7545ull, 0x6fbd6d5ebd3716b7ull, | ||||
| 	0x15651d968d029fceull, 0x9a0d8ccedd5c0445ull, 0xe0d5fc06ed698d3cull, 0xaf85882d2576a038ull, 0xd55df8e515432941ull, 0x5a3569bd451db2caull, 0x20ed197575283bb3ull, | ||||
| 	0xc49581ead523e8c2ull, 0xbe4df122e51661bbull, 0x3125607ab548fa30ull, 0x4bfd10b2857d7349ull, 0x04ad64994d625e4dull, 0x7e7514517d57d734ull, 0xf11d85092d094cbfull, | ||||
| 	0x8bc5f5c11d3cc5c6ull, 0x12b5926535897936ull, 0x686de2ad05bcf04full, 0xe70573f555e26bc4ull, 0x9ddd033d65d7e2bdull, 0xd28d7716adc8cfb9ull, 0xa85507de9dfd46c0ull, | ||||
| 	0x273d9686cda3dd4bull, 0x5de5e64efd965432ull, 0xb99d7ed15d9d8743ull, 0xc3450e196da80e3aull, 0x4c2d9f413df695b1ull, 0x36f5ef890dc31cc8ull, 0x79a59ba2c5dc31ccull, | ||||
| 	0x037deb6af5e9b8b5ull, 0x8c157a32a5b7233eull, 0xf6cd0afa9582aa47ull, 0x4ad64994d625e4daull, 0x300e395ce6106da3ull, 0xbf66a804b64ef628ull, 0xc5bed8cc867b7f51ull, | ||||
| 	0x8aeeace74e645255ull, 0xf036dc2f7e51db2cull, 0x7f5e4d772e0f40a7ull, 0x05863dbf1e3ac9deull, 0xe1fea520be311aafull, 0x9b26d5e88e0493d6ull, 0x144e44b0de5a085dull, | ||||
| 	0x6e963478ee6f8124ull, 0x21c640532670ac20ull, 0x5b1e309b16452559ull, 0xd476a1c3461bbed2ull, 0xaeaed10b762e37abull, 0x37deb6af5e9b8b5bull, 0x4d06c6676eae0222ull, | ||||
| 	0xc26e573f3ef099a9ull, 0xb8b627f70ec510d0ull, 0xf7e653dcc6da3dd4ull, 0x8d3e2314f6efb4adull, 0x0256b24ca6b12f26ull, 0x788ec2849684a65full, 0x9cf65a1b368f752eull, | ||||
| 	0xe62e2ad306bafc57ull, 0x6946bb8b56e467dcull, 0x139ecb4366d1eea5ull, 0x5ccebf68aecec3a1ull, 0x2616cfa09efb4ad8ull, 0xa97e5ef8cea5d153ull, 0xd3a62e30fe90582aull, | ||||
| 	0xb0c7b7e3c7593bd8ull, 0xca1fc72bf76cb2a1ull, 0x45775673a732292aull, 0x3faf26bb9707a053ull, 0x70ff52905f188d57ull, 0x0a2722586f2d042eull, 0x854fb3003f739fa5ull, | ||||
| 	0xff97c3c80f4616dcull, 0x1bef5b57af4dc5adull, 0x61372b9f9f784cd4ull, 0xee5fbac7cf26d75full, 0x9487ca0fff135e26ull, 0xdbd7be24370c7322ull, 0xa10fceec0739fa5bull, | ||||
| 	0x2e675fb4576761d0ull, 0x54bf2f7c6752e8a9ull, 0xcdcf48d84fe75459ull, 0xb71738107fd2dd20ull, 0x387fa9482f8c46abull, 0x42a7d9801fb9cfd2ull, 0x0df7adabd7a6e2d6ull, | ||||
| 	0x772fdd63e7936bafull, 0xf8474c3bb7cdf024ull, 0x829f3cf387f8795dull, 0x66e7a46c27f3aa2cull, 0x1c3fd4a417c62355ull, 0x935745fc4798b8deull, 0xe98f353477ad31a7ull, | ||||
| 	0xa6df411fbfb21ca3ull, 0xdc0731d78f8795daull, 0x536fa08fdfd90e51ull, 0x29b7d047efec8728ull, | ||||
| }; | ||||
|  | ||||
| u64 crc64( void const* data, ssize len ) | ||||
| { | ||||
| 	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; | ||||
| } | ||||
|  | ||||
| #pragma endregion Hashing | ||||
							
								
								
									
										11
									
								
								base/dependencies/hashing.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								base/dependencies/hashing.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #pragma once | ||||
| #include "containers.hpp" | ||||
| #endif | ||||
|  | ||||
| #pragma region Hashing | ||||
|  | ||||
| u32 crc32( void const* data, ssize len ); | ||||
| u64 crc64( void const* data, ssize len ); | ||||
|  | ||||
| #pragma endregion Hashing | ||||
							
								
								
									
										403
									
								
								base/dependencies/macros.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										403
									
								
								base/dependencies/macros.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,403 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #   pragma once | ||||
| #endif | ||||
|  | ||||
| #pragma region Macros | ||||
|  | ||||
| #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 | ||||
| #endif | ||||
|  | ||||
| #ifndef bit | ||||
| #define bit( Value )                             ( 1 << Value ) | ||||
| #define bitfield_is_equal( Type, Field, Mask ) ( (scast(Type, Mask) & scast(Type, Field)) == scast(Type, Mask) ) | ||||
| #endif | ||||
|  | ||||
| // Mainly intended for forcing the base library to utilize only C-valid constructs or type coercion | ||||
| #ifndef GEN_C_LIKE_CPP | ||||
| #define GEN_C_LIKE_CPP 0 | ||||
| #endif | ||||
|  | ||||
| #if GEN_COMPILER_CPP | ||||
| #	ifndef cast | ||||
| #	define cast( type, value ) (tmpl_cast<type>( value )) | ||||
| #	endif | ||||
| #else | ||||
| #	ifndef cast | ||||
| #	define cast( type, value )  ( (type)(value) ) | ||||
| #	endif | ||||
| #endif | ||||
|  | ||||
| #if GEN_COMPILER_CPP | ||||
| #	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 ccast | ||||
| #	define ccast( type, value ) ( (type)(value) ) | ||||
| #	endif | ||||
| #	ifndef pcast | ||||
| #	define pcast( type, value ) ( * (type*)(& value) ) | ||||
| #	endif | ||||
| #	ifndef rcast | ||||
| #	define rcast( type, value ) ( (type)(value) ) | ||||
| #	endif | ||||
| #	ifndef scast | ||||
| #	define scast( type, value ) ( (type)(value) ) | ||||
| #	endif | ||||
| #endif | ||||
|  | ||||
| #ifndef stringize | ||||
| #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) | ||||
|  | ||||
| #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,  \ | ||||
| 		_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 | ||||
|  | ||||
| // ## deletes preceding comma if _VA_ARGS__ is empty (GCC, Clang) | ||||
| #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, \ | ||||
| 		 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, \ | ||||
| 		 0                                       \ | ||||
| 	) | ||||
| #endif | ||||
|  | ||||
| #ifndef clamp | ||||
| #define clamp( x, lower, upper )      min( max( ( x ), ( lower ) ), ( upper ) ) | ||||
| #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 ) ) ) | ||||
| #endif | ||||
| #ifndef size_of | ||||
| #define size_of( x )                  ( ssize )( sizeof( x ) ) | ||||
| #endif | ||||
|  | ||||
| #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 | ||||
|  | ||||
| #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_C | ||||
| #ifndef static_assert | ||||
| #undef  static_assert | ||||
|     #if GEN_COMPILER_C && __STDC_VERSION__ >= 201112L | ||||
|         #define static_assert(condition, message) _Static_assert(condition, message) | ||||
|     #else | ||||
|         #define static_assert(condition, message) typedef char static_assertion_##__LINE__[(condition)?1:-1] | ||||
| 	#endif | ||||
| #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(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 | ||||
| #		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 | ||||
|  | ||||
| #if 0 | ||||
| #ifndef GEN_OPTIMIZE_MAPPINGS_BEGIN | ||||
| #	define GEN_OPTIMIZE_MAPPINGS_BEGIN _pragma(optimize("gt", on)) | ||||
| #	define GEN_OPITMIZE_MAPPINGS_END   _pragma(optimize("", on)) | ||||
| #endif | ||||
| #else | ||||
| #	define GEN_OPTIMIZE_MAPPINGS_BEGIN | ||||
| #	define GEN_OPITMIZE_MAPPINGS_END | ||||
| #endif | ||||
|  | ||||
| #if GEN_COMPILER_C | ||||
| //   ____                       _        ______                _   _                ____                  _                 __ _ | ||||
| //  / ___}                     (_)      |  ____}              | | (_)              / __ \                | |               | |(_) | ||||
| // | | ___  ___ _ __   ___ _ __ _  ___  | |__ _   _ _ __   ___| |_ _  ___  _ __   | |  | |_   _____ _ __ | | ___   __ _  __| | _ _ __   __ _ | ||||
| // | |{__ |/ _ \ '_ \ / _ \ '__} |/ __| |  __} | | | '_ \ / __} __} |/ _ \| '_ \  | |  | \ \ / / _ \ '_ \| |/ _ \ / _` |/ _` || | '_ \ / _` | | ||||
| // | |__j |  __/ | | |  __/ |  | | (__  | |  | |_| | | | | (__| l_| | (_) | | | | | l__| |\ V /  __/ | | | | (_) | (_| | (_| || | | | | (_| | | ||||
| //  \____/ \___}_l l_l\___}_l  l_l\___| l_l   \__,_l_l l_l\___}\__}_l\___/l_l l_l  \____/  \_/ \___}_l l_l_l\___/ \__,_l\__,_l|_|_| |_|\__, | | ||||
| // 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 unobfuscated as possible. | ||||
|  | ||||
| #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.. | ||||
|  | ||||
| #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_GENERIC_SEL_ENTRY_COMMA_DELIMITER( slot_exp, GEN_GENERIC_SEL_ENTRY_TYPE( slot_exp, ): GEN_GENERIC_SEL_ENTRY_FUNCTION( slot_exp, ) GEN_COMMA_OPERATOR, , ) | ||||
| //                                                          ^ Selects the comma                              ^ is the type                             ^ is the function                             ^ Insert a comma | ||||
| // The slot won't exist if that comma is not found.                                                                                                                                                  | | ||||
|  | ||||
| // For the occastion where an expression didn't resolve to a selection option the "default: <value>" wilbe set to: | ||||
| typedef struct GENCPP_NO_RESOLVED_GENERIC_SELECTION GENCPP_NO_RESOLVED_GENERIC_SELECTION; | ||||
| struct GENCPP_NO_RESOLVED_GENERIC_SELECTION { | ||||
| 	void* _THE_VOID_SLOT_; | ||||
| }; | ||||
| GENCPP_NO_RESOLVED_GENERIC_SELECTION const gen_generic_selection_fail = {0}; | ||||
| // Which will provide the message:  error: called object type 'struct NO_RESOLVED_GENERIC_SELECTION' is not a function or function pointer | ||||
| // ---------------------------------------------------------------------------------------------------------------------------------- | ||||
|  | ||||
| // Below are generated on demand for an overlaod depdendent on a type: | ||||
| // -----------------------------------------------------------------------------------------------------#define GEN_FUNCTION_GENERIC_EXAMPLE( selector_arg ) _Generic(       k | ||||
| #define GEN_FUNCTION_GENERIC_EXAMPLE( selector_arg ) _Generic(       \ | ||||
| (selector_arg), /* 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 ) \ | ||||
| 	default: gen_generic_selection_fail                              \ | ||||
| ) GEN_RESOLVED_FUNCTION_CALL( selector_arg ) | ||||
| // ---------------------------------------------------------------------------------------------------------------------------------- | ||||
|  | ||||
| // 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: | ||||
|  | ||||
| // To add support for long: | ||||
| #define GEN_EXAMPLE_HASH__ARGS_SIG_1 GEN_GENERIC_FUNCTION_ARG_SIGNATURE( hash__P_long, long long ) | ||||
| size_t gen_example_hash__P_long( long val ) { return val * 2654435761ull; } | ||||
|  | ||||
| // To add support for long long: | ||||
| #define GEN_EXAMPLE_HASH__ARGS_SIG_2 GEN_GENERIC_FUNCTION_ARG_SIGNATURE( hash__P_long_long, long long ) | ||||
| size_t gen_example_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 gen_hash_example( 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( HASH__ARGS_SIG_8 ) \ | ||||
| 	default: gen_generic_selection_fail                        \ | ||||
| ) GEN_RESOLVED_FUNCTION_CALL( function_arguments ) | ||||
|  | ||||
| // Additional Variations: | ||||
|  | ||||
| // If the function takes more than one argument the following is used: | ||||
| #define GEN_FUNCTION_GENERIC_EXAMPLE_VARADIC( selector_arg, ... ) _Generic( \ | ||||
| (selector_arg),                                                             \ | ||||
| 	GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( FunctionID__ARGS_SIG_1 )        \ | ||||
| 	GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( FunctionID__ARGS_SIG_2 )        \ | ||||
| 	/* ... */                                                               \ | ||||
| 	GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT(FunctionID__ARGS_SIG_N )         \ | ||||
| 	default: gen_generic_selection_fail                                     \ | ||||
| ) GEN_RESOLVED_FUNCTION_CALL( selector_arg, __VA_ARG__ ) | ||||
|  | ||||
| // If the function does not take the arugment as a parameter: | ||||
| #define GEN_FUNCTION_GENERIC_EXAMPLE_DIRECT_TYPE( selector_arg ) _Generic( \ | ||||
| ( GEN_TYPE_TO_EXP(selector_arg) ),                                         \ | ||||
| 	GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( FunctionID__ARGS_SIG_1 )       \ | ||||
| 	GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( FunctionID__ARGS_SIG_2 )       \ | ||||
| 	/* ... */                                                              \ | ||||
| 	GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT(FunctionID__ARGS_SIG_N )        \ | ||||
| 	default: gen_generic_selection_fail                                    \ | ||||
| ) GEN_RESOLVED_FUNCTION_CALL() | ||||
|  | ||||
| // Used to keep the _Generic keyword happy as bare types are not considered "expressions" | ||||
| #define GEN_TYPE_TO_EXP(type) (* (type*)NULL) | ||||
|  | ||||
| // typedef void* GEN_GenericExampleType; | ||||
| // GEN_FUNCTION_GENERIC_EXAMPLE_DIRECT_TYPE( GEN_GenericExampleType ); | ||||
|  | ||||
| // END OF ------------------------ _Generic function overloading ----------------------------------------- END OF | ||||
| #endif | ||||
|  | ||||
| #pragma endregion Macros | ||||
							
								
								
									
										522
									
								
								base/dependencies/memory.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										522
									
								
								base/dependencies/memory.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,522 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	pragma once | ||||
| #	include "printing.cpp" | ||||
| #endif | ||||
|  | ||||
| #pragma region Memory | ||||
|  | ||||
| void* mem_copy( void* dest, void const* source, ssize n ) | ||||
| { | ||||
| 	if ( dest == nullptr ) | ||||
| 	{ | ||||
| 		return nullptr; | ||||
| 	} | ||||
|  | ||||
| 	return memcpy( dest, source, n ); | ||||
| } | ||||
|  | ||||
| void const* mem_find( void const* data, u8 c, ssize n ) | ||||
| { | ||||
| 	u8 const* s = rcast( u8 const*, data); | ||||
| 	while ( ( rcast( uptr, s) & ( sizeof( usize ) - 1 ) ) && n && *s != c ) | ||||
| 	{ | ||||
| 		s++; | ||||
| 		n--; | ||||
| 	} | ||||
| 	if ( n && *s != c ) | ||||
| 	{ | ||||
| 		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( ssize ); | ||||
| 		} | ||||
| 		s = rcast( u8 const*, w); | ||||
| 		while ( n && *s != c ) | ||||
| 		{ | ||||
| 			s++; | ||||
| 			n--; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return n ? rcast( void const*, s ) : NULL; | ||||
| } | ||||
|  | ||||
| #define GEN_HEAP_STATS_MAGIC 0xDEADC0DE | ||||
|  | ||||
| typedef struct _heap_stats _heap_stats; | ||||
| struct _heap_stats | ||||
| { | ||||
| 	u32 magic; | ||||
| 	ssize  used_memory; | ||||
| 	ssize  alloc_count; | ||||
| }; | ||||
|  | ||||
| global _heap_stats _heap_stats_info; | ||||
|  | ||||
| void heap_stats_init( void ) | ||||
| { | ||||
| 	zero_item( &_heap_stats_info ); | ||||
| 	_heap_stats_info.magic = GEN_HEAP_STATS_MAGIC; | ||||
| } | ||||
|  | ||||
| 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; | ||||
| } | ||||
|  | ||||
| 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; | ||||
| } | ||||
|  | ||||
| void heap_stats_check( void ) | ||||
| { | ||||
| 	GEN_ASSERT_MSG( _heap_stats_info.magic == GEN_HEAP_STATS_MAGIC, "heap_stats is not initialised yet, call heap_stats_init first!" ); | ||||
| 	GEN_ASSERT( _heap_stats_info.used_memory == 0 ); | ||||
| 	GEN_ASSERT( _heap_stats_info.alloc_count == 0 ); | ||||
| } | ||||
|  | ||||
| typedef struct _heap_alloc_info _heap_alloc_info; | ||||
| struct _heap_alloc_info | ||||
| { | ||||
| 	ssize    size; | ||||
| 	void* physical_start; | ||||
| }; | ||||
|  | ||||
| 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 ); | ||||
| 	// unused( old_size ); | ||||
| 	if ( ! alignment ) | ||||
| 		alignment = GEN_DEFAULT_MEMORY_ALIGNMENT; | ||||
|  | ||||
| #ifdef GEN_HEAP_ANALYSIS | ||||
| 	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  = 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; | ||||
| 			} | ||||
| 			break; | ||||
| 		case EAllocation_ALLOC : | ||||
| 			{ | ||||
| 				size += track_size; | ||||
| 			} | ||||
| 			break; | ||||
| 		default : | ||||
| 			break; | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| 	switch ( type ) | ||||
| 	{ | ||||
| #if defined( GEN_COMPILER_MSVC ) || ( defined( GEN_COMPILER_GCC ) && defined( GEN_SYSTEM_WINDOWS ) ) || ( defined( GEN_COMPILER_TINYC ) && defined( GEN_SYSTEM_WINDOWS ) ) | ||||
| 		case EAllocation_ALLOC : | ||||
| 			ptr = _aligned_malloc( size, alignment ); | ||||
| 			if ( flags & ALLOCATOR_FLAG_CLEAR_TO_ZERO ) | ||||
| 				zero_size( ptr, size ); | ||||
| 			break; | ||||
| 		case EAllocation_FREE : | ||||
| 			_aligned_free( old_memory ); | ||||
| 			break; | ||||
| 		case EAllocation_RESIZE : | ||||
| 			{ | ||||
| 				AllocatorInfo a = heap(); | ||||
| 				ptr             = default_resize_align( a, old_memory, old_size, size, alignment ); | ||||
| 			} | ||||
| 			break; | ||||
|  | ||||
| #elif defined( GEN_SYSTEM_LINUX ) && ! defined( GEN_CPU_ARM ) && ! defined( GEN_COMPILER_TINYC ) | ||||
| 		case EAllocation_ALLOC : | ||||
| 			{ | ||||
| 				ptr = aligned_alloc( alignment, ( size + alignment - 1 ) & ~( alignment - 1 ) ); | ||||
|  | ||||
| 				if ( flags & GEN_ALLOCATOR_FLAG_CLEAR_TO_ZERO ) | ||||
| 				{ | ||||
| 					zero_size( ptr, size ); | ||||
| 				} | ||||
| 			} | ||||
| 			break; | ||||
|  | ||||
| 		case EAllocation_FREE : | ||||
| 			{ | ||||
| 				free( old_memory ); | ||||
| 			} | ||||
| 			break; | ||||
|  | ||||
| 		case EAllocation_RESIZE : | ||||
| 			{ | ||||
| 				AllocatorInfo a = heap(); | ||||
| 				ptr             = default_resize_align( a, old_memory, old_size, size, alignment ); | ||||
| 			} | ||||
| 			break; | ||||
| #else | ||||
| 		case EAllocation_ALLOC : | ||||
| 			{ | ||||
| 				posix_memalign( &ptr, alignment, size ); | ||||
|  | ||||
| 				if ( flags & GEN_ALLOCATOR_FLAG_CLEAR_TO_ZERO ) | ||||
| 				{ | ||||
| 					zero_size( ptr, size ); | ||||
| 				} | ||||
| 			} | ||||
| 			break; | ||||
|  | ||||
| 		case EAllocation_FREE : | ||||
| 			{ | ||||
| 				free( old_memory ); | ||||
| 			} | ||||
| 			break; | ||||
|  | ||||
| 		case EAllocation_RESIZE : | ||||
| 			{ | ||||
| 				AllocatorInfo a = heap(); | ||||
| 				ptr             = default_resize_align( a, old_memory, old_size, size, alignment ); | ||||
| 			} | ||||
| 			break; | ||||
| #endif | ||||
|  | ||||
| 		case EAllocation_FREE_ALL : | ||||
| 			break; | ||||
| 	} | ||||
|  | ||||
| #ifdef GEN_HEAP_ANALYSIS | ||||
| 	if ( type == EAllocation_ALLOC ) | ||||
| 	{ | ||||
| 		_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                           = rcast( void*, alloc_info + 1 ); | ||||
| 		_heap_stats_info.used_memory += alloc_info->size; | ||||
| 		_heap_stats_info.alloc_count++; | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| 	return ptr; | ||||
| } | ||||
|  | ||||
| #pragma region VirtualMemory | ||||
| VirtualMemory vm_from_memory( void* data, ssize size ) | ||||
| { | ||||
| 	VirtualMemory vm; | ||||
| 	vm.data = data; | ||||
| 	vm.size = size; | ||||
| 	return vm; | ||||
| } | ||||
|  | ||||
| #if defined( GEN_SYSTEM_WINDOWS ) | ||||
| VirtualMemory vm_alloc( void* addr, ssize size ) | ||||
| { | ||||
| 	VirtualMemory vm; | ||||
| 	GEN_ASSERT( size > 0 ); | ||||
| 	vm.data = VirtualAlloc( addr, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE ); | ||||
| 	vm.size = size; | ||||
| 	return vm; | ||||
| } | ||||
|  | ||||
| b32 vm_free( VirtualMemory vm ) | ||||
| { | ||||
| 	MEMORY_BASIC_INFORMATION info; | ||||
| 	while ( vm.size > 0 ) | ||||
| 	{ | ||||
| 		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 > scast( usize, vm.size) ) | ||||
| 		{ | ||||
| 			return false; | ||||
| 		} | ||||
| 		if ( VirtualFree( vm.data, 0, MEM_RELEASE ) == 0 ) | ||||
| 			return false; | ||||
| 		vm.data  = pointer_add( vm.data, info.RegionSize ); | ||||
| 		vm.size -= info.RegionSize; | ||||
| 	} | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| VirtualMemory vm_trim( VirtualMemory vm, ssize lead_size, ssize size ) | ||||
| { | ||||
| 	VirtualMemory new_vm = { 0 }; | ||||
| 	void*             ptr; | ||||
| 	GEN_ASSERT( vm.size >= lead_size + size ); | ||||
|  | ||||
| 	ptr = pointer_add( vm.data, lead_size ); | ||||
|  | ||||
| 	vm_free( vm ); | ||||
| 	new_vm = vm_alloc( ptr, size ); | ||||
| 	if ( new_vm.data == ptr ) | ||||
| 		return new_vm; | ||||
| 	if ( new_vm.data ) | ||||
| 		vm_free( new_vm ); | ||||
| 	return new_vm; | ||||
| } | ||||
|  | ||||
| b32 vm_purge( VirtualMemory vm ) | ||||
| { | ||||
| 	VirtualAlloc( vm.data, vm.size, MEM_RESET, PAGE_READWRITE ); | ||||
| 	// NOTE: Can this really fail? | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| ssize virtual_memory_page_size( ssize* alignment_out ) | ||||
| { | ||||
| 	SYSTEM_INFO info; | ||||
| 	GetSystemInfo( &info ); | ||||
| 	if ( alignment_out ) | ||||
| 		*alignment_out = info.dwAllocationGranularity; | ||||
| 	return info.dwPageSize; | ||||
| } | ||||
|  | ||||
| #else | ||||
| #	include <sys/mman.h> | ||||
|  | ||||
| #	ifndef MAP_ANONYMOUS | ||||
| #		define MAP_ANONYMOUS MAP_ANON | ||||
| #	endif | ||||
| VirtualMemory vm_alloc( void* addr, ssize size ) | ||||
| { | ||||
| 	VirtualMemory vm; | ||||
| 	GEN_ASSERT( size > 0 ); | ||||
| 	vm.data = mmap( addr, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0 ); | ||||
| 	vm.size = size; | ||||
| 	return vm; | ||||
| } | ||||
|  | ||||
| b32 vm_free( VirtualMemory vm ) | ||||
| { | ||||
| 	munmap( vm.data, vm.size ); | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| VirtualMemory vm_trim( VirtualMemory vm, ssize lead_size, ssize size ) | ||||
| { | ||||
| 	void*  ptr; | ||||
| 	ssize trail_size; | ||||
| 	GEN_ASSERT( vm.size >= lead_size + size ); | ||||
|  | ||||
| 	ptr        = pointer_add( vm.data, lead_size ); | ||||
| 	trail_size = vm.size - lead_size - size; | ||||
|  | ||||
| 	if ( lead_size != 0 ) | ||||
| 		vm_free( vm_from_memory(( vm.data, lead_size ) ); | ||||
| 	if ( trail_size != 0 ) | ||||
| 		vm_free( vm_from_memory( ptr, trail_size ) ); | ||||
| 	return vm_from_memory( ptr, size ); | ||||
| } | ||||
|  | ||||
| b32 vm_purge( VirtualMemory vm ) | ||||
| { | ||||
| 	int err = madvise( vm.data, vm.size, MADV_DONTNEED ); | ||||
| 	return err != 0; | ||||
| } | ||||
|  | ||||
| ssize virtual_memory_page_size( ssize* alignment_out ) | ||||
| { | ||||
| 	// TODO: Is this always true? | ||||
| 	ssize result = scast( ssize, sysconf( _SC_PAGE_SIZE )); | ||||
| 	if ( alignment_out ) | ||||
| 		*alignment_out = result; | ||||
| 	return result; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #pragma endregion VirtualMemory | ||||
|  | ||||
| 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; | ||||
|  | ||||
| 	// unused( old_size ); | ||||
|  | ||||
| 	switch ( type ) | ||||
| 	{ | ||||
| 		case EAllocation_ALLOC : | ||||
| 			{ | ||||
| 				void* end        = pointer_add( arena->PhysicalStart, arena->TotalUsed ); | ||||
| 				ssize total_size = align_forward_s64( size, alignment ); | ||||
|  | ||||
| 				// NOTE: Out of memory | ||||
| 				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!!)"); | ||||
| 					return nullptr; | ||||
| 				} | ||||
|  | ||||
| 				ptr              = align_forward( end, alignment ); | ||||
| 				arena->TotalUsed += total_size; | ||||
|  | ||||
| 				if ( flags & ALLOCATOR_FLAG_CLEAR_TO_ZERO ) | ||||
| 					zero_size( ptr, size ); | ||||
| 			} | ||||
| 			break; | ||||
|  | ||||
| 		case EAllocation_FREE : | ||||
| 			// NOTE: Free all at once | ||||
| 			// Use Temp_Arena_Memory if you want to free a block | ||||
| 			break; | ||||
|  | ||||
| 		case EAllocation_FREE_ALL : | ||||
| 			arena->TotalUsed = 0; | ||||
| 			break; | ||||
|  | ||||
| 		case EAllocation_RESIZE : | ||||
| 			{ | ||||
| 				// TODO : Check if ptr is on top of stack and just extend | ||||
| 				AllocatorInfo a = arena->Backing; | ||||
| 				ptr             = default_resize_align( a, old_memory, old_size, size, alignment ); | ||||
| 			} | ||||
| 			break; | ||||
| 	} | ||||
| 	return ptr; | ||||
| } | ||||
|  | ||||
| void* pool_allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ) | ||||
| { | ||||
| 	Pool* pool = rcast( Pool*, allocator_data); | ||||
| 	void* ptr  = NULL; | ||||
|  | ||||
| 	// unused( old_size ); | ||||
|  | ||||
| 	switch ( type ) | ||||
| 	{ | ||||
| 		case EAllocation_ALLOC : | ||||
| 			{ | ||||
| 				uptr next_free; | ||||
|  | ||||
| 				GEN_ASSERT( size == pool->BlockSize ); | ||||
| 				GEN_ASSERT( alignment == pool->BlockAlign ); | ||||
| 				GEN_ASSERT( pool->FreeList != NULL ); | ||||
|  | ||||
| 				next_free        = * rcast( uptr*, pool->FreeList); | ||||
| 				ptr              = pool->FreeList; | ||||
| 				pool->FreeList   = rcast( void*, next_free); | ||||
| 				pool->TotalSize += pool->BlockSize; | ||||
|  | ||||
| 				if ( flags & ALLOCATOR_FLAG_CLEAR_TO_ZERO ) | ||||
| 					zero_size( ptr, size ); | ||||
| 			} | ||||
| 			break; | ||||
|  | ||||
| 		case EAllocation_FREE : | ||||
| 			{ | ||||
| 				uptr* next; | ||||
| 				if ( old_memory == NULL ) | ||||
| 					return NULL; | ||||
|  | ||||
| 				next             = rcast( uptr*, old_memory); | ||||
| 				*next            = rcast( uptr, pool->FreeList); | ||||
| 				pool->FreeList   = old_memory; | ||||
| 				pool->TotalSize -= pool->BlockSize; | ||||
| 			} | ||||
| 			break; | ||||
|  | ||||
| 		case EAllocation_FREE_ALL : | ||||
| 			{ | ||||
| 				ssize    actual_block_size, block_index; | ||||
| 				void* curr; | ||||
| 				uptr* end; | ||||
|  | ||||
| 				actual_block_size = pool->BlockSize + pool->BlockAlign; | ||||
| 				pool->TotalSize   = 0; | ||||
|  | ||||
| 				// NOTE: Init intrusive freelist | ||||
| 				curr = pool->PhysicalStart; | ||||
| 				for ( block_index = 0; block_index < pool->NumBlocks - 1; block_index++ ) | ||||
| 				{ | ||||
| 					uptr* next = rcast( uptr*, curr); | ||||
| 					* next     = rcast( uptr, curr) + actual_block_size; | ||||
| 					curr       = pointer_add( curr, actual_block_size ); | ||||
| 				} | ||||
|  | ||||
| 				end            = rcast( uptr*, curr); | ||||
| 				* end          = scast( uptr, NULL); | ||||
| 				pool->FreeList = pool->PhysicalStart; | ||||
| 			} | ||||
| 			break; | ||||
|  | ||||
| 		case EAllocation_RESIZE : | ||||
| 			// NOTE: Cannot resize | ||||
| 			GEN_PANIC( "You cannot resize something allocated by with a pool." ); | ||||
| 			break; | ||||
| 	} | ||||
|  | ||||
| 	return ptr; | ||||
| } | ||||
|  | ||||
| Pool pool_init_align( AllocatorInfo backing, ssize num_blocks, ssize block_size, ssize block_align ) | ||||
| { | ||||
| 	Pool pool = {}; | ||||
|  | ||||
| 	ssize    actual_block_size, pool_size, block_index; | ||||
| 	void *data, *curr; | ||||
| 	uptr* end; | ||||
|  | ||||
| 	zero_item( &pool ); | ||||
|  | ||||
| 	pool.Backing     = backing; | ||||
| 	pool.BlockSize   = block_size; | ||||
| 	pool.BlockAlign  = block_align; | ||||
| 	pool.NumBlocks   = num_blocks; | ||||
|  | ||||
| 	actual_block_size = block_size + block_align; | ||||
| 	pool_size         = num_blocks * actual_block_size; | ||||
|  | ||||
| 	data = alloc_align( backing, pool_size, block_align ); | ||||
|  | ||||
| 	// NOTE: Init intrusive freelist | ||||
| 	curr = data; | ||||
| 	for ( block_index = 0; block_index < num_blocks - 1; block_index++ ) | ||||
| 	{ | ||||
| 		uptr* next = ( uptr* ) curr; | ||||
| 		*next      = ( uptr  ) curr + actual_block_size; | ||||
| 		curr       = pointer_add( curr, actual_block_size ); | ||||
| 	} | ||||
|  | ||||
| 	end  =  ( uptr* ) curr; | ||||
| 	*end =  ( uptr )  NULL; | ||||
|  | ||||
| 	pool.PhysicalStart = data; | ||||
| 	pool.FreeList      = data; | ||||
|  | ||||
| 	return pool; | ||||
| } | ||||
|  | ||||
| void pool_clear(Pool* pool) | ||||
| { | ||||
| 	ssize actual_block_size, block_index; | ||||
| 	void* curr; | ||||
| 	uptr* end; | ||||
|  | ||||
| 	actual_block_size = pool->BlockSize + pool->BlockAlign; | ||||
|  | ||||
| 	curr = pool->PhysicalStart; | ||||
| 	for ( block_index = 0; block_index < pool->NumBlocks - 1; block_index++ ) | ||||
| 	{ | ||||
| 		uptr* next = ( uptr* ) curr; | ||||
| 		*next      = ( uptr  ) curr + actual_block_size; | ||||
| 		curr       = pointer_add( curr, actual_block_size ); | ||||
| 	} | ||||
|  | ||||
| 	end  =  ( uptr* ) curr; | ||||
| 	*end =  ( uptr )  NULL; | ||||
|  | ||||
| 	pool->FreeList = pool->PhysicalStart; | ||||
| } | ||||
|  | ||||
| #pragma endregion Memory | ||||
							
								
								
									
										673
									
								
								base/dependencies/memory.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										673
									
								
								base/dependencies/memory.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,673 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	pragma once | ||||
| #	include "debug.hpp" | ||||
| #endif | ||||
|  | ||||
| #pragma region Memory | ||||
|  | ||||
| #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 ) ) | ||||
|  | ||||
| #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; | ||||
| } | ||||
|  | ||||
| //! Checks if value is power of 2. | ||||
| b32 is_power_of_two( ssize x ); | ||||
|  | ||||
| //! Aligns address to specified alignment. | ||||
| void* align_forward( void* ptr, ssize alignment ); | ||||
|  | ||||
| //! Aligns value to a specified alignment. | ||||
| s64 align_forward_by_value( s64 value, ssize alignment ); | ||||
|  | ||||
| //! Moves pointer forward by bytes. | ||||
| void* pointer_add( void* ptr, ssize bytes ); | ||||
|  | ||||
| //! Moves pointer forward by bytes. | ||||
| void const* pointer_add_const( void const* ptr, ssize bytes ); | ||||
|  | ||||
| //! Calculates difference between two addresses. | ||||
| 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, ssize size ); | ||||
|  | ||||
| //! Search for a constant value within the size limit at memory location. | ||||
| void const* mem_find( void const* data, u8 byte_value, ssize size ); | ||||
|  | ||||
| //! Copy memory from source to destination. | ||||
| void* mem_move( void* dest, void const* source, ssize size ); | ||||
|  | ||||
| //! Set constant value at memory location with specified 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. | ||||
| 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 | ||||
|  | ||||
| //! Clears up an array. | ||||
| #define zero_array( a, count ) zero_size( ( a ), size_of( *( a ) ) * count ) | ||||
|  | ||||
| enum AllocType : u8 | ||||
| { | ||||
| 	EAllocation_ALLOC, | ||||
| 	EAllocation_FREE, | ||||
| 	EAllocation_FREE_ALL, | ||||
| 	EAllocation_RESIZE, | ||||
| }; | ||||
|  | ||||
| typedef void*(AllocatorProc)( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ); | ||||
|  | ||||
| struct AllocatorInfo | ||||
| { | ||||
| 	AllocatorProc* Proc; | ||||
| 	void*          Data; | ||||
| }; | ||||
|  | ||||
| enum AllocFlag | ||||
| { | ||||
| 	ALLOCATOR_FLAG_CLEAR_TO_ZERO = bit( 0 ), | ||||
| }; | ||||
|  | ||||
| #ifndef GEN_DEFAULT_MEMORY_ALIGNMENT | ||||
| #	define GEN_DEFAULT_MEMORY_ALIGNMENT ( 2 * size_of( void* ) ) | ||||
| #endif | ||||
|  | ||||
| #ifndef GEN_DEFAULT_ALLOCATOR_FLAGS | ||||
| #	define GEN_DEFAULT_ALLOCATOR_FLAGS ( ALLOCATOR_FLAG_CLEAR_TO_ZERO ) | ||||
| #endif | ||||
|  | ||||
| //! Allocate memory with default alignment. | ||||
| void* alloc( AllocatorInfo a, ssize size ); | ||||
|  | ||||
| //! Allocate memory with specified alignment. | ||||
| void* alloc_align( AllocatorInfo a, ssize size, ssize alignment ); | ||||
|  | ||||
| //! Free allocated memory. | ||||
| void allocator_free( AllocatorInfo a, void* ptr ); | ||||
|  | ||||
| //! Free all memory allocated by an allocator. | ||||
| void free_all( AllocatorInfo a ); | ||||
|  | ||||
| //! Resize an allocated memory. | ||||
| void* resize( AllocatorInfo a, void* ptr, ssize old_size, ssize new_size ); | ||||
|  | ||||
| //! Resize an allocated memory with specified 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 ) ) | ||||
|  | ||||
| //! Allocate memory for an array of items. | ||||
| #define alloc_array( allocator_, Type, count ) ( Type* )alloc( allocator_, size_of( Type ) * ( count ) ) | ||||
|  | ||||
| /* heap memory analysis tools */ | ||||
| /* define GEN_HEAP_ANALYSIS to enable this feature */ | ||||
| /* 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 ); | ||||
| 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 | ||||
| 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, 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 ) { AllocatorInfo allocator = { heap_allocator_proc, nullptr }; return allocator; } | ||||
|  | ||||
| //! Helper to allocate memory using heap allocator. | ||||
| #define malloc( sz ) alloc( heap(), sz ) | ||||
|  | ||||
| //! Helper to free memory allocated by heap allocator. | ||||
| #define mfree( ptr ) free( heap(), ptr ) | ||||
|  | ||||
| struct VirtualMemory | ||||
| { | ||||
| 	void*  data; | ||||
| 	ssize size; | ||||
| }; | ||||
|  | ||||
| //! 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; | ||||
|  | ||||
| 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 | ||||
| { | ||||
| 	AllocatorInfo Backing; | ||||
| 	void*         PhysicalStart; | ||||
| 	ssize         TotalSize; | ||||
| 	ssize         TotalUsed; | ||||
| 	ssize         TempCount; | ||||
|  | ||||
| #if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP | ||||
| #pragma region Member Mapping | ||||
| 	forceinline operator AllocatorInfo() { return 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 arena_allocator_proc( allocator_data, type, size, alignment, old_memory, old_size, flags ); } | ||||
| 	forceinline static Arena init_from_memory( void* start, ssize size )                                                                                      { return arena_init_from_memory( start, size ); } | ||||
| 	forceinline static Arena init_from_allocator( AllocatorInfo backing, ssize size )                                                                         { return arena_init_from_allocator( backing, size ); } | ||||
| 	forceinline static Arena init_sub( Arena& parent, ssize size )                                                                                            { return arena_init_from_allocator( parent.Backing, size ); } | ||||
| 	forceinline        ssize alignment_of( ssize alignment )                                                                                                  { return arena_alignment_of(this, alignment); } | ||||
| 	forceinline        void  free()                                                                                                                           { return arena_free(this);  } | ||||
| 	forceinline        ssize size_remaining( ssize alignment )                                                                                                { return arena_size_remaining(this, alignment); } | ||||
|  | ||||
| // This id is defined by Unreal for asserts | ||||
| #pragma push_macro("check") | ||||
| #undef check | ||||
| 	forceinline void check() { arena_check(this); } | ||||
| #pragma pop_macro("check") | ||||
|  | ||||
| #pragma endregion Member Mapping | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| #if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP | ||||
| 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") | ||||
| #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 | ||||
|  | ||||
| #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); | ||||
| template<s32 Size> void             fixed_arena_free(FixedArena<Size>* fixed_arena); | ||||
|  | ||||
| #if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP | ||||
| 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_COMPILER_CPP && ! GEN_C_LIKE_CPP | ||||
| #pragma region Member Mapping | ||||
| 	forceinline operator AllocatorInfo() { return fixed_arena_allocator_info(this); } | ||||
|  | ||||
| 	forceinline static FixedArena init()                          { FixedArena result; fixed_arena_init<Size>(result); return result; } | ||||
| 	forceinline ssize             size_remaining(ssize alignment) { fixed_arena_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 FixedArena_1KB   = FixedArena< kilobytes( 1 ) >; | ||||
| using FixedArena_4KB   = FixedArena< kilobytes( 4 ) >; | ||||
| using FixedArena_8KB   = FixedArena< kilobytes( 8 ) >; | ||||
| using FixedArena_16KB  = FixedArena< kilobytes( 16 ) >; | ||||
| using FixedArena_32KB  = FixedArena< kilobytes( 32 ) >; | ||||
| using FixedArena_64KB  = FixedArena< kilobytes( 64 ) >; | ||||
| using FixedArena_128KB = FixedArena< kilobytes( 128 ) >; | ||||
| using FixedArena_256KB = FixedArena< kilobytes( 256 ) >; | ||||
| using FixedArena_512KB = FixedArena< kilobytes( 512 ) >; | ||||
| using FixedArena_1MB   = FixedArena< megabytes( 1 ) >; | ||||
| using FixedArena_2MB   = FixedArena< megabytes( 2 ) >; | ||||
| using FixedArena_4MB   = FixedArena< megabytes( 4 ) >; | ||||
| #pragma endregion FixedArena | ||||
|  | ||||
| #pragma region Pool | ||||
| struct Pool; | ||||
|  | ||||
| void* pool_allocator_proc(void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags); | ||||
|  | ||||
| Pool          pool_init(AllocatorInfo backing, ssize num_blocks, ssize block_size); | ||||
| Pool          pool_init_align(AllocatorInfo backing, ssize num_blocks, ssize block_size, ssize block_align); | ||||
| AllocatorInfo pool_allocator_info(Pool* pool); | ||||
| void          pool_clear(Pool* pool); | ||||
| void          pool_free(Pool* pool); | ||||
|  | ||||
| #if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP | ||||
| 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); } | ||||
| #endif | ||||
|  | ||||
| struct Pool | ||||
| { | ||||
| 	AllocatorInfo Backing; | ||||
| 	void*         PhysicalStart; | ||||
| 	void*         FreeList; | ||||
| 	ssize         BlockSize; | ||||
| 	ssize         BlockAlign; | ||||
| 	ssize         TotalSize; | ||||
| 	ssize         NumBlocks; | ||||
|  | ||||
| #if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP | ||||
| #pragma region Member Mapping | ||||
|     forceinline operator AllocatorInfo() { return 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 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 pool_init(backing, num_blocks, block_size); } | ||||
|     forceinline static Pool  init_align(AllocatorInfo backing, ssize num_blocks, ssize block_size, ssize block_align)                                       { return pool_init_align(backing, num_blocks, block_size, block_align); } | ||||
|     forceinline        void  clear() { pool_clear( this); } | ||||
|     forceinline        void  free()  { 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 ) ); | ||||
| } | ||||
|  | ||||
| inline | ||||
| mem_ptr align_forward( void* ptr, ssize alignment ) | ||||
| { | ||||
| 	GEN_ASSERT( is_power_of_two( alignment ) ); | ||||
| 	uptr p       = to_uptr(ptr); | ||||
| 	uptr forward = (p + ( alignment - 1 ) ) & ~( alignment - 1 ); | ||||
|  | ||||
| 	return to_mem_ptr(forward); | ||||
| } | ||||
|  | ||||
| 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) ); | ||||
| } | ||||
|  | ||||
| inline | ||||
| void* mem_move( void* destination, void const* source, ssize byte_count ) | ||||
| { | ||||
| 	if ( destination == NULL ) | ||||
| 	{ | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	u8*       dest_ptr = rcast( u8*, destination); | ||||
| 	u8 const* src_ptr  = rcast( u8 const*, source); | ||||
|  | ||||
| 	if ( dest_ptr == src_ptr ) | ||||
| 		return dest_ptr; | ||||
|  | ||||
| 	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 ( to_uptr(src_ptr) % size_of( ssize ) == to_uptr(dest_ptr) % size_of( ssize ) ) | ||||
| 		{ | ||||
| 			while ( pcast( uptr, dest_ptr) % size_of( ssize ) ) | ||||
| 			{ | ||||
| 				if ( ! byte_count-- ) | ||||
| 					return destination; | ||||
|  | ||||
| 				*dest_ptr++ = *src_ptr++; | ||||
| 			} | ||||
| 			while ( byte_count >= size_of( ssize ) ) | ||||
| 			{ | ||||
| 				* 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 ( ; byte_count; byte_count-- ) | ||||
| 			*dest_ptr++ = *src_ptr++; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		if ( ( to_uptr(src_ptr) % size_of( ssize ) ) == ( to_uptr(dest_ptr) % size_of( ssize ) ) ) | ||||
| 		{ | ||||
| 			while ( to_uptr( dest_ptr + byte_count ) % size_of( ssize ) ) | ||||
| 			{ | ||||
| 				if ( ! byte_count-- ) | ||||
| 					return destination; | ||||
|  | ||||
| 				dest_ptr[ byte_count ] = src_ptr[ byte_count ]; | ||||
| 			} | ||||
| 			while ( byte_count >= size_of( ssize ) ) | ||||
| 			{ | ||||
| 				byte_count                              -= size_of( ssize ); | ||||
| 				* rcast(ssize*, dest_ptr + byte_count )  = * rcast( ssize const*, src_ptr + byte_count ); | ||||
| 			} | ||||
| 		} | ||||
| 		while ( byte_count ) | ||||
| 			byte_count--, dest_ptr[ byte_count ] = src_ptr[ byte_count ]; | ||||
| 	} | ||||
|  | ||||
| 	return destination; | ||||
| } | ||||
|  | ||||
| inline | ||||
| void* mem_set( void* destination, u8 fill_byte, ssize byte_count ) | ||||
| { | ||||
| 	if ( destination == NULL ) | ||||
| 	{ | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	ssize align_offset; | ||||
| 	u8*   dest_ptr  = rcast( u8*, destination); | ||||
| 	u32   fill_word = ( ( u32 )-1 ) / 255 * fill_byte; | ||||
|  | ||||
| 	if ( byte_count == 0 ) | ||||
| 		return destination; | ||||
|  | ||||
| 	dest_ptr[ 0 ] = dest_ptr[ byte_count - 1 ] = fill_byte; | ||||
| 	if ( byte_count < 3 ) | ||||
| 		return destination; | ||||
|  | ||||
| 	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; | ||||
|  | ||||
| 	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 fill_doubleword = ( scast( u64, fill_word) << 32 ) | fill_word; | ||||
| 		while ( byte_count > 31 ) | ||||
| 		{ | ||||
| 			* 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; | ||||
|  | ||||
| 			byte_count -= 32; | ||||
| 			dest_ptr += 32; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return destination; | ||||
| } | ||||
|  | ||||
| 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 ); | ||||
| } | ||||
|  | ||||
| inline | ||||
| void* alloc( AllocatorInfo a, ssize size ) { | ||||
| 	return alloc_align( a, size, GEN_DEFAULT_MEMORY_ALIGNMENT ); | ||||
| } | ||||
|  | ||||
| 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 ); | ||||
| } | ||||
|  | ||||
| inline | ||||
| void free_all( AllocatorInfo a ) { | ||||
| 	a.Proc( a.Data, EAllocation_FREE_ALL, 0, 0, nullptr, 0, GEN_DEFAULT_ALLOCATOR_FLAGS ); | ||||
| } | ||||
|  | ||||
| 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 ); | ||||
| } | ||||
|  | ||||
| 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 ); | ||||
| } | ||||
|  | ||||
| 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 ) | ||||
| 	{ | ||||
| 		allocator_free( a, old_memory ); | ||||
| 		return nullptr; | ||||
| 	} | ||||
|  | ||||
| 	if ( new_size < old_size ) | ||||
| 		new_size = old_size; | ||||
|  | ||||
| 	if ( old_size == new_size ) | ||||
| 	{ | ||||
| 		return old_memory; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		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 ) ); | ||||
| 		allocator_free( a, old_memory ); | ||||
| 		return new_memory; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| inline | ||||
| void zero_size( void* ptr, ssize size ) { | ||||
| 	mem_set( ptr, 0, size ); | ||||
| } | ||||
|  | ||||
| #pragma endregion Memory | ||||
							
								
								
									
										1114
									
								
								base/dependencies/parsing.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1114
									
								
								base/dependencies/parsing.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										432
									
								
								base/dependencies/parsing.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										432
									
								
								base/dependencies/parsing.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,432 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	pragma once | ||||
| #endif | ||||
|  | ||||
| #pragma region ADT | ||||
|  | ||||
| enum ADT_Type : u32 | ||||
| { | ||||
| 	EADT_TYPE_UNINITIALISED, /* node was not initialised, this is a programming error! */ | ||||
| 	EADT_TYPE_ARRAY, | ||||
| 	EADT_TYPE_OBJECT, | ||||
| 	EADT_TYPE_STRING, | ||||
| 	EADT_TYPE_MULTISTRING, | ||||
| 	EADT_TYPE_INTEGER, | ||||
| 	EADT_TYPE_REAL, | ||||
| }; | ||||
|  | ||||
| enum ADT_Props : u32 | ||||
| { | ||||
| 	EADT_PROPS_NONE, | ||||
| 	EADT_PROPS_NAN, | ||||
| 	EADT_PROPS_NAN_NEG, | ||||
| 	EADT_PROPS_INFINITY, | ||||
| 	EADT_PROPS_INFINITY_NEG, | ||||
| 	EADT_PROPS_FALSE, | ||||
| 	EADT_PROPS_TRUE, | ||||
| 	EADT_PROPS_NULL, | ||||
| 	EADT_PROPS_IS_EXP, | ||||
| 	EADT_PROPS_IS_HEX, | ||||
|  | ||||
| 	// Used internally so that people can fill in real numbers they plan to write. | ||||
| 	EADT_PROPS_IS_PARSED_REAL, | ||||
| }; | ||||
|  | ||||
| enum ADT_NamingStyle : u32 | ||||
| { | ||||
| 	EADT_NAME_STYLE_DOUBLE_QUOTE, | ||||
| 	EADT_NAME_STYLE_SINGLE_QUOTE, | ||||
| 	EADT_NAME_STYLE_NO_QUOTES, | ||||
| }; | ||||
|  | ||||
| enum ADT_AssignStyle : u32 | ||||
| { | ||||
| 	EADT_ASSIGN_STYLE_COLON, | ||||
| 	EADT_ASSIGN_STYLE_EQUALS, | ||||
| 	EADT_ASSIGN_STYLE_LINE, | ||||
| }; | ||||
|  | ||||
| enum ADT_DelimStyle : u32 | ||||
| { | ||||
| 	EADT_DELIM_STYLE_COMMA, | ||||
| 	EADT_DELIM_STYLE_LINE, | ||||
| 	EADT_DELIM_STYLE_NEWLINE, | ||||
| }; | ||||
|  | ||||
| enum ADT_Error : u32 | ||||
| { | ||||
| 	EADT_ERROR_NONE, | ||||
| 	EADT_ERROR_INTERNAL, | ||||
| 	EADT_ERROR_ALREADY_CONVERTED, | ||||
| 	EADT_ERROR_INVALID_TYPE, | ||||
| 	EADT_ERROR_OUT_OF_MEMORY, | ||||
| }; | ||||
|  | ||||
| struct ADT_Node | ||||
| { | ||||
| 	char const*      name; | ||||
| 	struct ADT_Node* parent; | ||||
|  | ||||
| 	/* properties */ | ||||
| 	ADT_Type type  : 4; | ||||
| 	u8 props : 4; | ||||
| #ifndef GEN_PARSER_DISABLE_ANALYSIS | ||||
| 	u8 cfg_mode          : 1; | ||||
| 	u8 name_style        : 2; | ||||
| 	u8 assign_style      : 2; | ||||
| 	u8 delim_style       : 2; | ||||
| 	u8 delim_line_width  : 4; | ||||
| 	u8 assign_line_width : 4; | ||||
| #endif | ||||
|  | ||||
| 	/* adt data */ | ||||
| 	union | ||||
| 	{ | ||||
| 		char const*     string; | ||||
| 		Array(ADT_Node) nodes;    ///< zpl_array | ||||
|  | ||||
| 		struct | ||||
| 		{ | ||||
| 			union | ||||
| 			{ | ||||
| 				f64 real; | ||||
| 				s64 integer; | ||||
| 			}; | ||||
|  | ||||
| #ifndef GEN_PARSER_DISABLE_ANALYSIS | ||||
| 			/* number analysis */ | ||||
| 			s32 base; | ||||
| 			s32 base2; | ||||
| 			u8  base2_offset : 4; | ||||
| 			s8  exp          : 4; | ||||
| 			u8  neg_zero     : 1; | ||||
| 			u8  lead_digit   : 1; | ||||
| #endif | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| /* ADT NODE LIMITS | ||||
| 	* delimiter and assignment segment width is limited to 128 whitespace symbols each. | ||||
| 	* real number limits decimal position to 128 places. | ||||
| 	* real number exponent is limited to 64 digits. | ||||
| 	*/ | ||||
|  | ||||
| /** | ||||
| 	* @brief Initialise an ADT object or array | ||||
| 	* | ||||
| 	* @param node | ||||
| 	* @param backing Memory allocator used for descendants | ||||
| 	* @param name Node's name | ||||
| 	* @param is_array | ||||
| 	* @return error code | ||||
| 	*/ | ||||
| u8 adt_make_branch( ADT_Node* node, AllocatorInfo backing, char const* name, b32 is_array ); | ||||
|  | ||||
| /** | ||||
| 	* @brief Destroy an ADT branch and its descendants | ||||
| 	* | ||||
| 	* @param node | ||||
| 	* @return error code | ||||
| 	*/ | ||||
| u8 adt_destroy_branch( ADT_Node* node ); | ||||
|  | ||||
| /** | ||||
| 	* @brief Initialise an ADT leaf | ||||
| 	* | ||||
| 	* @param node | ||||
| 	* @param name Node's name | ||||
| 	* @param type Node's type (use zpl_adt_make_branch for container nodes) | ||||
| 	* @return error code | ||||
| 	*/ | ||||
| u8 adt_make_leaf( ADT_Node* node, char const* name, ADT_Type type ); | ||||
|  | ||||
|  | ||||
| /** | ||||
| 	* @brief Fetch a node using provided URI string. | ||||
| 	* | ||||
| 	* This method uses a basic syntax to fetch a node from the ADT. The following features are available | ||||
| 	* to retrieve the data: | ||||
| 	* | ||||
| 	* - "a/b/c" navigates through objects "a" and "b" to get to "c" | ||||
| 	* - "arr/[foo=123]/bar" iterates over "arr" to find any object with param "foo" that matches the value "123", then gets its field called "bar" | ||||
| 	* - "arr/3" retrieves the 4th element in "arr" | ||||
| 	* - "arr/[apple]" retrieves the first element of value "apple" in "arr" | ||||
| 	* | ||||
| 	* @param node ADT node | ||||
| 	* @param uri Locator string as described above | ||||
| 	* @return zpl_adt_node* | ||||
| 	* | ||||
| 	* @see code/apps/examples/json_get.c | ||||
| 	*/ | ||||
| ADT_Node* adt_query( ADT_Node* node, char const* uri ); | ||||
|  | ||||
| /** | ||||
| 	* @brief Find a field node within an object by the given name. | ||||
| 	* | ||||
| 	* @param node | ||||
| 	* @param name | ||||
| 	* @param deep_search Perform search recursively | ||||
| 	* @return zpl_adt_node * node | ||||
| 	*/ | ||||
| ADT_Node* adt_find( ADT_Node* node, char const* name, b32 deep_search ); | ||||
|  | ||||
| /** | ||||
| 	* @brief Allocate an unitialised node within a container at a specified index. | ||||
| 	* | ||||
| 	* @param parent | ||||
| 	* @param index | ||||
| 	* @return zpl_adt_node * node | ||||
| 	*/ | ||||
| ADT_Node* adt_alloc_at( ADT_Node* parent, ssize index ); | ||||
|  | ||||
| /** | ||||
| 	* @brief Allocate an unitialised node within a container. | ||||
| 	* | ||||
| 	* @param parent | ||||
| 	* @return zpl_adt_node * node | ||||
| 	*/ | ||||
| ADT_Node* adt_alloc( ADT_Node* parent ); | ||||
|  | ||||
| /** | ||||
| 	* @brief Move an existing node to a new container at a specified index. | ||||
| 	* | ||||
| 	* @param node | ||||
| 	* @param new_parent | ||||
| 	* @param index | ||||
| 	* @return zpl_adt_node * node | ||||
| 	*/ | ||||
| ADT_Node* adt_move_node_at( ADT_Node* node, ADT_Node* new_parent, ssize index ); | ||||
|  | ||||
| /** | ||||
| 	* @brief Move an existing node to a new container. | ||||
| 	* | ||||
| 	* @param node | ||||
| 	* @param new_parent | ||||
| 	* @return zpl_adt_node * node | ||||
| 	*/ | ||||
| ADT_Node* adt_move_node( ADT_Node* node, ADT_Node* new_parent ); | ||||
|  | ||||
| /** | ||||
| 	* @brief Swap two nodes. | ||||
| 	* | ||||
| 	* @param node | ||||
| 	* @param other_node | ||||
| 	* @return | ||||
| 	*/ | ||||
| void adt_swap_nodes( ADT_Node* node, ADT_Node* other_node ); | ||||
|  | ||||
| /** | ||||
| 	* @brief Remove node from container. | ||||
| 	* | ||||
| 	* @param node | ||||
| 	* @return | ||||
| 	*/ | ||||
| void adt_remove_node( ADT_Node* node ); | ||||
|  | ||||
| /** | ||||
| 	* @brief Initialise a node as an object | ||||
| 	* | ||||
| 	* @param obj | ||||
| 	* @param name | ||||
| 	* @param backing | ||||
| 	* @return | ||||
| 	*/ | ||||
| b8 adt_set_obj( ADT_Node* obj, char const* name, AllocatorInfo backing ); | ||||
|  | ||||
| /** | ||||
| 	* @brief Initialise a node as an array | ||||
| 	* | ||||
| 	* @param obj | ||||
| 	* @param name | ||||
| 	* @param backing | ||||
| 	* @return | ||||
| 	*/ | ||||
| b8 adt_set_arr( ADT_Node* obj, char const* name, AllocatorInfo backing ); | ||||
|  | ||||
| /** | ||||
| 	* @brief Initialise a node as a string | ||||
| 	* | ||||
| 	* @param obj | ||||
| 	* @param name | ||||
| 	* @param value | ||||
| 	* @return | ||||
| 	*/ | ||||
| b8 adt_set_str( ADT_Node* obj, char const* name, char const* value ); | ||||
|  | ||||
| /** | ||||
| 	* @brief Initialise a node as a float | ||||
| 	* | ||||
| 	* @param obj | ||||
| 	* @param name | ||||
| 	* @param value | ||||
| 	* @return | ||||
| 	*/ | ||||
| b8 adt_set_flt( ADT_Node* obj, char const* name, f64 value ); | ||||
|  | ||||
| /** | ||||
| 	* @brief Initialise a node as a signed integer | ||||
| 	* | ||||
| 	* @param obj | ||||
| 	* @param name | ||||
| 	* @param value | ||||
| 	* @return | ||||
| 	*/ | ||||
| b8 adt_set_int( ADT_Node* obj, char const* name, s64 value ); | ||||
|  | ||||
| /** | ||||
| 	* @brief Append a new node to a container as an object | ||||
| 	* | ||||
| 	* @param parent | ||||
| 	* @param name | ||||
| 	* @return* | ||||
| 	*/ | ||||
| ADT_Node* adt_append_obj( ADT_Node* parent, char const* name ); | ||||
|  | ||||
| /** | ||||
| 	* @brief Append a new node to a container as an array | ||||
| 	* | ||||
| 	* @param parent | ||||
| 	* @param name | ||||
| 	* @return* | ||||
| 	*/ | ||||
| ADT_Node* adt_append_arr( ADT_Node* parent, char const* name ); | ||||
|  | ||||
| /** | ||||
| 	* @brief Append a new node to a container as a string | ||||
| 	* | ||||
| 	* @param parent | ||||
| 	* @param name | ||||
| 	* @param value | ||||
| 	* @return* | ||||
| 	*/ | ||||
| ADT_Node* adt_append_str( ADT_Node* parent, char const* name, char const* value ); | ||||
|  | ||||
| /** | ||||
| 	* @brief Append a new node to a container as a float | ||||
| 	* | ||||
| 	* @param parent | ||||
| 	* @param name | ||||
| 	* @param value | ||||
| 	* @return* | ||||
| 	*/ | ||||
| ADT_Node* adt_append_flt( ADT_Node* parent, char const* name, f64 value ); | ||||
|  | ||||
| /** | ||||
| 	* @brief Append a new node to a container as a signed integer | ||||
| 	* | ||||
| 	* @param parent | ||||
| 	* @param name | ||||
| 	* @param value | ||||
| 	* @return* | ||||
| 	*/ | ||||
| ADT_Node* adt_append_int( ADT_Node* parent, char const* name, s64 value ); | ||||
|  | ||||
| /* parser helpers */ | ||||
|  | ||||
| /** | ||||
| 	* @brief Parses a text and stores the result into an unitialised node. | ||||
| 	* | ||||
| 	* @param node | ||||
| 	* @param base | ||||
| 	* @return* | ||||
| 	*/ | ||||
| char* adt_parse_number( ADT_Node* node, char* base ); | ||||
|  | ||||
| /** | ||||
| 	* @brief Parses a text and stores the result into an unitialised node. | ||||
| 	* This function expects the entire input to be a number. | ||||
| 	* | ||||
| 	* @param node | ||||
| 	* @param base | ||||
| 	* @return* | ||||
| 	*/ | ||||
| char* adt_parse_number_strict( ADT_Node* node, char* base_str ); | ||||
|  | ||||
| /** | ||||
| 	* @brief Parses and converts an existing string node into a number. | ||||
| 	* | ||||
| 	* @param node | ||||
| 	* @return | ||||
| 	*/ | ||||
| ADT_Error adt_str_to_number( ADT_Node* node ); | ||||
|  | ||||
| /** | ||||
| 	* @brief Parses and converts an existing string node into a number. | ||||
| 	* This function expects the entire input to be a number. | ||||
| 	* | ||||
| 	* @param node | ||||
| 	* @return | ||||
| 	*/ | ||||
| ADT_Error adt_str_to_number_strict( ADT_Node* node ); | ||||
|  | ||||
| /** | ||||
| 	* @brief Prints a number into a file stream. | ||||
| 	* | ||||
| 	* The provided file handle can also be a memory mapped stream. | ||||
| 	* | ||||
| 	* @see zpl_file_stream_new | ||||
| 	* @param file | ||||
| 	* @param node | ||||
| 	* @return | ||||
| 	*/ | ||||
| ADT_Error adt_print_number( FileInfo* file, ADT_Node* node ); | ||||
|  | ||||
| /** | ||||
| 	* @brief Prints a string into a file stream. | ||||
| 	* | ||||
| 	* The provided file handle can also be a memory mapped stream. | ||||
| 	* | ||||
| 	* @see zpl_file_stream_new | ||||
| 	* @param file | ||||
| 	* @param node | ||||
| 	* @param escaped_chars | ||||
| 	* @param escape_symbol | ||||
| 	* @return | ||||
| 	*/ | ||||
| ADT_Error adt_print_string( FileInfo* file, ADT_Node* node, char const* escaped_chars, char const* escape_symbol ); | ||||
|  | ||||
| #pragma endregion ADT | ||||
|  | ||||
| #pragma region CSV | ||||
|  | ||||
| enum CSV_Error : u32 | ||||
| { | ||||
| 	ECSV_Error__NONE, | ||||
| 	ECSV_Error__INTERNAL, | ||||
| 	ECSV_Error__UNEXPECTED_END_OF_INPUT, | ||||
| 	ECSV_Error__MISMATCHED_ROWS, | ||||
| }; | ||||
|  | ||||
| typedef ADT_Node CSV_Object; | ||||
|  | ||||
| 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 ); | ||||
|  | ||||
| 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 */ | ||||
|  | ||||
| inline | ||||
| u8 csv_parse( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header ) | ||||
| { | ||||
| 	return csv_parse_delimiter( root, text, allocator, has_header, ',' ); | ||||
| } | ||||
|  | ||||
| inline | ||||
| void csv_write( FileInfo* file, CSV_Object* obj ) | ||||
| { | ||||
| 	csv_write_delimiter( file, obj, ',' ); | ||||
| } | ||||
|  | ||||
| inline | ||||
| String csv_write_string( AllocatorInfo a, CSV_Object* obj ) | ||||
| { | ||||
| 	return csv_write_string_delimiter( a, obj, ',' ); | ||||
| } | ||||
|  | ||||
| #pragma endregion CSV | ||||
							
								
								
									
										176
									
								
								base/dependencies/platform.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								base/dependencies/platform.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,176 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	pragma once | ||||
| #endif | ||||
|  | ||||
| #pragma region Platform Detection | ||||
|  | ||||
| /* Platform architecture */ | ||||
|  | ||||
| #if defined( _WIN64 ) || defined( __x86_64__ ) || defined( _M_X64 ) || defined( __64BIT__ ) || defined( __powerpc64__ ) || defined( __ppc64__ ) || defined( __aarch64__ ) | ||||
| #	ifndef GEN_ARCH_64_BIT | ||||
| #		define GEN_ARCH_64_BIT 1 | ||||
| #	endif | ||||
| #else | ||||
| #	ifndef GEN_ARCH_32_BItxt_StrCaT | ||||
| #		define GEN_ARCH_32_BIT 1 | ||||
| #	endif | ||||
| #endif | ||||
|  | ||||
| /* Platform OS */ | ||||
|  | ||||
| #if defined( _WIN32 ) || defined( _WIN64 ) | ||||
| #	ifndef GEN_SYSTEM_WINDOWS | ||||
| #		define GEN_SYSTEM_WINDOWS 1 | ||||
| #	endif | ||||
| #elif defined( __APPLE__ ) && defined( __MACH__ ) | ||||
| #	ifndef GEN_SYSTEM_OSX | ||||
| #		define GEN_SYSTEM_OSX 1 | ||||
| #	endif | ||||
| #	ifndef GEN_SYSTEM_MACOS | ||||
| #		define GEN_SYSTEM_MACOS 1 | ||||
| #	endif | ||||
| #	include <TargetConditionals.h> | ||||
| #	if TARGET_IPHONE_SIMULATOR == 1 || TARGET_OS_IPHONE == 1 | ||||
| #		ifndef GEN_SYSTEM_IOS | ||||
| #			define GEN_SYSTEM_IOS 1 | ||||
| #		endif | ||||
| #	endif | ||||
| #elif defined( __unix__ ) | ||||
| #	ifndef GEN_SYSTEM_UNIX | ||||
| #		define GEN_SYSTEM_UNIX 1 | ||||
| #	endif | ||||
| #	if defined( ANDROID ) || defined( __ANDROID__ ) | ||||
| #		ifndef GEN_SYSTEM_ANDROID | ||||
| #			define GEN_SYSTEM_ANDROID 1 | ||||
| #		endif | ||||
| #		ifndef GEN_SYSTEM_LINUX | ||||
| #			define GEN_SYSTEM_LINUX 1 | ||||
| #		endif | ||||
| #	elif defined( __linux__ ) | ||||
| #		ifndef GEN_SYSTEM_LINUX | ||||
| #			define GEN_SYSTEM_LINUX 1 | ||||
| #		endif | ||||
| #	elif defined( __FreeBSD__ ) || defined( __FreeBSD_kernel__ ) | ||||
| #		ifndef GEN_SYSTEM_FREEBSD | ||||
| #			define GEN_SYSTEM_FREEBSD 1 | ||||
| #		endif | ||||
| #	elif defined( __OpenBSD__ ) | ||||
| #		ifndef GEN_SYSTEM_OPENBSD | ||||
| #			define GEN_SYSTEM_OPENBSD 1 | ||||
| #		endif | ||||
| #	elif defined( __EMSCRIPTEN__ ) | ||||
| #		ifndef GEN_SYSTEM_EMSCRIPTEN | ||||
| #			define GEN_SYSTEM_EMSCRIPTEN 1 | ||||
| #		endif | ||||
| #	elif defined( __CYGWIN__ ) | ||||
| #		ifndef GEN_SYSTEM_CYGWIN | ||||
| #			define GEN_SYSTEM_CYGWIN 1 | ||||
| #		endif | ||||
| #	else | ||||
| #		error This UNIX operating system is not supported | ||||
| #	endif | ||||
| #else | ||||
| #	error This operating system is not supported | ||||
| #endif | ||||
|  | ||||
| /* Platform compiler */ | ||||
|  | ||||
| #if defined( _MSC_VER ) | ||||
| #	pragma message("Detected MSVC") | ||||
| // #	define GEN_COMPILER_CLANG 0 | ||||
| #	define GEN_COMPILER_MSVC  1 | ||||
| // #	define GEN_COMPILER_GCC   0 | ||||
| #elif defined( __GNUC__ ) | ||||
| #	pragma message("Detected GCC") | ||||
| // #	define GEN_COMPILER_CLANG 0 | ||||
| // #	define GEN_COMPILER_MSVC  0 | ||||
| #	define GEN_COMPILER_GCC   1 | ||||
| #elif defined( __clang__ ) | ||||
| #	pragma message("Detected CLANG") | ||||
| #	define GEN_COMPILER_CLANG 1 | ||||
| // #	define GEN_COMPILER_MSVC  0 | ||||
| // #	define GEN_COMPILER_GCC   0 | ||||
| #else | ||||
| #	error Unknown compiler | ||||
| #endif | ||||
|  | ||||
| #if defined( __has_attribute ) | ||||
| #	define GEN_HAS_ATTRIBUTE( attribute ) __has_attribute( attribute ) | ||||
| #else | ||||
| #	define GEN_HAS_ATTRIBUTE( attribute ) ( 0 ) | ||||
| #endif | ||||
|  | ||||
| #if defined(GEN_GCC_VERSION_CHECK) | ||||
| #  undef GEN_GCC_VERSION_CHECK | ||||
| #endif | ||||
| #if defined(GEN_GCC_VERSION) | ||||
| #  define GEN_GCC_VERSION_CHECK(major,minor,patch) (GEN_GCC_VERSION >= GEN_VERSION_ENCODE(major, minor, patch)) | ||||
| #else | ||||
| #  define GEN_GCC_VERSION_CHECK(major,minor,patch) (0) | ||||
| #endif | ||||
|  | ||||
| #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("GENCPP: Detected C") | ||||
| #endif | ||||
|  | ||||
| #pragma endregion Platform Detection | ||||
|  | ||||
| #pragma region Mandatory Includes | ||||
|  | ||||
| #	include <stdarg.h> | ||||
| #	include <stddef.h> | ||||
|  | ||||
| #	if defined( GEN_SYSTEM_WINDOWS ) | ||||
| #		include <intrin.h> | ||||
| #	endif | ||||
|  | ||||
| #if GEN_COMPILER_C | ||||
| #include <assert.h> | ||||
| #include <stdbool.h> | ||||
| #endif | ||||
|  | ||||
| #pragma endregion Mandatory Includes | ||||
|  | ||||
| #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          } | ||||
| #endif | ||||
							
								
								
									
										601
									
								
								base/dependencies/printing.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										601
									
								
								base/dependencies/printing.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,601 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	pragma once | ||||
| #	include "filesystem.hpp" | ||||
| #	include "strings.hpp" | ||||
| #	include "string_ops.cpp" | ||||
| #endif | ||||
|  | ||||
| #pragma region Printing | ||||
|  | ||||
| enum | ||||
| { | ||||
| 	GEN_FMT_MINUS = bit( 0 ), | ||||
| 	GEN_FMT_PLUS  = bit( 1 ), | ||||
| 	GEN_FMT_ALT   = bit( 2 ), | ||||
| 	GEN_FMT_SPACE = bit( 3 ), | ||||
| 	GEN_FMT_ZERO  = bit( 4 ), | ||||
|  | ||||
| 	GEN_FMT_CHAR   = bit( 5 ), | ||||
| 	GEN_FMT_SHORT  = bit( 6 ), | ||||
| 	GEN_FMT_INT    = bit( 7 ), | ||||
| 	GEN_FMT_LONG   = bit( 8 ), | ||||
| 	GEN_FMT_LLONG  = bit( 9 ), | ||||
| 	GEN_FMT_SIZE   = bit( 10 ), | ||||
| 	GEN_FMT_INTPTR = bit( 11 ), | ||||
|  | ||||
| 	GEN_FMT_UNSIGNED = bit( 12 ), | ||||
| 	GEN_FMT_LOWER    = bit( 13 ), | ||||
| 	GEN_FMT_UPPER    = bit( 14 ), | ||||
| 	GEN_FMT_WIDTH    = bit( 15 ), | ||||
|  | ||||
| 	GEN_FMT_DONE = bit( 30 ), | ||||
|  | ||||
| 	GEN_FMT_INTS = GEN_FMT_CHAR | GEN_FMT_SHORT | GEN_FMT_INT | GEN_FMT_LONG | GEN_FMT_LLONG | GEN_FMT_SIZE | GEN_FMT_INTPTR | ||||
| }; | ||||
|  | ||||
| typedef struct _format_info _format_info; | ||||
| struct _format_info | ||||
| { | ||||
| 	s32 base; | ||||
| 	s32 flags; | ||||
| 	s32 width; | ||||
| 	s32 precision; | ||||
| }; | ||||
|  | ||||
| internal ssize _print_string( char* text, ssize max_len, _format_info* info, char const* str ) | ||||
| { | ||||
| 	ssize res = 0, len = 0; | ||||
| 	ssize remaining = max_len; | ||||
| 	char* begin     = text; | ||||
|  | ||||
| 	if ( str == NULL && max_len >= 6 ) | ||||
| 	{ | ||||
| 		res += str_copy_nulpad( text, "(null)", 6 ); | ||||
| 		return res; | ||||
| 	} | ||||
|  | ||||
| 	if ( info && info->precision >= 0 ) | ||||
| 		// Made the design decision for this library that precision is the length of the string. | ||||
| 		len = info->precision; | ||||
| 	else | ||||
| 		len = str_len( str ); | ||||
|  | ||||
| 	if ( info && ( info->width == 0 && info->flags & GEN_FMT_WIDTH ) ) | ||||
| 	{ | ||||
| 		return res; | ||||
| 	} | ||||
|  | ||||
| 	if ( info && ( info->width == 0 || info->flags & GEN_FMT_MINUS ) ) | ||||
| 	{ | ||||
| 		if ( info->precision > 0 ) | ||||
| 			len = info->precision < len ? info->precision : len; | ||||
| 		if ( res + len > max_len ) | ||||
| 			return res; | ||||
| 		res  += str_copy_nulpad( text, str, len ); | ||||
| 		text += res; | ||||
|  | ||||
| 		if ( info->width > res ) | ||||
| 		{ | ||||
| 			ssize padding = info->width - len; | ||||
|  | ||||
| 			char pad = ( info->flags & GEN_FMT_ZERO ) ? '0' : ' '; | ||||
| 			while ( padding-- > 0 && remaining-- > 0 ) | ||||
| 				*text++ = pad, res++; | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		if ( info && ( info->width > res ) ) | ||||
| 		{ | ||||
| 			ssize   padding = info->width - len; | ||||
| 			char pad     = ( info->flags & GEN_FMT_ZERO ) ? '0' : ' '; | ||||
| 			while ( padding-- > 0 && remaining-- > 0 ) | ||||
| 				*text++ = pad, res++; | ||||
| 		} | ||||
|  | ||||
| 		if ( res + len > max_len ) | ||||
| 			return res; | ||||
| 		res += str_copy_nulpad( text, str, len ); | ||||
| 	} | ||||
|  | ||||
| 	if ( info ) | ||||
| 	{ | ||||
| 		if ( info->flags & GEN_FMT_UPPER ) | ||||
| 			str_to_upper( begin ); | ||||
| 		else if ( info->flags & GEN_FMT_LOWER ) | ||||
| 			str_to_lower( begin ); | ||||
| 	} | ||||
|  | ||||
| 	return res; | ||||
| } | ||||
|  | ||||
| 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 ssize _print_repeated_char( char* text, ssize max_len, _format_info* info, char arg ) | ||||
| { | ||||
| 	ssize  res = 0; | ||||
| 	s32 rem = ( info ) ? ( info->width > 0 ) ? info->width : 1 : 1; | ||||
| 	res     = rem; | ||||
| 	while ( rem-- > 0 ) | ||||
| 		*text++ = arg; | ||||
|  | ||||
| 	return res; | ||||
| } | ||||
|  | ||||
| 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 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 ssize _print_f64( char* text, ssize max_len, _format_info* info, b32 is_hexadecimal, f64 arg ) | ||||
| { | ||||
| 	// TODO: Handle exponent notation | ||||
| 	ssize    width, len, remaining = max_len; | ||||
| 	char* text_begin = text; | ||||
|  | ||||
| 	if ( arg ) | ||||
| 	{ | ||||
| 		u64 value; | ||||
| 		if ( arg < 0 ) | ||||
| 		{ | ||||
| 			if ( remaining > 1 ) | ||||
| 				*text = '-', remaining--; | ||||
| 			text++; | ||||
| 			arg = -arg; | ||||
| 		} | ||||
| 		else if ( info->flags & GEN_FMT_MINUS ) | ||||
| 		{ | ||||
| 			if ( remaining > 1 ) | ||||
| 				*text = '+', remaining--; | ||||
| 			text++; | ||||
| 		} | ||||
|  | ||||
| 		value  = scast( u64, arg); | ||||
| 		len    = _print_u64( text, remaining, NULL, value ); | ||||
| 		text  += len; | ||||
|  | ||||
| 		if ( len >= remaining ) | ||||
| 			remaining = min( remaining, 1 ); | ||||
| 		else | ||||
| 			remaining -= len; | ||||
| 		arg -= value; | ||||
|  | ||||
| 		if ( info->precision < 0 ) | ||||
| 			info->precision = 6; | ||||
|  | ||||
| 		if ( ( info->flags & GEN_FMT_ALT ) || info->precision > 0 ) | ||||
| 		{ | ||||
| 			s64 mult = 10; | ||||
| 			if ( remaining > 1 ) | ||||
| 				*text = '.', remaining--; | ||||
| 			text++; | ||||
| 			while ( info->precision-- > 0 ) | ||||
| 			{ | ||||
| 				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  -= scast( f64, value / mult); | ||||
| 				mult *= 10; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		if ( remaining > 1 ) | ||||
| 			*text = '0', remaining--; | ||||
| 		text++; | ||||
| 		if ( info->flags & GEN_FMT_ALT ) | ||||
| 		{ | ||||
| 			if ( remaining > 1 ) | ||||
| 				*text = '.', remaining--; | ||||
| 			text++; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	width = info->width - ( text - text_begin ); | ||||
| 	if ( width > 0 ) | ||||
| 	{ | ||||
| 		char  fill = ( info->flags & GEN_FMT_ZERO ) ? '0' : ' '; | ||||
| 		char* end  = text + remaining - 1; | ||||
| 		len        = ( text - text_begin ); | ||||
|  | ||||
| 		for ( len = ( text - text_begin ); len--; ) | ||||
| 		{ | ||||
| 			if ( ( text_begin + len + width ) < end ) | ||||
| 				*( text_begin + len + width ) = *( text_begin + len ); | ||||
| 		} | ||||
|  | ||||
| 		len   = width; | ||||
| 		text += len; | ||||
| 		if ( len >= remaining ) | ||||
| 			remaining = min( remaining, 1 ); | ||||
| 		else | ||||
| 			remaining -= len; | ||||
|  | ||||
| 		while ( len-- ) | ||||
| 		{ | ||||
| 			if ( text_begin + len < end ) | ||||
| 				text_begin[ len ] = fill; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return ( text - text_begin ); | ||||
| } | ||||
|  | ||||
| neverinline ssize str_fmt_va( char* text, ssize max_len, char const* fmt, va_list va ) | ||||
| { | ||||
| 	char const* text_begin = text; | ||||
| 	ssize          remaining  = max_len, res; | ||||
|  | ||||
| 	while ( *fmt ) | ||||
| 	{ | ||||
| 		_format_info info = { 0 }; | ||||
| 		ssize        len  = 0; | ||||
| 		info.precision    = -1; | ||||
|  | ||||
| 		while ( *fmt && *fmt != '%' && remaining ) | ||||
| 			*text++ = *fmt++; | ||||
|  | ||||
| 		if ( *fmt == '%' ) | ||||
| 		{ | ||||
| 			do | ||||
| 			{ | ||||
| 				switch ( *++fmt ) | ||||
| 				{ | ||||
| 					case '-' : | ||||
| 						{ | ||||
| 							info.flags |= GEN_FMT_MINUS; | ||||
| 							break; | ||||
| 						} | ||||
| 					case '+' : | ||||
| 						{ | ||||
| 							info.flags |= GEN_FMT_PLUS; | ||||
| 							break; | ||||
| 						} | ||||
| 					case '#' : | ||||
| 						{ | ||||
| 							info.flags |= GEN_FMT_ALT; | ||||
| 							break; | ||||
| 						} | ||||
| 					case ' ' : | ||||
| 						{ | ||||
| 							info.flags |= GEN_FMT_SPACE; | ||||
| 							break; | ||||
| 						} | ||||
| 					case '0' : | ||||
| 						{ | ||||
| 							info.flags |= ( GEN_FMT_ZERO | GEN_FMT_WIDTH ); | ||||
| 							break; | ||||
| 						} | ||||
| 					default : | ||||
| 						{ | ||||
| 							info.flags |= GEN_FMT_DONE; | ||||
| 							break; | ||||
| 						} | ||||
| 				} | ||||
| 			} while ( ! ( info.flags & GEN_FMT_DONE ) ); | ||||
| 		} | ||||
|  | ||||
| 		// NOTE: Optional Width | ||||
| 		if ( *fmt == '*' ) | ||||
| 		{ | ||||
| 			int width = va_arg( va, int ); | ||||
| 			if ( width < 0 ) | ||||
| 			{ | ||||
| 				info.flags |= GEN_FMT_MINUS; | ||||
| 				info.width  = -width; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				info.width = width; | ||||
| 			} | ||||
| 			info.flags |= GEN_FMT_WIDTH; | ||||
| 			fmt++; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			info.width = scast( s32, str_to_i64( fmt, ccast( char**, & fmt), 10 )); | ||||
| 			if ( info.width != 0 ) | ||||
| 			{ | ||||
| 				info.flags |= GEN_FMT_WIDTH; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// NOTE: Optional Precision | ||||
| 		if ( *fmt == '.' ) | ||||
| 		{ | ||||
| 			fmt++; | ||||
| 			if ( *fmt == '*' ) | ||||
| 			{ | ||||
| 				info.precision = va_arg( va, int ); | ||||
| 				fmt++; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				info.precision = scast( s32, str_to_i64( fmt, ccast( char**, & fmt), 10 )); | ||||
| 			} | ||||
| 			info.flags &= ~GEN_FMT_ZERO; | ||||
| 		} | ||||
|  | ||||
| 		switch ( *fmt++ ) | ||||
| 		{ | ||||
| 			case 'h' : | ||||
| 				if ( *fmt == 'h' ) | ||||
| 				{    // hh => char | ||||
| 					info.flags |= GEN_FMT_CHAR; | ||||
| 					fmt++; | ||||
| 				} | ||||
| 				else | ||||
| 				{    // h => short | ||||
| 					info.flags |= GEN_FMT_SHORT; | ||||
| 				} | ||||
| 				break; | ||||
|  | ||||
| 			case 'l' : | ||||
| 				if ( *fmt == 'l' ) | ||||
| 				{    // ll => long long | ||||
| 					info.flags |= GEN_FMT_LLONG; | ||||
| 					fmt++; | ||||
| 				} | ||||
| 				else | ||||
| 				{    // l => long | ||||
| 					info.flags |= GEN_FMT_LONG; | ||||
| 				} | ||||
| 				break; | ||||
|  | ||||
| 				break; | ||||
|  | ||||
| 			case 'z' :    // NOTE: zpl_usize | ||||
| 				info.flags |= GEN_FMT_UNSIGNED; | ||||
| 				// fallthrough | ||||
| 			case 't' :    // NOTE: zpl_isize | ||||
| 				info.flags |= GEN_FMT_SIZE; | ||||
| 				break; | ||||
|  | ||||
| 			default : | ||||
| 				fmt--; | ||||
| 				break; | ||||
| 		} | ||||
|  | ||||
| 		switch ( *fmt ) | ||||
| 		{ | ||||
| 			case 'u' : | ||||
| 				info.flags |= GEN_FMT_UNSIGNED; | ||||
| 				// fallthrough | ||||
| 			case 'd' : | ||||
| 			case 'i' : | ||||
| 				info.base = 10; | ||||
| 				break; | ||||
|  | ||||
| 			case 'o' : | ||||
| 				info.base = 8; | ||||
| 				break; | ||||
|  | ||||
| 			case 'x' : | ||||
| 				info.base   = 16; | ||||
| 				info.flags |= ( GEN_FMT_UNSIGNED | GEN_FMT_LOWER ); | ||||
| 				break; | ||||
|  | ||||
| 			case 'X' : | ||||
| 				info.base   = 16; | ||||
| 				info.flags |= ( GEN_FMT_UNSIGNED | GEN_FMT_UPPER ); | ||||
| 				break; | ||||
|  | ||||
| 			case 'f' : | ||||
| 			case 'F' : | ||||
| 			case 'g' : | ||||
| 			case 'G' : | ||||
| 				len = _print_f64( text, remaining, &info, 0, va_arg( va, f64 ) ); | ||||
| 				break; | ||||
|  | ||||
| 			case 'a' : | ||||
| 			case 'A' : | ||||
| 				len = _print_f64( text, remaining, &info, 1, va_arg( va, f64 ) ); | ||||
| 				break; | ||||
|  | ||||
| 			case 'c' : | ||||
| 				len = _print_char( text, remaining, &info, scast( char, va_arg( va, int ) )); | ||||
| 				break; | ||||
|  | ||||
| 			case 's' : | ||||
| 				len = _print_string( text, remaining, &info, va_arg( va, char* ) ); | ||||
| 				break; | ||||
|  | ||||
| 			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 = { va_arg( va, char*) }; | ||||
|  | ||||
| 				info.precision = string_length(gen_str); | ||||
| 				len            = _print_string( text, remaining, &info, gen_str ); | ||||
| 			} | ||||
| 			break; | ||||
|  | ||||
| 			case 'r' : | ||||
| 				len = _print_repeated_char( text, remaining, &info, va_arg( va, int ) ); | ||||
| 				break; | ||||
|  | ||||
| 			case 'p' : | ||||
| 				info.base   = 16; | ||||
| 				info.flags |= ( GEN_FMT_LOWER | GEN_FMT_UNSIGNED | GEN_FMT_ALT | GEN_FMT_INTPTR ); | ||||
| 				break; | ||||
|  | ||||
| 			case '%' : | ||||
| 				len = _print_char( text, remaining, &info, '%' ); | ||||
| 				break; | ||||
|  | ||||
| 			default : | ||||
| 				fmt--; | ||||
| 				break; | ||||
| 		} | ||||
|  | ||||
| 		fmt++; | ||||
|  | ||||
| 		if ( info.base != 0 ) | ||||
| 		{ | ||||
| 			if ( info.flags & GEN_FMT_UNSIGNED ) | ||||
| 			{ | ||||
| 				u64 value = 0; | ||||
| 				switch ( info.flags & GEN_FMT_INTS ) | ||||
| 				{ | ||||
| 					case GEN_FMT_CHAR : | ||||
| 						value = scast( u64, scast( u8, va_arg( va, int ))); | ||||
| 						break; | ||||
| 					case GEN_FMT_SHORT : | ||||
| 						value = scast( u64, scast( u16, va_arg( va, int ))); | ||||
| 						break; | ||||
| 					case GEN_FMT_LONG: | ||||
| 						value = scast( u64, va_arg( va, unsigned long )); | ||||
| 						break; | ||||
| 					case GEN_FMT_LLONG : | ||||
| 						value = scast( u64, va_arg( va, unsigned long long )); | ||||
| 						break; | ||||
| 					case GEN_FMT_SIZE : | ||||
| 						value = scast( u64, va_arg( va, usize )); | ||||
| 						break; | ||||
| 					case GEN_FMT_INTPTR : | ||||
| 						value = scast( u64, va_arg( va, uptr )); | ||||
| 						break; | ||||
| 					default : | ||||
| 						value = scast( u64, va_arg( va, unsigned int )); | ||||
| 						break; | ||||
| 				} | ||||
|  | ||||
| 				len = _print_u64( text, remaining, &info, value ); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				s64 value = 0; | ||||
| 				switch ( info.flags & GEN_FMT_INTS ) | ||||
| 				{ | ||||
| 					case GEN_FMT_CHAR : | ||||
| 						value = scast( s64, scast( s8, va_arg( va, int ))); | ||||
| 						break; | ||||
| 					case GEN_FMT_SHORT : | ||||
| 						value = scast( s64, scast( s16, va_arg( va, int ))); | ||||
| 						break; | ||||
| 					case GEN_FMT_LONG : | ||||
| 						value = scast( s64, va_arg( va, long )); | ||||
| 						break; | ||||
| 					case GEN_FMT_LLONG : | ||||
| 						value = scast( s64, va_arg( va, long long )); | ||||
| 						break; | ||||
| 					case GEN_FMT_SIZE : | ||||
| 						value = scast( s64, va_arg( va, usize )); | ||||
| 						break; | ||||
| 					case GEN_FMT_INTPTR : | ||||
| 						value = scast( s64, va_arg( va, uptr )); | ||||
| 						break; | ||||
| 					default : | ||||
| 						value = scast( s64, va_arg( va, int )); | ||||
| 						break; | ||||
| 				} | ||||
|  | ||||
| 				len = _print_i64( text, remaining, &info, value ); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		text += len; | ||||
| 		if ( len >= remaining ) | ||||
| 			remaining = min( remaining, 1 ); | ||||
| 		else | ||||
| 			remaining -= len; | ||||
| 	} | ||||
|  | ||||
| 	*text++ = '\0'; | ||||
| 	res     = ( text - text_begin ); | ||||
| 	return ( res >= max_len || res < 0 ) ? -1 : res; | ||||
| } | ||||
|  | ||||
| char* str_fmt_buf_va( char const* fmt, va_list va ) | ||||
| { | ||||
| 	local_persist thread_local char buffer[ GEN_PRINTF_MAXLEN ]; | ||||
| 	str_fmt_va( buffer, size_of( buffer ), fmt, va ); | ||||
| 	return buffer; | ||||
| } | ||||
|  | ||||
| char* str_fmt_buf( char const* fmt, ... ) | ||||
| { | ||||
| 	va_list va; | ||||
| 	char*   str; | ||||
| 	va_start( va, fmt ); | ||||
| 	str = str_fmt_buf_va( fmt, va ); | ||||
| 	va_end( va ); | ||||
| 	return str; | ||||
| } | ||||
|  | ||||
| ssize str_fmt_file_va( FileInfo* f, char const* fmt, va_list va ) | ||||
| { | ||||
| 	local_persist thread_local char buf[ GEN_PRINTF_MAXLEN ]; | ||||
| 	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; | ||||
| } | ||||
|  | ||||
| ssize str_fmt_file( FileInfo* f, char const* fmt, ... ) | ||||
| { | ||||
| 	ssize      res; | ||||
| 	va_list va; | ||||
| 	va_start( va, fmt ); | ||||
| 	res = str_fmt_file_va( f, fmt, va ); | ||||
| 	va_end( va ); | ||||
| 	return res; | ||||
| } | ||||
|  | ||||
| ssize str_fmt( char* str, ssize n, char const* fmt, ... ) | ||||
| { | ||||
| 	ssize      res; | ||||
| 	va_list va; | ||||
| 	va_start( va, fmt ); | ||||
| 	res = str_fmt_va( str, n, fmt, va ); | ||||
| 	va_end( va ); | ||||
| 	return res; | ||||
| } | ||||
|  | ||||
| ssize str_fmt_out_va( char const* fmt, va_list va ) | ||||
| { | ||||
| 	return str_fmt_file_va( file_get_standard( EFileStandard_OUTPUT ), fmt, 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 ); | ||||
| } | ||||
|  | ||||
| ssize str_fmt_out_err( char const* fmt, ... ) | ||||
| { | ||||
| 	ssize      res; | ||||
| 	va_list va; | ||||
| 	va_start( va, fmt ); | ||||
| 	res = str_fmt_out_err_va( fmt, va ); | ||||
| 	va_end( va ); | ||||
| 	return res; | ||||
| } | ||||
|  | ||||
| #pragma endregion Printing | ||||
							
								
								
									
										42
									
								
								base/dependencies/printing.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								base/dependencies/printing.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	pragma once | ||||
| #	include "string_ops.hpp" | ||||
| #endif | ||||
|  | ||||
| #pragma region Printing | ||||
|  | ||||
| typedef struct FileInfo 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 ); | ||||
| 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 | ||||
| ssize log_fmt(char const* fmt, ...) | ||||
| { | ||||
| 	ssize res; | ||||
| 	va_list va; | ||||
|  | ||||
| 	va_start(va, fmt); | ||||
| 	res = str_fmt_out_va(fmt, va); | ||||
| 	va_end(va); | ||||
|  | ||||
| 	return res; | ||||
| } | ||||
|  | ||||
| #pragma endregion Printing | ||||
							
								
								
									
										84
									
								
								base/dependencies/src_start.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								base/dependencies/src_start.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,84 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	include "header_start.hpp" | ||||
| #endif | ||||
|  | ||||
| #pragma region Macros and Includes | ||||
|  | ||||
| #	include <stdio.h> | ||||
| // NOTE: Ensure we use standard methods for these calls if we use GEN_PICO | ||||
| #	if ! defined( GEN_PICO_CUSTOM_ROUTINES ) | ||||
| #		if ! defined( GEN_MODULE_CORE ) | ||||
| #			define _strlen                   strlen | ||||
| #			define _printf_err( fmt, ... )   fprintf( stderr, fmt, __VA_ARGS__ ) | ||||
| #			define _printf_err_va( fmt, va ) vfprintf( stderr, fmt, va ) | ||||
| #		else | ||||
| #			define _strlen                   str_len | ||||
| #			define _printf_err( fmt, ... )   str_fmt_out_err( fmt, __VA_ARGS__ ) | ||||
| #			define _printf_err_va( fmt, va ) str_fmt_out_err_va( fmt, va ) | ||||
| #		endif | ||||
| #	endif | ||||
| # | ||||
| #	include <errno.h> | ||||
| # | ||||
| #	if defined( GEN_SYSTEM_UNIX ) || defined( GEN_SYSTEM_MACOS ) | ||||
| #		include <unistd.h> | ||||
| #	elif defined( GEN_SYSTEM_WINDOWS ) | ||||
| #		if ! defined( GEN_NO_WINDOWS_H ) | ||||
| #			ifndef WIN32_LEAN_AND_MEAN | ||||
| #				ifndef NOMINMAX | ||||
| #					define NOMINMAX | ||||
| #				endif | ||||
| # | ||||
| #				define WIN32_LEAN_AND_MEAN | ||||
| #				define WIN32_MEAN_AND_LEAN | ||||
| #				define VC_EXTRALEAN | ||||
| #			endif | ||||
| #			include <windows.h> | ||||
| #			undef NOMINMAX | ||||
| #			undef WIN32_LEAN_AND_MEAN | ||||
| #			undef WIN32_MEAN_AND_LEAN | ||||
| #			undef VC_EXTRALEAN | ||||
| #		endif | ||||
| #	endif | ||||
|  | ||||
| #include <sys/stat.h> | ||||
|  | ||||
| #ifdef GEN_SYSTEM_MACOS | ||||
| #	include <copyfile.h> | ||||
| #endif | ||||
|  | ||||
| #ifdef GEN_SYSTEM_CYGWIN | ||||
| #	include <windows.h> | ||||
| #endif | ||||
|  | ||||
| #if defined( GEN_SYSTEM_WINDOWS ) && ! defined( GEN_COMPILER_GCC ) | ||||
| #	include <io.h> | ||||
| #endif | ||||
|  | ||||
| #if defined( GEN_SYSTEM_LINUX ) | ||||
| #	include <sys/types.h> | ||||
| #endif | ||||
|  | ||||
| #ifdef GEN_BENCHMARK | ||||
| // Timing includes | ||||
| #if defined( GEN_SYSTEM_MACOS ) || GEN_SYSTEM_UNIX | ||||
| #	include <time.h> | ||||
| #	include <sys/time.h> | ||||
| #endif | ||||
|  | ||||
| #if defined( GEN_SYSTEM_MACOS ) | ||||
| #	include <mach/mach.h> | ||||
| #	include <mach/mach_time.h> | ||||
| #	include <mach/clock.h> | ||||
| #endif | ||||
|  | ||||
| #if defined( GEN_SYSTEM_EMSCRIPTEN ) | ||||
| #	include <emscripten.h> | ||||
| #endif | ||||
|  | ||||
| #if defined( GEN_SYSTEM_WINDOWS ) | ||||
| #	include <timezoneapi.h> | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #pragma endregion Macros and Includes | ||||
							
								
								
									
										215
									
								
								base/dependencies/string_ops.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										215
									
								
								base/dependencies/string_ops.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,215 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	pragma once | ||||
| #	include "string_ops.hpp" | ||||
| #	include "debug.cpp" | ||||
| #endif | ||||
|  | ||||
| #pragma region String Ops | ||||
|  | ||||
| internal | ||||
| ssize _scan_zpl_i64( const char* text, s32 base, s64* value ) | ||||
| { | ||||
| 	const char* text_begin = text; | ||||
| 	s64         result     = 0; | ||||
| 	b32         negative   = false; | ||||
|  | ||||
| 	if ( *text == '-' ) | ||||
| 	{ | ||||
| 		negative = true; | ||||
| 		text++; | ||||
| 	} | ||||
|  | ||||
| 	if ( base == 16 && str_compare_len( text, "0x", 2 ) == 0 ) | ||||
| 		text += 2; | ||||
|  | ||||
| 	for ( ;; ) | ||||
| 	{ | ||||
| 		s64 v; | ||||
| 		if ( char_is_digit( *text ) ) | ||||
| 			v = *text - '0'; | ||||
| 		else if ( base == 16 && char_is_hex_digit( *text ) ) | ||||
| 			v = hex_digit_to_int( *text ); | ||||
| 		else | ||||
| 			break; | ||||
|  | ||||
| 		result *= base; | ||||
| 		result += v; | ||||
| 		text++; | ||||
| 	} | ||||
|  | ||||
| 	if ( value ) | ||||
| 	{ | ||||
| 		if ( negative ) | ||||
| 			result = -result; | ||||
| 		*value = result; | ||||
| 	} | ||||
|  | ||||
| 	return ( text - text_begin ); | ||||
| } | ||||
|  | ||||
| // TODO : Are these good enough for characters? | ||||
| global const char _num_to_char_table[] = | ||||
| 	"0123456789" | ||||
| 	"ABCDEFGHIJKLMNOPQRSTUVWXYZ" | ||||
| 	"abcdefghijklmnopqrstuvwxyz" | ||||
| 	"@$"; | ||||
|  | ||||
| s64 str_to_i64( const char* str, char** end_ptr, s32 base ) | ||||
| { | ||||
| 	ssize  len; | ||||
| 	s64 value; | ||||
|  | ||||
| 	if ( ! base ) | ||||
| 	{ | ||||
| 		if ( ( str_len( str ) > 2 ) && ( str_compare_len( str, "0x", 2 ) == 0 ) ) | ||||
| 			base = 16; | ||||
| 		else | ||||
| 			base = 10; | ||||
| 	} | ||||
|  | ||||
| 	len = _scan_zpl_i64( str, base, &value ); | ||||
| 	if ( end_ptr ) | ||||
| 		*end_ptr = ( char* )str + len; | ||||
| 	return value; | ||||
| } | ||||
|  | ||||
| void i64_to_str( s64 value, char* string, s32 base ) | ||||
| { | ||||
| 	char* buf      = string; | ||||
| 	b32   negative = false; | ||||
| 	u64   v; | ||||
|  | ||||
| 	if ( value < 0 ) | ||||
| 	{ | ||||
| 		negative = true; | ||||
| 		value    = -value; | ||||
| 	} | ||||
|  | ||||
| 	v = scast( u64, value); | ||||
| 	if ( v != 0 ) | ||||
| 	{ | ||||
| 		while ( v > 0 ) | ||||
| 		{ | ||||
| 			*buf++  = _num_to_char_table[ v % base ]; | ||||
| 			v      /= base; | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		*buf++ = '0'; | ||||
| 	} | ||||
| 	if ( negative ) | ||||
| 		*buf++ = '-'; | ||||
| 	*buf = '\0'; | ||||
| 	str_reverse( string ); | ||||
| } | ||||
|  | ||||
| void u64_to_str( u64 value, char* string, s32 base ) | ||||
| { | ||||
| 	char* buf = string; | ||||
|  | ||||
| 	if ( value ) | ||||
| 	{ | ||||
| 		while ( value > 0 ) | ||||
| 		{ | ||||
| 			*buf++  = _num_to_char_table[ value % base ]; | ||||
| 			value  /= base; | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		*buf++ = '0'; | ||||
| 	} | ||||
| 	*buf = '\0'; | ||||
|  | ||||
| 	str_reverse( string ); | ||||
| } | ||||
|  | ||||
| f64 str_to_f64( const char* str, char** end_ptr ) | ||||
| { | ||||
| 	f64 result, value, sign, scale; | ||||
| 	s32 frac; | ||||
|  | ||||
| 	while ( char_is_space( *str ) ) | ||||
| 	{ | ||||
| 		str++; | ||||
| 	} | ||||
|  | ||||
| 	sign = 1.0; | ||||
| 	if ( *str == '-' ) | ||||
| 	{ | ||||
| 		sign = -1.0; | ||||
| 		str++; | ||||
| 	} | ||||
| 	else if ( *str == '+' ) | ||||
| 	{ | ||||
| 		str++; | ||||
| 	} | ||||
|  | ||||
| 	for ( value = 0.0; char_is_digit( *str ); str++ ) | ||||
| 	{ | ||||
| 		value = value * 10.0 + ( *str - '0' ); | ||||
| 	} | ||||
|  | ||||
| 	if ( *str == '.' ) | ||||
| 	{ | ||||
| 		f64 pow10 = 10.0; | ||||
| 		str++; | ||||
| 		while ( char_is_digit( *str ) ) | ||||
| 		{ | ||||
| 			value += ( *str - '0' ) / pow10; | ||||
| 			pow10 *= 10.0; | ||||
| 			str++; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	frac  = 0; | ||||
| 	scale = 1.0; | ||||
| 	if ( ( *str == 'e' ) || ( *str == 'E' ) ) | ||||
| 	{ | ||||
| 		u32 exp; | ||||
|  | ||||
| 		str++; | ||||
| 		if ( *str == '-' ) | ||||
| 		{ | ||||
| 			frac = 1; | ||||
| 			str++; | ||||
| 		} | ||||
| 		else if ( *str == '+' ) | ||||
| 		{ | ||||
| 			str++; | ||||
| 		} | ||||
|  | ||||
| 		for ( exp = 0; char_is_digit( *str ); str++ ) | ||||
| 		{ | ||||
| 			exp = exp * 10 + ( *str - '0' ); | ||||
| 		} | ||||
| 		if ( exp > 308 ) | ||||
| 			exp = 308; | ||||
|  | ||||
| 		while ( exp >= 50 ) | ||||
| 		{ | ||||
| 			scale *= 1e50; | ||||
| 			exp   -= 50; | ||||
| 		} | ||||
| 		while ( exp >= 8 ) | ||||
| 		{ | ||||
| 			scale *= 1e8; | ||||
| 			exp   -= 8; | ||||
| 		} | ||||
| 		while ( exp > 0 ) | ||||
| 		{ | ||||
| 			scale *= 10.0; | ||||
| 			exp   -= 1; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	result = sign * ( frac ? ( value / scale ) : ( value * scale ) ); | ||||
|  | ||||
| 	if ( end_ptr ) | ||||
| 		* end_ptr = rcast( char*, ccast(char*, str) ); | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| #pragma endregion String Ops | ||||
							
								
								
									
										287
									
								
								base/dependencies/string_ops.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										287
									
								
								base/dependencies/string_ops.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,287 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	pragma once | ||||
| #	include "memory.hpp" | ||||
| #endif | ||||
|  | ||||
| #pragma region String Ops | ||||
|  | ||||
| const char* char_first_occurence( const char* str, 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 ); | ||||
|  | ||||
| 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 | ||||
| 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 ); | ||||
|  | ||||
| inline | ||||
| const char* char_first_occurence( const char* s, char c ) | ||||
| { | ||||
| 	char ch = c; | ||||
| 	for ( ; *s != ch; s++ ) | ||||
| 	{ | ||||
| 		if ( *s == '\0' ) | ||||
| 			return NULL; | ||||
| 	} | ||||
| 	return s; | ||||
| } | ||||
|  | ||||
| inline | ||||
| b32 char_is_alpha( char c ) | ||||
| { | ||||
| 	if ( ( c >= 'A' && c <= 'Z' ) || ( c >= 'a' && c <= 'z' ) ) | ||||
| 		return true; | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline | ||||
| b32 char_is_alphanumeric( char c ) | ||||
| { | ||||
| 	return char_is_alpha( c ) || char_is_digit( c ); | ||||
| } | ||||
|  | ||||
| inline | ||||
| b32 char_is_digit( char c ) | ||||
| { | ||||
| 	if ( c >= '0' && c <= '9' ) | ||||
| 		return true; | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| 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; | ||||
| } | ||||
|  | ||||
| inline | ||||
| b32 char_is_space( char c ) | ||||
| { | ||||
| 	if ( c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v' ) | ||||
| 		return true; | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline | ||||
| char char_to_lower( char c ) | ||||
| { | ||||
| 	if ( c >= 'A' && c <= 'Z' ) | ||||
| 		return 'a' + ( c - 'A' ); | ||||
| 	return c; | ||||
| } | ||||
|  | ||||
| inline char char_to_upper( char c ) | ||||
| { | ||||
| 	if ( c >= 'a' && c <= 'z' ) | ||||
| 		return 'A' + ( c - 'a' ); | ||||
| 	return c; | ||||
| } | ||||
|  | ||||
| inline | ||||
| s32 digit_to_int( char c ) | ||||
| { | ||||
| 	return char_is_digit( c ) ? c - '0' : c - 'W'; | ||||
| } | ||||
|  | ||||
| inline | ||||
| s32 hex_digit_to_int( char c ) | ||||
| { | ||||
| 	if ( char_is_digit( c ) ) | ||||
| 		return digit_to_int( c ); | ||||
| 	else if ( is_between( c, 'a', 'f' ) ) | ||||
| 		return c - 'a' + 10; | ||||
| 	else if ( is_between( c, 'A', 'F' ) ) | ||||
| 		return c - 'A' + 10; | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| inline | ||||
| s32 str_compare( const char* s1, const char* s2 ) | ||||
| { | ||||
| 	while ( *s1 && ( *s1 == *s2 ) ) | ||||
| 	{ | ||||
| 		s1++, s2++; | ||||
| 	} | ||||
| 	return *( u8* )s1 - *( u8* )s2; | ||||
| } | ||||
|  | ||||
| inline | ||||
| s32 str_compare_len( const char* s1, const char* s2, ssize len ) | ||||
| { | ||||
| 	for ( ; len > 0; s1++, s2++, len-- ) | ||||
| 	{ | ||||
| 		if ( *s1 != *s2 ) | ||||
| 			return ( ( s1 < s2 ) ? -1 : +1 ); | ||||
| 		else if ( *s1 == '\0' ) | ||||
| 			return 0; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| inline | ||||
| char* str_copy( char* dest, const char* source, ssize len ) | ||||
| { | ||||
| 	GEN_ASSERT_NOT_NULL( dest ); | ||||
| 	if ( source ) | ||||
| 	{ | ||||
| 		char* str = dest; | ||||
| 		while ( len > 0 && *source ) | ||||
| 		{ | ||||
| 			*str++ = *source++; | ||||
| 			len--; | ||||
| 		} | ||||
| 		while ( len > 0 ) | ||||
| 		{ | ||||
| 			*str++ = '\0'; | ||||
| 			len--; | ||||
| 		} | ||||
| 	} | ||||
| 	return dest; | ||||
| } | ||||
|  | ||||
| inline | ||||
| ssize str_copy_nulpad( char* dest, const char* source, ssize len ) | ||||
| { | ||||
| 	ssize result = 0; | ||||
| 	GEN_ASSERT_NOT_NULL( dest ); | ||||
| 	if ( source ) | ||||
| 	{ | ||||
| 		const char* source_start = source; | ||||
| 		char*       str          = dest; | ||||
| 		while ( len > 0 && *source ) | ||||
| 		{ | ||||
| 			*str++ = *source++; | ||||
| 			len--; | ||||
| 		} | ||||
| 		while ( len > 0 ) | ||||
| 		{ | ||||
| 			*str++ = '\0'; | ||||
| 			len--; | ||||
| 		} | ||||
|  | ||||
| 		result = source - source_start; | ||||
| 	} | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| inline | ||||
| ssize str_len( const char* str ) | ||||
| { | ||||
| 	if ( str == NULL ) | ||||
| 	{ | ||||
| 		return 0; | ||||
| 	} | ||||
| 	const char* p = str; | ||||
| 	while ( *str ) | ||||
| 		str++; | ||||
| 	return str - p; | ||||
| } | ||||
|  | ||||
| inline | ||||
| ssize str_len_capped( const char* str, ssize max_len ) | ||||
| { | ||||
| 	const char* end = rcast(const char*, mem_find( str, 0, max_len )); | ||||
| 	if ( end ) | ||||
| 		return end - str; | ||||
| 	return max_len; | ||||
| } | ||||
|  | ||||
| inline | ||||
| char* str_reverse( char* str ) | ||||
| { | ||||
| 	ssize    len  = str_len( str ); | ||||
| 	char* a    = str + 0; | ||||
| 	char* b    = str + len - 1; | ||||
| 	len       /= 2; | ||||
| 	while ( len-- ) | ||||
| 	{ | ||||
| 		swap( *a, *b ); | ||||
| 		a++, b--; | ||||
| 	} | ||||
| 	return str; | ||||
| } | ||||
|  | ||||
| inline | ||||
| char const* str_skip( char const* str, char c ) | ||||
| { | ||||
| 	while ( *str && *str != c ) | ||||
| 	{ | ||||
| 		++str; | ||||
| 	} | ||||
| 	return str; | ||||
| } | ||||
|  | ||||
| inline | ||||
| char const* str_skip_any( char const* str, char const* char_list ) | ||||
| { | ||||
| 	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 ); | ||||
| 	} | ||||
| 	return closest_ptr; | ||||
| } | ||||
|  | ||||
| inline | ||||
| char const* str_trim( char const* str, b32 catch_newline ) | ||||
| { | ||||
| 	while ( *str && char_is_space( *str ) && ( ! catch_newline || ( catch_newline && *str != '\n' ) ) ) | ||||
| 	{ | ||||
| 		++str; | ||||
| 	} | ||||
| 	return str; | ||||
| } | ||||
|  | ||||
| inline | ||||
| void str_to_lower( char* str ) | ||||
| { | ||||
| 	if ( ! str ) | ||||
| 		return; | ||||
| 	while ( *str ) | ||||
| 	{ | ||||
| 		*str = char_to_lower( *str ); | ||||
| 		str++; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| inline | ||||
| void str_to_upper( char* str ) | ||||
| { | ||||
| 	if ( ! str ) | ||||
| 		return; | ||||
| 	while ( *str ) | ||||
| 	{ | ||||
| 		*str = char_to_upper( *str ); | ||||
| 		str++; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| #pragma endregion String Ops | ||||
							
								
								
									
										61
									
								
								base/dependencies/strings.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								base/dependencies/strings.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	pragma once | ||||
| #	include "hashing.cpp" | ||||
| #endif | ||||
|  | ||||
| #pragma region String | ||||
|  | ||||
| String string_make_length( AllocatorInfo allocator, char const* str, ssize length ) | ||||
| { | ||||
| 	ssize const header_size = sizeof( StringHeader ); | ||||
|  | ||||
| 	s32   alloc_size = header_size + length + 1; | ||||
| 	void* allocation = alloc( allocator, alloc_size ); | ||||
|  | ||||
| 	if ( allocation == nullptr ) { | ||||
| 		String null_string = {nullptr}; | ||||
| 		return null_string; | ||||
| 	} | ||||
|  | ||||
| 	StringHeader* | ||||
| 	header = rcast(StringHeader*, allocation); | ||||
| 	header->Allocator = allocator; | ||||
| 	header->Capacity  = length; | ||||
| 	header->Length    = length; | ||||
|  | ||||
| 	String  result = { rcast( char*, allocation) + header_size }; | ||||
|  | ||||
| 	if ( length && str ) | ||||
| 		mem_copy( result, str, length ); | ||||
| 	else | ||||
| 		mem_set( result, 0, alloc_size - header_size ); | ||||
|  | ||||
| 	result[ length ] = '\0'; | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| String string_make_reserve( AllocatorInfo allocator, ssize capacity ) | ||||
| { | ||||
| 	ssize const header_size = sizeof( StringHeader ); | ||||
|  | ||||
| 	s32   alloc_size = header_size + capacity + 1; | ||||
| 	void* allocation = alloc( allocator, alloc_size ); | ||||
|  | ||||
| 	if ( allocation == nullptr ) { | ||||
| 		String null_string = {nullptr}; | ||||
| 		return null_string; | ||||
| 	} | ||||
| 	mem_set( allocation, 0, alloc_size ); | ||||
|  | ||||
| 	StringHeader* | ||||
| 	header            = rcast(StringHeader*, allocation); | ||||
| 	header->Allocator = allocator; | ||||
| 	header->Capacity  = capacity; | ||||
| 	header->Length    = 0; | ||||
|  | ||||
| 	String result = { rcast(char*, allocation) + header_size }; | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| #pragma endregion String | ||||
							
								
								
									
										744
									
								
								base/dependencies/strings.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										744
									
								
								base/dependencies/strings.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,744 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	pragma once | ||||
| #	include "hashing.hpp" | ||||
| #endif | ||||
|  | ||||
| #pragma region Strings | ||||
|  | ||||
| struct StrC; | ||||
|  | ||||
| StrC        to_strc_from_c_str       (char const* bad_string); | ||||
| 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_visualize_whitespace(StrC str, AllocatorInfo allocator); | ||||
|  | ||||
| // Constant string with length. | ||||
| struct StrC | ||||
| { | ||||
| 	ssize       Len; | ||||
| 	char const* Ptr; | ||||
|  | ||||
| #if GEN_COMPILER_CPP | ||||
| 	forceinline operator char const* ()               const { return Ptr; } | ||||
| 	forceinline char const& operator[]( ssize index ) const { return Ptr[index]; } | ||||
|  | ||||
| #if ! GEN_C_LIKE_CPP | ||||
| 	forceinline bool        is_equal            (StrC rhs)                const { return strc_are_equal(* this, rhs); } | ||||
| 	forceinline char const* back                ()                        const { return strc_back(* this); } | ||||
| 	forceinline bool        contains            (StrC substring)          const { return strc_contains(* this, substring); } | ||||
| 	forceinline StrC        duplicate           (AllocatorInfo allocator) const { return strc_duplicate(* this, allocator); } | ||||
| 	forceinline b32         starts_with         (StrC substring)          const { return strc_starts_with(* this, substring); } | ||||
| 	forceinline StrC        visualize_whitespace(AllocatorInfo allocator) const { return strc_visualize_whitespace(* this, allocator); } | ||||
| #endif | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| #define cast_to_strc( str ) * rcast( StrC*, (str) - sizeof(ssize) ) | ||||
|  | ||||
| #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 | ||||
|  | ||||
| inline | ||||
| bool strc_are_equal(StrC lhs, StrC rhs) | ||||
| { | ||||
| 	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; | ||||
| } | ||||
|  | ||||
| // 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. | ||||
| #pragma region String | ||||
| struct StringHeader; | ||||
|  | ||||
| #if GEN_COMPILER_C | ||||
| typedef char* String; | ||||
| #else | ||||
| struct String; | ||||
| #endif | ||||
|  | ||||
| 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); | ||||
|  | ||||
| struct StringHeader { | ||||
| 	AllocatorInfo Allocator; | ||||
| 	ssize         Capacity; | ||||
| 	ssize         Length; | ||||
| }; | ||||
|  | ||||
| #if GEN_COMPILER_CPP | ||||
| 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; } | ||||
|  | ||||
| #if ! GEN_C_LIKE_CPP | ||||
| 	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 | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| 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); } | ||||
|  | ||||
| #if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP | ||||
| 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_COMPILER_CPP && ! GEN_C_LIKE_CPP | ||||
| 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 | ||||
|  | ||||
| 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; | ||||
| } | ||||
|  | ||||
| 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); | ||||
| } | ||||
|  | ||||
| forceinline | ||||
| String string_make_strc(AllocatorInfo allocator, StrC str) { | ||||
| 	return string_make_length(allocator, str.Ptr, str.Len); | ||||
| } | ||||
|  | ||||
| inline | ||||
| String string_fmt(AllocatorInfo allocator, char* buf, ssize buf_size, char const* fmt, ...) { | ||||
| 	va_list va; | ||||
| 	va_start(va, fmt); | ||||
| 	ssize res = str_fmt_va(buf, buf_size, fmt, va) - 1; | ||||
| 	va_end(va); | ||||
|  | ||||
| 	return string_make_length(allocator, buf, res); | ||||
| } | ||||
|  | ||||
| inline | ||||
| String string_fmt_buf(AllocatorInfo allocator, char const* fmt, ...) | ||||
| { | ||||
| 	local_persist thread_local | ||||
| 	PrintF_Buffer buf = struct_init(PrintF_Buffer, {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); | ||||
| } | ||||
|  | ||||
| inline | ||||
| String string_join(AllocatorInfo allocator, char const** parts, ssize num_parts, char const* glue) | ||||
| { | ||||
| 	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) | ||||
| 			string_append_c_str(& result, glue); | ||||
| 	} | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| 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) | ||||
| { | ||||
| 	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; | ||||
|  | ||||
| 		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; | ||||
| } | ||||
|  | ||||
| inline | ||||
| bool string_are_equal_strc(String const lhs, StrC rhs) | ||||
| { | ||||
| 	if (string_length(lhs) != (rhs.Len)) | ||||
| 		return false; | ||||
|  | ||||
| 	for (ssize idx = 0; idx < string_length(lhs); ++idx) | ||||
| 		if (lhs[idx] != rhs.Ptr[idx]) | ||||
| 			return false; | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| 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; | ||||
| } | ||||
|  | ||||
| forceinline | ||||
| char* string_back(String str) { | ||||
| 	return & (str)[string_length(str) - 1]; | ||||
| } | ||||
|  | ||||
| inline | ||||
| bool string_contains_StrC(String const str, StrC substring) | ||||
| { | ||||
| 	StringHeader const* header = rcast(StringHeader const*, scast(char const*, str) - sizeof(StringHeader)); | ||||
|  | ||||
| 	if (substring.Len > header->Length) | ||||
| 		return false; | ||||
|  | ||||
| 	ssize main_len = header->Length; | ||||
| 	ssize sub_len  = substring.Len; | ||||
|  | ||||
| 	for (ssize idx = 0; idx <= main_len - sub_len; ++idx) | ||||
| 	{ | ||||
| 		if (str_compare_len(str + idx, substring.Ptr, sub_len) == 0) | ||||
| 			return true; | ||||
| 	} | ||||
|  | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline | ||||
| bool string_contains_string(String const str, String const substring) | ||||
| { | ||||
| 	StringHeader const* header = rcast(StringHeader const*, scast(char const*, str) - sizeof(StringHeader)); | ||||
|  | ||||
| 	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; | ||||
| 	} | ||||
|  | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| forceinline | ||||
| ssize string_capacity(String const str) { | ||||
| 	StringHeader const* header = rcast(StringHeader const*, scast(char const*, str) - sizeof(StringHeader)); | ||||
| 	return header->Capacity; | ||||
| } | ||||
|  | ||||
| forceinline | ||||
| void string_clear(String str) { | ||||
| 	string_get_header(str)->Length = 0; | ||||
| } | ||||
|  | ||||
| forceinline | ||||
| String string_duplicate(String const str, AllocatorInfo allocator) { | ||||
| 	return string_make_length(allocator, str, string_length(str)); | ||||
| } | ||||
|  | ||||
| forceinline | ||||
| void string_free(String* str) { | ||||
| 	GEN_ASSERT(str != nullptr); | ||||
| 	if (! (* str)) | ||||
| 		return; | ||||
|  | ||||
| 	StringHeader* header = string_get_header(* str); | ||||
| 	allocator_free(header->Allocator, header); | ||||
| } | ||||
|  | ||||
| forceinline | ||||
| StringHeader* string_get_header(String str) { | ||||
| 	return (StringHeader*)(scast(char*, str) - sizeof(StringHeader)); | ||||
| } | ||||
|  | ||||
| forceinline | ||||
| ssize string_length(String const str) | ||||
| { | ||||
| 	StringHeader const* header = rcast(StringHeader const*, scast(char const*, str) - sizeof(StringHeader)); | ||||
| 	return header->Length; | ||||
| } | ||||
|  | ||||
| inline | ||||
| bool string_make_space_for(String* str, char const* to_append, ssize add_len) | ||||
| { | ||||
| 	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; | ||||
|  | ||||
| 		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; | ||||
| } | ||||
|  | ||||
| forceinline | ||||
| b32 string_starts_with_string(String const str, String substring) { | ||||
| 	if (string_length(substring) > string_length(str)) | ||||
| 		return false; | ||||
|  | ||||
| 	b32 result = str_compare_len(str, substring, string_length(substring) - 1) == 0; | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| inline | ||||
| void string_skip_line(String str) | ||||
| { | ||||
| #define current (*scanner) | ||||
| 	char* scanner = str; | ||||
| 	while (current != '\r' && current != '\n') { | ||||
| 		++scanner; | ||||
| 	} | ||||
|  | ||||
| 	s32 new_length = scanner - str; | ||||
|  | ||||
| 	if (current == '\r') { | ||||
| 		new_length += 1; | ||||
| 	} | ||||
|  | ||||
| 	mem_move((char*)str, scanner, new_length); | ||||
|  | ||||
| 	StringHeader* header = string_get_header(str); | ||||
| 	header->Length = new_length; | ||||
| #undef current | ||||
| } | ||||
|  | ||||
| inline | ||||
| void strip_space(String str) | ||||
| { | ||||
| 	char* write_pos = str; | ||||
| 	char* read_pos  = str; | ||||
|  | ||||
| 	while (* read_pos) | ||||
| 	{ | ||||
| 		if (! char_is_space(* read_pos)) | ||||
| 		{ | ||||
|    			* write_pos = * read_pos; | ||||
| 			write_pos++; | ||||
| 		} | ||||
| 		read_pos++; | ||||
| 	} | ||||
|    write_pos[0] = '\0';  // Null-terminate the modified string | ||||
|  | ||||
| 	// Update the length if needed | ||||
| 	string_get_header(str)->Length = write_pos - str; | ||||
| } | ||||
|  | ||||
| forceinline | ||||
| StrC string_to_strc(String str) { | ||||
| 	StrC result = { string_length(str), (char const*)str }; | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| inline | ||||
| void string_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++; | ||||
|  | ||||
| 	while (end_pos > start_pos && char_first_occurence(cut_set, *end_pos)) | ||||
| 	end_pos--; | ||||
|  | ||||
| 	len = scast(ssize, (start_pos > end_pos) ? 0 : ((end_pos - start_pos) + 1)); | ||||
|  | ||||
| 	if (str != start_pos) | ||||
| 		mem_move(str, start_pos, len); | ||||
|  | ||||
| 	str[len] = '\0'; | ||||
|  | ||||
| 	string_get_header(str)->Length = len; | ||||
| } | ||||
|  | ||||
| forceinline | ||||
| void string_trim_space(String str) { | ||||
| 	string_trim(str, " \t\r\n\v\f"); | ||||
| } | ||||
|  | ||||
| inline | ||||
| String string_visualize_whitespace(String const str) | ||||
| { | ||||
| 	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. | ||||
|  | ||||
| 	for (char const* c = string_begin(str); c != string_end(str); c = string_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 result; | ||||
| } | ||||
| #pragma endregion String | ||||
|  | ||||
| #if GEN_COMPILER_CPP | ||||
| struct String_POD { | ||||
| 	char* Data; | ||||
| }; | ||||
| static_assert( sizeof( String_POD ) == sizeof( String ), "String is not a POD" ); | ||||
| #endif | ||||
|  | ||||
| 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. | ||||
| typedef StrC StringCached; | ||||
|  | ||||
| // Implements basic string interning. Data structure is based off the ZPL Hashtable. | ||||
| typedef HashTable(StringCached) StringTable; | ||||
| #pragma endregion Strings | ||||
							
								
								
									
										167
									
								
								base/dependencies/timing.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										167
									
								
								base/dependencies/timing.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,167 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	pragma once | ||||
| #	include "filesystem.cpp" | ||||
| #endif | ||||
|  | ||||
| #pragma region Timing | ||||
|  | ||||
| #ifdef GEN_BENCHMARK | ||||
| 	#if defined( GEN_COMPILER_MSVC ) && ! defined( __clang__ ) | ||||
| 	u64 read_cpu_time_stamp_counter( void ) | ||||
| 	{ | ||||
| 		return __rdtsc(); | ||||
| 	} | ||||
| 	#elif defined( __i386__ ) | ||||
| 	u64 read_cpu_time_stamp_counter( void ) | ||||
| 	{ | ||||
| 		u64 x; | ||||
| 		__asm__ volatile( ".byte 0x0f, 0x31" : "=A"( x ) ); | ||||
| 		return x; | ||||
| 	} | ||||
| 	#elif defined( __x86_64__ ) | ||||
| 	u64 read_cpu_time_stamp_counter( void ) | ||||
| 	{ | ||||
| 		u32 hi, lo; | ||||
| 		__asm__ __volatile__( "rdtsc" : "=a"( lo ), "=d"( hi ) ); | ||||
| 		return scast( u64, lo ) | ( scast( u64, hi ) << 32 ); | ||||
| 	} | ||||
| 	#elif defined( __powerpc__ ) | ||||
| 	u64 read_cpu_time_stamp_counter( void ) | ||||
| 	{ | ||||
| 		u64 result = 0; | ||||
| 		u32 upper, lower, tmp; | ||||
| 		__asm__ volatile( | ||||
| 			"0:                   \n" | ||||
| 			"\tmftbu   %0         \n" | ||||
| 			"\tmftb    %1         \n" | ||||
| 			"\tmftbu   %2         \n" | ||||
| 			"\tcmpw    %2,%0      \n" | ||||
| 			"\tbne     0b         \n" | ||||
| 			: "=r"( upper ), "=r"( lower ), "=r"( tmp ) | ||||
| 		); | ||||
| 		result = upper; | ||||
| 		result = result << 32; | ||||
| 		result = result | lower; | ||||
|  | ||||
| 		return result; | ||||
| 	} | ||||
| 	#elif defined( GEN_SYSTEM_EMSCRIPTEN ) | ||||
| 	u64 read_cpu_time_stamp_counter( void ) | ||||
| 	{ | ||||
| 		return ( u64 )( emscripten_get_now() * 1e+6 ); | ||||
| 	} | ||||
| 	#elif defined( GEN_CPU_ARM ) && ! defined( GEN_COMPILER_TINYC ) | ||||
| 	u64 read_cpu_time_stamp_counter( void ) | ||||
| 	{ | ||||
| 	#	if defined( __aarch64__ ) | ||||
| 		int64_t r = 0; | ||||
| 		asm volatile( "mrs %0, cntvct_el0" : "=r"( r ) ); | ||||
| 	#	elif ( __ARM_ARCH >= 6 ) | ||||
| 		uint32_t r = 0; | ||||
| 		uint32_t pmccntr; | ||||
| 		uint32_t pmuseren; | ||||
| 		uint32_t pmcntenset; | ||||
|  | ||||
| 		// Read the user mode perf monitor counter access permissions. | ||||
| 		asm volatile( "mrc p15, 0, %0, c9, c14, 0" : "=r"( pmuseren ) ); | ||||
| 		if ( pmuseren & 1 ) | ||||
| 		{    // Allows reading perfmon counters for user mode code. | ||||
| 			asm volatile( "mrc p15, 0, %0, c9, c12, 1" : "=r"( pmcntenset ) ); | ||||
| 			if ( pmcntenset & 0x80000000ul ) | ||||
| 			{    // Is it counting? | ||||
| 				asm volatile( "mrc p15, 0, %0, c9, c13, 0" : "=r"( pmccntr ) ); | ||||
| 				// The counter is set up to count every 64th cycle | ||||
| 				return ( ( int64_t )pmccntr ) * 64;    // Should optimize to << 6 | ||||
| 			} | ||||
| 		} | ||||
| 	#	else | ||||
| 	#		error "No suitable method for read_cpu_time_stamp_counter for this cpu type" | ||||
| 	#	endif | ||||
|  | ||||
| 		return r; | ||||
| 	} | ||||
| 	#else | ||||
| 	u64 read_cpu_time_stamp_counter( void ) | ||||
| 	{ | ||||
| 		GEN_PANIC( "read_cpu_time_stamp_counter is not supported on this particular setup" ); | ||||
| 		return -0; | ||||
| 	} | ||||
| 	#endif | ||||
|  | ||||
| 	#if defined( GEN_SYSTEM_WINDOWS ) || defined( GEN_SYSTEM_CYGWIN ) | ||||
|  | ||||
| 	u64 time_rel_ms( void ) | ||||
| 	{ | ||||
| 		local_persist LARGE_INTEGER win32_perf_count_freq = {}; | ||||
| 		u64                         result; | ||||
| 		LARGE_INTEGER               counter; | ||||
| 		local_persist LARGE_INTEGER win32_perf_counter = {}; | ||||
| 		if ( ! win32_perf_count_freq.QuadPart ) | ||||
| 		{ | ||||
| 			QueryPerformanceFrequency( &win32_perf_count_freq ); | ||||
| 			GEN_ASSERT( win32_perf_count_freq.QuadPart != 0 ); | ||||
| 			QueryPerformanceCounter( &win32_perf_counter ); | ||||
| 		} | ||||
|  | ||||
| 		QueryPerformanceCounter( &counter ); | ||||
|  | ||||
| 		result = ( counter.QuadPart - win32_perf_counter.QuadPart ) * 1000 / ( win32_perf_count_freq.QuadPart ); | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	#else | ||||
|  | ||||
| 	#	if defined( GEN_SYSTEM_LINUX ) || defined( GEN_SYSTEM_FREEBSD ) || defined( GEN_SYSTEM_OPENBSD ) || defined( GEN_SYSTEM_EMSCRIPTEN ) | ||||
| 	u64 _unix_gettime( void ) | ||||
| 	{ | ||||
| 		struct timespec t; | ||||
| 		u64             result; | ||||
|  | ||||
| 		clock_gettime( 1 /*CLOCK_MONOTONIC*/, &t ); | ||||
| 		result = 1000 * t.tv_sec + 1.0e-6 * t.tv_nsec; | ||||
| 		return result; | ||||
| 	} | ||||
| 	#	endif | ||||
|  | ||||
| 	u64 time_rel_ms( void ) | ||||
| 	{ | ||||
| 	#	if defined( GEN_SYSTEM_OSX ) | ||||
| 		u64 result; | ||||
|  | ||||
| 		local_persist u64 timebase  = 0; | ||||
| 		local_persist u64 timestart = 0; | ||||
|  | ||||
| 		if ( ! timestart ) | ||||
| 		{ | ||||
| 			mach_timebase_info_data_t tb = { 0 }; | ||||
| 			mach_timebase_info( &tb ); | ||||
| 			timebase   = tb.numer; | ||||
| 			timebase  /= tb.denom; | ||||
| 			timestart  = mach_absolute_time(); | ||||
| 		} | ||||
|  | ||||
| 		// NOTE: mach_absolute_time() returns things in nanoseconds | ||||
| 		result = 1.0e-6 * ( mach_absolute_time() - timestart ) * timebase; | ||||
| 		return result; | ||||
| 	#	else | ||||
| 		local_persist u64 unix_timestart = 0.0; | ||||
|  | ||||
| 		if ( ! unix_timestart ) | ||||
| 		{ | ||||
| 			unix_timestart = _unix_gettime(); | ||||
| 		} | ||||
|  | ||||
| 		u64 now = _unix_gettime(); | ||||
|  | ||||
| 		return ( now - unix_timestart ); | ||||
| 	#	endif | ||||
| 	} | ||||
| 	#endif | ||||
|  | ||||
| 	f64 time_rel( void ) | ||||
| 	{ | ||||
| 		return ( f64 )( time_rel_ms() * 1e-3 ); | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| #pragma endregion Timing | ||||
							
								
								
									
										19
									
								
								base/dependencies/timing.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								base/dependencies/timing.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	pragma once | ||||
| #	include "filesystem.hpp" | ||||
| #endif | ||||
|  | ||||
| #pragma region Timing | ||||
|  | ||||
| #ifdef GEN_BENCHMARK | ||||
| //! Return CPU timestamp. | ||||
| u64 read_cpu_time_stamp_counter( void ); | ||||
|  | ||||
| //! Return relative time (in seconds) since the application start. | ||||
| f64 time_rel( void ); | ||||
|  | ||||
| //! Return relative time since the application start. | ||||
| u64 time_rel_ms( void ); | ||||
| #endif | ||||
|  | ||||
| #pragma endregion Timing | ||||
							
								
								
									
										2
									
								
								base/enums/AttributeTokens.csv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								base/enums/AttributeTokens.csv
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| API_Export, GEN_API_Export_Code | ||||
| API_Import, GEN_API_Import_Code | ||||
| 
 | 
							
								
								
									
										61
									
								
								base/enums/ECodeTypes.csv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								base/enums/ECodeTypes.csv
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | ||||
| Invalid,             "__NA__" | ||||
| Untyped,             "__NA__" | ||||
| NewLine,             "__NA__" | ||||
| Comment,             "//" | ||||
| Access_Private,      "private" | ||||
| Access_Protected,    "protected" | ||||
| Access_Public,       "public" | ||||
| PlatformAttributes,  "__NA__" | ||||
| Class,               "class" | ||||
| Class_Fwd,           "clsss" | ||||
| Class_Body,          "__NA__" | ||||
| Constructor,         "__NA__" | ||||
| Constructor_Fwd,     "__NA__" | ||||
| Destructor,          "__NA__" | ||||
| Destructor_Fwd,      "__NA__" | ||||
| Enum,                "enum" | ||||
| Enum_Fwd,            "enum" | ||||
| Enum_Body,           "__NA__" | ||||
| Enum_Class,          "enum class" | ||||
| Enum_Class_Fwd,      "enum class" | ||||
| Execution,           "__NA__" | ||||
| Export_Body,         "__NA__" | ||||
| Extern_Linkage,      "extern" | ||||
| Extern_Linkage_Body, "extern" | ||||
| Friend,              "friend" | ||||
| Function,            "__NA__" | ||||
| Function_Fwd,        "__NA__" | ||||
| Function_Body,       "__NA__" | ||||
| Global_Body,         "__NA__" | ||||
| Module,              "module" | ||||
| Namespace,           "namespace" | ||||
| Namespace_Body,      "__NA__" | ||||
| Operator,            "operator" | ||||
| Operator_Fwd,        "operator" | ||||
| Operator_Member,     "operator" | ||||
| Operator_Member_Fwd, "operator" | ||||
| Operator_Cast,       "operator" | ||||
| Operator_Cast_Fwd,   "operator" | ||||
| Parameters,          "__NA__" | ||||
| Preprocess_Define,   "define" | ||||
| Preprocess_Include,  "include" | ||||
| Preprocess_If,       "if" | ||||
| Preprocess_IfDef,    "ifdef" | ||||
| Preprocess_IfNotDef, "ifndef" | ||||
| Preprocess_ElIf,     "elif" | ||||
| Preprocess_Else,     "else" | ||||
| Preprocess_EndIf,    "endif" | ||||
| Preprocess_Pragma,   "pragma" | ||||
| Specifiers,          "__NA__" | ||||
| Struct,              "struct" | ||||
| Struct_Fwd,          "struct" | ||||
| Struct_Body,         "__NA__" | ||||
| Template,            "template" | ||||
| Typedef,             "typedef" | ||||
| Typename,            "__NA__" | ||||
| Union,               "union" | ||||
| Union_Fwd,           "union" | ||||
| Union_Body,          "__NA__" | ||||
| Using,               "using" | ||||
| Using_Namespace,     "using namespace" | ||||
| Variable,            "__NA__" | ||||
| 
 | 
							
								
								
									
										144
									
								
								base/enums/ECode_ExecutionSupport.csv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								base/enums/ECode_ExecutionSupport.csv
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,144 @@ | ||||
| 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 | ||||
|  | ||||
| Expression | ||||
|  | ||||
| Expr_Identifier | ||||
| Expr_NumericLiteral | ||||
| Expr_StringLiteral | ||||
|  | ||||
| Expr_Alignof | ||||
| Expr_ProcCall | ||||
|  | ||||
| Expr_Assign_Add | ||||
| Expr_Assign_Subtract | ||||
| Expr_Assign_Multiply | ||||
| Expr_Assign_Divide | ||||
| Expr_Assign_Modulo | ||||
| Expr_Assign_Bitwise_And | ||||
| Expr_Assign_Bitwise_Or | ||||
| Expr_Assign_Bitwise_XOr | ||||
| Expr_Assign_LeftShift | ||||
| Expr_Assign_RightShift | ||||
|  | ||||
| Expr_CStyleCast | ||||
| Expr_FunctionalCast | ||||
| Expr_ConstCast | ||||
| Expr_DynamicCast | ||||
| Expr_ReinterpretCast | ||||
| Expr_StaticCast | ||||
|  | ||||
| Expr_Unary_Add | ||||
| Expr_Unary_Minus | ||||
| Expr_Unary_Not | ||||
| Expr_Unary_Increment | ||||
| Expr_Unary_Decrement | ||||
| Expr_Indirection | ||||
| Expr_AddressOf, | ||||
|  | ||||
| Expr_UnaryPost_Increment | ||||
| Expr_UnaryPost_Decrement | ||||
| Expr_Subscript | ||||
|  | ||||
| Expr_Binary_Add | ||||
| Expr_Binary_Subtract | ||||
| Expr_Binary_Multiply | ||||
| Expr_Binary_Divide | ||||
| Expr_Binary_Modulo | ||||
| Expr_Binary_Bitwise_And | ||||
| Expr_Binary_Bitwise_Or | ||||
| Expr_Binary_Bitwise_XOr | ||||
| Expr_Binary_Bitwise_LeftShift | ||||
| Expr_Binary_Bitwise_RightShift | ||||
| Expr_Binary_Logical_Not | ||||
| Expr_Binary_Logical_And | ||||
| Expr_Binary_Logical_Or | ||||
| Expr_Binary_Equal | ||||
| Expr_Binary_NotEqual | ||||
| Expr_Binary_Lesser | ||||
| Expr_Binary_Greater | ||||
| Expr_Binary_LesserEqual | ||||
| Expr_Binary_GreaterEqual | ||||
| Expr_MemberOfObject, | ||||
| Expr_MemberOfPointer, | ||||
| Expr_PointerToMemberOfObject, | ||||
| Expr_PointerToMemberOfPointer, | ||||
| Expr_Comma, | ||||
| Expr_Tenary, | ||||
|  | ||||
| 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 | ||||
|  | ||||
| Statement | ||||
| Stmt_Break | ||||
| Stmt_Case | ||||
| Stmt_Continue | ||||
| Stmt_Declaration | ||||
| Stmt_Do | ||||
| Stmt_Expr | ||||
| Stmt_Else | ||||
| Stmt_If | ||||
| Stmt_For | ||||
| Stmt_Goto | ||||
| Stmt_Label | ||||
| Stmt_Switch | ||||
| Stmt_Switch | ||||
| Stmt_While | ||||
|  | ||||
| Struct | ||||
| Struct_Fwd | ||||
| Struct_Body | ||||
| Template | ||||
| Typedef | ||||
| Typename | ||||
| Union | ||||
| Union_Body | ||||
| Using | ||||
| Using_Namespace | ||||
| Variable | ||||
| Can't render this file because it has a wrong number of fields in line 56. | 
							
								
								
									
										47
									
								
								base/enums/EOperator.csv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								base/enums/EOperator.csv
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| Invalid,         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,             "new" | ||||
| NewArray,        "new[]" | ||||
| Delete,          "delete" | ||||
| DeleteArray,     "delete[]" | ||||
| 
 | 
							
								
								
									
										26
									
								
								base/enums/ESpecifier.csv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								base/enums/ESpecifier.csv
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| Invalid,          INVALID | ||||
| Consteval,        consteval | ||||
| Constexpr,        constexpr | ||||
| Constinit,        constinit | ||||
| Explicit,         explicit | ||||
| External_Linkage, extern | ||||
| ForceInline, 	  forceinline | ||||
| Global,           global | ||||
| Inline,           inline | ||||
| Internal_Linkage, internal | ||||
| Local_Persist,    local_persist | ||||
| Mutable,          mutable | ||||
| NeverInline,      neverinline | ||||
| Ptr,              * | ||||
| Ref,              & | ||||
| Register,         register | ||||
| RValue,           && | ||||
| Static,           static | ||||
| Thread_Local,     thread_local | ||||
| Virtual,          virtual | ||||
| Const,            const | ||||
| Final,            final | ||||
| NoExceptions,     noexcept | ||||
| Override,         override | ||||
| Pure,             = 0 | ||||
| Volatile,         volatile | ||||
| 
 | 
							
								
								
									
										95
									
								
								base/enums/ETokType.csv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								base/enums/ETokType.csv
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,95 @@ | ||||
| Invalid,                "__invalid__" | ||||
| Access_Private,         "private" | ||||
| Access_Protected,       "protected" | ||||
| Access_Public,          "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__" | ||||
| Comment_End,            "__comment_end__" | ||||
| Comment_Start,          "__comment_start__" | ||||
| Char,                   "__character__" | ||||
| Comma,                  "," | ||||
| Decl_Class,             "class" | ||||
| Decl_GNU_Attribute,     "__attribute__" | ||||
| Decl_MSVC_Attribute,    "__declspec" | ||||
| Decl_Enum,              "enum" | ||||
| Decl_Extern_Linkage,    "extern" | ||||
| Decl_Friend,            "friend" | ||||
| Decl_Module,            "module" | ||||
| Decl_Namespace,         "namespace" | ||||
| Decl_Operator,          "operator" | ||||
| Decl_Struct,            "struct" | ||||
| Decl_Template,          "template" | ||||
| Decl_Typedef,           "typedef" | ||||
| Decl_Using,             "using" | ||||
| Decl_Union,             "union" | ||||
| Identifier,             "__identifier__" | ||||
| Module_Import,          "import" | ||||
| Module_Export,          "export" | ||||
| NewLine,                "__new_line__" | ||||
| Number,                 "__number__" | ||||
| Operator,               "__operator__" | ||||
| Preprocess_Hash,        "#" | ||||
| Preprocess_Define,      "define" | ||||
| Preprocess_If,          "if" | ||||
| Preprocess_IfDef,       "ifdef" | ||||
| Preprocess_IfNotDef,    "ifndef" | ||||
| Preprocess_ElIf,        "elif" | ||||
| Preprocess_Else,        "else" | ||||
| Preprocess_EndIf,       "endif" | ||||
| Preprocess_Include,     "include" | ||||
| Preprocess_Pragma,      "pragma" | ||||
| Preprocess_Content,	    "__macro_content__" | ||||
| Preprocess_Macro,       "__macro__" | ||||
| Preprocess_Unsupported, "__unsupported__" | ||||
| Spec_Alignas,           "alignas" | ||||
| Spec_Const,             "const" | ||||
| Spec_Consteval,         "consteval" | ||||
| Spec_Constexpr,         "constexpr" | ||||
| Spec_Constinit,         "constinit" | ||||
| Spec_Explicit,          "explicit" | ||||
| Spec_Extern,            "extern" | ||||
| Spec_Final,             "final" | ||||
| Spec_ForceInline,	    "forceinline" | ||||
| Spec_Global,            "global" | ||||
| Spec_Inline,            "inline" | ||||
| Spec_Internal_Linkage,  "internal" | ||||
| Spec_LocalPersist,      "local_persist" | ||||
| Spec_Mutable,           "mutable" | ||||
| Spec_NeverInline,       "neverinline" | ||||
| Spec_Override,          "override" | ||||
| Spec_Static,            "static" | ||||
| Spec_ThreadLocal,       "thread_local" | ||||
| Spec_Volatile,          "volatile" | ||||
| Spec_Virtual,           "virtual" | ||||
| Star,                   "*" | ||||
| Statement_End,          ";" | ||||
| StaticAssert,           "static_assert" | ||||
| String,                 "__string__" | ||||
| Type_Typename,          "typename" | ||||
| Type_Unsigned,          "unsigned" | ||||
| Type_Signed,            "signed" | ||||
| Type_Short,             "short" | ||||
| Type_Long,              "long" | ||||
| Type_bool,              "bool" | ||||
| Type_char,              "char" | ||||
| Type_int,               "int" | ||||
| Type_double,            "double" | ||||
| Type_MS_int8,           "__int8" | ||||
| Type_MS_int16,          "__int16" | ||||
| Type_MS_int32,          "__int32" | ||||
| Type_MS_int64,          "__int64" | ||||
| Type_MS_W64,            "_W64" | ||||
| Varadic_Argument,       "..." | ||||
| __Attributes_Start,     "__attrib_start__" | ||||
| 
 | 
							
								
								
									
										183
									
								
								base/enums/ETokType_ExecutionSupport.csv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										183
									
								
								base/enums/ETokType_ExecutionSupport.csv
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,183 @@ | ||||
| Invalid,                "__invalid__" | ||||
| Access_Private,         "private" | ||||
| Access_Protected,       "protected" | ||||
| Access_Public,          "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__" | ||||
| Comment_End,            "__comment_end__" | ||||
| Comment_Start,          "__comment_start__" | ||||
| Char,                   "__character__" | ||||
| Comma,                  "," | ||||
|  | ||||
| Decl_Class,             "class" | ||||
| Decl_Default            "default" | ||||
| Decl_GNU_Attribute,     "__attribute__" | ||||
| Decl_MSVC_Attribute,    "__declspec" | ||||
| Decl_Enum,              "enum" | ||||
| Decl_Extern_Linkage,    "extern" | ||||
| Decl_Friend,            "friend" | ||||
| Decl_Module,            "module" | ||||
| Decl_Namespace,         "namespace" | ||||
| Decl_Operator,          "operator" | ||||
| Decl_Struct,            "struct" | ||||
| Decl_Template,          "template" | ||||
|  | ||||
| Decl_Type,              "decltype" | ||||
|  | ||||
| Decl_Typedef,           "typedef" | ||||
| Decl_Using,             "using" | ||||
| Decl_Union,             "union" | ||||
|  | ||||
| Expr_AlignOf,           "alignof" | ||||
|  | ||||
|  | ||||
| Identifier,             "__identifier__" | ||||
|  | ||||
| Module_Import,          "import" | ||||
| Module_Export,          "export" | ||||
|  | ||||
| NewLine,                "__new_line__" | ||||
|  | ||||
| Number,                 "__number__" | ||||
|  | ||||
| Operator,               "__operator__" | ||||
|  | ||||
| Op_Assign,                    "=" | ||||
| Op_Assign_Add,                "+=" | ||||
| Op_Assign_Subtract,           "-=" | ||||
| Op_Assign_Multiply,           "*=" | ||||
| Op_Assign_Divide,             "/=" | ||||
| Op_Assign_Modulo,             "%=" | ||||
| Op_Assign_Bitwise_And,        "&=" | ||||
| Op_Assign_Bitwise_Or,         "|=" | ||||
| Op_Assign_Bitwise_XOr,        "^=" | ||||
| Op_Assign_Bitwise_LeftShift,  "<<=" | ||||
| Op_Assign_Bitwise_RightShift, ">>=" | ||||
|  | ||||
| Op_Increment, "++" | ||||
| Op_Decrement, "--" | ||||
|  | ||||
| Op_Add,                 "+" | ||||
| Op_Subtract,            "-" | ||||
| Op_Multiply,            "*" | ||||
| Op_Divide,              "/" | ||||
| Op_Modulo,              "%" | ||||
|  | ||||
| Op_Bitwise_And,         "&" | ||||
| Op_Bitwise_Or,          "|" | ||||
| Op_Bitwise_XOr,         "^" | ||||
| Op_Bitwise_LeftShitf,   "<<" | ||||
| Op_Bitwise_RightShift,  ">>" | ||||
|  | ||||
| Op_UnaryAdd,            "+" | ||||
| Op_UnaryMinus,          "-" | ||||
| Op_UnaryNot,            "~" | ||||
|  | ||||
| Op_Logical_Not,         "!" | ||||
| Op_Logical_And,         "&&" | ||||
| Op_Logical_Or,          "||" | ||||
|  | ||||
| Op_Equal,               "==" | ||||
| Op_NotEqual,            "!=" | ||||
| Op_Lesser,              "<" | ||||
| Op_Greater,             ">" | ||||
| Op_LesserEqual,         "<=" | ||||
| Op_GreaterEqual",       ">= | ||||
|  | ||||
| Op_Subscript,                "[]" | ||||
| Op_Indirection,              "*" | ||||
| Op_AddressOf,                "&" | ||||
| Op_MemberOfObject,           "." | ||||
| Op_MemberOfPointer",         "->" | ||||
| Op_PointerToMemberOfObject,  ".*" | ||||
| Op_PointerToMemberOfPointer, "->*" | ||||
|  | ||||
| Op_Comma,                    "," | ||||
| Op_Ternary,                  "?" | ||||
|  | ||||
| Preprocess_Hash,        "#" | ||||
| Preprocess_Define,      "define" | ||||
| Preprocess_If,          "if" | ||||
| Preprocess_IfDef,       "ifdef" | ||||
| Preprocess_IfNotDef,    "ifndef" | ||||
| Preprocess_ElIf,        "elif" | ||||
| Preprocess_Else,        "else" | ||||
| Preprocess_EndIf,       "endif" | ||||
| Preprocess_Include,     "include" | ||||
| Preprocess_Pragma,      "pragma" | ||||
| Preprocess_Content,	    "__macro_content__" | ||||
| Preprocess_Macro,       "__macro__" | ||||
| Preprocess_Generic,     "_Generic" | ||||
| Preprocess_Unsupported, "__unsupported__" | ||||
|  | ||||
| Spec_Alignof,           "alignof" | ||||
| Spec_Const,             "const" | ||||
| Spec_Consteval,         "consteval" | ||||
| Spec_Constexpr,         "constexpr" | ||||
| Spec_Constinit,         "constinit" | ||||
| Spec_Explicit,          "explicit" | ||||
| Spec_Extern,            "extern" | ||||
| Spec_Final,             "final" | ||||
| Spec_ForceInline,	    "forceinline" | ||||
| Spec_Global,            "global" | ||||
| Spec_Inline,            "inline" | ||||
| Spec_Internal_Linkage,  "internal" | ||||
| Spec_LocalPersist,      "local_persist" | ||||
| Spec_Mutable,           "mutable" | ||||
| Spec_NeverInline,       "neverinline" | ||||
| Spec_Override,          "override" | ||||
| Spec_Static,            "static" | ||||
| Spec_ThreadLocal,       "thread_local" | ||||
| Spec_Volatile,          "volatile" | ||||
| Spec_Virtual,           "virtual" | ||||
|  | ||||
| Star,                   "*" | ||||
|  | ||||
| Stmt_Break,             "break" | ||||
| Stmt_Case,              "case" | ||||
| Stmt_Continue,          "continue" | ||||
| Stmt_Default,           "default" | ||||
| Stmt_Do,                "do" | ||||
| Stmt_Else,              "else" | ||||
| Stmt_End,               ";" | ||||
| Stmt_If,                "if" | ||||
| Stmt_For,               "for" | ||||
| Stmt_Goto,              "goto" | ||||
| Stmt_Return,            "return" | ||||
| Stmt_Switch,            "switch" | ||||
| Stmt_While,             "while" | ||||
|  | ||||
| StaticAssert,           "static_assert" | ||||
| String,                 "__string__" | ||||
|  | ||||
| Type_Auto,              "auto" | ||||
| Type_Unsigned,          "unsigned" | ||||
| Type_Signed,            "signed" | ||||
| Type_Short,             "short" | ||||
| Type_Long,              "long" | ||||
| Type_bool,              "bool" | ||||
| Type_char,              "char" | ||||
| Type_int,               "int" | ||||
| Type_float,             "float" | ||||
| Type_double,            "double" | ||||
| Type_MS_int8,           "__int8" | ||||
| Type_MS_int16,          "__int16" | ||||
| Type_MS_int32,          "__int32" | ||||
| Type_MS_int64,          "__int64" | ||||
| Type_MS_W64,            "_W64" | ||||
|  | ||||
| Varadic_Argument,       "..." | ||||
|  | ||||
| __Attributes_Start,     "__attrib_start__" | ||||
| Can't render this file because it contains an unexpected character in line 25 and column 25. | 
							
								
								
									
										43
									
								
								base/gen.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								base/gen.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| #include "helpers/push_ignores.inline.hpp" | ||||
|  | ||||
| // ReSharper disable CppClangTidyClangDiagnosticSwitchEnum | ||||
|  | ||||
| #if ! defined(GEN_DONT_ENFORCE_GEN_TIME_GUARD) && ! defined(GEN_TIME) | ||||
| #	error Gen.hpp : GEN_TIME not defined | ||||
| #endif | ||||
|  | ||||
| #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 | ||||
| #	include "gen.dep.cpp" | ||||
| #endif | ||||
|  | ||||
| GEN_NS_BEGIN | ||||
|  | ||||
| #include "components/static_data.cpp" | ||||
|  | ||||
| #include "components/ast_case_macros.cpp" | ||||
| #include "components/ast.cpp" | ||||
| #include "components/code_serialization.cpp" | ||||
|  | ||||
| #include "components/interface.cpp" | ||||
| #include "components/interface.upfront.cpp" | ||||
| #include "components/gen/etoktype.cpp" | ||||
| #include "components/lexer.cpp" | ||||
| #include "components/parser.cpp" | ||||
| #include "components/interface.parsing.cpp" | ||||
| #include "components/interface.untyped.cpp" | ||||
|  | ||||
| GEN_NS_END | ||||
|  | ||||
| #include "helpers/pop_container_defines.inline.hpp" | ||||
| #include "helpers/pop_ignores.inline.hpp" | ||||
							
								
								
									
										17
									
								
								base/gen.dep.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								base/gen.dep.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| // This file is intended to be included within gen.cpp (There is no pragma diagnostic ignores) | ||||
| #include "gen.dep.hpp" | ||||
|  | ||||
| #include "dependencies/src_start.cpp" | ||||
|  | ||||
| GEN_NS_BEGIN | ||||
|  | ||||
| #include "dependencies/debug.cpp" | ||||
| #include "dependencies/string_ops.cpp" | ||||
| #include "dependencies/printing.cpp" | ||||
| #include "dependencies/memory.cpp" | ||||
| #include "dependencies/hashing.cpp" | ||||
| #include "dependencies/strings.cpp" | ||||
| #include "dependencies/filesystem.cpp" | ||||
| #include "dependencies/timing.cpp" | ||||
|  | ||||
| GEN_NS_END | ||||
							
								
								
									
										20
									
								
								base/gen.dep.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								base/gen.dep.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| // This file is intended to be included within gen.hpp (There is no pragma diagnostic ignores) | ||||
| #pragma once | ||||
|  | ||||
| #include "dependencies/platform.hpp" | ||||
|  | ||||
| GEN_NS_BEGIN | ||||
|  | ||||
| #include "dependencies/macros.hpp" | ||||
| #include "dependencies/basic_types.hpp" | ||||
| #include "dependencies/debug.hpp" | ||||
| #include "dependencies/memory.hpp" | ||||
| #include "dependencies/string_ops.hpp" | ||||
| #include "dependencies/printing.hpp" | ||||
| #include "dependencies/containers.hpp" | ||||
| #include "dependencies/hashing.hpp" | ||||
| #include "dependencies/strings.hpp" | ||||
| #include "dependencies/filesystem.hpp" | ||||
| #include "dependencies/timing.hpp" | ||||
|  | ||||
| GEN_NS_END | ||||
							
								
								
									
										40
									
								
								base/gen.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								base/gen.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| /* | ||||
| 	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 | ||||
| */ | ||||
| #pragma once | ||||
|  | ||||
| #include "helpers/push_ignores.inline.hpp" | ||||
| #include "components/header_start.hpp" | ||||
|  | ||||
| // Has container defines pushed | ||||
| #include "gen.dep.hpp" | ||||
|  | ||||
| GEN_NS_BEGIN | ||||
|  | ||||
| #include "components/types.hpp" | ||||
| #include "components/gen/ecode.hpp" | ||||
| #include "components/gen/eoperator.hpp" | ||||
| #include "components/gen/especifier.hpp" | ||||
|  | ||||
| #include "components/ast.hpp" | ||||
| #include "components/code_types.hpp" | ||||
| #include "components/ast_types.hpp" | ||||
|  | ||||
| #include "components/interface.hpp" | ||||
|  | ||||
| #include "components/inlines.hpp" | ||||
| #include "components/gen/ast_inlines.hpp" | ||||
| #include "components/header_end.hpp" | ||||
|  | ||||
| #include "auxillary/builder.hpp" | ||||
| #include "auxillary/scanner.hpp" | ||||
|  | ||||
| GEN_NS_END | ||||
|  | ||||
| #include "helpers/pop_container_defines.inline.hpp" | ||||
| #include "helpers/pop_ignores.inline.hpp" | ||||
							
								
								
									
										423
									
								
								base/gencpp.refactor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										423
									
								
								base/gencpp.refactor
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,423 @@ | ||||
|  __VERSION 1 | ||||
|  | ||||
| // This is a example template to be used with the refactor program | ||||
| // Use it to refactor the naming convention of this library to your own. | ||||
| // Can be used as an aid to help use use your project's implementation if it fullfills the dependencies of this project. | ||||
| // Example: Most likely have a memory and string library already, just rename the functions and make sure the args are the same. | ||||
| // Program: https://github.com/Ed94/refactor | ||||
|  | ||||
| // NOTE: Due to the current limitations of the program, not every symbol in the library can be renamed. | ||||
| // This is due to the program not actually parsing C/C++. | ||||
|  | ||||
| // not       : Ignore | ||||
| // include   : #includes | ||||
| // word      : Alphanumeric or underscore | ||||
| // namespace : Prefix search and replace (c-namspaces). | ||||
| // regex     : Unavailable in __VERSION 1. | ||||
|  | ||||
| // Precedence (highest to lowest): | ||||
| // word, namespace, regex | ||||
|  | ||||
| // TODO(ED): THIS IS VERY OUTDATED | ||||
|  | ||||
| // Gen Macro namespace | ||||
| // namespace GEN_, new_namespace_ | ||||
|  | ||||
| // ---------- Dependency Macros | ||||
|     // Platform | ||||
| // word GEN_ARCH_64_BIT, new_name | ||||
| // word GEN_ARCH_32_BIT, new_name | ||||
|  | ||||
| // word GEN_SYSTEM_ANDROID,    new_name | ||||
| // word GEN_SYSTEM_CYGWIN,     new_name | ||||
| // word GEN_SYSTEM_EMSCRIPTEN, new_name | ||||
| // word GEN_SYSTEM_FREEBSD,    new_name | ||||
| // word GEN_SYSTEM_IOS,	       new_name | ||||
| // word GEN_SYSTEM_LINUX,      new_name | ||||
| // word GEN_SYSTEM_MACOS,      new_name | ||||
| // word GEN_SYSTEM_OPENBSD,    new_name | ||||
| // word GEN_SYSTEM_OSX,        new_name | ||||
| // word GEN_SYSTEM_UNIX,       new_name | ||||
| // word GEN_SYSTEM_WINDOWS,    new_name | ||||
|  | ||||
| // word GEN_COMPILER_CLANG, new_name | ||||
| // word GEN_COMPILER_GCC,   new_name | ||||
| // word GEN_COMPILER_MINGW, new_name | ||||
| // word GEN_COMPILER_MSVC,  new_name | ||||
|  | ||||
| // word global,        new_name | ||||
| // word internal,      new_name | ||||
| // word local_persist, new_name | ||||
| // word forceinline,   new_name | ||||
| // word neverinline,   new_name | ||||
|  | ||||
| // word bit,               new_name | ||||
| // word bitfield_is_equal, new_name | ||||
|  | ||||
| // word ccast, new_name | ||||
| // word pcast, new_name | ||||
| // word rcast, new_name | ||||
| // word scast, new_name | ||||
|  | ||||
| // word num_args,      new_name | ||||
| // word num_args_impl, new_name | ||||
|  | ||||
| // word stringize,    new_name | ||||
| // word stringize_va, new_name | ||||
|  | ||||
| // word do_once,           new_name | ||||
| // word do_once_start,     new_name | ||||
| // word do_once_end,       new_name | ||||
| // word label_scope_start, new_name | ||||
| // word label_scope_end,   new_name | ||||
|  | ||||
| // word count_of,   new_name | ||||
| // word is_between, new_name | ||||
| // word min,        new_name | ||||
| // word size_of,    new_name | ||||
| // word offset_of,  new_name | ||||
| // word swap,       new_name | ||||
|  | ||||
|     // Basic Types | ||||
| // word GEN_U8_MIN, new_name | ||||
| // word GEN_U8_MAX, new_name | ||||
| // word GEN_I8_MIN, new_name | ||||
| // word GEN_I8_MAX, new_name | ||||
|  | ||||
| // word GEN_U16_MIN, new_name | ||||
| // word GEN_U16_MAX, new_name | ||||
| // word GEN_I16_MIN, new_name | ||||
| // word GEN_I16_MAX, new_name | ||||
|  | ||||
| // word GEN_U32_MIN, new_name | ||||
| // word GEN_U32_MAX, new_name | ||||
| // word GEN_I32_MIN, new_name | ||||
| // word GEN_I32_MAX, new_name | ||||
|  | ||||
| // word GEN_U64_MIN, new_name | ||||
| // word GEN_U64_MAX, new_name | ||||
| // word GEN_I64_MIN, new_name | ||||
| // word GEN_I64_MAX, new_name | ||||
|  | ||||
| // word GEN_USIZE_MIN, new_name | ||||
| // word GEN_USIZE_MAX, new_name | ||||
| // word GEN_ISIZE_MIN, new_name | ||||
| // word GEN_ISIZE_MAX, new_name | ||||
|  | ||||
| // word GEN_F32_MIN, new_name | ||||
| // word GEN_F32_MAX, new_name | ||||
| // word GEN_F64_MIN, new_name | ||||
| // word GEN_F64_MAX, new_name | ||||
|  | ||||
|     // Debug | ||||
| // word GEN_DEBUG_TRAP,      new_name | ||||
| // word GEN_ASSERT,          new_name | ||||
| // word GEN_ASSERT_MSG,      new_name | ||||
| // word GEN_ASSERT_NOT_NULL, new_name | ||||
| // word GEN_PANIC,           new_name | ||||
| // word GEN_FATAL,           new_name | ||||
|  | ||||
|     // Memory | ||||
| // word kilobytes, new_name | ||||
| // word megabytes, new_name | ||||
| // word gigabytes, new_name | ||||
| // word terabytes, new_name | ||||
|  | ||||
| // word zero_item,  new_name | ||||
| // word zero_array, new_name | ||||
|  | ||||
| // word alloc_item,  new_name | ||||
| // word alloc_array, new_name | ||||
|  | ||||
| // word malloc, new_name | ||||
| // word mfree,  new_name | ||||
|  | ||||
|     // Strings | ||||
| // word txt, new_name | ||||
| // word cast_to_strc, new_name | ||||
|  | ||||
| // ---------- Dependency Types | ||||
|  | ||||
| // word b8,   new_name | ||||
| // word b16,  new_name | ||||
| // word b32,  new_name | ||||
| // word s8,   new_name | ||||
| // word s16,  new_name | ||||
| // word s32,  new_name | ||||
| // word s64,  new_name | ||||
| // word u8,   new_name | ||||
| // word u16,  new_name | ||||
| // word u32,  new_name | ||||
| // word u64,  new_name | ||||
| // word usize,   new_name | ||||
| // word ssize,   new_name | ||||
| // word sptr, new_name | ||||
| // word uptr, new_name | ||||
| // word f32,  new_name | ||||
| // word f64,  new_name | ||||
|  | ||||
| // namespace EAllocator_, new_namespace_ | ||||
| // namespace EFileMode_,  new_namespace_ | ||||
| // namespace EFileError_, new_namespace_ | ||||
|  | ||||
| // word AllocatorInfo,    new_name | ||||
| // word AllocatorProc,    new_name | ||||
| // word AllocFlag,        new_name | ||||
| // word AllocType,        new_name | ||||
| // word ArrayHeader,      new_name | ||||
| // word DirEntry,         new_name | ||||
| // word DirInfo,          new_name | ||||
| // word DirType,          new_name | ||||
| // word FileDescriptor,   new_name | ||||
| // word FileError,        new_name | ||||
| // word FileInfo,         new_name | ||||
| // word FileTime,         new_name | ||||
| // word FileModeFlag,     new_name | ||||
| // word FileOperations,   new_name | ||||
| // word FileStandardType, new_name | ||||
| // word SeekWhenceType,   new_name | ||||
|  | ||||
| // ---------- Dependency Data | ||||
|  | ||||
| // word default_file_operations, new_name | ||||
|  | ||||
| // ---------- Dependency Procedures | ||||
|  | ||||
| // word align_forward,          new_name | ||||
| // word align_fordward_i64,     new_name | ||||
| // word alloc,                  new_name | ||||
| // word alloc_align,            new_name | ||||
| // word assert_handler,         new_name | ||||
| // word assert_crash,           new_name | ||||
| // word char_first_occurence,   new_name | ||||
| // word char_is_alpha,          new_name | ||||
| // word char_is_alphanumeric,   new_name | ||||
| // word char_is_digit,          new_name | ||||
| // word char_is_hex_digit,      new_name | ||||
| // word char_is_space,          new_name | ||||
| // word char_to_lower,		    new_name | ||||
| // word char_to_upper,		    new_name | ||||
| // word crc32,                  new_name | ||||
| // word default_resize_align,   new_name | ||||
| // word digit_to_int,		    new_name | ||||
| // word file_close,  		    new_name | ||||
| // word file_get_standard,      new_name | ||||
| // word file_name,              new_name | ||||
| // word file_open,              new_name | ||||
| // word file_open_mode,         new_name | ||||
| // word file_seek, 			    new_name | ||||
| // word file_tell, 			    new_name | ||||
| // word file_write, 		    new_name | ||||
| // word file_write_at, 		    new_name | ||||
| // word file_write_at_check,    new_name | ||||
| // word free,                   new_name | ||||
| // word free_all,               new_name | ||||
| // word heap,                   new_name | ||||
| // word heap_allocator_proc,    new_name | ||||
| // word heap_stats_check,       new_name | ||||
| // word heap_stats_alloc_count, new_name | ||||
| // word heap_stats_init,        new_name | ||||
| // word heap_stats_used_memory, new_name | ||||
| // word hex_digit_to_int,	    new_name | ||||
| // word i64_to_str,			    new_name | ||||
| // word is_power_of_two,        new_name | ||||
| // word log_fmt,                new_name | ||||
| // word mem_copy,               new_name | ||||
| // word mem_move,               new_name | ||||
| // word mem_set,                new_name | ||||
| // word pointer_add,            new_name | ||||
| // word mem_copy,               new_name | ||||
| // word mem_find,               new_name | ||||
| // word mem_move,               new_name | ||||
| // word mem_set,                new_name | ||||
| // word resize,                 new_name | ||||
| // word resize_align,           new_name | ||||
| // word process_exit,           new_name | ||||
| // word str_compare,            new_name | ||||
| // word str_copy,               new_name | ||||
| // word str_copy_nulpad, 	    new_name | ||||
| // word str_fmt_buf,            new_name | ||||
| // word str_fmt_buf_va,	        new_name | ||||
| // word str_fmt_file_va,        new_name | ||||
| // word str_fmt_out_va,         new_name | ||||
| // word str_fmt_out_err,        new_name | ||||
| // word str_fmt_out_err_va,	    new_name | ||||
| // word str_fmt_va,             new_name | ||||
| // word str_len,                new_name | ||||
| // word str_reverse, 		    new_name | ||||
| // word str_to_i64, 		    new_name | ||||
| // word str_to_lower, 		    new_name | ||||
| // word str_to_upper,  	        new_name | ||||
| // word u64_to_str, 		    new_name | ||||
| // word zero_size,              new_name | ||||
|  | ||||
| // ---------- gencpp Macros | ||||
|  | ||||
| // word log_failure, new_name | ||||
|  | ||||
| // word NullCode,      new_name | ||||
| // word CodeInvalid, new_name | ||||
|  | ||||
| // ------------ gencpp common | ||||
|  | ||||
| // word Arena,     new_name | ||||
| // word Array,     new_name | ||||
| // word HashTable, new_name | ||||
| // word Pool,      new_name | ||||
| // word StrC,      new_name | ||||
| // word String,    new_name | ||||
|  | ||||
| // word to_str,  new_name | ||||
| // word to_str,  new_name | ||||
| // word to_type, new_name | ||||
|  | ||||
| // ------------ gencpp Types & Constants | ||||
|  | ||||
| // word LogFailType, new_name | ||||
|  | ||||
| // word AccessSpec,     new_name | ||||
| // word ECode,          new_name | ||||
| // word EnumClass,      new_name | ||||
| // word EnumRegular,    new_name | ||||
| // word EnumT,          new_name | ||||
| // word EOperator,      new_name | ||||
| // word ESpecifier,     new_name | ||||
| // word OperatorT,      new_name | ||||
| // word ModuleFlag,     new_name | ||||
| // word SpecifierT,     new_name | ||||
| // word StringCached,   new_name | ||||
| // word StringTable,    new_name | ||||
| // word UsingRegular,   new_name | ||||
| // word UsingNamespace, new_name | ||||
|  | ||||
| // ------------ gencpp Data | ||||
|  | ||||
| // word API_Export,   new_name | ||||
| // word API_Import,   new_name | ||||
| // word AST_POD_Size, new_name | ||||
| // word AST,          new_name | ||||
| // word AST_POD,      new_name | ||||
| // word Code,         new_name | ||||
| // word Code_POD,     new_name | ||||
| // word Keyword,      new_name | ||||
|  | ||||
| // ------------ gencpp API | ||||
|  | ||||
| // word init,                             new_name | ||||
| // word deinit,                           new_name | ||||
|  | ||||
| // word get_cached_string,                new_name | ||||
| // word make_code,                        new_name | ||||
| // word make_code_entries,                new_name | ||||
|  | ||||
| // word set_allocator_data_arrays,        new_name | ||||
| // word set_allocator_code_pool,          new_name | ||||
| // word set_allocator_code_entries_arena, new_name | ||||
| // word set_allocator_string_arena,       new_name | ||||
| // word set_allocator_string_table,       new_name | ||||
| // word set_allocator_type_table,         new_name | ||||
|  | ||||
| // ------------ upfront constructor namespace | ||||
| // namespace def_ new_namespace_ | ||||
|  | ||||
| // ------------ upfront constructor individual | ||||
|  | ||||
| // word def_attributes,      new_name | ||||
| // word def_comment,         new_name | ||||
| // word def_class,           new_name | ||||
| // word def_constructor,     new_name | ||||
| // word def_destructor,      new_name | ||||
| // word def_define,          new_name | ||||
| // word def_enum,            new_name | ||||
| // word def_execution,       new_name | ||||
| // word def_extern_link,     new_name | ||||
| // word def_friend,          new_name | ||||
| // word def_function,        new_name | ||||
| // word def_include,         new_name | ||||
| // word def_module,          new_name | ||||
| // word def_namespace,       new_name | ||||
| // word def_operator,        new_name | ||||
| // word def_operator_cast,   new_name | ||||
| // word def_param,           new_name | ||||
| // word def_pargma,          new_name | ||||
| // word def_preprocess_cond, new_name | ||||
| // word def_specifier,       new_name | ||||
| // word def_struct,          new_name | ||||
| // word def_template,        new_name | ||||
| // word def_type,            new_name | ||||
| // word def_typedef,         new_name | ||||
| // word def_union,           new_name | ||||
| // word def_using,           new_name | ||||
| // word def_using_namespace, new_name | ||||
| // word def_variable,        new_name | ||||
|  | ||||
| // word def_body,             new_name | ||||
| // word def_class_body,       new_name | ||||
| // word def_enum_body,        new_name | ||||
| // word def_export_body,      new_name | ||||
| // word def_extern_link_body, new_name | ||||
| // word def_function_body,    new_name | ||||
| // word def_global_body,      new_name | ||||
| // word def_namespace_body,   new_name | ||||
| // word def_params,           new_name | ||||
| // word def_specifiers,       new_name | ||||
| // word def_struct_body,      new_name | ||||
| // word def_union_body,       new_name | ||||
|  | ||||
| // ------------ parse constructor namespace | ||||
| // namespace parse_, new_namespace_ | ||||
|  | ||||
| // ------------ parse constructor individual | ||||
|  | ||||
| // word parse_class,       new_name | ||||
| // word parse_enum,        new_name | ||||
| // word parse_export_body, new_name | ||||
| // word parse_extern_link, new_name | ||||
| // word parse_friend,      new_name | ||||
| // word parse_function,    new_name | ||||
| // word parse_global_body, new_name | ||||
| // word parse_namespace,   new_name | ||||
| // word parse_operator,    new_name | ||||
| // word parse_struct,      new_name | ||||
| // word parse_template,    new_name | ||||
| // word parse_type,        new_name | ||||
| // word parse_typedef,     new_name | ||||
| // word parse_union,       new_name | ||||
| // word parse_using,       new_name | ||||
| // word parse_variable,    new_name | ||||
|  | ||||
| // ------------ untyped constructor namespace | ||||
| // namespace untyped_, new_namespace_ | ||||
|  | ||||
| // ------------ untyped constructor individual | ||||
|  | ||||
| // word token_fmt_impl,    new_name | ||||
| // word token_fmt_va,      new_name | ||||
| // word untyped_str,       new_name | ||||
| // word untyped_fmt,       new_name | ||||
| // word untyped_token_fmt, new_name | ||||
|  | ||||
| // ------------ File Ops | ||||
|  | ||||
| // word Builder, new_name | ||||
| // word Editor,  new_name | ||||
| // word Scanner, new_name | ||||
|  | ||||
| // ------------ gencpp user macros | ||||
|  | ||||
| // word gen_main,     new_name | ||||
| // word GEN_TIME,     new_name | ||||
|  | ||||
| // word __,        new_name | ||||
| // word name,      new_name | ||||
| // word code,      new_name | ||||
| // word args,      new_name | ||||
| // word code_str,  new_name | ||||
| // word code_fmt,  new_name | ||||
| // word token_fmt, new_name | ||||
|  | ||||
| // ------------ Type AST namespace | ||||
| // namespace t_, new_namespace_ | ||||
|  | ||||
| // ------------ Specifier AST namespace | ||||
| // namespace spec_, new_namespace_ | ||||
							
								
								
									
										685
									
								
								base/helpers/base_codegen.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										685
									
								
								base/helpers/base_codegen.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,685 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "gen.hpp" | ||||
|  | ||||
| using namespace gen; | ||||
|  | ||||
| #include "dependencies/parsing.hpp" | ||||
| #include "misc.hpp" | ||||
|  | ||||
| CodeBody gen_ecode( char const* path, bool use_c_definition = false ) | ||||
| { | ||||
| 	CSV_Columns2 csv_enum = parse_csv_two_columns(GlobalAllocator, path ); | ||||
|  | ||||
| 	String enum_entries           = string_make_reserve( GlobalAllocator, kilobytes(1) ); | ||||
| 	String to_str_entries         = string_make_reserve( GlobalAllocator, kilobytes(1) ); | ||||
| 	String to_keyword_str_entries = string_make_reserve( GlobalAllocator, kilobytes(1) ); | ||||
|  | ||||
| 	for ( ssize idx = 0; idx < array_num(csv_enum.Col_1); ++ idx ) 	{ | ||||
| 		char const* code    = csv_enum.Col_1[idx].string; | ||||
| 		char const* keyword = csv_enum.Col_2[idx].string; | ||||
| 		// TODO(Ed): to_str_entries and the others in here didn't have proper sizing of the StrC slice. | ||||
| 		string_append_fmt( & enum_entries,           "CT_%s,\n", code ); | ||||
| 		string_append_fmt( & to_str_entries,         "{ sizeof(\"%s\"), \"%s\" },\n", code, code ); | ||||
| 		string_append_fmt( & to_keyword_str_entries, "{ sizeof(\"%s\") - 1, \"%s\" },\n", keyword, keyword ); | ||||
| 	} | ||||
|  | ||||
| 	CodeEnum enum_code; | ||||
| 	if (use_c_definition) { | ||||
| 		enum_code = parse_enum(token_fmt_impl((3 + 1) / 2, "entries", string_to_strc(enum_entries), | ||||
| 			"enum CodeType enum_underlying(u32) { <entries> CT_NumTypes, CT_UnderlyingType = GEN_U32_MAX };" | ||||
| 		)); | ||||
| 	} | ||||
| 	else { | ||||
| 		enum_code = parse_enum(token_fmt_impl((3 + 1) / 2, "entries", string_to_strc(enum_entries), | ||||
| 			"enum CodeType : u32 { <entries> CT_NumTypes, CT_UnderlyingType = GEN_U32_MAX };" | ||||
| 		)); | ||||
| 	} | ||||
|  | ||||
| #pragma push_macro("local_persist") | ||||
| #undef local_persist | ||||
| 	StrC lookup_size = string_to_strc(string_fmt_buf(GlobalAllocator, "%d", array_num(csv_enum.Col_1) )); | ||||
| 	CodeBody to_str_fns = parse_global_body( token_fmt( | ||||
| 		"entries",  string_to_strc(to_str_entries) | ||||
| 	,	"keywords", string_to_strc(to_keyword_str_entries) | ||||
| 	,	"num",      lookup_size | ||||
| 	, stringize( | ||||
| 		inline | ||||
| 		StrC codetype_to_str( CodeType type ) | ||||
| 		{ | ||||
| 			local_persist | ||||
| 			StrC lookup[<num>] = { | ||||
| 				<entries> | ||||
| 			}; | ||||
| 			return lookup[ type ]; | ||||
| 		} | ||||
|  | ||||
| 		inline | ||||
| 		StrC codetype_to_keyword_str( CodeType type ) | ||||
| 		{ | ||||
| 			local_persist | ||||
| 			StrC lookup[ <num> ] = { | ||||
| 				<keywords> | ||||
| 			}; | ||||
| 			return lookup[ type ]; | ||||
| 		} | ||||
| 	))); | ||||
| #pragma pop_macro("local_persist") | ||||
|  | ||||
| 	CodeBody result = def_body(CT_Global_Body); | ||||
| 	body_append(result, enum_code); | ||||
|  | ||||
| 	if (use_c_definition) { | ||||
| 		CodeTypedef code_t = parse_typedef(code(typedef enum CodeType CodeType; )); | ||||
| 		body_append(result, code_t); | ||||
| 	} | ||||
|  | ||||
| 	body_append(result, to_str_fns); | ||||
|  | ||||
| 	if (! use_c_definition) { | ||||
| 		#pragma push_macro("forceinline") | ||||
| 		#undef forceinline | ||||
| 		CodeBody alias_mappings = parse_global_body(code( | ||||
| 			forceinline StrC to_str        (CodeType type) { return codetype_to_str(type);         } | ||||
| 			forceinline StrC to_keyword_str(CodeType type) { return codetype_to_keyword_str(type); } | ||||
| 		)); | ||||
| 		#pragma pop_macro("forceinline") | ||||
| 		body_append(result, alias_mappings); | ||||
| 	} | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| CodeBody gen_eoperator( char const* path, bool use_c_definition = false ) | ||||
| { | ||||
| 	CSV_Columns2 csv_enum = parse_csv_two_columns(GlobalAllocator, path); | ||||
|  | ||||
| 	String enum_entries   = string_make_reserve( GlobalAllocator, kilobytes(1) ); | ||||
| 	String to_str_entries = string_make_reserve( GlobalAllocator, kilobytes(1) ); | ||||
|  | ||||
| 	for (usize idx = 0; idx < array_num(csv_enum.Col_1); idx++) { | ||||
| 		char const* enum_str     = csv_enum.Col_1[idx].string; | ||||
| 		char const* entry_to_str = csv_enum.Col_2[idx].string; | ||||
|  | ||||
| 		string_append_fmt( & enum_entries, "Op_%s,\n", enum_str ); | ||||
| 		string_append_fmt( & to_str_entries, "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str); | ||||
| 	} | ||||
|  | ||||
| 	CodeEnum  enum_code; | ||||
| 	if (use_c_definition) | ||||
| 	{ | ||||
| 	#pragma push_macro("enum_underlying") | ||||
| 	#undef enum_underlying | ||||
| 		enum_code = parse_enum(token_fmt("entries", string_to_strc(enum_entries), stringize( | ||||
| 			enum Operator enum_underlying(u32) | ||||
| 			{ | ||||
| 				<entries> | ||||
| 				Op_NumOps, | ||||
| 				Op_UnderlyingType = GEN_U32_MAX | ||||
| 			}; | ||||
| 		))); | ||||
| 	#pragma pop_macro("enum_underlying") | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		enum_code = parse_enum(token_fmt("entries", string_to_strc(enum_entries), stringize( | ||||
| 			enum Operator : u32 | ||||
| 			{ | ||||
| 				<entries> | ||||
| 				Op_NumOps, | ||||
| 				Op_UnderlyingType = GEN_U32_MAX | ||||
| 			}; | ||||
| 		))); | ||||
| 	} | ||||
|  | ||||
| #pragma push_macro("local_persist") | ||||
| #undef local_persist | ||||
| 	StrC lookup_size = string_to_strc(string_fmt_buf(GlobalAllocator, "%d", array_num(csv_enum.Col_1) )); | ||||
| 	CodeFn to_str   = parse_function(token_fmt( | ||||
| 		"entries", string_to_strc(to_str_entries) | ||||
| 	,	"num",     lookup_size | ||||
| 	, stringize( | ||||
| 		inline | ||||
| 		StrC operator_to_str( Operator op ) | ||||
| 		{ | ||||
| 			local_persist | ||||
| 			StrC lookup[<num>] = { | ||||
| 				<entries> | ||||
| 			}; | ||||
|  | ||||
| 			return lookup[ op ]; | ||||
| 		} | ||||
| 	))); | ||||
| #pragma pop_macro("local_persist") | ||||
|  | ||||
| 	CodeBody result = def_body(CT_Global_Body); | ||||
| 	body_append(result, enum_code); | ||||
| 	if ( use_c_definition ) { | ||||
| 		CodeTypedef operator_t = parse_typedef(code( typedef enum Operator Operator; )); | ||||
| 		body_append(result, operator_t); | ||||
| 	} | ||||
|  | ||||
| 	body_append(result, to_str); | ||||
|  | ||||
| 	if (! use_c_definition) | ||||
| 	{ | ||||
| 	#pragma push_macro("forceinline") | ||||
| 	#undef forceinline | ||||
| 		CodeBody alias_mappings = parse_global_body(code( | ||||
| 			forceinline StrC to_str(Operator op) { return operator_to_str(op); } | ||||
| 		)); | ||||
| 	#pragma pop_macro("forceinline") | ||||
| 		body_append(result, alias_mappings); | ||||
| 	} | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| CodeBody gen_especifier( char const* path, bool use_c_definition = false ) | ||||
| { | ||||
| 	CSV_Columns2 csv_enum = parse_csv_two_columns(GlobalAllocator, path); | ||||
|  | ||||
| 	String enum_entries   = string_make_reserve( GlobalAllocator, kilobytes(1) ); | ||||
| 	String to_str_entries = string_make_reserve( GlobalAllocator, kilobytes(1) ); | ||||
|  | ||||
| 	for (usize idx = 0; idx < array_num(csv_enum.Col_1); idx++) | ||||
| 	{ | ||||
| 		char const* enum_str     = enum_strs[idx].string; | ||||
| 		char const* entry_to_str = str_strs [idx].string; | ||||
|  | ||||
| 		string_append_fmt( & enum_entries, "Spec_%s,\n", enum_str ); | ||||
| 		string_append_fmt( & to_str_entries, "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str); | ||||
| 	} | ||||
|  | ||||
| 	CodeEnum enum_code; | ||||
| 	if (use_c_definition) | ||||
| 	{ | ||||
| 	#pragma push_macro("enum_underlying") | ||||
| 	#undef enum_underlying | ||||
| 		enum_code = parse_enum(token_fmt("entries", string_to_strc(enum_entries), stringize( | ||||
| 			enum Specifier enum_underlying(u32) | ||||
| 			{ | ||||
| 				<entries> | ||||
| 				Spec_NumSpecifiers, | ||||
| 				Spec_UnderlyingType = GEN_U32_MAX | ||||
| 			}; | ||||
| 		))); | ||||
| 	#pragma pop_macro("enum_underlying") | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		enum_code = parse_enum(token_fmt("entries", string_to_strc(enum_entries), stringize( | ||||
| 			enum Specifier : u32 | ||||
| 			{ | ||||
| 				<entries> | ||||
| 				Spec_NumSpecifiers, | ||||
| 				Spec_UnderlyingType = GEN_U32_MAX | ||||
| 			}; | ||||
| 		))); | ||||
| 	} | ||||
|  | ||||
| 	CodeFn is_trailing = parse_function(token_fmt("specifier", string_to_strc(to_str_entries), stringize( | ||||
| 		inline | ||||
| 		bool spec_is_trailing( Specifier specifier ) | ||||
| 		{ | ||||
| 			return specifier > Spec_Virtual; | ||||
| 		} | ||||
| 	))); | ||||
|  | ||||
| #pragma push_macro("local_persist") | ||||
| #pragma push_macro("do_once_start") | ||||
| #pragma push_macro("do_once_end") | ||||
| #pragma push_macro("forceinline") | ||||
| #pragma push_macro("neverinline") | ||||
| #undef local_persist | ||||
| #undef do_once_start | ||||
| #undef do_once_end | ||||
| #undef forceinline | ||||
| #undef neverinline | ||||
| 	StrC lookup_size = string_to_strc(string_fmt_buf(GlobalAllocator, "%d", array_num(csv_enum.Col_1) )); | ||||
| 	CodeFn to_str   = parse_function(token_fmt( | ||||
| 		"entries", string_to_strc(to_str_entries) | ||||
| 	,	"num",     lookup_size | ||||
| 	, stringize( | ||||
| 		inline | ||||
| 		StrC spec_to_str( Specifier type ) | ||||
| 		{ | ||||
| 			local_persist | ||||
| 			StrC lookup[<num>] = { | ||||
| 				<entries> | ||||
| 			}; | ||||
|  | ||||
| 			return lookup[ type ]; | ||||
| 		} | ||||
| 	))); | ||||
|  | ||||
| 	CodeFn to_type = parse_function( token_fmt( "entries", string_to_strc(to_str_entries), stringize( | ||||
| 		inline | ||||
| 		Specifier strc_to_specifier( StrC str ) | ||||
| 		{ | ||||
| 			local_persist | ||||
| 			u32 keymap[ Spec_NumSpecifiers ]; | ||||
| 			do_once_start | ||||
| 				for ( u32 index = 0; index < Spec_NumSpecifiers; index++ ) | ||||
| 				{ | ||||
| 					StrC enum_str = spec_to_str( (Specifier)index ); | ||||
|  | ||||
| 					// We subtract 1 to remove the null terminator | ||||
| 					// This is because the tokens lexed are not null terminated. | ||||
| 					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 < Spec_NumSpecifiers; index++ ) | ||||
| 			{ | ||||
| 				if ( keymap[index] == hash ) | ||||
| 					return (Specifier)index; | ||||
| 			} | ||||
|  | ||||
| 			return Spec_Invalid; | ||||
| 		} | ||||
| 	))); | ||||
| #pragma pop_macro("local_persist") | ||||
| #pragma pop_macro("do_once_start") | ||||
| #pragma pop_macro("do_once_end") | ||||
| #pragma pop_macro("forceinline") | ||||
| #pragma pop_macro("neverinline") | ||||
|  | ||||
| 	CodeBody result = def_body(CT_Global_Body); | ||||
| 	body_append(result, enum_code); | ||||
| 	if (use_c_definition) | ||||
| 	{ | ||||
| 		CodeTypedef specifier_t = parse_typedef( code(typedef u32 Specifier; )); | ||||
| 		body_append(result, specifier_t); | ||||
| 	} | ||||
|  | ||||
| 	body_append(result, to_str); | ||||
| 	body_append(result, is_trailing); | ||||
| 	body_append(result, to_type); | ||||
|  | ||||
| 	if (! use_c_definition) | ||||
| 	{ | ||||
| 	#pragma push_macro("forceinline") | ||||
| 	#undef forceinline | ||||
| 		CodeBody alias_mappings = parse_global_body(code( | ||||
| 			forceinline StrC      to_str (Specifier spec)            { return spec_to_str(spec); } | ||||
| 			forceinline Specifier to_type( StrC str )                { return strc_to_specifier(str); } | ||||
| 			forceinline bool      is_trailing( Specifier specifier ) { return spec_is_trailing(specifier); } | ||||
| 		)); | ||||
| 	#pragma pop_macro("forceinline") | ||||
| 		body_append(result, alias_mappings); | ||||
| 	} | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| CodeBody gen_etoktype( char const* etok_path, char const* attr_path, bool use_c_definition = false ) | ||||
| { | ||||
| 	char  scratch_mem[kilobytes(16)]; | ||||
| 	Arena scratch = arena_init_from_memory( scratch_mem, sizeof(scratch_mem) ); | ||||
|  | ||||
| 	AllocatorInfo scratch_info = arena_allocator_info(& scratch); | ||||
|  | ||||
| 	FileContents enum_content = file_read_contents( scratch_info, file_zero_terminate, etok_path ); | ||||
|  | ||||
| 	CSV_Object csv_enum_nodes; | ||||
| 	csv_parse( &csv_enum_nodes, rcast(char*, enum_content.data), GlobalAllocator, false ); | ||||
|  | ||||
| 	FileContents attrib_content = file_read_contents( scratch_info, file_zero_terminate, attr_path ); | ||||
|  | ||||
| 	CSV_Object csv_attr_nodes; | ||||
| 	csv_parse( &csv_attr_nodes, rcast(char*, attrib_content.data), GlobalAllocator, false ); | ||||
|  | ||||
| 	Array<ADT_Node> enum_strs          = csv_enum_nodes.nodes[0].nodes; | ||||
| 	Array<ADT_Node> enum_str_strs      = csv_enum_nodes.nodes[1].nodes; | ||||
| 	Array<ADT_Node> attribute_strs     = csv_attr_nodes.nodes[0].nodes; | ||||
| 	Array<ADT_Node> attribute_str_strs = csv_attr_nodes.nodes[1].nodes; | ||||
|  | ||||
| 	String enum_entries             = string_make_reserve( GlobalAllocator, kilobytes(2) ); | ||||
| 	String to_str_entries           = string_make_reserve( GlobalAllocator, kilobytes(4) ); | ||||
| 	String attribute_entries        = string_make_reserve( GlobalAllocator, kilobytes(2) ); | ||||
| 	String to_str_attributes        = string_make_reserve( GlobalAllocator, kilobytes(4) ); | ||||
| 	String attribute_define_entries = string_make_reserve( GlobalAllocator, kilobytes(4) ); | ||||
|  | ||||
| 	for (usize idx = 0; idx < array_num(enum_strs); idx++) | ||||
| 	{ | ||||
| 		char const* enum_str     = enum_strs[idx].string; | ||||
| 		char const* entry_to_str = enum_str_strs [idx].string; | ||||
|  | ||||
| 		string_append_fmt( & enum_entries, "Tok_%s,\n", enum_str ); | ||||
| 		string_append_fmt( & to_str_entries, "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str); | ||||
| 	} | ||||
|  | ||||
| 	for ( usize idx = 0; idx < array_num(attribute_strs); idx++ ) | ||||
| 	{ | ||||
| 		char const* attribute_str = attribute_strs[idx].string; | ||||
| 		char const* entry_to_str  = attribute_str_strs [idx].string; | ||||
|  | ||||
| 		string_append_fmt( & attribute_entries, "Tok_Attribute_%s,\n", attribute_str ); | ||||
| 		string_append_fmt( & to_str_attributes, "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str); | ||||
| 		string_append_fmt( & attribute_define_entries, "Entry( Tok_Attribute_%s, \"%s\" )", attribute_str, entry_to_str ); | ||||
|  | ||||
| 		if ( idx < array_num(attribute_strs) - 1 ) | ||||
| 			string_append_strc( & attribute_define_entries, txt(" \\\n")); | ||||
| 		else | ||||
| 			string_append_strc( & attribute_define_entries, txt("\n")); | ||||
| 	} | ||||
|  | ||||
| #pragma push_macro("GEN_DEFINE_ATTRIBUTE_TOKENS") | ||||
| #undef GEN_DEFINE_ATTRIBUTE_TOKENS | ||||
| 	CodeDefine attribute_entires_def = def_define( name(GEN_DEFINE_ATTRIBUTE_TOKENS), string_to_strc(attribute_define_entries)  ); | ||||
| #pragma pop_macro("GEN_DEFINE_ATTRIBUTE_TOKENS") | ||||
|  | ||||
| 	// We cannot parse this enum, it has Attribute names as enums | ||||
| 	CodeEnum enum_code; | ||||
| 	if (use_c_definition) | ||||
| 	{ | ||||
| 		enum_code = parse_enum(token_fmt("entries", string_to_strc(enum_entries), "attribute_toks", string_to_strc(attribute_entries), stringize( | ||||
| 			enum TokType | ||||
| 			{ | ||||
| 				<entries> | ||||
| 				<attribute_toks> | ||||
| 				Tok_NumTokens, | ||||
| 				Tok_UnderlyingType = GEN_U32_MAX | ||||
| 			}; | ||||
| 		))); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		enum_code = parse_enum(token_fmt("entries", string_to_strc(enum_entries), "attribute_toks", string_to_strc(attribute_entries), stringize( | ||||
| 			enum TokType : u32 | ||||
| 			{ | ||||
| 				<entries> | ||||
| 				<attribute_toks> | ||||
| 				Tok_NumTokens | ||||
| 			}; | ||||
| 		))); | ||||
| 	} | ||||
|  | ||||
| #pragma push_macro("local_persist") | ||||
| #pragma push_macro("do_once_start") | ||||
| #pragma push_macro("do_once_end") | ||||
| #undef local_persist | ||||
| #undef do_once_start | ||||
| #undef do_once_end | ||||
| 	CodeFn to_str = parse_function(token_fmt("entries", string_to_strc(to_str_entries), "attribute_toks", string_to_strc(to_str_attributes), stringize( | ||||
| 		inline | ||||
| 		StrC toktype_to_str( TokType type ) | ||||
| 		{ | ||||
| 			local_persist | ||||
| 			StrC lookup[] = { | ||||
| 				<entries> | ||||
| 				<attribute_toks> | ||||
| 			}; | ||||
|  | ||||
| 			return lookup[ type ]; | ||||
| 		} | ||||
| 	))); | ||||
|  | ||||
| 	CodeFn to_type = parse_function( token_fmt( "entries", string_to_strc(to_str_entries), stringize( | ||||
| 		inline | ||||
| 		TokType strc_to_toktype( StrC str ) | ||||
| 		{ | ||||
| 			local_persist | ||||
| 			u32 keymap[ Tok_NumTokens ]; | ||||
| 			do_once_start | ||||
| 				for ( u32 index = 0; index < Tok_NumTokens; index++ ) | ||||
| 				{ | ||||
| 					StrC enum_str = toktype_to_str( (TokType)index ); | ||||
|  | ||||
| 					// We subtract 1 to remove the null terminator | ||||
| 					// This is because the tokens lexed are not null terminated. | ||||
| 					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 < Tok_NumTokens; index++ ) | ||||
| 			{ | ||||
| 				if ( keymap[index] == hash ) | ||||
| 					return (TokType)index; | ||||
| 			} | ||||
|  | ||||
| 			return Tok_Invalid; | ||||
| 		} | ||||
| 	))); | ||||
| #pragma pop_macro("local_persist") | ||||
| #pragma pop_macro("do_once_start") | ||||
| #pragma pop_macro("do_once_end") | ||||
|  | ||||
| 	CodeBody result = def_body(CT_Global_Body); | ||||
| 	body_append(result, untyped_str(txt("GEN_NS_PARSER_BEGIN\n\n"))); | ||||
| 	body_append(result, attribute_entires_def); | ||||
| 	body_append(result, enum_code); | ||||
| 	if (use_c_definition) | ||||
| 	{ | ||||
| 		CodeTypedef td_toktype = parse_typedef( code( typedef enum TokType TokType; )); | ||||
| 		body_append(result, td_toktype); | ||||
| 	} | ||||
| 	body_append(result, to_str); | ||||
| 	body_append(result, to_type); | ||||
| 	body_append(result, untyped_str(txt("\nGEN_NS_PARSER_END\n\n"))); | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| CodeBody gen_ast_inlines() | ||||
| { | ||||
| #pragma push_macro("GEN_NS") | ||||
| #pragma push_macro("rcast") | ||||
| #pragma push_macro("log_failure") | ||||
| #pragma push_macro("CodeInvalid") | ||||
| #undef GEN_NS | ||||
| #undef rcast | ||||
| #undef log_failure | ||||
| #undef CodeInvalid | ||||
| 	char const* code_impl_tmpl = stringize( | ||||
| 		\n | ||||
| 		inline | ||||
| 		<typename>& <typename>::operator =( Code other ) | ||||
| 		{ | ||||
| 			if ( other.ast != nullptr && other->Parent != nullptr ) | ||||
| 			{ | ||||
| 				ast         = rcast( decltype(ast), code_duplicate(other).ast); | ||||
| 				ast->Parent = { nullptr }; | ||||
| 			} | ||||
|  | ||||
| 			ast = rcast( decltype( ast ), other.ast ); | ||||
| 			return * this; | ||||
| 		} | ||||
| 		inline | ||||
| 		<typename>::operator bool() | ||||
| 		{ | ||||
| 			return ast != nullptr; | ||||
| 		} | ||||
| 	); | ||||
|  | ||||
| 	char const* codetype_impl_tmpl = stringize( | ||||
| 		inline | ||||
| 		Code<typename>::operator Code() | ||||
| 		{ | ||||
| 			return *rcast( Code*, this ); | ||||
| 		} | ||||
| 		inline | ||||
| 		AST_<typename>* Code<typename>::operator->() | ||||
| 		{ | ||||
| 			if ( ast == nullptr ) | ||||
| 			{ | ||||
| 				log_failure( "Attempt to dereference a nullptr!" ); | ||||
| 				return nullptr; | ||||
| 			} | ||||
| 			return ast; | ||||
| 		} | ||||
| 		\n | ||||
| 	); | ||||
| #pragma pop_macro("GEN_NS") | ||||
| #pragma pop_macro("CodeInvalid") | ||||
|  | ||||
| 	CodeBody impl_code          = parse_global_body( token_fmt( "typename", StrC name(Code),               code_impl_tmpl )); | ||||
| 	CodeBody impl_code_body     = parse_global_body( token_fmt( "typename", StrC name(CodeBody),           code_impl_tmpl )); | ||||
| 	CodeBody impl_code_attr     = parse_global_body( token_fmt( "typename", StrC name(CodeAttributes),     code_impl_tmpl )); | ||||
| 	CodeBody impl_code_cmt      = parse_global_body( token_fmt( "typename", StrC name(CodeComment),        code_impl_tmpl )); | ||||
| 	CodeBody impl_code_constr   = parse_global_body( token_fmt( "typename", StrC name(CodeConstructor),    code_impl_tmpl )); | ||||
| 	CodeBody impl_code_class    = parse_global_body( token_fmt( "typename", StrC name(CodeClass),          code_impl_tmpl )); | ||||
| 	CodeBody impl_code_define   = parse_global_body( token_fmt( "typename", StrC name(CodeDefine),         code_impl_tmpl )); | ||||
| 	CodeBody impl_code_destruct = parse_global_body( token_fmt( "typename", StrC name(CodeDestructor),     code_impl_tmpl )); | ||||
| 	CodeBody impl_code_enum     = parse_global_body( token_fmt( "typename", StrC name(CodeEnum),           code_impl_tmpl )); | ||||
| 	CodeBody impl_code_exec     = parse_global_body( token_fmt( "typename", StrC name(CodeExec),           code_impl_tmpl )); | ||||
| 	CodeBody impl_code_extern   = parse_global_body( token_fmt( "typename", StrC name(CodeExtern),         code_impl_tmpl )); | ||||
| 	CodeBody impl_code_include  = parse_global_body( token_fmt( "typename", StrC name(CodeInclude),        code_impl_tmpl )); | ||||
| 	CodeBody impl_code_friend   = parse_global_body( token_fmt( "typename", StrC name(CodeFriend),         code_impl_tmpl )); | ||||
| 	CodeBody impl_code_fn	    = parse_global_body( token_fmt( "typename", StrC name(CodeFn),             code_impl_tmpl )); | ||||
| 	CodeBody impl_code_module   = parse_global_body( token_fmt( "typename", StrC name(CodeModule),         code_impl_tmpl )); | ||||
| 	CodeBody impl_code_ns       = parse_global_body( token_fmt( "typename", StrC name(CodeNS),             code_impl_tmpl )); | ||||
| 	CodeBody impl_code_op       = parse_global_body( token_fmt( "typename", StrC name(CodeOperator),       code_impl_tmpl )); | ||||
| 	CodeBody impl_code_opcast   = parse_global_body( token_fmt( "typename", StrC name(CodeOpCast),         code_impl_tmpl )); | ||||
| 	CodeBody impl_code_param    = parse_global_body( token_fmt( "typename", StrC name(CodeParam),          code_impl_tmpl )); | ||||
| 	CodeBody impl_code_pragma   = parse_global_body( token_fmt( "typename", StrC name(CodePragma),         code_impl_tmpl )); | ||||
| 	CodeBody impl_code_precond  = parse_global_body( token_fmt( "typename", StrC name(CodePreprocessCond), code_impl_tmpl )); | ||||
| 	CodeBody impl_code_specs    = parse_global_body( token_fmt( "typename", StrC name(CodeSpecifiers),     code_impl_tmpl )); | ||||
| 	CodeBody impl_code_struct   = parse_global_body( token_fmt( "typename", StrC name(CodeStruct),         code_impl_tmpl )); | ||||
| 	CodeBody impl_code_tmpl     = parse_global_body( token_fmt( "typename", StrC name(CodeTemplate),       code_impl_tmpl )); | ||||
| 	CodeBody impl_code_type     = parse_global_body( token_fmt( "typename", StrC name(CodeTypename),       code_impl_tmpl )); | ||||
| 	CodeBody impl_code_typedef  = parse_global_body( token_fmt( "typename", StrC name(CodeTypedef),        code_impl_tmpl )); | ||||
| 	CodeBody impl_code_union    = parse_global_body( token_fmt( "typename", StrC name(CodeUnion),          code_impl_tmpl )); | ||||
| 	CodeBody impl_code_using    = parse_global_body( token_fmt( "typename", StrC name(CodeUsing),          code_impl_tmpl )); | ||||
| 	CodeBody impl_code_var      = parse_global_body( token_fmt( "typename", StrC name(CodeVar),            code_impl_tmpl )); | ||||
|  | ||||
| 	body_append(impl_code_attr,     parse_global_body( token_fmt( "typename", StrC name(Attributes),     codetype_impl_tmpl ))); | ||||
| 	body_append(impl_code_cmt,      parse_global_body( token_fmt( "typename", StrC name(Comment),        codetype_impl_tmpl ))); | ||||
| 	body_append(impl_code_constr,   parse_global_body( token_fmt( "typename", StrC name(Constructor),    codetype_impl_tmpl ))); | ||||
| 	body_append(impl_code_define,   parse_global_body( token_fmt( "typename", StrC name(Define),         codetype_impl_tmpl ))); | ||||
| 	body_append(impl_code_destruct, parse_global_body( token_fmt( "typename", StrC name(Destructor),     codetype_impl_tmpl ))); | ||||
| 	body_append(impl_code_enum,     parse_global_body( token_fmt( "typename", StrC name(Enum),           codetype_impl_tmpl ))); | ||||
| 	body_append(impl_code_exec,     parse_global_body( token_fmt( "typename", StrC name(Exec),           codetype_impl_tmpl ))); | ||||
| 	body_append(impl_code_extern,   parse_global_body( token_fmt( "typename", StrC name(Extern),         codetype_impl_tmpl ))); | ||||
| 	body_append(impl_code_include,  parse_global_body( token_fmt( "typename", StrC name(Include),        codetype_impl_tmpl ))); | ||||
| 	body_append(impl_code_friend,   parse_global_body( token_fmt( "typename", StrC name(Friend),         codetype_impl_tmpl ))); | ||||
| 	body_append(impl_code_fn,       parse_global_body( token_fmt( "typename", StrC name(Fn),             codetype_impl_tmpl ))); | ||||
| 	body_append(impl_code_module,   parse_global_body( token_fmt( "typename", StrC name(Module),         codetype_impl_tmpl ))); | ||||
| 	body_append(impl_code_ns,       parse_global_body( token_fmt( "typename", StrC name(NS),             codetype_impl_tmpl ))); | ||||
| 	body_append(impl_code_op,       parse_global_body( token_fmt( "typename", StrC name(Operator),       codetype_impl_tmpl ))); | ||||
| 	body_append(impl_code_opcast,   parse_global_body( token_fmt( "typename", StrC name(OpCast),         codetype_impl_tmpl ))); | ||||
| 	body_append(impl_code_pragma,   parse_global_body( token_fmt( "typename", StrC name(Pragma),         codetype_impl_tmpl ))); | ||||
| 	body_append(impl_code_precond,  parse_global_body( token_fmt( "typename", StrC name(PreprocessCond), codetype_impl_tmpl ))); | ||||
| 	body_append(impl_code_tmpl,     parse_global_body( token_fmt( "typename", StrC name(Template),       codetype_impl_tmpl ))); | ||||
| 	body_append(impl_code_type,     parse_global_body( token_fmt( "typename", StrC name(Typename),       codetype_impl_tmpl ))); | ||||
| 	body_append(impl_code_typedef,  parse_global_body( token_fmt( "typename", StrC name(Typedef),        codetype_impl_tmpl ))); | ||||
| 	body_append(impl_code_union,    parse_global_body( token_fmt( "typename", StrC name(Union),          codetype_impl_tmpl ))); | ||||
| 	body_append(impl_code_using,    parse_global_body( token_fmt( "typename", StrC name(Using),          codetype_impl_tmpl ))); | ||||
| 	body_append(impl_code_var,      parse_global_body( token_fmt( "typename", StrC name(Var),            codetype_impl_tmpl ))); | ||||
|  | ||||
| 	#pragma push_macro("forceinline") | ||||
| 	#undef forceinline | ||||
| 	char const* cast_tmpl = stringize( | ||||
| 		forceinline Code::operator Code<typename>() const | ||||
| 		{ | ||||
| 			return { (AST_<typename>*) ast }; | ||||
| 		} | ||||
| 	); | ||||
| 	#pragma pop_macro("forceinline") | ||||
|  | ||||
| 	CodeBody impl_cast_body      = parse_global_body( token_fmt( "typename", StrC name(Body),           cast_tmpl )); | ||||
| 	CodeBody impl_cast_attribute = parse_global_body( token_fmt( "typename", StrC name(Attributes),     cast_tmpl )); | ||||
| 	CodeBody impl_cast_cmt       = parse_global_body( token_fmt( "typename", StrC name(Comment),        cast_tmpl )); | ||||
| 	CodeBody impl_cast_constr    = parse_global_body( token_fmt( "typename", StrC name(Constructor),    cast_tmpl )); | ||||
| 	CodeBody impl_cast_class     = parse_global_body( token_fmt( "typename", StrC name(Class),          cast_tmpl )); | ||||
| 	CodeBody impl_cast_define    = parse_global_body( token_fmt( "typename", StrC name(Define),         cast_tmpl )); | ||||
| 	CodeBody impl_cast_destruct  = parse_global_body( token_fmt( "typename", StrC name(Destructor),     cast_tmpl )); | ||||
| 	CodeBody impl_cast_enum      = parse_global_body( token_fmt( "typename", StrC name(Enum),           cast_tmpl )); | ||||
| 	CodeBody impl_cast_exec      = parse_global_body( token_fmt( "typename", StrC name(Exec),           cast_tmpl )); | ||||
| 	CodeBody impl_cast_extern    = parse_global_body( token_fmt( "typename", StrC name(Extern),         cast_tmpl )); | ||||
| 	CodeBody impl_cast_friend    = parse_global_body( token_fmt( "typename", StrC name(Friend),         cast_tmpl )); | ||||
| 	CodeBody impl_cast_fn        = parse_global_body( token_fmt( "typename", StrC name(Fn),             cast_tmpl )); | ||||
| 	CodeBody impl_cast_include   = parse_global_body( token_fmt( "typename", StrC name(Include),        cast_tmpl )); | ||||
| 	CodeBody impl_cast_module    = parse_global_body( token_fmt( "typename", StrC name(Module),         cast_tmpl )); | ||||
| 	CodeBody impl_cast_ns        = parse_global_body( token_fmt( "typename", StrC name(NS),             cast_tmpl )); | ||||
| 	CodeBody impl_cast_op        = parse_global_body( token_fmt( "typename", StrC name(Operator),       cast_tmpl )); | ||||
| 	CodeBody impl_cast_opcast    = parse_global_body( token_fmt( "typename", StrC name(OpCast),         cast_tmpl )); | ||||
| 	CodeBody impl_cast_param     = parse_global_body( token_fmt( "typename", StrC name(Param),          cast_tmpl )); | ||||
| 	CodeBody impl_cast_pragma    = parse_global_body( token_fmt( "typename", StrC name(Pragma),         cast_tmpl )); | ||||
| 	CodeBody impl_cast_precond   = parse_global_body( token_fmt( "typename", StrC name(PreprocessCond), cast_tmpl )); | ||||
| 	CodeBody impl_cast_specs     = parse_global_body( token_fmt( "typename", StrC name(Specifiers),     cast_tmpl )); | ||||
| 	CodeBody impl_cast_struct    = parse_global_body( token_fmt( "typename", StrC name(Struct),         cast_tmpl )); | ||||
| 	CodeBody impl_cast_tmpl      = parse_global_body( token_fmt( "typename", StrC name(Template),       cast_tmpl )); | ||||
| 	CodeBody impl_cast_type      = parse_global_body( token_fmt( "typename", StrC name(Typename),       cast_tmpl )); | ||||
| 	CodeBody impl_cast_typedef   = parse_global_body( token_fmt( "typename", StrC name(Typedef),        cast_tmpl )); | ||||
| 	CodeBody impl_cast_union     = parse_global_body( token_fmt( "typename", StrC name(Union),          cast_tmpl )); | ||||
| 	CodeBody impl_cast_using     = parse_global_body( token_fmt( "typename", StrC name(Using),          cast_tmpl )); | ||||
| 	CodeBody impl_cast_var       = parse_global_body( token_fmt( "typename", StrC name(Var),            cast_tmpl )); | ||||
|  | ||||
| 	CodeBody result = def_global_body( args( | ||||
| 		def_pragma( txt("region generated code inline implementation")), | ||||
| 		fmt_newline, | ||||
| 		impl_code, | ||||
| 		impl_code_body, | ||||
| 		impl_code_attr, | ||||
| 		impl_code_cmt, | ||||
| 		impl_code_constr, | ||||
| 		impl_code_class, | ||||
| 		impl_code_define, | ||||
| 		impl_code_destruct, | ||||
| 		impl_code_enum, | ||||
| 		impl_code_exec, | ||||
| 		impl_code_extern, | ||||
| 		impl_code_friend, | ||||
| 		impl_code_fn, | ||||
| 		impl_code_include, | ||||
| 		impl_code_module, | ||||
| 		impl_code_ns, | ||||
| 		impl_code_op, | ||||
| 		impl_code_opcast, | ||||
| 		impl_code_param, | ||||
| 		impl_code_pragma, | ||||
| 		impl_code_precond, | ||||
| 		impl_code_specs, | ||||
| 		impl_code_struct, | ||||
| 		impl_code_tmpl, | ||||
| 		impl_code_type, | ||||
| 		impl_code_typedef, | ||||
| 		impl_code_union, | ||||
| 		impl_code_using, | ||||
| 		impl_code_var, | ||||
| 		fmt_newline, | ||||
| 		def_pragma( txt("endregion generated code inline implementation")), | ||||
| 		fmt_newline, | ||||
| 		def_pragma( txt("region generated AST/Code cast implementation")), | ||||
| 		untyped_str(txt("GEN_OPTIMIZE_MAPPINGS_BEGIN\n")), | ||||
| 		fmt_newline, | ||||
| 		impl_cast_body, | ||||
| 		impl_cast_attribute, | ||||
| 		impl_cast_cmt, | ||||
| 		impl_cast_constr, | ||||
| 		impl_cast_class, | ||||
| 		impl_cast_define, | ||||
| 		impl_cast_destruct, | ||||
| 		impl_cast_enum, | ||||
| 		impl_cast_exec, | ||||
| 		impl_cast_extern, | ||||
| 		impl_cast_friend, | ||||
| 		impl_cast_fn, | ||||
| 		impl_cast_include, | ||||
| 		impl_cast_module, | ||||
| 		impl_cast_ns, | ||||
| 		impl_cast_op, | ||||
| 		impl_cast_opcast, | ||||
| 		impl_cast_param, | ||||
| 		impl_cast_pragma, | ||||
| 		impl_cast_precond, | ||||
| 		impl_cast_specs, | ||||
| 		impl_cast_struct, | ||||
| 		impl_cast_tmpl, | ||||
| 		impl_cast_type, | ||||
| 		impl_cast_typedef, | ||||
| 		impl_cast_union, | ||||
| 		impl_cast_using, | ||||
| 		impl_cast_var, | ||||
| 		fmt_newline, | ||||
| 		untyped_str(txt("GEN_OPITMIZE_MAPPINGS_END\n")), | ||||
| 		def_pragma( txt("endregion generated AST/Code cast implementation")), | ||||
| 		fmt_newline | ||||
| 	)); | ||||
|  | ||||
| 	return result; | ||||
| #pragma pop_macro("rcast") | ||||
| #pragma pop_macro("log_failure") | ||||
| } | ||||
							
								
								
									
										86
									
								
								base/helpers/misc.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								base/helpers/misc.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,86 @@ | ||||
|  | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #pragma once | ||||
| #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 "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" | ||||
| #endif | ||||
|  | ||||
| // Will format a file with the given style at the provided path. | ||||
| // Assumes clang-format is defined in an user-exposed or system enviornment PATH. | ||||
| void clang_format_file( char const* path, char const* style_path ) | ||||
| { | ||||
| 	GEN_ASSERT_NOT_NULL(path); | ||||
| 	String resolved_path = string_make_strc(GlobalAllocator, to_strc_from_c_str(path)); | ||||
|  | ||||
| 	String style_arg; | ||||
| 	if (style_path) { | ||||
| 		stle_arg = string_make_strc(GlobalAllocator, txt("-style=file:")); | ||||
| 		string_append_fmt( & style_arg, "%s ", style_path ); | ||||
| 	} | ||||
|  | ||||
| 	StrC clang_format      = txt("clang-format ") | ||||
| 	StrC cf_format_inplace = txt("-i ") | ||||
| 	StrC 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:\n"); | ||||
| 	system( command ); | ||||
| 	log_fmt("\tclang-format finished formatting.\n"); | ||||
| } | ||||
| // Will refactor a file with the given script at the provided path. | ||||
| // Assumes refactor is defined in an user-exposed or system enviornment PATH. | ||||
| // (See: ./gencpp/scripts/build.ci.ps1 for how) | ||||
| void refactor_file( char const* path, char const* refactor_script ) | ||||
| { | ||||
| 	GEN_ASSERT_NOT_NULL(path, refactor_script); | ||||
|  | ||||
| 	#define refactor | ||||
|  | ||||
| 	String command = string_make_strc(GlobalAllocator, txt("refactor"))); | ||||
|  | ||||
| 	log_fmt("\tBeginning refactor:\n"); | ||||
| 	system(command); | ||||
| 		log_fmt("\nRefactoring complete.\n"); | ||||
|  | ||||
| 	#undef refactor | ||||
| } | ||||
|  | ||||
| Code code_refactor_and_format( Code code, char const* scratch_path, char const* refactor_script, char_const* clang_format_sytle_path ) | ||||
| { | ||||
| 	GEN_ASSERT_NOT_NULL(code); | ||||
| 	GEN_ASSERT_NOT_NULL(scratch_path); | ||||
| 	Builder scratch_file = builder_open("gen/scratch.hpp"); | ||||
| 	builder_print( & scratch_file, code); | ||||
| 	builder_write(& scratch_file); | ||||
|  | ||||
| 	if (refactor_script) { | ||||
| 		refactor_file(scratch_path, refactor_script) | ||||
| 	} | ||||
| 	if ( clang_format_sytle_path ) { | ||||
| 		clang_format_file(scratch_path, clang_format_sytle_path); | ||||
| 	} | ||||
|  | ||||
| 	Code result = scan_file( scratch_path ); | ||||
| 	remove("gen/scratch.hpp"); | ||||
| 	return result; | ||||
| } | ||||
							
								
								
									
										39
									
								
								base/helpers/pop_container_defines.inline.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								base/helpers/pop_container_defines.inline.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
|  | ||||
| #undef array_init | ||||
| #undef array_init_reserve | ||||
| #undef array_append_array | ||||
| #undef array_append | ||||
| #undef array_append_items | ||||
| #undef array_append_at | ||||
| #undef array_append_items_at | ||||
| #undef array_back | ||||
| #undef array_clear | ||||
| #undef array_fill | ||||
| #undef array_free | ||||
| #undef arary_grow | ||||
| #undef array_num | ||||
| #undef arary_pop | ||||
| #undef arary_remove_at | ||||
| #undef arary_reserve | ||||
| #undef arary_resize | ||||
| #undef arary_set_capacity | ||||
| #undef arary_get_header | ||||
|  | ||||
| #undef hashtable_init | ||||
| #undef hashtable_init_reserve | ||||
| #undef hashtable_clear | ||||
| #undef hashtable_destroy | ||||
| #undef hashtable_get | ||||
| #undef hashtable_grow | ||||
| #undef hashtable_rehash | ||||
| #undef hashtable_rehash_fast | ||||
| #undef hashtable_remove | ||||
| #undef hashtable_remove_entry | ||||
| #undef hashtable_set | ||||
| #undef hashtable_slot | ||||
| #undef hashtable_map | ||||
| #undef hashtable_map_mut | ||||
|  | ||||
| //#undef hashtable_add_entry | ||||
| //#undef hashtable_find | ||||
| //#undef hashtable_full | ||||
							
								
								
									
										7
									
								
								base/helpers/pop_ignores.inline.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								base/helpers/pop_ignores.inline.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| #ifdef __clang__ | ||||
| #	pragma clang diagnostic pop | ||||
| #endif | ||||
|  | ||||
| #ifdef __GNUC__ | ||||
| #	pragma GCC diagnostic pop | ||||
| #endif | ||||
							
								
								
									
										39
									
								
								base/helpers/push_container_defines.inline.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								base/helpers/push_container_defines.inline.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
|  | ||||
| #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 ) | ||||
|  | ||||
| #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_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) | ||||
|  | ||||
| //#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) | ||||
							
								
								
									
										21
									
								
								base/helpers/push_ignores.inline.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								base/helpers/push_ignores.inline.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| #ifdef __clang__ | ||||
| #	pragma clang diagnostic push | ||||
| #	pragma clang diagnostic ignored "-Wunused-const-variable" | ||||
| #	pragma clang diagnostic ignored "-Wunused-but-set-variable" | ||||
| #	pragma clang diagnostic ignored "-Wswitch" | ||||
| #	pragma clang diagnostic ignored "-Wunused-variable" | ||||
| #   pragma clang diagnostic ignored "-Wunknown-pragmas" | ||||
| #	pragma clang diagnostic ignored "-Wvarargs" | ||||
| #	pragma clang diagnostic ignored "-Wunused-function" | ||||
| #	pragma clang diagnostic ignored "-Wbraced-scalar-init" | ||||
| #   pragma clang diagnostic ignored "-W#pragma-messages" | ||||
| #	pragma clang diagnostic ignored "-Wstatic-in-inline" | ||||
| #endif | ||||
|  | ||||
| #ifdef __GNUC__ | ||||
| #	pragma GCC diagnostic push | ||||
| #   pragma GCC diagnostic ignored "-Wunknown-pragmas" | ||||
| #	pragma GCC diagnostic ignored "-Wcomment" | ||||
| #	pragma GCC diagnostic ignored "-Wswitch" | ||||
| #	pragma GCC diagnostic ignored "-Wunused-variable" | ||||
| #endif | ||||
							
								
								
									
										78
									
								
								base/helpers/undef.macros.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								base/helpers/undef.macros.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,78 @@ | ||||
| #if GEN_TIME | ||||
| // This undefines the macros used by the gen library but are not necessary for the user. | ||||
|  | ||||
| #undef GEN_ARCH_64_BIT | ||||
| #undef GEN_ARCH_32_BIT | ||||
|  | ||||
| #undef GEN_SYSTEM_ANDROID | ||||
| #undef GEN_SYSTEM_CYGWIN | ||||
| #undef GEN_SYSTEM_EMSCRIPTEN | ||||
| #undef GEN_SYSTEM_FREEBSD | ||||
| #undef GEN_SYSTEM_IOS | ||||
| #undef GEN_SYSTEM_LINUX | ||||
| #undef GEN_SYSTEM_MACOS | ||||
| #undef GEN_SYSTEM_OPENBSD | ||||
| #undef GEN_SYSTEM_OSX | ||||
| #undef GEN_SYSTEM_UNIX | ||||
| #undef GEN_SYSTEM_WINDOWS | ||||
|  | ||||
| #undef GEN_COMPILER_CLANG | ||||
| #undef GEN_COMPILER_GCC | ||||
| #undef GEN_COMPILER_MINGW | ||||
| #undef GEN_COMPILER_MSVC | ||||
|  | ||||
| #undef forceinline | ||||
| #undef neverinline | ||||
|  | ||||
| #undef global | ||||
| #undef internal | ||||
| #undef local_persist | ||||
|  | ||||
| #undef kilobytes | ||||
| #undef megabytes | ||||
| #undef gigabytes | ||||
| #undef terabytes | ||||
|  | ||||
| #undef zero_item | ||||
| #undef zero_array | ||||
|  | ||||
| #undef alloc_item | ||||
| #undef alloc_array | ||||
|  | ||||
| #undef malloc | ||||
| #undef mfree | ||||
|  | ||||
| #undef count_of | ||||
| #undef is_between | ||||
| #undef min | ||||
| #undef size_of | ||||
| #undef swap | ||||
|  | ||||
| #undef bit | ||||
| #undef bitfield_is_equal | ||||
| #undef ccast | ||||
| #undef scast | ||||
| #undef rcast | ||||
| #undef pcast | ||||
| #undef do_once | ||||
| #undef do_once_start | ||||
| #undef do_once_end | ||||
| #undef num_args | ||||
| #undef num_args_impl | ||||
| #undef stringize | ||||
| #undef stringize | ||||
| #undef stringize_va | ||||
| #undef txt | ||||
|  | ||||
| #undef GEN_TIME | ||||
| #undef gen_main | ||||
| #undef __ | ||||
| #undef name | ||||
| #undef code | ||||
| #undef args | ||||
| #undef code_str | ||||
| #undef code_fmt | ||||
| #undef token_fmt | ||||
|  | ||||
| // GEN_TIME | ||||
| #endif | ||||
		Reference in New Issue
	
	Block a user