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