Compare commits
9 Commits
59951fb602
...
main
Author | SHA1 | Date | |
---|---|---|---|
922bb76c75 | |||
05823d7ef8 | |||
1bb3a0b196 | |||
2905b71835 | |||
4c7b0ad621 | |||
842955a3ef | |||
f3d32f00f9 | |||
d0dce15c58 | |||
8c9c3aea2f |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -3,4 +3,6 @@
|
||||
01_vec_no_metaprogramming
|
||||
02_vec_macros
|
||||
03_vec_xmacros
|
||||
04_vec_codegen
|
||||
04_codegen/codegen
|
||||
compile_commands.json
|
||||
|
498
04_codegen/codegen.c
Normal file
498
04_codegen/codegen.c
Normal file
@@ -0,0 +1,498 @@
|
||||
#include "codegen.h"
|
||||
#include "../mem_arena/arena.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define ARR_LEN(ARR) sizeof(ARR) / sizeof(ARR[0])
|
||||
#define MEM_ARENA_LENGTH 10 * 1024 * 1024
|
||||
#define LONG_BUFFER_LENGTH 8192
|
||||
#define MEDIUM_BUFFER_LENGTH 4096
|
||||
#define SHORT_BUFFER_LENGTH 1024
|
||||
|
||||
enum vec_funcs {
|
||||
VEC_FUNC_ADD,
|
||||
VEC_FUNC_SUB,
|
||||
VEC_FUNC_MUL,
|
||||
VEC_FUNC_DOT,
|
||||
VEC_FUNC_MAGNITUDE,
|
||||
VEC_FUNC_PRINT,
|
||||
|
||||
COUNT_VEC_FUNCS,
|
||||
};
|
||||
|
||||
void write_vec_func_implementation(arena_t *arena, func_data_t *func,
|
||||
const struct_def_t *s, char *body,
|
||||
const char *operator, const char * separator,
|
||||
const char *end);
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
const char *output_file = "vec.h";
|
||||
FILE *temp = fopen(output_file, "w");
|
||||
fclose(temp);
|
||||
|
||||
FILE *fp = fopen(output_file, "a");
|
||||
|
||||
arena_t main_mem = {0};
|
||||
arena_init(&main_mem, MEM_ARENA_LENGTH);
|
||||
|
||||
arena_t temp_mem = {0};
|
||||
arena_init(&temp_mem, MEM_ARENA_LENGTH);
|
||||
|
||||
const char *header_name = "VEC_H";
|
||||
|
||||
write_header_guard_open(&temp_mem, fp, header_name);
|
||||
|
||||
include_header_t headers[] = {
|
||||
{.type = INCLUDE_TYPE_USER, .header = "../aliases.h"},
|
||||
{.type = INCLUDE_TYPE_SYSTEM, .header = "stdio.h"},
|
||||
{.type = INCLUDE_TYPE_SYSTEM, .header = "math.h"},
|
||||
};
|
||||
|
||||
for (u64 i = 0; i < ARR_LEN(headers); ++i) {
|
||||
write_include(&temp_mem, fp, &(headers[i]));
|
||||
}
|
||||
|
||||
fwrite("\n", 1, 1, fp);
|
||||
|
||||
type_info_t base_types[] = {
|
||||
(type_info_t){.name = "i32", .short_name = 'i', .printf_spec = 'd'},
|
||||
(type_info_t){.name = "f32", .short_name = 'f', .printf_spec = 'f'},
|
||||
};
|
||||
|
||||
u64 dimensions[] = {2, 3};
|
||||
|
||||
const char *member_names[] = {"x", "y", "z"};
|
||||
|
||||
const char *arg_names[] = {"v1", "v2"};
|
||||
|
||||
func_data_t funcs[COUNT_VEC_FUNCS] = {
|
||||
[VEC_FUNC_ADD] =
|
||||
(func_data_t){
|
||||
.base_name = "vec_add",
|
||||
.arg_count = 2,
|
||||
.arg_names = arg_names,
|
||||
},
|
||||
[VEC_FUNC_SUB] =
|
||||
(func_data_t){
|
||||
.base_name = "vec_sub",
|
||||
.arg_count = 2,
|
||||
.arg_names = arg_names,
|
||||
},
|
||||
[VEC_FUNC_MUL] =
|
||||
(func_data_t){
|
||||
.base_name = "vec_mul",
|
||||
.arg_count = 2,
|
||||
.arg_names = arg_names,
|
||||
},
|
||||
[VEC_FUNC_DOT] =
|
||||
(func_data_t){
|
||||
.base_name = "vec_dot",
|
||||
.arg_count = 2,
|
||||
.arg_names = arg_names,
|
||||
},
|
||||
[VEC_FUNC_MAGNITUDE] =
|
||||
(func_data_t){
|
||||
.base_name = "vec_magnitude",
|
||||
.arg_count = 1,
|
||||
.arg_names = arg_names,
|
||||
},
|
||||
[VEC_FUNC_PRINT] =
|
||||
(func_data_t){
|
||||
.base_name = "vec_print",
|
||||
.arg_count = 1,
|
||||
.arg_names = arg_names,
|
||||
},
|
||||
};
|
||||
|
||||
for (u64 i = 0; i < COUNT_VEC_FUNCS; ++i) {
|
||||
write_macro_func(&temp_mem, fp, &(funcs[i]));
|
||||
}
|
||||
|
||||
data_type_t void_data_type = (data_type_t){
|
||||
.type = DATA_TYPE_NORMAL,
|
||||
.type_info = (type_info_t){.name = "void"},
|
||||
};
|
||||
|
||||
for (u64 i = 0; i < ARR_LEN(base_types); ++i) {
|
||||
for (u64 j = 0; j < ARR_LEN(dimensions); ++j) {
|
||||
type_info_t base_type = base_types[i];
|
||||
data_type_t base_data_type =
|
||||
(data_type_t){.type = DATA_TYPE_NORMAL, .type_info = base_type};
|
||||
u64 mem_count = dimensions[j];
|
||||
|
||||
char *typename = (char *)arena_alloc(&main_mem, SHORT_BUFFER_LENGTH);
|
||||
sprintf(typename, "vec%lu%c_t", mem_count, base_type.short_name);
|
||||
|
||||
identifier_t members[mem_count];
|
||||
memset(members, 0, sizeof(identifier_t) * mem_count);
|
||||
|
||||
for (u64 k = 0; k < mem_count; ++k) {
|
||||
members[k] = (identifier_t){
|
||||
.name = member_names[k],
|
||||
.type = base_data_type,
|
||||
};
|
||||
}
|
||||
|
||||
struct_def_t s = (struct_def_t){
|
||||
.name = typename,
|
||||
.mem_count = mem_count,
|
||||
.members = members,
|
||||
};
|
||||
|
||||
data_type_t vec_data_type =
|
||||
(data_type_t){.type = DATA_TYPE_STRUCT, .struct_def = s};
|
||||
|
||||
write_struct(&temp_mem, fp, &s);
|
||||
|
||||
funcs[VEC_FUNC_ADD].func.ret_type = vec_data_type;
|
||||
funcs[VEC_FUNC_SUB].func.ret_type = vec_data_type;
|
||||
funcs[VEC_FUNC_MUL].func.ret_type = vec_data_type;
|
||||
funcs[VEC_FUNC_DOT].func.ret_type = base_data_type;
|
||||
funcs[VEC_FUNC_MAGNITUDE].func.ret_type = base_data_type;
|
||||
funcs[VEC_FUNC_PRINT].func.ret_type = void_data_type;
|
||||
|
||||
for (u64 k = 0; k < COUNT_VEC_FUNCS; ++k) {
|
||||
func_data_t *func = &(funcs[k]);
|
||||
|
||||
char *name = (char *)arena_alloc(&main_mem, SHORT_BUFFER_LENGTH);
|
||||
sprintf(name, "%s_%s", func->base_name, typename);
|
||||
|
||||
u64 alloc_size = sizeof(identifier_t) * func->arg_count;
|
||||
identifier_t *args = (identifier_t *)arena_alloc(&main_mem, alloc_size);
|
||||
|
||||
for (u64 l = 0; l < func->arg_count; ++l) {
|
||||
args[l] =
|
||||
(identifier_t){.type = vec_data_type, .name = func->arg_names[l]};
|
||||
}
|
||||
|
||||
func->func.name = name;
|
||||
func->func.args = args;
|
||||
|
||||
write_func_declaration(&temp_mem, fp, func);
|
||||
}
|
||||
|
||||
const char *vec_impl_begin = "#ifdef VEC_IMPLEMENTATION\n\n";
|
||||
fwrite(vec_impl_begin, strlen(vec_impl_begin), 1, fp);
|
||||
|
||||
const char *operators[VEC_FUNC_DOT] = {
|
||||
[VEC_FUNC_ADD] = "+",
|
||||
[VEC_FUNC_SUB] = "-",
|
||||
[VEC_FUNC_MUL] = "*",
|
||||
};
|
||||
|
||||
for (u64 k = 0; k < VEC_FUNC_DOT; ++k) {
|
||||
func_data_t *func = &(funcs[k]);
|
||||
|
||||
char *body = (char *)arena_alloc(&main_mem, MEDIUM_BUFFER_LENGTH);
|
||||
sprintf(body, "\treturn (%s) {", typename);
|
||||
|
||||
write_vec_func_implementation(&main_mem, func, &s, body, operators[k],
|
||||
", ", "};\n");
|
||||
|
||||
write_func_defintion(&temp_mem, fp, func);
|
||||
}
|
||||
|
||||
func_data_t *vec_dot_func = &(funcs[VEC_FUNC_DOT]);
|
||||
char *vec_dot_body = (char *)arena_alloc(&main_mem, MEDIUM_BUFFER_LENGTH);
|
||||
strcat(vec_dot_body, "\treturn ");
|
||||
|
||||
write_vec_func_implementation(&main_mem, vec_dot_func, &s, vec_dot_body,
|
||||
operators[VEC_FUNC_MUL], " +", " 0;\n");
|
||||
|
||||
write_func_defintion(&temp_mem, fp, vec_dot_func);
|
||||
|
||||
func_data_t *vec_magnitude_func = &(funcs[VEC_FUNC_MAGNITUDE]);
|
||||
char *vec_magnitude_body =
|
||||
(char *)arena_alloc(&main_mem, MEDIUM_BUFFER_LENGTH);
|
||||
sprintf(vec_magnitude_body, "\t%s dotproduct = %s(%s, %s);\n",
|
||||
base_type.name, vec_dot_func->func.name,
|
||||
vec_magnitude_func->arg_names[0],
|
||||
vec_magnitude_func->arg_names[0]);
|
||||
strcat(vec_magnitude_body, "\treturn (");
|
||||
strcat(vec_magnitude_body, base_type.name);
|
||||
strcat(vec_magnitude_body, ")sqrtf(dotproduct);\n");
|
||||
|
||||
vec_magnitude_func->func.body = vec_magnitude_body;
|
||||
|
||||
write_func_defintion(&temp_mem, fp, vec_magnitude_func);
|
||||
|
||||
func_data_t *vec_print_func = &(funcs[VEC_FUNC_PRINT]);
|
||||
char *vec_print_body =
|
||||
(char *)arena_alloc(&main_mem, MEDIUM_BUFFER_LENGTH);
|
||||
strcat(vec_print_body, "\tprintf(\"{%");
|
||||
|
||||
for (u64 k = 0; k < s.mem_count; ++k) {
|
||||
if (k > 0) {
|
||||
strcat(vec_print_body, ", %");
|
||||
}
|
||||
|
||||
strcat(vec_print_body, &(base_type.printf_spec));
|
||||
}
|
||||
|
||||
strcat(vec_print_body, "}\\n\",");
|
||||
|
||||
for (u64 k = 0; k < s.mem_count; ++k) {
|
||||
if (k > 0) {
|
||||
strcat(vec_print_body, ",");
|
||||
}
|
||||
|
||||
for (u64 l = 0; l < vec_print_func->arg_count; ++l) {
|
||||
char *arg = (char *)arena_alloc(&main_mem, SHORT_BUFFER_LENGTH);
|
||||
sprintf(arg, " %s.%s", vec_print_func->arg_names[l],
|
||||
s.members[k].name);
|
||||
|
||||
strcat(vec_print_body, arg);
|
||||
}
|
||||
}
|
||||
|
||||
strcat(vec_print_body, ");\n");
|
||||
|
||||
vec_print_func->func.body = vec_print_body;
|
||||
|
||||
write_func_defintion(&temp_mem, fp, vec_print_func);
|
||||
|
||||
const char *vec_impl_end = "#endif // VEC_IMPLEMENTATION\n\n";
|
||||
fwrite(vec_impl_end, strlen(vec_impl_end), 1, fp);
|
||||
}
|
||||
|
||||
arena_clear(&main_mem);
|
||||
}
|
||||
|
||||
write_header_guard_close(&temp_mem, fp, header_name);
|
||||
|
||||
arena_free(&temp_mem);
|
||||
arena_free(&main_mem);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void write_header_guard_open(arena_t *arena, FILE *fp, const char *header_id) {
|
||||
char header_guard[LONG_BUFFER_LENGTH] = {0};
|
||||
|
||||
sprintf(header_guard, "#ifndef %s\n#define %s\n\n", header_id, header_id);
|
||||
|
||||
u64 length = strlen(header_guard);
|
||||
|
||||
fwrite(header_guard, length, 1, fp);
|
||||
}
|
||||
|
||||
void write_header_guard_close(arena_t *arena, FILE *fp, const char *header_id) {
|
||||
char *header_guard = (char *)arena_alloc(arena, LONG_BUFFER_LENGTH);
|
||||
if (!header_guard) {
|
||||
return;
|
||||
}
|
||||
|
||||
sprintf(header_guard, "#endif // %s", header_id);
|
||||
|
||||
u64 length = strlen(header_guard);
|
||||
|
||||
fwrite(header_guard, length, 1, fp);
|
||||
|
||||
arena_clear(arena);
|
||||
}
|
||||
|
||||
void write_include(arena_t *arena, FILE *fp, const include_header_t *header) {
|
||||
u64 length = 0;
|
||||
|
||||
char *include_line = (char *)arena_alloc(arena, LONG_BUFFER_LENGTH);
|
||||
if (!include_line) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (header->type) {
|
||||
case INCLUDE_TYPE_SYSTEM:
|
||||
sprintf(include_line, "#include <%s>\n", header->header);
|
||||
|
||||
length = strlen(include_line);
|
||||
|
||||
fwrite(include_line, length, 1, fp);
|
||||
|
||||
break;
|
||||
case INCLUDE_TYPE_USER:
|
||||
sprintf(include_line, "#include \"%s\"\n", header->header);
|
||||
|
||||
length = strlen(include_line);
|
||||
|
||||
fwrite(include_line, length, 1, fp);
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
arena_clear(arena);
|
||||
}
|
||||
|
||||
void write_data_type(char *dst, const data_type_t *data_type) {
|
||||
switch (data_type->type) {
|
||||
case DATA_TYPE_NORMAL:
|
||||
strcat(dst, data_type->type_info.name);
|
||||
|
||||
break;
|
||||
case DATA_TYPE_STRUCT:
|
||||
strcat(dst, data_type->struct_def.name);
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void write_identifier(char *dst, const identifier_t *identifier) {
|
||||
write_data_type(dst, &(identifier->type));
|
||||
|
||||
strcat(dst, " ");
|
||||
strcat(dst, identifier->name);
|
||||
}
|
||||
|
||||
void write_struct(arena_t *arena, FILE *fp, const struct_def_t *struct_def) {
|
||||
char *struct_output = (char *)arena_alloc(arena, LONG_BUFFER_LENGTH);
|
||||
if (!struct_output) {
|
||||
return;
|
||||
}
|
||||
|
||||
strcat(struct_output, "typedef struct {");
|
||||
|
||||
for (u64 i = 0; i < struct_def->mem_count; ++i) {
|
||||
strcat(struct_output, "\n\t");
|
||||
|
||||
const identifier_t *member = &(struct_def->members[i]);
|
||||
|
||||
write_identifier(struct_output, member);
|
||||
|
||||
strcat(struct_output, ";");
|
||||
}
|
||||
|
||||
strcat(struct_output, "\n} ");
|
||||
strcat(struct_output, struct_def->name);
|
||||
strcat(struct_output, ";\n\n");
|
||||
|
||||
u64 length = strlen(struct_output);
|
||||
|
||||
fwrite(struct_output, length, 1, fp);
|
||||
|
||||
arena_clear(arena);
|
||||
}
|
||||
|
||||
void write_func_prototype(char *dst, const func_data_t *func) {
|
||||
strcat(dst, "INTERNAL ");
|
||||
|
||||
write_data_type(dst, &(func->func.ret_type));
|
||||
|
||||
strcat(dst, " ");
|
||||
strcat(dst, func->func.name);
|
||||
strcat(dst, "(");
|
||||
|
||||
for (u64 i = 0; i < func->arg_count; ++i) {
|
||||
if (i > 0) {
|
||||
strcat(dst, ", ");
|
||||
}
|
||||
|
||||
const identifier_t *arg = &(func->func.args[i]);
|
||||
|
||||
write_identifier(dst, arg);
|
||||
}
|
||||
|
||||
strcat(dst, ")");
|
||||
}
|
||||
|
||||
void write_func_declaration(arena_t *arena, FILE *fp, const func_data_t *func) {
|
||||
char *func_declaration = (char *)arena_alloc(arena, LONG_BUFFER_LENGTH);
|
||||
if (!func_declaration) {
|
||||
return;
|
||||
}
|
||||
|
||||
write_func_prototype(func_declaration, func);
|
||||
|
||||
strcat(func_declaration, ";\n\n");
|
||||
|
||||
u64 length = strlen(func_declaration);
|
||||
|
||||
fwrite(func_declaration, length, 1, fp);
|
||||
|
||||
arena_clear(arena);
|
||||
}
|
||||
|
||||
void write_func_defintion(arena_t *arena, FILE *fp, const func_data_t *func) {
|
||||
char *func_definition = (char *)arena_alloc(arena, LONG_BUFFER_LENGTH);
|
||||
if (!func_definition) {
|
||||
return;
|
||||
}
|
||||
|
||||
write_func_prototype(func_definition, func);
|
||||
|
||||
strcat(func_definition, " {\n");
|
||||
|
||||
strcat(func_definition, func->func.body);
|
||||
|
||||
strcat(func_definition, "}\n\n");
|
||||
|
||||
u64 length = strlen(func_definition);
|
||||
|
||||
fwrite(func_definition, length, 1, fp);
|
||||
|
||||
arena_clear(arena);
|
||||
}
|
||||
|
||||
void write_macro_func(arena_t *arena, FILE *fp, const func_data_t *func) {
|
||||
char *func_definition = (char *)arena_alloc(arena, LONG_BUFFER_LENGTH);
|
||||
if (!func_definition) {
|
||||
return;
|
||||
}
|
||||
|
||||
strcat(func_definition, "#define ");
|
||||
strcat(func_definition, func->base_name);
|
||||
strcat(func_definition, "(T");
|
||||
|
||||
for (u64 i = 0; i < func->arg_count; ++i) {
|
||||
strcat(func_definition, ", ");
|
||||
strcat(func_definition, func->arg_names[i]);
|
||||
}
|
||||
|
||||
strcat(func_definition, ") ");
|
||||
strcat(func_definition, func->base_name);
|
||||
strcat(func_definition, "_##T(");
|
||||
|
||||
for (u64 i = 0; i < func->arg_count; ++i) {
|
||||
if (i > 0) {
|
||||
strcat(func_definition, ", ");
|
||||
}
|
||||
|
||||
strcat(func_definition, func->arg_names[i]);
|
||||
}
|
||||
|
||||
strcat(func_definition, ")\n\n");
|
||||
|
||||
u64 length = strlen(func_definition);
|
||||
|
||||
fwrite(func_definition, length, 1, fp);
|
||||
|
||||
arena_clear(arena);
|
||||
}
|
||||
|
||||
void write_vec_func_implementation(arena_t *arena, func_data_t *func,
|
||||
const struct_def_t *s, char *body,
|
||||
const char *operator, const char * separator,
|
||||
const char *end) {
|
||||
for (u64 l = 0; l < s->mem_count; ++l) {
|
||||
for (u64 m = 0; m < func->arg_count; ++m) {
|
||||
if (m > 0) {
|
||||
strcat(body, " ");
|
||||
strcat(body, operator);
|
||||
}
|
||||
|
||||
char *arg = (char *)arena_alloc(arena, SHORT_BUFFER_LENGTH);
|
||||
sprintf(arg, " %s.%s", func->arg_names[m], s->members[l].name);
|
||||
|
||||
strcat(body, arg);
|
||||
}
|
||||
|
||||
strcat(body, separator);
|
||||
}
|
||||
|
||||
strcat(body, end);
|
||||
|
||||
func->func.body = body;
|
||||
}
|
77
04_codegen/codegen.h
Normal file
77
04_codegen/codegen.h
Normal file
@@ -0,0 +1,77 @@
|
||||
#ifndef CODEGEN_H
|
||||
#define CODEGEN_H
|
||||
|
||||
#include "../aliases.h"
|
||||
#include "../mem_arena/arena.h"
|
||||
#include <stdio.h>
|
||||
|
||||
typedef enum {
|
||||
INCLUDE_TYPE_SYSTEM,
|
||||
INCLUDE_TYPE_USER,
|
||||
COUNT_INCLUDE_TYPES,
|
||||
} include_type;
|
||||
|
||||
typedef struct {
|
||||
include_type type;
|
||||
const char *header;
|
||||
} include_header_t;
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
char short_name;
|
||||
char printf_spec;
|
||||
} type_info_t;
|
||||
|
||||
typedef struct identifier_s identifier_t;
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
u64 mem_count;
|
||||
identifier_t *members;
|
||||
} struct_def_t;
|
||||
|
||||
typedef enum {
|
||||
DATA_TYPE_NORMAL,
|
||||
DATA_TYPE_STRUCT,
|
||||
COUNT_DATA_TYPE,
|
||||
} data_type;
|
||||
|
||||
typedef struct {
|
||||
data_type type;
|
||||
union {
|
||||
type_info_t type_info;
|
||||
struct_def_t struct_def;
|
||||
};
|
||||
} data_type_t;
|
||||
|
||||
struct identifier_s {
|
||||
data_type_t type;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
data_type_t ret_type;
|
||||
const char *name;
|
||||
identifier_t *args;
|
||||
const char *body;
|
||||
} func_t;
|
||||
|
||||
typedef struct {
|
||||
const char *base_name;
|
||||
u64 arg_count;
|
||||
const char **arg_names;
|
||||
func_t func;
|
||||
} func_data_t;
|
||||
|
||||
void write_header_guard_open(arena_t *arena, FILE *fp, const char *header_id);
|
||||
void write_header_guard_close(arena_t *arena, FILE *fp, const char *header_id);
|
||||
void write_include(arena_t *arena, FILE *fp, const include_header_t *header);
|
||||
void write_data_type(char *dst, const data_type_t *data_type);
|
||||
void write_identifier(char *dst, const identifier_t *identifier);
|
||||
void write_struct(arena_t *arena, FILE *fp, const struct_def_t *struct_def);
|
||||
void write_func_prototype(char *dst, const func_data_t *func);
|
||||
void write_func_declaration(arena_t *arena, FILE *fp, const func_data_t *func);
|
||||
void write_func_defintion(arena_t *arena, FILE *fp, const func_data_t *func);
|
||||
void write_macro_func(arena_t *arena, FILE *fp, const func_data_t *func);
|
||||
|
||||
#endif // !CODEGEN_H
|
18
04_codegen/main.c
Normal file
18
04_codegen/main.c
Normal file
@@ -0,0 +1,18 @@
|
||||
#define VEC_IMPLEMENTATION
|
||||
#include "vec.h"
|
||||
#undef VEC_IMPLEMENTATION
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
vec2i_t v1 = (vec2i_t){2, 3};
|
||||
vec2i_t v2 = (vec2i_t){4, 5};
|
||||
|
||||
vec_print(vec2i_t, vec_add(vec2i_t, v1, v2));
|
||||
vec_print(vec2i_t, vec_sub(vec2i_t, v1, v2));
|
||||
vec_print(vec2i_t, vec_mul(vec2i_t, v1, v2));
|
||||
printf("%d\n", vec_dot(vec2i_t, v1, v2));
|
||||
printf("%d\n", vec_magnitude(vec2i_t, v1));
|
||||
printf("%d\n", vec_magnitude(vec2i_t, v2));
|
||||
|
||||
return 0;
|
||||
}
|
206
04_codegen/vec.h
Normal file
206
04_codegen/vec.h
Normal file
@@ -0,0 +1,206 @@
|
||||
#ifndef VEC_H
|
||||
#define VEC_H
|
||||
|
||||
#include "../aliases.h"
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#define vec_add(T, v1, v2) vec_add_##T(v1, v2)
|
||||
|
||||
#define vec_sub(T, v1, v2) vec_sub_##T(v1, v2)
|
||||
|
||||
#define vec_mul(T, v1, v2) vec_mul_##T(v1, v2)
|
||||
|
||||
#define vec_dot(T, v1, v2) vec_dot_##T(v1, v2)
|
||||
|
||||
#define vec_magnitude(T, v1) vec_magnitude_##T(v1)
|
||||
|
||||
#define vec_print(T, v1) vec_print_##T(v1)
|
||||
|
||||
typedef struct {
|
||||
i32 x;
|
||||
i32 y;
|
||||
} vec2i_t;
|
||||
|
||||
INTERNAL vec2i_t vec_add_vec2i_t(vec2i_t v1, vec2i_t v2);
|
||||
|
||||
INTERNAL vec2i_t vec_sub_vec2i_t(vec2i_t v1, vec2i_t v2);
|
||||
|
||||
INTERNAL vec2i_t vec_mul_vec2i_t(vec2i_t v1, vec2i_t v2);
|
||||
|
||||
INTERNAL i32 vec_dot_vec2i_t(vec2i_t v1, vec2i_t v2);
|
||||
|
||||
INTERNAL i32 vec_magnitude_vec2i_t(vec2i_t v1);
|
||||
|
||||
INTERNAL void vec_print_vec2i_t(vec2i_t v1);
|
||||
|
||||
#ifdef VEC_IMPLEMENTATION
|
||||
|
||||
INTERNAL vec2i_t vec_add_vec2i_t(vec2i_t v1, vec2i_t v2) {
|
||||
return (vec2i_t) { v1.x + v2.x, v1.y + v2.y, };
|
||||
}
|
||||
|
||||
INTERNAL vec2i_t vec_sub_vec2i_t(vec2i_t v1, vec2i_t v2) {
|
||||
return (vec2i_t) { v1.x - v2.x, v1.y - v2.y, };
|
||||
}
|
||||
|
||||
INTERNAL vec2i_t vec_mul_vec2i_t(vec2i_t v1, vec2i_t v2) {
|
||||
return (vec2i_t) { v1.x * v2.x, v1.y * v2.y, };
|
||||
}
|
||||
|
||||
INTERNAL i32 vec_dot_vec2i_t(vec2i_t v1, vec2i_t v2) {
|
||||
return v1.x * v2.x + v1.y * v2.y + 0;
|
||||
}
|
||||
|
||||
INTERNAL i32 vec_magnitude_vec2i_t(vec2i_t v1) {
|
||||
i32 dotproduct = vec_dot_vec2i_t(v1, v1);
|
||||
return (i32)sqrtf(dotproduct);
|
||||
}
|
||||
|
||||
INTERNAL void vec_print_vec2i_t(vec2i_t v1) {
|
||||
printf("{%d, %d}\n", v1.x, v1.y);
|
||||
}
|
||||
|
||||
#endif // VEC_IMPLEMENTATION
|
||||
|
||||
typedef struct {
|
||||
i32 x;
|
||||
i32 y;
|
||||
i32 z;
|
||||
} vec3i_t;
|
||||
|
||||
INTERNAL vec3i_t vec_add_vec3i_t(vec3i_t v1, vec3i_t v2);
|
||||
|
||||
INTERNAL vec3i_t vec_sub_vec3i_t(vec3i_t v1, vec3i_t v2);
|
||||
|
||||
INTERNAL vec3i_t vec_mul_vec3i_t(vec3i_t v1, vec3i_t v2);
|
||||
|
||||
INTERNAL i32 vec_dot_vec3i_t(vec3i_t v1, vec3i_t v2);
|
||||
|
||||
INTERNAL i32 vec_magnitude_vec3i_t(vec3i_t v1);
|
||||
|
||||
INTERNAL void vec_print_vec3i_t(vec3i_t v1);
|
||||
|
||||
#ifdef VEC_IMPLEMENTATION
|
||||
|
||||
INTERNAL vec3i_t vec_add_vec3i_t(vec3i_t v1, vec3i_t v2) {
|
||||
return (vec3i_t) { v1.x + v2.x, v1.y + v2.y, v1.z + v2.z, };
|
||||
}
|
||||
|
||||
INTERNAL vec3i_t vec_sub_vec3i_t(vec3i_t v1, vec3i_t v2) {
|
||||
return (vec3i_t) { v1.x - v2.x, v1.y - v2.y, v1.z - v2.z, };
|
||||
}
|
||||
|
||||
INTERNAL vec3i_t vec_mul_vec3i_t(vec3i_t v1, vec3i_t v2) {
|
||||
return (vec3i_t) { v1.x * v2.x, v1.y * v2.y, v1.z * v2.z, };
|
||||
}
|
||||
|
||||
INTERNAL i32 vec_dot_vec3i_t(vec3i_t v1, vec3i_t v2) {
|
||||
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z + 0;
|
||||
}
|
||||
|
||||
INTERNAL i32 vec_magnitude_vec3i_t(vec3i_t v1) {
|
||||
i32 dotproduct = vec_dot_vec3i_t(v1, v1);
|
||||
return (i32)sqrtf(dotproduct);
|
||||
}
|
||||
|
||||
INTERNAL void vec_print_vec3i_t(vec3i_t v1) {
|
||||
printf("{%d, %d, %d}\n", v1.x, v1.y, v1.z);
|
||||
}
|
||||
|
||||
#endif // VEC_IMPLEMENTATION
|
||||
|
||||
typedef struct {
|
||||
f32 x;
|
||||
f32 y;
|
||||
} vec2f_t;
|
||||
|
||||
INTERNAL vec2f_t vec_add_vec2f_t(vec2f_t v1, vec2f_t v2);
|
||||
|
||||
INTERNAL vec2f_t vec_sub_vec2f_t(vec2f_t v1, vec2f_t v2);
|
||||
|
||||
INTERNAL vec2f_t vec_mul_vec2f_t(vec2f_t v1, vec2f_t v2);
|
||||
|
||||
INTERNAL f32 vec_dot_vec2f_t(vec2f_t v1, vec2f_t v2);
|
||||
|
||||
INTERNAL f32 vec_magnitude_vec2f_t(vec2f_t v1);
|
||||
|
||||
INTERNAL void vec_print_vec2f_t(vec2f_t v1);
|
||||
|
||||
#ifdef VEC_IMPLEMENTATION
|
||||
|
||||
INTERNAL vec2f_t vec_add_vec2f_t(vec2f_t v1, vec2f_t v2) {
|
||||
return (vec2f_t) { v1.x + v2.x, v1.y + v2.y, };
|
||||
}
|
||||
|
||||
INTERNAL vec2f_t vec_sub_vec2f_t(vec2f_t v1, vec2f_t v2) {
|
||||
return (vec2f_t) { v1.x - v2.x, v1.y - v2.y, };
|
||||
}
|
||||
|
||||
INTERNAL vec2f_t vec_mul_vec2f_t(vec2f_t v1, vec2f_t v2) {
|
||||
return (vec2f_t) { v1.x * v2.x, v1.y * v2.y, };
|
||||
}
|
||||
|
||||
INTERNAL f32 vec_dot_vec2f_t(vec2f_t v1, vec2f_t v2) {
|
||||
return v1.x * v2.x + v1.y * v2.y + 0;
|
||||
}
|
||||
|
||||
INTERNAL f32 vec_magnitude_vec2f_t(vec2f_t v1) {
|
||||
f32 dotproduct = vec_dot_vec2f_t(v1, v1);
|
||||
return (f32)sqrtf(dotproduct);
|
||||
}
|
||||
|
||||
INTERNAL void vec_print_vec2f_t(vec2f_t v1) {
|
||||
printf("{%f, %f}\n", v1.x, v1.y);
|
||||
}
|
||||
|
||||
#endif // VEC_IMPLEMENTATION
|
||||
|
||||
typedef struct {
|
||||
f32 x;
|
||||
f32 y;
|
||||
f32 z;
|
||||
} vec3f_t;
|
||||
|
||||
INTERNAL vec3f_t vec_add_vec3f_t(vec3f_t v1, vec3f_t v2);
|
||||
|
||||
INTERNAL vec3f_t vec_sub_vec3f_t(vec3f_t v1, vec3f_t v2);
|
||||
|
||||
INTERNAL vec3f_t vec_mul_vec3f_t(vec3f_t v1, vec3f_t v2);
|
||||
|
||||
INTERNAL f32 vec_dot_vec3f_t(vec3f_t v1, vec3f_t v2);
|
||||
|
||||
INTERNAL f32 vec_magnitude_vec3f_t(vec3f_t v1);
|
||||
|
||||
INTERNAL void vec_print_vec3f_t(vec3f_t v1);
|
||||
|
||||
#ifdef VEC_IMPLEMENTATION
|
||||
|
||||
INTERNAL vec3f_t vec_add_vec3f_t(vec3f_t v1, vec3f_t v2) {
|
||||
return (vec3f_t) { v1.x + v2.x, v1.y + v2.y, v1.z + v2.z, };
|
||||
}
|
||||
|
||||
INTERNAL vec3f_t vec_sub_vec3f_t(vec3f_t v1, vec3f_t v2) {
|
||||
return (vec3f_t) { v1.x - v2.x, v1.y - v2.y, v1.z - v2.z, };
|
||||
}
|
||||
|
||||
INTERNAL vec3f_t vec_mul_vec3f_t(vec3f_t v1, vec3f_t v2) {
|
||||
return (vec3f_t) { v1.x * v2.x, v1.y * v2.y, v1.z * v2.z, };
|
||||
}
|
||||
|
||||
INTERNAL f32 vec_dot_vec3f_t(vec3f_t v1, vec3f_t v2) {
|
||||
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z + 0;
|
||||
}
|
||||
|
||||
INTERNAL f32 vec_magnitude_vec3f_t(vec3f_t v1) {
|
||||
f32 dotproduct = vec_dot_vec3f_t(v1, v1);
|
||||
return (f32)sqrtf(dotproduct);
|
||||
}
|
||||
|
||||
INTERNAL void vec_print_vec3f_t(vec3f_t v1) {
|
||||
printf("{%f, %f, %f}\n", v1.x, v1.y, v1.z);
|
||||
}
|
||||
|
||||
#endif // VEC_IMPLEMENTATION
|
||||
|
||||
#endif // VEC_H
|
13
README.md
13
README.md
@@ -6,12 +6,13 @@ Exploring different ideas for implementing generics in C.
|
||||
|
||||
[02_macros](./02_macros) is an implementation that uses simple macros to define 2D and 3D vectors for different data types.
|
||||
|
||||
[03_xmacros](./03_xmacros) is an implementation that relies on X macros to allow for defining any N-dimensional vector for different data types. In this case, only 2D and 3D vectors were defined, but it can be easily expanded to other dimensions.
|
||||
[03_xmacros](./03_xmacros) is an implementation that relies on X macros to allow for defining any N-dimensional vector for different data types. In this case, only 2D and 3D vectors were defined (for parity with the previous techniques), but it can be easily expanded to other dimensions.
|
||||
|
||||
## General assessment of the different techniques
|
||||
|
||||
| Technique | Readability | Debugging | Maintenance | Extensibility | Score |
|
||||
| --------------------- | ----------- | ---------- | ----------- | ------------- | -------- |
|
||||
| 01_no_metaprogramming | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐ | 3.25 / 5 |
|
||||
| 02_macros | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | 3.75 / 5 |
|
||||
| 03_xmacros | ⭐ | ⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | 2.75 / 5 |
|
||||
| Technique | Ease of implementation | Readability | Debugging | Maintenance | Extensibility | Applicability to other problems | Score (out of 5) |
|
||||
| --------------------- | ---------------------- | ----------- | ---------- | ----------- | ------------- | ------------------------------- | ------------------- |
|
||||
| 01_no_metaprogramming | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐ | | 3.00 |
|
||||
| 02_macros | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | | 3.17 |
|
||||
| 03_xmacros | ⭐⭐⭐ | ⭐ | ⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | | 2.33 |
|
||||
| 04_codegen | ⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐ | 3.17 |
|
||||
|
6
compile
6
compile
@@ -7,3 +7,9 @@ LIBS="-lm"
|
||||
$CC $CFLAGS -I01_no_metaprogramming ./01_no_metaprogramming/*.c $LIBS -o 01_vec_no_metaprogramming
|
||||
$CC $CFLAGS -I02_macros ./02_macros/*.c $LIBS -o 02_vec_macros
|
||||
$CC $CFLAGS -I03_xmacros ./03_xmacros/*.c $LIBS -o 03_vec_xmacros
|
||||
|
||||
$CC $CFLAGS -I04_codegen -Imem_arena 04_codegen/codegen.c mem_arena/*.c -o 04_codegen/codegen
|
||||
cd 04_codegen
|
||||
./codegen
|
||||
cd ../
|
||||
$CC $CFLAGS -I04_codegen ./04_codegen/main.c $LIBS -o 04_vec_codegen
|
||||
|
47
mem_arena/arena.c
Normal file
47
mem_arena/arena.c
Normal file
@@ -0,0 +1,47 @@
|
||||
#include "arena.h"
|
||||
#include "../aliases.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
bool arena_init(arena_t *arena, u64 capacity) {
|
||||
arena->buf = (u8 *)malloc(capacity);
|
||||
if (!(arena->buf)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
arena->capacity = capacity;
|
||||
|
||||
arena->offset = arena->buf;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
u8 *arena_alloc(arena_t *arena, u64 size) {
|
||||
if (arena->offset + size >= arena->buf + arena->capacity) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u8 *output = arena->offset;
|
||||
|
||||
arena->offset += size;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
void arena_clear(arena_t *arena) {
|
||||
memset(arena->buf, 0, arena->offset - arena->buf);
|
||||
|
||||
arena->offset = arena->buf;
|
||||
}
|
||||
|
||||
void arena_free(arena_t *arena) {
|
||||
arena->capacity = 0;
|
||||
|
||||
arena->offset = NULL;
|
||||
|
||||
if (arena->buf) {
|
||||
free(arena->buf);
|
||||
}
|
||||
|
||||
arena->buf = NULL;
|
||||
}
|
18
mem_arena/arena.h
Normal file
18
mem_arena/arena.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef ARENA_H
|
||||
#define ARENA_H
|
||||
|
||||
#include "../aliases.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct {
|
||||
u64 capacity;
|
||||
u8 *buf;
|
||||
u8 *offset;
|
||||
} arena_t;
|
||||
|
||||
bool arena_init(arena_t *arena, u64 capacity);
|
||||
u8 *arena_alloc(arena_t *arena, u64 size);
|
||||
void arena_clear(arena_t *arena);
|
||||
void arena_free(arena_t *arena);
|
||||
|
||||
#endif // !ARENA_H
|
Reference in New Issue
Block a user