Browse Source
* These new classes are based on the STB data structures which are fully C-compatible * Dictionary is still WIPwindows-imgui
3 changed files with 209 additions and 4 deletions
@ -0,0 +1,50 @@ |
|||
(set-cakelisp-option cakelisp-src-dir "Dependencies/cakelisp/src") |
|||
|
|||
(add-cakelisp-search-directory "Dependencies/cakelisp/runtime") |
|||
(import &comptime-only "CHelpers.cake" "Dependencies.cake") |
|||
|
|||
;; TODO: Make this an "infect" to the importer rather than having to be global |
|||
(add-c-search-directory-global "Dependencies/stb") |
|||
;; TODO: Remove once importing this module no longer changes all compile commands |
|||
(add-build-config-label "STB") |
|||
|
|||
;; Enforce only defining the implemention once |
|||
(comptime-cond |
|||
('stb-ds-defined) |
|||
(true |
|||
(c-preprocessor-define STB_DS_IMPLEMENTATION) |
|||
(comptime-define-symbol 'stb-ds-defined))) |
|||
|
|||
(c-import &with-decls "stb_ds.h" |
|||
&with-defs "stb_ds.h") |
|||
|
|||
(comptime-cond |
|||
('auto-test |
|||
(c-import "stdio.h") |
|||
(defun test--dictionary (&return int) |
|||
(defstruct dictionary-entry |
|||
key (* char) |
|||
value (* (const char))) |
|||
(var my-dictionary (* dictionary-entry) null) |
|||
;; (sh_new_strdup my-dictionary) |
|||
(when (shgetp_null my-dictionary "Test") |
|||
(fprintf stderr "Expected not to get entry back\n") |
|||
(return 1)) |
|||
;; TODO Memory leak |
|||
(var my-entry dictionary-entry (array (strdup "cakelisp") "a programming language")) |
|||
(shputs my-dictionary my-entry) |
|||
(var returned-entry (* dictionary-entry) (shgetp_null my-dictionary "cakelisp")) |
|||
;; (unless (and returned-entry (path returned-entry > key) (path returned-entry > value)) |
|||
;; (fprintf stderr "Expected to get valid entry back\n") |
|||
;; (return 1)) |
|||
(fprintf stderr "what is %s? %s\n" |
|||
(path returned-entry > key) |
|||
(path returned-entry > value)) |
|||
(shfree my-dictionary) |
|||
(return 0)))) |
|||
|
|||
(add-c-search-directory-module "Dependencies/stb") |
|||
|
|||
(add-dependency-git-submodule clone-stb-headers-dictionary |
|||
"https://github.com/nothings/stb" |
|||
"Dependencies/stb") |
@ -0,0 +1,152 @@ |
|||
;; Dynamic array |
|||
;; See Dependencies/stb/stb_ds.h for how to use this |
|||
;; In short, (var my-dynarray (* thing) null) |
|||
;; ...then have at it. (dynarray-free my-dynarray) once you're done |
|||
;; |
|||
;; Note that almost all dynarray functions are macros which may change the array pointer passed in, |
|||
;; which means you need to pass (* (* type)) if you are going to let another function manipulate it |
|||
|
|||
(set-cakelisp-option cakelisp-src-dir "Dependencies/cakelisp/src") |
|||
|
|||
(add-cakelisp-search-directory "Dependencies/cakelisp/runtime") |
|||
(import &comptime-only "CHelpers.cake" "Dependencies.cake") |
|||
|
|||
;; TODO: Make this an "infect" to the importer rather than having to be global |
|||
(add-c-search-directory-global "Dependencies/stb") |
|||
;; TODO: Remove once importing this module no longer changes all compile commands |
|||
(add-build-config-label "STB") |
|||
|
|||
;; (add-c-search-directory-module "Dependencies/stb") |
|||
|
|||
(add-dependency-git-submodule clone-stb-headers-dynamic-array |
|||
"https://github.com/nothings/stb" |
|||
"Dependencies/stb") |
|||
|
|||
;; Enforce only defining the implemention once |
|||
(comptime-cond |
|||
('stb-ds-defined) |
|||
(true |
|||
(c-preprocessor-define STB_DS_IMPLEMENTATION) |
|||
(comptime-define-symbol 'stb-ds-defined))) |
|||
|
|||
(c-import &with-decls "stb_ds.h" |
|||
&with-defs "stb_ds.h" |
|||
;; For dynstring |
|||
"<stdarg.h>" "<stdio.h>") |
|||
|
|||
(def-c-function-alias dynarray-free arrfree) ;; (array (* T)) |
|||
|
|||
(def-c-function-alias dynarray-append arrput) ;; (array (* T) item T) |
|||
(def-c-function-alias dynarray-pop arrpop) ;; (array (* T) &return T) |
|||
(def-c-function-alias dynarray-insert arrins) ;; (array (* T) index int item T) |
|||
(def-c-function-alias dynarray-delete arrdel) ;; (array (* T) index int) |
|||
;; Delete array[index] and replace it with last item in array |
|||
(def-c-function-alias dynarray-delete-swap arrdelswap) ;; (array (* T) index int) |
|||
|
|||
(def-c-function-alias dynarray-length arrlenu) ;; (array (* T) &return size_t) |
|||
(def-c-function-alias dynarray-capacity arrcap) ;; (array (* T) &return size_t) |
|||
|
|||
(def-c-function-alias dynarray-set-length arrsetlen) ;; (array (* T)) |
|||
;; Make room but don't change the length, so you can push without resize |
|||
(def-c-function-alias dynarray-set-capacity arrsetcap) ;; (array (* T)) |
|||
|
|||
(defmacro each-in-dynarray (dynarray any iterator-name symbol &rest body any) |
|||
(tokenize-push output |
|||
(c-for |
|||
(var (token-splice iterator-name) size_t 0) |
|||
;; We could hoist this out but it should be a quick op anyways |
|||
(< (token-splice iterator-name) (dynarray-length (token-splice dynarray))) |
|||
(incr (token-splice iterator-name)) |
|||
(token-splice-rest body tokens))) |
|||
(return true)) |
|||
|
|||
;; Dynamic string |
|||
;; Helpers for creating auto-resizing strings |
|||
;; The underlying data structure is DynamicArray. Its functions may be used on the string |
|||
;; Note that dynstrings never shrink, and are sized to powers of two |
|||
|
|||
;; Use mainly for signaling you expect to be able to resize etc. the array |
|||
(def-type-alias-global dynstring (* char)) |
|||
|
|||
;; Returns the length of the string, not including the null terminator |
|||
(defun dynstring-printf (str (* dynstring) format (* (const char)) |
|||
&variable-arguments |
|||
&return int) |
|||
;; Start with something reasonable to work with |
|||
(unless (deref str) |
|||
(dynarray-set-capacity (deref str) 16)) |
|||
|
|||
(var num-chars-required int 0) |
|||
;; This will only run twice, thanks to vsnprintf returning the size needed |
|||
(while true |
|||
(var args va_list) |
|||
(va_start args format) |
|||
(set num-chars-required |
|||
(vsnprintf (deref str) (dynarray-capacity (deref str)) format args)) |
|||
(va_end args) |
|||
(if (>= num-chars-required (dynarray-capacity (deref str))) |
|||
;; Grow the string. +1 for null terminator |
|||
(dynarray-set-capacity (deref str) (+ 1 num-chars-required)) |
|||
;; Got the size right the first time (or a little over, oh well) |
|||
(break))) |
|||
|
|||
;; dynarray doesn't know we're printing to it, so we must update length header to match |
|||
;; We do include the null terminator in the array length |
|||
(dynarray-set-length (deref str) (+ 1 num-chars-required)) |
|||
(return num-chars-required)) |
|||
|
|||
;; dynarray-length includes the null terminator. This function removes it |
|||
(defun dynstring-strlen (str dynstring &return size_t) |
|||
(return (- (dynarray-length str) 1))) |
|||
|
|||
(comptime-cond |
|||
('auto-test |
|||
(c-import "stdio.h") |
|||
(defun test--dynamic-array (&return int) |
|||
(var my-dynarray (* int) null) |
|||
(dynarray-append my-dynarray 1) |
|||
(dynarray-append my-dynarray 2) |
|||
(dynarray-append my-dynarray 3) |
|||
(dynarray-append my-dynarray 4) |
|||
(dynarray-append my-dynarray 5) |
|||
(unless (and (= 5 (dynarray-length my-dynarray)) |
|||
(= 2 (at 1 my-dynarray))) |
|||
(return 1)) |
|||
(each-in-dynarray my-dynarray i (fprintf stderr "%d " (at i my-dynarray))) |
|||
|
|||
(fprintf stderr "\nPop:\n") |
|||
(dynarray-pop my-dynarray) |
|||
(each-in-dynarray my-dynarray i (fprintf stderr "%d " (at i my-dynarray))) |
|||
|
|||
(fprintf stderr "\nInsert:\n") |
|||
(dynarray-insert my-dynarray 1 3) |
|||
(each-in-dynarray my-dynarray i (fprintf stderr "%d " (at i my-dynarray))) |
|||
|
|||
(fprintf stderr "\nDelete:\n") |
|||
(dynarray-delete my-dynarray 1) |
|||
(each-in-dynarray my-dynarray i (fprintf stderr "%d " (at i my-dynarray))) |
|||
|
|||
(fprintf stderr "\nDelete swap:\n") |
|||
(dynarray-delete-swap my-dynarray 1) |
|||
(each-in-dynarray my-dynarray i (fprintf stderr "%d " (at i my-dynarray))) |
|||
|
|||
(fprintf stderr "\nCapacity after all that: %d\n" |
|||
(type-cast (dynarray-capacity my-dynarray) int)) |
|||
(dynarray-free my-dynarray) |
|||
(return 0)) |
|||
|
|||
(defun print-dynstring-details (str dynstring) |
|||
(fprintf stderr "dynstring: '%s'\n capacity: %d length: %d strlen: %d\n" |
|||
str |
|||
(type-cast (dynarray-capacity str) int) |
|||
(type-cast (dynarray-length str) int) |
|||
(type-cast (dynstring-strlen str) int))) |
|||
|
|||
(defun test--dynamic-string (&return int) |
|||
(var my-string dynstring null) |
|||
(dynstring-printf (addr my-string) "The answer is %d" 42) |
|||
(print-dynstring-details my-string) |
|||
(dynstring-printf (addr my-string) "Short %d" 42) |
|||
(print-dynstring-details my-string) |
|||
(dynarray-free my-string) |
|||
(return 0)))) |
Loading…
Reference in new issue