Browse Source

Added dynamic array, string, and dictionary

* These new classes are based on the STB data structures which are
  fully C-compatible
* Dictionary is still WIP
windows-imgui
Macoy Madson 7 months ago
parent
commit
f09dbb2e47
  1. 50
      src/Dictionary.cake
  2. 152
      src/DynamicArray.cake
  3. 11
      test/src/GameLibTests.cake

50
src/Dictionary.cake

@ -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")

152
src/DynamicArray.cake

@ -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))))

11
test/src/GameLibTests.cake

@ -37,12 +37,15 @@
(true
"src/Config_Linux.cake")))
(gamelib-run-test
"Auto Test"
(array platform-config
"../src/AutoTest.cake" "../src/SDL.cake" "../src/Math.cake"
"../src/Aubio.cake" "../src/ImGui.cake" "../src/Dictionary.cake"
"../src/DynamicArray.cake"))
(gamelib-run-test "Ogre" (array platform-config "src/OgreApp.cake"))
(gamelib-run-test "SDL Ogre" (array platform-config "src/SDLOgreApp.cake"))
(gamelib-run-test "Auto Test"
(array platform-config
"../src/AutoTest.cake" "../src/SDL.cake" "../src/Math.cake"
"../src/Aubio.cake" "../src/ImGui.cake" "../src/Dictionary.cake"))
(gamelib-build "Vocal Game (hot reload)"
(array platform-config "src/MakeHotReload.cake" "src/VocalGame.cake"))

Loading…
Cancel
Save