This commit is contained in:
Abdulmujeeb Raji 2025-01-29 15:23:13 +00:00
parent 515c1200a7
commit 71bf582ba6
Signed by: midnadimple
GPG key ID: EB02C582F8C3962B
7 changed files with 159 additions and 61 deletions

View file

@ -27,7 +27,8 @@ of making the region of memory allocated to more explicit.
operations are included by default.
- [x] Generic data-structures. The premier one is the
[Dynamic Array](https://dylanfalconer.com/articles/dynamic-arrays-in-c), which
brings the power of C++'s `std::vector` to C.
brings the power of C++'s `std::vector` to C. There is also a HashMap, which is
implemented as a [4-ary hash-trie](https://nullprogram.com/blog/2023/09/30/).
- [x] A I/O system that supports both standard input/output and file
input/output. It's built on a basic buffer type that you can flush to output
data. This buffer type also acts as a **string builder**, by letting you append
@ -38,6 +39,7 @@ primitives.
- [ ] A 3D Math API with supports for Vectors and Matricies using SIMD.
- [ ] A simple GUI initialization system that gets you a window with immediate-mode
input and a Direct3D11 (Win32) / OpenGL (Linux) context to build a renderer with.
- [ ] A simple immediate mode GUI with support for custom widgets.
- [ ] An audio library. Windows implementation uses WASAPI, Linux uses ALSA.
---

View file

@ -0,0 +1,89 @@
#define BASTD_CLI
#include "../../bastd.c"
/* The sl_TYPE macro defines the type of the generic. It is cleared after every
include of "../slice.c"
*/
#define sl_TYPE I64
#include "../slice.c"
// SLICE types
FUNCTION void
fib_slice(Buffer *output, m_Allocator *perm)
{
// Slices can be created with a backing array to start with.
I64 init[] = {0, 1};
sl_I64 fib = sl_I64_create(init, 2);
for (;;) {
// The data in a slice can be accessed like a normal array
I64 a = fib.elems[fib.len - 2];
I64 b = fib.elems[fib.len - 1];
if (a + b > 255) {
break;
}
/* The sl_TYPE_push function automatically doubles the capacity of the
array if the slice is full and returns a pointer to a new element
*/
*sl_I64_push(&fib, perm) = a + b;
}
for (int i = 0; i < fib.len; i++) {
Buffer_appendI64(output, fib.elems[i]);
Buffer_appendU8(output, '\n');
}
Buffer_standardOutput(output);
}
/* These generic structures may have more than one required macro */
#define hm_KEY_TYPE S8
#define hm_KEY_HASHPROC S8_hash_prime19
#define hm_KEY_EQUALSPROC S8_equal
#define hm_VAL_TYPE U64
#include "../hashmap.c" // will define hm_S8_U64
// HASHMAPS
FUNCTION void
citypopulus_hashmap(Buffer *output, m_Allocator *perm)
{
// We always store a hashmap pointer, NOT the actual hashmap
hm_S8_U64 *database = hm_EMPTY;
*hm_S8_U64_upsert(&database, S8("London"), perm) = 8800000;
*hm_S8_U64_upsert(&database, S8("Lahore"), perm) = 13000000;
*hm_S8_U64_upsert(&database, S8("Dhaka"), perm) = 21280000;
*hm_S8_U64_upsert(&database, S8("Washington D.C."), perm) = 679000;
*hm_S8_U64_upsert(&database, S8("Taxila"), perm) = 739000;
// Can't iterate through hashmap, but in exchange, accessing values is fast
// NOTE: passing no allocator implies that you should NOT insert a value if it doesnt exist
U64 dc_population = *hm_S8_U64_upsert(&database, S8("Washington D.C."), NIL);
U64 lahore_population = *hm_S8_U64_upsert(&database, S8("Lahore"), NIL);
U64 london_population = *hm_S8_U64_upsert(&database, S8("London"), NIL);
Buffer_appendI64(output, dc_population);
Buffer_appendU8(output, '\n');
Buffer_appendI64(output, lahore_population);
Buffer_appendU8(output, '\n');
Buffer_appendI64(output, london_population);
Buffer_appendU8(output, '\n');
Buffer_standardOutput(output);
}
CALLBACK_EXPORT os_ErrorCode
os_entry(void)
{
m_Buddy buddy = m_Buddy_create(os_alloc(MEGA(2)), MEGA(2));
m_Allocator perm = m_BUDDY_ALLOCATOR(buddy);
Buffer output = BUFFER(m_MAKE(U8, KILO(2), &perm), KILO(2));
fib_slice(&output, &perm);
citypopulus_hashmap(&output, &perm);
return os_ErrorCode_success;
}

View file

@ -1,59 +0,0 @@
#define BASTD_CLI
#include "../../bastd.c"
/* The sl_TYPE macro defines the type of the generic. It is cleared after every
include of "../slice.c"
*/
#define sl_TYPE I64
#include "../slice.c"
CALLBACK_EXPORT os_ErrorCode
os_entry(void)
{
m_Buddy buddy = m_Buddy_create(os_alloc(MEGA(2)), MEGA(2));
m_Allocator perm = m_BUDDY_ALLOCATOR(buddy);
// Slices can be created with a backing array to start with.
I64 init[] = {0, 1};
sl_I64 fib = sl_I64_create(init, 2);
for (;;) {
// The data in a slice can be accessed like a normal array
I64 a = fib.elems[fib.len - 2];
I64 b = fib.elems[fib.len - 1];
if (a + b > 255) {
break;
}
/* The sl_TYPE_push function automatically doubles the capacity of the
array if the slice is full and returns a pointer to a new element
*/
*sl_I64_push(&fib, &perm) = a + b;
}
Buffer output = BUFFER(m_MAKE(U8, KILO(2), &perm), KILO(2));
for (int i = 0; i < fib.len; i++) {
Buffer_appendI64(&output, fib.elems[i]);
Buffer_appendU8(&output, '\n');
}
Buffer_standardOutput(&output);
// Wait for you to press enter
Buffer_appendS8(&output, S8("I've got a message for you. Press Enter to see it: "));
Buffer_standardOutput(&output);
Buffer_appendStandardInput(&output, 1024, &perm);
sl_S8 msgs = sl_S8_create(NIL, 0);
*sl_S8_push(&msgs, &perm) = S8("C standard library!");
*sl_S8_push(&msgs, &perm) = S8("a Bravely Arranged ");
*sl_S8_push(&msgs, &perm) = S8("This is ");
*sl_S8_push(&msgs, &perm) = S8("World! ");
*sl_S8_push(&msgs, &perm) = S8("Hello, ");
for (; msgs.len > 0;) {
Buffer_appendS8(&output, sl_S8_pop(&msgs));
}
Buffer_standardOutput(&output);
return os_ErrorCode_success;
}

53
bastd/hashmap.c Normal file
View file

@ -0,0 +1,53 @@
// GENERIC FILE, REDEFINED EVERY INCLUDE
#ifndef hm_KEY_TYPE
#error "No hm_KEY_TYPE given"
#endif
// hm_KEY_HASHPROC need signature "U64 procname(hm_KEY_TYPE)"
#ifndef hm_KEY_HASHPROC
#error "No hm_KEY_HASHPROC given"
#endif
#ifndef hm_KEY_EQUALSPROC
#error "No hm_KEY_EQUALSPROC given"
#endif
#ifndef hm_VAL_TYPE
#error "No hm_VAL_TYPE given"
#endif
#define hm_NAME CONCAT(CONCAT(hm_, hm_KEY_TYPE), CONCAT(_, hm_VAL_TYPE))
typedef struct hm_NAME hm_NAME;
struct hm_NAME {
hm_NAME *child[4];
hm_KEY_TYPE key;
hm_VAL_TYPE val;
};
// always store a pointer to the hashmap, not the actual value
#define hm_EMPTY NIL
FUNCTION hm_VAL_TYPE *
CONCAT(hm_NAME, _upsert) (hm_NAME **m, hm_KEY_TYPE key, m_Allocator *perm)
{
for (U64 h = hm_KEY_HASHPROC(key); *m; h <<= 2) {
if (hm_KEY_EQUALSPROC(key, (*m)->key)) {
return &(*m)->val;
}
m = &(*m)->child[h>>62];
}
if (perm == NIL) {
// just searching, dont insert a new value
return NIL;
}
*m = m_MAKE(hm_NAME, 1, perm);
(*m)->key = key;
return &(*m)->val;
}
#undef hm_NAME
#undef hm_VAL_TYPE
#undef hm_KEY_EQUALSPROC
#undef hm_KEY_HASHPROC
#undef hm_KEY_TYPE

View file

@ -352,6 +352,7 @@ m_Buddy_alloc(void *ctx, void *ptr, U64 old_size, U64 new_size) {
if (found != NIL) {
found->is_free = FALSE;
U8 *p = (U8 *)found + b->alignment;
m_memorySet(p, 0, new_size);
if (ptr != NIL) {
m_memoryCopy(p, ptr, old_size);
}

View file

@ -203,4 +203,16 @@ S8_join(sl_S8 s, S8 join, m_Allocator *perm) {
return (S8){total_length, mem};
}
// Should probably get a better hashing func, but oh well
FUNCTION U64
S8_hash_prime19(S8 s)
{
U64 h = 0x100;
for (U64 i = 0; i < s.len; i++) {
h ^= s.raw[i];
h *= 1111111111111111111u;
}
return h;
}
#endif//BASTD_STRING_C

View file

@ -7,7 +7,7 @@ set debugflags=/nologo /W3 /MTd /Od /Zi /RTC1 /fsanitize=address /link /incremen
REM Uncomment one of these to run an example. Try it! They're great documentation.
REM cl ..\bastd\examples\memory.c %debugflags%
REM cl ..\bastd\examples\fib_slice.c %debugflags%
REM cl ..\bastd\examples\data_structs.c %debugflags%
REM cl ..\bastd\examples\string.c %debugflags%
REM cl ..\bastd\examples\buffer.c %debugflags%
REM cl ..\bastd\examples\job_random.c %debugflags%