diff options
author | Kimplul <kimi.h.kuparinen@gmail.com> | 2025-07-10 19:44:04 +0300 |
---|---|---|
committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2025-07-10 19:44:04 +0300 |
commit | 645a8026b6f6a89cda5a24d96cf3de39c3ab32e1 (patch) | |
tree | 9388612433ba6a1325ece8a50830b9299e7cb598 | |
download | ngc-645a8026b6f6a89cda5a24d96cf3de39c3ab32e1.tar.gz ngc-645a8026b6f6a89cda5a24d96cf3de39c3ab32e1.zip |
initial commit
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | .gitmodules | 3 | ||||
-rw-r--r-- | Makefile | 8 | ||||
m--------- | deps/conts | 0 | ||||
-rw-r--r-- | example_vec/new/main.c | 33 | ||||
-rw-r--r-- | example_vec/new/vec.h | 116 | ||||
-rw-r--r-- | example_vec/old/conts.h | 22 | ||||
-rw-r--r-- | example_vec/old/main.c | 32 | ||||
-rw-r--r-- | example_vec/old/vec.h | 139 | ||||
-rw-r--r-- | src/main.c | 615 | ||||
-rwxr-xr-x | test/compile_main.sh | 8 | ||||
-rw-r--r-- | test/main.c | 19 | ||||
-rw-r--r-- | test/vec.h | 49 |
13 files changed, 1047 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..eb92346 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +ngc +ngc1 +build diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..70e8d9f --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "deps/conts"] + path = deps/conts + url = https://metanimi.dy.fi/cgit/conts diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7a49e49 --- /dev/null +++ b/Makefile @@ -0,0 +1,8 @@ +all: ngc1 + +ngc1: src/main.c + $(CC) -Ideps/conts/include -Wall -Wextra -g src/main.c -o ngc1 + +.PHONY: clean +clean: + $(RM) ngc1 diff --git a/deps/conts b/deps/conts new file mode 160000 +Subproject 7774ae2f8c2dca9ab2d93082856f031e78a1b5f diff --git a/example_vec/new/main.c b/example_vec/new/main.c new file mode 100644 index 0000000..a00c35c --- /dev/null +++ b/example_vec/new/main.c @@ -0,0 +1,33 @@ +#include "vec.h" + +typedef ints = vec[int](); + +#define foreach(name, i, s) \ + for (name##_iter i = name##_begin(s); !name##_end(s, i); i = name##_next(i)) + +int main() +{ + struct ints ints = ints_create(0); + for (int i = 0; i < 1000000; ++i) { + ints_append(&ints, i); + } + assert(ints_len(&ints) == 1000000); + + for (int i = 0; i < 1000000; ++i) { + int *v = ints_at(&ints, i); + assert(v && *v == i); + } + + int i = 0; + foreach(ints, iter, &ints) { + assert(iter && *iter == i); + i++; + } + + for (int i = 1000000 - 1; i >= 0; --i) { + ints_remove(&ints, i); + } + assert(ints_len(&ints) == 0); + + ints_destroy(&ints); +} diff --git a/example_vec/new/vec.h b/example_vec/new/vec.h new file mode 100644 index 0000000..613af51 --- /dev/null +++ b/example_vec/new/vec.h @@ -0,0 +1,116 @@ +#ifndef NGC_VEC_H +#define NGC_VEC_H + +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <stdbool.h> + +typedef vec[any type]() { + struct <> { + size_t n; + size_t s; + type *buf; + }; + + typedef type *<>_iter; + + struct <> <>_create(size_t reserve) + { + if (reserve == 0) + return (struct <>){.n = 0, .s = 0, .buf = NULL}; + + return (struct <>){ + .n = 0, + .s = reserve, + .buf = malloc(reserve * sizeof(type)) + }; + } + + bool <>_uninit(struct <> *v) + { + return v->buf == NULL; + } + + size_t <>_len(struct <> *v) + { + return v->n; + } + + + type *<>_at(struct <> *v, size_t i) + { + assert(i < v->n && "out of vector bounds"); + return &v->buf[i]; + } + + type *<>_pop(struct <> *v) + { + assert(v->n && "attempting to pop empty vector"); + v->n--; + return &v->buf[v->n]; + } + + type* <>_append(struct <> *v, type n) + { + v->n++; + if (v->n >= v->s) { + v->s = v->s == 0 ? 1 : 2 * v->s; + v->buf = realloc(v->buf, v->s * sizeof(type)); + } + + v->buf[v->n - 1] = n; + } + + void <>_reset(struct <> *v) + { + v->n = 0; + } + + void <>_destroy(struct <> *v) + { + free(v->buf); + } + + void <>_reserve(struct <> *v, size_t n) + { + if (v->n >= n) + return; + + while (v->s < v->n) + v->s = v->s == 0 ? 1 : 2 * v->s; + + v->buf = realloc(v->buf, v->s * sizeof(type)); + } + + void <>_shrink(struct <> *v, size_t n) + { + assert(v->n >= n); + v->n = n; + } + + void <>_remove(struct <> *v, size_t i) + { + assert(v->n > i); + size_t c = sizeof(type) * (v->n - i); + memcpy(&v->buf[i], &v->buf[i + 1], c); + v->n--; + } + + <>_iter <>_begin(struct <> *v) + { + return &v->buf[0]; + } + + bool <>_end(struct <> *v, <>_iter i) + { + return &v->buf[v->n] == i; + } + + <>_iter <>_next(<>_iter i) + { + return i + 1; + } +} + +#endif /* NGC_VEC_H */ diff --git a/example_vec/old/conts.h b/example_vec/old/conts.h new file mode 100644 index 0000000..d175d30 --- /dev/null +++ b/example_vec/old/conts.h @@ -0,0 +1,22 @@ +#ifndef CONTS_H +#define CONTS_H + +#define CONTS_JOIN2(a, b) a##_##b +#define CONTS_JOIN(a, b) CONTS_JOIN2(a, b) + +#define CONTAINER_OF(ptr, type, member) \ + (type *)((char *)(ptr) - offsetof(type, member)) + +#if __STDC_VERSION__ >= 202311UL +# define CONTS_AUTO auto +#elif defined(__GNUC__) +# define CONTS_AUTO __auto_type +#else +# warning "iteration won't work with this compiler" +#endif + +#define foreach(name, i, s)\ + for (CONTS_AUTO i = CONTS_JOIN(name, begin)(s);\ + !CONTS_JOIN(name, end)(s, i);\ + i = CONTS_JOIN(name, next)(i)) +#endif /* CONTS_H */ diff --git a/example_vec/old/main.c b/example_vec/old/main.c new file mode 100644 index 0000000..a84096c --- /dev/null +++ b/example_vec/old/main.c @@ -0,0 +1,32 @@ +#include <assert.h> + +#define VEC_TYPE int +#define VEC_NAME ints +#include <conts/vec.h> + +int main() +{ + struct ints ints = ints_create(0); + for (int i = 0; i < 1000000; ++i) { + ints_append(&ints, i); + } + assert(ints_len(&ints) == 1000000); + + for (int i = 0; i < 1000000; ++i) { + int *v = ints_at(&ints, i); + assert(v && *v == i); + } + + int i = 0; + foreach(ints, iter, &ints) { + assert(iter && *iter == i); + i++; + } + + for (int i = 1000000 - 1; i >= 0; --i) { + ints_remove(&ints, i); + } + assert(ints_len(&ints) == 0); + + ints_destroy(&ints); +} diff --git a/example_vec/old/vec.h b/example_vec/old/vec.h new file mode 100644 index 0000000..19fd18f --- /dev/null +++ b/example_vec/old/vec.h @@ -0,0 +1,139 @@ +#ifndef VEC_TYPE +#error "Need vector type" +#endif + +#ifndef VEC_NAME +#error "Need vector name" +#endif + +#include <stdbool.h> +#include <string.h> +#include <stdlib.h> +#include <assert.h> + +#include "conts.h" + +#define VEC(a) CONTS_JOIN(VEC_NAME, a) + +#define VEC_STRUCT VEC_NAME +struct VEC_STRUCT { + size_t n; + size_t s; + VEC_TYPE *buf; +}; + +static inline struct VEC_STRUCT VEC(create)(size_t reserve) +{ + if (reserve == 0) + return (struct VEC_STRUCT) {.n = 0, .s = 0, .buf = NULL}; + + return (struct VEC_STRUCT) { + .n = 0, + .s = reserve, + .buf = malloc(reserve * sizeof(VEC_TYPE)), + }; +} + +static inline bool VEC(uninit)(struct VEC_STRUCT *v) +{ + return v->buf == NULL; +} + +static inline size_t VEC(len)(struct VEC_STRUCT *v) +{ + return v->n; +} + +static inline VEC_TYPE *VEC(at)(struct VEC_STRUCT *v, size_t i) +{ + assert(i < v->n && "out of vector bounds"); + return &v->buf[i]; +} + +static inline VEC_TYPE *VEC(back)(struct VEC_STRUCT *v) +{ + assert(v->n); + return &v->buf[v->n - 1]; +} + +static inline VEC_TYPE *VEC(pop)(struct VEC_STRUCT *v) +{ + assert(v->n && "attempting to pop empty vector"); + v->n--; + return &v->buf[v->n]; +} + +static inline void VEC(append)(struct VEC_STRUCT *v, VEC_TYPE n) +{ + v->n++; + if (v->n >= v->s) { + v->s = v->s == 0 ? 1 : 2 * v->s; + v->buf = realloc(v->buf, v->s * sizeof(VEC_TYPE)); + } + + v->buf[v->n - 1] = n; +} + +static inline void VEC(reset)(struct VEC_STRUCT *v) +{ + v->n = 0; +} + +static inline void VEC(destroy)(struct VEC_STRUCT *v) { + free(v->buf); +} + +typedef int (*VEC(comp_t))(VEC_TYPE *a, VEC_TYPE *b); +static inline void VEC(sort)(struct VEC_STRUCT *v, VEC(comp_t) comp) +{ + qsort(v->buf, v->n, sizeof(VEC_TYPE), (__compar_fn_t)comp); +} + +static inline void VEC(reserve)(struct VEC_STRUCT *v, size_t n) +{ + if (v->n >= n) + return; + + v->n = n; + if (v->s >= v->n) + return; + + while (v->s < v->n) + v->s = v->s == 0 ? 1 : 2 * v->s; + + v->buf = realloc(v->buf, v->s * sizeof(VEC_TYPE)); +} + +static inline void VEC(shrink)(struct VEC_STRUCT *v, size_t n) +{ + assert(v->n >= n); + v->n = n; +} + +static inline void VEC(remove)(struct VEC_STRUCT *v, size_t i) +{ + assert(v->n > i); + size_t c = sizeof(VEC_TYPE) * (v->n - i); + memcpy(&v->buf[i], &v->buf[i + 1], c); + v->n--; +} + +static inline VEC_TYPE *VEC(begin)(struct VEC_STRUCT *v) +{ + return &v->buf[0]; +} + +static inline bool VEC(end)(struct VEC_STRUCT *v, VEC_TYPE *i) +{ + return &v->buf[v->n] == i; +} + +static inline VEC_TYPE *VEC(next)(VEC_TYPE *i) +{ + return i + 1; +} + +#undef VEC +#undef VEC_TYPE +#undef VEC_NAME +#undef VEC_STRUCT diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..0c7f8cd --- /dev/null +++ b/src/main.c @@ -0,0 +1,615 @@ +#include <stdio.h> +#include <ctype.h> +#include <assert.h> +#include <string.h> + +#define VEC_NAME tokens +#define VEC_TYPE char * +#include <conts/vec.h> + +struct def { + char *id; + char *types; + char *args; + char *body; +}; + +#define MAP_NAME defs +#define MAP_KEY char * +#define MAP_TYPE struct def +#define MAP_CMP(a, b) strcmp((a), (b)) +#define MAP_HASH(a) CONTS_MAP_STR_HASH(a) +#include <conts/map.h> + +struct defs templates; +struct defs traits; + +static void usage(FILE *f) +{ + fprintf(f, "usage: ngc <file>\n"); +} + +static char *append(char *grp, char c) +{ + /* pretty slow but good enough for now I guess */ + size_t len = strlen(grp); + grp = realloc(grp, len + 2); + grp[len] = c; + grp[len + 1] = '\0'; + return grp; +} + +static bool char_in(char c, const char *group) +{ + for (size_t i = 0; i < strlen(group); ++i) + if (c == group[i]) + return true; + + return false; +} + +static void optional_str_space(char *str, size_t *idx) +{ + if (!isspace(str[*idx])) + return; + + while (str[*idx] && isspace(str[*idx])) { + (*idx)++; + } +} + +static char *next_str_grp(char *str, size_t *idx) +{ + char *next = malloc(1 * sizeof(char)); + next[0] = '\0'; + + while (1) { + char c = str[*idx]; + if (!c) + return next; + + if (isspace(c)) + return next; + + /* special separators */ + if (char_in(c, "{[()]},.;")) + return next; + + next = append(next, c); + (*idx)++; + } + + return NULL; +} + +static char *next_str_until(char *str, size_t *idx, char *until) +{ + char *next = malloc(1 * sizeof(char)); + next[0] = '\0'; + + while (1) { + char c = str[*idx]; + if (!c) + return next; + + if (char_in(c, until)) + return next; + + next = append(next, c); + (*idx)++; + } + + return NULL; +} + +static char *optional_space(FILE *f) +{ + int c = fgetc(f); + if (c == EOF) + return NULL; + + if (!isspace(c)) { + ungetc(c, f); + return NULL; + } + + char *space = malloc(2 * sizeof(char)); + space[0] = c; + space[1] = '\0'; + + while (1) { + c = fgetc(f); + if (c == EOF) + return space; + + if (!isspace(c)) { + ungetc(c, f); + return space; + } + + space = append(space, c); + } + + return NULL; +} + +static char *next_grp(char *grp, FILE *f) +{ + /* the worst C parser you'll ever see, lol */ + int c = fgetc(f); + if (c == EOF) { + free(grp); + return NULL; + } + + grp = realloc(grp, 2 * sizeof(char *)); + grp[0] = c; + grp[1] = '\0'; + + if (isspace(c)) { + while (1) { + c = fgetc(f); + if (c == EOF) + return grp; + + if (!isspace(c)) { + ungetc(c, f); + return grp; + } + + grp = append(grp, c); + } + + return NULL; + } + + while (1) { + c = fgetc(f); + if (c == EOF) + return grp; + + if (isspace(c)) { + ungetc(c, f); + return grp; + } + + /* special separators */ + if (char_in(c, "{[(,.*")) { + ungetc(c, f); + return grp; + } + + grp = append(grp, c); + if (char_in(c, "}]);")) + return grp; + } + + return NULL; +} + +static void dump_tokens(struct tokens *tokens) +{ + foreach(tokens, t, tokens) { + printf("%s", *t); + free(*t); + } + tokens_destroy(tokens); +} + +static void drop_tokens(struct tokens *tokens) +{ + foreach(tokens, t, tokens) { + free(*t); + } + tokens_destroy(tokens); +} + +static char *collect_block(char *grp, FILE *f, int start, int end) +{ + int c = fgetc(f); + assert(c == start); + + grp = realloc(grp, 2 * sizeof(char)); + grp[0] = c; + grp[1] = '\0'; + + size_t depth = 1; + while (1) { + int c = fgetc(f); + assert(c != EOF); + grp = append(grp, c); + + if (c == start) + depth++; + + if (c == end) + depth--; + + if (depth == 0) + return grp; + } + + return NULL; +} + +static int is_identifier(char *id) +{ + while (*id) { + if (!isalnum(*id) && *id != '_') + return false; + + id++; + } + + return true; +} + +static char *collect_square_block(char *grp, FILE *f) +{ + return collect_block(grp, f, '[', ']'); +} + +static char *collect_paren_block(char *grp, FILE *f) +{ + return collect_block(grp, f, '(', ')'); +} + +static char *collect_curly_block(char *grp, FILE *f) +{ + return collect_block(grp, f, '{', '}'); +} + +static char *process_trait(char *id, struct tokens *tokens, char *grp, FILE *f) +{ + printf("/* found trait %s*/", id); + grp = collect_curly_block(grp, f); + assert(grp[0] == '{'); + + struct def *exists = defs_find(&traits, id); + if (exists) { + fprintf(stderr, "trait %s redefined\n", id); + drop_tokens(tokens); + return grp; + } + + struct def def = { + .id = strdup(id), + .types = NULL, + .args = NULL, + .body = strdup(grp) + }; + + defs_insert(&traits, def.id, def); + drop_tokens(tokens); + return grp; +} + +static char *process_supertemplate(char *id, char *types, char *args, struct tokens *tokens, char *grp, FILE *f) +{ + printf("/* found supertemplate %s */", id); + dump_tokens(tokens); + return grp; +} + +static char *maybe_process_template(char *id, struct tokens *tokens, char *grp, FILE *f) +{ + printf("/* maybe found template */"); + /* [type args] */ + grp = collect_square_block(grp, f); + char *types = strdup(grp); + tokens_append(tokens, types); + + char *space = optional_space(f); + if (space) + tokens_append(tokens, space); + + /* should be () if we're a template */ + int c = fgetc(f); + ungetc(c, f); + if (c != '(') { + printf("/* nope, no parens */"); + dump_tokens(tokens); + return grp; + } + + /* (value args) */ + grp = collect_paren_block(grp, f); + char *args = strdup(grp); + tokens_append(tokens, args); + + space = optional_space(f); + if (space) + tokens_append(tokens, space); + + c = fgetc(f); + ungetc(c, f); + if (c == '=') + return process_supertemplate(id, types, args, tokens, grp, f); + + if (c != '{') { + printf("/* nope, no block */"); + dump_tokens(tokens); + return grp; + } + + printf("/* it is! %s*/", id); + char *body = grp = collect_curly_block(grp, f); + + struct def *exists = defs_find(&templates, id); + if (exists) { + fprintf(stderr, "template %s redefined\n", id); + drop_tokens(tokens); + return grp; + } + + struct def def = { + /* these could be gotten rid of but works for now */ + .id = strdup(id), + .types = strdup(types), + .args = strdup(args), + .body = strdup(body) + }; + + defs_insert(&templates, def.id, def); + drop_tokens(tokens); + return grp; +} + +static bool word(char *hay, char *needle, size_t len) +{ + for (size_t i = 0; i < len; ++i) { + if (hay[i] != needle[i]) + return false; + } + + /* word ends in something other than alphanumeric */ + return !isalnum(hay[len]); +} + +static char *replace(char *body, char *replace, char *id, bool wordboundary) +{ + assert(body); + assert(id); + + char *orig = body; + char *new = malloc(1 * sizeof(char)); + new[0] = '\0'; + + size_t len = strlen(replace); + + while (body[0]) { + /* lol terrible */ + bool found = wordboundary ? word(body, replace, len) + : strncmp(body, replace, len) == 0; + + if (found) { + char *copy = id; + while (*copy) { + new = append(new, *copy); + copy++; + } + + body += len; + continue; + } + + new = append(new, body[0]); + body += 1; + } + + free(orig); + return new; +} + +static char *process_instance(char *id, struct tokens *tokens, char *grp, FILE *f) +{ + printf("/* found instance %s */", id); + /* discard equals sign */ + int c = fgetc(f); + assert(c == '='); + + char *space = optional_space(f); + if (space) + tokens_append(tokens, space); + + /* template */ + grp = next_grp(grp, f); + char *template = strdup(grp); + assert(is_identifier(template)); + tokens_append(tokens, template); + + /* types */ + space = optional_space(f); + if (space) + tokens_append(tokens, space); + + grp = collect_square_block(grp, f); + char *types = strdup(grp); + tokens_append(tokens, types); + + /* args */ + space = optional_space(f); + if (space) + tokens_append(tokens, space); + + grp = collect_paren_block(grp, f); + char *args = strdup(grp); + tokens_append(tokens, args); + + struct def *def = defs_find(&templates, template); + if (!def) { + /** @todo location info and so on */ + fprintf(stderr, "no such template: %s\n", template); + return grp; + } + + /** @todo check traits */ + + /* +1 to skip leading '{' */ + char *body = strdup(def->body + 1); + /* overwrite trailing '}' */ + body[strlen(body) - 1] = '\0'; + + body = replace(body, "<>", id, false); + + /* handle type args */ + char *params = def->types; + assert(params[0] == '['); + + /* skip '[' */ + size_t params_idx = 1; + + /* skip '(' in args */ + size_t types_idx = 1; + + while (1) { + /* get type param */ + optional_str_space(params, ¶ms_idx); + + char *trait = next_str_grp(params, ¶ms_idx); + assert(is_identifier(trait)); + + optional_str_space(params, ¶ms_idx); + char *name = next_str_grp(params, ¶ms_idx); + assert(is_identifier(name)); + + optional_str_space(params, ¶ms_idx); + char delim = params[params_idx++]; + assert(delim == ',' || delim == ']'); + + /* get arg type */ + optional_str_space(types, &types_idx); + char *type = next_str_until(types, &types_idx, ",]"); + char last = types[types_idx++]; + assert(last == ',' || last == ']'); + + /** @todo assert that we're dealing with a type? */ + body = replace(body, name, type, true); + + free(trait); + free(name); + free(type); + + if (delim == ']' && last == ']') + break; + + if (delim == ']') { + fprintf(stderr, "more type args than params\n"); + free(body); + drop_tokens(tokens); + return grp; + } + + if (last == ']') { + fprintf(stderr, "more type params than args\n"); + free(body); + drop_tokens(tokens); + return grp; + } + } + + /** @todo regular params, probably much like above but parsing the type + * might be a bit annoying... */ + + printf(body); + free(body); + + /* ; can probably be ignored...?*/ + drop_tokens(tokens); + return grp; +} + +static char *process_typedef(char *grp, FILE *f) +{ + struct tokens tokens = tokens_create(3); + tokens_append(&tokens, strdup(grp)); + + /* space */ + grp = next_grp(grp, f); + assert(grp); + tokens_append(&tokens, strdup(grp)); + + /* id */ + grp = next_grp(grp, f); + assert(grp); + + char *id = strdup(grp); + assert(is_identifier(id)); + tokens_append(&tokens, id); + + /* space/check */ + char *space = optional_space(f); + if (space) + tokens_append(&tokens, space); + + char c = fgetc(f); + ungetc(c, f); + if (c == '{' + && strcmp(id, "struct") != 0 + && strcmp(id, "union") != 0 + && strcmp(id, "enum") != 0) + return process_trait(id, &tokens, grp, f); + + if (c == '[') + return maybe_process_template(id, &tokens, grp, f); + + if (c == '=') + return process_instance(id, &tokens, grp, f); + + dump_tokens(&tokens); + return grp; +} + +static int process(FILE *f) +{ + char *grp = NULL; + while ((grp = next_grp(grp, f))) { + if (strcmp(grp, "typedef") == 0) + grp = process_typedef(grp, f); + else + printf("%s", grp); + } + + return 0; +} + +static void free_defs(struct defs *defs) +{ + foreach(defs, def, defs) { + struct def d = def->data; + free(d.id); + free(d.types); + free(d.args); + free(d.body); + } + + defs_destroy(defs); +} + +int main(int argc, char *argv[]) +{ + if (argc != 2) { + usage(stderr); + return -1; + } + + templates = defs_create(0); + traits = defs_create(0); + + char *fname = argv[1]; + + FILE *f = NULL; + if (strcmp(fname, "-") == 0) + f = stdin; + else + f = fopen(fname, "rb"); + + assert(f); + + int ret = process(f); + + free_defs(&templates); + free_defs(&traits); + fclose(f); + return ret; +} diff --git a/test/compile_main.sh b/test/compile_main.sh new file mode 100755 index 0000000..5467005 --- /dev/null +++ b/test/compile_main.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +set -eu + +mkdir -p build/test +gcc -E test/main.c -o build/test/main.c +./ngc build/test/main.c > build/test/main_ngc.c +gcc build/test/main_ngc.c -o build/test/main diff --git a/test/main.c b/test/main.c new file mode 100644 index 0000000..489618b --- /dev/null +++ b/test/main.c @@ -0,0 +1,19 @@ +#include <stdio.h> +#include "vec.h" + +typedef ints = vec[int](); + +int main() +{ + struct ints a = intscreate(); + for (size_t i = 0; i < 10; ++i) + intsappend(&a, i); + + int sum = 0; + for (size_t i = 0; i < 10; ++i) { + sum += *intsat(&a, i); + } + + printf("%i\n", sum); + intsdestroy(&a); +} diff --git a/test/vec.h b/test/vec.h new file mode 100644 index 0000000..810e663 --- /dev/null +++ b/test/vec.h @@ -0,0 +1,49 @@ +#ifndef VEC_H +#define VEC_H + +#include <stddef.h> +#include <assert.h> +#include <stdlib.h> + +typedef any {}; + +typedef vec[any type]() { + struct <> { + size_t n; + size_t s; + type *buf; + }; + + static inline struct <> <>create() + { + return (struct <>){ + .n = 0, + .s = 0, + .buf = NULL + }; + } + + static inline void <>append(struct <> *v, type n) + { + v->n++; + if (v->n > v->s) { + v->s = v->s == 0 ? 1 : 2 * v->s; + v->buf = realloc(v->buf, v->s * sizeof(type)); + } + + v->buf[v->n - 1] = n; + } + + static inline type *<>at(struct <> *v, size_t i) + { + assert(i < v->n); + return &v->buf[i]; + } + + static inline void <>destroy(struct <> *v) + { + free(v->buf); + } +} + +#endif /* VEC_H */ |