mirror of
https://github.com/Ed94/gencpp.git
synced 2024-11-10 02:54:53 -08:00
WIP: Array generation test. Still need gen.cpp impl.
This commit is contained in:
parent
340f466f24
commit
b4b518f005
27
Readme.md
27
Readme.md
@ -9,15 +9,16 @@ Version 1 will have c and a subset of c++ features available to it.
|
||||
|
||||
A metaprogram is built to generate files before the main program is built. We'll term runtime for this program as `gen_time`. The metaprogram's core implementation are within `gen.hpp` and `gen.cpp` in the project directory.
|
||||
|
||||
`gen.cpp` \`s `main()` will expect to call one `gen_main()` which the user will have to define once for their program. There they will dictate everything that should be generated.
|
||||
`gen.cpp` \`s `main()` is defined as `gen_main()` which the user will have to define once for their program. There they will dictate everything that should be generated.
|
||||
|
||||
In order to keep the locality of this code within the same files the following pattern may be used:
|
||||
|
||||
Within `program.cpp` :
|
||||
```cpp
|
||||
#ifdef gen_time
|
||||
#include "gen.hpp"
|
||||
|
||||
#ifdef gen_time
|
||||
|
||||
...
|
||||
|
||||
u32 gen_main()
|
||||
@ -37,19 +38,31 @@ This is ofc entirely optional and the metaprogram can be quite separated from th
|
||||
|
||||
## Building
|
||||
|
||||
To fill in.
|
||||
An example of building is provided in the test directory.
|
||||
|
||||
There are two meson build files the one within test is the program's build specification.
|
||||
The other one in the gen directory within test is the metaprogram's build specification.
|
||||
|
||||
Both of them build the same source file: `test.cpp`. The only differences between them is that gen need a different relative path to the include directories and defines the macro definition: `gen_time`.
|
||||
|
||||
This method is setup where all the metaprogram's code are the within the same files as the regular program's code.
|
||||
If in your use case, decide to have exclusive separation or partial separation of the metaprogam's code from the program's code files then your build configuration would need to change to reflect that (specifically the sources).
|
||||
|
||||
## Why
|
||||
|
||||
Macros in c/c++ are usually painful to debug, and templates can be unless your on a monsterous IDE (and even then fail often).
|
||||
|
||||
Unfortunately most programming langauges opt the approach of internally processing the generated code immediately within the AST or not expose it to the user in a nice way to even introspect as a text file. Stage metaprogramming doesn't have this problem, since its entire purpose is to create those generated files.
|
||||
Templates also have a heavy cost to compile-times due to their recursive nature of expansion if complex code is getting generated, or if heavy type checking system is used (assertsion require expansion, etc).
|
||||
|
||||
This is technically what the macro preprocessor does in a basic form, however naturally its easier to deal with for more complex generation.
|
||||
Unfortunately most programming langauges opt the approach of internally processing the generated code immediately within the AST or not expose it to the user in a nice way to even introspect as a text file.
|
||||
|
||||
The drawback naturally is generation functions at face value harder to grasp than something following a template pattern (for simple generation). This drawback becomes less valid the more complex the code generation becomes.
|
||||
Stage metaprogramming doesn't have this problem, since its entire purpose is to create those generated files that the final program will reference instead.
|
||||
|
||||
Thus a rule of thumb is if its a simple define you can get away with just the preprocessor, or if the templates being used don't break the debugger, this is most likely not neded.
|
||||
This is technically what the macro preprocessor does in a basic form, however a proper metaprogram for generation is easier to deal with for more complex generation.
|
||||
|
||||
The drawback naturally is generation functions, at face value, are harder to grasp than something following a template pattern (for simple generation). This drawback becomes less valid the more complex the code generation becomes.
|
||||
|
||||
Thus a rule of thumb is if its a simple definition you can get away with just the preprocessor `#define`, or if the templates being used don't break the debugger or your compile times, this is most likely not neded.
|
||||
|
||||
However, if the code being generated becomes complex, or from a datatable or database, this will be easier to deal with.
|
||||
|
||||
|
@ -57,6 +57,7 @@
|
||||
#define scast( Type_, Value_ ) static_cast< Type_ >( Value_ )
|
||||
#define rcast( Type_, Value_ ) reinterpret_cast< Type_ >( Value_ )
|
||||
#define pcast( Type_, Value_ ) ( * (Type_*)( & Value_ ) )
|
||||
#define txt( Value_ ) ZPL_STRINGIFY_EX( Value_ )
|
||||
|
||||
#define do_once() \
|
||||
do \
|
||||
@ -69,6 +70,19 @@ do \
|
||||
} \
|
||||
while(0) \
|
||||
|
||||
#define do_once_start \
|
||||
do \
|
||||
{ \
|
||||
static \
|
||||
bool Done = false; \
|
||||
if ( Done ) \
|
||||
break; \
|
||||
Done = true;
|
||||
|
||||
#define do_once_end \
|
||||
} \
|
||||
while(0);
|
||||
|
||||
|
||||
using Line = char*;
|
||||
using Array_Line = array( Line );
|
||||
|
114
project/gen.cpp
114
project/gen.cpp
@ -1,15 +1,21 @@
|
||||
#include "Bloat.hpp"
|
||||
#include "gen.hpp"
|
||||
#define gen_time
|
||||
|
||||
#ifdef gen_time
|
||||
namespace gen
|
||||
{
|
||||
void init()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ct Code make()
|
||||
{
|
||||
return { Code::Invalid, nullptr, nullptr, { nullptr } };
|
||||
}
|
||||
|
||||
Code decl_type( char const* name, Code specifiers, Code type )
|
||||
Code decl_type( char const* name, Code type, Code specifiers )
|
||||
{
|
||||
Code
|
||||
result = make();
|
||||
@ -47,7 +53,7 @@ namespace gen
|
||||
return result;
|
||||
}
|
||||
|
||||
Code make_parameters( s32 num, ... )
|
||||
Code def_parameters( s32 num, ... )
|
||||
{
|
||||
if (num <= 0)
|
||||
fatal("TT::make_paramters: num is %d", num);
|
||||
@ -85,30 +91,12 @@ namespace gen
|
||||
return result;
|
||||
}
|
||||
|
||||
Code make_fmt(char const* fmt, ...)
|
||||
{
|
||||
local_persist thread_local
|
||||
char buf[ZPL_PRINTF_MAXLEN] = { 0 };
|
||||
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
zpl_snprintf_va(buf, ZPL_PRINTF_MAXLEN, fmt, va);
|
||||
va_end(va);
|
||||
|
||||
Code
|
||||
result = make();
|
||||
result.Name = string_make( g_allocator, fmt );
|
||||
result.Type = Code::Untyped;
|
||||
result.Content = string_make( g_allocator, buf );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Code make_function( char const* name
|
||||
Code def_function( char const* name
|
||||
, Code specifiers
|
||||
, Code params
|
||||
, Code ret_type
|
||||
, Code body )
|
||||
, Code body
|
||||
)
|
||||
{
|
||||
Code
|
||||
result = make();
|
||||
@ -130,7 +118,22 @@ namespace gen
|
||||
return result;
|
||||
}
|
||||
|
||||
Code make_specifiers( u32 num, ... )
|
||||
Code def_function_body( u32 num, ... )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Code def_namespace( char const* name, Code body )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Code def_namespace_body( u32 num, ... )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Code def_specifiers( u32 num, ... )
|
||||
{
|
||||
if ( num <= 0 )
|
||||
fatal("gen::make_specifier: num cannot be zero.");
|
||||
@ -165,7 +168,22 @@ namespace gen
|
||||
return result;
|
||||
}
|
||||
|
||||
Code make_type( char const* name )
|
||||
Code def_struct( char const* name, Code body, Code parent, Code specifiers )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Code def_struct_body( u32 num, ... )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Code def_variable( char const* name, Code type, Code value, Code specifiers )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Code def_type( char const* name )
|
||||
{
|
||||
Code
|
||||
result = make();
|
||||
@ -175,6 +193,33 @@ namespace gen
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Code untyped_fmt(char const* fmt, ...)
|
||||
{
|
||||
local_persist thread_local
|
||||
char buf[ZPL_PRINTF_MAXLEN] = { 0 };
|
||||
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
zpl_snprintf_va(buf, ZPL_PRINTF_MAXLEN, fmt, va);
|
||||
va_end(va);
|
||||
|
||||
Code
|
||||
result = make();
|
||||
result.Name = string_make( g_allocator, fmt );
|
||||
result.Type = Code::Untyped;
|
||||
result.Content = string_make( g_allocator, buf );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Code token_fmt( char const* fmt, ... )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
string Code::to_string()
|
||||
{
|
||||
string result = string_make( g_allocator, "" );
|
||||
@ -232,6 +277,9 @@ namespace gen
|
||||
}
|
||||
break;
|
||||
|
||||
case Function_Body:
|
||||
break;
|
||||
|
||||
case Parameters:
|
||||
{
|
||||
result = string_append_fmt( result, "%s %s", Entries[0].to_string(), Name );
|
||||
@ -247,10 +295,6 @@ namespace gen
|
||||
}
|
||||
break;
|
||||
|
||||
case Struct:
|
||||
fatal("NOT SUPPORTED YET");
|
||||
break;
|
||||
|
||||
case Function:
|
||||
{
|
||||
u32 index = 0;
|
||||
@ -288,8 +332,16 @@ namespace gen
|
||||
result = string_append_fmt( result, "%s", Content );
|
||||
break;
|
||||
|
||||
case Struct:
|
||||
fatal("NOT SUPPORTED YET");
|
||||
break;
|
||||
|
||||
case Struct_Body:
|
||||
fatal("NOT SUPPORTED YET");
|
||||
break;
|
||||
|
||||
case Variable:
|
||||
// result = string_append_fmt( result, "%s", )
|
||||
fatal("NOT SUPPORTED YET");
|
||||
break;
|
||||
|
||||
case Typename:
|
||||
@ -300,6 +352,8 @@ namespace gen
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Builder::print( Code code )
|
||||
{
|
||||
Buffer = string_append_fmt( Buffer, "%s\n\n", code.to_string() );
|
||||
|
@ -20,6 +20,7 @@ namespace gen
|
||||
API_Export, // Vendor specific way to dynamic export
|
||||
External_Linkage, // extern
|
||||
Internal_Linkage, // static (within unit file)
|
||||
Static_Member, // static (within sturct/class)
|
||||
Local_Persist, // static (within function)
|
||||
Thread_Local, // thread_local
|
||||
|
||||
@ -62,7 +63,9 @@ namespace gen
|
||||
Decl_Function,
|
||||
Parameters, // Used with functions.
|
||||
Struct,
|
||||
Struct_Body,
|
||||
Function,
|
||||
Function_Body,
|
||||
Specifiers,
|
||||
Variable,
|
||||
Typename,
|
||||
@ -172,7 +175,11 @@ namespace gen
|
||||
Using_Code_POD;
|
||||
};
|
||||
|
||||
Code decl_type( char const* name, Code specifiers, Code type);
|
||||
constexpr Code UnusedCode = { Code::Unused, nullptr, nullptr, { nullptr } };
|
||||
|
||||
void init();
|
||||
|
||||
Code decl_type( char const* name, Code type, Code specifiers = UnusedCode );
|
||||
|
||||
Code decl_fn( char const* name
|
||||
, Code specifiers
|
||||
@ -180,26 +187,33 @@ namespace gen
|
||||
, Code ret_type
|
||||
);
|
||||
|
||||
Code make_parameters( s32 num, ... );
|
||||
Code def_parameters( s32 num, ... );
|
||||
|
||||
Code make_fmt( char const* fmt, ... );
|
||||
|
||||
Code make_function( char const* name
|
||||
Code def_function( char const* name
|
||||
, Code specifiers
|
||||
, Code params
|
||||
, Code ret_type
|
||||
, Code body
|
||||
);
|
||||
Code def_function_body( u32 num, ... );
|
||||
|
||||
Code make_specifiers( u32 num , ... );
|
||||
Code def_namespace( char const* name, Code body );
|
||||
Code def_namespace_body( u32 num, ... );
|
||||
|
||||
// Code make_variable( char const* name, char const* type );
|
||||
Code def_specifiers( u32 num , ... );
|
||||
|
||||
// Code make_template( Code subject, u32 num_dependents, ... );
|
||||
Code def_struct( char const* name, Code body, Code parent = UnusedCode, Code specifiers = UnusedCode );
|
||||
Code def_struct_body( u32 num, ... );
|
||||
|
||||
Code make_type( char const* name );
|
||||
Code def_variable( char const* name, Code type, Code value = UnusedCode, Code specifiers = UnusedCode );
|
||||
|
||||
// Code make_using( char const* name, char const* type );
|
||||
Code def_type( char const* name );
|
||||
|
||||
Code def_using( char const* name, Code type );
|
||||
|
||||
Code untyped_fmt( char const* fmt, ... );
|
||||
|
||||
Code token_fmt( char const* fmt, ... );
|
||||
|
||||
|
||||
struct Builder
|
||||
|
3
test/Array.cpp
Normal file
3
test/Array.cpp
Normal file
@ -0,0 +1,3 @@
|
||||
#include Array.cpp
|
||||
|
||||
|
376
test/Array.hpp
Normal file
376
test/Array.hpp
Normal file
@ -0,0 +1,376 @@
|
||||
/*
|
||||
This is based of the array container implementation in the zpl.h library.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Bloat.hpp"
|
||||
#include "gen.hpp"
|
||||
|
||||
#ifdef gen_time
|
||||
using namespace gen;
|
||||
|
||||
Code gen__array_base()
|
||||
{
|
||||
// Make these global consts to be accessed anywhere...
|
||||
Code t_sw = def_type( txt(sw) );
|
||||
Code t_uw = def_type( txt(uw) );
|
||||
Code t_allocator = def_type( txt(allocator) );
|
||||
|
||||
Code header;
|
||||
{
|
||||
Code num = def_variable( "Num", t_uw );
|
||||
Code capacity = def_variable( "Capacity", t_uw );
|
||||
Code allocator_var = def_variable( "Allocator", t_allocator );
|
||||
Code header_body = def_struct_body( 3, num, capacity, allocator_var );
|
||||
|
||||
header = def_struct( "ArrayHeader", header_body );
|
||||
}
|
||||
|
||||
Code grow_formula;
|
||||
{
|
||||
Code spec = def_specifiers(1, Specifier::Inline);
|
||||
Code params = def_parameters(1, "value", t_uw );
|
||||
Code body = untyped_fmt( "\t""return 2 * value * 8;" );
|
||||
|
||||
grow_formula = def_function( "grow_formula", spec, params, t_sw, body );
|
||||
}
|
||||
|
||||
Code base_body = def_struct_body(2, header, grow_formula);
|
||||
Code base = def_struct( "ArrayBase", base_body );
|
||||
return base;
|
||||
}
|
||||
|
||||
#define gen_array( Type_ ) gen__array( #Type_, sizeof(Type_), a_base )
|
||||
Code gen__array( char const* type_str, s32 type_size, Code parent )
|
||||
{
|
||||
// Make these global consts to be accessed anywhere...
|
||||
Code t_uw = def_type( txt(uw) );
|
||||
Code t_sw = def_type( txt(sw) );
|
||||
Code t_bool = def_type( txt(bool) );
|
||||
Code t_allocator = def_type( txt(allocator) );
|
||||
Code t_void = def_type( txt(void) );
|
||||
|
||||
Code v_nullptr = untyped_fmt( "nullptr" );
|
||||
|
||||
Code spec_ct = def_specifiers(1, Specifier::Constexpr );
|
||||
Code spec_inline = def_specifiers(1, Specifier::Inline );
|
||||
|
||||
Code type = def_type( type_str );
|
||||
Code ptr_type = def_type( string_sprintf_buf( g_allocator, "%s*", type_str ) );
|
||||
Code ref_type = def_type( string_sprintf_buf( g_allocator, "%s&", type_str ) );
|
||||
|
||||
string name = string_sprintf_buf( g_allocator, "Array_%s", type_str );
|
||||
|
||||
// From ArrayBase
|
||||
Code t_header = def_type( "Header" );
|
||||
Code ptr_header = def_type( "Header*" );
|
||||
Code ref_header = def_type( "Header&" );
|
||||
|
||||
Code array_def;
|
||||
{
|
||||
Code using_type = def_using( "type", type );
|
||||
Code data = def_variable( "Data", ptr_type );
|
||||
|
||||
Code init;
|
||||
{
|
||||
Code params = def_parameters( 1, "mem_hanlder", t_allocator );
|
||||
Code body = untyped_fmt( "\t""return init_reserve( mem_handler, grow_formula(0) );" );
|
||||
|
||||
init = def_function( "init", UnusedCode, params, t_bool, body );
|
||||
}
|
||||
|
||||
Code init_reserve;
|
||||
{
|
||||
Code params = def_parameters( 2, "mem_handler", ref_type, "capacity", t_sw );
|
||||
Code body;
|
||||
{
|
||||
Code header_value = untyped_fmt(
|
||||
"rcast( Header*, alloc( mem_handler, sizeof( Header ) + sizeof(type) + capacity ))"
|
||||
);
|
||||
Code header = def_variable( "", ptr_header, header_value );
|
||||
|
||||
Code null_check = untyped_fmt(
|
||||
"\t" "if (header == nullptr)"
|
||||
"\n\t\t" "return false;"
|
||||
);
|
||||
|
||||
Code header_init = untyped_fmt(
|
||||
"\n\t" "header->Num = 0;"
|
||||
"\n\t" "header->Capacity = capacity;"
|
||||
"\n\t" "header->Allocator = mem_handler;"
|
||||
);
|
||||
|
||||
Code assign_data = untyped_fmt(
|
||||
"\t" "Data = rcast( %s, header + 1 );", ptr_type
|
||||
);
|
||||
|
||||
Code ret_true = untyped_fmt( "\t""return true" );
|
||||
|
||||
body = def_function_body( 5
|
||||
, header
|
||||
, null_check
|
||||
, header_init
|
||||
, assign_data
|
||||
, ret_true
|
||||
);
|
||||
}
|
||||
|
||||
init_reserve = def_function( "init_reserve", UnusedCode, params, t_bool, body );
|
||||
}
|
||||
|
||||
Code free;
|
||||
{
|
||||
Code body = untyped_fmt(
|
||||
"\t" "Header& header = get_header();"
|
||||
"\n\t" "::free( header.Allocator, & get_header() );"
|
||||
);
|
||||
|
||||
free = def_function( "free", UnusedCode, UnusedCode, t_void, body );
|
||||
}
|
||||
|
||||
Code append;
|
||||
{
|
||||
Code params = def_parameters( 1, "value", type );
|
||||
Code body;
|
||||
{
|
||||
Code header = def_variable( "", ref_header, untyped_fmt( "get_header()") );
|
||||
|
||||
Code check_cap = untyped_fmt(
|
||||
"\t" "if ( header.Capacity < header.Num + 1 )"
|
||||
"\n\t\t" "if ( ! grow(0) )"
|
||||
"\n\t\t\t" "return false;"
|
||||
);
|
||||
|
||||
Code assign = untyped_fmt(
|
||||
"\t" "Data[ header.Num ] = value;"
|
||||
"\t\n" "header.Num++;"
|
||||
"\n"
|
||||
"\n\t" "return true;"
|
||||
);
|
||||
|
||||
body = def_function_body( 3, header, check_cap, assign );
|
||||
}
|
||||
|
||||
append = def_function( "append", UnusedCode, params, t_void, body );
|
||||
}
|
||||
|
||||
Code back;
|
||||
{
|
||||
Code body = untyped_fmt(
|
||||
"\t" "Header& header = get_header();"
|
||||
"\n\t" "return data[ header.Num - 1 ];"
|
||||
);
|
||||
|
||||
back = def_function( "back", UnusedCode, UnusedCode, type, body );
|
||||
}
|
||||
|
||||
Code clear;
|
||||
{
|
||||
Code body = untyped_fmt( "\t""get_header().Num = 0;" );
|
||||
|
||||
clear = def_function( "clear", UnusedCode, UnusedCode, t_void, body );
|
||||
}
|
||||
|
||||
Code fill;
|
||||
{
|
||||
Code params = def_parameters( 3, "begin", t_uw, "end", t_uw, "value", type );
|
||||
Code body;
|
||||
{
|
||||
Code header = def_variable( "", ref_header, untyped_fmt( "get_header()") );
|
||||
|
||||
Code check = untyped_fmt(
|
||||
"\t" "if ( begin < 0 || end >= header.Num )"
|
||||
"\n\t\t" "fatal( \"Range out of bounds\" );"
|
||||
);
|
||||
|
||||
Code iter = untyped_fmt(
|
||||
"\t" "for ( sw index = begin; index < end; index++ )"
|
||||
"\n\t\t" "Data[index] = vallue;"
|
||||
);
|
||||
|
||||
body = def_function_body( 3, header, check, iter );
|
||||
}
|
||||
|
||||
fill = def_function( "fill", UnusedCode, params, t_void, body );
|
||||
}
|
||||
|
||||
Code get_header;
|
||||
{
|
||||
Code body = untyped_fmt( "\t""return pcast( Header, Data - 1 );" );
|
||||
|
||||
get_header = def_function( "get_header", spec_inline, UnusedCode, ref_header, body );
|
||||
}
|
||||
|
||||
Code grow;
|
||||
{
|
||||
Code param = def_parameters( 1, "min_capacity", t_uw );
|
||||
Code body;
|
||||
{
|
||||
Code header = def_variable( "header", ref_header, untyped_fmt("get_header") );
|
||||
Code new_capacity = def_variable( "new_capacity", t_uw, untyped_fmt("grow_formula( header.Capacity )") );
|
||||
|
||||
Code check_n_set = untyped_fmt(
|
||||
"\t" "if ( new_capacity < min_capacity )"
|
||||
"\n\t\t" "new_capacity = min_capacity;"
|
||||
);
|
||||
|
||||
Code ret = untyped_fmt( "\t" "return set_capacity( new_capacity );" );
|
||||
|
||||
body = def_function_body( 4, header, new_capacity, check_n_set, ret );
|
||||
}
|
||||
|
||||
grow = def_function( "grow", UnusedCode, param, t_bool, body );
|
||||
}
|
||||
|
||||
Code pop;
|
||||
{
|
||||
Code body;
|
||||
{
|
||||
Code header = def_variable( "header", ref_header, untyped_fmt("get_header()") );
|
||||
|
||||
Code assertion = untyped_fmt( "\t" "assert( header.Num > 0 );" );
|
||||
Code decrement = untyped_fmt( "\t" "header.Num--; " );
|
||||
|
||||
body = def_function_body( 3, header, assertion, decrement );
|
||||
}
|
||||
|
||||
pop = def_function( "pop", UnusedCode, UnusedCode, t_void, body );
|
||||
}
|
||||
|
||||
Code reserve;
|
||||
{
|
||||
Code params = def_parameters( 1, "new_capacity", t_uw );
|
||||
Code body;
|
||||
{
|
||||
Code header = def_variable( "header", ref_header, untyped_fmt("get_header()") );
|
||||
|
||||
Code check_n_set = untyped_fmt(
|
||||
"\t" "if ( header.Capacity < new_capacity )"
|
||||
"\n\t\t" "return set_capacity( new_capacity );"
|
||||
);
|
||||
|
||||
Code ret = untyped_fmt( "\t" "return true" );
|
||||
|
||||
body = def_function_body( 3, header, check_n_set, ret );
|
||||
}
|
||||
|
||||
reserve = def_function( "reserve", UnusedCode, params, t_bool, body );
|
||||
}
|
||||
|
||||
Code resize;
|
||||
{
|
||||
Code param = def_parameters( 1, "new_num", t_uw );
|
||||
|
||||
Code body;
|
||||
{
|
||||
Code header = def_variable( "header", ref_header, untyped_fmt("get_header()") );
|
||||
|
||||
Code check_n_grow = untyped_fmt(
|
||||
"\t" "if ( header.Capacity < new_num )"
|
||||
"\n\t\t" "if ( ! grow( new_num) )"
|
||||
"\n\t\t\t" "return false;"
|
||||
);
|
||||
|
||||
Code set_n_ret = untyped_fmt(
|
||||
"\t" "header.Count = new_num;"
|
||||
"\n\t" "return true;"
|
||||
);
|
||||
|
||||
body = def_function_body( 3, header, check_n_grow, set_n_ret );
|
||||
}
|
||||
|
||||
resize = def_function( "resize", UnusedCode, param, t_bool, body );
|
||||
}
|
||||
|
||||
Code set_capacity;
|
||||
{
|
||||
Code param = def_parameters( 1, "capacity", t_uw );
|
||||
|
||||
Code body;
|
||||
{
|
||||
Code header = def_variable( "header", ref_header, untyped_fmt("get_header()") );
|
||||
|
||||
Code checks = untyped_fmt(
|
||||
"\t" "if ( capacity == header.Capacity )"
|
||||
"\n\t\t" "return true;"
|
||||
"\n"
|
||||
"\n\t" "if ( capacity < header.Num )"
|
||||
"\n\t\t" "header.Num = capacity;"
|
||||
);
|
||||
|
||||
Code size = def_variable( "size", t_uw, untyped_fmt("sizeof(Header) + sizeof(type) * capacity"));
|
||||
Code new_header = def_variable( "new_header", ptr_header, untyped_fmt("rcast( Header*, alloc( header.Allocator, size ));"));
|
||||
|
||||
Code check_n_move = untyped_fmt(
|
||||
"\t""if ( new_header == nullptr )"
|
||||
"\n\t\t""return false;"
|
||||
"\n"
|
||||
"\n\t""memmove( new_header, & header, sizeof(Header) + sizeof(type) * header.Num );"
|
||||
);
|
||||
|
||||
Code set_free_ret = untyped_fmt(
|
||||
"\t" "new_header->Allocator = header.Allocator;"
|
||||
"\n\t" "new_header->Num = header.Num;"
|
||||
"\n\t" "new_header->Capacity = header.Capacity;"
|
||||
"\n"
|
||||
"\n\t" "zpl_free( header );"
|
||||
"\n"
|
||||
"\n\t" "*Data = new_header + 1;"
|
||||
"\n"
|
||||
"\n\t" "return true;"
|
||||
);
|
||||
|
||||
body = def_function_body( 6, header, checks, size, new_header, check_n_move, set_free_ret );
|
||||
}
|
||||
|
||||
set_capacity = def_function( "set_capacity", UnusedCode, param, t_bool, body );
|
||||
}
|
||||
|
||||
Code body = def_struct_body( 15
|
||||
, using_type
|
||||
, data
|
||||
|
||||
, init
|
||||
, init_reserve
|
||||
, append
|
||||
, back
|
||||
, clear
|
||||
, fill
|
||||
, free
|
||||
, get_header
|
||||
, grow
|
||||
, pop
|
||||
, reserve
|
||||
, resize
|
||||
, set_capacity
|
||||
);
|
||||
|
||||
array_def = def_struct( name, body, parent );
|
||||
}
|
||||
|
||||
return array_def;
|
||||
}
|
||||
|
||||
u32 gen_array_file()
|
||||
{
|
||||
Code a_base = gen__array_base();
|
||||
|
||||
Code a_u32 = gen_array( u32 );
|
||||
Code a_cstr = gen_array( char const* );
|
||||
|
||||
Builder
|
||||
arraygen;
|
||||
arraygen.open( "Array.gen.hpp" );
|
||||
arraygen.print( a_u32 );
|
||||
arraygen.print( a_cstr );
|
||||
arraygen.write();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef gen_time
|
||||
# include "Array.gen.hpp"
|
||||
|
||||
# define array( Type_ ) array_##Type_
|
||||
#endif
|
@ -1,24 +0,0 @@
|
||||
inline
|
||||
u8 square(u8 value)
|
||||
{
|
||||
return value * value;
|
||||
}
|
||||
|
||||
inline
|
||||
u16 square(u16 value)
|
||||
{
|
||||
return value * value;
|
||||
}
|
||||
|
||||
inline
|
||||
u32 square(u32 value)
|
||||
{
|
||||
return value * value;
|
||||
}
|
||||
|
||||
inline
|
||||
u64 square(u64 value)
|
||||
{
|
||||
return value * value;
|
||||
}
|
||||
|
@ -12,7 +12,7 @@
|
||||
What it should generate:
|
||||
|
||||
inline
|
||||
type square_#type( type value )
|
||||
type square( type value )
|
||||
{
|
||||
return value * value;
|
||||
}
|
||||
@ -20,19 +20,18 @@
|
||||
#define gen_square( Type_ ) gen__square( #Type_ )
|
||||
Code gen__square( char const* type )
|
||||
{
|
||||
Code integral_type = make_type( type );
|
||||
Code integral_type = def_type( type );
|
||||
|
||||
string name = string_sprintf( g_allocator, (char*)sprintf_buf, ZPL_PRINTF_MAXLEN, "square", type );
|
||||
Code specifiers = make_specifiers( 1, Specifier::Inline );
|
||||
Code params = make_parameters( 1, "value", integral_type );
|
||||
Code ret_stmt = make_fmt( "\treturn value * value;" );
|
||||
|
||||
Code result = make_function( name,
|
||||
specifiers,
|
||||
params,
|
||||
integral_type,
|
||||
ret_stmt
|
||||
);
|
||||
Code result;
|
||||
{
|
||||
Code params = def_parameters( 1, "value", integral_type );
|
||||
Code specifiers = def_specifiers( 1, Specifier::Inline );
|
||||
Code ret_stmt = untyped_fmt( "\treturn value * value;" );
|
||||
|
||||
result = def_function( name, specifiers, params, integral_type, ret_stmt );
|
||||
}
|
||||
|
||||
if ( ! result )
|
||||
fatal( "Failed to generate square function for: %s", type );
|
||||
@ -60,7 +59,7 @@
|
||||
#endif
|
||||
|
||||
#ifndef gen_time
|
||||
#include "math.gen.hpp"
|
||||
#undef square
|
||||
# include "math.gen.hpp"
|
||||
# undef square
|
||||
|
||||
#endif
|
||||
|
@ -12,6 +12,8 @@ int gen_main()
|
||||
zpl_printf("\nPress any key after attaching to process\n");
|
||||
getchar();
|
||||
|
||||
gen::init()
|
||||
|
||||
int result = gen_math();
|
||||
|
||||
Memory::cleanup();
|
||||
|
33
thirdparty/zpl.h
vendored
33
thirdparty/zpl.h
vendored
@ -3948,24 +3948,28 @@ License:
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
ZPL_IMPL_INLINE b8 zpl__array_set_capacity(void **a_array, sw capacity) {
|
||||
array_header *h = ZPL_ARRAY_HEADER(*a_array);
|
||||
if (capacity == h->capacity) return true;
|
||||
if (capacity < h->count) h->count = capacity;
|
||||
sw size = size_of(array_header) + h->elem_size * capacity;
|
||||
array_header *nh = zpl_cast(array_header *) alloc(h->allocator, size);
|
||||
if (!nh) return false;
|
||||
zpl_memmove(nh, h, size_of(array_header) + h->elem_size * h->count);
|
||||
ZPL_IMPL_INLINE b8 zpl__array_set_capacity( void** a_array, sw capacity )
|
||||
{
|
||||
array_header* h = ZPL_ARRAY_HEADER( *a_array );
|
||||
if ( capacity == h->capacity )
|
||||
return true;
|
||||
if ( capacity < h->count )
|
||||
h->count = capacity;
|
||||
sw size = size_of( array_header ) + h->elem_size * capacity;
|
||||
array_header* nh = zpl_cast( array_header* ) alloc( h->allocator, size );
|
||||
if ( ! nh )
|
||||
return false;
|
||||
zpl_memmove( nh, h, size_of( array_header ) + h->elem_size * h->count );
|
||||
nh->allocator = h->allocator;
|
||||
nh->elem_size = h->elem_size;
|
||||
nh->count = h->count;
|
||||
nh->capacity = capacity;
|
||||
free(h->allocator, h);
|
||||
free( h->allocator, h );
|
||||
*a_array = nh + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
#define array_set_capacity(x, capacity) zpl__array_set_capacity(zpl_cast(void **) & (x), (capacity))
|
||||
#define array_set_capacity( x, capacity ) zpl__array_set_capacity( zpl_cast( void** ) & ( x ), ( capacity ) )
|
||||
|
||||
ZPL_IMPL_INLINE b8 zpl__array_grow(void **x, sw min_capacity) {
|
||||
sw new_capacity = ZPL_ARRAY_GROW_FORMULA(array_capacity(*x));
|
||||
@ -3982,7 +3986,14 @@ License:
|
||||
return true;
|
||||
}
|
||||
|
||||
#define array_append(x, item) (zpl__array_append_helper(zpl_cast(void **) & (x)) && (((x)[array_count(x)++] = (item)), true))
|
||||
#define array_append(x, item) \
|
||||
( \
|
||||
zpl__array_append_helper(zpl_cast(void **) & (x)) \
|
||||
&& ( \
|
||||
((x)[array_count(x)++] = (item)) \
|
||||
, true \
|
||||
) \
|
||||
)
|
||||
|
||||
ZPL_IMPL_INLINE b8 zpl__array_append_at_helper(void **x, sw ind) {
|
||||
if (ind >= array_count(*x)) ind = array_count(*x) - 1;
|
||||
|
Loading…
Reference in New Issue
Block a user