Compare commits

1 Commits

Author SHA1 Message Date
roodletoof bdabc97cca testing ci
C Tests / Build and Test (push) Has been cancelled
2026-06-21 21:16:45 +00:00
18 changed files with 353 additions and 879 deletions
-2
View File
@@ -1,2 +0,0 @@
CompileFlags:
Add: [-xc, -std=c99]
-2
View File
@@ -1,4 +1,2 @@
tags tags
*.un~ *.un~
/foobar
/foobar-expanded.c
+40 -194
View File
@@ -9,12 +9,11 @@
#include <string.h> #include <string.h>
typedef union any_align { char c; int i; long l; long long ll; float f; double d; void *p; long double ld; } any_align_t; typedef union any_align { char c; int i; long l; long long ll; float f; double d; void *p; long double ld; } any_align_t;
#define ALIGN_OF(TYPE) ((size_t)(&((struct{char c; TYPE t;}*) 256)->t) - 256) #define MAX_ALIGN ((size_t) sizeof(any_align_t))
#define MAX_ALIGN (ALIGN_OF(any_align_t))
#define KB (1024) #define KB (1024)
#define MB (KB * KB) #define MB (KB * KB)
#define GB (KB * KB * KB) #define GB (KB * KB * KB)
#define PTR_FROM_FIELD_PTR(STRUCT, FIELD, PTR) ((STRUCT *) (((char *) (PTR)) - offsetof(STRUCT, FIELD))) #define PTR_FROM_FIELD_PTR(STRUCT, FIELD, PTR) ((STRUCT *) (((char *) PTR) - offsetof(STRUCT, FIELD)))
// Contains all operations an allocator can do. Similar interface to sdtlibs // Contains all operations an allocator can do. Similar interface to sdtlibs
// malloc, realloc and free. // malloc, realloc and free.
@@ -138,7 +137,7 @@ allocator_t allocator_from_arena(arena_allocator_t *this);
// dynamic arrays ////////////////////////////////////////////////////////////// // dynamic arrays //////////////////////////////////////////////////////////////
typedef struct dyn_array_header { typedef struct dyn_array_header {
size_t n_items, capacity, item_size; size_t n_items, capacity, itemsize;
allocator_t allocator; allocator_t allocator;
union { union {
// allocates a little more memory than needed, but who cares? // allocates a little more memory than needed, but who cares?
@@ -149,29 +148,20 @@ typedef struct dyn_array_header {
typedef struct dyn_array_create_func_args { typedef struct dyn_array_create_func_args {
allocator_t allocator; allocator_t allocator;
size_t item_size; size_t itemsize;
size_t initial_capacity; size_t initial_capacity;
const char *file; const char *file;
int line; int line;
} dyn_array_create_func_args_t; } dyn_array_create_func_args_t;
void *dyn_array_create_func(dyn_array_create_func_args_t args); void *dyn_array_create_func(dyn_array_create_func_args_t args);
#define arr_make(TYPE, ...) ((TYPE *)dyn_array_create_func((dyn_array_create_func_args_t){ \ #define make_arr(TYPE, ...) ((TYPE *)dyn_array_create_func((dyn_array_create_func_args_t){ \
.item_size = sizeof(TYPE), \ .itemsize = sizeof(TYPE), \
.file = __FILE__, \ .file = __FILE__, \
.line = __LINE__, \ .line = __LINE__, \
.allocator = __VA_ARGS__, \ .allocator = __VA_ARGS__, \
})) }))
#define arr_init(PTR, ...) do { \
(*(PTR)) = dyn_array_create_func((dyn_array_create_func_args_t){ \
.item_size = sizeof(*(*(PTR))), \
.file = __FILE__, \
.line = __LINE__, \
.allocator = __VA_ARGS__, \
}); \
} while(0)
// Always reassign the array. if multiple variables reference the same growing // Always reassign the array. if multiple variables reference the same growing
// array, then you should be using pointer pointers. // array, then you should be using pointer pointers.
void *dyn_array_grow_func(void *this, size_t n_new_items, const char *file, int line); void *dyn_array_grow_func(void *this, size_t n_new_items, const char *file, int line);
@@ -233,107 +223,6 @@ bool dyn_array_contains_eq_func(void *this, uint8_t *value, dyn_array_eq_fn eq);
typedef int (*dyn_array_cmp_fn)(const void *a, const void *b); typedef int (*dyn_array_cmp_fn)(const void *a, const void *b);
void arr_qsort(void *this, dyn_array_cmp_fn cmp_fn); void arr_qsort(void *this, dyn_array_cmp_fn cmp_fn);
// maps ////////////////////////////////////////////////////////////////////
typedef uint32_t (*key_hash_func_t)(const void *key);
typedef bool (*key_equals_func_t)(const void *key1, const void *key2);
typedef struct map_header {
uint32_t capacity;
uint32_t item_size;
uint32_t key_size;
uint32_t mapping_capacity;
uint32_t n_items;
uint32_t key_offset;
allocator_t allocator;
key_hash_func_t hash;
key_equals_func_t equals;
int32_t *mapping_arr;
union {
uint8_t bytes[1];
any_align_t _[1];
};
} map_header_t;
typedef struct map_create_func_args {
allocator_t allocator;
const char *file;
key_hash_func_t hash; // OPTIONAL
key_equals_func_t equals; // OPTIONAL
unsigned int initial_capacity; // OPTIONAL
unsigned int item_size;
unsigned int key_offset;
unsigned int key_size;
int line;
} map_create_func_args_t;
void *map_create_func(map_create_func_args_t args);
#define map_init(PTR, ...) do { \
(*(PTR)) = map_create_func((map_create_func_args_t) { \
.item_size=sizeof(*(*(PTR))), \
.key_size=sizeof((*(PTR))->key), \
.key_offset=offsetof((*(PTR))->key), \
.file=__FILE__, \
.line=__LINE__, \
.allocator=__VA_ARGS__ \
}); \
} while(0)
#define set_init(PTR, ...) do { \
(*(PTR)) = map_create_func((map_create_func_args_t) { \
.item_size=sizeof(*(*(PTR))), \
.key_size=sizeof(*(*(PTR))), \
.key_offset=0, \
.file=__FILE__, \
.line=__LINE__, \
.allocator=__VA_ARGS__ \
}); \
} while(0)
int map_len_func(void *this);
#define map_len(THIS) map_len_func((void*) THIS)
int map_cap_func(void *this);
#define map_cap(THIS) map_cap_func((void*) THIS)
uint32_t fnv_1a(const uint8_t *bytes, const unsigned int size);
// Used for debugging the mapping array. Prints out nerdfonts icons to indicate
// the state of each mapping slot.
void map_print_mapping_state(void *this, FILE *file);
// Checks that the map can handle one more item. The maps capacity grows if not,
// usually by doubling the capacity.
void map_assure_growable_by_1(void **this, const char *file, int line);
typedef struct index_pair {
unsigned int new_i_into_mapping;
unsigned int old_i_into_mapping;
bool has_old;
} index_pair_t;
/*
* Hashes modulo the header->mapping_capacity. Will linearly probe until a free
* slot is found. If the key already exists in the mapping array, that will be
* indicated in the return value, and the user is expected to overwrite the old
* index with a tombstone if they are going to write a new value for that key.
*/
index_pair_t map_pair_hash(void *this, const uint8_t *pair);
bool map_key_equals(map_header_t *header, const uint8_t *key1_bytes, const uint8_t *key2_bytes);
unsigned int map_place(void *this, index_pair_t idx_pair);
// Exists to take a hash of a key and modulo it so it fits within the maps
// capacity.
uint32_t map_mod_index(const map_header_t *header, uint32_t i);
uint32_t map_hash_key(const map_header_t *header, const uint8_t *key);
// TODO: NOT DONE!!! FIRST try to get the existing in
#define set_add(THIS, VALUE) do { \
map_assure_growable_by_1((void**)THIS, __FILE__, __LINE__); \
unsigned int len = map_len(*(THIS)); \
(*(THIS))[len] = VALUE; \
index_pair_t idx_pair = map_pair_hash((*(THIS)), (const uint8_t*) (&(*(THIS))[len])); \
(*(THIS))[map_place((*(THIS)), idx_pair)] = VALUE; \
} while (0)
// CLI ///////////////////////////////////////////////////////////////////////// // CLI /////////////////////////////////////////////////////////////////////////
#define CLI_UNIQUE1 __macro_internal_34bba35b8b9b20a75f9881e3795630e25d36e620d9c9741e2e9141ba82ec6ef7__ #define CLI_UNIQUE1 __macro_internal_34bba35b8b9b20a75f9881e3795630e25d36e620d9c9741e2e9141ba82ec6ef7__
@@ -379,7 +268,12 @@ int cli_req_int_func(args_t args, const char *flag_name, const char *file, int l
) \ ) \
if (CLI_UNIQUE1) if (CLI_UNIQUE1)
// scan ///////////////////////////////////////////////////////////////////// // scanner /////////////////////////////////////////////////////////////////////
typedef struct error_node {
char *msg;
struct error_node *next;
} error_node_t;
typedef union scan_value { typedef union scan_value {
int digit; int digit;
@@ -397,50 +291,41 @@ typedef union scan_value {
char *string_literal; char *string_literal;
} scan_value_t; } scan_value_t;
typedef struct scan { typedef struct scanner {
const char *name; // name of the buffer const char *name; // name of the buffer
const char *start; // pointer to the full buffer const char *start; // pointer to the full buffer
const char *cur; // current pointer const char *cur; // current pointer
allocator_t allocator;
} scan_t;
typedef struct scan_error {
const char *filename;
int line;
int column;
const char *message;
} scan_error_t;
typedef struct scan_result {
bool ok;
union {
scan_error_t error;
scan_value_t value; scan_value_t value;
}; error_node_t *errors; // singly linked list of error strings
} scan_result_t; allocator_t allocator;
} scanner_t;
scan_t make_scan(const char *name, const char *buffer, allocator_t allocator); scanner_t make_scanner(const char *name, const char *buffer, allocator_t allocator);
void scan_next_line(scan_t *s); void scanner_recover(scanner_t *s);
scan_result_t scan_eof(scan_t *s); void scanner_error(scanner_t *s, const char *message);
scan_result_t scan_literal(scan_t *s, const char *lit); void scanner_error_and_recover(scanner_t *s, const char *message);
int scan_repeat_literal(scan_t *s, const char *lit); bool scan_eof(scanner_t *s);
scan_result_t scan_whitespace(scan_t *s); bool scan_literal(scanner_t *s, const char *lit);
scan_result_t scan_digit(scan_t *s); int scan_repeat_literal(scanner_t *s, const char *lit);
scan_result_t scan_i64(scan_t *s); bool scan_whitespace(scanner_t *s);
scan_result_t scan_i32(scan_t *s); bool scan_digit(scanner_t *s);
scan_result_t scan_i16(scan_t *s); bool scan_i64(scanner_t *s);
scan_result_t scan_i8(scan_t *s); bool scan_i32(scanner_t *s);
scan_result_t scan_u64(scan_t *s); bool scan_i16(scanner_t *s);
scan_result_t scan_u32(scan_t *s); bool scan_i8(scanner_t *s);
scan_result_t scan_u16(scan_t *s); bool scan_u64(scanner_t *s);
scan_result_t scan_u8(scan_t *s); bool scan_u32(scanner_t *s);
scan_result_t scan_f64(scan_t *s); bool scan_u16(scanner_t *s);
scan_result_t scan_f32(scan_t *s); bool scan_u8(scanner_t *s);
bool scan_f64(scanner_t *s);
bool scan_f32(scanner_t *s);
// Scan as much of an identifier as possible, you are responsible to scan for // Scan as much of an identifier as possible, you are responsible to scan for
// valid characters after the identifier is scanned. // valid characters after the identifier is scanned.
scan_result_t scan_identifier(scan_t *s); bool scan_identifier(scanner_t *s);
scan_result_t scan_string_literal(scan_t *s); bool scan_string_literal(scanner_t *s);
scan_value_t required(scan_result_t res); bool scanner_print_errors(scanner_t *s, FILE *fp);
bool looks_like_float(scanner_t *s);
bool looks_like_int(scanner_t *s);
// string builder ////////////////////////////////////////////////////////////// // string builder //////////////////////////////////////////////////////////////
typedef struct string_builder_node { typedef struct string_builder_node {
@@ -474,44 +359,6 @@ void sb_fprint_and_clear(string_builder_t *this, FILE *dest);
char *read_entire_file(const char *path, allocator_t allocator); char *read_entire_file(const char *path, allocator_t allocator);
char **read_all_file_lines(const char *path, allocator_t allocator); char **read_all_file_lines(const char *path, allocator_t allocator);
// easing //////////////////////////////////////////////////////////////////////
float ease_in_quad(float t);
float ease_out_quad(float t);
float ease_inout_quad(float t);
float ease_in_cubic(float t);
float ease_out_cubic(float t);
float ease_inout_cubic(float t);
float ease_in_quart(float t);
float ease_out_quart(float t);
float ease_inout_quart(float t);
float ease_in_quint(float t);
float ease_out_quint(float t);
float ease_inout_quint(float t);
float ease_in_expo(float t);
float ease_out_expo(float t);
float ease_inout_expo(float t);
float ease_in_circ(float t);
float ease_out_circ(float t);
float ease_inout_circ(float t);
float ease_in_back(float t);
float ease_out_back(float t);
float ease_inout_back(float t);
float ease_in_elastic(float t);
float ease_out_elastic(float t);
float ease_inout_elastic(float t);
float ease_in_bounce(float t);
float ease_out_bounce(float t);
float ease_inout_bounce(float t);
#ifdef CIG_IMPL #ifdef CIG_IMPL
void *allocator_alloc_func(allocator_t this, size_t bytes, const char *file, int line) { void *allocator_alloc_func(allocator_t this, size_t bytes, const char *file, int line) {
@@ -543,7 +390,6 @@ void allocator_reset(allocator_t this) {
#include "scanner.c" #include "scanner.c"
#include "string_builder.c" #include "string_builder.c"
#include "file_io.c" #include "file_io.c"
#include "map.c"
#endif // CIG_IMPL #endif // CIG_IMPL
+8 -8
View File
@@ -5,13 +5,13 @@
void *dyn_array_create_func(dyn_array_create_func_args_t args) { void *dyn_array_create_func(dyn_array_create_func_args_t args) {
dyn_array_header_t *header = allocator_alloc_func( dyn_array_header_t *header = allocator_alloc_func(
args.allocator, args.allocator,
sizeof(dyn_array_header_t) + args.item_size * args.initial_capacity, sizeof(dyn_array_header_t) + args.itemsize * args.initial_capacity,
args.file, args.file,
args.line args.line
); );
header->n_items = 0; header->n_items = 0;
header->capacity = args.initial_capacity; header->capacity = args.initial_capacity;
header->item_size = args.item_size; header->itemsize = args.itemsize;
header->allocator = args.allocator; header->allocator = args.allocator;
return &header->bytes; return &header->bytes;
} }
@@ -29,7 +29,7 @@ void *dyn_array_grow_func(void *this, size_t n_new_items, const char *file, int
header = allocator_resize_func( header = allocator_resize_func(
header->allocator, header->allocator,
header, header,
sizeof(dyn_array_header_t) + header->item_size * new_capacity, sizeof(dyn_array_header_t) + header->itemsize * new_capacity,
file, file,
line line
); );
@@ -71,8 +71,8 @@ bool dyn_array_contains_func(void *this, uint8_t *value) {
dyn_array_header_t *header = PTR_FROM_FIELD_PTR(dyn_array_header_t, bytes, this); dyn_array_header_t *header = PTR_FROM_FIELD_PTR(dyn_array_header_t, bytes, this);
for (size_t i = 0; i < header->n_items; i++) { for (size_t i = 0; i < header->n_items; i++) {
bool is_equal = true; bool is_equal = true;
for (size_t off = 0; off < header->item_size; off++) { for (size_t off = 0; off < header->itemsize; off++) {
if (header->bytes[i*header->item_size+off] != value[off]) { if (header->bytes[i*header->itemsize+off] != value[off]) {
is_equal = false; is_equal = false;
break; break;
} }
@@ -86,10 +86,10 @@ bool dyn_array_contains_func(void *this, uint8_t *value) {
bool dyn_array_contains_eq_func(void *this, uint8_t *value, dyn_array_eq_fn eq) { bool dyn_array_contains_eq_func(void *this, uint8_t *value, dyn_array_eq_fn eq) {
dyn_array_header_t *header = PTR_FROM_FIELD_PTR(dyn_array_header_t, bytes, this); dyn_array_header_t *header = PTR_FROM_FIELD_PTR(dyn_array_header_t, bytes, this);
size_t item_size = header->item_size; size_t itemsize = header->itemsize;
for (size_t i = 0; i < header->n_items; i++) { for (size_t i = 0; i < header->n_items; i++) {
void *element = &header->bytes[i * item_size]; void *element = &header->bytes[i * itemsize];
if (eq(element, value)) { if (eq(element, value)) {
return true; return true;
} }
@@ -116,5 +116,5 @@ void dyn_array_bounds_check_func(void *this, size_t index, const char *file, int
void arr_qsort(void *this, dyn_array_cmp_fn cmp_fn) { void arr_qsort(void *this, dyn_array_cmp_fn cmp_fn) {
dyn_array_header_t *header = PTR_FROM_FIELD_PTR(dyn_array_header_t, bytes, this); dyn_array_header_t *header = PTR_FROM_FIELD_PTR(dyn_array_header_t, bytes, this);
qsort(this, header->n_items, header->item_size, cmp_fn); qsort(this, header->n_items, header->itemsize, cmp_fn);
} }
-98
View File
@@ -1,98 +0,0 @@
#include "cig.h"
static float clamp(float t, float min, float max) {
if (t < min) {
return min;
}
if (max < t) {
return max;
}
return t;
}
static float norm(float t) {
return clamp(t, 0.0f, 1.0f);
}
float ease_in_quad(float t) {
t = norm(t);
return t * t;
}
float ease_out_quad(float t) {
}
float ease_inout_quad(float t) {
}
float ease_in_cubic(float t) {
}
float ease_out_cubic(float t) {
}
float ease_inout_cubic(float t) {
}
float ease_in_quart(float t) {
}
float ease_out_quart(float t) {
}
float ease_inout_quart(float t) {
}
float ease_in_quint(float t) {
}
float ease_out_quint(float t) {
}
float ease_inout_quint(float t) {
}
float ease_in_expo(float t) {
}
float ease_out_expo(float t) {
}
float ease_inout_expo(float t) {
}
float ease_in_circ(float t) {
}
float ease_out_circ(float t) {
}
float ease_inout_circ(float t) {
}
float ease_in_back(float t) {
}
float ease_out_back(float t) {
}
float ease_inout_back(float t) {
}
float ease_in_elastic(float t) {
}
float ease_out_elastic(float t) {
}
float ease_inout_elastic(float t) {
}
float ease_in_bounce(float t) {
}
float ease_out_bounce(float t) {
}
float ease_inout_bounce(float t) {
}
+1 -1
View File
@@ -19,7 +19,7 @@ char *read_entire_file(const char *path, allocator_t allocator) {
// Returns dynamic array, of fixed char strings. // Returns dynamic array, of fixed char strings.
char **read_all_file_lines(const char *path, allocator_t allocator) { char **read_all_file_lines(const char *path, allocator_t allocator) {
char *contents = read_entire_file(path, allocator); char *contents = read_entire_file(path, allocator);
char **lines = arr_make(char*, allocator); char **lines = make_arr(char*, allocator);
arr_append(lines, contents); arr_append(lines, contents);
bool just_split = false; bool just_split = false;
for (char *c = contents; (*c)!='\0'; c++) { for (char *c = contents; (*c)!='\0'; c++) {
+24 -6
View File
@@ -1,5 +1,5 @@
CC := "zig cc" CC := "zig cc"
CFLAGS := "-pedantic -Wall -Wextra -Wno-override-init -O0 -g3 -fno-omit-frame-pointer -fno-inline -fsanitize=address,undefined -fno-sanitize-recover=all" CFLAGS := "-pedantic -Wall -Wextra -Wno-override-init -O0 -g -fno-omit-frame-pointer -fno-inline"
LDFLAGS := if os() == "macos" { LDFLAGS := if os() == "macos" {
"$(pkg-config --libs --cflags criterion)" "$(pkg-config --libs --cflags criterion)"
} else { } else {
@@ -12,6 +12,29 @@ TESTBIN := TMP/"all_tests"
set shell := ["bash", "-cu"] set shell := ["bash", "-cu"]
FOOBAR := "foobar"
FOOBAR_SOURCE := FOOBAR+".c"
FOOBAR_BIN := TMP/FOOBAR
FOOBAR_EXPANDED := TMP/FOOBAR+"-expanded.c"
build_foobar2:
{{CC}} {{FOOBAR_SOURCE}} {{CFLAGS}} -o foobar2
run_foobar: build_foobar
{{FOOBAR_BIN}}
build_foobar: foobar_expanded
{{CC}} {{FOOBAR_EXPANDED}} {{CFLAGS}} -o {{FOOBAR_BIN}}
echo "{{FOOBAR_BIN}}"
foobar_expanded:
{{CC}} -P -E {{FOOBAR_SOURCE}} -o {{FOOBAR_EXPANDED}}
clang-format -i {{FOOBAR_EXPANDED}}
clean_foobar:
rm {{FOOBAR_BIN}}
[default] [default]
test: build test: build
{{TESTBIN}} {{TESTBIN}}
@@ -28,15 +51,10 @@ build:
DEPENDENCY_HEADERS := if os() == "macos" { DEPENDENCY_HEADERS := if os() == "macos" {
"$(pkg-config --cflags-only-I criterion | sed 's/-I//g')" "$(pkg-config --cflags-only-I criterion | sed 's/-I//g')"
} else if os() == "linux" {
"/usr/include/"
} else { } else {
"TODO" "TODO"
} }
tag: tag:
ctags --languages=c --langmap=c:.c.h -R .
tag-all:
echo "Making tags from project and headers in {{DEPENDENCY_HEADERS}}" echo "Making tags from project and headers in {{DEPENDENCY_HEADERS}}"
ctags --languages=c --langmap=c:.c.h -R {{DEPENDENCY_HEADERS}} . ctags --languages=c --langmap=c:.c.h -R {{DEPENDENCY_HEADERS}} .
+38
View File
@@ -0,0 +1,38 @@
CC := zig cc
CFLAGS := -pedantic -Wall -Wextra -Wno-override-init -O0 -g -fno-omit-frame-pointer -fno-inline
LDFLAGS := -lcriterion
TESTBIN := /tmp/all_tests
.PHONY: test scratch
run_test: test
$(TESTBIN)
run_test_memcheck: test
valgrind --leak-check=full --show-leak-kinds=all --trace-children=yes --error-exitcode=1 $(TESTBIN); \
test:
@echo "Discovering test files..."
@files=$$(find . -type f -name 'test*.c'); \
if [ -z "$$files" ]; then \
echo "No test files found!"; \
else \
echo "Compiling all test files into $(TESTBIN)..."; \
$(CC) $(CFLAGS) _allocator_impl.c $$files -o $(TESTBIN) $(LDFLAGS) || exit 1; \
fi
PROJECT_ROOT := $(shell pwd)
PROJECT_C_FILES := $(shell find $(PROJECT_ROOT) \( -name '*.c' -o -name '*.h' \))
CRITERION_HEADERS := $(shell find /usr/include/criterion)
ALL_FILES := $(PROJECT_C_FILES) $(CRITERION_HEADERS)
tags: $(ALL_FILES)
ctags -R $(ALL_FILES)
scratch: /tmp/scratch
valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=1 /tmp/scratch
/tmp/scratch: scratch.c
gcc scratch.c -o /tmp/scratch
-266
View File
@@ -1,266 +0,0 @@
#include "cig.h"
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#define FLAG_FREE (-1)
#define FLAG_TOMBSTONE (-2)
// TODO: when setting a key to a gravestone, then while the mapping
// item to the right is FLAG_FREE, you can set this one to FLAG_FREE,
// go one index less, and if that is also a FLAG_GRAVESTONE, you can
// continue the process.
#define ESC "\033["
#define RED ESC "31m"
#define DEFAULT ESC "0m"
#define COLORED(COLOR, TEXT) COLOR TEXT DEFAULT
uint32_t map_mod_index(const map_header_t *header, uint32_t i) {
return i % header->mapping_capacity;
}
void map_print_mapping_state(void *this, FILE *file) {
map_header_t *header = PTR_FROM_FIELD_PTR(map_header_t, bytes, this);
for ( unsigned int i = 0; i < header->mapping_capacity; i++ ) {
int mapping = header->mapping_arr[i];
if (mapping == FLAG_TOMBSTONE) {
fprintf(file, "󰮢");
} else if (mapping == FLAG_FREE) {
fprintf(file, "");
} else if (mapping < 0) {
fprintf(file, COLORED(RED, ""));
} else {
fprintf(file, "");
}
}
fprintf(file, "\n");
}
static inline unsigned int mapping_cap(unsigned int capacity) {
return capacity * 2;
}
typedef struct __map_sizes {
size_t header_bytes;
size_t mapping_arr_bytes;
} __map_sizes_t;
__map_sizes_t __map_sizes(size_t capacity, size_t item_size) {
const size_t header_bytes = sizeof(map_header_t) + item_size * capacity;
map_header_t foo;
// TODO: this is shit. I am defining that the mapping arr is 2x the size of
// the items arr in multiple places. Figure this out at some point.
const size_t mapping_arr_bytes = sizeof(*foo.mapping_arr) * capacity * 2;
return (__map_sizes_t){
.header_bytes=header_bytes,
.mapping_arr_bytes=mapping_arr_bytes,
};
}
void *map_create_func(
map_create_func_args_t args
) {
__map_sizes_t sizes = __map_sizes(
args.initial_capacity,
args.item_size
);
map_header_t *header = allocator_alloc_func(
args.allocator,
sizes.header_bytes,
args.file,
args.line
);
header->mapping_arr = allocator_alloc_func(
args.allocator,
sizes.mapping_arr_bytes,
args.file,
args.line
);
header->mapping_capacity = args.initial_capacity * 2;
header->n_items = 0;
header->capacity = args.initial_capacity;
header->item_size = args.item_size;
header->key_size = args.key_size;
header->allocator = args.allocator;
header->hash = args.hash;
header->equals = args.equals;
for ( unsigned int i = 0; i < header->mapping_capacity; i++ ) {
header->mapping_arr[i] = FLAG_FREE;
}
return header->bytes;
}
static const uint8_t *__cig_key_ptr_from_pair_ptr(const map_header_t *this, const uint8_t *pair) {
return (const uint8_t *) (&pair[this->key_offset]);
}
bool map_key_equals(map_header_t *header, const uint8_t *key1_bytes, const uint8_t *key2_bytes) {
if (header->equals != NULL) {
return header->equals(key1_bytes, key2_bytes);
}
for ( unsigned int i = 0; i < header->key_size; i++ ) {
if (key1_bytes[i] != key2_bytes[i]) {
return false;
}
}
return true;
}
unsigned int map_place(void *this, index_pair_t idx) {
map_header_t *header = PTR_FROM_FIELD_PTR(map_header_t, bytes, this);
if (idx.has_old) {
header->mapping_arr[idx.new_i_into_mapping] = header->mapping_arr[idx.old_i_into_mapping];
header->mapping_arr[idx.old_i_into_mapping] = FLAG_TOMBSTONE;
for ( long i = idx.old_i_into_mapping; i != idx.new_i_into_mapping; map_mod_index(header, i-1) ) {
if (header->mapping_arr[i] == FLAG_TOMBSTONE) {
header->mapping_arr[i] = FLAG_FREE;
} else {
break;
}
}
} else {
header->mapping_arr[idx.new_i_into_mapping] = header->n_items;
header->n_items++;
}
return header->mapping_arr[idx.new_i_into_mapping];
}
uint32_t map_hash_key(const map_header_t *header, const uint8_t *key) {
if (header->hash != NULL) {
return map_mod_index(header, header->hash(key));
} else {
return map_mod_index(header, fnv_1a(key, header->key_size));
}
}
typedef struct pair {
const uint8_t *pair;
const size_t pair_len;
const uint8_t *key;
const size_t key_len;
} pair_t;
static pair_t __map_get_pair_at(const map_header_t *this, size_t index) {
const uint8_t *pair = (uint8_t*)(&this->bytes[index * this->item_size]);
const size_t pair_len = this->item_size;
const uint8_t *key = __cig_key_ptr_from_pair_ptr(this, pair);
const size_t key_len = this->key_size;
return (pair_t) {
.pair=pair,
.pair_len=pair_len,
.key=key,
.key_len=key_len,
};
}
index_pair_t map_pair_hash(void *this, const uint8_t *pair) {
map_header_t *header = PTR_FROM_FIELD_PTR(map_header_t, bytes, this);
const uint8_t *new_key = __cig_key_ptr_from_pair_ptr(header, pair);
// find the initial index based on hash
uint32_t i_into_mapping = map_hash_key(header, new_key);
int existing_i_into_bytes = header->mapping_arr[i_into_mapping];
if (existing_i_into_bytes == FLAG_FREE) {
return (index_pair_t) {
.has_old=false,
.new_i_into_mapping=i_into_mapping,
};
}
// TODO THIS!!
}
// TODO: search all occurances of **this. The whole point is to reassign to the
// variable!
void map_assure_growable_by_1(void **this, const char *file, int line) {
map_header_t *header = PTR_FROM_FIELD_PTR(map_header_t, bytes, *this);
unsigned int new_n_items = header->n_items + 1;
if (new_n_items <= header->capacity) {
return;
}
allocator_t allocator = header->allocator;
unsigned int new_capacity = 1;
if (header->capacity > 0) {
new_capacity = header->capacity * 2;
}
__map_sizes_t new_size = __map_sizes(
new_capacity,
header->item_size
);
header = allocator_resize_func(allocator, header, new_size.header_bytes, file, line);
header->mapping_arr = (int*) allocator_resize_func(allocator, header->mapping_arr, new_size.mapping_arr_bytes, file, line);
header->mapping_capacity = new_capacity * 2;
header->capacity=new_capacity;
// first we have to clear the entire mapping array
for ( unsigned int i = 0; i < header->mapping_capacity; i++ ) {
header->mapping_arr[i] = FLAG_FREE;
}
// Then we have to re-hash and map all the items in the existing map.
// The reason for re-hashing is that all hashes are moduloed by the
// size of the mapping array, so the resulting hash will likely change.
for ( unsigned int i = 0; i < header->n_items; i++ ) {
void *pair = &(((uint8_t *)(*this))[i*header->item_size]);
// This is okay, because we absolutely know that the keys don't already
// exist. (assuming all the other code for map is doing it's job)
// TODO: when the header is retrieved within the map_pair_hash function the address is completely wrong. Scrambles the parameters and fucks everyghing!!!
// TODO!!!
// TODO!!!
// TODO!!!
// TODO!!!
unsigned int mapping_index = map_pair_hash(*this, pair).new_i_into_mapping;
header->mapping_arr[mapping_index] = i;
}
// TODO!!!! FUCKING reasign to *this IDIOT!
}
uint32_t fnv_1a(const uint8_t *bytes, const unsigned int size) {
// Yanked from: https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
const uint32_t PRIME = 0x01000193;
const uint32_t OFFSET = 0x811c9dc5;
uint32_t hash = OFFSET;
for (unsigned int i = 0; i < size; i++) {
uint32_t byte = (uint32_t)bytes[i];
hash = hash ^ byte;
hash = hash * PRIME;
}
return hash;
}
int map_len_func(void *this) {
if (this == NULL) {
return 0;
}
map_header_t *header = PTR_FROM_FIELD_PTR(map_header_t, bytes, this);
return header->n_items;
}
int map_cap_func(void *this) {
if (this == NULL) {
return 0;
}
map_header_t *header = PTR_FROM_FIELD_PTR(map_header_t, bytes, this);
return header->capacity;
}
#undef FLAG_FREE
#undef FLAG_TOMBSTONE
#undef ESC
#undef RED
#undef DEFAULT
#undef COLORED
View File
+176 -129
View File
@@ -4,17 +4,19 @@
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
scan_t make_scan(const char *name, const char *buffer, allocator_t allocator) { scanner_t make_scanner(const char *name, const char *buffer, allocator_t allocator) {
scan_t s = { scanner_t s = {
.name = name, .name = name,
.start = buffer, .start = buffer,
.cur = buffer, .cur = buffer,
.value = {0},
.errors = NULL,
.allocator = allocator .allocator = allocator
}; };
return s; return s;
} }
void scan_next_line(scan_t *s) { void scanner_recover(scanner_t *s) {
while (*s->cur && *s->cur != '\n') { while (*s->cur && *s->cur != '\n') {
s->cur++; s->cur++;
} }
@@ -22,9 +24,7 @@ void scan_next_line(scan_t *s) {
s->cur++; // move *past* the newline s->cur++; // move *past* the newline
} }
// TODO: probably do not need an allocator for a scanner? void scanner_error(scanner_t *s, const char *message) {
scan_error_t scan_error(const scan_t *s, const char *message) {
const char *error_pos = s->cur; // use current scanner position const char *error_pos = s->cur; // use current scanner position
// Compute line + column (1-based) // Compute line + column (1-based)
int line = 1, col = 1; int line = 1, col = 1;
@@ -32,78 +32,79 @@ scan_error_t scan_error(const scan_t *s, const char *message) {
if (*p == '\n') { line++; col = 1; } if (*p == '\n') { line++; col = 1; }
else col++; else col++;
} }
// need 40 bytes for pair of largest possible 64 bit values, then some for
return (scan_error_t) { // ':' and ' ' characters. Just rounded up to 64 because reasons.
.filename = s->name, size_t length = strlen(s->name) + 1 + strlen(message) + 1 + 64;
.line = line, char *buf = allocator_alloc(s->allocator, length);
.column = col, snprintf(
.message = message buf,
}; length,
"%s:%d:%d: %s",
s->name, line, col, message
);
error_node_t *node = allocator_alloc(s->allocator, sizeof(error_node_t));
node->msg = buf;
node->next = NULL;
if (!s->errors) {
s->errors = node;
} else {
error_node_t *p = s->errors;
while (p->next) p = p->next;
p->next = node;
}
} }
#define scan_value_result(VAL) ((scan_result_t){.ok=true, .value=(scan_value_t){VAL}}) void scanner_error_and_recover(scanner_t *s, const char *message) {
scanner_error(s, message);
scan_result_t scan_error_result(const scan_t *s, const char *message) { scanner_recover(s);
return (scan_result_t) {
.ok=false,
.error=scan_error(s, message),
};
} }
scan_result_t scan_eof(scan_t *s) { bool scan_eof(scanner_t *s) {
return (scan_result_t) { return *s->cur == '\0';
.ok=*s->cur == '\0',
.error=scan_error(s, "null character not found"),
};
} }
scan_result_t scan_literal(scan_t *s, const char *lit) { bool scan_literal(scanner_t *s, const char *lit) {
const char *save = s->cur; const char *save = s->cur;
while (*lit && *lit == *s->cur) { while (*lit && *lit == *s->cur) {
lit++; lit++;
s->cur++; s->cur++;
} }
if (*lit == '\0') { if (*lit == '\0') {
return scan_value_result(0); return true;
} }
s->cur = save; s->cur = save;
return scan_error_result(s, "invalid literal"); return false;
// TODO: add another optional string field to specify what literal is
// missing
} }
int scan_repeat_literal(scan_t *s, const char *lit) { int scan_repeat_literal(scanner_t *s, const char *lit) {
int n_repeats = 0; int n_repeats = 0;
while (scan_literal(s, lit).ok) { while (scan_literal(s, lit)) {
n_repeats++; n_repeats++;
} }
return n_repeats; return n_repeats;
} }
scan_result_t scan_whitespace(scan_t *s) { bool scan_whitespace(scanner_t *s) {
const char *save = s->cur; const char *save = s->cur;
while (isspace((unsigned char)*s->cur)) s->cur++; while (isspace((unsigned char)*s->cur)) s->cur++;
return (scan_result_t) { return save != s->cur;
.ok=save != s->cur,
.error=scan_error(s, "expected whitespace"),
};
} }
scan_result_t scan_digit(scan_t *s) { bool scan_digit(scanner_t *s) {
if (!isdigit((unsigned char)*s->cur)) { if (!isdigit((unsigned char)*s->cur)) {
return scan_error_result(s, "expected digit"); return false;
} }
s->value.digit = (*s->cur) - '0';
s->cur++; s->cur++;
return scan_value_result(.digit=(*s->cur) - '0'); return true;
} }
scan_result_t scan_i64(scan_t *s) { bool scan_i64(scanner_t *s) {
const char *save = s->cur; const char *save = s->cur;
if (*s->cur == '-' || *s->cur == '+') s->cur++; if (*s->cur == '-' || *s->cur == '+') s->cur++;
if (!isdigit((unsigned char)*s->cur)) { if (!isdigit((unsigned char)*s->cur)) {
s->cur = save; s->cur = save;
return scan_error_result(s, "is not an integer"); return false;
} }
s->cur = save; s->cur = save;
char *end; char *end;
@@ -111,63 +112,69 @@ scan_result_t scan_i64(scan_t *s) {
int64_t val = strtoll(s->cur, &end, 10); int64_t val = strtoll(s->cur, &end, 10);
if (end == s->cur) { if (end == s->cur) {
s->cur = save; s->cur = save;
return scan_error_result(s, "is not an integer"); return false;
} }
if (errno == ERANGE) { if (errno == ERANGE) {
return scan_error_result(s, "integer does not fit in i64 value"); scanner_error(s, "integer does not fit in i64 value");
return false;
} }
s->cur = end; s->cur = end;
return scan_value_result(.i64=val); s->value.i64 = val;
return true;
} }
scan_result_t scan_i32(scan_t *s) { bool scan_i32(scanner_t *s) {
scan_result_t result_i64 = scan_i64(s); if (!scan_i64(s)) {
if (!result_i64.ok) { return false;
return result_i64;
} }
int32_t val = (int32_t)result_i64.value.i64; int32_t val = (int32_t)s->value.i64;
int64_t back = (int64_t)val; int64_t back = (int64_t)val;
if (back != result_i64.value.i64) { if (back != s->value.i64) {
return scan_error_result(s, "integer does not fit in i32 value"); scanner_error(s, "int does not fit in i32 value");
return false;
} }
return scan_value_result(.i32=val); s->value.i32 = val;
return true;
} }
scan_result_t scan_i16(scan_t *s) { bool scan_i16(scanner_t *s) {
scan_result_t result_i64 = scan_i64(s); if (!scan_i64(s)) {
if (!result_i64.ok) { return false;
return result_i64;
} }
int16_t val = (int16_t)result_i64.value.i64; int16_t val = (int16_t)s->value.i64;
int64_t back = (int64_t)val; int64_t back = (int64_t)val;
if (back != result_i64.value.i64) { if (back != s->value.i64) {
return scan_error_result(s, "integer does not fit in i16 value"); scanner_error(s, "int does not fit in i16 value");
return false;
} }
return scan_value_result(.i16=val); s->value.i16 = val;
return true;
} }
scan_result_t scan_i8(scan_t *s) { bool scan_i8(scanner_t *s) {
scan_result_t result_i64 = scan_i64(s); if (!scan_i64(s)) {
if (!result_i64.ok) { return false;
return result_i64;
} }
int8_t val = (int8_t)result_i64.value.i64; int8_t val = (int8_t)s->value.i64;
int64_t back = (int64_t)val; int64_t back = (int64_t)val;
if (back != result_i64.value.i64) { if (back != s->value.i64) {
return scan_error_result(s, "integer does not fit in i8 value"); scanner_error(s, "int does not fit in i8 value");
return false;
} }
return scan_value_result(.i8=val); s->value.i8 = val;
return true;
} }
scan_result_t scan_u64(scan_t *s) { bool scan_u64(scanner_t *s) {
const char *save = s->cur; const char *save = s->cur;
if (*s->cur == '-') { if (*s->cur == '-') {
return scan_error_result(s, "- is not allowed for unsigned integers"); scanner_error(s, "- is not allowed for unsigned integers");
return false;
} }
if (*s->cur == '+') s->cur++; if (*s->cur == '+') s->cur++;
if (!isdigit((unsigned char)*s->cur)) { if (!isdigit((unsigned char)*s->cur)) {
s->cur = save; s->cur = save;
return scan_error_result(s, "not an integer"); return false;
} }
s->cur = save; s->cur = save;
char *end; char *end;
@@ -175,106 +182,112 @@ scan_result_t scan_u64(scan_t *s) {
uint64_t val = strtoull(s->cur, &end, 10); uint64_t val = strtoull(s->cur, &end, 10);
if (end == s->cur) { if (end == s->cur) {
s->cur = save; s->cur = save;
return scan_error_result(s, "not an integer"); return false;
} }
if (errno == ERANGE) { if (errno == ERANGE) {
return scan_error_result(s, "integer does not fit in i64 value"); scanner_error(s, "integer does not fit in u64 value");
return false;
} }
s->cur = end; s->cur = end;
return scan_value_result(.u64=val); s->value.u64 = val;
return true;
} }
scan_result_t scan_u32(scan_t *s) { bool scan_u32(scanner_t *s) {
scan_result_t result_u64 = scan_u64(s); if (!scan_u64(s)) {
if (!result_u64.ok) { return false;
return result_u64;
} }
uint32_t val = (uint32_t)result_u64.value.u64; uint32_t val = (uint32_t)s->value.u64;
uint64_t back = (uint64_t)val; uint64_t back = (uint64_t)val;
if (back != result_u64.value.u64) { if (back != s->value.u64) {
return scan_error_result(s, "integer does not fit in u32 values"); scanner_error(s, "int does not fit in u32 value");
return false;
} }
return scan_value_result(.u32=val); s->value.u32 = val;
return true;
} }
scan_result_t scan_u16(scan_t *s) { bool scan_u16(scanner_t *s) {
scan_result_t result_u64 = scan_u64(s); if (!scan_u64(s)) {
if (!result_u64.ok) { return false;
return result_u64;
} }
uint16_t val = (uint16_t)result_u64.value.u64; uint16_t val = (uint16_t)s->value.u64;
uint64_t back = (uint64_t)val; uint64_t back = (uint64_t)val;
if (back != result_u64.value.u64) { if (back != s->value.u64) {
return scan_error_result(s, "integer does not fit in u16 value"); scanner_error(s, "int does not fit in u16 value");
return false;
} }
return scan_value_result(.u16=val); s->value.u16 = val;
return true;
} }
scan_result_t scan_u8(scan_t *s) { bool scan_u8(scanner_t *s) {
scan_result_t result_u64 = scan_u64(s); if (!scan_u64(s)) {
if (!result_u64.ok) { return false;
return result_u64;
} }
uint8_t val = (uint8_t)result_u64.value.u64; uint8_t val = (uint8_t)s->value.u64;
uint64_t back = (uint64_t)val; uint64_t back = (uint64_t)val;
if (back != result_u64.value.u64) { if (back != s->value.u64) {
return scan_error_result(s, "integer does not fit in u8 value"); scanner_error(s, "int does not fit in u8 value");
return false;
} }
return scan_value_result(.u8=val); s->value.u8 = val;
return true;
} }
scan_result_t scan_f64(scan_t *s) { bool scan_f64(scanner_t *s) {
const char *save = s->cur; const char *save = s->cur;
char *end; char *end;
errno = 0; errno = 0;
double val = strtod(s->cur, &end); double val = strtod(s->cur, &end);
if (end == s->cur) { if (end == s->cur) {
s->cur = save; s->cur = save;
return scan_error_result(s, "not a float"); return false;
} }
if (errno == ERANGE) { if (errno == ERANGE) {
return scan_error_result(s, "float does not fit in f64 value"); scanner_error(s, "float does not fit in f64 value");
return false;
} }
s->cur = end; s->cur = end;
return scan_value_result(.f64=val); s->value.f64 = val;
return true;
} }
scan_result_t scan_f32(scan_t *s) { bool scan_f32(scanner_t *s) {
scan_result_t result_f64 = scan_f64(s); if (!scan_f64(s)) {
if (!result_f64.ok) { return false;
return result_f64;
} }
float val = (float)result_f64.value.f64; float val = (float)s->value.f64;
double back = (double)val; double back = (double)val;
if (back != result_f64.value.f64) { if (back != s->value.f64) {
return scan_error_result(s, "float does not fit in f32 value"); scanner_error(s, "float does not fit in f32 value");
return false;
} }
return scan_value_result(.f32=val); s->value.f32 = val;
return true;
} }
scan_result_t scan_identifier(scan_t *s) { bool scan_identifier(scanner_t *s) {
if (!isalpha((unsigned char)*s->cur) && *s->cur != '_') { if (!isalpha((unsigned char)*s->cur) && *s->cur != '_') {
return scan_error_result(s, "not an identifier"); return false;
} }
const char *start = s->cur++; const char *start = s->cur++;
while (isalnum((unsigned char)*s->cur) || *s->cur == '_') { while (isalnum((unsigned char)*s->cur) || *s->cur == '_') {
s->cur++; s->cur++;
} }
// TODO: use arraylists just to standardize?
size_t len = s->cur - start; size_t len = s->cur - start;
char *buf = allocator_alloc(s->allocator, len + 1); char *buf = allocator_alloc(s->allocator, len + 1);
memcpy(buf, start, len); memcpy(buf, start, len);
buf[len] = '\0'; buf[len] = '\0';
return scan_value_result(.identifier=buf); s->value.identifier = buf;
return true;
} }
scan_result_t scan_string_literal(scan_t *s) { bool scan_string_literal(scanner_t *s) {
// TODO: use arraylists just to standardize?
const char *save = s->cur; const char *save = s->cur;
if (*s->cur != '"') { if (*s->cur != '"')
return scan_error_result(s, "missing opening quote"); return false;
}
s->cur++; // skip opening quote s->cur++; // skip opening quote
char *buf = allocator_alloc(s->allocator, 256); char *buf = allocator_alloc(s->allocator, 256);
size_t cap = 256; size_t cap = 256;
@@ -291,8 +304,9 @@ scan_result_t scan_string_literal(scan_t *s) {
case '"': c = '"'; break; case '"': c = '"'; break;
case '0': c = '\0'; break; case '0': c = '\0'; break;
default: default:
scanner_error(s, "invalid escape sequence");
s->cur = save; s->cur = save;
return scan_error_result(s, "invalid excape sequence"); return false;
} }
} }
if (len + 2 >= cap) { if (len + 2 >= cap) {
@@ -302,18 +316,51 @@ scan_result_t scan_string_literal(scan_t *s) {
buf[len++] = c; buf[len++] = c;
} }
if (*s->cur != '"') { if (*s->cur != '"') {
scanner_error(s, "unterminated string literal");
s->cur = save; s->cur = save;
return scan_error_result(s, "unterminated string literal"); return false;
} }
s->cur++; // skip closing quote s->cur++; // skip closing quote
buf[len] = '\0'; buf[len] = '\0';
return scan_value_result(.string_literal=buf); s->value.string_literal = buf;
return true;
} }
scan_value_t required(scan_result_t res) { bool scanner_print_errors(scanner_t *s, FILE *fp) {
if (!res.ok) { for (error_node_t *node = s->errors; node != NULL; node = node->next) {
fprintf(stderr, "%s:%d:%d: %s", res.error.filename, res.error.line, res.error.column, res.error.message); fprintf(fp, "%s\n", node->msg);
exit(1);
} }
return res.value; return s->errors != NULL;
}
bool looks_like_float(scanner_t *s) {
const char *cur = s->cur;
if (
((*cur) == '+') ||
((*cur) == '-')
) {
cur++;
}
if (!isdigit(((unsigned char)*cur))) {
return false;
} else {
cur++;
}
while (isdigit(((unsigned char)*cur))) {
cur++;
}
if ((*cur) != '.') {
return false;
} else {
cur++;
}
return isdigit(((unsigned char)*cur));
}
bool looks_like_int(scanner_t *s) {
const char *cur = s->cur;
if (*cur == '+' || *cur == '-') {
cur++;
}
return isdigit(*cur);
} }
+7 -7
View File
@@ -139,7 +139,7 @@ Test(arena_allocator, resize_with_zero_capacity) {
typedef struct { typedef struct {
size_t size; size_t size;
size_t capacity; size_t capacity;
size_t item_size; size_t itemsize;
allocator_t allocator; allocator_t allocator;
uint8_t bytes[]; uint8_t bytes[];
} test_header_t; } test_header_t;
@@ -148,7 +148,7 @@ Test(arena_allocator, resize_with_zero_capacity) {
test_header_t *header = allocator_alloc(arena, sizeof(test_header_t)); test_header_t *header = allocator_alloc(arena, sizeof(test_header_t));
header->size = 0; header->size = 0;
header->capacity = 0; header->capacity = 0;
header->item_size = sizeof(int); header->itemsize = sizeof(int);
// Resize to add space for 1 element // Resize to add space for 1 element
header = allocator_resize(arena, header, sizeof(test_header_t) + sizeof(int) * 1); header = allocator_resize(arena, header, sizeof(test_header_t) + sizeof(int) * 1);
@@ -185,7 +185,7 @@ Test(arena_allocator, dyn_array_resize_pattern) {
allocator_t arena = arena_allocator_create(backing, 10 * KB); allocator_t arena = arena_allocator_create(backing, 10 * KB);
allocator_reset(arena); allocator_reset(arena);
int *arr = arr_make(int, arena); int *arr = make_arr(int, arena);
// Add 100 elements, forcing multiple resizes // Add 100 elements, forcing multiple resizes
for (int i = 0; i < 100; i++) { for (int i = 0; i < 100; i++) {
@@ -206,8 +206,8 @@ Test(arena_allocator, multiple_arrays_resize) {
allocator_t arena = arena_allocator_create(backing, 20 * KB); allocator_t arena = arena_allocator_create(backing, 20 * KB);
allocator_reset(arena); allocator_reset(arena);
int *arr1 = arr_make(int, arena); int *arr1 = make_arr(int, arena);
int *arr2 = arr_make(int, arena); int *arr2 = make_arr(int, arena);
// Add to arr1 // Add to arr1
for (int i = 0; i < 50; i++) { for (int i = 0; i < 50; i++) {
@@ -266,11 +266,11 @@ Test(arena_allocator, nested_structures_with_resize) {
allocator_reset(arena); allocator_reset(arena);
// Create array of int pointers (like dyn_array of dyn_arrays) // Create array of int pointers (like dyn_array of dyn_arrays)
int **rows = arr_make(int*, arena); int **rows = make_arr(int*, arena);
// Add 5 rows // Add 5 rows
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
int *row = arr_make(int, arena); int *row = make_arr(int, arena);
for (int j = 0; j < 10; j++) { for (int j = 0; j < 10; j++) {
arr_append(row, i * 10 + j); arr_append(row, i * 10 + j);
} }
+15 -15
View File
@@ -8,7 +8,7 @@ static bool int_eq(const void *a, const void *b) {
Test(dynamic_arrays, append) { Test(dynamic_arrays, append) {
with_borrow(alloc) { with_borrow(alloc) {
int *numbers = arr_make(int, alloc); int *numbers = make_arr(int, alloc);
arr_append(numbers, 40); arr_append(numbers, 40);
arr_append(numbers, 41); arr_append(numbers, 41);
arr_append(numbers, 42); arr_append(numbers, 42);
@@ -28,7 +28,7 @@ Test(dynamic_arrays, append) {
Test(dynamic_arrays, pop) { Test(dynamic_arrays, pop) {
with_borrow(alloc) { with_borrow(alloc) {
int *numbers = arr_make(int, alloc); int *numbers = make_arr(int, alloc);
arr_append(numbers, 40); arr_append(numbers, 40);
arr_append(numbers, 41); arr_append(numbers, 41);
arr_append(numbers, 42); arr_append(numbers, 42);
@@ -55,7 +55,7 @@ Test(dynamic_arrays, pop) {
Test(dynamic_arrays, contains) { Test(dynamic_arrays, contains) {
with_borrow(alloc) { with_borrow(alloc) {
int *numbers = arr_make(int, alloc); int *numbers = make_arr(int, alloc);
arr_append(numbers, 20); arr_append(numbers, 20);
cr_expect(arr_contains(numbers, (int){20})); cr_expect(arr_contains(numbers, (int){20}));
arr_reset(numbers); arr_reset(numbers);
@@ -75,7 +75,7 @@ Test(dynamic_arrays, contains) {
Test(dynamic_arrays, contains_found) { Test(dynamic_arrays, contains_found) {
with_borrow(alloc) { with_borrow(alloc) {
int *arr = arr_make(int, alloc, .initial_capacity = 5); int *arr = make_arr(int, alloc, .initial_capacity = 5);
arr_append(arr, 10); arr_append(arr, 10);
arr_append(arr, 20); arr_append(arr, 20);
arr_append(arr, 30); arr_append(arr, 30);
@@ -88,7 +88,7 @@ Test(dynamic_arrays, contains_found) {
Test(dynamic_arrays, contains_not_found) { Test(dynamic_arrays, contains_not_found) {
with_borrow(alloc) { with_borrow(alloc) {
int *arr = arr_make(int, alloc, .initial_capacity = 5); int *arr = make_arr(int, alloc, .initial_capacity = 5);
arr_append(arr, 10); arr_append(arr, 10);
arr_append(arr, 20); arr_append(arr, 20);
arr_append(arr, 30); arr_append(arr, 30);
@@ -101,7 +101,7 @@ Test(dynamic_arrays, contains_not_found) {
Test(dynamic_arrays, contains_empty) { Test(dynamic_arrays, contains_empty) {
with_borrow(alloc) { with_borrow(alloc) {
int *arr = arr_make(int, alloc, .initial_capacity = 5); int *arr = make_arr(int, alloc, .initial_capacity = 5);
cr_assert_not(arr_contains(arr, (int){10})); cr_assert_not(arr_contains(arr, (int){10}));
} }
@@ -110,7 +110,7 @@ Test(dynamic_arrays, contains_empty) {
Test(dynamic_arrays, contains_cmp_found) { Test(dynamic_arrays, contains_cmp_found) {
with_borrow(alloc) { with_borrow(alloc) {
int *arr = arr_make(int, alloc, .initial_capacity = 5); int *arr = make_arr(int, alloc, .initial_capacity = 5);
arr_append(arr, 10); arr_append(arr, 10);
arr_append(arr, 20); arr_append(arr, 20);
arr_append(arr, 30); arr_append(arr, 30);
@@ -123,7 +123,7 @@ Test(dynamic_arrays, contains_cmp_found) {
Test(dynamic_arrays, contains_cmp_not_found) { Test(dynamic_arrays, contains_cmp_not_found) {
with_borrow(alloc) { with_borrow(alloc) {
int *arr = arr_make(int, alloc, .initial_capacity = 5); int *arr = make_arr(int, alloc, .initial_capacity = 5);
arr_append(arr, 10); arr_append(arr, 10);
arr_append(arr, 20); arr_append(arr, 20);
arr_append(arr, 30); arr_append(arr, 30);
@@ -136,7 +136,7 @@ Test(dynamic_arrays, contains_cmp_not_found) {
Test(dynamic_arrays, contains_cmp_empty) { Test(dynamic_arrays, contains_cmp_empty) {
with_borrow(alloc) { with_borrow(alloc) {
int *arr = arr_make(int, alloc, .initial_capacity = 5); int *arr = make_arr(int, alloc, .initial_capacity = 5);
cr_assert_not(arr_contains_cmp(arr, int_eq, (int){10})); cr_assert_not(arr_contains_cmp(arr, int_eq, (int){10}));
} }
@@ -156,7 +156,7 @@ static bool kv_eq_by_key(const void *a, const void *b) {
Test(dynamic_arrays, contains_cmp_key_value_map) { Test(dynamic_arrays, contains_cmp_key_value_map) {
with_borrow(alloc) { with_borrow(alloc) {
kv_pair_t *map = arr_make(kv_pair_t, alloc, .initial_capacity = 10); kv_pair_t *map = make_arr(kv_pair_t, alloc, .initial_capacity = 10);
// Add some key-value pairs // Add some key-value pairs
arr_append(map, ((kv_pair_t){.key = 1, .value = "one"})); arr_append(map, ((kv_pair_t){.key = 1, .value = "one"}));
@@ -176,7 +176,7 @@ Test(dynamic_arrays, contains_cmp_key_value_map) {
Test(dynamic_arrays, get_valid_indices) { Test(dynamic_arrays, get_valid_indices) {
with_borrow(alloc) { with_borrow(alloc) {
int *arr = arr_make(int, alloc); int *arr = make_arr(int, alloc);
arr_append(arr, 10); arr_append(arr, 10);
arr_append(arr, 20); arr_append(arr, 20);
arr_append(arr, 30); arr_append(arr, 30);
@@ -191,7 +191,7 @@ Test(dynamic_arrays, get_valid_indices) {
Test(dynamic_arrays, set_valid_indices) { Test(dynamic_arrays, set_valid_indices) {
with_borrow(alloc) { with_borrow(alloc) {
int *arr = arr_make(int, alloc); int *arr = make_arr(int, alloc);
arr_append(arr, 10); arr_append(arr, 10);
arr_append(arr, 20); arr_append(arr, 20);
arr_append(arr, 30); arr_append(arr, 30);
@@ -208,7 +208,7 @@ Test(dynamic_arrays, set_valid_indices) {
Test(dynamic_arrays, get_out_of_bounds, .exit_code = 1) { Test(dynamic_arrays, get_out_of_bounds, .exit_code = 1) {
with_borrow(alloc) { with_borrow(alloc) {
int *arr = arr_make(int, alloc); int *arr = make_arr(int, alloc);
arr_append(arr, 10); arr_append(arr, 10);
arr_append(arr, 20); arr_append(arr, 20);
dyn_array_bounds_check_func( arr, 2, __FILE__, __LINE__, false); dyn_array_bounds_check_func( arr, 2, __FILE__, __LINE__, false);
@@ -217,7 +217,7 @@ Test(dynamic_arrays, get_out_of_bounds, .exit_code = 1) {
Test(dynamic_arrays, set_out_of_bounds, .exit_code = 1) { Test(dynamic_arrays, set_out_of_bounds, .exit_code = 1) {
with_borrow(alloc) { with_borrow(alloc) {
int *arr = arr_make(int, alloc); int *arr = make_arr(int, alloc);
arr_append(arr, 10); arr_append(arr, 10);
arr_append(arr, 20); arr_append(arr, 20);
@@ -227,7 +227,7 @@ Test(dynamic_arrays, set_out_of_bounds, .exit_code = 1) {
Test(dynamic_arrays, get_empty_array, .exit_code = 1) { Test(dynamic_arrays, get_empty_array, .exit_code = 1) {
with_borrow(alloc) { with_borrow(alloc) {
int *arr = arr_make(int, alloc); int *arr = make_arr(int, alloc);
dyn_array_bounds_check_func( arr, 0, __FILE__, __LINE__, false); dyn_array_bounds_check_func( arr, 0, __FILE__, __LINE__, false);
} }
} }
-34
View File
@@ -1,34 +0,0 @@
#include <criterion/criterion.h>
#include "cig.h"
#include <stdio.h>
#define FLAG_FREE (-1)
#define FLAG_TOMBSTONE (-2)
static int count_filled(void *map) {
map_header_t *header = PTR_FROM_FIELD_PTR(map_header_t, bytes, map);
int count = 0;
for (unsigned int i = 0; i < header->mapping_capacity; i++) {
if (header->mapping_arr[i] >= 0) {
count++;
}
}
return count;
}
Test(map, test) {
with_borrow(allocator) {
int *s;
set_init(&s, allocator);
int count = count_filled((void*)s);
cr_assert_eq(count, 0, "%d != 0", count);
for (int i = 0; i < 10; i++) {
set_add(&s, 1);
count = count_filled((void*)s);
cr_assert_eq(count, 1, "%d != 0", count);
map_print_mapping_state((void*)s, stdout);
fflush(stdout);
}
}
}
-36
View File
@@ -1,36 +0,0 @@
#include <stdbool.h>
#include <criterion/criterion.h>
#include "cig.h"
typedef long long T;
#define CAPACITY 50
Test(map_hash_key, foo) {
map_header_t header = (map_header_t){0};
header.key_size = sizeof(T);
header.mapping_capacity = CAPACITY;
bool hashed[CAPACITY] = {0};
for (T i = 0; i < CAPACITY; i++) {
uint32_t index = map_hash_key(&header, (const uint8_t*)(&i));
cr_assert(index < CAPACITY);
hashed[index] = true;
}
int n_unique = 0;
for (int i = 0; i < CAPACITY; i++) {
if (hashed[i]) {
n_unique++;
}
}
cr_assert_gt(n_unique, 1);
cr_assert_lt(n_unique, CAPACITY);
printf("Expect high number below 50. Got %d unique hashes.\nThis means %d collisions\n", n_unique, (int)(CAPACITY - n_unique));
}
// TODO: test hash with custom hash function.
-80
View File
@@ -1,80 +0,0 @@
#include <criterion/criterion.h>
#include "cig.h"
Test(map_key_equals, ints) {
{ // should be equal
int key1 = 20;
int key2 = 20;
map_header_t header = (map_header_t) { 0 };
header.key_size = sizeof(key1);
cr_assert(
map_key_equals(
&header,
(const uint8_t*)&key1,
(const uint8_t*)&key2
),
"key %d is not equal to key %d",
key1,
key2
);
}
{ // should not be equal
int key1 = 20;
int key2 = 21;
map_header_t header = (map_header_t) { 0 };
header.key_size = sizeof(key1);
cr_assert(
!map_key_equals(
&header,
(const uint8_t*)&key1,
(const uint8_t*)&key2
),
"key %d is equal to key %d",
key1,
key2
);
}
}
static bool inverse_int_equals(const void *key1, const void *key2) {
int key1_i = *((int*)key1);
int key2_i = *((int*)key2);
return key1_i != key2_i;
}
Test(map_key_equals, custom) {
{ // should be equal
int key1 = 20;
int key2 = 21;
map_header_t header = (map_header_t) { 0 };
header.key_size = sizeof(key1);
header.equals = inverse_int_equals;
cr_assert(
map_key_equals(
&header,
(const uint8_t*)&key1,
(const uint8_t*)&key2
),
"key %d is equal to key %d",
key1,
key2
);
}
{ // should not be equal
int key1 = 20;
int key2 = 20;
map_header_t header = (map_header_t) { 0 };
header.key_size = sizeof(key1);
header.equals = inverse_int_equals;
cr_assert(
!map_key_equals(
&header,
(const uint8_t*)&key1,
(const uint8_t*)&key2
),
"key %d is not equal to key %d",
key1,
key2
);
}
}
+43
View File
@@ -0,0 +1,43 @@
#include <assert.h>
#include <criterion/criterion.h>
#include "cig.h"
Test(scanner, looks_like_float) {
const char *buffer =
"1.0 true\n"
"12.34 true\n"
"0.5 true\n"
"9.99 true\n"
"+1.2 true\n"
"-3.14 true\n"
"1 false\n"
"42 false\n"
"+7 false\n"
"1. false\n"
".5 false\n"
"+. false\n"
"abc false\n"
"+x false\n";
with_borrow(allocator) {
scanner_t scanner = make_scanner("test", buffer, allocator);
while (!scan_eof(&scanner)) {
bool does_look_like_float = looks_like_float(&scanner);
bool does_look_like_int = looks_like_float(&scanner);
while (*scanner.cur++ != ' ');
bool expect;
if (scan_literal(&scanner, "true")) {
expect = true;
} else if (scan_literal(&scanner, "false")) {
expect = false;
} else {
assert(false && "invalid expectation");
}
scan_whitespace(&scanner);
cr_assert_eq(does_look_like_float, expect);
if (does_look_like_float) {
cr_assert(does_look_like_int);
}
}
}
}