mirror of
				https://github.com/Ed94/gencpp.git
				synced 2025-10-30 22:40:54 -07:00 
			
		
		
		
	WIP: Restructuring project
This commit is contained in:
		| @@ -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 | ||||
| @@ -1,95 +0,0 @@ | ||||
| // Testing to make sure backend of library is operating properly. | ||||
|  | ||||
| #define GEN_DEFINE_LIBRARY_CODE_CONSTANTS | ||||
| #define GEN_ENFORCE_STRONG_CODE_TYPES | ||||
| #define GEN_EXPOSE_BACKEND | ||||
| #define GEN_BENCHMARK | ||||
|  | ||||
| #define GEN_GLOBAL_BUCKET_SIZE   megabytes(10) | ||||
| #define GEN_CODE_POOL_BLOCK_SIZE megabytes(32) | ||||
| #define GEN_STRING_ARENA_SIZE    megabytes(1) | ||||
|  | ||||
| #include "gen.hpp" | ||||
| #include "gen.builder.hpp" | ||||
|  | ||||
| void check_sanity() | ||||
| { | ||||
| 	using namespace gen; | ||||
| 	gen::init(); | ||||
| 	log_fmt("\ncheck_sanity:\n"); | ||||
|  | ||||
| 	// Test string caching: | ||||
| 	CodeType t_int_dupe = def_type( name(int) ); | ||||
|  | ||||
| 	if ( t_int_dupe->Name != t_int->Name ) | ||||
| 		GEN_FATAL("check_sanity: String caching failed!"); | ||||
|  | ||||
|  | ||||
| 	// Purposefully uses an excessive amount of memory to make sure the the memory backend doesn't break. | ||||
| 	// This has been tested with num_iterations set to 15000000 (generates 15 million lines of code), the Global_BlockSize, along with CodePool_NumBlocks, and SizePer_StringArena | ||||
| 	// must be adjusted to gigabytes(2), kilobytes(512), and gigabyte(1) for good performance without crashing. | ||||
| 	/* | ||||
| 		Typical usage (megabytes(10), kilobytes(4), megabytes(1), for 650000 (the limit of 10 meg partition buckets in global arena) ) | ||||
| 		Memory after builder: | ||||
| 		Num Global Arenas       : 14 TotalSize: 146800640 ! | ||||
| 		Num Code Pools          : 794 TotalSize: 416284672 ! | ||||
| 		Num String Cache Arenas : 60 TotalSize: 62914560 ! | ||||
| 		Num String Cache        : 1300007 | ||||
|  | ||||
| 		Memory usage to expect at 15 mil file: | ||||
| 		Num Global Arenas       : 2 TotalSize: 4294967296 ! | ||||
| 		Num Code Pools          : 144 TotalSize: 9663676416 ! | ||||
| 		Num String Cache Arenas : 2 TotalSize: 2147483648 ! | ||||
| 		Num String Cache        : 30000025 | ||||
| 	*/ | ||||
| 	constexpr | ||||
| 	s32 num_iterations = 325000; | ||||
|  | ||||
| 	Array<CodeTypedef> typedefs = Array<CodeTypedef>::init_reserve( GlobalAllocator, num_iterations * 2 ); | ||||
|  | ||||
| 	s32 idx = num_iterations; | ||||
| 	while( --idx ) | ||||
| 	{ | ||||
| 		// Stress testing string allocation | ||||
| 		String type_name = String::fmt_buf( GlobalAllocator, "type_%ld", idx ); | ||||
| 		String typedef_name = String::fmt_buf(GlobalAllocator, "typedef_%ld", idx ); | ||||
|  | ||||
| 		CodeTypedef type_as_int = def_typedef( type_name, t_int ); | ||||
| 		CodeType    type        = def_type( type_name ); | ||||
| 		CodeTypedef type_def    = def_typedef( typedef_name, type ); | ||||
|  | ||||
| 		typedefs.append( type_as_int ); | ||||
| 		typedefs.append( type_def ); | ||||
| 	} | ||||
|  | ||||
| 	log_fmt("\nMemory before builder:\n"); | ||||
| 	log_fmt("Num Global Arenas       : %llu TotalSize: %llu !\n", Global_AllocatorBuckets.num(), Global_AllocatorBuckets.num() * Global_BucketSize); | ||||
| 	log_fmt("Num Code Pools          : %llu TotalSize: %llu !\n", CodePools.num(), CodePools.num() * CodePool_NumBlocks * CodePools.back().BlockSize); | ||||
| 	log_fmt("Num String Cache Arenas : %llu TotalSize: %llu !\n", StringArenas.num(), StringArenas.num() * SizePer_StringArena); | ||||
| 	log_fmt("Num String Cache        : %llu\n", StringCache.Entries.num(), StringCache); | ||||
|  | ||||
| 	Builder builder = Builder::open( "./gen/sanity.gen.hpp" ); | ||||
|  | ||||
| 	idx = typedefs.num(); | ||||
| #ifdef GEN_BENCHMARK | ||||
| 	u64 time_start = time_rel_ms(); | ||||
| #endif | ||||
| 	while( --idx ) | ||||
| 	{ | ||||
| 		builder.print( typedefs[idx] ); | ||||
| 	} | ||||
|  | ||||
| 	builder.write(); | ||||
| #ifdef GEN_BENCHMARK | ||||
| 	log_fmt("\n\nBuilder finished writting. Time taken: %llu ms\n", time_rel_ms() - time_start); | ||||
| #endif | ||||
|  | ||||
| 	log_fmt("\nMemory after builder:\n"); | ||||
| 	log_fmt("Num Global Arenas       : %llu TotalSize: %llu !\n", Global_AllocatorBuckets.num(), Global_AllocatorBuckets.num() * Global_BucketSize); | ||||
| 	log_fmt("Num Code Pools          : %llu TotalSize: %llu !\n", CodePools.num(), CodePools.num() * CodePool_NumBlocks * CodePools.back().BlockSize); | ||||
| 	log_fmt("Num String Cache Arenas : %llu TotalSize: %llu !\n", StringArenas.num(), StringArenas.num() * SizePer_StringArena); | ||||
| 	log_fmt("Num String Cache        : %llu\n", StringCache.Entries.num(), StringCache); | ||||
|  | ||||
| 	gen::deinit(); | ||||
| 	log_fmt("\nSanity passed!\n"); | ||||
| } | ||||
| @@ -1,81 +0,0 @@ | ||||
| #if GEN_TIME | ||||
| #define GEN_DEFINE_LIBRARY_CODE_CONSTANTS | ||||
| #define GEN_ENFORCE_STRONG_CODE_TYPES | ||||
| #define GEN_EXPOSE_BACKEND | ||||
| #define GEN_BENCHMARK | ||||
| #include "gen.cpp" | ||||
| #include "gen.builder.cpp" | ||||
| #include "gen.scanner.cpp" | ||||
| #include "sanity.cpp" | ||||
| #include "SOA.cpp" | ||||
|  | ||||
| #ifdef GEN_SYSTEM_WINDOWS | ||||
| 	#include <process.h> | ||||
| #endif | ||||
|  | ||||
| using namespace gen; | ||||
|  | ||||
| void format_file( char const* path ) | ||||
| { | ||||
| 	String resolved_path = String::make(GlobalAllocator, to_str(path)); | ||||
|  | ||||
| 	String style_arg = String::make(GlobalAllocator, txt("-style=file:")); | ||||
| 	style_arg.append("../scripts/.clang-format "); | ||||
|  | ||||
| 	// Need to execute clang format on the generated file to get it to match the original. | ||||
| 	#define clang_format      "clang-format " | ||||
| 	#define cf_format_inplace "-i " | ||||
| 	#define cf_verbose        "-verbose " | ||||
| 	String command = String::make( GlobalAllocator, clang_format ); | ||||
| 	command.append( cf_format_inplace ); | ||||
| 	command.append( cf_verbose ); | ||||
| 	command.append( style_arg ); | ||||
| 	command.append( resolved_path ); | ||||
| 		log_fmt("\tRunning clang-format on file:\n"); | ||||
| 		system( command ); | ||||
| 		log_fmt("\tclang-format finished reformatting.\n"); | ||||
| 	#undef cf_cmd | ||||
| 	#undef cf_format_inplace | ||||
| 	#undef cf_style | ||||
| 	#undef cf_verbse | ||||
| } | ||||
|  | ||||
| Code dump_to_scratch_and_retireve( Code code ) | ||||
| { | ||||
| 	Builder ecode_file_temp = Builder::open("gen/scratch.hpp"); | ||||
| 	ecode_file_temp.print(code); | ||||
| 	ecode_file_temp.write(); | ||||
| 	format_file("gen/scratch.hpp"); | ||||
| 	Code result = scan_file( "gen/scratch.hpp" ); | ||||
| 	remove("gen/scratch.hpp"); | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| #include "validate.original.cpp" | ||||
| #include "validate.singleheader.cpp" | ||||
|  | ||||
| int gen_main() | ||||
| { | ||||
| 	log_fmt("\ngen_time:"); | ||||
|  | ||||
| 	// check_sanity(); | ||||
|  | ||||
| 	// check_SOA(); | ||||
|  | ||||
| 	// validate_original_files_ast(); | ||||
| 	validate_singleheader_ast(); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
| #endif | ||||
|  | ||||
|  | ||||
| // This only has to be done if symbol conflicts occur. | ||||
| #ifndef GEN_TIME | ||||
| 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_upfront() | ||||
| { | ||||
| 	using namespace gen; | ||||
| 	log_fmt("\nupfront: "); | ||||
| 	gen::init(); | ||||
|  | ||||
| 	// TODO | ||||
|  | ||||
| 	gen::deinit(); | ||||
| 	log_fmt("Passed!\n"); | ||||
| } | ||||
|  | ||||
| #endif | ||||
| @@ -1,3 +0,0 @@ | ||||
| // Constructs an AST from the bootstrap generated gen files, then serializes it to a set of files. | ||||
| // Using the new set of serialized files, reconstructs the AST and then serializes it again. | ||||
| // The two sets of serialized files should be identical. (Verified by comparing the file hashes) | ||||
| @@ -1,186 +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" | ||||
| #include "gen.scanner.hpp" | ||||
| using namespace gen; | ||||
|  | ||||
| #define path_root         "../" | ||||
| #define path_project      path_root       "project/" | ||||
| #define path_scripts      path_root       "scripts/" | ||||
| #define path_components   path_project    "components/" | ||||
| #define path_generated    path_components "gen/" | ||||
| #define path_dependencies path_project    "dependencies/" | ||||
| #define path_helpers      path_project    "helpers/" | ||||
|  | ||||
| void validate_file_ast( char const* path, char const* path_gen ) | ||||
| { | ||||
| 	log_fmt( "\nValidating: %s", path ); | ||||
|  | ||||
| 	String path_temp = String::make_length( GlobalAllocator, path_gen, str_len( path_gen ) ); | ||||
|  | ||||
| 	// Sleep(100); | ||||
| 	FileContents file  = file_read_contents( GlobalAllocator, true, path ); | ||||
|  | ||||
| 	// Duplicate and format | ||||
| 	{ | ||||
| 		// Sleep(100); | ||||
| 		FileInfo  scratch; | ||||
| 		FileError error = file_open_mode( & scratch, EFileMode_WRITE, "gen/scratch.cpp" ); | ||||
| 		if ( error != EFileError_NONE ) { | ||||
| 			log_failure( "gen::File::open - Could not open file: %s", "gen/scratch.cpp"); | ||||
| 			return; | ||||
| 		} | ||||
| 		// Sleep(100); | ||||
| 		b32 result = file_write( & scratch, file.data, file.size ); | ||||
| 		if ( result == false ) { | ||||
| 			log_failure("gen::File::write - Failed to write to file: %s\n", file_name( & scratch ) ); | ||||
| 			file_close( & scratch ); | ||||
| 			return; | ||||
| 		} | ||||
| 		file_close( & scratch ); | ||||
| 		// Sleep(100); | ||||
| 		format_file( "gen/scratch.cpp" ); | ||||
| 		// Sleep(100); | ||||
|  | ||||
| 		file = file_read_contents( GlobalAllocator, true, "gen/scratch.cpp" ); | ||||
| 	} | ||||
|  | ||||
| 	u64          time_start = time_rel_ms(); | ||||
| 	CodeBody     ast        = parse_global_body( { file.size, (char const*)file.data } ); | ||||
| 	log_fmt("\n\tAst generated. Time taken: %llu ms", time_rel_ms() - time_start); | ||||
|  | ||||
| 	log_fmt("\n\tSerializng ast:\n"); | ||||
| 	time_start = time_rel_ms(); | ||||
| 	Builder | ||||
| 	builder = Builder::open( path_gen ); | ||||
| 	builder.print( ast ); | ||||
| 	builder.write(); | ||||
| 	log_fmt("\tSerialized. Time taken: %llu ms", time_rel_ms() - time_start); | ||||
|  | ||||
| 	// Need to execute clang format on the generated file to get it to match the original. | ||||
| 	#define clang_format      "clang-format " | ||||
| 	#define cf_format_inplace "-i " | ||||
| 	#define cf_style          "-style=file:" "C:/projects/gencpp/scripts/.clang-format " | ||||
| 	#define cf_verbose        "-verbose " | ||||
| 	String command = String::make( GlobalAllocator, clang_format ); | ||||
| 	command.append( cf_format_inplace ); | ||||
| 	command.append( cf_style ); | ||||
| 	command.append( cf_verbose ); | ||||
| 	command.append( path_gen ); | ||||
| 		log_fmt("\n\tRunning clang-format on generated file:\n"); | ||||
| 		system( command ); | ||||
| 		log_fmt("\tclang-format finished reformatting."); | ||||
| 	#undef cf_cmd | ||||
| 	#undef cf_format_inplace | ||||
| 	#undef cf_style | ||||
| 	#undef cf_verbse | ||||
|  | ||||
| 	FileContents file_gen  = file_read_contents( GlobalAllocator, true, path_gen ); | ||||
| 	log_fmt("\n\tReconstructing from generated file:"); | ||||
| 	         time_start = time_rel_ms(); | ||||
| 	CodeBody ast_gen    = parse_global_body( { file_gen.size, (char const*)file_gen.data } ); | ||||
| 	log_fmt("\n\tAst generated. Time taken: %llu ms", time_rel_ms() - time_start); | ||||
|  | ||||
| 	time_start = time_rel_ms(); | ||||
|  | ||||
| 	if ( ast.is_equal( ast_gen ) ) | ||||
| 		log_fmt( "\n\tPassed!: AST passed validation! " ); | ||||
| 	else | ||||
| 		log_fmt( "\nFailed: AST did not pass validation " ); | ||||
|  | ||||
| 	log_fmt( "Time taken: %llu ms\n", time_rel_ms() - time_start ); | ||||
| } | ||||
|  | ||||
| void validate_original_files_ast() | ||||
| { | ||||
| 	gen::init(); | ||||
| 	log_fmt("\nvalidate_original_files_ast:\n"); | ||||
|  | ||||
| 	PreprocessorDefines.append( get_cached_string( txt("GEN_FILE_SEEK_PROC("))); | ||||
| 	PreprocessorDefines.append( get_cached_string( txt("GEN_FILE_READ_AT_PROC("))); | ||||
| 	PreprocessorDefines.append( get_cached_string( txt("GEN_FILE_WRITE_AT_PROC("))); | ||||
| 	PreprocessorDefines.append( get_cached_string( txt("GEN_FILE_CLOSE_PROC("))); | ||||
| 	PreprocessorDefines.append( get_cached_string( txt("GEN_FILE_OPEN_PROC("))); | ||||
|  | ||||
| 	// Helpers | ||||
| 	{ | ||||
| 		#define validate( path ) validate_file_ast( path_helpers path, "gen/original/helpers/" path ); | ||||
| 		validate( "push_ignores.inline.hpp" ); | ||||
| 		validate( "pop_ignores.inline.hpp" ); | ||||
| 		#undef validate | ||||
| 	} | ||||
|  | ||||
| 	// Dependencies | ||||
| 	{ | ||||
| 		#define validate( path ) validate_file_ast( path_dependencies path, "gen/original/dependencies/" path ) | ||||
| 		validate( "platform.hpp"     ); | ||||
| 		validate( "macros.hpp"       ); | ||||
| 		validate( "basic_types.hpp"  ); | ||||
| 		validate( "debug.hpp"        ); | ||||
| 		validate( "memory.hpp"       ); | ||||
| 		validate( "string_ops.hpp"   ); | ||||
| 		validate( "printing.hpp"     ); | ||||
| 		validate( "containers.hpp"   ); | ||||
| 		validate( "hashing.hpp"      ); | ||||
| 		validate( "strings.hpp"      ); | ||||
| 		validate( "filesystem.hpp"   ); | ||||
| 		validate( "timing.hpp"       ); | ||||
|  | ||||
| 		validate( "src_start.cpp"    ); | ||||
| 		validate( "debug.cpp"        ); | ||||
| 		validate( "string_ops.cpp"   ); | ||||
| 		validate( "printing.cpp"     ); | ||||
| 		validate( "memory.cpp"       ); | ||||
| 		validate( "hashing.cpp"      ); | ||||
| 		validate( "strings.cpp"      ); | ||||
| 		validate( "filesystem.cpp"   ); | ||||
| 		validate( "timing.cpp"       ); | ||||
|  | ||||
| 		validate( "parsing.cpp"      ); | ||||
| 		validate( "parisng.hpp"      ); | ||||
| 		#undef validate | ||||
| 	} | ||||
|  | ||||
| 	// Components | ||||
| 	{ | ||||
| 		#define validate( path ) validate_file_ast( path_components path, "gen/original/components/" path ) | ||||
| 		validate( "header_start.hpp" ); | ||||
| 		validate( "types.hpp" ); | ||||
| 		validate( "gen/ecode.hpp" ); | ||||
| 		validate( "gen/eoperator.hpp" ); | ||||
| 		validate( "gen/especifier.hpp" ); | ||||
| 		validate( "ast.hpp" ); | ||||
| 		validate( "code_types.hpp" ); | ||||
| 		validate( "ast_types.hpp" ); | ||||
| 		validate( "interface.hpp" ); | ||||
| 		validate( "inlines.hpp" ); | ||||
| 		validate( "gen/ast_inlines.hpp" ); | ||||
| 		validate( "header_end.hpp" ); | ||||
|  | ||||
| 		validate( "static_data.cpp" ); | ||||
| 		validate( "ast_case_macros.cpp" ); | ||||
| 		validate( "ast.cpp" ); | ||||
| 		validate( "code_serialization.cpp" ); | ||||
| 		validate( "interface.cpp" ); | ||||
| 		validate( "interface.upfront.cpp" ); | ||||
| 		validate( "gen/etoktype.cpp" ); | ||||
| 		validate( "lexer.cpp" ); | ||||
| 		validate( "parser.cpp" ); | ||||
| 		validate( "interface.parsing.cpp" ); | ||||
| 		validate( "interface.untyped.cpp" ); | ||||
| 		#undef validate | ||||
| 	} | ||||
|  | ||||
| 	gen::deinit(); | ||||
| } | ||||
|  | ||||
| #undef path_root | ||||
| #undef path_project | ||||
| #undef path_scripts | ||||
| #undef path_components | ||||
| #undef path_generated | ||||
| #undef path_dependencies | ||||
| @@ -1,86 +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" | ||||
| #include "gen.scanner.hpp" | ||||
| using namespace gen; | ||||
|  | ||||
| void validate_singleheader_ast() | ||||
| { | ||||
| 	#define root_dir "../" | ||||
| 	gen::init(); | ||||
| 	log_fmt("\nvalidate_singleheader_ast:\n"); | ||||
|  | ||||
| 	FileContents file = file_read_contents( GlobalAllocator, true, root_dir "singleheader/gen/gen.hpp" ); | ||||
|  | ||||
| 	// Duplicate and format | ||||
| 	{ | ||||
| 		// Sleep(100); | ||||
| 		FileInfo  scratch; | ||||
| 		FileError error = file_open_mode( & scratch, EFileMode_WRITE, "gen/scratch.cpp" ); | ||||
| 		if ( error != EFileError_NONE ) { | ||||
| 			log_failure( "gen::File::open - Could not open file: %s", "gen/scratch.cpp"); | ||||
| 			return; | ||||
| 		} | ||||
| 		// Sleep(100); | ||||
| 		b32 result = file_write( & scratch, file.data, file.size ); | ||||
| 		if ( result == false ) { | ||||
| 			log_failure("gen::File::write - Failed to write to file: %s\n", file_name( & scratch ) ); | ||||
| 			file_close( & scratch ); | ||||
| 			return; | ||||
| 		} | ||||
| 		file_close( & scratch ); | ||||
| 		// Sleep(100); | ||||
| 		format_file( "gen/scratch.cpp" ); | ||||
| 		// Sleep(100); | ||||
|  | ||||
| 		file = file_read_contents( GlobalAllocator, true, "gen/scratch.cpp" ); | ||||
| 	} | ||||
|  | ||||
| 	u64          time_start = time_rel_ms(); | ||||
| 	CodeBody     ast        = parse_global_body( { file.size, (char const*)file.data } ); | ||||
| 	log_fmt("\nAst generated. Time taken: %llu ms\n", time_rel_ms() - time_start); | ||||
|  | ||||
| 	log_fmt("\nSerializng ast:\n"); | ||||
| 	time_start = time_rel_ms(); | ||||
| 	Builder | ||||
| 	builder = Builder::open( "gen/singleheader_copy.gen.hpp" ); | ||||
| 	builder.print( ast ); | ||||
| 	builder.write(); | ||||
| 	log_fmt("Serialized. Time taken: %llu ms\n", time_rel_ms() - time_start); | ||||
|  | ||||
| 	// Need to execute clang format on the generated file to get it to match the original. | ||||
| 	#define script_path          root_dir "scripts/" | ||||
| 	#define clang_format         "clang-format " | ||||
| 	#define cf_format_inplace    "-i " | ||||
| 	#define cf_style             "-style=file:" "C:/projects/gencpp/scripts/.clang-format " | ||||
| 	#define cf_verbose           "-verbose " | ||||
|  | ||||
| 	log_fmt("\nRunning clang-format on generated file:\n"); | ||||
| 	system( clang_format cf_format_inplace cf_style cf_verbose "gen/singleheader_copy.gen.hpp" ); | ||||
| 	log_fmt("clang-format finished reformatting.\n"); | ||||
| 	#undef script_path | ||||
| 	#undef cf_cmd | ||||
| 	#undef cf_format_inplace | ||||
| 	#undef cf_style | ||||
| 	#undef cf_verbse | ||||
|  | ||||
| 	FileContents file_gen  = file_read_contents( GlobalAllocator, true, "gen/singleheader_copy.gen.hpp" ); | ||||
| 	log_fmt("\nReconstructing from generated file:\n"); | ||||
| 	         time_start = time_rel_ms(); | ||||
| 	CodeBody ast_gen    = parse_global_body( { file_gen.size, (char const*)file_gen.data } ); | ||||
| 	log_fmt("\nAst generated. Time taken: %llu ms\n\n", time_rel_ms() - time_start); | ||||
|  | ||||
| 	time_start = time_rel_ms(); | ||||
|  | ||||
| 	if ( ast.is_equal( ast_gen ) ) | ||||
| 		log_fmt( "\nPassed!: AST passed validation!\n" ); | ||||
| 	else | ||||
| 		log_fmt( "\nFailed: AST did not pass validation\n" ); | ||||
|  | ||||
| 	log_fmt( "Time taken: %llu ms\n", time_rel_ms() - time_start ); | ||||
|  | ||||
| 	gen::deinit(); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user