mirror of
				https://github.com/Ed94/gencpp.git
				synced 2025-10-29 14:00:52 -07:00 
			
		
		
		
	WIP: Restructuring project
This commit is contained in:
		
							
								
								
									
										2
									
								
								.vscode/c_cpp_properties.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.vscode/c_cpp_properties.json
									
									
									
									
										vendored
									
									
								
							| @@ -3,7 +3,7 @@ | ||||
|         { | ||||
|             "name": "Bootstrap", | ||||
|             "includePath": [ | ||||
|                 "${workspaceFolder}/project/**" | ||||
|                 "${workspaceFolder}/base/**" | ||||
|             ], | ||||
|             "defines": [ | ||||
|                 "_DEBUG", | ||||
|   | ||||
							
								
								
									
										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). | ||||
| @@ -2,6 +2,8 @@ | ||||
| #	include "builder.hpp" | ||||
| #endif | ||||
| 
 | ||||
| #pragma region Builder | ||||
| 
 | ||||
| Builder builder_open( char const* path ) | ||||
| { | ||||
| 	Builder result; | ||||
| @@ -54,3 +56,4 @@ void builder_write(Builder* builder) | ||||
| 	string_free(& builder->Buffer); | ||||
| } | ||||
| 
 | ||||
| #pragma endregion Builder | ||||
| @@ -1,8 +1,22 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	pragma once | ||||
| #	include "gen.hpp" | ||||
| #	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; | ||||
| 
 | ||||
| @@ -51,3 +65,5 @@ void    builder_print_fmt( Builder& builder, char const* fmt, ...) { | ||||
| 	va_end( va ); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #pragma endregion Builder | ||||
| @@ -1,6 +1,18 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	pragma once | ||||
| #	include "../gen.hpp" | ||||
| #	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 | ||||
| 
 | ||||
| /*
 | ||||
| @@ -1,8 +1,22 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	pragma once | ||||
| #	include "gen.hpp" | ||||
| #	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.
 | ||||
| @@ -119,41 +133,53 @@ Code scan_file( char const* path ) | ||||
| 	return untyped_str( string_to_strc(str) ); | ||||
| } | ||||
| 
 | ||||
| #if 0 | ||||
| struct CodeFile | ||||
| CodeBody parse_file( const char* path ) | ||||
| { | ||||
| 	using namespace Parser; | ||||
| 	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; | ||||
| } | ||||
| 
 | ||||
| 	String              FilePath; | ||||
| 	TokArray            Tokens; | ||||
| 	Array<ParseFailure> ParseFailures; | ||||
| 	Code                CodeRoot; | ||||
| // 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; | ||||
| }; | ||||
| 
 | ||||
| namespace Parser | ||||
| { | ||||
| 	struct ParseFailure | ||||
| 	{ | ||||
| 		String Reason; | ||||
| 		Code   Node; | ||||
| 	}; | ||||
| } | ||||
| typedef struct CSV_Columns2 CSV_Columns2; | ||||
| struct CSV_Columns2 { | ||||
| 	CSV_Object Owner; | ||||
| 	Array<ADT_Node> Col_1; | ||||
| 	Array<ADT_Node> Col_2; | ||||
| }; | ||||
| 
 | ||||
| CodeFile scan_file( char const* path ) | ||||
| { | ||||
| 	using namespace Parser; | ||||
| 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) ); | ||||
| 
 | ||||
| 	CodeFile | ||||
| 	result = {}; | ||||
| 	result.FilePath = String::make( GlobalAllocator, path ); | ||||
| 
 | ||||
| 	Code code = scan_file( path ); | ||||
| 	result.CodeRoot = code; | ||||
| 
 | ||||
| 	ParseContext context = parser_get_last_context(); | ||||
| 	result.Tokens        = context.Tokens; | ||||
| 	result.ParseFailures = context.Failures; | ||||
| 	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; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| 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); | ||||
| } | ||||
| @@ -31,6 +31,9 @@ GEN_NS_BEGIN | ||||
| #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" | ||||
| @@ -2,50 +2,35 @@ | ||||
| 
 | ||||
| #include "gen.hpp" | ||||
| 
 | ||||
| GEN_NS_BEGIN | ||||
| #include "dependencies/parsing.hpp" | ||||
| GEN_NS_END | ||||
| 
 | ||||
| using namespace gen; | ||||
| 
 | ||||
| #include "dependencies/parsing.hpp" | ||||
| #include "misc.hpp" | ||||
| 
 | ||||
| CodeBody gen_ecode( char const* path, bool use_c_definition = false ) | ||||
| { | ||||
| 	char  scratch_mem[kilobytes(4)]; | ||||
| 	Arena scratch = arena_init_from_memory( scratch_mem, sizeof(scratch_mem) ); | ||||
| 
 | ||||
| 	file_read_contents( arena_allocator_info( & scratch), file_zero_terminate, path ); | ||||
| 
 | ||||
| 	CSV_Object csv_nodes; | ||||
| 	csv_parse( &csv_nodes, scratch_mem, GlobalAllocator, false ); | ||||
| 
 | ||||
| 	Array<ADT_Node> enum_strs    = csv_nodes.nodes[0].nodes; | ||||
| 	Array<ADT_Node> keyword_strs = csv_nodes.nodes[1].nodes; | ||||
| 	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(enum_strs); ++ idx ) | ||||
| 	{ | ||||
| 		char const* code    = enum_strs   [idx].string; | ||||
| 		char const* keyword = keyword_strs[idx].string; | ||||
| 
 | ||||
| 	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) | ||||
| 	{ | ||||
| 	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 | ||||
| 	{ | ||||
| 	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 };" | ||||
| 		)); | ||||
| @@ -53,7 +38,7 @@ CodeBody gen_ecode( char const* path, bool use_c_definition = false ) | ||||
| 
 | ||||
| #pragma push_macro("local_persist") | ||||
| #undef local_persist | ||||
| 	StrC lookup_size = string_to_strc(string_fmt_buf(GlobalAllocator, "%d", array_num(enum_strs) )); | ||||
| 	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) | ||||
| @@ -84,16 +69,14 @@ CodeBody gen_ecode( char const* path, bool use_c_definition = false ) | ||||
| 	CodeBody result = def_body(CT_Global_Body); | ||||
| 	body_append(result, enum_code); | ||||
| 
 | ||||
| 	if (use_c_definition) | ||||
| 	{ | ||||
| 	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) | ||||
| 	{ | ||||
| 	if (! use_c_definition) { | ||||
| 		#pragma push_macro("forceinline") | ||||
| 		#undef forceinline | ||||
| 		CodeBody alias_mappings = parse_global_body(code( | ||||
| @@ -108,24 +91,14 @@ CodeBody gen_ecode( char const* path, bool use_c_definition = false ) | ||||
| 
 | ||||
| CodeBody gen_eoperator( char const* path, bool use_c_definition = false ) | ||||
| { | ||||
| 	char scratch_mem[kilobytes(4)]; | ||||
| 	Arena scratch = arena_init_from_memory( scratch_mem, sizeof(scratch_mem) ); | ||||
| 
 | ||||
| 	file_read_contents( arena_allocator_info(& scratch), file_zero_terminate, path ); | ||||
| 
 | ||||
| 	CSV_Object csv_nodes; | ||||
| 	csv_parse( &csv_nodes, scratch_mem, GlobalAllocator, false ); | ||||
| 
 | ||||
| 	Array<ADT_Node> enum_strs = csv_nodes.nodes[0].nodes; | ||||
| 	Array<ADT_Node> str_strs  = csv_nodes.nodes[1].nodes; | ||||
| 	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(enum_strs); idx++) | ||||
| 	{ | ||||
| 		char const* enum_str     = enum_strs[idx].string; | ||||
| 		char const* entry_to_str = str_strs [idx].string; | ||||
| 	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); | ||||
| @@ -160,7 +133,7 @@ CodeBody gen_eoperator( char const* path, bool use_c_definition = false ) | ||||
| 
 | ||||
| #pragma push_macro("local_persist") | ||||
| #undef local_persist | ||||
| 	StrC lookup_size = string_to_strc(string_fmt_buf(GlobalAllocator, "%d", array_num(enum_strs) )); | ||||
| 	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 | ||||
| @@ -180,8 +153,7 @@ CodeBody gen_eoperator( char const* path, bool use_c_definition = false ) | ||||
| 
 | ||||
| 	CodeBody result = def_body(CT_Global_Body); | ||||
| 	body_append(result, enum_code); | ||||
| 	if ( use_c_definition ) | ||||
| 	{ | ||||
| 	if ( use_c_definition ) { | ||||
| 		CodeTypedef operator_t = parse_typedef(code( typedef enum Operator Operator; )); | ||||
| 		body_append(result, operator_t); | ||||
| 	} | ||||
| @@ -203,21 +175,12 @@ CodeBody gen_eoperator( char const* path, bool use_c_definition = false ) | ||||
| 
 | ||||
| CodeBody gen_especifier( char const* path, bool use_c_definition = false ) | ||||
| { | ||||
| 	char scratch_mem[kilobytes(4)]; | ||||
| 	Arena scratch = arena_init_from_memory( scratch_mem, sizeof(scratch_mem) ); | ||||
| 
 | ||||
| 	file_read_contents( arena_allocator_info(& scratch), file_zero_terminate, path ); | ||||
| 
 | ||||
| 	CSV_Object csv_nodes; | ||||
| 	csv_parse( &csv_nodes, scratch_mem, GlobalAllocator, false ); | ||||
| 
 | ||||
| 	Array<ADT_Node> enum_strs = csv_nodes.nodes[0].nodes; | ||||
| 	Array<ADT_Node> str_strs  = csv_nodes.nodes[1].nodes; | ||||
| 	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(enum_strs); idx++) | ||||
| 	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; | ||||
| @@ -271,7 +234,7 @@ CodeBody gen_especifier( char const* path, bool use_c_definition = false ) | ||||
| #undef do_once_end | ||||
| #undef forceinline | ||||
| #undef neverinline | ||||
| 	StrC lookup_size = string_to_strc(string_fmt_buf(GlobalAllocator, "%d", array_num(enum_strs) )); | ||||
| 	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 | ||||
							
								
								
									
										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; | ||||
| } | ||||
| @@ -52,7 +52,7 @@ constexpr StrC implementation_guard_end = txt(R"( | ||||
| #pragma endregion GENCPP IMPLEMENTATION GUARD | ||||
| )"); | ||||
|  | ||||
| void format_file( char const* path ) | ||||
| void CHANGE_format_file( char const* path ) | ||||
| { | ||||
| 	String resolved_path = String::make(GlobalAllocator, to_strc_from_c_str(path)); | ||||
|  | ||||
| @@ -77,7 +77,7 @@ void format_file( char const* path ) | ||||
| 	#undef cf_verbse | ||||
| } | ||||
|  | ||||
| Code format_code_to_untyped( Code code ) | ||||
| Code CHANGE_format_code_to_untyped( Code code ) | ||||
| { | ||||
| 	Builder ecode_file_temp = Builder::open("gen/scratch.hpp"); | ||||
| 	ecode_file_temp.print(code); | ||||
| @@ -88,18 +88,8 @@ Code format_code_to_untyped( Code code ) | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| CodeBody parse_file( const char* path ) | ||||
| { | ||||
| 	FileContents file = file_read_contents( GlobalAllocator, true, path ); | ||||
| 	CodeBody     code = parse_global_body( { file.size, (char const*)file.data } ); | ||||
| 	log_fmt("\nParsed: %s\n", path); | ||||
| 	return code; | ||||
| } | ||||
|  | ||||
| constexpr bool helper_use_c_definition = true; | ||||
|  | ||||
| constexpr bool will_refactor_to_gen_namespace = true; | ||||
|  | ||||
| int gen_main() | ||||
| { | ||||
| #define project_dir "../project/" | ||||
| @@ -116,8 +106,8 @@ int gen_main() | ||||
| 	PreprocessorDefines.append(txt("Using_CodeOps(")); | ||||
| 	PreprocessorDefines.append(txt("GEN_OPTIMIZE_MAPPINGS_BEGIN")); | ||||
| 	PreprocessorDefines.append(txt("GEN_OPITMIZE_MAPPINGS_END")); | ||||
| 	//PreprocessorDefines.append(txt("GEN_EXECUTION_EXPRESSION_SUPPORT")); | ||||
| 	PreprocessorDefines.append(txt("GEN_PARAM_DEFAULT")); | ||||
| 	//PreprocessorDefines.append(txt("GEN_EXECUTION_EXPRESSION_SUPPORT")); | ||||
|  | ||||
| 	Code push_ignores           = scan_file( project_dir "helpers/push_ignores.inline.hpp" ); | ||||
| 	Code pop_ignores            = scan_file( project_dir "helpers/pop_ignores.inline.hpp" ); | ||||
| @@ -1181,10 +1171,10 @@ R"(#define <interface_name>( code ) _Generic( (code), \ | ||||
|  | ||||
| #pragma region Resolve Components | ||||
| 	CodeBody array_arena = gen_array(txt("gen_Arena"), txt("Array_gen_Arena")); | ||||
| 	CodeBody array_pool  = gen_array(txt("gen_Pool"), txt("Array_gen_Pool")); | ||||
| 	CodeBody array_pool  = gen_array(txt("gen_Pool"),  txt("Array_gen_Pool")); | ||||
| 	CodeBody array_token = gen_array(txt("gen_Token"), txt("Array_gen_Token")); | ||||
|  | ||||
| 	Code src_static_data 	    = scan_file( project_dir "components/static_data.cpp" ); | ||||
| 	Code src_static_data 	      = scan_file( project_dir "components/static_data.cpp" ); | ||||
| 	Code src_ast_case_macros    = scan_file( project_dir "components/ast_case_macros.cpp" ); | ||||
| 	Code src_code_serialization = scan_file( project_dir "components/code_serialization.cpp" ); | ||||
| 	Code src_interface          = scan_file( project_dir "components/interface.cpp" ); | ||||
|   | ||||
| @@ -1,14 +1,5 @@ | ||||
|  __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 | ||||
| @@ -21,6 +12,9 @@ | ||||
| // Gen Macro namespace | ||||
| // namespace GEN_, new_namespace_ | ||||
|  | ||||
| // c_library.refactor | ||||
| // Used to prefix all exposed identifiers with the gen_namespace by c_library.cpp using ./gencpp/scripts/helpers/refactor.exe | ||||
|  | ||||
| // Macros | ||||
|  | ||||
| word global,                       gen_global | ||||
|   | ||||
							
								
								
									
										15
									
								
								gen_segemented/Readme.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								gen_segemented/Readme.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| # Generate Segemented Library | ||||
|  | ||||
| The principal (user) files are `gen.hpp` and `gen.cpp`. | ||||
| They contain includes for its various components: `components/<component_name>.<hpp/cpp>` | ||||
|  | ||||
| Dependencies are bundled into `gen.dep.<hpp/cpp>`. They are included in `gen.<hpp/cpp>` before component includes. | ||||
| Just like the `gen.<hpp/cpp>` they include their components: `dependencies/<dependency_name>.<hpp/cpp>` | ||||
|  | ||||
|  | ||||
| Both libraries use *pre-generated* (self-hosting I guess) version of the library to then generate the latest version of itself. | ||||
|  | ||||
| They dedicated header and source files. Dependencies included at the top of the file and each header starting with a pragma once. | ||||
| The output will be in the `project/gen` directory (if the directory does not exist, it will create it). | ||||
|  | ||||
| Use those to get a general idea of how to make your own tailored version. | ||||
| @@ -16,6 +16,7 @@ GEN_NS_END | ||||
| #include "auxillary/builder.hpp" | ||||
| #include "auxillary/builder.cpp" | ||||
| #include "auxillary/scanner.hpp" | ||||
| #include "auxillary/misc.hpp" | ||||
| 
 | ||||
| using namespace gen; | ||||
| 
 | ||||
| @@ -25,50 +26,20 @@ constexpr char const* generation_notice = | ||||
| 
 | ||||
| #include <cstdlib>   // for system()
 | ||||
| 
 | ||||
| void format_file( char const* path ) | ||||
| { | ||||
| 	String resolved_path = string_make_strc(GlobalAllocator, to_strc_from_c_str(path)); | ||||
| constexpr char const* path_format_style = "../scripts/.clang-format "; | ||||
| constexpr char const* scratch_file      = "gen/scratch.hpp"; | ||||
| constexpr char const* path_base         = "../base/"; | ||||
| 
 | ||||
| 	String style_arg = string_make_strc(GlobalAllocator, txt("-style=file:")); | ||||
| 	string_append_strc( & style_arg, txt("../scripts/.clang-format ")); | ||||
| 
 | ||||
| 	// Need to execute clang format on the generated file to get it to match the original.
 | ||||
| 	#define clang_format      txt("clang-format ") | ||||
| 	#define cf_format_inplace txt("-i ") | ||||
| 	#define cf_verbose        txt("-verbose ") | ||||
| 	String command = string_make_strc( GlobalAllocator, clang_format ); | ||||
| 	string_append_strc( & command, cf_format_inplace ); | ||||
| 	string_append_strc( & command, cf_verbose ); | ||||
| 	string_append_string( & command, style_arg ); | ||||
| 	string_append_string( & command, resolved_path ); | ||||
| 		log_fmt("\tRunning clang-format on file:\n"); | ||||
| 		system( command ); | ||||
| 		log_fmt("\tclang-format finished reformatting.\n"); | ||||
| 	#undef cf_cmd | ||||
| 	#undef cf_format_inplace | ||||
| 	#undef cf_style | ||||
| 	#undef cf_verbse | ||||
| } | ||||
| 
 | ||||
| Code dump_to_scratch_and_retireve( Code code ) | ||||
| { | ||||
| 	Builder ecode_file_temp = builder_open("gen/scratch.hpp"); | ||||
| 	builder_print( & ecode_file_temp, code); | ||||
| 	builder_write(& ecode_file_temp); | ||||
| 	format_file("gen/scratch.hpp"); | ||||
| 	Code result = scan_file( "gen/scratch.hpp" ); | ||||
| 	remove("gen/scratch.hpp"); | ||||
| 	return result; | ||||
| Code format( Code code ) { | ||||
| 	return code_refactor_and_format(code, scratch_file, nullptr, path_format_style ); | ||||
| } | ||||
| 
 | ||||
| int gen_main() | ||||
| { | ||||
| 	gen::init(); | ||||
| 
 | ||||
| 	// PreprocessorDefines.append("GEN_NS");
 | ||||
| 
 | ||||
| 	Code push_ignores = scan_file( "helpers/push_ignores.inline.hpp" ); | ||||
| 	Code pop_ignores  = scan_file( "helpers/pop_ignores.inline.hpp" ); | ||||
| 	Code push_ignores = scan_file( path_base "helpers/push_ignores.inline.hpp" ); | ||||
| 	Code pop_ignores  = scan_file( path_base "helpers/pop_ignores.inline.hpp" ); | ||||
| 
 | ||||
| 	// gen_dep.hpp
 | ||||
| 	{ | ||||
| @@ -176,11 +147,11 @@ int gen_main() | ||||
| 		builder_print_fmt(header, "#pragma region Types\n" ); | ||||
| 		builder_print( header, types ); | ||||
| 		builder_print( header, fmt_newline); | ||||
| 		builder_print( header, dump_to_scratch_and_retireve(ecode) ); | ||||
| 		builder_print( header, format(ecode) ); | ||||
| 		builder_print( header, fmt_newline); | ||||
| 		builder_print( header, dump_to_scratch_and_retireve(eoperator) ); | ||||
| 		builder_print( header, format(eoperator) ); | ||||
| 		builder_print( header, fmt_newline); | ||||
| 		builder_print( header, dump_to_scratch_and_retireve(especifier) ); | ||||
| 		builder_print( header, format(especifier) ); | ||||
| 		builder_print( header, fmt_newline); | ||||
| 		builder_print_fmt( header, "#pragma endregion Types\n\n" ); | ||||
| 
 | ||||
| @@ -195,7 +166,7 @@ int gen_main() | ||||
| 		builder_print_fmt( header, "\n#pragma region Inlines\n" ); | ||||
| 		builder_print( header, inlines ); | ||||
| 		builder_print( header, fmt_newline ); | ||||
| 		builder_print( header, dump_to_scratch_and_retireve(ast_inlines) ); | ||||
| 		builder_print( header, format(ast_inlines) ); | ||||
| 		builder_print( header, fmt_newline ); | ||||
| 		builder_print_fmt( header, "#pragma endregion Inlines\n" ); | ||||
| 
 | ||||
| @@ -206,22 +177,22 @@ int gen_main() | ||||
| 
 | ||||
| 		Builder header_ecode = builder_open( "components/gen/ecode.hpp" ); | ||||
| 		builder_print( & header_ecode, gen_component_header ); | ||||
| 		builder_print( & header_ecode, dump_to_scratch_and_retireve(ecode) ); | ||||
| 		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, dump_to_scratch_and_retireve(eoperator) ); | ||||
| 		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, dump_to_scratch_and_retireve(especifier) ); | ||||
| 		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, dump_to_scratch_and_retireve(ast_inlines) ); | ||||
| 		builder_print( & header_ast_inlines, format(ast_inlines) ); | ||||
| 		builder_write( & header_ast_inlines); | ||||
| 	} | ||||
| 
 | ||||
| @@ -240,11 +211,10 @@ int gen_main() | ||||
| 		Code        untyped 	       = scan_file( "components/interface.untyped.cpp" ); | ||||
| 
 | ||||
| 		CodeBody etoktype         = gen_etoktype( "enums/ETokType.csv", "enums/AttributeTokens.csv" ); | ||||
| 		//CodeNS   nspaced_etoktype = def_namespace( name(parser), def_namespace_body( args(etoktype)) );
 | ||||
| 		CodeBody nspaced_etoktype = def_global_body( args( | ||||
| 			etoktype | ||||
| 		)); | ||||
| 		Code formatted_toktype = dump_to_scratch_and_retireve(nspaced_etoktype); | ||||
| 		Code formatted_toktype = format(nspaced_etoktype); | ||||
| 
 | ||||
| 		Builder _src = builder_open( "gen/gen.cpp" ); | ||||
| 		Builder* src = & _src; | ||||
| @@ -1,66 +0,0 @@ | ||||
| # Documentation | ||||
|  | ||||
| The library is fragmented into a series of headers and source files meant to be scanned in and then generated to a tailored format for the target `gen` files. | ||||
|  | ||||
| The principal (user) files are `gen.hpp` and `gen.cpp`.   | ||||
| They contain includes for its various components: `components/<component_name>.<hpp/cpp>` | ||||
|  | ||||
| Dependencies are bundled into `gen.dep.<hpp/cpp>`.   | ||||
| Just like the `gen.<hpp/cpp>` they include their components: `dependencies/<dependency_name>.<hpp/cpp>` | ||||
|  | ||||
| Code not making up the core library is located in `auxiliary/<auxiliary_name>.<hpp/cpp>`. These are optional extensions or tools for the library. | ||||
|  | ||||
| Both libraries use *pre-generated* (self-hosting I guess) version of the library to then generate the latest version of itself. | ||||
|  | ||||
| The default `gen.bootstrap.cpp` located in the project folder is meant to be produce a standard segmented library, where the components of the library   | ||||
| have relatively dedicated header and source files. Dependencies included at the top of the file and each header starting with a pragma once.   | ||||
| The output will be in the `project/gen` directory (if the directory does not exist, it will create it). | ||||
|  | ||||
| Use those to get a general idea of how to make your own tailored version. | ||||
|  | ||||
| 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. | ||||
|  | ||||
| By default the base library implementation strictly uses a C-like interface. This is to allow for the generation of a C-variant of the library using [gen_c_library](../gen_c_library/). However, the library was written in C++ and supports some of its features: | ||||
|  | ||||
| * `GEN_SUPPORT_CPP_REFERENCES` : Will enable support for reference interface on some definitions | ||||
| * `GEN_SUPPORT_CPP_MEMBER_FEATURES` : Will enable support for definitions to have their interface as members. | ||||
|  | ||||
| *Note: A variant of the C++ library could be generated where those additonal support features are removed (see gen_c_library implementation for an idea of how)* | ||||
|  | ||||
| ## On multi-threading | ||||
|  | ||||
| Currently unsupported. I want the library to be *stable* and *correct*, with the addition of exhausting all basic single-threaded optimizations before I consider multi-threading. | ||||
|  | ||||
| ## Extending the library | ||||
|  | ||||
| This library is relatively very small, 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 constructor as it has multiple permutations of definitions that could be created that are not trivial to determine if valid. | ||||
|  | ||||
| The library has its code segmented into component files, use it to help create a derived version without needing to have to rewrite a generated file directly or build on top of the header via composition or inheritance. | ||||
|  | ||||
| The parser is documented under `docs/Parsing.md` and `docs/Parser_Algo.md`. | ||||
|  | ||||
| ## 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). | ||||
| @@ -1,10 +0,0 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "gen.hpp" | ||||
|  | ||||
| GEN_NS_BEGIN | ||||
| #include "dependencies/parsing.hpp" | ||||
| GEN_NS_END | ||||
|  | ||||
| using namespace gen; | ||||
|  | ||||
| @@ -40,7 +40,7 @@ Push-Location $path_root | ||||
|        $vendor       = $null | ||||
|        $release      = $null | ||||
| 	   $verbose      = $false | ||||
| [bool] $bootstrap    = $false | ||||
| [bool] $segemented   = $false | ||||
| [bool] $singleheader = $false | ||||
| [bool] $c_library    = $false | ||||
| [bool] $unreal       = $false | ||||
| @@ -56,7 +56,7 @@ if ( $args ) { $args | ForEach-Object { | ||||
| 		"verbose"			  { $verbose      = $true } | ||||
| 		"release"             { $release      = $true } | ||||
| 		"debug"               { $release      = $false } | ||||
| 		"bootstrap"           { $bootstrap    = $true } | ||||
| 		"segemented"          { $segemented   = $true } | ||||
| 		"singleheader"        { $singleheader = $true } | ||||
| 		"c_library"           { $c_library    = $true } | ||||
| 		"unreal"              { $unreal       = $true } | ||||
| @@ -88,7 +88,7 @@ else { | ||||
| 	$optimize = $true | ||||
| } | ||||
|  | ||||
| if ( $bootstrap -eq $false -and $singleheader -eq $false -and $c_library -eq $false -and $unreal -eq $false -and $test -eq $false ) { | ||||
| if ( $segmented -eq $false -and $singleheader -eq $false -and $c_library -eq $false -and $unreal -eq $false -and $test -eq $false ) { | ||||
| 	throw "No build target specified. One must be specified, this script will not assume one" | ||||
| } | ||||
|  | ||||
| @@ -100,25 +100,23 @@ write-host "Build Type: $(if ($release) {"Release"} else {"Debug"} )" | ||||
|  | ||||
| #region Building | ||||
| $path_build        = Join-Path $path_root build | ||||
| $path_project      = Join-Path $path_root project | ||||
| $path_scripts      = Join-Path $path_root scripts | ||||
| $path_base         = Join-Path $path_root base | ||||
| $path_c_library    = join-Path $path_root gen_c_library | ||||
| $path_segmented    = Join-Path $path_root gen_segmented | ||||
| $path_singleheader = Join-Path $path_root gen_singleheader | ||||
| $path_scripts      = Join-Path $path_root scripts | ||||
| $path_unreal       = Join-Path $path_root gen_unreal_engine | ||||
| $path_test         = Join-Path $path_root test | ||||
|  | ||||
| if ( $bootstrap ) | ||||
| if ( $base ) | ||||
| { | ||||
| 	$path_build    = join-path $path_project build | ||||
| 	$path_gen      = join-path $path_project gen | ||||
| 	$path_comp_gen = join-path $path_project components/gen | ||||
| 	$path_build    = join-path $path_base      build | ||||
| 	$path_comp     = join-path $path_segmented 'components' | ||||
| 	$path_comp_gen = join-path $path_comp      'gen' | ||||
|  | ||||
| 	if ( -not(Test-Path($path_build) )) { | ||||
| 		New-Item -ItemType Directory -Path $path_build | ||||
| 	} | ||||
| 	if ( -not(Test-Path($path_gen) )) { | ||||
| 		New-Item -ItemType Directory -Path $path_gen | ||||
| 	} | ||||
| 	if ( -not(Test-Path($path_comp_gen) )) { | ||||
| 		New-Item -ItemType Directory -Path $path_comp_gen | ||||
| 	} | ||||
| @@ -131,8 +129,46 @@ if ( $bootstrap ) | ||||
| 	) | ||||
|  | ||||
| 	$includes   = @( $path_project) | ||||
| 	$unit       = join-path $path_project "bootstrap.cpp" | ||||
| 	$executable = join-path $path_build   "bootstrap.exe" | ||||
| 	$unit       = join-path $path_base  "base.cpp" | ||||
| 	$executable = join-path $path_build "base.exe" | ||||
|  | ||||
| 	$result = build-simple $path_build $includes $compiler_args $linker_args $unit $executable | ||||
|  | ||||
| 	Push-Location $path_project | ||||
| 		if ( Test-Path( $executable ) ) { | ||||
| 			write-host "`nRunning bootstrap" | ||||
| 			$time_taken = Measure-Command { & $executable | ||||
| 					| ForEach-Object { | ||||
| 						write-host `t $_ -ForegroundColor Green | ||||
| 					} | ||||
| 				} | ||||
| 			write-host "`nBootstrap completed in $($time_taken.TotalMilliseconds) ms" | ||||
| 		} | ||||
| 	Pop-Location | ||||
| } | ||||
|  | ||||
| if ( $segmented ) | ||||
| { | ||||
| 	$path_build = join-path $path_segmented build | ||||
| 	$path_gen   = join-path $path_segmented gen | ||||
|  | ||||
| 	if ( -not(Test-Path($path_build) )) { | ||||
| 		New-Item -ItemType Directory -Path $path_build | ||||
| 	} | ||||
| 	if ( -not(Test-Path($path_gen) )) { | ||||
| 		New-Item -ItemType Directory -Path $path_gen | ||||
| 	} | ||||
|  | ||||
| 	$compiler_args = @() | ||||
| 	$compiler_args += ( $flag_define + 'GEN_TIME' ) | ||||
|  | ||||
| 	$linker_args   = @( | ||||
| 		$flag_link_win_subsystem_console | ||||
| 	) | ||||
|  | ||||
| 	$includes   = @( $path_project) | ||||
| 	$unit       = join-path $path_segmented "segmented.cpp" | ||||
| 	$executable = join-path $path_build     "segmented.exe" | ||||
|  | ||||
| 	$result = build-simple $path_build $includes $compiler_args $linker_args $unit $executable | ||||
|  | ||||
| @@ -294,7 +330,8 @@ if ( $unreal ) | ||||
| 	. $refactor_unreal | ||||
| } | ||||
|  | ||||
| if ( $test ) | ||||
| # TODO(Ed): The unit testing needs a full rewrite | ||||
| if ( $test -and $false ) | ||||
| { | ||||
| 	$path_gen          = join-path $path_test gen | ||||
| 	$path_gen_build    = join-path $path_gen  build | ||||
| @@ -356,55 +393,4 @@ if ( $test ) | ||||
| } | ||||
| #endregion Building | ||||
|  | ||||
| #region Formatting | ||||
| push-location $path_scripts | ||||
| if ( $false -and $bootstrap -and (Test-Path (Join-Path $path_project "gen/gen.hpp")) ) | ||||
| { | ||||
| 	$path_gen      = join-path $path_project gen | ||||
| 	$include  = @( | ||||
| 		'gen.hpp', 'gen.cpp', | ||||
| 		'gen.dep.hpp', 'gen.dep.cpp', | ||||
| 		'gen.builder.hpp', 'gen.builder.cpp' | ||||
| 		'gen.scanner.hpp', 'gen.scanner.cpp' | ||||
| 	) | ||||
| 	$exclude  = $null | ||||
| 	# format-cpp $path_gen $include $exclude | ||||
| 	format-cpp $path_comp_gen @( 'ast_inlines.hpp', 'ecode.hpp', 'especifier.hpp', 'eoperator.hpp', 'etoktype.cpp' ) $null | ||||
| } | ||||
|  | ||||
| if ( $false -and $singleheader -and (Test-Path (Join-Path $path_singleheader "gen/gen.hpp")) ) | ||||
| { | ||||
| 	$path_gen = join-path $path_singleheader gen | ||||
| 	$include  = @( | ||||
| 		'gen.hpp' | ||||
| 	) | ||||
| 	$exclude  = $null | ||||
| 	format-cpp $path_gen $include $exclude | ||||
| } | ||||
|  | ||||
| if ( $false -and $unreal -and (Test-Path( Join-Path $path_unreal "gen/gen.hpp")) ) | ||||
| { | ||||
| 	$path_gen = join-path $path_unreal gen | ||||
| 	$include  = @( | ||||
| 		'gen.hpp', 'gen.cpp', | ||||
| 		'gen.dep.hpp', 'gen.dep.cpp', | ||||
| 		'gen.builder.hpp', 'gen.builder.cpp' | ||||
| 		'gen.scanner.hpp', 'gen.scanner.cpp' | ||||
| 	) | ||||
| 	$exclude  = $null | ||||
| 	format-cpp $path_gen $include $exclude | ||||
| } | ||||
|  | ||||
| if ( $test -and $false ) | ||||
| { | ||||
| 	$path_gen = join-path $path_test gen | ||||
| 	$include  = @( | ||||
| 		'*.gen.hpp' | ||||
| 	) | ||||
| 	$exclude  = $null | ||||
| 	format-cpp $path_gen $include $exclude | ||||
| } | ||||
| pop-location | ||||
| #endregion Formatting | ||||
|  | ||||
| Pop-Location # $path_root | ||||
|   | ||||
| @@ -1,6 +1,3 @@ | ||||
| # Test | ||||
|  | ||||
| The implementaiton here is not well organized and needs a rewrite.. | ||||
|  | ||||
| I only do basic sanity and parsing tests for the most part.   | ||||
| The library is getting practical usage tests in [genc](https://github.com/Ed94/genc) and other projects. | ||||
| The implementaiton here has been gutted and will be rewritten... | ||||
|   | ||||
							
								
								
									
										146
									
								
								test/SOA.cpp
									
									
									
									
									
								
							
							
						
						
									
										146
									
								
								test/SOA.cpp
									
									
									
									
									
								
							| @@ -1,146 +0,0 @@ | ||||
| #define GEN_DEFINE_LIBRARY_CODE_CONSTANTS | ||||
| #define GEN_ENFORCE_STRONG_CODE_TYPES | ||||
| #define GEN_EXPOSE_BACKEND | ||||
| #define GEN_BENCHMARK | ||||
| #include "gen.hpp" | ||||
| #include "gen.builder.hpp" | ||||
| using namespace gen; | ||||
|  | ||||
| Code gen_SOA( CodeStruct struct_def, s32 num_entries = 0 ) | ||||
| { | ||||
| 	StringCached name = get_cached_string( token_fmt( "name", (StrC)struct_def->Name, | ||||
| 		stringize( SOA_<name> ) | ||||
| 	)); | ||||
|  | ||||
| 	Code | ||||
| 	soa_entry = { struct_def.duplicate() }; | ||||
| 	soa_entry->Name = get_cached_string( name(Entry) ); | ||||
|  | ||||
| 	constexpr s32 Num_Vars_Cap = 128; | ||||
|  | ||||
| 	local_persist Code var_memory[Num_Vars_Cap]; | ||||
| 	local_persist Arena var_arena; | ||||
| 	do_once_start | ||||
| 		var_arena = Arena::init_from_memory( var_memory, kilobytes(Num_Vars_Cap) ); | ||||
| 	do_once_end | ||||
|  | ||||
| 	Array<CodeVar> vars = Array<CodeVar>::init( var_arena );; | ||||
|  | ||||
| 	CodeStruct soa = def_struct( name, def_struct_body( args( soa_entry ) )); | ||||
| 	{ | ||||
| 		for ( Code struct_mem : struct_def->Body ) | ||||
| 		{ | ||||
| 			if ( struct_mem->Type == ECode::Variable ) | ||||
| 			{ | ||||
| 				CodeType var_type        = struct_mem.cast<CodeVar>()->ValueType; | ||||
| 				StrC     num_entries_str = to_str( str_fmt_buf( "%d", num_entries ) ); | ||||
|  | ||||
| 				CodeVar entry_arr = { nullptr }; | ||||
| 				if ( ! num_entries) | ||||
| 				{ | ||||
| 					entry_arr = parse_variable( token_fmt( "type", (StrC)var_type->Name, "name", (StrC)struct_mem->Name, | ||||
| 						stringize( Array<<type>> <name>; ) | ||||
| 					)); | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					entry_arr = parse_variable( token_fmt( "type", (StrC)var_type->Name, "name", (StrC)struct_mem->Name, "num", num_entries_str, | ||||
| 						stringize( <type> <name>[<num>]; ) | ||||
| 					)); | ||||
| 				} | ||||
|  | ||||
| 				vars.append( entry_arr ); | ||||
| 				soa->Body.append( entry_arr ); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	CodeFn make; | ||||
| 	{ | ||||
| 		make = parse_function( token_fmt("SOA_Type", (StrC)name, | ||||
| 			stringize( | ||||
| 				static | ||||
| 				<SOA_Type> make( AllocatorInfo allocator ) | ||||
| 				{ | ||||
| 					<SOA_Type> soa = {}; | ||||
| 				} | ||||
| 			) | ||||
| 		)); | ||||
|  | ||||
| 		if ( ! num_entries ) | ||||
| 		{ | ||||
| 			for ( CodeVar member : vars ) | ||||
| 			{ | ||||
| 				Code arr_init = def_execution( token_fmt( "var_name", (StrC)member->Name, "var_type", (StrC)member->ValueType->Name, | ||||
| 					stringize( soa.<var_name> = <var_type>::init( allocator ); ) | ||||
| 				)); | ||||
|  | ||||
| 				make->Body.append( arr_init ); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		make->Body.append( def_execution( code( return soa; ) )); | ||||
| 	} | ||||
|  | ||||
| 	CodeFn get; | ||||
| 	{ | ||||
| 		get = parse_function( code( | ||||
| 			Entry get( s32 idx ) | ||||
| 			{ | ||||
| 			} | ||||
| 		)); | ||||
|  | ||||
| 		String content = String::make( GlobalAllocator, "return\n{\n" ); | ||||
|  | ||||
| 		for ( CodeVar member : vars ) | ||||
| 		{ | ||||
| 			content.append_fmt( token_fmt( "var_name", (StrC)member->Name, | ||||
| 				"<var_name>[idx]," | ||||
| 			)); | ||||
| 		} | ||||
|  | ||||
| 		content.append( "};" ); | ||||
|  | ||||
| 		CodeExec ret = def_execution( content ); | ||||
|  | ||||
| 		get->Body.append( ret ); | ||||
| 	} | ||||
|  | ||||
| 	soa->Body.append( make ); | ||||
| 	soa->Body.append( get ); | ||||
| 	soa->Body.raw()->validate_body(); | ||||
| 	vars.free(); | ||||
|  | ||||
| 	return soa; | ||||
| } | ||||
|  | ||||
| void check_SOA() | ||||
| { | ||||
| 	log_fmt("\ncheck_SOA:"); | ||||
| 	gen::init(); | ||||
|  | ||||
| 	Builder soa_test = Builder::open( "SOA.gen.hpp" ); | ||||
|  | ||||
| 	soa_test.print( parse_using( code( | ||||
| 		using u16 = unsigned short; | ||||
| 	))); | ||||
| 	soa_test.print( def_include( txt("gen.hpp"))); | ||||
| 	soa_test.print( def_using_namespace( name(gen) ) ); | ||||
|  | ||||
| 	soa_test.print( gen_SOA( | ||||
| 		parse_struct( code( | ||||
| 			struct TestStruct | ||||
| 			{ | ||||
| 				u8  A; | ||||
| 				u16 B; | ||||
| 				u32 C; | ||||
| 				u64 D; | ||||
| 			}; | ||||
| 		)) | ||||
| 		, 100 | ||||
| 	)); | ||||
|  | ||||
| 	soa_test.write(); | ||||
| 	gen::deinit(); | ||||
| 	log_fmt(" passed!\n"); | ||||
| } | ||||
| @@ -1,25 +0,0 @@ | ||||
| # Unreal Header & Source reconstruction tests | ||||
|  | ||||
| ***Note: This validation test has not been implemented yet.*** | ||||
|  | ||||
| Will test the following modules + plugins: | ||||
|  | ||||
| * Kismet | ||||
| * Slate | ||||
| * RTTI Bases | ||||
| * Gameframework | ||||
| * Actor & Component Bases | ||||
| * Lyra | ||||
|  | ||||
| In the future I could attempt to do a similar test to that of the godot engine full compilation test. | ||||
|  | ||||
| For now it just does the following: | ||||
|  | ||||
| * Download the Unreal source code | ||||
| * For each module | ||||
|     1. Grab all header and source file paths | ||||
|     2. Generate an ast for each file and serialize it to a file called `<name of file>.gen.<h/c>` | ||||
|     3. Reconstruct the ast from the generated file | ||||
|     4. Compare the original ast to the reconstructed ast | ||||
|  | ||||
| This wil most likely be the most difficult test along-side godot's full compilation test. | ||||
| @@ -1,294 +0,0 @@ | ||||
| #pragma once | ||||
|  | ||||
| #if GEN_TIME | ||||
| #define GEN_DEFINE_LIBRARY_CODE_CONSTANTS | ||||
| #define GEN_ENFORCE_STRONG_CODE_TYPES | ||||
| #define GEN_EXPOSE_BACKEND | ||||
| #define GEN_BENCHMARK | ||||
| #include "gen.hpp" | ||||
|  | ||||
| using namespace gen; | ||||
|  | ||||
| Code gen__array_base() | ||||
| { | ||||
| 	return parse_global_body( code( | ||||
| 		struct ArrayHeader | ||||
| 		{ | ||||
| 			AllocatorInfo Allocator; | ||||
| 			usize            Capacity; | ||||
| 			usize            Num; | ||||
| 		}; | ||||
|  | ||||
| 		static inline usize array_grow_formula( usize value ) | ||||
| 		{ | ||||
| 			return 2 * value * 8; | ||||
| 		} | ||||
| 	)); | ||||
| } | ||||
|  | ||||
| Code gen__array( StrC type ) | ||||
| { | ||||
| 	StrC name; | ||||
| 	{ | ||||
| 		char const* name_str = str_fmt_buf( "Array_%s\0", type.Ptr ); | ||||
| 		s32         name_len = str_len( name_str ); | ||||
|  | ||||
| 		name = { name_len, name_str }; | ||||
| 	}; | ||||
|  | ||||
| 	CodeStruct array = parse_struct( token_fmt( "ArrayType", name, "type", type, | ||||
| 		stringize( | ||||
| 			struct <ArrayType> | ||||
| 			{ | ||||
| 				using Header = ArrayHeader; | ||||
| 				using Type   = <type>; | ||||
|  | ||||
| 				static constexpr auto grow_formula = &array_grow_formula; | ||||
|  | ||||
| 				static | ||||
| 				<ArrayType> init( AllocatorInfo allocator ) | ||||
| 				{ | ||||
| 					return init_reserve( allocator, grow_formula(0) ); | ||||
| 				} | ||||
|  | ||||
| 				static | ||||
| 				<ArrayType> init_reserve( AllocatorInfo allocator, ssize capacity ) | ||||
| 				{ | ||||
| 					Header* header = rcast( Header*, alloc( allocator, sizeof(Header) + sizeof(Type) )); | ||||
|  | ||||
| 					if ( header == nullptr ) | ||||
| 						return { nullptr }; | ||||
|  | ||||
| 					header->Allocator = allocator; | ||||
| 					header->Capacity  = capacity; | ||||
| 					header->Num       = 0; | ||||
|  | ||||
| 					return { rcast( Type*, header + 1) }; | ||||
| 				} | ||||
|  | ||||
| 				bool append( Type value ) | ||||
| 				{ | ||||
| 					Header& header = get_header(); | ||||
|  | ||||
| 					if ( header.Num == header.Capacity ) | ||||
| 					{ | ||||
| 						if ( ! grow( header.Capacity )) | ||||
| 							return false; | ||||
| 					} | ||||
|  | ||||
| 					Data[ header.Num ] = value; | ||||
| 					header.Num++; | ||||
|  | ||||
| 					return true; | ||||
| 				} | ||||
|  | ||||
| 				Type& back( void ) | ||||
| 				{ | ||||
| 					Header& header = get_header(); | ||||
| 					return Data[ header.Num - 1 ]; | ||||
| 				} | ||||
|  | ||||
| 				void clear( void ) | ||||
| 				{ | ||||
| 					Header& header = get_header(); | ||||
| 					header.Num     = 0; | ||||
| 				} | ||||
|  | ||||
| 				bool fill( usize begin, usize end, Type value ) | ||||
| 				{ | ||||
| 					Header& header = get_header(); | ||||
|  | ||||
| 					if ( begin < 0 || end >= header.Num ) | ||||
| 						return false; | ||||
|  | ||||
| 					for ( ssize idx = begin; idx < end; idx++ ) | ||||
| 					{ | ||||
| 						Data[ idx ] = value; | ||||
| 					} | ||||
|  | ||||
| 					return true; | ||||
| 				} | ||||
|  | ||||
| 				void free( void ) | ||||
| 				{ | ||||
| 					Header& header = get_header(); | ||||
| 					gen::free( header.Allocator, &header ); | ||||
| 				} | ||||
|  | ||||
| 				Header& get_header( void ) | ||||
| 				{ | ||||
| 					return *( reinterpret_cast< Header* >( Data ) - 1 ); | ||||
| 				} | ||||
|  | ||||
| 				bool grow( usize min_capacity ) | ||||
| 				{ | ||||
| 					Header& header       = get_header(); | ||||
| 					usize      new_capacity = grow_formula( header.Capacity ); | ||||
|  | ||||
| 					if ( new_capacity < min_capacity ) | ||||
| 						new_capacity = 8; | ||||
|  | ||||
| 					return set_capacity( new_capacity ); | ||||
| 				} | ||||
|  | ||||
| 				usize num( void ) | ||||
| 				{ | ||||
| 					return get_header().Num; | ||||
| 				} | ||||
|  | ||||
| 				bool pop( void ) | ||||
| 				{ | ||||
| 					Header& header = get_header(); | ||||
|  | ||||
| 					GEN_ASSERT( header.Num > 0 ); | ||||
| 					header.Num--; | ||||
| 				} | ||||
|  | ||||
| 				void remove_at( usize idx ) | ||||
| 				{ | ||||
| 					Header* header = &get_header(); | ||||
| 					GEN_ASSERT( idx < header->Num ); | ||||
|  | ||||
| 					mem_move( header + idx, header + idx + 1, sizeof( Type ) * ( header->Num - idx - 1 ) ); | ||||
| 					header->Num--; | ||||
| 				} | ||||
|  | ||||
| 				bool reserve( usize new_capacity ) | ||||
| 				{ | ||||
| 					Header& header = get_header(); | ||||
|  | ||||
| 					if ( header.Capacity < new_capacity ) | ||||
| 						return set_capacity( new_capacity ); | ||||
|  | ||||
| 					return true; | ||||
| 				} | ||||
|  | ||||
| 				bool resize( usize num ) | ||||
| 				{ | ||||
| 					Header& header = get_header(); | ||||
|  | ||||
| 					if ( num > header.Capacity ) | ||||
| 					{ | ||||
| 						if ( ! grow( header.Capacity ) ) | ||||
| 							return false; | ||||
| 					} | ||||
|  | ||||
| 					header.Num = num; | ||||
| 					return true; | ||||
| 				} | ||||
|  | ||||
| 				bool set_capacity( usize new_capacity ) | ||||
| 				{ | ||||
| 					Header& header = get_header(); | ||||
|  | ||||
| 					if ( new_capacity == header.Capacity ) | ||||
| 						return true; | ||||
|  | ||||
| 					if ( new_capacity < header.Num ) | ||||
| 						header.Num = new_capacity; | ||||
|  | ||||
| 					ssize      size       = sizeof( Header ) + sizeof( Type ) * new_capacity; | ||||
| 					Header* new_header = rcast( Header*, alloc( header.Allocator, size ) ); | ||||
|  | ||||
| 					if ( new_header == nullptr ) | ||||
| 						return false; | ||||
|  | ||||
| 					mem_move( new_header, &header, sizeof( Header ) + sizeof( Type ) * header.Num ); | ||||
|  | ||||
| 					new_header->Allocator = header.Allocator; | ||||
| 					new_header->Num       = header.Num; | ||||
| 					new_header->Capacity  = new_capacity; | ||||
|  | ||||
| 					gen::free( header.Allocator, &header ); | ||||
|  | ||||
| 					Data = ( Type* )new_header + 1; | ||||
| 					return true; | ||||
| 				} | ||||
|  | ||||
| 				Type* Data; | ||||
|  | ||||
| 				operator Type*() | ||||
| 				{ | ||||
| 					return Data; | ||||
| 				} | ||||
| 			}; | ||||
| 		) | ||||
| 	)); | ||||
|  | ||||
| 	return array; | ||||
| } | ||||
|  | ||||
|  | ||||
| struct GenArrayRequest | ||||
| { | ||||
| 	StrC Dependency; | ||||
| 	StrC Type; | ||||
| }; | ||||
| Array<GenArrayRequest> GenArrayRequests; | ||||
|  | ||||
| void gen__array_request( StrC type, StrC dep = {} ) | ||||
| { | ||||
| 	do_once_start | ||||
| 		GenArrayRequests = Array<GenArrayRequest>::init( GlobalAllocator ); | ||||
| 	do_once_end | ||||
|  | ||||
| 	// Make sure we don't already have a request for the type. | ||||
| 	for ( ssize idx = 0; idx < GenArrayRequests.num(); ++idx ) | ||||
| 	{ | ||||
| 		StrC const reqest_type = GenArrayRequests[ idx ].Type; | ||||
|  | ||||
| 		if ( reqest_type.Len != type.Len ) | ||||
| 			continue; | ||||
|  | ||||
| 		if ( str_compare( reqest_type.Ptr, type.Ptr, reqest_type.Len ) == 0 ) | ||||
| 			return; | ||||
| 	} | ||||
|  | ||||
| 	GenArrayRequest request = { dep, type }; | ||||
| 	GenArrayRequests.append( request ); | ||||
| } | ||||
| #define gen_array( type ) gen__array_request( code(type) ) | ||||
|  | ||||
| u32 gen_array_file() | ||||
| { | ||||
| 	Builder | ||||
| 	gen_array_file; | ||||
| 	gen_array_file.open( "array.Parsed.gen.hpp" ); | ||||
|  | ||||
| 	Code include_gen = def_include( txt("gen.hpp") ); | ||||
| 	gen_array_file.print( include_gen ); | ||||
|  | ||||
| 	gen_array_file.print( def_using_namespace( name(gen))); | ||||
|  | ||||
| 	Code array_base = gen__array_base(); | ||||
| 	gen_array_file.print( array_base ); | ||||
|  | ||||
| 	GenArrayRequest* current = GenArrayRequests; | ||||
| 	s32 left = GenArrayRequests.num(); | ||||
| 	while (left--) | ||||
| 	{ | ||||
| 		GenArrayRequest const& request = * current; | ||||
|  | ||||
| 		Code generated_array = gen__array( request.Type ); | ||||
|  | ||||
| 		if ( request.Dependency ) | ||||
| 		{ | ||||
| 			char const* cmt_str = str_fmt_buf( "// Dependency for %s type", request.Type ); | ||||
| 			s32         cmt_len = str_len( cmt_str ); | ||||
|  | ||||
| 			Code cmt     = def_comment( { cmt_len, cmt_str } ); | ||||
| 			Code include = def_include( request.Dependency ); | ||||
|  | ||||
| 			gen_array_file.print( cmt ); | ||||
| 			gen_array_file.print( include ); | ||||
| 		} | ||||
|  | ||||
| 		gen_array_file.print( generated_array ); | ||||
| 		current++; | ||||
| 	} | ||||
|  | ||||
| 	gen_array_file.write(); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| #endif | ||||
| @@ -1,205 +0,0 @@ | ||||
| #pragma once | ||||
|  | ||||
| #if GEN_TIME | ||||
| #define GEN_DEFINE_LIBRARY_CODE_CONSTANTS | ||||
| #define GEN_ENFORCE_STRONG_CODE_TYPES | ||||
| #define GEN_EXPOSE_BACKEND | ||||
| #define GEN_BENCHMARK | ||||
| #include "gen.hpp" | ||||
|  | ||||
| using namespace gen; | ||||
|  | ||||
| Code gen__buffer_base() | ||||
| { | ||||
| 	return parse_global_body( code( | ||||
| 		struct BufferHeader | ||||
| 		{ | ||||
| 			AllocatorInfo Backing; | ||||
| 			usize            Capacity; | ||||
| 			usize            Num; | ||||
| 		}; | ||||
| 	)); | ||||
| } | ||||
|  | ||||
| Code gen__buffer( StrC type ) | ||||
| { | ||||
| 	StrC name; | ||||
| 	{ | ||||
| 		char const* name_str = str_fmt_buf( "Buffer_%s\0", type.Ptr ); | ||||
| 		s32         name_len = str_len( name_str ); | ||||
|  | ||||
| 		name = { name_len, name_str }; | ||||
| 	}; | ||||
|  | ||||
| 	Code buffer = parse_struct( token_fmt( "BufferName", name, "type", type, | ||||
| 		stringize( | ||||
| 			struct <BufferName> | ||||
| 			{ | ||||
| 				using Header = BufferHeader; | ||||
| 				using Type   = <type>; | ||||
|  | ||||
| 				static <BufferName> init( AllocatorInfo allocator, ssize capacity ) | ||||
| 				{ | ||||
| 					Header* header = rcast( Header*, alloc( allocator, sizeof( Header ) + capacity * sizeof( Type ) ) ); | ||||
|  | ||||
| 					if ( header == nullptr ) | ||||
| 						return { nullptr }; | ||||
|  | ||||
| 					header->Backing  = allocator; | ||||
| 					header->Capacity = capacity; | ||||
| 					header->Num      = 0; | ||||
|  | ||||
| 					return { rcast( Type*, header + 1 ) }; | ||||
| 				} | ||||
|  | ||||
| 				<BufferName> init( AllocatorInfo allocator, <BufferName> other ) | ||||
| 				{ | ||||
| 					Header& other_header = other.get_header(); | ||||
| 					Header* header       = rcast( Header*, alloc( allocator, sizeof( Header ) + other_header.Capacity * sizeof( Type ) ) ); | ||||
|  | ||||
| 					if ( header == nullptr ) | ||||
| 						return { nullptr }; | ||||
|  | ||||
| 					header->Backing  = allocator; | ||||
| 					header->Capacity = other_header.Capacity; | ||||
| 					header->Num      = other_header.Num; | ||||
|  | ||||
| 					mem_copy( header + 1, other.Data, other_header.Num * sizeof( Type ) ); | ||||
|  | ||||
| 					return { rcast( Type*, header + 1 ) }; | ||||
| 				} | ||||
|  | ||||
| 				void append( Type value ) | ||||
| 				{ | ||||
| 					Header& header     = get_header(); | ||||
| 					Data[ header.Num ] = value; | ||||
| 					header.Num++; | ||||
| 				} | ||||
|  | ||||
| 				void append( Type* values, ssize num ) | ||||
| 				{ | ||||
| 					Header& header = get_header(); | ||||
| 					GEN_ASSERT( header.Num + num <= header.Capacity); | ||||
|  | ||||
| 					mem_copy( Data + header.Num, values, num * sizeof( Type ) ); | ||||
| 					header.Num += num; | ||||
| 				} | ||||
|  | ||||
| 				void clear( void ) | ||||
| 				{ | ||||
| 					Header& header = get_header(); | ||||
| 					header.Num     = 0; | ||||
| 				} | ||||
|  | ||||
| 				Type& end( void ) | ||||
| 				{ | ||||
| 					Header& header = get_header(); | ||||
| 					return Data[ header.Num - 1 ]; | ||||
| 				} | ||||
|  | ||||
| 				void free( void ) | ||||
| 				{ | ||||
| 					Header& header = get_header(); | ||||
| 					gen::free( header.Backing, &header ); | ||||
| 				} | ||||
|  | ||||
| 				Header& get_header( void ) | ||||
| 				{ | ||||
| 					return *( rcast( Header*, Data ) - 1 ); | ||||
| 				} | ||||
|  | ||||
| 				ssize num( void ) | ||||
| 				{ | ||||
| 					return get_header().Num; | ||||
| 				} | ||||
|  | ||||
| 				void wipe( void ) | ||||
| 				{ | ||||
| 					Header& header = get_header(); | ||||
| 					header.Num     = 0; | ||||
| 					mem_set( Data, 0, header.Capacity * sizeof( Type ) ); | ||||
| 				} | ||||
|  | ||||
| 				operator Type*() | ||||
| 				{ | ||||
| 					return Data; | ||||
| 				} | ||||
|  | ||||
| 				Type* Data; | ||||
| 			}; | ||||
| 		) | ||||
| 	)); | ||||
|  | ||||
| 	return buffer; | ||||
| } | ||||
|  | ||||
| struct GenBufferRequest | ||||
| { | ||||
| 	StrC Dependency; | ||||
| 	StrC Type; | ||||
| }; | ||||
| Array<GenBufferRequest> GenBufferRequests; | ||||
|  | ||||
| void gen__buffer_request( StrC type, StrC dep = {} ) | ||||
| { | ||||
| 	do_once_start | ||||
| 		GenBufferRequests = Array<GenBufferRequest>::init( GlobalAllocator ); | ||||
| 	do_once_end | ||||
|  | ||||
| 	// Make sure we don't already have a request for the type. | ||||
| 	for ( ssize idx = 0; idx < GenBufferRequests.num(); ++idx ) | ||||
| 	{ | ||||
| 		StrC const reqest_type = GenBufferRequests[ idx ].Type; | ||||
|  | ||||
| 		if ( reqest_type.Len != type.Len ) | ||||
| 			continue; | ||||
|  | ||||
| 		if ( str_compare( reqest_type.Ptr, type.Ptr, reqest_type.Len ) == 0 ) | ||||
| 			return; | ||||
| 	} | ||||
|  | ||||
| 	GenBufferRequest request = { dep, type }; | ||||
| 	GenBufferRequests.append( request ); | ||||
| } | ||||
| #define gen_buffer( type ) gen__buffer_request( code(type) ) | ||||
|  | ||||
| u32 gen_buffer_file() | ||||
| { | ||||
| 	Builder | ||||
| 	gen_buffer_file; | ||||
| 	gen_buffer_file.open( "buffer.Parsed.gen.hpp" ); | ||||
|  | ||||
| 	gen_buffer_file.print( def_include( txt("gen.hpp")) ); | ||||
| 	gen_buffer_file.print( def_using_namespace( name(gen))); | ||||
|  | ||||
| 	gen_buffer_file.print( gen__buffer_base() ); | ||||
|  | ||||
| 	GenBufferRequest* current = GenBufferRequests; | ||||
| 	s32 left = GenBufferRequests.num(); | ||||
| 	while (left--) | ||||
| 	{ | ||||
| 		GenBufferRequest const& request = * current; | ||||
|  | ||||
| 		Code generated_buffer = gen__buffer( current->Type ); | ||||
|  | ||||
| 		if ( request.Dependency ) | ||||
| 		{ | ||||
| 			char const* cmt_str = str_fmt_buf( "// Dependency for %s type", request.Type ); | ||||
| 			s32         cmt_len = str_len( cmt_str ); | ||||
|  | ||||
| 			Code cmt     = def_comment( { cmt_len, cmt_str } ); | ||||
| 			Code include = def_include( request.Dependency ); | ||||
|  | ||||
| 			gen_buffer_file.print( cmt ); | ||||
| 			gen_buffer_file.print( include ); | ||||
| 		} | ||||
|  | ||||
| 		gen_buffer_file.print( generated_buffer ); | ||||
| 		current++; | ||||
| 	} | ||||
|  | ||||
| 	gen_buffer_file.write(); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| #endif // GEN_TIME | ||||
| @@ -1,359 +0,0 @@ | ||||
| #pragma once | ||||
|  | ||||
| #if GEN_TIME | ||||
| #define GEN_DEFINE_LIBRARY_CODE_CONSTANTS | ||||
| #define GEN_ENFORCE_STRONG_CODE_TYPES | ||||
| #define GEN_EXPOSE_BACKEND | ||||
| #define GEN_BENCHMARK | ||||
| #include "gen.hpp" | ||||
| #include "Array.Parsed.hpp" | ||||
|  | ||||
| using namespace gen; | ||||
|  | ||||
| Code gen__hashtable_base() | ||||
| { | ||||
| 	return parse_global_body( code( | ||||
| 		struct HashTable_FindResult | ||||
| 		{ | ||||
| 			ssize HashIndex; | ||||
| 			ssize PrevIndex; | ||||
| 			ssize EntryIndex; | ||||
| 		}; | ||||
| 	)); | ||||
| } | ||||
|  | ||||
| Code gen__hashtable( StrC type ) | ||||
| { | ||||
| 	StringCached name; | ||||
| 	{ | ||||
| 		char const* name_str = str_fmt_buf( "HashTable_%s", type.Ptr ); | ||||
| 		s32         len      = str_len( name_str ); | ||||
|  | ||||
| 		name = get_cached_string({ len, name_str }); | ||||
| 	} | ||||
|  | ||||
| 	Code ht_entry = parse_struct( token_fmt( "HashTableName", (StrC)name, "type", type, | ||||
| 		stringize( | ||||
| 			struct <HashTableName>_Entry | ||||
| 			{ | ||||
| 				u64 Key; | ||||
| 				ssize  Next; | ||||
| 				<type> Value; | ||||
| 			}; | ||||
| 		) | ||||
| 	)); | ||||
|  | ||||
| 	StringCached ht_entry_name = get_cached_string( token_fmt( "HashTableName", (StrC)name, "<HashTableName>_Entry" )); | ||||
|  | ||||
| 	Code array_ht_entry = gen__array( ht_entry_name ); | ||||
|  | ||||
| 	Code hashtable = parse_struct( token_fmt( "HashTableName", (StrC)name, "type", type, | ||||
| 		stringize( | ||||
| 			struct <HashTableName> | ||||
| 			{ | ||||
| 				using Type        = <type>; | ||||
| 				using Entry       = <HashTableName>_Entry; | ||||
| 				using Array_Entry = Array_<HashTableName>_Entry; | ||||
| 				using FindResult  = HashTable_FindResult; | ||||
| 				using MapProc     = void ( * )( u64 key, Type value ); | ||||
| 				using MapMutProc  = void ( * )( u64 key, Type* value ); | ||||
|  | ||||
| 				static | ||||
| 				<HashTableName> init( AllocatorInfo allocator ) | ||||
| 				{ | ||||
| 					<HashTableName> | ||||
| 					result         = { 0 }; | ||||
| 					result.Hashes  = Array_sw ::init( allocator ); | ||||
| 					result.Entries = Array_Entry::init( allocator ); | ||||
| 					return result; | ||||
| 				} | ||||
|  | ||||
| 				void clear( void ) | ||||
| 				{ | ||||
| 					for ( s32 idx = 0; idx < Hashes.num(); idx++ ) | ||||
| 						Hashes[ idx ] = -1; | ||||
|  | ||||
| 					Entries.clear(); | ||||
| 				} | ||||
|  | ||||
| 				void destroy( void ) | ||||
| 				{ | ||||
| 					if ( Hashes ) | ||||
| 						Hashes.free(); | ||||
| 					if ( Entries ) | ||||
| 						Entries.free(); | ||||
| 				} | ||||
|  | ||||
| 				Type* get( u64 key ) | ||||
| 				{ | ||||
| 					ssize idx = find( key ).EntryIndex; | ||||
|  | ||||
| 					if ( idx > 0 ) | ||||
| 						return &Entries[ idx ].Value; | ||||
|  | ||||
| 					return nullptr; | ||||
| 				} | ||||
|  | ||||
| 				void grow( void ) | ||||
| 				{ | ||||
| 					ssize new_num = array_grow_formula( Entries.num() ); | ||||
|  | ||||
| 					rehash( new_num ); | ||||
| 				} | ||||
|  | ||||
| 				void map( MapProc map_proc ) | ||||
| 				{ | ||||
| 					GEN_ASSERT_NOT_NULL( map_proc ); | ||||
|  | ||||
| 					for ( ssize idx = 0; idx < Entries.num(); idx++ ) | ||||
| 					{ | ||||
| 						map_proc( Entries[ idx ].Key, Entries[ idx ].Value ); | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 				void map_mut( MapMutProc map_proc ) | ||||
| 				{ | ||||
| 					GEN_ASSERT_NOT_NULL( map_proc ); | ||||
|  | ||||
| 					for ( ssize idx = 0; idx < Entries.num(); idx++ ) | ||||
| 					{ | ||||
| 						map_proc( Entries[ idx ].Key, &Entries[ idx ].Value ); | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 				void rehash( ssize new_num ) | ||||
| 				{ | ||||
| 					ssize            idx; | ||||
| 					ssize            last_added_index; | ||||
| 					HashTable_u32 new_ht = HashTable_u32::init( Hashes.get_header().Allocator ); | ||||
|  | ||||
| 					new_ht.Hashes.resize( new_num ); | ||||
| 					new_ht.Entries.reserve( new_ht.Hashes.num() ); | ||||
|  | ||||
| 					for ( idx = 0; idx < new_ht.Hashes.num(); ++idx ) | ||||
| 						new_ht.Hashes[ idx ] = -1; | ||||
|  | ||||
| 					for ( idx = 0; idx < Entries.num(); ++idx ) | ||||
| 					{ | ||||
| 						Entry&     entry = Entries[ idx ]; | ||||
| 						FindResult find_result; | ||||
|  | ||||
| 						if ( new_ht.Hashes.num() == 0 ) | ||||
| 							new_ht.grow(); | ||||
|  | ||||
| 						entry            = Entries[ idx ]; | ||||
| 						find_result      = new_ht.find( entry.Key ); | ||||
| 						last_added_index = new_ht.add_entry( 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; | ||||
| 					} | ||||
|  | ||||
| 					destroy(); | ||||
|  | ||||
| 					Hashes  = new_ht.Hashes; | ||||
| 					Entries = new_ht.Entries; | ||||
| 				} | ||||
|  | ||||
| 				void rehash_fast( void ) | ||||
| 				{ | ||||
| 					ssize idx; | ||||
|  | ||||
| 					for ( idx = 0; idx < Entries.num(); idx++ ) | ||||
| 						Entries[ idx ].Next = -1; | ||||
|  | ||||
| 					for ( idx = 0; idx < Hashes.num(); idx++ ) | ||||
| 						Hashes[ idx ] = -1; | ||||
|  | ||||
| 					for ( idx = 0; idx < Entries.num(); idx++ ) | ||||
| 					{ | ||||
| 						Entry*     entry; | ||||
| 						FindResult find_result; | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 				void remove( u64 key ) | ||||
| 				{ | ||||
| 					FindResult find_result = find( key ); | ||||
|  | ||||
| 					if ( find_result.EntryIndex >= 0 ) | ||||
| 					{ | ||||
| 						Entries.remove_at( find_result.EntryIndex ); | ||||
| 						rehash_fast(); | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 				void remove_entry( ssize idx ) | ||||
| 				{ | ||||
| 					Entries.remove_at( idx ); | ||||
| 				} | ||||
|  | ||||
| 				void set( u64 key, Type value ) | ||||
| 				{ | ||||
| 					ssize         idx; | ||||
| 					FindResult find_result; | ||||
|  | ||||
| 					if ( Hashes.num() == 0 ) | ||||
| 						grow(); | ||||
|  | ||||
| 					find_result = find( key ); | ||||
|  | ||||
| 					if ( find_result.EntryIndex >= 0 ) | ||||
| 					{ | ||||
| 						idx = find_result.EntryIndex; | ||||
| 					} | ||||
| 					else | ||||
| 					{ | ||||
| 						idx = add_entry( key ); | ||||
|  | ||||
| 						if ( find_result.PrevIndex >= 0 ) | ||||
| 						{ | ||||
| 							Entries[ find_result.PrevIndex ].Next = idx; | ||||
| 						} | ||||
| 						else | ||||
| 						{ | ||||
| 							Hashes[ find_result.HashIndex ] = idx; | ||||
| 						} | ||||
| 					} | ||||
|  | ||||
| 					Entries[ idx ].Value = value; | ||||
|  | ||||
| 					if ( full() ) | ||||
| 						grow(); | ||||
| 				} | ||||
|  | ||||
| 				ssize slot( u64 key ) | ||||
| 				{ | ||||
| 					for ( ssize idx = 0; idx < Hashes.num(); ++idx ) | ||||
| 						if ( Hashes[ idx ] == key ) | ||||
| 							return idx; | ||||
|  | ||||
| 					return -1; | ||||
| 				} | ||||
|  | ||||
| 				Array_sw    Hashes; | ||||
| 				Array_Entry Entries; | ||||
|  | ||||
| 			protected: | ||||
|  | ||||
| 				ssize add_entry( u64 key ) | ||||
| 				{ | ||||
| 					ssize    idx; | ||||
| 					Entry entry = { key, -1 }; | ||||
| 					idx         = Entries.num(); | ||||
| 					Entries.append( entry ); | ||||
| 					return idx; | ||||
| 				} | ||||
|  | ||||
| 				HashTable_FindResult find( u64 key ) | ||||
| 				{ | ||||
| 					FindResult result = { -1, -1, -1 }; | ||||
| 					if ( Hashes.num() > 0 ) | ||||
| 					{ | ||||
| 						result.HashIndex  = key % Hashes.num(); | ||||
| 						result.EntryIndex = Hashes[ result.HashIndex ]; | ||||
|  | ||||
| 						while ( result.EntryIndex >= 0 ) | ||||
| 						{ | ||||
| 							if ( Entries[ result.EntryIndex ].Key == key ) | ||||
| 								break; | ||||
|  | ||||
| 							result.PrevIndex  = result.EntryIndex; | ||||
| 							result.EntryIndex = Entries[ result.EntryIndex ].Next; | ||||
| 						} | ||||
| 					} | ||||
| 					return result; | ||||
| 				} | ||||
|  | ||||
| 				b32 full( void ) | ||||
| 				{ | ||||
| 					return 0.75f * Hashes.num() < Entries.num(); | ||||
| 				} | ||||
| 			}; | ||||
| 		) | ||||
| 	)); | ||||
|  | ||||
| 	return def_global_body( args( ht_entry, array_ht_entry, hashtable )); | ||||
| } | ||||
|  | ||||
| struct GenHashTableRequest | ||||
| { | ||||
| 	StrC Dependency; | ||||
| 	StrC Type; | ||||
| }; | ||||
| Array<GenHashTableRequest> GenHashTableRequests; | ||||
|  | ||||
| void gen__hashtable_request( StrC type, StrC dep = {} ) | ||||
| { | ||||
| 	do_once_start | ||||
| 		GenHashTableRequests = Array<GenHashTableRequest>::init( GlobalAllocator ); | ||||
|  | ||||
| 		gen_array( ssize ); | ||||
| 	do_once_end | ||||
|  | ||||
| 	// Make sure we don't already have a request for the type. | ||||
| 	for ( ssize idx = 0; idx < GenHashTableRequests.num(); ++idx ) | ||||
| 	{ | ||||
| 		StrC const reqest_type = GenHashTableRequests[ idx ].Type; | ||||
|  | ||||
| 		if ( reqest_type.Len != type.Len ) | ||||
| 			continue; | ||||
|  | ||||
| 		if ( str_compare( reqest_type.Ptr, type.Ptr, reqest_type.Len ) == 0 ) | ||||
| 			return; | ||||
| 	} | ||||
|  | ||||
| 	GenHashTableRequest request = { dep, type }; | ||||
| 	GenHashTableRequests.append( request ); | ||||
| } | ||||
| #define gen_hashtable( type ) gen__hashtable_request( code(type) ) | ||||
|  | ||||
| u32 gen_hashtable_file() | ||||
| { | ||||
| 	Builder | ||||
| 	gen_hashtable_file; | ||||
| 	gen_hashtable_file.open( "hashtable.Parsed.gen.hpp" ); | ||||
|  | ||||
| 	gen_hashtable_file.print( def_include( txt("gen.hpp")) ); | ||||
| 	gen_hashtable_file.print( def_include( txt("Array.Parsed.hpp")) ); | ||||
| 	gen_hashtable_file.print( def_include( txt("array.Parsed.gen.hpp")) ); | ||||
|  | ||||
| 	gen_hashtable_file.print( def_using_namespace( name(gen))); | ||||
|  | ||||
| 	gen_hashtable_file.print( gen__hashtable_base()); | ||||
|  | ||||
| 	GenHashTableRequest* current = GenHashTableRequests; | ||||
| 	s32 left = GenHashTableRequests.num(); | ||||
| 	while (left--) | ||||
| 	{ | ||||
| 		GenHashTableRequest const& request = * current; | ||||
|  | ||||
| 		Code generated_buffer = gen__hashtable( current->Type ); | ||||
|  | ||||
| 		if ( request.Dependency ) | ||||
| 		{ | ||||
| 			char const* cmt_str = str_fmt_buf( "// Dependency for %s type", request.Type ); | ||||
| 			s32         cmt_len = str_len( cmt_str ); | ||||
|  | ||||
| 			Code cmt     = def_comment( { cmt_len, cmt_str } ); | ||||
| 			Code include = def_include( request.Dependency ); | ||||
|  | ||||
| 			gen_hashtable_file.print( cmt ); | ||||
| 			gen_hashtable_file.print( include ); | ||||
| 		} | ||||
|  | ||||
| 		gen_hashtable_file.print( generated_buffer ); | ||||
| 		current++; | ||||
| 	} | ||||
|  | ||||
| 	gen_hashtable_file.write(); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| #endif // GEN_TIME | ||||
| @@ -1,175 +0,0 @@ | ||||
| #pragma once | ||||
|  | ||||
| #if GEN_TIME | ||||
| #define GEN_DEFINE_LIBRARY_CODE_CONSTANTS | ||||
| #define GEN_ENFORCE_STRONG_CODE_TYPES | ||||
| #define GEN_EXPOSE_BACKEND | ||||
| #define GEN_BENCHMARK | ||||
| #include "gen.hpp" | ||||
| #include "Buffer.Parsed.hpp" | ||||
|  | ||||
| using namespace gen; | ||||
|  | ||||
| Code gen__ring( StrC type ) | ||||
| { | ||||
| 	static Code t_allocator_info = def_type( name(AllocatorInfo) ); | ||||
|  | ||||
| 	StringCached name; | ||||
| 	{ | ||||
| 		char const* name_str = str_fmt_buf( "Ring_%s\0", type.Ptr ); | ||||
| 		s32         name_len = str_len( name_str ); | ||||
|  | ||||
| 		name = get_cached_string({ name_len, name_str }); | ||||
| 	}; | ||||
|  | ||||
| 	StrC buffer_name = to_str( str_fmt_buf( "Buffer_%s", type.Ptr )); | ||||
|  | ||||
| 	Code ring = parse_struct( token_fmt( "RingName", (StrC)name, "type", type, "BufferName", buffer_name, | ||||
| 		stringize( | ||||
| 			struct <RingName> | ||||
| 			{ | ||||
| 				using Type = <type>; | ||||
|  | ||||
| 				static <RingName> init( AllocatorInfo allocator, usize max_size ) | ||||
| 				{ | ||||
| 					<RingName> result = { 0 }; | ||||
|  | ||||
| 					result.Backing  = allocator; | ||||
| 					result.Buffer   = <BufferName>::init( allocator, max_size + 1 ); | ||||
|  | ||||
| 					if ( result.Buffer == nullptr ) | ||||
| 						return { nullptr }; | ||||
|  | ||||
| 					result.Capacity = max_size + 1; | ||||
| 					return result; | ||||
| 				} | ||||
|  | ||||
| 				void append( s16 value ) | ||||
| 				{ | ||||
| 					Buffer[ Head ] = value; | ||||
| 					Head           = ( Head + 1 ) % Capacity; | ||||
| 					if ( Head == Tail ) | ||||
| 						Tail = ( Tail + 1 ) % Capacity; | ||||
| 				} | ||||
|  | ||||
| 				inline void append( Type* values, ssize num ) | ||||
| 				{ | ||||
| 					for ( ssize idx = 0; idx < num; idx++ ) | ||||
| 						append( values[ idx ] ); | ||||
| 				} | ||||
|  | ||||
| 				bool empty( void ) | ||||
| 				{ | ||||
| 					return Head == Tail; | ||||
| 				} | ||||
|  | ||||
| 				void free( void ) | ||||
| 				{ | ||||
| 					Buffer.free(); | ||||
| 				} | ||||
|  | ||||
| 				bool full( void ) | ||||
| 				{ | ||||
| 					return ( Head + 1 ) % Capacity == Tail; | ||||
| 				} | ||||
|  | ||||
| 				Type& get( void ) | ||||
| 				{ | ||||
| 					Type& data = Buffer[ Tail ]; | ||||
| 					Tail       = ( Tail + 1 ) % Capacity; | ||||
| 					return data; | ||||
| 				} | ||||
|  | ||||
| 				void wipe( void ) | ||||
| 				{ | ||||
| 					Head = 0; | ||||
| 					Tail = 0; | ||||
| 					Buffer.wipe(); | ||||
| 				} | ||||
|  | ||||
| 				AllocatorInfo Backing; | ||||
| 				usize            Capacity; | ||||
| 				usize            Head; | ||||
| 				usize            Tail; | ||||
| 				<BufferName>  Buffer; | ||||
| 			}; | ||||
| 		) | ||||
| 	)); | ||||
|  | ||||
| 	return ring; | ||||
| } | ||||
|  | ||||
| struct GenRingRequest | ||||
| { | ||||
| 	StrC Dependency; | ||||
| 	StrC Type; | ||||
| }; | ||||
| Array<GenRingRequest> GenRingRequests; | ||||
|  | ||||
| void gen__ring_request( StrC type, StrC dep = {} ) | ||||
| { | ||||
| 	do_once_start | ||||
| 		GenRingRequests = Array<GenRingRequest>::init( GlobalAllocator ); | ||||
| 	do_once_end | ||||
|  | ||||
| 	// Make sure we don't already have a request for the type. | ||||
| 	for ( ssize idx = 0; idx < GenRingRequests.num(); ++idx ) | ||||
| 	{ | ||||
| 		StrC const reqest_type = GenRingRequests[ idx ].Type; | ||||
|  | ||||
| 		if ( reqest_type.Len != type.Len ) | ||||
| 			continue; | ||||
|  | ||||
| 		if ( str_compare( reqest_type.Ptr, type.Ptr, reqest_type.Len ) == 0 ) | ||||
| 			return; | ||||
| 	} | ||||
|  | ||||
| 	// Ring definition depends on a array and buffer definition. | ||||
| 	gen__buffer_request( type, dep ); | ||||
|  | ||||
| 	GenRingRequest request = { dep, type }; | ||||
| 	GenRingRequests.append( request ); | ||||
| } | ||||
| #define gen_ring( type ) gen__ring_request( code(type)  ) | ||||
|  | ||||
| u32 gen_ring_file() | ||||
| { | ||||
| 	Builder | ||||
| 	gen_ring_file; | ||||
| 	gen_ring_file.open( "ring.Parsed.gen.hpp" ); | ||||
|  | ||||
| 	gen_ring_file.print( def_include( txt("gen.hpp")) ); | ||||
| 	gen_ring_file.print( def_include( txt("buffer.Parsed.gen.hpp")) ); | ||||
| 	// gen_ring_file.print( gen__ring_base() ); | ||||
|  | ||||
| 	gen_ring_file.print( def_using_namespace( name(gen))); | ||||
|  | ||||
| 	GenRingRequest* current = GenRingRequests; | ||||
| 	s32 left = GenRingRequests.num(); | ||||
| 	while (left--) | ||||
| 	{ | ||||
| 		GenRingRequest const& request = * current; | ||||
|  | ||||
| 		Code generated_ring = gen__ring( current->Type ); | ||||
|  | ||||
| 		if ( request.Dependency ) | ||||
| 		{ | ||||
| 			char const* cmt_str = str_fmt_buf( "// Dependency for %s type", request.Type ); | ||||
| 			s32         cmt_len = str_len( cmt_str ); | ||||
|  | ||||
| 			Code cmt     = def_comment( { cmt_len, cmt_str } ); | ||||
| 			Code include = def_include( request.Dependency ); | ||||
|  | ||||
| 			gen_ring_file.print( cmt ); | ||||
| 			gen_ring_file.print( include ); | ||||
| 		} | ||||
|  | ||||
| 		gen_ring_file.print( generated_ring ); | ||||
| 		current++; | ||||
| 	} | ||||
|  | ||||
| 	gen_ring_file.write(); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| #endif // GEN_TIME | ||||
| @@ -1,344 +0,0 @@ | ||||
| #pragma once | ||||
| #ifdef GEN_TIME | ||||
| #define GEN_DEFINE_LIBRARY_CODE_CONSTANTS | ||||
| #define GEN_ENFORCE_STRONG_CODE_TYPES | ||||
| #define GEN_EXPOSE_BACKEND | ||||
| #define GEN_BENCHMARK | ||||
| #include "gen.hpp" | ||||
|  | ||||
| using namespace gen; | ||||
|  | ||||
| u32 gen_sanity() | ||||
| { | ||||
| 	Builder | ||||
| 	gen_sanity_file; | ||||
| 	gen_sanity_file.open("./sanity.Parsed.gen.hpp"); | ||||
|  | ||||
| 	gen_sanity_file.print( def_comment( txt( | ||||
| 		"The following will show a series of base cases for the gen parsed api.\n" | ||||
| 	))); | ||||
|  | ||||
| 	// Typedef | ||||
| 	{ | ||||
| 		CodeTypedef u8_typedef = parse_typedef( code( | ||||
| 			typedef unsigned char u8; | ||||
| 		)); | ||||
|  | ||||
| 		gen_sanity_file.print(u8_typedef); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	// Class | ||||
| 	{ | ||||
| 		CodeClass fwd = parse_class( code( | ||||
| 			class TestEmptyClass; | ||||
| 		)); | ||||
|  | ||||
| 		CodeClass empty_body = parse_class( code( | ||||
| 			class TestEmptyClass | ||||
| 			{}; | ||||
| 		)); | ||||
|  | ||||
| 		empty_body->Body.append( def_comment( txt("Empty class body") ) ); | ||||
|  | ||||
| 		gen_sanity_file.print(fwd); | ||||
| 		gen_sanity_file.print(empty_body); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	// Enum | ||||
| 	{ | ||||
| 		CodeEnum fwd = parse_enum( code( | ||||
| 			enum ETestEnum : u8; | ||||
| 		)); | ||||
|  | ||||
| 		CodeEnum def = parse_enum( code( | ||||
| 			enum ETestEnum : u8 | ||||
| 			{ | ||||
| 				A, | ||||
| 				B, | ||||
| 				C | ||||
| 			}; | ||||
| 		)); | ||||
|  | ||||
| 		CodeEnum fwd_enum_class = parse_enum( code( | ||||
| 			enum class ETestEnumClass : u8; | ||||
| 		)); | ||||
|  | ||||
| 		gen_sanity_file.print(fwd); | ||||
| 		gen_sanity_file.print(def); | ||||
| 		gen_sanity_file.print(fwd_enum_class); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	// External Linkage | ||||
| 	{ | ||||
| 		CodeComment empty_comment = def_comment( txt("Empty external linkage") ); | ||||
|  | ||||
| 		CodeExtern c_extern = parse_extern_link( code( | ||||
| 			extern "C" | ||||
| 			{ | ||||
| 			}; | ||||
| 		)); | ||||
|  | ||||
| 		c_extern->Body.append( empty_comment ); | ||||
|  | ||||
| 		gen_sanity_file.print(c_extern); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	// Friend | ||||
| 	{ | ||||
| 		CodeClass fwd = parse_class( code( | ||||
| 			class TestFriendClass; | ||||
| 		)); | ||||
|  | ||||
| 		CodeClass def = parse_class( code( | ||||
| 			class TestFriend | ||||
| 			{ | ||||
| 				friend class TestFriendClass; | ||||
| 			}; | ||||
| 		)); | ||||
|  | ||||
| 		gen_sanity_file.print(fwd); | ||||
| 		gen_sanity_file.print(def); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	// Function | ||||
| 	{ | ||||
| 		CodeFn fwd = parse_function( code( | ||||
| 			void test_function(); | ||||
| 		)); | ||||
|  | ||||
| 		CodeFn def = parse_function( code( | ||||
| 			void test_function() | ||||
| 			{ | ||||
| 			} | ||||
| 		)); | ||||
|  | ||||
| 		def->Body.append( def_comment( txt("Empty function body") ) ); | ||||
|  | ||||
| 		gen_sanity_file.print(fwd); | ||||
| 		gen_sanity_file.print(def); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	// Namespace | ||||
| 	{ | ||||
| 		CodeNS def = parse_namespace( code( | ||||
| 			namespace TestNamespace | ||||
| 			{ | ||||
| 			} | ||||
| 		)); | ||||
|  | ||||
| 		def->Body.append( def_comment( txt("Empty namespace body") ) ); | ||||
|  | ||||
| 		gen_sanity_file.print(def); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	// Operator | ||||
| 	{ | ||||
| 		CodeEnum bitflagtest = parse_enum( code( | ||||
| 			enum class EBitFlagTest : u8 | ||||
| 			{ | ||||
| 				A = 1 << 0, | ||||
| 				B = 1 << 1, | ||||
| 				C = 1 << 2 | ||||
| 			}; | ||||
| 		)); | ||||
|  | ||||
| 		CodeOperator op_fwd = parse_operator( code( | ||||
| 			EBitFlagTest operator | ( EBitFlagTest a, EBitFlagTest b ); | ||||
| 		)); | ||||
|  | ||||
| 		CodeOperator op_or = parse_operator( code( | ||||
| 			EBitFlagTest operator | ( EBitFlagTest a, EBitFlagTest b ) | ||||
| 			{ | ||||
| 				return EBitFlagTest( (u8)a | (u8)b ); | ||||
| 			} | ||||
| 		)); | ||||
|  | ||||
| 		gen_sanity_file.print(bitflagtest); | ||||
| 		gen_sanity_file.print(op_fwd); | ||||
| 		gen_sanity_file.print(op_or); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	// Operator cast | ||||
| 	{ | ||||
| 		CodeOpCast op_ptr = parse_operator_cast( code( | ||||
| 			operator u8* (); | ||||
| 		)); | ||||
|  | ||||
| 		CodeClass class_def = parse_class( code( | ||||
| 			class TestClass | ||||
| 			{ | ||||
| 			}; | ||||
| 		)); | ||||
|  | ||||
| 		class_def->Body.append( op_ptr ); | ||||
|  | ||||
| 		gen_sanity_file.print(class_def); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	// Parameters | ||||
| 	{ | ||||
| 		CodeFn fwd = parse_function( code( | ||||
| 			void test_function_param( int a ); | ||||
| 		)); | ||||
|  | ||||
| 		CodeFn def = parse_function( code( | ||||
| 			void test_function_param2( int a, int b ) | ||||
| 			{ | ||||
| 			} | ||||
| 		)); | ||||
|  | ||||
| 		def->Body.append( def_comment( txt("Empty function body") ) ); | ||||
|  | ||||
| 		gen_sanity_file.print(fwd); | ||||
| 		gen_sanity_file.print(def); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	// Specifiers | ||||
| 	{ | ||||
| 		CodeFn fwd_fn = parse_function( code( | ||||
| 			inline | ||||
| 			void test_function_specifiers(); | ||||
| 		)); | ||||
|  | ||||
| 		CodeTypedef typedef_u8_ptr = parse_typedef( code( | ||||
| 			typedef u8* u8_ptr; | ||||
| 		)); | ||||
|  | ||||
| 		gen_sanity_file.print(fwd_fn); | ||||
| 		gen_sanity_file.print(typedef_u8_ptr); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	// Struct | ||||
| 	{ | ||||
| 		CodeStruct fwd = parse_struct( code( | ||||
| 			struct TestEmptyStruct; | ||||
| 		)); | ||||
|  | ||||
| 		CodeStruct empty_body = parse_struct( code( | ||||
| 			struct TestEmptyStruct | ||||
| 			{}; | ||||
| 		)); | ||||
|  | ||||
| 		empty_body->Body.append( def_comment( txt("Empty struct body") ) ); | ||||
|  | ||||
| 		gen_sanity_file.print(fwd); | ||||
| 		gen_sanity_file.print(empty_body); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	// Union | ||||
| 	{ | ||||
| 		CodeUnion empty = parse_union( code( | ||||
| 			union TestEmptyUnion | ||||
| 			{ | ||||
| 			}; | ||||
| 		)); | ||||
|  | ||||
| 		empty->Body.append( def_comment( txt("Empty union body") ) ); | ||||
|  | ||||
| 		gen_sanity_file.print( parse_typedef( code( typedef unsigned short u16; )) ); | ||||
| 		gen_sanity_file.print( parse_typedef( code( typedef unsigned long  u32; )) ); | ||||
|  | ||||
| 		CodeUnion def = parse_union( code( | ||||
| 			union TestUnion | ||||
| 			{ | ||||
| 				u8  a; | ||||
| 				u16 b; | ||||
| 				u32 c; | ||||
| 			}; | ||||
| 		)); | ||||
|  | ||||
| 		gen_sanity_file.print(empty); | ||||
| 		gen_sanity_file.print(def); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	// Using | ||||
| 	{ | ||||
| 		CodeUsing reg = (CodeUsing) parse_using( code( | ||||
| 			using TestUsing = u8; | ||||
| 		)); | ||||
|  | ||||
| 		CodeNS nspace = parse_namespace( code( | ||||
| 			namespace TestNamespace | ||||
| 			{ | ||||
| 			}; | ||||
|  | ||||
| 		)); | ||||
|  | ||||
| 		CodeUsing npspace_using = parse_using( code( | ||||
| 			using namespace TestNamespace; | ||||
| 		)); | ||||
|  | ||||
| 		gen_sanity_file.print(reg); | ||||
| 		gen_sanity_file.print(nspace); | ||||
| 		gen_sanity_file.print(npspace_using); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	// Variable | ||||
| 	{ | ||||
| 		CodeVar bss = parse_variable( code( | ||||
| 			u8 test_variable; | ||||
| 		)); | ||||
|  | ||||
| 		CodeVar data = parse_variable( code( | ||||
| 			u8 test_variable = 0x12; | ||||
| 		)); | ||||
|  | ||||
| 		gen_sanity_file.print(bss); | ||||
| 		gen_sanity_file.print(data); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	// template | ||||
| 	{ | ||||
| 	#pragma push_macro("template") | ||||
| 	#undef template | ||||
| 		CodeTemplate tmpl = parse_template( code( | ||||
| 			template< typename Type > | ||||
| 			void test_template( Type a ) | ||||
| 			{ | ||||
| 			} | ||||
| 		)); | ||||
| 	#pragma pop_macro("template") | ||||
|  | ||||
| 		gen_sanity_file.print(tmpl); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	gen_sanity_file.print( def_comment( txt( | ||||
| 		"End of base case tests\n" | ||||
| 	))); | ||||
|  | ||||
| 	gen_sanity_file.write(); | ||||
| 	return 0; | ||||
| } | ||||
| #endif | ||||
| @@ -1,75 +0,0 @@ | ||||
| #ifdef GEN_TIME | ||||
| #define GEN_FEATURE_PARSING | ||||
| #define GEN_DEFINE_LIBRARY_CODE_CONSTANTS | ||||
| #define GEN_ENFORCE_STRONG_CODE_TYPES | ||||
| #define GEN_EXPOSE_BACKEND | ||||
| #define GEN_BENCHMARK | ||||
| #include "Array.Parsed.hpp" | ||||
| #include "Buffer.Parsed.hpp" | ||||
| #include "HashTable.Parsed.hpp" | ||||
| #include "Ring.Parsed.hpp" | ||||
| #include "Sanity.Parsed.hpp" | ||||
| #include "SOA.cpp" | ||||
| #include "gen.cpp" | ||||
|  | ||||
| using namespace gen; | ||||
|  | ||||
| // TODO : Need to make a more robust test suite | ||||
|  | ||||
| int gen_main() | ||||
| { | ||||
| 	gen::init(); | ||||
|  | ||||
| 	gen_sanity(); | ||||
|  | ||||
| 	gen_array( u8 ); | ||||
| 	gen_array( ssize ); | ||||
|  | ||||
| 	gen_buffer( u8 ); | ||||
|  | ||||
| 	gen_hashtable( u32 ); | ||||
|  | ||||
| 	gen_ring( s16 ); | ||||
| 	gen_ring( usize ); | ||||
|  | ||||
| 	gen_array_file(); | ||||
| 	gen_buffer_file(); | ||||
| 	gen_hashtable_file(); | ||||
| 	gen_ring_file(); | ||||
|  | ||||
| 	Builder soa_test; soa_test.open( "SOA.gen.hpp" ); | ||||
|  | ||||
| 	soa_test.print( parse_using( code( | ||||
| 		using u16 = unsigned short; | ||||
| 	))); | ||||
|  | ||||
| 	soa_test.print( def_include( txt("gen.hpp"))); | ||||
|  | ||||
| 	soa_test.print( def_using_namespace( name(gen) ) ); | ||||
|  | ||||
| 	soa_test.print( gen_SOA( | ||||
| 		parse_struct( code( | ||||
| 			struct TestStruct | ||||
| 			{ | ||||
| 				u8  A; | ||||
| 				u16 B; | ||||
| 				u32 C; | ||||
| 				u64 D; | ||||
| 			}; | ||||
| 		)) | ||||
| 	)); | ||||
|  | ||||
| 	soa_test.write(); | ||||
|  | ||||
| 	gen::deinit(); | ||||
| 	return 0; | ||||
| } | ||||
| #endif | ||||
|  | ||||
|  | ||||
| #ifdef runtime | ||||
| int main() | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| #endif | ||||
| @@ -1,375 +0,0 @@ | ||||
| #pragma once | ||||
|  | ||||
|  | ||||
|  | ||||
| #if GEN_TIME | ||||
| #include "gen.hpp" | ||||
|  | ||||
| using namespace gen; | ||||
|  | ||||
| Code gen__array_base() | ||||
| { | ||||
| 	CodeType t_allocator_info = def_type( name(AllocatorInfo) ); | ||||
|  | ||||
| 	CodeStruct header = def_struct( name(ArrayHeader), | ||||
| 	def_struct_body( args( | ||||
| 		  def_variable( t_allocator_info, name(Allocator) ) | ||||
| 		, def_variable( t_uw,             name(Capacity) ) | ||||
| 		, def_variable( t_uw,             name(Num) ) | ||||
| 	))); | ||||
|  | ||||
| 	CodeFn grow_formula = def_function( name(array_grow_formula), def_param( t_uw, name(value)), t_uw | ||||
| 		, def_execution( code( return 2 * value * 8; ) ) | ||||
| 		, def_specifiers( args( ESpecifier::Static, ESpecifier::Inline ) ) | ||||
| 	); | ||||
|  | ||||
| 	return def_global_body( args( header, grow_formula ) ); | ||||
| } | ||||
|  | ||||
| Code gen__array( StrC type ) | ||||
| { | ||||
| 	static CodeType t_allocator_info = def_type( name(AllocatorInfo) ); | ||||
| 	static Code     v_nullptr        = code_str(nullptr); | ||||
|  | ||||
| 	static CodeSpecifiers spec_ct_member     = def_specifiers( 2, ESpecifier::Constexpr, ESpecifier::Static ); | ||||
| 	static CodeSpecifiers spec_static_inline = def_specifiers( 2, ESpecifier::Static, ESpecifier::Inline ); | ||||
| 	static CodeSpecifiers spec_static        = def_specifier( ESpecifier::Static ); | ||||
|  | ||||
| 	static CodeUsing using_header    = def_using( name(Header), def_type( name(ArrayHeader) ) ); | ||||
| 	static CodeVar ct_grow_formula = def_variable( t_auto, name(grow_formula), untyped_str( code( & array_grow_formula )), spec_ct_member ); | ||||
|  | ||||
| 	StrC name; | ||||
| 	{ | ||||
| 		char const* name_str = str_fmt_buf( "Array_%s\0", type.Ptr ); | ||||
| 		s32         name_len = str_len( name_str ); | ||||
|  | ||||
| 		name = { name_len, name_str }; | ||||
| 	}; | ||||
|  | ||||
| 	CodeType t_array_type = def_type( name ); | ||||
|  | ||||
| 	CodeType t_type     = def_type( type ); | ||||
| 	CodeType t_type_ptr = def_type( type, __, spec_ptr ); | ||||
| 	CodeType t_type_ref = def_type( type, __, spec_ref ); | ||||
|  | ||||
| 	CodeType t_alias     = def_type( name(Type) ); | ||||
| 	CodeType t_alias_ptr = def_type( name(Type), __, spec_ptr ); | ||||
| 	CodeType t_alias_ref = def_type( name(Type), __, spec_ref ); | ||||
|  | ||||
| 	CodeType t_header     = def_type( name(Header) ); | ||||
| 	CodeType t_header_ptr = def_type( name(Header), __, spec_ptr ); | ||||
| 	CodeType t_header_ref = def_type( name(Header), __, spec_ref ); | ||||
|  | ||||
| 	CodeStruct array = {0}; | ||||
| 	{ | ||||
| 		CodeUsing using_type = def_using( name(Type), t_type ); | ||||
| 		CodeVar   data       = def_variable( t_alias_ptr, name(Data) ); | ||||
|  | ||||
| 		CodeFn init = def_function( name(init), def_param( t_allocator_info, name(allocator) ), t_array_type | ||||
| 			, def_execution( code( | ||||
| 				return init_reserve( allocator, grow_formula(0) ); | ||||
| 			)) | ||||
| 			, spec_static | ||||
| 		); | ||||
|  | ||||
| 		CodeFn init_reserve; | ||||
| 		{ | ||||
| 			CodeParam params = def_params( args( | ||||
| 				  def_param( t_allocator_info, name(allocator) ) | ||||
| 				, def_param( t_sw, name(capacity) ) | ||||
| 			)); | ||||
|  | ||||
| 			Code body = def_execution( code( | ||||
| 				Header* header = rcast( Header*, alloc( allocator, sizeof(Header) + sizeof(Type) )); | ||||
|  | ||||
| 				if ( header == nullptr ) | ||||
| 					return { nullptr }; | ||||
|  | ||||
| 				header->Allocator = allocator; | ||||
| 				header->Capacity  = capacity; | ||||
| 				header->Num       = 0; | ||||
|  | ||||
| 				return { rcast( Type*, header + 1) }; | ||||
| 			)); | ||||
|  | ||||
| 			init_reserve = def_function( name(init_reserve), params, t_array_type, body, spec_static ); | ||||
| 		} | ||||
|  | ||||
| 		CodeFn append = def_function( name(append), def_param(t_alias, name(value)), t_bool | ||||
| 			, def_execution( code( | ||||
| 				Header* header = get_header(); | ||||
|  | ||||
| 				if ( header->Num == header->Capacity ) | ||||
| 				{ | ||||
| 					if ( ! grow( header->Capacity )) | ||||
| 						return false; | ||||
|  | ||||
| 					header = get_header(); | ||||
| 				} | ||||
|  | ||||
| 				Data[ header->Num ] = value; | ||||
| 				header->Num++; | ||||
|  | ||||
| 				return true; | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeFn back = def_function( name(back), __, t_alias_ref | ||||
| 			, def_execution( code( | ||||
| 				Header& header = * get_header(); | ||||
| 				return Data[ header.Num - 1 ]; | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeFn clear = def_function( name(clear), __, t_void | ||||
| 			, def_execution( code( | ||||
| 				Header& header = * get_header(); | ||||
| 				header.Num = 0; | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeFn fill; | ||||
| 		{ | ||||
| 			CodeParam params = def_params( args( | ||||
| 				  def_param( t_uw,    name(begin) ) | ||||
| 				, def_param( t_uw,    name(end) ) | ||||
| 				, def_param( t_alias, name(value) ) | ||||
| 			)); | ||||
|  | ||||
| 			Code body = untyped_str( code( | ||||
| 				Header& header = * get_header(); | ||||
|  | ||||
| 				if ( begin < 0 || end >= header.Num ) | ||||
| 					return false; | ||||
|  | ||||
| 				for ( ssize idx = begin; idx < end; idx++ ) | ||||
| 				{ | ||||
| 					Data[ idx ] = value; | ||||
| 				} | ||||
|  | ||||
| 				return true; | ||||
| 			)); | ||||
|  | ||||
| 			fill = def_function( name(fill), params, t_bool, body ); | ||||
| 		} | ||||
|  | ||||
| 		CodeFn free = def_function( name(free), __, t_void | ||||
| 			, def_execution( code( | ||||
| 				Header* header = get_header(); | ||||
| 				gen::free( header->Allocator, header ); | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeFn get_header = def_function( name(get_header), __, t_header_ptr | ||||
| 			, def_execution( code( | ||||
| 				return rcast( Header*, Data ) - 1; | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeFn grow = def_function( name(grow), def_param( t_uw, name(min_capacity)), t_bool | ||||
| 			, def_execution( code( | ||||
| 				Header& header = * get_header(); | ||||
|  | ||||
| 				usize new_capacity = grow_formula( header.Capacity ); | ||||
|  | ||||
| 				if ( new_capacity < min_capacity ) | ||||
| 					new_capacity = 8; | ||||
|  | ||||
| 				return set_capacity( new_capacity ); | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeFn num = def_function( name(num), __, t_uw | ||||
| 			, def_execution( code( | ||||
| 				return get_header()->Num; | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeFn pop = def_function( name(pop), __, t_bool | ||||
| 			, def_execution( code( | ||||
| 				Header& header = * get_header(); | ||||
|  | ||||
| 				GEN_ASSERT( header.Num > 0 ); | ||||
| 				header.Num--; | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeFn remove_at = def_function( name(remove_at), def_param( t_uw, name(idx)), t_void | ||||
| 			, def_execution( code( | ||||
| 				Header* header = get_header(); | ||||
| 				GEN_ASSERT( idx < header->Num ); | ||||
|  | ||||
| 				mem_move( header + idx, header + idx + 1, sizeof( Type ) * ( header->Num - idx - 1 ) ); | ||||
| 				header->Num--; | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeFn reserve = def_function( name(reserve), def_param( t_uw, name(new_capacity)), t_bool | ||||
| 			, def_execution( code( | ||||
| 				Header& header = * get_header(); | ||||
|  | ||||
| 				if ( header.Capacity < new_capacity ) | ||||
| 					return set_capacity( new_capacity ); | ||||
|  | ||||
| 				return true; | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeFn resize = def_function( name(resize), def_param( t_uw, name(num)), t_bool | ||||
| 			, def_execution( code( | ||||
| 				Header* header = get_header(); | ||||
|  | ||||
| 				if ( num > header->Capacity ) | ||||
| 				{ | ||||
| 					if ( ! grow( header->Capacity )) | ||||
| 						return false; | ||||
|  | ||||
| 					header = get_header(); | ||||
| 				} | ||||
|  | ||||
| 				header->Num = num; | ||||
| 				return true; | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeFn set_capacity; | ||||
| 		{ | ||||
| 			Code body = def_execution( code( | ||||
| 				Header& header = * get_header(); | ||||
|  | ||||
| 				if ( new_capacity == header.Capacity ) | ||||
| 					return true; | ||||
|  | ||||
| 				if ( new_capacity < header.Num ) | ||||
| 					header.Num = new_capacity; | ||||
|  | ||||
| 				ssize      size       = sizeof(Header) + sizeof(Type) * new_capacity; | ||||
| 				Header* new_header = rcast( Header*, alloc( header.Allocator, size )); | ||||
|  | ||||
| 				if ( new_header == nullptr ) | ||||
| 					return false; | ||||
|  | ||||
| 				mem_move( new_header, & header, sizeof( Header ) + sizeof(Type) * header.Num ); | ||||
|  | ||||
| 				new_header->Capacity = new_capacity; | ||||
|  | ||||
| 				gen::free( header.Allocator, & header ); | ||||
|  | ||||
| 				Data = rcast( Type*, new_header + 1); | ||||
|  | ||||
| 				return true; | ||||
| 			)); | ||||
|  | ||||
| 			set_capacity = def_function( name(set_capacity), def_param( t_uw, name(new_capacity)), t_bool, body ); | ||||
| 		} | ||||
|  | ||||
| 		CodeOpCast op_ptr = def_operator_cast( t_type_ptr, def_execution( code( | ||||
| 			return Data; | ||||
| 		))); | ||||
|  | ||||
| 		CodeBody body = def_struct_body( args( | ||||
| 			  using_header | ||||
| 			, using_type | ||||
| 			, ct_grow_formula | ||||
|  | ||||
| 			, init | ||||
| 			, init_reserve | ||||
|  | ||||
| 			, append | ||||
| 			, back | ||||
| 			, clear | ||||
| 			, fill | ||||
| 			, free | ||||
| 			, get_header | ||||
| 			, grow | ||||
| 			, num | ||||
| 			, pop | ||||
| 			, remove_at | ||||
| 			, reserve | ||||
| 			, resize | ||||
| 			, set_capacity | ||||
|  | ||||
| 			, op_ptr | ||||
|  | ||||
| 			, data | ||||
| 		)); | ||||
| 		array = def_struct( name, body ); | ||||
| 	} | ||||
|  | ||||
| 	return array; | ||||
| } | ||||
|  | ||||
|  | ||||
| struct GenArrayRequest | ||||
| { | ||||
| 	StrC Dependency; | ||||
| 	StrC Type; | ||||
| }; | ||||
| Array<GenArrayRequest> GenArrayRequests; | ||||
|  | ||||
| void gen__array_request( StrC type, StrC dep = {} ) | ||||
| { | ||||
| 	do_once_start | ||||
| 		GenArrayRequests = Array<GenArrayRequest>::init( GlobalAllocator ); | ||||
| 	do_once_end | ||||
|  | ||||
| 	// Make sure we don't already have a request for the type. | ||||
| 	for ( ssize idx = 0; idx < GenArrayRequests.num(); ++idx ) | ||||
| 	{ | ||||
| 		StrC const reqest_type = GenArrayRequests[ idx ].Type; | ||||
|  | ||||
| 		if ( reqest_type.Len != type.Len ) | ||||
| 			continue; | ||||
|  | ||||
| 		if ( str_compare( reqest_type.Ptr, type.Ptr, reqest_type.Len ) == 0 ) | ||||
| 			return; | ||||
| 	} | ||||
|  | ||||
| 	GenArrayRequest request = { dep, type }; | ||||
| 	GenArrayRequests.append( request ); | ||||
| } | ||||
| #define gen_array( type ) gen__array_request( code(type) ) | ||||
|  | ||||
| u32 gen_array_file() | ||||
| { | ||||
| 	Builder | ||||
| 	gen_array_file; | ||||
| 	gen_array_file.open( "array.Upfront.gen.hpp" ); | ||||
|  | ||||
| 	CodeInclude include_gen = def_include( txt("gen.hpp") ); | ||||
| 	gen_array_file.print( include_gen ); | ||||
|  | ||||
| 	gen_array_file.print( def_using_namespace( name(gen))); | ||||
|  | ||||
| 	Code array_base = gen__array_base(); | ||||
| 	gen_array_file.print( array_base ); | ||||
|  | ||||
| 	GenArrayRequest* current = GenArrayRequests; | ||||
| 	s32 left = GenArrayRequests.num(); | ||||
| 	while (left--) | ||||
| 	{ | ||||
| 		GenArrayRequest const& request = * current; | ||||
|  | ||||
| 		Code generated_array = gen__array( request.Type ); | ||||
|  | ||||
| 		if ( request.Dependency ) | ||||
| 		{ | ||||
| 			char const* cmt_str = str_fmt_buf( "// Dependency for %s type", request.Type ); | ||||
| 			s32         cmt_len = str_len( cmt_str ); | ||||
|  | ||||
| 			CodeComment cmt     = def_comment( { cmt_len, cmt_str } ); | ||||
| 			CodeInclude include = def_include( request.Dependency ); | ||||
|  | ||||
| 			gen_array_file.print( cmt ); | ||||
| 			gen_array_file.print( include ); | ||||
| 		} | ||||
|  | ||||
| 		gen_array_file.print( generated_array ); | ||||
| 		current++; | ||||
| 	} | ||||
|  | ||||
| 	gen_array_file.write(); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| #endif | ||||
| @@ -1,275 +0,0 @@ | ||||
| #pragma once | ||||
|  | ||||
| #if GEN_TIME | ||||
| #include "gen.hpp" | ||||
|  | ||||
| using namespace gen; | ||||
|  | ||||
| Code gen__buffer_base() | ||||
| { | ||||
| 	CodeType t_allocator_info = def_type( name(AllocatorInfo) ); | ||||
|  | ||||
| 	Code header = def_struct( name(BufferHeader), | ||||
| 	def_struct_body( args( | ||||
| 		  def_variable( t_allocator_info, name(Backing) ) | ||||
| 		, def_variable( t_uw,             name(Capacity) ) | ||||
| 		, def_variable( t_uw,             name(Num) ) | ||||
| 	))); | ||||
|  | ||||
| 	return def_global_body( 1, header ); | ||||
| } | ||||
|  | ||||
| Code gen__buffer( StrC type, ssize type_size ) | ||||
| { | ||||
| 	static CodeType t_allocator_info = def_type( name(AllocatorInfo)); | ||||
|  | ||||
| 	static CodeUsing using_header = def_using( name(Header), def_type( name(BufferHeader) ) ); | ||||
|  | ||||
| 	StrC name; | ||||
| 	{ | ||||
| 		char const* name_str = str_fmt_buf( "Buffer_%s\0", type.Ptr ); | ||||
| 		s32         name_len = str_len( name_str ); | ||||
|  | ||||
| 		name = { name_len, name_str }; | ||||
| 	}; | ||||
|  | ||||
| 	CodeType t_buffer_type = def_type( name ); | ||||
|  | ||||
| 	CodeType t_type        = def_type( type ); | ||||
| 	CodeType t_type_ptr    = def_type( type, __, spec_ptr ); | ||||
| 	CodeType t_type_ref    = def_type( type, __, spec_ref ); | ||||
|  | ||||
| 	CodeType t_header      = def_type( name(Header) ); | ||||
| 	CodeType t_header_ptr  = def_type( name(Header), __, spec_ptr ); | ||||
| 	CodeType t_header_ref  = def_type( name(Header), __, spec_ref ); | ||||
|  | ||||
| 	CodeStruct buffer = {0}; | ||||
| 	{ | ||||
| 		CodeUsing using_type = def_using( name(Type), t_type ); | ||||
| 		CodeVar   data       = def_variable( t_type_ptr, name(Data) ); | ||||
|  | ||||
| 		CodeFn init; | ||||
| 		{ | ||||
| 			CodeParam params = def_params( args( | ||||
| 				  def_param( t_allocator_info, name(allocator)) | ||||
| 				, def_param( t_sw,             name(capacity)) | ||||
| 			)); | ||||
|  | ||||
| 			Code body = def_execution( code( | ||||
| 				Header* header = rcast( Header*, alloc( allocator, sizeof(Header) + capacity * sizeof(Type) ) ); | ||||
|  | ||||
| 				if ( header == nullptr ) | ||||
| 					return { nullptr }; | ||||
|  | ||||
| 				header->Backing  = allocator; | ||||
| 				header->Capacity = capacity; | ||||
| 				header->Num      = 0; | ||||
|  | ||||
| 				return { rcast( Type*, header + 1) }; | ||||
| 			)); | ||||
|  | ||||
| 			init = def_function( name(init), params, t_buffer_type, body, spec_static_member ); | ||||
| 		} | ||||
|  | ||||
| 		CodeFn init_copy; | ||||
| 		{ | ||||
| 			CodeParam params = def_params( args( | ||||
| 				  def_param( t_allocator_info, name(allocator)) | ||||
| 				, def_param( t_buffer_type,    name(other)) | ||||
| 			)); | ||||
|  | ||||
| 			init_copy = def_function( name(init), params, t_buffer_type | ||||
| 				, def_execution( code( | ||||
| 					Header& other_header = other.get_header(); | ||||
| 					Header* header = rcast( Header*, alloc( allocator, sizeof(Header) + other_header.Capacity * sizeof(Type) ) ); | ||||
|  | ||||
| 					if ( header == nullptr ) | ||||
| 						return { nullptr }; | ||||
|  | ||||
| 					header->Backing  = allocator; | ||||
| 					header->Capacity = other_header.Capacity; | ||||
| 					header->Num      = other_header.Num; | ||||
|  | ||||
| 					mem_copy( header + 1, other.Data, other_header.Num * sizeof(Type) ); | ||||
| 					return { rcast( Type*, header + 1) }; | ||||
| 				)) | ||||
| 			); | ||||
| 		} | ||||
|  | ||||
| 		CodeFn append = def_function( name(append), def_param( t_type, name(value)), t_void | ||||
| 			, def_execution( code( | ||||
| 				Header& header = get_header(); | ||||
| 				Data[ header.Num ] = value; | ||||
| 				header.Num++; | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeFn appendv; | ||||
| 		{ | ||||
| 			CodeParam params = def_params( args( | ||||
| 				  def_param( t_type_ptr, name( values)) | ||||
| 				, def_param( t_sw, 	 name( num)) | ||||
| 			)); | ||||
|  | ||||
| 			appendv = def_function( name(append), params, t_void | ||||
| 				, def_execution( code( | ||||
| 					Header& header = get_header(); | ||||
|  | ||||
| 					GEN_ASSERT( header.Num + num <= header.Capacity); | ||||
|  | ||||
| 					mem_copy( Data + header.Num, values, num * sizeof( Type ) ); | ||||
|  | ||||
| 					header.Num += num; | ||||
| 				)) | ||||
| 			); | ||||
| 		} | ||||
|  | ||||
| 		CodeFn clear = def_function( name(clear), __, t_void | ||||
| 			, def_execution( code( | ||||
| 				Header& header = get_header(); | ||||
| 				header.Num = 0; | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeFn end = def_function( name(end), __, t_type_ref | ||||
| 			, def_execution( code( | ||||
| 				Header& header = get_header(); | ||||
| 				return Data[ header.Num - 1 ]; | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeFn free = def_function( name(free), __, t_void | ||||
| 			, def_execution( code( | ||||
| 				Header& header = get_header(); | ||||
| 				gen::free( header.Backing, & header ); | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeFn get_header = def_function( name(get_header), __, t_header_ref | ||||
| 			, def_execution( code( | ||||
| 				return * ( rcast( Header*, Data ) - 1 ); | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeFn num = def_function( name(num), __, t_sw | ||||
| 			, def_execution( code( | ||||
| 				return get_header().Num; | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeFn pop = def_function( name(pop), __, t_type | ||||
| 			, def_execution( code( | ||||
| 				Header& header = get_header(); | ||||
| 				header.Num--; | ||||
| 				return Data[ header.Num ]; | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeFn wipe = def_function( name(wipe), __, t_void | ||||
| 			, def_execution( code( | ||||
| 				Header& header = get_header(); | ||||
| 				header.Num = 0; | ||||
| 				mem_set( Data, 0, header.Capacity * sizeof( Type ) ); | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeOpCast op_type_ptr = def_operator_cast( t_type_ptr, def_execution( code( | ||||
| 			return Data; | ||||
| 		))); | ||||
|  | ||||
| 		buffer = def_struct( name, def_struct_body( args( | ||||
| 			  using_header | ||||
| 			, using_type | ||||
|  | ||||
| 			, init | ||||
| 			, init_copy | ||||
| 			, append | ||||
| 			, appendv | ||||
| 			, clear | ||||
| 			, end | ||||
| 			, free | ||||
| 			, get_header | ||||
| 			, num | ||||
| 			, pop | ||||
| 			, wipe | ||||
|  | ||||
| 			, op_type_ptr | ||||
|  | ||||
| 			, data | ||||
| 		))); | ||||
| 	} | ||||
|  | ||||
| 	return buffer; | ||||
| } | ||||
|  | ||||
| struct GenBufferRequest | ||||
| { | ||||
| 	StrC Dependency; | ||||
| 	StrC Type; | ||||
| 	ssize   TypeSize; | ||||
| }; | ||||
| Array<GenBufferRequest> GenBufferRequests; | ||||
|  | ||||
| void gen__buffer_request( StrC type, StrC dep = {} ) | ||||
| { | ||||
| 	do_once_start | ||||
| 		GenBufferRequests = Array<GenBufferRequest>::init( GlobalAllocator ); | ||||
| 	do_once_end | ||||
|  | ||||
| 	// Make sure we don't already have a request for the type. | ||||
| 	for ( ssize idx = 0; idx < GenBufferRequests.num(); ++idx ) | ||||
| 	{ | ||||
| 		StrC const reqest_type = GenBufferRequests[ idx ].Type; | ||||
|  | ||||
| 		if ( reqest_type.Len != type.Len ) | ||||
| 			continue; | ||||
|  | ||||
| 		if ( str_compare( reqest_type.Ptr, type.Ptr, reqest_type.Len ) == 0 ) | ||||
| 			return; | ||||
| 	} | ||||
|  | ||||
| 	GenBufferRequest request = { dep, type}; | ||||
| 	GenBufferRequests.append( request ); | ||||
| } | ||||
| #define gen_buffer( type ) gen__buffer_request( code(type)) | ||||
|  | ||||
| u32 gen_buffer_file() | ||||
| { | ||||
| 	Builder | ||||
| 	gen_buffer_file; | ||||
| 	gen_buffer_file.open( "buffer.Upfront.gen.hpp" ); | ||||
|  | ||||
| 	gen_buffer_file.print( def_include( txt("gen.hpp")) ); | ||||
| 	gen_buffer_file.print( def_using_namespace( name(gen)) ); | ||||
|  | ||||
| 	gen_buffer_file.print( gen__buffer_base() ); | ||||
|  | ||||
| 	GenBufferRequest* current = GenBufferRequests; | ||||
| 	s32 left = GenBufferRequests.num(); | ||||
| 	while (left--) | ||||
| 	{ | ||||
| 		GenBufferRequest const& request = * current; | ||||
|  | ||||
| 		Code generated_buffer = gen__buffer( current->Type, current->TypeSize ); | ||||
|  | ||||
| 		if ( request.Dependency ) | ||||
| 		{ | ||||
| 			char const* cmt_str = str_fmt_buf( "// Dependency for %s type", request.Type ); | ||||
| 			s32         cmt_len = str_len( cmt_str ); | ||||
|  | ||||
| 			Code cmt     = def_comment( { cmt_len, cmt_str } ); | ||||
| 			Code include = def_include( request.Dependency ); | ||||
|  | ||||
| 			gen_buffer_file.print( cmt ); | ||||
| 			gen_buffer_file.print( include ); | ||||
| 		} | ||||
|  | ||||
| 		gen_buffer_file.print( generated_buffer ); | ||||
| 		current++; | ||||
| 	} | ||||
|  | ||||
| 	gen_buffer_file.write(); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| #endif // GEN_TIME | ||||
| @@ -1,486 +0,0 @@ | ||||
| #pragma once | ||||
|  | ||||
| #if GEN_TIME | ||||
| #include "gen.hpp" | ||||
| #include "Array.Upfront.hpp" | ||||
|  | ||||
| using namespace gen; | ||||
|  | ||||
| Code gen__hashtable_base() | ||||
| { | ||||
| 	CodeVar hashIndex   = def_variable( t_sw, name(HashIndex) ); | ||||
| 	CodeVar entry_prev  = def_variable( t_sw, name(PrevIndex) ); | ||||
| 	CodeVar entry_index = def_variable( t_sw, name(EntryIndex) ); | ||||
|  | ||||
| 	CodeStruct find_result = def_struct( name(HashTable_FindResult), def_struct_body( 3 | ||||
| 		, hashIndex | ||||
| 		, entry_prev | ||||
| 		, entry_index | ||||
| 	)); | ||||
|  | ||||
| 	return find_result; | ||||
| } | ||||
|  | ||||
| Code gen__hashtable( StrC type ) | ||||
| { | ||||
| 	static CodeType t_allocator_info = def_type( name(AllocatorInfo) ); | ||||
|  | ||||
| 	CodeType t_find_result = def_type( name(HashTable_FindResult) ); | ||||
|  | ||||
| 	StringCached name; | ||||
| 	{ | ||||
| 		char const* name_str = str_fmt_buf( "HashTable_%s", type.Ptr ); | ||||
| 		s32         len      = str_len( name_str ); | ||||
|  | ||||
| 		name = get_cached_string({ len, name_str }); | ||||
| 	} | ||||
|  | ||||
| 	CodeType t_ht_type = def_type( name ); | ||||
|  | ||||
| 	CodeType t_type     = def_type( type ); | ||||
| 	CodeType t_type_ptr = def_type( type, __, spec_ptr ); | ||||
| 	CodeType t_type_ref = def_type( type, __, spec_ref ); | ||||
|  | ||||
| 	// Hash table depends on array container for its entry structure. | ||||
| 	CodeType t_ht_entry, t_array_ht_entry; | ||||
| 	CodeStruct ht_entry, array_ht_entry; | ||||
| 	{ | ||||
| 		char const* name_str = str_fmt_buf( "HashTable_%s_Entry", type.Ptr ); | ||||
| 		s32         len      = str_len( name_str ); | ||||
|  | ||||
| 		StringCached ht_entry_name = get_cached_string({ len, name_str }); | ||||
|  | ||||
| 		t_ht_entry = def_type( ht_entry_name ); | ||||
| 		ht_entry   = def_struct( ht_entry_name, def_struct_body( args( | ||||
| 			  def_variable( t_u64,  name(Key)) | ||||
| 			, def_variable( t_sw,   name(Next)) | ||||
| 			, def_variable( t_type, name(Value)) | ||||
| 		))); | ||||
|  | ||||
| 		array_ht_entry   = gen__array( ht_entry_name ); | ||||
| 		t_array_ht_entry = def_type( array_ht_entry->Name ); | ||||
| 	} | ||||
|  | ||||
| 	CodeStruct hashtable = {0}; | ||||
| 	{ | ||||
| 		CodeUsing using_entry       = def_using( name(Entry), t_ht_entry ); | ||||
| 		CodeUsing using_array_entry = def_using( name(Array_Entry), t_array_ht_entry ); | ||||
| 		CodeUsing using_find_result = def_using( name(FindResult), t_find_result ); | ||||
|  | ||||
| 		CodeType t_array_sw    = def_type( name(Array_sw) ); | ||||
| 		CodeType t_array_entry = def_type( name(Array_Entry) ); | ||||
|  | ||||
| 		CodeVar hashes  = def_variable( t_array_sw, name(Hashes) ); | ||||
| 		CodeVar entries = def_variable( t_array_entry, name(Entries)); | ||||
|  | ||||
| 		CodeFn init; | ||||
| 		{ | ||||
| 			char const* tmpl = stringize( | ||||
| 				<type> result = { 0 }; | ||||
|  | ||||
| 				result.Hashes  = Array_sw   ::init( allocator ); | ||||
| 				result.Entries = Array_Entry::init( allocator ); | ||||
|  | ||||
| 				return result; | ||||
| 			); | ||||
| 			Code body = def_execution( token_fmt( "type", (StrC)name, tmpl ) ); | ||||
|  | ||||
| 			init = def_function( name(init), def_param( t_allocator_info, name(allocator)), t_ht_type, body, spec_static_member ); | ||||
| 		} | ||||
|  | ||||
|  | ||||
| 		CodeFn init_reserve; | ||||
| 		{ | ||||
| 			char const* tmpl = stringize( | ||||
| 				<type> result = { { nullptr }, { nullptr } }; | ||||
|  | ||||
| 				result.Hashes  = Array_sw::init_reserve( allocator, num ); | ||||
| 				result.Hashes.get_header()->Num = num; | ||||
|  | ||||
| 				result.Entries = Array_Entry::init_reserve( allocator, num ); | ||||
|  | ||||
| 				return result; | ||||
| 			); | ||||
| 			Code body = def_execution( token_fmt( "type", (StrC)name, tmpl ) ); | ||||
|  | ||||
| 			CodeParam params = def_params( args( def_param( t_allocator_info, name(allocator)), def_param( t_sw, name(num)))); | ||||
|  | ||||
| 			init_reserve = def_function( name(init_reserve), params, t_ht_type, body, spec_static_member ); | ||||
| 		} | ||||
|  | ||||
| 		CodeFn clear = def_function( name(clear), __, t_void | ||||
| 			, def_execution( code( | ||||
| 				for ( s32 idx = 0; idx < Hashes.num(); idx++ ) | ||||
| 					Hashes[ idx ] = -1; | ||||
|  | ||||
| 				Entries.clear(); | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeFn destroy = def_function( name(destroy), __, t_void | ||||
| 			, def_execution( code( | ||||
| 				if ( Hashes && Hashes.get_header()->Capacity ) | ||||
| 					Hashes.free(); | ||||
| 				if ( Entries && Hashes.get_header()->Capacity ) | ||||
| 					Entries.free(); | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeFn get = def_function( name(get), def_param( t_u64, name(key)), t_type_ptr | ||||
| 			, def_execution( code( | ||||
| 				ssize idx = find( key ).EntryIndex; | ||||
| 				if ( idx >= 0 ) | ||||
| 					return & Entries[ idx ].Value; | ||||
|  | ||||
| 				return nullptr; | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeUsing using_map_proc; | ||||
| 		{ | ||||
| 			char const* tmpl = stringize( | ||||
| 				void (*) ( u64 key, <type> value ) | ||||
| 			); | ||||
| 			CodeType value = def_type( token_fmt( "type", (StrC)t_type.to_string(), tmpl ) ); | ||||
|  | ||||
| 			using_map_proc = def_using ( name(MapProc), value); | ||||
| 		} | ||||
|  | ||||
| 		CodeFn map; | ||||
| 		{ | ||||
| 			CodeType t_map_proc = def_type( name(MapProc) ); | ||||
|  | ||||
| 			Code body = def_execution( code( | ||||
| 				GEN_ASSERT_NOT_NULL( map_proc ); | ||||
|  | ||||
| 				for ( ssize idx = 0; idx < Entries.num(); idx++ ) | ||||
| 				{ | ||||
| 					map_proc( Entries[ idx ].Key, Entries[ idx ].Value ); | ||||
| 				} | ||||
| 			)); | ||||
|  | ||||
| 			map = def_function( name(map), def_param( t_map_proc, name(map_proc) ), t_void, body ); | ||||
| 		} | ||||
|  | ||||
| 		CodeUsing using_map_mut_proc; | ||||
| 		{ | ||||
| 			char const* tmpl = stringize( | ||||
| 				void (*) ( u64 key, <type> value ) | ||||
| 			); | ||||
| 			CodeType value = def_type( token_fmt( "type", (StrC)t_type_ptr.to_string(), tmpl ) ); | ||||
|  | ||||
| 			using_map_mut_proc = def_using ( name(MapMutProc), value); | ||||
| 		} | ||||
|  | ||||
| 		CodeFn map_mut; | ||||
| 		{ | ||||
| 			CodeType t_map_mut_proc = def_type( name(MapMutProc)); | ||||
|  | ||||
| 			Code body = def_execution( code( | ||||
| 				GEN_ASSERT_NOT_NULL( map_proc ); | ||||
|  | ||||
| 				for ( ssize idx = 0; idx < Entries.num(); idx++ ) | ||||
| 				{ | ||||
| 					map_proc( Entries[ idx ].Key, & Entries[ idx ].Value ); | ||||
| 				} | ||||
| 			)); | ||||
|  | ||||
| 			map_mut = def_function( name(map_mut), def_param( t_map_mut_proc, name(map_proc)), t_void, body ); | ||||
| 		} | ||||
|  | ||||
| 		CodeFn grow = def_function( name(grow), __, t_void | ||||
| 			, def_execution( code( | ||||
| 				ssize new_num = array_grow_formula( Entries.num() ); | ||||
| 				rehash( new_num ); | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeFn rehash; | ||||
| 		{ | ||||
| 			char const* tmpl = stringize( | ||||
| 				ssize idx; | ||||
| 				ssize last_added_index; | ||||
|  | ||||
| 				<type> new_ht = init_reserve( Hashes.get_header()->Allocator, new_num ); | ||||
|  | ||||
| 				Array_sw::Header* hash_header = new_ht.Hashes.get_header(); | ||||
|  | ||||
| 				for ( idx = 0; idx < new_ht.Hashes.num(); ++idx ) | ||||
| 					new_ht.Hashes[ idx ] = -1; | ||||
|  | ||||
| 				for ( idx = 0; idx < Entries.num(); ++idx ) | ||||
| 				{ | ||||
| 					Entry& entry = Entries[ idx ]; | ||||
|  | ||||
| 					FindResult find_result; | ||||
|  | ||||
| 					if ( new_ht.Hashes.num() == 0 ) | ||||
| 						new_ht.grow(); | ||||
|  | ||||
| 					entry            = Entries[ idx ]; | ||||
| 					find_result      = new_ht.find( entry.Key ); | ||||
| 					last_added_index = new_ht.add_entry( 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; | ||||
| 				} | ||||
|  | ||||
| 				destroy(); | ||||
| 				*this = new_ht; | ||||
| 			); | ||||
| 			Code body = def_execution( token_fmt( "type", (StrC)name, tmpl ) ); | ||||
|  | ||||
| 			rehash = def_function( name(rehash), def_param( t_sw, name(new_num)), t_void, body ); | ||||
| 		} | ||||
|  | ||||
| 		CodeFn rehash_fast; | ||||
| 		{ | ||||
| 			char const* tmpl = stringize( | ||||
| 				ssize idx; | ||||
|  | ||||
| 				for ( idx = 0; idx < Entries.num(); idx++ ) | ||||
| 					Entries[ idx ].Next = -1; | ||||
|  | ||||
| 				for ( idx = 0; idx < Hashes.num(); idx++ ) | ||||
| 					Hashes[ idx ] = -1; | ||||
|  | ||||
| 				for ( idx = 0; idx < Entries.num(); idx++ ) | ||||
| 				{ | ||||
| 					Entry* entry; | ||||
|  | ||||
| 					FindResult find_result; | ||||
| 				} | ||||
| 			); | ||||
| 			Code body = def_execution( token_fmt( "type", name, tmpl ) ); | ||||
|  | ||||
| 			rehash_fast = def_function( name(rehash_fast), __, t_void, body ); | ||||
| 		} | ||||
|  | ||||
| 		CodeFn remove = def_function( name(remove), def_param( t_u64, name(key)), t_void | ||||
| 			, def_execution( code( | ||||
| 				FindResult find_result = find( key); | ||||
|  | ||||
| 				if ( find_result.EntryIndex >= 0 ) | ||||
| 				{ | ||||
| 					Entries.remove_at( find_result.EntryIndex ); | ||||
| 					rehash_fast(); | ||||
| 				} | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeFn remove_entry = def_function( name(remove_entry), def_param( t_sw, name(idx)), t_void | ||||
| 			, def_execution( code( | ||||
| 				Entries.remove_at( idx ); | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeFn set; | ||||
| 		{ | ||||
| 			CodeParam params = def_params( args( | ||||
| 				  def_param( t_u64,  name(key)) | ||||
| 				, def_param( t_type, name(value)) | ||||
| 			)); | ||||
|  | ||||
| 			Code body = def_execution( code( | ||||
| 				ssize idx; | ||||
| 				FindResult find_result; | ||||
|  | ||||
| 				if ( Hashes.num() == 0 ) | ||||
| 					grow(); | ||||
|  | ||||
| 				find_result = find( key ); | ||||
|  | ||||
| 				if ( find_result.EntryIndex >= 0 ) | ||||
| 				{ | ||||
| 					idx = find_result.EntryIndex; | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					idx = add_entry( key ); | ||||
|  | ||||
| 					if ( find_result.PrevIndex >= 0 ) | ||||
| 					{ | ||||
| 						Entries[ find_result.PrevIndex ].Next = idx; | ||||
| 					} | ||||
| 					else | ||||
| 					{ | ||||
| 						Hashes[ find_result.HashIndex ] = idx; | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 				Entries[ idx ].Value = value; | ||||
|  | ||||
| 				if ( full() ) | ||||
| 					grow(); | ||||
| 			)); | ||||
|  | ||||
| 			set = def_function( name(set), params, t_void, body ); | ||||
| 		} | ||||
|  | ||||
| 		CodeFn slot = def_function( name(slot), def_param( t_u64, name(key)), t_sw | ||||
| 			, def_execution( code( | ||||
| 				for ( ssize idx = 0; idx < Hashes.num(); ++idx ) | ||||
| 					if ( Hashes[ idx ] == key ) | ||||
| 						return idx; | ||||
|  | ||||
| 				return -1; | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeFn add_entry = def_function( name(add_entry), def_param( t_u64, name(key)), t_sw | ||||
| 			, def_execution( code( | ||||
| 				ssize idx; | ||||
| 				Entry entry = { key, -1 }; | ||||
|  | ||||
| 				idx = Entries.num(); | ||||
| 				Entries.append( entry ); | ||||
| 				return idx; | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeFn find = def_function( name(find), def_param( t_u64, name(key)), t_find_result | ||||
| 			, def_execution( code( | ||||
| 				FindResult result = { -1, -1, -1 }; | ||||
|  | ||||
| 				if ( Hashes.num() > 0 ) | ||||
| 				{ | ||||
| 					result.HashIndex    = key % Hashes.num(); | ||||
| 					result.EntryIndex  = Hashes[ result.HashIndex ]; | ||||
|  | ||||
| 					while ( result.EntryIndex >= 0 ) | ||||
| 					{ | ||||
| 						if ( Entries[ result.EntryIndex ].Key == key ) | ||||
| 							break; | ||||
|  | ||||
| 						result.PrevIndex  = result.EntryIndex; | ||||
| 						result.EntryIndex = Entries[ result.EntryIndex ].Next; | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 				return result; | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeFn full = def_function( name(full), __, t_b32 | ||||
| 			, def_execution( code( | ||||
| 				return 0.75f * Hashes.num() < Entries.num(); | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		hashtable = def_struct( name, def_struct_body( args( | ||||
| 			  using_entry | ||||
| 			, using_array_entry | ||||
| 			, using_find_result | ||||
| 			, using_map_proc | ||||
| 			, using_map_mut_proc | ||||
|  | ||||
| 			, init | ||||
| 			, init_reserve | ||||
|  | ||||
| 			, clear | ||||
| 			, destroy | ||||
| 			, get | ||||
| 			, grow | ||||
| 			, map | ||||
| 			, map_mut | ||||
| 			, rehash | ||||
| 			, rehash_fast | ||||
| 			, remove | ||||
| 			, remove_entry | ||||
| 			, set | ||||
| 			, slot | ||||
|  | ||||
| 			, hashes | ||||
| 			, entries | ||||
|  | ||||
| 			, access_protected | ||||
| 			, add_entry | ||||
| 			, find | ||||
| 			, full | ||||
| 		))); | ||||
| 	} | ||||
|  | ||||
| 	return def_global_body( args( ht_entry, array_ht_entry, hashtable )); | ||||
| } | ||||
|  | ||||
| struct GenHashTableRequest | ||||
| { | ||||
| 	StrC Dependency; | ||||
| 	StrC Type; | ||||
| }; | ||||
| Array<GenHashTableRequest> GenHashTableRequests; | ||||
|  | ||||
| void gen__hashtable_request( StrC type, StrC dep = {} ) | ||||
| { | ||||
| 	do_once_start | ||||
| 		GenHashTableRequests = Array<GenHashTableRequest>::init( GlobalAllocator ); | ||||
|  | ||||
| 		gen_array( ssize ); | ||||
| 	do_once_end | ||||
|  | ||||
| 	// Make sure we don't already have a request for the type. | ||||
| 	for ( ssize idx = 0; idx < GenHashTableRequests.num(); ++idx ) | ||||
| 	{ | ||||
| 		StrC const reqest_type = GenHashTableRequests[ idx ].Type; | ||||
|  | ||||
| 		if ( reqest_type.Len != type.Len ) | ||||
| 			continue; | ||||
|  | ||||
| 		if ( str_compare( reqest_type.Ptr, type.Ptr, reqest_type.Len ) == 0 ) | ||||
| 			return; | ||||
| 	} | ||||
|  | ||||
| 	GenHashTableRequest request = { dep, type }; | ||||
| 	GenHashTableRequests.append( request ); | ||||
| } | ||||
| #define gen_hashtable( type ) gen__hashtable_request( code(type)) | ||||
|  | ||||
| u32 gen_hashtable_file() | ||||
| { | ||||
| 	Builder | ||||
| 	gen_hashtable_file; | ||||
| 	gen_hashtable_file.open( "hashtable.Upfront.gen.hpp" ); | ||||
|  | ||||
| 	gen_hashtable_file.print( def_include( txt("gen.hpp")) ); | ||||
| 	gen_hashtable_file.print( def_include( txt("Array.Upfront.hpp")) ); | ||||
| 	gen_hashtable_file.print( def_include( txt("array.Upfront.gen.hpp")) ); | ||||
|  | ||||
| 	gen_hashtable_file.print( def_using_namespace( name(gen))); | ||||
|  | ||||
| 	gen_hashtable_file.print( gen__hashtable_base()); | ||||
|  | ||||
| 	GenHashTableRequest* current = GenHashTableRequests; | ||||
| 	s32 left = GenHashTableRequests.num(); | ||||
| 	while (left--) | ||||
| 	{ | ||||
| 		GenHashTableRequest const& request = * current; | ||||
|  | ||||
| 		Code generated_buffer = gen__hashtable( current->Type  ); | ||||
|  | ||||
| 		if ( request.Dependency ) | ||||
| 		{ | ||||
| 			char const* cmt_str = str_fmt_buf( "// Dependency for %s type", request.Type ); | ||||
| 			s32         cmt_len = str_len( cmt_str ); | ||||
|  | ||||
| 			Code cmt     = def_comment( { cmt_len, cmt_str } ); | ||||
| 			Code include = def_include( request.Dependency ); | ||||
|  | ||||
| 			gen_hashtable_file.print( cmt ); | ||||
| 			gen_hashtable_file.print( include ); | ||||
| 		} | ||||
|  | ||||
| 		gen_hashtable_file.print( generated_buffer ); | ||||
| 		current++; | ||||
| 	} | ||||
|  | ||||
| 	gen_hashtable_file.write(); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| #endif // GEN_TIME | ||||
| @@ -1,228 +0,0 @@ | ||||
| #pragma once | ||||
|  | ||||
| #if GEN_TIME | ||||
| #include "gen.hpp" | ||||
| #include "Buffer.Upfront.hpp" | ||||
|  | ||||
| using namespace gen; | ||||
|  | ||||
| Code gen__ring( StrC type ) | ||||
| { | ||||
| 	static CodeType t_allocator_info = def_type( name(AllocatorInfo) ); | ||||
|  | ||||
| 	String name; | ||||
| 	{ | ||||
| 		char const* name_str = str_fmt_buf( "Ring_%s\0", type.Ptr ); | ||||
| 		s32         name_len = str_len( name_str ); | ||||
|  | ||||
| 		name = get_cached_string({ name_len, name_str }); | ||||
| 	}; | ||||
|  | ||||
| 	CodeType t_ring_type     = def_type( name ); | ||||
| 	CodeType t_ring_type_ptr = def_type( name, __, spec_ptr ); | ||||
|  | ||||
| 	CodeType t_type       = def_type( type ); | ||||
| 	CodeType t_type_ptr   = def_type( type, __, spec_ptr ); | ||||
| 	CodeType t_type_ref   = def_type( type, __, spec_ref ); | ||||
|  | ||||
| 	CodeType t_buffer_type; | ||||
| 	{ | ||||
| 		char const* name_str = str_fmt_buf( "Buffer_%s\0", type.Ptr ); | ||||
| 		s32         len      = str_len( name_str ); | ||||
|  | ||||
| 		t_buffer_type = def_type( { len, name_str } ); | ||||
| 	} | ||||
|  | ||||
| 	CodeStruct ring = {0}; | ||||
| 	{ | ||||
| 		CodeUsing using_type = def_using( name(Type), t_type ); | ||||
|  | ||||
| 		CodeVar backing  = def_variable( t_allocator_info, name(Backing) ); | ||||
| 		CodeVar capacity = def_variable( t_uw, name(Capacity) ); | ||||
| 		CodeVar head     = def_variable( t_uw, name(Head) ); | ||||
| 		CodeVar tail     = def_variable( t_uw, name(Tail) ); | ||||
| 		CodeVar buffer   = def_variable( t_buffer_type, name(Buffer) ); | ||||
|  | ||||
| 		CodeFn init; | ||||
| 		{ | ||||
| 			CodeParam params = def_params( args( | ||||
| 				  def_param( t_allocator_info, name(allocator) ) | ||||
| 				, def_param( t_uw,             name(max_size) ) | ||||
| 			)); | ||||
|  | ||||
| 			char const* tmpl = stringize( | ||||
| 				<type> result = { 0 }; | ||||
|  | ||||
| 				result.Backing = allocator; | ||||
|  | ||||
| 				result.Buffer = Buffer_<data_type>::init( allocator, max_size + 1 ); | ||||
|  | ||||
| 				if ( result.Buffer == nullptr ) | ||||
| 					return { nullptr }; | ||||
|  | ||||
| 				result.Capacity = max_size + 1; | ||||
|  | ||||
| 				return result; | ||||
| 			); | ||||
| 			Code body = def_execution( token_fmt( "type", (StrC)name, "data_type", type, tmpl )); | ||||
|  | ||||
| 			init = def_function( name(init), params, t_ring_type, body, spec_static_member ); | ||||
| 		} | ||||
|  | ||||
| 		CodeFn append = def_function( name(append), def_param( t_type, name(value)), t_void | ||||
| 			, def_execution( code( | ||||
| 				Buffer[ Head ] = value; | ||||
| 				Head = ( Head + 1 ) % Capacity; | ||||
|  | ||||
| 			if ( Head == Tail ) | ||||
| 					Tail = ( Tail + 1 ) % Capacity; | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeFn appendv; | ||||
| 		{ | ||||
| 			CodeParam params = def_params( 2 | ||||
| 				, def_param( t_type_ptr, name(values)) | ||||
| 				, def_param( t_sw,       name(num)) | ||||
| 			); | ||||
|  | ||||
| 			Code body = def_execution( code( | ||||
| 				for ( ssize idx = 0; idx < num; idx++ ) | ||||
| 					append( values[ idx ] ); | ||||
| 			)); | ||||
|  | ||||
| 			appendv = def_function( name(append), params, t_void, body, spec_inline ); | ||||
| 		} | ||||
|  | ||||
| 		CodeFn empty = def_function( name(empty), __, t_bool | ||||
| 			, def_execution( code( | ||||
| 				return Head == Tail; | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeFn free = def_function( name(free), __, t_void | ||||
| 			, def_execution( code( | ||||
| 				Buffer.free(); | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeFn full = def_function( name(full), __, t_bool | ||||
| 			, def_execution( code( | ||||
| 				return (Head + 1) % Capacity == Tail; | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeFn get = def_function( name(get), __, t_type_ref | ||||
| 			, def_execution( code( | ||||
| 				Type& data = Buffer[ Tail ]; | ||||
| 				Tail = ( Tail + 1 ) % Capacity; | ||||
|  | ||||
| 				return data; | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		CodeFn wipe = def_function( name(wipe), __, t_void | ||||
| 			, def_execution( code( | ||||
| 				Head = 0; | ||||
| 				Tail = 0; | ||||
| 				Buffer.wipe(); | ||||
| 			)) | ||||
| 		); | ||||
|  | ||||
| 		ring = def_struct( name, def_struct_body( args( | ||||
| 			using_type, | ||||
|  | ||||
| 			init, | ||||
|  | ||||
| 			append, | ||||
| 			appendv, | ||||
| 			empty, | ||||
| 			free, | ||||
| 			full, | ||||
| 			get, | ||||
| 			wipe, | ||||
|  | ||||
| 			backing, | ||||
| 			capacity, | ||||
| 			head, | ||||
| 			tail, | ||||
| 			buffer | ||||
| 		))); | ||||
| 	} | ||||
|  | ||||
| 	return ring; | ||||
| } | ||||
|  | ||||
| struct GenRingRequest | ||||
| { | ||||
| 	StrC Dependency; | ||||
| 	StrC Type; | ||||
| }; | ||||
| Array<GenRingRequest> GenRingRequests; | ||||
|  | ||||
| void gen__ring_request( StrC type, StrC dep = {} ) | ||||
| { | ||||
| 	do_once_start | ||||
| 		GenRingRequests = Array<GenRingRequest>::init( GlobalAllocator ); | ||||
| 	do_once_end | ||||
|  | ||||
| 	// Make sure we don't already have a request for the type. | ||||
| 	for ( ssize idx = 0; idx < GenRingRequests.num(); ++idx ) | ||||
| 	{ | ||||
| 		StrC const reqest_type = GenRingRequests[ idx ].Type; | ||||
|  | ||||
| 		if ( reqest_type.Len != type.Len ) | ||||
| 			continue; | ||||
|  | ||||
| 		if ( str_compare( reqest_type.Ptr, type.Ptr, reqest_type.Len ) == 0 ) | ||||
| 			return; | ||||
| 	} | ||||
|  | ||||
| 	// Ring definition depends on a array and buffer definition. | ||||
| 	gen__buffer_request( type, dep ); | ||||
|  | ||||
| 	GenRingRequest request = { dep, type }; | ||||
| 	GenRingRequests.append( request ); | ||||
| } | ||||
| #define gen_ring( type ) gen__ring_request( code(type) ) | ||||
|  | ||||
| u32 gen_ring_file() | ||||
| { | ||||
| 	Builder | ||||
| 	gen_ring_file; | ||||
| 	gen_ring_file.open( "ring.Upfront.gen.hpp" ); | ||||
|  | ||||
| 	gen_ring_file.print( def_include( txt("gen.hpp")) ); | ||||
| 	gen_ring_file.print( def_include( txt("buffer.Upfront.gen.hpp")) ); | ||||
|  | ||||
| 	gen_ring_file.print( def_using_namespace( name(gen))); | ||||
|  | ||||
| 	GenRingRequest* current = GenRingRequests; | ||||
| 	s32 left = GenRingRequests.num(); | ||||
| 	while (left--) | ||||
| 	{ | ||||
| 		GenRingRequest const& request = * current; | ||||
|  | ||||
| 		Code generated_ring = gen__ring( current->Type ); | ||||
|  | ||||
| 		if ( request.Dependency ) | ||||
| 		{ | ||||
| 			char const* cmt_str = str_fmt_buf( "// Dependency for %s type", request.Type ); | ||||
| 			s32         cmt_len = str_len( cmt_str ); | ||||
|  | ||||
| 			Code cmt     = def_comment( { cmt_len, cmt_str } ); | ||||
| 			Code include = def_include( request.Dependency ); | ||||
|  | ||||
| 			gen_ring_file.print( cmt ); | ||||
| 			gen_ring_file.print( include ); | ||||
| 		} | ||||
|  | ||||
| 		gen_ring_file.print( generated_ring ); | ||||
| 		current++; | ||||
| 	} | ||||
|  | ||||
| 	gen_ring_file.write(); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| #endif // GEN_TIME | ||||
| @@ -1,331 +0,0 @@ | ||||
| #ifdef GEN_TIME | ||||
| #include "gen.hpp" | ||||
|  | ||||
| using namespace gen; | ||||
|  | ||||
| u32 gen_sanity_upfront() | ||||
| { | ||||
| 	Builder | ||||
| 	gen_sanity_file; | ||||
| 	gen_sanity_file.open("./sanity.Upfront.gen.hpp"); | ||||
|  | ||||
| 	// Comment | ||||
| 	{ | ||||
| 		CodeComment comment_test = def_comment( txt("Sanity check: def_comment test") ); | ||||
|  | ||||
| 		gen_sanity_file.print(comment_test); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
| 	gen_sanity_file.print( def_comment( txt( | ||||
| 		"The following will show a series of base cases for the gen api.\n" | ||||
| 	))); | ||||
|  | ||||
| 	// Class | ||||
| 	{ | ||||
| 		CodeClass fwd = def_class( name(TestEmptyClass) ); | ||||
| 		CodeClass empty_body; | ||||
| 		{ | ||||
| 			CodeComment cmt  = def_comment( txt("Empty class body") ); | ||||
| 			CodeBody    body = def_class_body( args( cmt ) ); | ||||
|  | ||||
| 			empty_body = def_class( name(TestEmptyClass), body ); | ||||
| 		} | ||||
|  | ||||
| 		gen_sanity_file.print(fwd); | ||||
| 		gen_sanity_file.print(empty_body); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	// Typedef | ||||
| 	{ | ||||
| 		CodeType    t_unsigned_char = def_type( name(unsigned char) ); | ||||
| 		CodeTypedef u8_typedef      = def_typedef( name(u8), t_unsigned_char ); | ||||
|  | ||||
| 		gen_sanity_file.print(u8_typedef); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	// Enum | ||||
| 	{ | ||||
| 		CodeEnum fwd = def_enum( name(ETestEnum), NullCode, t_u8 ); | ||||
| 		CodeEnum def; | ||||
| 		{ | ||||
| 			Code body = untyped_str( code( | ||||
| 				A, | ||||
| 				B, | ||||
| 				C | ||||
| 			)); | ||||
|  | ||||
| 			def = def_enum( name(ETestEnum), body, t_u8 ); | ||||
| 		} | ||||
|  | ||||
| 		CodeEnum fwd_enum_class = def_enum( name(ETestEnumClass), NullCode, t_u8, EnumClass ); | ||||
|  | ||||
| 		gen_sanity_file.print(fwd); | ||||
| 		gen_sanity_file.print(def); | ||||
| 		gen_sanity_file.print(fwd_enum_class); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	// External Linkage | ||||
| 	{ | ||||
| 		CodeBody body = def_extern_link_body( 1 | ||||
| 			, def_comment( txt("Empty extern body") ) | ||||
| 		); | ||||
|  | ||||
| 		CodeExtern c_extern = def_extern_link( name(C), body ); | ||||
|  | ||||
| 		gen_sanity_file.print(c_extern); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	// Friend | ||||
| 	{ | ||||
| 		CodeClass fwd  = def_class( name(TestFriendFwd)); | ||||
| 		CodeBody  body = def_class_body( args( def_friend( fwd ) ) ); | ||||
|  | ||||
| 		gen_sanity_file.print( def_class( name(TestFriend), body ) ); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	// Function | ||||
| 	{ | ||||
| 		CodeFn fwd = def_function( name(test_function) ); | ||||
| 		CodeFn def; | ||||
| 		{ | ||||
| 			CodeBody body = def_function_body( 1 | ||||
| 				, def_comment( txt("Empty function body") ) | ||||
| 			); | ||||
|  | ||||
| 			def = def_function( name(test_function), __, __, body ); | ||||
| 		} | ||||
|  | ||||
| 		gen_sanity_file.print(fwd); | ||||
| 		gen_sanity_file.print(def); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	// Include | ||||
| 	{ | ||||
| 		CodeInclude include = def_include( txt("../DummyInclude.hpp") ); | ||||
|  | ||||
| 		gen_sanity_file.print(include); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	// Module | ||||
| 	if (0) | ||||
| 	{ | ||||
| 		CodeModule module_export = def_module( name(TestModule), ModuleFlag::Export ); | ||||
| 		CodeModule module_import = def_module( name(TestModule), ModuleFlag::Import ); | ||||
| 		CodeModule module_both   = def_module( name(TestModule), ModuleFlag::Export | ModuleFlag::Import ); | ||||
|  | ||||
| 		gen_sanity_file.print(module_global_fragment); | ||||
| 		gen_sanity_file.print(module_private_fragment); | ||||
| 		gen_sanity_file.print(module_export); | ||||
| 		gen_sanity_file.print(module_import); | ||||
| 		gen_sanity_file.print(module_both); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	// Namespace | ||||
| 	{ | ||||
| 		CodeNS namespace_def; | ||||
| 		{ | ||||
| 			CodeBody body = def_namespace_body( 1 | ||||
| 				, def_comment( txt("Empty namespace body") ) | ||||
| 			); | ||||
|  | ||||
| 			namespace_def = def_namespace( name(TestNamespace), body ); | ||||
| 		} | ||||
|  | ||||
| 		gen_sanity_file.print(namespace_def); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	// Operator | ||||
| 	{ | ||||
| 		// Going to make a bit flag set of overloads for this. | ||||
|  | ||||
| 		CodeEnum bitflagtest; | ||||
| 		{ | ||||
| 			CodeBody body = def_enum_body( 1, untyped_str( code( | ||||
| 				A = 1 << 0, | ||||
| 				B = 1 << 1, | ||||
| 				C = 1 << 2 | ||||
| 			))); | ||||
| 			bitflagtest = def_enum( name(EBitFlagtest), body, t_u8,  EnumClass ); | ||||
| 		} | ||||
| 		CodeType t_bitflag = def_type( name(EBitFlagtest) ); | ||||
|  | ||||
| 		CodeOperator op_fwd, op_or; | ||||
| 		{ | ||||
| 			CodeParam params = def_params( args( | ||||
| 				def_param( t_bitflag, name(a) ), | ||||
| 				def_param( t_bitflag, name(b) ) | ||||
| 			)); | ||||
|  | ||||
| 			op_fwd = def_operator( EOperator::BOr, params, t_bitflag ); | ||||
| 			op_or  = def_operator( EOperator::BOr, params, t_bitflag, untyped_str( code( | ||||
| 				return EBitFlagtest( (u8)a | (u8)b ); | ||||
| 			))); | ||||
| 		} | ||||
|  | ||||
| 		gen_sanity_file.print(bitflagtest); | ||||
| 		gen_sanity_file.print(op_fwd); | ||||
| 		gen_sanity_file.print(op_or); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	// Operator cast | ||||
| 	{ | ||||
| 		CodeType t_u8_ptr = def_type( name(u8), __, spec_ptr ); | ||||
|  | ||||
| 		CodeOpCast op_ptr = def_operator_cast( t_u8_ptr, __ ); | ||||
|  | ||||
| 		CodeClass op_class = def_class( name(TestOperatorCast), def_class_body( args( op_ptr) ) ); | ||||
|  | ||||
| 		gen_sanity_file.print(op_class); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	// Parameters | ||||
| 	{ | ||||
| 		CodeFn fwd; | ||||
| 		{ | ||||
| 			CodeParam params = def_param( t_u8, name(a) ); | ||||
|  | ||||
| 			fwd = def_function( name(test_function_wparam), params ); | ||||
| 		} | ||||
|  | ||||
| 		CodeFn def, def2; | ||||
| 		{ | ||||
| 			CodeBody body = def_function_body( 1 | ||||
| 				, def_comment( txt("Empty function body") ) | ||||
| 			); | ||||
|  | ||||
| 			CodeParam params = def_params( args( | ||||
| 				  def_param( t_u8, name(a) ) | ||||
| 				, def_param( t_u8, name(b) ) | ||||
| 			)); | ||||
|  | ||||
| 			def = def_function( name(test_function_wparams), params, __, body ); | ||||
|  | ||||
| 			CodeParam param_a = def_param( t_u8, name(a)); | ||||
| 			CodeParam param_b = def_param( t_u8, name(b)); | ||||
| 			CodeParam params_arr[2] = { param_a, param_b }; | ||||
|  | ||||
| 			CodeParam params2 = def_params( 2, params_arr ); | ||||
|  | ||||
| 			def2 = def_function( name(test_function_wparams2), params2, __, body ); | ||||
| 		} | ||||
|  | ||||
| 		gen_sanity_file.print(fwd); | ||||
| 		gen_sanity_file.print(def); | ||||
| 		gen_sanity_file.print(def2); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	// Specifiers | ||||
| 	{ | ||||
| 		CodeFn fwd_fn = def_function( name(test_function_specifiers), __, __, __, spec_inline ); | ||||
|  | ||||
| 		// TODO : Need an op overload here | ||||
|  | ||||
| 		CodeType    u8_ptr         = def_type( name(u8), __, spec_ptr ); | ||||
| 		CodeTypedef typedef_u8_ptr = def_typedef( name(ConstExprTest), u8_ptr ); | ||||
|  | ||||
| 		gen_sanity_file.print(fwd_fn); | ||||
| 		gen_sanity_file.print(typedef_u8_ptr); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	// Struct | ||||
| 	{ | ||||
| 		CodeClass fwd = def_class( name(TestEmptyStruct) ); | ||||
| 		CodeClass empty_body; | ||||
| 		{ | ||||
| 			CodeComment cmt  = def_comment( txt("Empty struct body") ); | ||||
| 			CodeBody    body = def_class_body( args( cmt ) ); | ||||
|  | ||||
| 			empty_body = def_class( name(TestEmptyStruct), body ); | ||||
| 		} | ||||
|  | ||||
| 		gen_sanity_file.print(fwd); | ||||
| 		gen_sanity_file.print(empty_body); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	// Union | ||||
| 	{ | ||||
| 		CodeBody body = def_union_body( 1 | ||||
| 			, def_comment( txt("Empty union body") ) | ||||
| 		); | ||||
|  | ||||
| 		CodeUnion def = def_union( name(TestEmptyUnion), body ); | ||||
|  | ||||
| 		gen_sanity_file.print(def); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	// Using | ||||
| 	{ | ||||
| 		CodeUsing reg    = def_using( name(TestUsing), t_u8 ); | ||||
| 		CodeUsing nspace = def_using_namespace( name(TestNamespace) ); | ||||
|  | ||||
| 		gen_sanity_file.print(reg); | ||||
| 		gen_sanity_file.print(nspace); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	// Variable | ||||
| 	{ | ||||
| 		CodeVar bss  = def_variable( t_u8, name(test_variable) ); | ||||
| 		CodeVar data = def_variable( t_u8, name(test_variable2), untyped_str( code( 0x12 )) ); | ||||
|  | ||||
| 		gen_sanity_file.print(bss); | ||||
| 		gen_sanity_file.print(data); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	// Template | ||||
| 	{ | ||||
| 		CodeType t_Type = def_type( name(Type) ); | ||||
|  | ||||
| 		CodeTemplate tmpl = def_template(  def_param( t_class, name(Type) ) | ||||
| 			, def_function( name(test_template), def_param( t_Type, name(a) ), __ | ||||
| 				, def_function_body(1, def_comment( txt("Empty template function body"))) | ||||
| 			) | ||||
| 		); | ||||
|  | ||||
| 		gen_sanity_file.print(tmpl); | ||||
| 	} | ||||
|  | ||||
| 	gen_sanity_file.print_fmt("\n"); | ||||
|  | ||||
| 	gen_sanity_file.print( def_comment( txt( | ||||
| 		"End of base case tests.\n" | ||||
| 	))); | ||||
|  | ||||
| 	gen_sanity_file.write(); | ||||
| 	return 0; | ||||
| } | ||||
| #endif | ||||
| @@ -1,49 +0,0 @@ | ||||
| #ifdef GEN_TIME | ||||
| #define GEN_FEATURE_PARSING | ||||
| #define GEN_DEFINE_LIBRARY_CODE_CONSTANTS | ||||
| #define GEN_ENFORCE_STRONG_CODE_TYPES | ||||
| #define GEN_EXPOSE_BACKEND | ||||
| #define GEN_BENCHMARK | ||||
| #include "gen.cpp" | ||||
| #include "Array.Upfront.hpp" | ||||
| #include "Buffer.Upfront.hpp" | ||||
| #include "HashTable.Upfront.hpp" | ||||
| #include "Ring.Upfront.hpp" | ||||
| #include "Sanity.Upfront.hpp" | ||||
|  | ||||
|  | ||||
| using namespace gen; | ||||
|  | ||||
|  | ||||
| int gen_main() | ||||
| { | ||||
| 	gen::init(); | ||||
|  | ||||
| 	gen_sanity_upfront(); | ||||
|  | ||||
| 	gen_array( u8 ); | ||||
| 	gen_array( ssize ); | ||||
|  | ||||
| 	gen_buffer( u8 ); | ||||
|  | ||||
| 	gen_hashtable( u32 ); | ||||
|  | ||||
| 	gen_ring( s16 ); | ||||
|  | ||||
| 	gen_array_file(); | ||||
| 	gen_buffer_file(); | ||||
| 	gen_hashtable_file(); | ||||
| 	gen_ring_file(); | ||||
|  | ||||
| 	gen::deinit(); | ||||
| 	return 0; | ||||
| } | ||||
| #endif | ||||
|  | ||||
|  | ||||
| #ifdef runtime | ||||
| int main() | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| #endif | ||||
| @@ -1,21 +0,0 @@ | ||||
| #ifdef GEN_TIME | ||||
| #define GEN_FEATURE_PARSING | ||||
| #define GEN_DEFINE_LIBRARY_CODE_CONSTANTS | ||||
| #define GEN_ENFORCE_STRONG_CODE_TYPES | ||||
| #define GEN_EXPOSE_BACKEND | ||||
| #define GEN_BENCHMARK | ||||
| #include "gen.hpp" | ||||
|  | ||||
| void check_parsing() | ||||
| { | ||||
| 	using namespace gen; | ||||
| 	log_fmt("\nupfront: "); | ||||
| 	gen::init(); | ||||
|  | ||||
| 	// TODO | ||||
|  | ||||
| 	gen::deinit(); | ||||
| 	log_fmt("Passed!\n"); | ||||
| } | ||||
|  | ||||
| #endif | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user