mirror of
https://github.com/Ed94/gencpp.git
synced 2025-06-14 18:51:47 -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