Fix leaks, curious case of gebs blog post
This commit is contained in:
2
baked.c
2
baked.c
@ -19,6 +19,7 @@ INCBIN(hotreload_js, "./etc/hotreload.js");
|
||||
|
||||
INCBIN(blog_welcome_md, "./blog/welcome.md");
|
||||
INCBIN(blog_weird_page_md, "./blog/weird-page.md");
|
||||
INCBIN(blog_curious_case_of_gebs_md, "./blog/curious-case-of-gebs.md");
|
||||
|
||||
Baked_Resource *baked_resources = NULL;
|
||||
|
||||
@ -45,6 +46,7 @@ void init_baked_resources(void)
|
||||
add_baked_resource("hotreload.js", hotreload_js_data, hotreload_js_size);
|
||||
add_baked_resource("blog-welcome.md", blog_welcome_md_data, blog_welcome_md_size);
|
||||
add_baked_resource("blog-weird-page.md", blog_weird_page_md_data, blog_weird_page_md_size);
|
||||
add_baked_resource("blog-curious-case-of-gebs.md", blog_curious_case_of_gebs_md_data, blog_curious_case_of_gebs_md_size);
|
||||
}
|
||||
|
||||
void free_baked_resources(void)
|
||||
|
1
baked.h
1
baked.h
@ -16,6 +16,7 @@ INCBIN_EXTERN(hotreload_js);
|
||||
|
||||
INCBIN_EXTERN(blog_welcome_md);
|
||||
INCBIN_EXTERN(blog_weird_page_md);
|
||||
INCBIN_EXTERN(blog_curious_case_of_gebs_md);
|
||||
|
||||
typedef struct {
|
||||
char *key; // path
|
||||
|
60
blog/curious-case-of-gebs.md
Normal file
60
blog/curious-case-of-gebs.md
Normal file
@ -0,0 +1,60 @@
|
||||
# GEBS - the Good Enough Build System
|
||||
|
||||
GEBS is a reiteration of my previous build system "MIBS" (or MIni Build System). It takes some inspiration from
|
||||
[Tsoding's](https://twitch.tv/tsoding) [nobuild](https://github.com/tsoding/nobuild) and later on [nob.h](https://github.com/tsoding/nob.h).
|
||||
The key difference is the way GEBS is implemented on the inside, which makes it more powerful and extensible than nob.h.
|
||||
GEBS also includes a bunch of extra helper macros, which turn C into a language more akin to Go or Zig, but more on that later.
|
||||
|
||||
## So what makes GEBS different?
|
||||
|
||||
### Allocators
|
||||
|
||||
So one thing I've noticed is that nob.h is used alongside of [arena](https://github.com/tsoding/arena). If you look into the implementation
|
||||
you can see some things, which are somewhat redundant like \`arena_sprintf()\` or \`arena_da_append()\`, \`arena_sb_append_cstr()\` and so on...
|
||||
First of all, why is an arena library managing string builders and dynamic arrays? In my opinion it should be the other way around.
|
||||
A string builder should rather accept a generic allocator interface, which it can then utilize to get it's memory. In GEBS this is done
|
||||
via a \`Gebs_Allocator\` interface.
|
||||
|
||||
\`\`\`c
|
||||
typedef struct {
|
||||
void *(*malloc)(void *self, size_t size);
|
||||
void (*free)(void *self, void *memory);
|
||||
void *(*realloc)(void *self, void *memory, size_t prev_size, size_t new_size);
|
||||
} Gebs_Allocator;
|
||||
|
||||
// Wrapper macros
|
||||
#define gebs_malloc(alloc, size) ((alloc)->malloc((void *)(alloc), (size)))
|
||||
#define gebs_free(alloc, memory) ((alloc)->free((void *)(alloc), (memory)))
|
||||
#define gebs_realloc(alloc, memory, prev_size, new_size) \
|
||||
((alloc)->realloc((void *)(alloc), (memory), (prev_size), (new_size)))
|
||||
\`\`\`
|
||||
|
||||
We then can implement an allocator that conforms to this interface and it will work with any dynamic structure.
|
||||
This is my version of the \`XXX_da_append()\` macro:
|
||||
|
||||
\`\`\`c
|
||||
#define gebs_list_append_alloc(alloc, list, item) \\
|
||||
do { \\
|
||||
if ((list)->items == nil) { \\
|
||||
(list)->capacity = 1; \\
|
||||
(list)->items = gebs_malloc((alloc), \\
|
||||
sizeof(*(list)->items) * (list)->capacity); \\
|
||||
} else { \\
|
||||
if ((list)->count == (list)->capacity) { \\
|
||||
size_t __prev_capacity = (list)->capacity; \\
|
||||
(list)->capacity *= 2; \\
|
||||
(list)->items = gebs_realloc((alloc), (list)->items, \\
|
||||
sizeof(*(list)->items) * __prev_capacity, \\
|
||||
sizeof(*(list)->items) * (list)->capacity); \\
|
||||
} \\
|
||||
} \\
|
||||
(list)->items[(list)->count++] = (item); \\
|
||||
} while(0)
|
||||
|
||||
#define gebs_list_append(list, item) \\
|
||||
gebs_list_append_alloc(&gebs_default_allocator, (list), (item))
|
||||
\`\`\`
|
||||
|
||||
This way a dynamic list can work with any kind of allocator - the default libc allocator, an arena or literally anything else.
|
||||
We're not tied to the libc allocator and then have to implement the same macro of all other allocators.
|
||||
|
3
build.c
3
build.c
@ -36,7 +36,8 @@ int main(int argc, char ** argv)
|
||||
"./etc/simple.min.css",
|
||||
|
||||
"./blog/welcome.md",
|
||||
"./blog/weird-page.md"
|
||||
"./blog/weird-page.md",
|
||||
"./blog/curious-case-of-gebs.md"
|
||||
) {
|
||||
|
||||
RULE("./mongoose.o", "./mongoose/mongoose.c") {
|
||||
|
2
gebs
2
gebs
Submodule gebs updated: c3be4ce8ee...6db36114d5
13
main.c
13
main.c
@ -108,6 +108,17 @@ void init_route_hashtable(void)
|
||||
baked_resource_each(&put_blogs);
|
||||
}
|
||||
|
||||
void free_route_hashtable(void)
|
||||
{
|
||||
for (size_t i = 0; i < shlen(route_hashtable); i++) {
|
||||
if (strlen(route_hashtable[i].key) >= strlen("blog-")
|
||||
&& strncmp(route_hashtable[i].key, "blog-", strlen("blog-")) == 0) {
|
||||
free(route_hashtable[i].key);
|
||||
}
|
||||
}
|
||||
shfree(route_hashtable);
|
||||
}
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
start_timer();
|
||||
@ -118,6 +129,7 @@ int main(int argc, char ** argv)
|
||||
struct mg_mgr mgr;
|
||||
mg_mgr_init(&mgr);
|
||||
init_route_hashtable();
|
||||
defer { free_route_hashtable(); }
|
||||
|
||||
mg_wakeup_init(&mgr);
|
||||
mg_http_listen(&mgr, "http://localhost:8080", &event_handler, NULL);
|
||||
@ -128,7 +140,6 @@ int main(int argc, char ** argv)
|
||||
}
|
||||
|
||||
mg_mgr_free(&mgr);
|
||||
shfree(route_hashtable);
|
||||
|
||||
free_baked_resources();
|
||||
|
||||
|
Reference in New Issue
Block a user