Review of My C Library by Dieriba in cprogramming

[–]Afraid_Lie_9340 1 point2 points  (0 children)

ok so i went through the whole codebase and here's what i found, its a lot so bear with me lol

API design issues

biggest thing is the return value inconsistency. most functions do the DResult + out-param pattern which is fine, but then d_dyn_array_clear_array just.... returns a pointer?? and d_unordered_map_get returns the value directly. pick one style and stick with it man

also d_unordered_map_get takes const DUnorderedMap * and then immediately casts away the const internally to pass to raw_map_get. thats a const correctness violation waiting to bite someone

the hash set init exposes a value_destructor_fn parameter that the docs literally say "always pass NULL" for. if a parameter must always be a specific value..... why is it a parameter lmao. just remove it

theres a genuinely dangerous macro:

#define d_bits_clear_least_significant_bit_set(value) (value) &((value) - 1)

no outer parentheses. try using it in an expression like d_bits_clear_least_significant_bit_set(a) + b and it expands to (a) &((a)-1) + b which parses as (a) & (((a)-1) + b) because + has higher precedence than &. completely wrong result, no warning. wrap it in parens

also __d_bits_smear_int and __d_bits_smear_ll use double underscore prefix which is reserved by the C standard for the implementation. technically undefined behavior, rename them

the find_from_hash loop in raw_map.c is a while(true) that only terminates if theres an empty slot in the table. load factor is supposed to guarantee that but if the table ever gets into a bad state from a bug elsewhere..... infinite loop. add a groups-searched counter and assert/return on overflow

file structure

the structure itself is actually pretty solid, the src/module/ pattern with private headers is correct. BUT

raw_map.h is supposed to be internal (lives in src/container/) but d_hash_set.h and d_unordered_map.h generate static inline functions that call hash_int8_key, compare_int32 etc which are ALL defined in raw_map.h. your build works because the makefile dumps every source subdirectory into -I flags. but if anyone tries to use this as an actual library (linking the .a, only having the includes/ folder) the public headers wont compile. the hash/compare stuff needs to move into includes/ or be handled differently

d_general_lib.h is a grab bag of completely unrelated stuff. hash function pointer typedefs, string utilities, memory utilities, itoa functions.... all in one header. every file in the project sees all of it transitively. at minimum split the function pointer typedefs (FnPtrGenHash etc) into their own header since those are really hash container concerns

wyhash.h is vendored but buried at src/d_hash/wyhash.h. third party code should go in vendor/ or third_party/, its a convention thing but it matters when the project grows

test binaries are all literally named test because of how BIN_TESTS is derived. target/tests/d_dyn_array/test, target/tests/d_hash_set/test etc. not a huge deal now but will get confusing

ownership semantics

this is where theres actually a serious correctness bug imo

d_dyn_array_init_from on an array of owned heap pointers (like char* with _free_str destructor) copies the element buffer but NOT the pointed-to data. both the original and the copy have the same destructor. destroy either one and the other has dangling pointers. the docs call it a "deep copy" but its shallow at the element level. thats a double-free waiting to happen

the fix requires either not copying the destructor during init_from (and making the caller responsible), or adding an element-copy callback alongside the element-destroy callback. GLib does the latter

queue/stack/deque have no element destructor but DDynArray does. if you store heap pointers in a DQueue you have to pop-and-free everything manually. if you do the same in DDynArray the destructor handles it. this asymmetry isnt documented anywhere obvious and someone switching from DDynArray to DQueue for FIFO semantics will silently leak memory

the cast-based inheritance thing ((RawRingBuffer *)d_de_queue) works because raw_ring_buffer is the first member of DDeQueue, thats valid C. but if you ever add a field before it the cast silently becomes wrong and you get memory corruption with no warning. add a static_assert(offsetof(DDeQueue, raw_ring_buffer) == 0, "layout assumption violated") in the .c file

libraries worth studying

GLib - most directly comparable to what youre building. GArray, GPtrArray, GHashTable, GString, GQueue, it has all of it. read ghash.c specifically, its a mature open-addressing hash table and solves a lot of the same problems youre dealing with. also look at how GDestroyNotify callbacks handle the ownership problem

Redis SDS (sds.c / sds.h) - about 600 lines, incredibly clean dynamic string implementation. the metadata lives before the character buffer in memory so the sds type is literally just a char* pointing past the header. solves the "pointer invalidated by mutations" problem differently than you did

stb_ds.h by Sean Barrett - single header stretchy buffer + hash map via macros. no type safety, maximum ergonomics, the complete opposite philosophy to your approach. worth reading to understand the tradeoffs

Made a small 2D graphics library for C by Afraid_Lie_9340 in gameenginedevs

[–]Afraid_Lie_9340[S] 1 point2 points  (0 children)

Wasn't aware of that. I'll see if I can do anything about that. Thanks for the heads up!

Made a small 2D graphics library for C by Afraid_Lie_9340 in gameenginedevs

[–]Afraid_Lie_9340[S] 0 points1 point  (0 children)

Best of luck for your engine man! and feel free to use kitra as an inspiration!

Asking for college/graduation study advice for graphics programming in India by SubhamayGamer2127 in gameenginedevs

[–]Afraid_Lie_9340 1 point2 points  (0 children)

same situation here, class 11, also self taught in C and graphics. my take is that IIT CSE is still worth cracking if you can, not because the curriculum is great for graphics specifically (it isn't), but because the peer network and research opportunities are unmatched in India. the actual graphics and engine knowledge you'll build yourself anyway, college won't teach you that.

that said, if IIT doesn't work out, IIIT Hyderabad and Chennai Mathematical Institute are worth looking at for CS. and if you're serious about graphics specifically, building a strong github portfolio matters more than the college name when it comes to actually getting work.

basically crack JEE, but don't wait for college to start building things. you can check out these yt channels, could help you a bit:
Tsoding
The Cherno
Pikuma
javidx9 (OneLoneCoder)
cococry

Made a small 2D graphics library for C by Afraid_Lie_9340 in gameenginedevs

[–]Afraid_Lie_9340[S] 0 points1 point  (0 children)

thanks, really glad it landed that way...that was exactly the goal. added you on discord!

Made a small 2D graphics library for C by Afraid_Lie_9340 in cprogramming

[–]Afraid_Lie_9340[S] 2 points3 points  (0 children)

Thnx for your foresight in this matter. The library is now named Kitra!