mirror of
https://github.com/Ed94/gencpp.git
synced 2024-11-10 02:54:53 -08:00
Parser constructor passes all current tests...
Pretty much have a working library now... Albiet with problably quite a few hidden bugs in parsing. Next steps are to start converting library to use its own Arena, Pool, Array, HashTable types. And either work on zpl dependency gutting or making a more robust set of tests.
This commit is contained in:
parent
ddb3244467
commit
f9085d4b6f
@ -588,8 +588,10 @@ Names or Content fields are interned strings and thus showed be cached using `ge
|
|||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
|
|
||||||
* May be in need of a better name, I found a few repos with this same one...
|
* Implement a context stack for the parsing, allows for accurate scope validation for the AST types.
|
||||||
* Make a test suite made up of collections based of the ZPL library templated colllection macros and the memory module.
|
* Make a test suite thats covers some base cases and zpl containers (+ anything else suitable)
|
||||||
|
* Finish support for module specifiers and standard/platform attributes.
|
||||||
* Remove full ZPL dependency, move into Bloat header/source only what is used.
|
* Remove full ZPL dependency, move into Bloat header/source only what is used.
|
||||||
* Generate a single-header library.
|
* Generate a single-header library.
|
||||||
* Actually get to version 1.
|
* Actually get to version 1.
|
||||||
|
* May be in need of a better name, I found a few repos with this same one...
|
||||||
|
@ -4615,16 +4615,19 @@ namespace gen
|
|||||||
case TokType::Access_Public:
|
case TokType::Access_Public:
|
||||||
member = access_public;
|
member = access_public;
|
||||||
eat( TokType::Access_Public );
|
eat( TokType::Access_Public );
|
||||||
|
eat( TokType::Assign_Classifer );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TokType::Access_Protected:
|
case TokType::Access_Protected:
|
||||||
member = access_protected;
|
member = access_protected;
|
||||||
eat( TokType::Access_Protected );
|
eat( TokType::Access_Protected );
|
||||||
|
eat( TokType::Assign_Classifer );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TokType::Access_Private:
|
case TokType::Access_Private:
|
||||||
member = access_private;
|
member = access_private;
|
||||||
eat( TokType::Access_Private );
|
eat( TokType::Access_Private );
|
||||||
|
eat( TokType::Assign_Classifer );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TokType::Decl_Class:
|
case TokType::Decl_Class:
|
||||||
@ -5721,10 +5724,13 @@ namespace gen
|
|||||||
{
|
{
|
||||||
using namespace Parser;
|
using namespace Parser;
|
||||||
|
|
||||||
|
Token context_tok = prevtok;
|
||||||
|
|
||||||
SpecifierT specs_found[16] { ESpecifier::Num_Specifiers };
|
SpecifierT specs_found[16] { ESpecifier::Num_Specifiers };
|
||||||
s32 num_specifiers = 0;
|
s32 num_specifiers = 0;
|
||||||
|
|
||||||
Token name = { nullptr, 0, TokType::Invalid };
|
Token name = { nullptr, 0, TokType::Invalid };
|
||||||
|
Token func_sig = { currtok.Text, 0, TokType::Invalid };
|
||||||
|
|
||||||
while ( left && tok_is_specifier( currtok ) )
|
while ( left && tok_is_specifier( currtok ) )
|
||||||
{
|
{
|
||||||
@ -5793,13 +5799,11 @@ namespace gen
|
|||||||
eat( currtok.Type );
|
eat( currtok.Type );
|
||||||
}
|
}
|
||||||
|
|
||||||
Token func_sig = { nullptr, 0, TokType::Invalid };
|
// Not sure if its technically possible to cast ot a function pointer user defined operator cast...
|
||||||
|
// Supporting it is not worth the effort.
|
||||||
if ( check( TokType::Capture_Start ) && prevtok.Type == TokType::Capture_End )
|
if ( check( TokType::Capture_Start ) && context_tok.Type != TokType::Decl_Operator )
|
||||||
{
|
{
|
||||||
// Its a function type
|
// Its a function type
|
||||||
|
|
||||||
func_sig = currtok;
|
|
||||||
eat( TokType::Capture_Start );
|
eat( TokType::Capture_Start );
|
||||||
|
|
||||||
while ( check( TokType::Star ) || currtok.Type == TokType::Spec_Const )
|
while ( check( TokType::Star ) || currtok.Type == TokType::Spec_Const )
|
||||||
@ -5807,6 +5811,8 @@ namespace gen
|
|||||||
eat( currtok.Type );
|
eat( currtok.Type );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if its a using statement there will not be an ID.
|
||||||
|
if ( check( TokType::Identifier ) )
|
||||||
eat(TokType::Identifier);
|
eat(TokType::Identifier);
|
||||||
|
|
||||||
eat( TokType::Capture_End );
|
eat( TokType::Capture_End );
|
||||||
@ -5817,8 +5823,15 @@ namespace gen
|
|||||||
|
|
||||||
// TODO : Change this to validate the parameters...
|
// TODO : Change this to validate the parameters...
|
||||||
// Bruteforce lex the parameters, no validation.
|
// Bruteforce lex the parameters, no validation.
|
||||||
while ( ! check( TokType::Capture_End ))
|
s32 level = 0;
|
||||||
|
while ( ! check( TokType::Capture_End ) || level > 0 )
|
||||||
{
|
{
|
||||||
|
if ( check( TokType::Capture_Start ) )
|
||||||
|
level++;
|
||||||
|
|
||||||
|
if ( check( TokType::Capture_End ) )
|
||||||
|
level--;
|
||||||
|
|
||||||
eat( currtok.Type );
|
eat( currtok.Type );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5833,17 +5846,10 @@ namespace gen
|
|||||||
result = make_code();
|
result = make_code();
|
||||||
result->Type = Typename;
|
result->Type = Typename;
|
||||||
|
|
||||||
if ( func_sig )
|
if ( func_sig.Length > 0 )
|
||||||
{
|
{
|
||||||
// Brute force name to the entire signature.
|
// Bruteforce all tokens together.
|
||||||
|
name = func_sig;
|
||||||
String custom_name = String::make( Memory::GlobalAllocator, name );
|
|
||||||
|
|
||||||
if ( num_specifiers )
|
|
||||||
custom_name.append( def_specifiers( num_specifiers, (SpecifierT*)specs_found ).to_string() );
|
|
||||||
|
|
||||||
custom_name.append( " " );
|
|
||||||
custom_name.append(func_sig );
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -50,7 +50,7 @@ $path_scripts = Join-Path $path_root scripts
|
|||||||
Pop-Location
|
Pop-Location
|
||||||
|
|
||||||
# Test NonParsed
|
# Test NonParsed
|
||||||
if ($false) {
|
if ($true) {
|
||||||
$gencpp = Join-Path $path_gen_build gencpp.exe
|
$gencpp = Join-Path $path_gen_build gencpp.exe
|
||||||
|
|
||||||
Push-location $path_gen
|
Push-location $path_gen
|
||||||
|
@ -23,7 +23,7 @@ Code gen__array_base()
|
|||||||
return def_global_body( 2, header, grow_formula );
|
return def_global_body( 2, header, grow_formula );
|
||||||
}
|
}
|
||||||
|
|
||||||
Code gen__array( StrC type, sw type_size )
|
Code gen__array( StrC type )
|
||||||
{
|
{
|
||||||
static Code t_allocator_info = def_type( name(AllocatorInfo) );
|
static Code t_allocator_info = def_type( name(AllocatorInfo) );
|
||||||
static Code v_nullptr = untyped_str( code(nullptr));
|
static Code v_nullptr = untyped_str( code(nullptr));
|
||||||
@ -299,11 +299,10 @@ struct GenArrayRequest
|
|||||||
{
|
{
|
||||||
StrC Dependency;
|
StrC Dependency;
|
||||||
StrC Type;
|
StrC Type;
|
||||||
sw Size;
|
|
||||||
};
|
};
|
||||||
Array(GenArrayRequest) GenArrayRequests;
|
Array(GenArrayRequest) GenArrayRequests;
|
||||||
|
|
||||||
void gen__array_request( StrC type, sw size, StrC dep = {} )
|
void gen__array_request( StrC type, StrC dep = {} )
|
||||||
{
|
{
|
||||||
do_once_start
|
do_once_start
|
||||||
array_init( GenArrayRequests, Memory::GlobalAllocator );
|
array_init( GenArrayRequests, Memory::GlobalAllocator );
|
||||||
@ -321,10 +320,10 @@ void gen__array_request( StrC type, sw size, StrC dep = {} )
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GenArrayRequest request = { dep, type, size };
|
GenArrayRequest request = { dep, type };
|
||||||
array_append( GenArrayRequests, request );
|
array_append( GenArrayRequests, request );
|
||||||
}
|
}
|
||||||
#define gen_array( type ) gen__array_request( { txt_to_StrC(type) }, sizeof(type) )
|
#define gen_array( type ) gen__array_request( { txt_to_StrC(type) } )
|
||||||
|
|
||||||
u32 gen_array_file()
|
u32 gen_array_file()
|
||||||
{
|
{
|
||||||
@ -344,7 +343,7 @@ u32 gen_array_file()
|
|||||||
{
|
{
|
||||||
GenArrayRequest const& request = * current;
|
GenArrayRequest const& request = * current;
|
||||||
|
|
||||||
Code generated_array = gen__array( request.Type, request.Size );
|
Code generated_array = gen__array( request.Type );
|
||||||
|
|
||||||
if ( request.Dependency )
|
if ( request.Dependency )
|
||||||
{
|
{
|
||||||
|
@ -48,7 +48,6 @@ Code gen__hashtable( StrC type, sw type_size )
|
|||||||
s32 len = str_len( name_str );
|
s32 len = str_len( name_str );
|
||||||
|
|
||||||
StringCached ht_entry_name = get_cached_string({ len, name_str });
|
StringCached ht_entry_name = get_cached_string({ len, name_str });
|
||||||
sw const entry_size = sizeof( u64 ) + sizeof( sw ) + type_size;
|
|
||||||
|
|
||||||
t_ht_entry = def_type( ht_entry_name );
|
t_ht_entry = def_type( ht_entry_name );
|
||||||
ht_entry = def_struct( ht_entry_name, def_struct_body( 3
|
ht_entry = def_struct( ht_entry_name, def_struct_body( 3
|
||||||
@ -57,7 +56,7 @@ Code gen__hashtable( StrC type, sw type_size )
|
|||||||
, def_variable( t_type, name(Value))
|
, def_variable( t_type, name(Value))
|
||||||
));
|
));
|
||||||
|
|
||||||
array_ht_entry = gen__array( ht_entry_name, entry_size );
|
array_ht_entry = gen__array( ht_entry_name );
|
||||||
t_array_ht_entry = def_type( array_ht_entry->Name );
|
t_array_ht_entry = def_type( array_ht_entry->Name );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +89,7 @@ Code gen__hashtable( StrC type, sw type_size )
|
|||||||
|
|
||||||
Code clear = def_function( name(clear), __, t_void
|
Code clear = def_function( name(clear), __, t_void
|
||||||
, def_execution( code(
|
, def_execution( code(
|
||||||
for ( s32 idx = 0; idx < Hashes.num(), idx++ )
|
for ( s32 idx = 0; idx < Hashes.num(); idx++ )
|
||||||
Hashes[ idx ] = -1;
|
Hashes[ idx ] = -1;
|
||||||
|
|
||||||
Entries.clear();
|
Entries.clear();
|
||||||
@ -222,7 +221,7 @@ Code gen__hashtable( StrC type, sw type_size )
|
|||||||
);
|
);
|
||||||
Code body = def_execution( token_fmt( tmpl, 1, "type", name ) );
|
Code body = def_execution( token_fmt( tmpl, 1, "type", name ) );
|
||||||
|
|
||||||
rehash = def_function( name(rehash), def_param( t_sw, name(new_num)), t_void, body, spec_inline);
|
rehash = def_function( name(rehash), def_param( t_sw, name(new_num)), t_void, body );
|
||||||
}
|
}
|
||||||
|
|
||||||
Code rehash_fast;
|
Code rehash_fast;
|
||||||
@ -435,7 +434,7 @@ u32 gen_hashtable_file()
|
|||||||
|
|
||||||
gen_buffer_file.print( def_include( StrC::from("Bloat.hpp")) );
|
gen_buffer_file.print( def_include( StrC::from("Bloat.hpp")) );
|
||||||
gen_buffer_file.print( def_include( StrC::from("Array.NonParsed.hpp")) );
|
gen_buffer_file.print( def_include( StrC::from("Array.NonParsed.hpp")) );
|
||||||
gen_buffer_file.print( def_include( StrC::from("array.gen.hpp")) );
|
gen_buffer_file.print( def_include( StrC::from("array.NonParsed.gen.hpp")) );
|
||||||
|
|
||||||
gen_buffer_file.print( gen__hashtable_base());
|
gen_buffer_file.print( gen__hashtable_base());
|
||||||
|
|
||||||
|
@ -1 +0,0 @@
|
|||||||
//
|
|
@ -197,7 +197,7 @@ u32 gen_ring_file()
|
|||||||
gen_ring_file.open( "ring.NonParsed.gen.hpp" );
|
gen_ring_file.open( "ring.NonParsed.gen.hpp" );
|
||||||
|
|
||||||
gen_ring_file.print( def_include( StrC::from("Bloat.hpp")) );
|
gen_ring_file.print( def_include( StrC::from("Bloat.hpp")) );
|
||||||
gen_ring_file.print( def_include( StrC::from("buffer.gen.hpp")) );
|
gen_ring_file.print( def_include( StrC::from("buffer.NonParsed.gen.hpp")) );
|
||||||
// gen_ring_file.print( gen__ring_base() );
|
// gen_ring_file.print( gen__ring_base() );
|
||||||
|
|
||||||
GenRingRequest* current = GenRingRequests;
|
GenRingRequest* current = GenRingRequests;
|
||||||
|
@ -22,7 +22,7 @@ Code gen__array_base()
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Code gen__array( StrC type, sw type_size )
|
Code gen__array( StrC type )
|
||||||
{
|
{
|
||||||
StrC name;
|
StrC name;
|
||||||
{
|
{
|
||||||
@ -184,7 +184,7 @@ Code gen__array( StrC type, sw type_size )
|
|||||||
header.Num = new_capacity;
|
header.Num = new_capacity;
|
||||||
|
|
||||||
sw size = sizeof( Header ) + sizeof( Type ) * new_capacity;
|
sw size = sizeof( Header ) + sizeof( Type ) * new_capacity;
|
||||||
Header* new_header = reinterpret_cast< Header* >( alloc( header.Allocator, size ) );
|
Header* new_header = rcast( Header*, alloc( header.Allocator, size ) );
|
||||||
|
|
||||||
if ( new_header == nullptr )
|
if ( new_header == nullptr )
|
||||||
return false;
|
return false;
|
||||||
@ -223,7 +223,6 @@ struct GenArrayRequest
|
|||||||
{
|
{
|
||||||
StrC Dependency;
|
StrC Dependency;
|
||||||
StrC Type;
|
StrC Type;
|
||||||
sw Size;
|
|
||||||
};
|
};
|
||||||
Array(GenArrayRequest) GenArrayRequests;
|
Array(GenArrayRequest) GenArrayRequests;
|
||||||
|
|
||||||
@ -245,7 +244,7 @@ void gen__array_request( StrC type, sw size, StrC dep = {} )
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GenArrayRequest request = { dep, type, size };
|
GenArrayRequest request = { dep, type };
|
||||||
array_append( GenArrayRequests, request );
|
array_append( GenArrayRequests, request );
|
||||||
}
|
}
|
||||||
#define gen_array( type ) gen__array_request( { txt_to_StrC(type) }, sizeof(type) )
|
#define gen_array( type ) gen__array_request( { txt_to_StrC(type) }, sizeof(type) )
|
||||||
@ -268,7 +267,7 @@ u32 gen_array_file()
|
|||||||
{
|
{
|
||||||
GenArrayRequest const& request = * current;
|
GenArrayRequest const& request = * current;
|
||||||
|
|
||||||
Code generated_array = gen__array( request.Type, request.Size );
|
Code generated_array = gen__array( request.Type );
|
||||||
|
|
||||||
if ( request.Dependency )
|
if ( request.Dependency )
|
||||||
{
|
{
|
||||||
|
202
test/Parsed/Buffer.Parsed.hpp
Normal file
202
test/Parsed/Buffer.Parsed.hpp
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if gen_time
|
||||||
|
#include "gen.hpp"
|
||||||
|
|
||||||
|
using namespace gen;
|
||||||
|
|
||||||
|
Code gen__buffer_base()
|
||||||
|
{
|
||||||
|
return parse_global_body( code(
|
||||||
|
struct BufferHeader
|
||||||
|
{
|
||||||
|
AllocatorInfo Backing;
|
||||||
|
uw Capacity;
|
||||||
|
uw 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(
|
||||||
|
txt(
|
||||||
|
struct <BufferName>
|
||||||
|
{
|
||||||
|
using Header = BufferHeader;
|
||||||
|
using Type = <type>;
|
||||||
|
|
||||||
|
static <BufferName> init( AllocatorInfo allocator, sw 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, sw num )
|
||||||
|
{
|
||||||
|
Header& header = get_header();
|
||||||
|
ZPL_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();
|
||||||
|
zpl::free( header.Backing, &header );
|
||||||
|
}
|
||||||
|
|
||||||
|
Header& get_header( void )
|
||||||
|
{
|
||||||
|
return *( rcast( Header*, Data ) - 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
sw 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;
|
||||||
|
};
|
||||||
|
),
|
||||||
|
2
|
||||||
|
, "BufferName", (char const*) name
|
||||||
|
, "type", (char const*) type
|
||||||
|
));
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct GenBufferRequest
|
||||||
|
{
|
||||||
|
StrC Dependency;
|
||||||
|
StrC Type;
|
||||||
|
};
|
||||||
|
Array(GenBufferRequest) GenBufferRequests;
|
||||||
|
|
||||||
|
void gen__buffer_request( StrC type, StrC dep = {} )
|
||||||
|
{
|
||||||
|
do_once_start
|
||||||
|
array_init( GenBufferRequests, Memory::GlobalAllocator );
|
||||||
|
do_once_end
|
||||||
|
|
||||||
|
// Make sure we don't already have a request for the type.
|
||||||
|
for ( sw idx = 0; idx < array_count( GenBufferRequests ); ++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 };
|
||||||
|
array_append( GenBufferRequests, request );
|
||||||
|
}
|
||||||
|
#define gen_buffer( type ) gen__buffer_request( { txt_to_StrC(type) } )
|
||||||
|
|
||||||
|
u32 gen_buffer_file()
|
||||||
|
{
|
||||||
|
Builder
|
||||||
|
gen_buffer_file;
|
||||||
|
gen_buffer_file.open( "buffer.Parsed.gen.hpp" );
|
||||||
|
|
||||||
|
gen_buffer_file.print( def_include( StrC::from("Bloat.hpp")) );
|
||||||
|
gen_buffer_file.print( gen__buffer_base() );
|
||||||
|
|
||||||
|
GenBufferRequest* current = GenBufferRequests;
|
||||||
|
s32 left = array_count( GenBufferRequests );
|
||||||
|
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
|
359
test/Parsed/HashTable.Parsed.hpp
Normal file
359
test/Parsed/HashTable.Parsed.hpp
Normal file
@ -0,0 +1,359 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if gen_time
|
||||||
|
#include "gen.hpp"
|
||||||
|
#include "Array.Parsed.hpp"
|
||||||
|
|
||||||
|
using namespace gen;
|
||||||
|
|
||||||
|
Code gen__hashtable_base()
|
||||||
|
{
|
||||||
|
return parse_global_body( code(
|
||||||
|
struct HashTable_FindResult
|
||||||
|
{
|
||||||
|
sw HashIndex;
|
||||||
|
sw PrevIndex;
|
||||||
|
sw EntryIndex;
|
||||||
|
};
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Code gen__hashtable( StrC type, sw type_size )
|
||||||
|
{
|
||||||
|
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(
|
||||||
|
txt(
|
||||||
|
struct <HashTableName>_Entry
|
||||||
|
{
|
||||||
|
u64 Key;
|
||||||
|
sw Next;
|
||||||
|
<type> Value;
|
||||||
|
};
|
||||||
|
),
|
||||||
|
2
|
||||||
|
, "HashTableName", (char const*) name
|
||||||
|
, "type", (char const*) type
|
||||||
|
));
|
||||||
|
|
||||||
|
StringCached ht_entry_name = get_cached_string( token_fmt( "<HashTableName>_Entry", 1, "HashTableName", name ) );
|
||||||
|
|
||||||
|
Code array_ht_entry = gen__array( ht_entry_name );
|
||||||
|
|
||||||
|
Code hashtable = parse_struct( token_fmt(
|
||||||
|
txt(
|
||||||
|
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 )
|
||||||
|
{
|
||||||
|
sw idx = find( key ).EntryIndex;
|
||||||
|
|
||||||
|
if ( idx > 0 )
|
||||||
|
return &Entries[ idx ].Value;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void grow( void )
|
||||||
|
{
|
||||||
|
sw new_num = array_grow_formula( Entries.num() );
|
||||||
|
|
||||||
|
rehash( new_num );
|
||||||
|
}
|
||||||
|
|
||||||
|
void map( MapProc map_proc )
|
||||||
|
{
|
||||||
|
ZPL_ASSERT_NOT_NULL( map_proc );
|
||||||
|
|
||||||
|
for ( sw idx = 0; idx < Entries.num(); idx++ )
|
||||||
|
{
|
||||||
|
map_proc( Entries[ idx ].Key, Entries[ idx ].Value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void map_mut( MapMutProc map_proc )
|
||||||
|
{
|
||||||
|
ZPL_ASSERT_NOT_NULL( map_proc );
|
||||||
|
|
||||||
|
for ( sw idx = 0; idx < Entries.num(); idx++ )
|
||||||
|
{
|
||||||
|
map_proc( Entries[ idx ].Key, &Entries[ idx ].Value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rehash( sw new_num )
|
||||||
|
{
|
||||||
|
sw idx;
|
||||||
|
sw 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 )
|
||||||
|
{
|
||||||
|
sw 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( sw idx )
|
||||||
|
{
|
||||||
|
Entries.remove_at( idx );
|
||||||
|
}
|
||||||
|
|
||||||
|
void set( u64 key, Type value )
|
||||||
|
{
|
||||||
|
sw 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
sw slot( u64 key )
|
||||||
|
{
|
||||||
|
for ( sw idx = 0; idx < Hashes.num(); ++idx )
|
||||||
|
if ( Hashes[ idx ] == key )
|
||||||
|
return idx;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Array_sw Hashes;
|
||||||
|
Array_Entry Entries;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
sw add_entry( u64 key )
|
||||||
|
{
|
||||||
|
sw 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();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
),
|
||||||
|
2
|
||||||
|
, "HashTableName", (char const*) name
|
||||||
|
, "type", (char const*) type
|
||||||
|
));
|
||||||
|
|
||||||
|
return def_global_body( 3, ht_entry, array_ht_entry, hashtable );
|
||||||
|
}
|
||||||
|
|
||||||
|
struct GenHashTableRequest
|
||||||
|
{
|
||||||
|
StrC Dependency;
|
||||||
|
StrC Type;
|
||||||
|
sw TypeSize;
|
||||||
|
};
|
||||||
|
Array(GenHashTableRequest) GenHashTableRequests;
|
||||||
|
|
||||||
|
void gen__hashtable_request( StrC type, sw size, StrC dep = {} )
|
||||||
|
{
|
||||||
|
do_once_start
|
||||||
|
array_init( GenHashTableRequests, Memory::GlobalAllocator );
|
||||||
|
|
||||||
|
gen_array( sw );
|
||||||
|
do_once_end
|
||||||
|
|
||||||
|
// Make sure we don't already have a request for the type.
|
||||||
|
for ( sw idx = 0; idx < array_count( GenHashTableRequests ); ++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, size};
|
||||||
|
array_append( GenHashTableRequests, request );
|
||||||
|
}
|
||||||
|
#define gen_hashtable( type ) gen__hashtable_request( { txt_to_StrC(type) }, sizeof( type ))
|
||||||
|
|
||||||
|
u32 gen_hashtable_file()
|
||||||
|
{
|
||||||
|
Builder
|
||||||
|
gen_buffer_file;
|
||||||
|
gen_buffer_file.open( "hashtable.Parsed.gen.hpp" );
|
||||||
|
|
||||||
|
gen_buffer_file.print( def_include( StrC::from("Bloat.hpp")) );
|
||||||
|
gen_buffer_file.print( def_include( StrC::from("Array.Parsed.hpp")) );
|
||||||
|
gen_buffer_file.print( def_include( StrC::from("array.Parsed.gen.hpp")) );
|
||||||
|
gen_buffer_file.print( gen__hashtable_base());
|
||||||
|
|
||||||
|
GenHashTableRequest* current = GenHashTableRequests;
|
||||||
|
s32 left = array_count( GenHashTableRequests );
|
||||||
|
while (left--)
|
||||||
|
{
|
||||||
|
GenHashTableRequest const& request = * current;
|
||||||
|
|
||||||
|
Code generated_buffer = gen__hashtable( 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
|
171
test/Parsed/Ring.Parsed.hpp
Normal file
171
test/Parsed/Ring.Parsed.hpp
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if gen_time
|
||||||
|
#include "gen.hpp"
|
||||||
|
#include "Buffer.Parsed.hpp"
|
||||||
|
|
||||||
|
using namespace gen;
|
||||||
|
|
||||||
|
Code gen__ring( StrC type )
|
||||||
|
{
|
||||||
|
static Code 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 });
|
||||||
|
};
|
||||||
|
|
||||||
|
Code ring = parse_struct( token_fmt(
|
||||||
|
txt(
|
||||||
|
struct <RingName>
|
||||||
|
{
|
||||||
|
using Type = <type>;
|
||||||
|
|
||||||
|
static <RingName> init( AllocatorInfo allocator, uw 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, sw num )
|
||||||
|
{
|
||||||
|
for ( sw 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;
|
||||||
|
uw Capacity;
|
||||||
|
uw Head;
|
||||||
|
uw Tail;
|
||||||
|
<BufferName> Buffer;
|
||||||
|
};
|
||||||
|
),
|
||||||
|
3
|
||||||
|
, "RingName", (char const*) name
|
||||||
|
, "type", (char const*) type
|
||||||
|
, "BufferName", str_fmt_buf( "Buffer_%s", type.Ptr )
|
||||||
|
));
|
||||||
|
|
||||||
|
return ring;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct GenRingRequest
|
||||||
|
{
|
||||||
|
StrC Dependency;
|
||||||
|
StrC Type;
|
||||||
|
};
|
||||||
|
Array(GenRingRequest) GenRingRequests;
|
||||||
|
|
||||||
|
void gen__ring_request( StrC type, sw size, StrC dep = {} )
|
||||||
|
{
|
||||||
|
do_once_start
|
||||||
|
array_init( GenRingRequests, Memory::GlobalAllocator );
|
||||||
|
do_once_end
|
||||||
|
|
||||||
|
// Make sure we don't already have a request for the type.
|
||||||
|
for ( sw idx = 0; idx < array_count( GenRingRequests ); ++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 };
|
||||||
|
array_append( GenRingRequests, request );
|
||||||
|
}
|
||||||
|
#define gen_ring( type ) gen__ring_request( { txt_to_StrC(type) }, sizeof( type ))
|
||||||
|
|
||||||
|
u32 gen_ring_file()
|
||||||
|
{
|
||||||
|
Builder
|
||||||
|
gen_ring_file;
|
||||||
|
gen_ring_file.open( "ring.Parsed.gen.hpp" );
|
||||||
|
|
||||||
|
gen_ring_file.print( def_include( StrC::from("Bloat.hpp")) );
|
||||||
|
gen_ring_file.print( def_include( StrC::from("buffer.Parsed.gen.hpp")) );
|
||||||
|
// gen_ring_file.print( gen__ring_base() );
|
||||||
|
|
||||||
|
GenRingRequest* current = GenRingRequests;
|
||||||
|
s32 left = array_count( GenRingRequests );
|
||||||
|
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,8 +1,8 @@
|
|||||||
#include "Bloat.cpp"
|
#include "Bloat.cpp"
|
||||||
#include "Parsed\Array.Parsed.hpp"
|
#include "Parsed\Array.Parsed.hpp"
|
||||||
// #include "Parsed\Buffer.Parsed.hpp"
|
#include "Parsed\Buffer.Parsed.hpp"
|
||||||
// #include "Parsed\HashTable.Parsed.hpp"
|
#include "Parsed\HashTable.Parsed.hpp"
|
||||||
// #include "Parsed\Ring.Parsed.hpp"
|
#include "Parsed\Ring.Parsed.hpp"
|
||||||
#include "Parsed\Sanity.Parsed.hpp"
|
#include "Parsed\Sanity.Parsed.hpp"
|
||||||
|
|
||||||
|
|
||||||
@ -17,21 +17,22 @@ int gen_main()
|
|||||||
Memory::setup();
|
Memory::setup();
|
||||||
gen::init();
|
gen::init();
|
||||||
|
|
||||||
// gen_sanity();
|
gen_sanity();
|
||||||
|
|
||||||
gen_array( u8 );
|
gen_array( u8 );
|
||||||
// gen_array( sw );
|
gen_array( sw );
|
||||||
|
|
||||||
// gen_buffer( u8 );
|
gen_buffer( u8 );
|
||||||
|
|
||||||
// gen_hashtable( u32 );
|
gen_hashtable( u32 );
|
||||||
|
|
||||||
// gen_ring( s16 );
|
gen_ring( s16 );
|
||||||
|
gen_ring( uw );
|
||||||
|
|
||||||
gen_array_file();
|
gen_array_file();
|
||||||
// gen_buffer_file();
|
gen_buffer_file();
|
||||||
// gen_hashtable_file();
|
gen_hashtable_file();
|
||||||
// gen_ring_file();
|
gen_ring_file();
|
||||||
|
|
||||||
gen::deinit();
|
gen::deinit();
|
||||||
Memory::cleanup();
|
Memory::cleanup();
|
||||||
|
Loading…
Reference in New Issue
Block a user