mmmmh
This commit is contained in:
parent
82aee127b0
commit
a92b119549
99 changed files with 6922 additions and 5723 deletions
131
docs/arena.md
Normal file
131
docs/arena.md
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
---
|
||||
title = Arena
|
||||
---
|
||||
# Arena
|
||||
-----------
|
||||
|
||||
An arena is a bump allocator, under the hood it can use one of 3 strategies to allocate its data:
|
||||
|
||||
* `Virtual`: allocates with virtual memory, meaning that it reserves the data upfront, but only allocates one page at a time (usually 64 Kb). This is the preferred way to use the arena as it can freely allocate gigabytes of memory for free
|
||||
* `Malloc`: allocates the memory upfront using malloc
|
||||
* `Static`: uses a buffer passed by the user instead of allocating
|
||||
|
||||
To help with allocating big chunks of data, `arena.h` defines the macros `KB`, `MB`, and `GB`. If you don't need them you can define `ARENA_NO_SIZE_HELPERS`
|
||||
|
||||
To create an arena use the macro `arenaMake`:
|
||||
```c
|
||||
arena_t varena = arenaMake(ARENA_VIRTUAL, GB(1));
|
||||
uint8 buffer[1024];
|
||||
arena_t sarena = arenaMake(ARENA_STATIC, sizeof(buffer), buffer);
|
||||
```
|
||||
|
||||
To allocate use the `alloc` macro. The parameters to allocate are:
|
||||
|
||||
* A pointer to the arena
|
||||
* The type to allocate
|
||||
* (optional) the number of items to allocate
|
||||
* (optional) flags:
|
||||
* `ALLOC_NOZERO`: by default the arena sets the memory to zero before returning, use this if you want to skip it
|
||||
* `ALLOC_SOFT_FAIL`: by default the arena panics when an allocation fails, meaning that it never returns `NULL`.
|
||||
* (automatic) the align of the type
|
||||
* (automatic) the size of the type
|
||||
|
||||
Example usage:
|
||||
|
||||
```c
|
||||
// allocate 15 strings
|
||||
str_t *string_list = alloc(arena, str_t, 15);
|
||||
// allocate a 1024 bytes buffer
|
||||
uint8 *buffer = alloc(arena, uint8, 1024);
|
||||
// allocate a structure
|
||||
game_t *game = alloc(arena, game_t);
|
||||
```
|
||||
|
||||
The strength of the arena is that it makes it much easier to reason about lifetimes, for instance:
|
||||
|
||||
```c
|
||||
// pass a pointer to the arena for the data that we need to return
|
||||
WCHAR *win32_get_full_path(arena_t *arena, const char *rel_path) {
|
||||
// we need a small scratch arena for allocations that
|
||||
// will be thrown away at the end of this function
|
||||
uint8 scratch_buf[1024];
|
||||
arena_t scratch = arenaMake(ARENA_STATIC, sizeof(scratch_buf, scratch_buf));
|
||||
|
||||
WCHAR *win32_rel_path = str_to_wchar(&scratch, rel_path);
|
||||
|
||||
DWORD pathlen = GetFullPathName(win32_rel_path, 0, NULL, NULL);
|
||||
WCHAR *fullpath = alloc(arena, WCHAR, pathlen + 1);
|
||||
GetFullPath(win32_rel_path, pathlen + 1, fullpath, NULL);
|
||||
|
||||
// notice how we don't need to free anything at the end
|
||||
return fullpath;
|
||||
}
|
||||
```
|
||||
|
||||
There are a few helper functions:
|
||||
|
||||
* `arenaScratch`: sub allocate an arena from another arena
|
||||
* `arenaTell`: returns the number of bytes allocated
|
||||
* `arenaRemaining`: returns the number of bytes that can still be allocated
|
||||
* `arenaRewind`: rewinds the arena to N bytes from the start (effectively "freeing" that memory)
|
||||
* `arenaPop`: pops N bytes from the arena (effectively "freeing" that memory)
|
||||
|
||||
Here is an example usage of a full program:
|
||||
|
||||
```c
|
||||
typedef struct {
|
||||
char *buf;
|
||||
usize len;
|
||||
} str_t;
|
||||
|
||||
str_t read_file(arena_t *arena, const char *filename) {
|
||||
str_t out = {0};
|
||||
|
||||
FILE *fp = fopen(filename, "rb");
|
||||
if (!fp) goto error;
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
out.len = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
out.buf = alloc(arena, char, out.len + 1);
|
||||
|
||||
fread(out.buf, 1, out.len, fp);
|
||||
|
||||
error:
|
||||
return out;
|
||||
}
|
||||
|
||||
void write_file(const char *filename, str_t data) {
|
||||
FILE *fp = fopen(filename, "wb");
|
||||
if (!fp) return;
|
||||
fwrite(data.buf, 1, data.len, fp);
|
||||
}
|
||||
|
||||
int main() {
|
||||
arena_t arena = arenaMake(ARENA_VIRTUAL, GB(1));
|
||||
str_t title = {0};
|
||||
|
||||
{
|
||||
uint8 tmpbuf[KB(5)];
|
||||
arena_t scratch = arenaMake(ARENA_STATIC, sizeof(tmpbuf), tmpbuf);
|
||||
str_t file = read_file(&scratch, "file.json");
|
||||
json_t json = json_parse(&scratch, file);
|
||||
title = str_dup(arena, json_get(json, "title"));
|
||||
}
|
||||
|
||||
{
|
||||
// copying an arena by value effectively makes it a scratch arena,
|
||||
// as long as you don't use the original inside the same scope!
|
||||
arena_t scratch = arena;
|
||||
str_t to_write = str_fmt(
|
||||
&scratch,
|
||||
"{ \"title\": \"%s\" }", title.buf
|
||||
);
|
||||
write_file("out.json", to_write);
|
||||
}
|
||||
|
||||
// cleanup all allocations at once
|
||||
arenaCleanup(&arena);
|
||||
}
|
||||
```
|
||||
32
docs/base64.md
Normal file
32
docs/base64.md
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
title = Base 64
|
||||
---
|
||||
# Base 64
|
||||
----------
|
||||
|
||||
The `base64.h` header has only two functions, one to encode and one to decode to/from base 64.
|
||||
|
||||
Example usage:
|
||||
```c
|
||||
char *recv_callback(arena_t *arena, buffer_t msg) {
|
||||
buffer_t decoded = base64Decode(arena, msg);
|
||||
alloc(arena, char); // allocate an extra char for the null pointer
|
||||
return (char *)decoded.data;
|
||||
}
|
||||
|
||||
buffer_t send_callback(arena_t *arena) {
|
||||
char msg[] = "Hello World!";
|
||||
buffer_t buf = {
|
||||
.data = msg,
|
||||
.len = arrlen(msg) - 1, // don't include the null pointer
|
||||
};
|
||||
buffer_t encoded = base64Encode(arena, buf);
|
||||
return encoded;
|
||||
}
|
||||
|
||||
int main() {
|
||||
arena_t arena = arenaMake(ARENA_VIRTUAL, GB(1));
|
||||
run_server(&arena, 8080, recv_callback, send_callback);
|
||||
arenaCleanup(&arena);
|
||||
}
|
||||
```
|
||||
49
docs/cthreads.md
Normal file
49
docs/cthreads.md
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
---
|
||||
title = Threads
|
||||
---
|
||||
# Threads
|
||||
----------
|
||||
|
||||
Cross platform threads, mutexes and conditional variables.
|
||||
The api is very similar to pthreads, here is a small example program that uses threads and mutexes.
|
||||
|
||||
```c
|
||||
struct {
|
||||
bool exit;
|
||||
cmutex_t mtx;
|
||||
} state = {0};
|
||||
|
||||
int f1(void *) {
|
||||
mtxLock(state.mtx);
|
||||
state.exit = true;
|
||||
mtxUnlock(state.mtx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int f2(void *) {
|
||||
while (true) {
|
||||
bool exit = false;
|
||||
if (mtxTryLock(state.mtx)) {
|
||||
exit = state.exit;
|
||||
mtxUnlock(state.mtx);
|
||||
}
|
||||
|
||||
if (exit) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main() {
|
||||
state.mtx = mtxInit();
|
||||
|
||||
cthread_t t1 = thrCreate(f1, NULL);
|
||||
thrDetach(t1);
|
||||
|
||||
cthread_t t2 = thrCreate(f2, NULL);
|
||||
thrJoin(t2, NULL);
|
||||
|
||||
mtxFree(state.mtx);
|
||||
}
|
||||
```
|
||||
52
docs/dir.md
Normal file
52
docs/dir.md
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
---
|
||||
title = Dir
|
||||
---
|
||||
# Dir
|
||||
----------
|
||||
|
||||
This header provides a simple directory walker, here is an example usage:
|
||||
|
||||
```c
|
||||
typedef struct source_t {
|
||||
str_t filename;
|
||||
struct source_t *next;
|
||||
} source_t;
|
||||
|
||||
sources_t get_sources(arena_t *arena, strview_t path) {
|
||||
uint8 tmpbuf[KB(5)] = {0};
|
||||
arena_t scratch = arenaMake(ARENA_STATIC, sizeof(tmpbuf), tmpbuf);
|
||||
|
||||
dir_t *dir = dirOpen(&scratch, path);
|
||||
dir_entry_t *entry = NULL;
|
||||
|
||||
source_t *sources = NULL;
|
||||
|
||||
while ((entry = dirNext(&scratch, dir))) {
|
||||
if (entry->type != DIRTYPE_FILE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
strview_t ext = fileGetExtension(strv(entry->name));
|
||||
if (!strvEquals(ext, strv(".c"))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
source_t *new_source = alloc(arena, source_t);
|
||||
new_source->filename = strFmt(arena, "%v/%v", path, entry->name);
|
||||
new_source->next = sources;
|
||||
sources = new_source;
|
||||
}
|
||||
|
||||
return sources;
|
||||
}
|
||||
|
||||
int main() {
|
||||
arena_t arena = arenaMake(ARENA_VIRTUAL, GB(1));
|
||||
source_t *sources = get_sources(&arena, strv("src/colla"));
|
||||
while (sources) {
|
||||
info("> %v", sources->filename);
|
||||
sources = sources->next;
|
||||
}
|
||||
arenaCleanup(&arena);
|
||||
}
|
||||
```
|
||||
BIN
docs/docs.com
Normal file
BIN
docs/docs.com
Normal file
Binary file not shown.
41
docs/file.md
Normal file
41
docs/file.md
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
title = File
|
||||
---
|
||||
# File
|
||||
----------
|
||||
|
||||
This header provides cross platform file functionality.
|
||||
It has all the basics that you can expect which work exactly like the stdio counterparts:
|
||||
|
||||
* `fileOpen`
|
||||
* `fileClose`
|
||||
* `fileIsValid`
|
||||
* `fileRead`
|
||||
* `fileWrite`
|
||||
* `fileSeekEnd`
|
||||
* `fileRewind`
|
||||
* `fileTell`
|
||||
|
||||
Then there are a few helpers functions for reading / writing:
|
||||
|
||||
* Writing:
|
||||
* `filePutc`
|
||||
* `filePuts`
|
||||
* `filePrintf`
|
||||
* `fileWriteWhole`
|
||||
* Reading:
|
||||
* `fileReadWhole`
|
||||
* `fileReadWholeStr`
|
||||
|
||||
There are also some functions to get info about a file without having to open it:
|
||||
|
||||
* `fileExists`
|
||||
* `fileSize`
|
||||
* `fileGetTime`
|
||||
* `fileHasChanged`
|
||||
|
||||
And finally, there are some helper functions:
|
||||
|
||||
* `fileGetFullPath` (for windows)
|
||||
* `fileSplitPath` / `fileGetFilename` / `fileGetExtension`
|
||||
* `fileDelete`
|
||||
28
docs/format.md
Normal file
28
docs/format.md
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
title = Format
|
||||
---
|
||||
# Format
|
||||
----------
|
||||
|
||||
Small formatting utility, it has 2 functions (and the `va_list` alternatives):
|
||||
|
||||
* `fmtPrint`: equivalent to
|
||||
* `fmtBuffer`
|
||||
|
||||
It uses [stb_sprintf](https://github.com/nothings/stb/blob/master/stb_sprintf.h) under the hood, but it also has support for printing buffers using `%v` (structures that are a pair of pointer/size)
|
||||
|
||||
This means it can print strings and [string views](/str).
|
||||
|
||||
In
|
||||
|
||||
Usage example:
|
||||
|
||||
```c
|
||||
int main() {
|
||||
strview_t v = strv("world");
|
||||
char buffer[1024] = {0};
|
||||
|
||||
fmtPrint("Hello %v!", v);
|
||||
fmtBuffer(buffer, sizeof(buffer), "Hello %v!", v);
|
||||
}
|
||||
```
|
||||
37
docs/highlight.md
Normal file
37
docs/highlight.md
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
---
|
||||
title = Highlight
|
||||
---
|
||||
# Highlight
|
||||
----------
|
||||
|
||||
This header provides an highlighter for c-like languages (mostly c).
|
||||
The usage is simple, first create a highlight context using hlInit, for which you need an hl_config_t. The only mandatory argument is colors, which are the strings put before the keywords in the highlighted text.
|
||||
|
||||
You can also pass some flags:
|
||||
* `HL_FLAG_HTML`: escapes html characters
|
||||
|
||||
If you're using the offline documentation, this is the code used to highlight inside the markdown code blocks (simplified to remove actual markdown parsing):
|
||||
|
||||
```c
|
||||
str_t highlight_code_block(arena_t *arena, strview_t code) {
|
||||
uint8 tmpbuf[KB(5)];
|
||||
arena_t scratch = arenaMake(ARENA_STATIC, sizeof(tmpbuf), tmpbuf);
|
||||
|
||||
hl_ctx_t *hl = hlInit(&scratch, &(hl_config_t){
|
||||
.colors = {
|
||||
[HL_COLOR_NORMAL] = strv("</span>"),
|
||||
[HL_COLOR_PREPROC] = strv("<span class=\"c-preproc\">"),
|
||||
[HL_COLOR_TYPES] = strv("<span class=\"c-types\">"),
|
||||
[HL_COLOR_CUSTOM_TYPES] = strv("<span class=\"c-custom-types\">"),
|
||||
[HL_COLOR_KEYWORDS] = strv("<span class=\"c-kwrds\">"),
|
||||
[HL_COLOR_NUMBER] = strv("<span class=\"c-num\">"),
|
||||
[HL_COLOR_STRING] = strv("<span class=\"c-str\">"),
|
||||
[HL_COLOR_COMMENT] = strv("<span class=\"c-cmnt\">"),
|
||||
[HL_COLOR_FUNC] = strv("<span class=\"c-func\">"),
|
||||
[HL_COLOR_SYMBOL] = strv("<span class=\"c-sym\">"),
|
||||
[HL_COLOR_MACRO] = strv("<span class=\"c-macro\">"),
|
||||
},
|
||||
.flags = HL_FLAG_HTML,
|
||||
});
|
||||
}
|
||||
```
|
||||
79
docs/hot_reload.md
Normal file
79
docs/hot_reload.md
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
---
|
||||
title = Hot Reload
|
||||
---
|
||||
# Hot Reload
|
||||
----------
|
||||
|
||||
This header provides cross-platform library hot-reloading. To use it you need to have to entry points, one for the host and one for the client.
|
||||
|
||||
In the client you can then implement these functions:
|
||||
|
||||
* `hr_init`: called when the library is loaded (or reloaded)
|
||||
* `hr_loop`: called every "tick" (or whenever the host decides)
|
||||
* `hr_close`: called when the host finishes
|
||||
|
||||
In the client you need to call these functions:
|
||||
|
||||
* `hrOpen`: load the library and call `hr_init`
|
||||
* `hrStep`: call `hr_loop`
|
||||
* `hrReload`: check if the library has changed, and if so reload it and call `hr_init` again
|
||||
* `hrClose`: call `hr_close` and cleanup
|
||||
|
||||
Example usage:
|
||||
|
||||
### Client
|
||||
|
||||
```c
|
||||
int hr_init(hr_t *ctx) {
|
||||
uint8 tmpbuf[KB(5)];
|
||||
arena_t scratch = arenaMake(ARENA_STATIC, sizeof(tmpbuf), tmpbuf);
|
||||
|
||||
state_t *state = ctx->userdata;
|
||||
uint64 timestamp = fileGetTime(scratch, strv("sprite.png"));
|
||||
if (timestamp > state->last_write) {
|
||||
state->last_write = timestamp;
|
||||
destroy_image(state->sprite);
|
||||
state->sprite = load_image(strv("sprite.png"));
|
||||
}
|
||||
}
|
||||
|
||||
int hr_loop(hr_t *ctx) {
|
||||
state_t *state = ctx->userdata;
|
||||
draw_image(state->sprite, state->posx, state->posy);
|
||||
}
|
||||
|
||||
int hr_close(hr_t *ctx) {
|
||||
state_t *state = ctx->userdata;
|
||||
destroy_image(state->sprite);
|
||||
}
|
||||
```
|
||||
|
||||
### Host
|
||||
|
||||
```c
|
||||
typedef struct {
|
||||
hr_t hr;
|
||||
image_t sprite;
|
||||
int posx;
|
||||
int posy;
|
||||
uint64 last_write;
|
||||
} state_t;
|
||||
|
||||
int main() {
|
||||
arena_t arena = arenaMake(ARENA_VIRTUAL, GB(1));
|
||||
|
||||
state_t state = {0};
|
||||
state.hr.userdata = &state;
|
||||
|
||||
if (!hrOpen(&state.hr, strv("bin/client.dll"))) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (game_poll()) {
|
||||
hrReload(&state.hr);
|
||||
hrStep(&state.hr);
|
||||
}
|
||||
|
||||
hrClose(&state.hr, true);
|
||||
}
|
||||
```
|
||||
45
docs/html.md
Normal file
45
docs/html.md
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
---
|
||||
title = HTML
|
||||
---
|
||||
# HTML
|
||||
----------
|
||||
|
||||
This header provides an easy (although debatably sane) way to generate html in c.
|
||||
|
||||
There are three types of tags:
|
||||
* One and done tags, like `<img>` or `<hr>` which only have an opening tag
|
||||
* Basic tags which follow this format: `<tag>content</tag>`
|
||||
* Tags where the content is probably other tags
|
||||
|
||||
You can open and close any tags using `tagBeg` and `tagEnd`, you can also set attributes like this:
|
||||
|
||||
```c
|
||||
tagBeg("div", .class="content", .id="main");
|
||||
```
|
||||
|
||||
Finally, you can use the `htmlRaw` macro to write raw html.
|
||||
|
||||
Example code:
|
||||
```c
|
||||
str_t generate_page(arena_t *arena, page_t *data) {
|
||||
str_t out = STR_EMPTY;
|
||||
|
||||
htmlBeg(arena, &out);
|
||||
headBeg();
|
||||
title(data->title);
|
||||
htmlRaw(<script src="script.js"></script>)
|
||||
style(data->css);
|
||||
headEnd();
|
||||
bodyBeg();
|
||||
divBeg(.id="main");
|
||||
h1("Hello World!");
|
||||
hr();
|
||||
p("Some content blah blah");
|
||||
img(.src="image.png");
|
||||
divEnd();
|
||||
bodyEnd();
|
||||
htmlEnd();
|
||||
|
||||
return out;
|
||||
}
|
||||
```
|
||||
5
docs/http.md
Normal file
5
docs/http.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title = HTTP
|
||||
---
|
||||
# HTTP
|
||||
----------
|
||||
5
docs/ini.md
Normal file
5
docs/ini.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title = Ini
|
||||
---
|
||||
# Ini
|
||||
----------
|
||||
5
docs/json.md
Normal file
5
docs/json.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title = Json
|
||||
---
|
||||
# Json
|
||||
----------
|
||||
5
docs/markdown.md
Normal file
5
docs/markdown.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title = Markdown
|
||||
---
|
||||
# Markdown
|
||||
----------
|
||||
5
docs/readme.md
Normal file
5
docs/readme.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title = Readme
|
||||
---
|
||||
# Readme
|
||||
----------
|
||||
5
docs/server.md
Normal file
5
docs/server.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title = Server
|
||||
---
|
||||
# Server
|
||||
----------
|
||||
5
docs/sha1.md
Normal file
5
docs/sha1.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title = SHA-1
|
||||
---
|
||||
# SHA-1
|
||||
----------
|
||||
5
docs/socket.md
Normal file
5
docs/socket.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title = Socket
|
||||
---
|
||||
# Socket
|
||||
----------
|
||||
5
docs/str.md
Normal file
5
docs/str.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title = Str
|
||||
---
|
||||
# Str
|
||||
----------
|
||||
5
docs/strstream.md
Normal file
5
docs/strstream.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title = StrStream
|
||||
---
|
||||
# StrStream
|
||||
----------
|
||||
5
docs/tracelog.md
Normal file
5
docs/tracelog.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title = Tracelog
|
||||
---
|
||||
# Tracelog
|
||||
----------
|
||||
5
docs/utf8.md
Normal file
5
docs/utf8.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title = UTF-8
|
||||
---
|
||||
# UTF-8
|
||||
----------
|
||||
5
docs/vec.md
Normal file
5
docs/vec.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title = Vec
|
||||
---
|
||||
# Vec
|
||||
----------
|
||||
5
docs/vmem.md
Normal file
5
docs/vmem.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title = VMem
|
||||
---
|
||||
# VMem
|
||||
----------
|
||||
5
docs/websocket.md
Normal file
5
docs/websocket.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title = WebSocket
|
||||
---
|
||||
# WebSocket
|
||||
----------
|
||||
5
docs/xml.md
Normal file
5
docs/xml.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title = Xml
|
||||
---
|
||||
# Xml
|
||||
----------
|
||||
Loading…
Add table
Add a link
Reference in a new issue