From ae4d57665bd82a4766a7a7e497776eee2fd47464 Mon Sep 17 00:00:00 2001 From: James Date: Tue, 23 Jan 2024 09:51:00 -0800 Subject: [PATCH 001/101] Add nine slice API --- src/playdate/api.nim | 4 +- src/playdate/nineslice.nim | 160 +++++++++++++++++++++++++++++++ tests/source/nineslice_27x3.png | Bin 0 -> 104 bytes tests/source/nineslice_60x60.png | Bin 0 -> 270 bytes tests/source/nineslice_6x6.png | Bin 0 -> 101 bytes tests/source/nineslice_9x9.png | Bin 0 -> 150 bytes tests/src/playdate_tests.nim | 4 +- tests/t_nineslice.nim | 124 ++++++++++++++++++++++++ 8 files changed, 288 insertions(+), 4 deletions(-) create mode 100644 src/playdate/nineslice.nim create mode 100644 tests/source/nineslice_27x3.png create mode 100644 tests/source/nineslice_60x60.png create mode 100644 tests/source/nineslice_6x6.png create mode 100644 tests/source/nineslice_9x9.png create mode 100644 tests/t_nineslice.nim diff --git a/src/playdate/api.nim b/src/playdate/api.nim index 984a644..82cd981 100644 --- a/src/playdate/api.nim +++ b/src/playdate/api.nim @@ -7,8 +7,8 @@ import bindings/utils {.all.} as memory import bindings/api export api -import graphics, system, file, sprite, display, sound, lua, json, utils, types -export graphics, system, file, sprite, display, sound, lua, json, utils, types +import graphics, system, file, sprite, display, sound, lua, json, utils, types, nineslice +export graphics, system, file, sprite, display, sound, lua, json, utils, types, nineslice macro initSDK*() = return quote do: diff --git a/src/playdate/nineslice.nim b/src/playdate/nineslice.nim new file mode 100644 index 0000000..ee1aad0 --- /dev/null +++ b/src/playdate/nineslice.nim @@ -0,0 +1,160 @@ +import graphics +import std/[importutils, bitops, math, strutils] + +privateAccess(BitmapData) +privateAccess(LCDBitmap) + +type + NineSliceRow {.byref.} = object + ## The bytes for a single row within a nine slice + leftBytes: seq[uint8] + middleBytes: seq[uint8] + rightBytes: seq[uint8] + leftRightBitLen: int + + NineSliceData = ref object + ## Stores the rows for a single nine slice bitmap + top: seq[NineSliceRow] + middle: seq[NineSliceRow] + bottom: seq[NineSliceRow] + + NineSlice* = ref object + ## A precalculated nine slice + image: NineSliceData + mask: NineSliceData + +func copyBits( + source: ptr UncheckedArray[uint8]; + target: var seq[uint8]; + sourceStartBit, sourceOffsetBit, sourceLen, targetStartBit, targetLen: int +) = + ## Copies a sequence of bits from the source to the target, where all bit positions are absolute relative to + ## the start of the source or target + let minLength = ceil((targetStartBit + targetLen) / 8).toInt + target.setLen(max(target.len, minLength)) + + for bit in 0..= 3) + assert(source.height >= 3) + return NineSlice( + image: createNineSliceData(source.getData), + mask: if source.getBitmapMask.resource == nil: nil else: createNineSliceData(source.getBitmapMask.getData) + ) + +func overlapBytes(left, right: uint8, offset: int): uint8 = + ## Given two bytes, creates a new byte that is partially made up of the left byte, and partially made up of + ## the right hand byte. The amount taken from each is determined by the `offset` + let leftContribution = left shl (8 - offset) + let rightContribution = right shr offset + result = leftContribution or rightContribution + +func drawRow(target: var BitmapData, source: NineSliceRow, targetY: int) = + ## Draws a single row to a nine slice. + let targetOffsetByte = target.rowbytes * targetY + + # Draw the left column, a byte at a time + for i, byteValue in source.leftBytes: + target.data[i + targetOffsetByte] = byteValue + + # Draw the stretched out middle column + let imageWidthInBytes = target.width div 8 + let middleBytesLen = imageWidthInBytes - (2 * (source.leftRightBitLen div 8)) + for i in 0..42!3HFg0!tPHDaPU;cPEB*=VV?2IZB=`jv*3L zlT#8Bew=q;`19XCfRkBSS=rIlhb1&X@WNFihLtN>SodGotN^NJ@O1TaS?83{1OTbT B8wmga literal 0 HcmV?d00001 diff --git a/tests/source/nineslice_60x60.png b/tests/source/nineslice_60x60.png new file mode 100644 index 0000000000000000000000000000000000000000..700b0b21d8bbb4f73ac329aaa18019083471d25c GIT binary patch literal 270 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw1|+Ti+$;i8jKx9jP7LeL$-D$|PI$UFhGaCp zon^?^Y#_k$Ug_We)a6`384VQ^=iHsy#T02C*TTDR-KxN-D4Tg(_DwI^P@nKSrpM5H z;@wvX`vb3vPd7O9PT>vTp?5jYx8HHwTRd54dcm9xeVHMfojo=&>3{3+1vBb=wL z8N%$RbbDL){phsQwR#lJ1l9DU-lnUxLigVK6S5snKDXL|eq!)+^>bP0l+XkKid1rO literal 0 HcmV?d00001 diff --git a/tests/source/nineslice_6x6.png b/tests/source/nineslice_6x6.png new file mode 100644 index 0000000000000000000000000000000000000000..c241f5b83bf2bc98d274c7a25a0cb4c2f2268a12 GIT binary patch literal 101 zcmeAS@N?(olHy`uVBq!ia0vp^Y#_`5A|IT2?*XJ3i-X*q7}lMWc?smmd%8G=aLn9$ w(vXpXfrD8g?f*IB#`SwxTDK{1O0@S!SoX1ScloXe1S)0lboFyt=akR{0DtTnNB{r; literal 0 HcmV?d00001 diff --git a/tests/source/nineslice_9x9.png b/tests/source/nineslice_9x9.png new file mode 100644 index 0000000000000000000000000000000000000000..6bfe6855fcc47b29a5989bd0dde0dfb870aa96f8 GIT binary patch literal 150 zcmeAS@N?(olHy`uVBq!ia0vp^oFL4>1|%O$WD@{VjKx9jP7LeL$-D$|0z6$DLnNlQ zPB7# Date: Sat, 10 Feb 2024 16:25:52 -0800 Subject: [PATCH 002/101] Rename setup build task It conflicts with a built in nimble task --- .github/actions/project-setup/action.yml | 17 +++++++++++++++++ .github/workflows/build.yml | 4 ++-- README.md | 2 +- src/playdate/build/nimble.nim | 2 +- 4 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 .github/actions/project-setup/action.yml diff --git a/.github/actions/project-setup/action.yml b/.github/actions/project-setup/action.yml new file mode 100644 index 0000000..e441e7e --- /dev/null +++ b/.github/actions/project-setup/action.yml @@ -0,0 +1,17 @@ +name: Common setup steps for a playdate nimble project +inputs: + working-directory: + required: true +runs: + using: "composite" + steps: + + - name: Nimble example setup + shell: bash + working-directory: ${{ inputs.working-directory }} + run: nimble configure; + + - name: Install dependencies + shell: bash + working-directory: ${{ inputs.working-directory }} + run: nimble install --depsOnly --accept \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2c81a3c..ecf2c30 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -30,7 +30,7 @@ jobs: run: | export PLAYDATE_SDK_PATH=$(readlink -f $(find PlaydateSDK-* -maxdepth 0 -type d)); cd playdate_example; - nimble setup; + nimble playdateSetup; - name: Install dependencies working-directory: ./playdate_example run: nimble install --depsOnly --accept @@ -87,7 +87,7 @@ jobs: run: | export PLAYDATE_SDK_PATH=$(readlink -f $(find PlaydateSDK-* -maxdepth 0 -type d)); cd tests; - nimble setup; + nimble playdateSetup; - name: Compile for simulator working-directory: ./tests diff --git a/README.md b/README.md index 9904204..caca804 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ echo 'include playdate/build/config' > config.nims; 4. Finally, run this command to setup the structure of the project, which prepares your application to be compiled and bundled correctly: ``` -nimble setup +nimble configure ``` ## Usage diff --git a/src/playdate/build/nimble.nim b/src/playdate/build/nimble.nim index 9864746..0887918 100644 --- a/src/playdate/build/nimble.nim +++ b/src/playdate/build/nimble.nim @@ -103,7 +103,7 @@ task all, "Build for both the simulator and the device": postBuild(Target.device) bundlePDX() -task setup, "Initialize the build structure": +task configure, "Initialize the build structure": ## Creates a default source directory if it doesn't already exist # Calling `sdkPath` will ensure the SDK environment variable is saved From 99d13020e3abc1a5cd56a44fb5e2bc820e7ee78d Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Sun, 11 Feb 2024 17:15:34 +0100 Subject: [PATCH 003/101] Print pdc version during PDX bundle creation --- src/playdate/build/nimble.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/playdate/build/nimble.nim b/src/playdate/build/nimble.nim index ba9443c..9864746 100644 --- a/src/playdate/build/nimble.nim +++ b/src/playdate/build/nimble.nim @@ -10,6 +10,8 @@ when not compiles(task): proc bundlePDX() = ## Bundles pdx file using parent directory name. + echo("pdc version:") + exec(pdcPath() & " --version") exec(pdcPath() & " --verbose -sdkpath " & sdkPath() & " source " & thisDir().splitPath.tail) From dd4c8fad612d18a0e50f8dffdfef8e86d32dd471 Mon Sep 17 00:00:00 2001 From: James Date: Sun, 11 Feb 2024 09:36:43 -0800 Subject: [PATCH 004/101] Update workflow playdate ini path The 2.3.0 SDK release moved the location of the simulator ini file to conform to XDG locations. This change updates the build to use the new location https://sdk.play.date/changelog/\#_2_3_0 --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 60fd8b2..2c81a3c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -98,7 +98,7 @@ jobs: # alert from showing in the first place - name: Create simulator ini run: | - export PD_INI_DIR="$HOME/.Playdate Simulator" + export PD_INI_DIR="$HOME/.config/Playdate Simulator" mkdir -p "$PD_INI_DIR" export PD_INI_FILE="$PD_INI_DIR/Playdate Simulator.ini" echo "ShowPerfWarning=0" > $PD_INI_FILE From f664dda53d3bbe304326abf8f46f7e6bdb17725e Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Thu, 15 Feb 2024 18:35:04 +0100 Subject: [PATCH 005/101] Add LCDBitmap.tileBitmap --- src/playdate/graphics.nim | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/playdate/graphics.nim b/src/playdate/graphics.nim index b058b06..f7df425 100644 --- a/src/playdate/graphics.nim +++ b/src/playdate/graphics.nim @@ -181,6 +181,10 @@ proc rotated*(this: LCDBitmap, rotation: float32, scale: float32): tuple[bitmap: LCDBitmap, allocatedSize: int] {.inline.} = return this.rotated(rotation, scale, scale) +proc tileBitmap*(this: LCDBitmap, x: int, y: int, width: int, height: int, flip: LCDBitmapFlip) = + privateAccess(PlaydateGraphics) + playdate.graphics.tileBitmap(this.resource, x.cint, y.cint, width.cint, height.cint, flip) + type LCDBitmapTableObj = object resource: LCDBitmapTablePtr proc `=destroy`(this: var LCDBitmapTableObj) = From 9aeb214a9e61c4de456b0dfe92edf7828fa35452 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Sat, 16 Mar 2024 17:42:41 +0100 Subject: [PATCH 006/101] Fix/align button state names, ignore IDEA files --- .gitignore | 3 +++ playdate_example/src/playdate_example.nim | 12 ++++++------ src/playdate/system.nim | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 4a0815f..637f30c 100644 --- a/.gitignore +++ b/.gitignore @@ -56,3 +56,6 @@ $RECYCLE.BIN/ tests/t_* !tests/t_*.* tests/playdate_tests + +# IntelliJ IDEA +.idea \ No newline at end of file diff --git a/playdate_example/src/playdate_example.nim b/playdate_example/src/playdate_example.nim index f343e6e..2b4c352 100644 --- a/playdate_example/src/playdate_example.nim +++ b/playdate_example/src/playdate_example.nim @@ -19,18 +19,18 @@ var y = int(LCD_ROWS / 2) + 32 proc update(): int = # playdate is the global PlaydateAPI instance, available when playdate/api is imported - let buttonsState = playdate.system.getButtonsState() + let buttonState = playdate.system.getButtonState() - if kButtonRight in buttonsState.current: + if kButtonRight in buttonState.current: x += 10 - if kButtonLeft in buttonsState.current: + if kButtonLeft in buttonState.current: x -= 10 - if kButtonUp in buttonsState.current: + if kButtonUp in buttonState.current: y -= 10 - if kButtonDown in buttonsState.current: + if kButtonDown in buttonState.current: y += 10 - if kButtonA in buttonsState.pushed: + if kButtonA in buttonState.pushed: samplePlayer.play(1, 1.0) let goalX = x.toFloat diff --git a/src/playdate/system.nim b/src/playdate/system.nim index b55fd34..6f22205 100644 --- a/src/playdate/system.nim +++ b/src/playdate/system.nim @@ -46,7 +46,7 @@ proc setUpdateCallback*(this: ptr PlaydateSys, update: PDCallbackFunction) = this.setUpdateCallback(privateUpdate, playdate) # --- -proc getButtonsState* (this: ptr PlaydateSys): tuple[current: PDButtons, pushed: PDButtons, released: PDButtons] = +proc getButtonState* (this: ptr PlaydateSys): tuple[current: PDButtons, pushed: PDButtons, released: PDButtons] = privateAccess(PlaydateSys) var current, pushed, released: uint32 this.getButtonState(cast[ptr PDButton](addr(current)), cast[ptr PDButton](addr(pushed)), cast[ptr PDButton](addr(released))) From 4e6b5d34e23812706e57d8d3883d7b0f497a1082 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Sat, 16 Mar 2024 17:44:35 +0100 Subject: [PATCH 007/101] Add file.exists() --- src/playdate/file.nim | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/playdate/file.nim b/src/playdate/file.nim index f842713..5c075a8 100644 --- a/src/playdate/file.nim +++ b/src/playdate/file.nim @@ -42,6 +42,12 @@ proc stat*(this: ptr PlaydateFile, path: string): FileStat {.raises: [IOError]} raise newException(IOError, $playdate.file.geterr()) return info +proc exists*(this: ptr PlaydateFile, path: string): bool = + privateAccess(PlaydateFile) + var info: FileStat = FileStat() + let res = this.stat(path.cstring, addr(info[])) + return res != 0 + proc unlink*(this: ptr PlaydateFile, path: string, recursive: bool) {.raises: [IOError]} = privateAccess(PlaydateFile) let res = this.unlink(path.cstring, if recursive: 1 else: 0) From 056df90d95f84cc28c5dd5ce248bafa668741fc7 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Sat, 16 Mar 2024 18:06:23 +0100 Subject: [PATCH 008/101] Change pdx name to use project folder name --- src/playdate/build/utils.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/playdate/build/utils.nim b/src/playdate/build/utils.nim index 6c3dc46..ba92eef 100644 --- a/src/playdate/build/utils.nim +++ b/src/playdate/build/utils.nim @@ -23,7 +23,7 @@ proc nimble*(args: varargs[string]) = proc pdxName*(): string = ## The name of the pdx file to generate - "playdate" & ".pdx" + projectDir() & ".pdx" proc sdkPath*(): string = ## Returns the path of the playdate SDK From b71b164dcc4d8fc6e033da31c3444c12cf9b6f0e Mon Sep 17 00:00:00 2001 From: James Date: Sun, 17 Mar 2024 10:38:47 -0700 Subject: [PATCH 009/101] Use playdate realloc for memory management Fixes #59 --- src/playdate/api.nim | 6 +-- src/playdate/bindings/graphics.nim | 15 ++++--- src/playdate/bindings/malloc.nim | 72 ++++++++++++++++++++++++++++++ src/playdate/bindings/system.nim | 3 +- src/playdate/bindings/utils.nim | 2 - src/playdate/build/config.nim | 31 +++++++++---- src/playdate/types.nim | 3 +- 7 files changed, 108 insertions(+), 24 deletions(-) create mode 100644 src/playdate/bindings/malloc.nim diff --git a/src/playdate/api.nim b/src/playdate/api.nim index 82cd981..80ad787 100644 --- a/src/playdate/api.nim +++ b/src/playdate/api.nim @@ -3,7 +3,6 @@ import macros import std/importutils -import bindings/utils {.all.} as memory import bindings/api export api @@ -17,9 +16,10 @@ macro initSDK*() = proc eventHandler(playdateAPI: ptr PlaydateAPI, event: PDSystemEvent, arg: uint32): cint {.cdecl, exportc.} = privateAccess(PlaydateSys) if event == kEventInit: + when declared(setupRealloc): + setupRealloc(playdateAPI.system.realloc) NimMain() api.playdate = playdateAPI - memory.realloc = playdateAPI.system.realloc handler(event, arg) return 0 @@ -50,4 +50,4 @@ when not defined(simulator) and defined(release): return 0 proc write(handle: cint, data: ptr cchar, size: cint): cint {.cdecl, exportc: "_write".} = - return -1 \ No newline at end of file + return -1 diff --git a/src/playdate/bindings/graphics.nim b/src/playdate/bindings/graphics.nim index 60abbe8..adb9262 100644 --- a/src/playdate/bindings/graphics.nim +++ b/src/playdate/bindings/graphics.nim @@ -73,8 +73,9 @@ type LCDBitmapTablePtr {.importc: "LCDBitmapTable*", header: "pd_api.h".} = poin type LCDFontPtr {.importc: "LCDFont*", header: "pd_api.h".} = pointer type LCDFontObj = object resource: LCDFontPtr -proc `=destroy`(this: var LCDFontObj) = - discard utils.realloc(this.resource, 0) + +proc `=destroy`(this: var LCDFontObj) = deallocImpl(this.resource) + type LCDFont* = ref LCDFontObj type LCDFontDataPtr {.importc: "LCDFontData*", header: "pd_api.h".} = object @@ -83,15 +84,17 @@ type LCDFontData* = LCDFontDataPtr type LCDFontPagePtr {.importc: "LCDFontPage*", header: "pd_api.h".} = pointer type LCDFontPageObj = object resource: LCDFontPagePtr -proc `=destroy`(this: var LCDFontPageObj) = - discard utils.realloc(this.resource, 0) + +proc `=destroy`(this: var LCDFontPageObj) = deallocImpl(this.resource) + type LCDFontPage* = ref LCDFontPageObj type LCDFontGlyphPtr {.importc: "LCDFontGlyph*", header: "pd_api.h".} = pointer type LCDFontGlyphObj = object resource: LCDFontGlyphPtr -proc `=destroy`(this: var LCDFontGlyphObj) = - discard utils.realloc(this.resource, 0) + +proc `=destroy`(this: var LCDFontGlyphObj) = deallocImpl(this.resource) + type LCDFontGlyph* = ref LCDFontGlyphObj type LCDVideoPlayerRaw {.importc: "LCDVideoPlayer", header: "pd_api.h".} = object diff --git a/src/playdate/bindings/malloc.nim b/src/playdate/bindings/malloc.nim new file mode 100644 index 0000000..02e786d --- /dev/null +++ b/src/playdate/bindings/malloc.nim @@ -0,0 +1,72 @@ +## +## This file is a re-implementation of malloc.nim in the Nim standard library.It allows Nim itself to use the +## memory allocators provided by the playdate SDK. +## +## It works by by patching it in as a replacement in your configs.nim file, like this: +## +## ```nim +## patchFile("stdlib", "malloc", nimblePlaydatePath / "src/playdate/bindings/malloc") +## ``` +## +## This patching is automatically configured when using `playdate/build/config`, as recommended by the setup +## documentation. +## + +{.push stackTrace: off.} + +when defined(memtrace): + import system/ansi_c + +type PDRealloc = proc (p: pointer; size: csize_t): pointer {.tags: [], raises: [], cdecl, gcsafe.} + +var pdrealloc: PDRealloc + +proc setupRealloc*(allocator: PDRealloc) = + when defined(memtrace): + cfprintf(cstderr, "Setting up playdate allocator") + pdrealloc = allocator + +proc allocImpl(size: Natural): pointer = + when defined(memtrace): + cfprintf(cstderr, "Allocating %d\n", size) + result = pdrealloc(nil, size.csize_t) + when defined(memtrace): + cfprintf(cstderr, " At %p\n", result) + +proc alloc0Impl(size: Natural): pointer = + result = allocImpl(size) + zeroMem(result, size) + +proc reallocImpl(p: pointer, newSize: Natural): pointer = + when defined(memtrace): + cfprintf(cstderr, "Reallocating %p with size %d\n", p, newSize) + return pdrealloc(p, newSize.csize_t) + +proc realloc0Impl(p: pointer, oldsize, newSize: Natural): pointer = + result = realloc(p, newSize.csize_t) + if newSize > oldSize: + zeroMem(cast[pointer](cast[uint](result) + uint(oldSize)), newSize - oldSize) + +proc deallocImpl(p: pointer) = + when defined(memtrace): + cfprintf(cstderr, "Freeing %p\n", p) + discard pdrealloc(p, 0) + +# The shared allocators map on the regular ones + +proc allocSharedImpl(size: Natural): pointer {.used.} = allocImpl(size) + +proc allocShared0Impl(size: Natural): pointer {.used.} = alloc0Impl(size) + +proc reallocSharedImpl(p: pointer, newSize: Natural): pointer {.used.} = reallocImpl(p, newSize) + +proc reallocShared0Impl(p: pointer, oldsize, newSize: Natural): pointer {.used.} = realloc0Impl(p, oldSize, newSize) + +proc deallocSharedImpl(p: pointer) {.used.} = deallocImpl(p) + +proc getOccupiedMem(): int {.used.} = discard +proc getFreeMem(): int {.used.} = discard +proc getTotalMem(): int {.used.} = discard +proc deallocOsPages() {.used.} = discard + +{.pop.} diff --git a/src/playdate/bindings/system.nim b/src/playdate/bindings/system.nim index e38e3fc..1f774d5 100644 --- a/src/playdate/bindings/system.nim +++ b/src/playdate/bindings/system.nim @@ -34,8 +34,7 @@ type PDMenuItemCallbackFunctionRaw {.importc: "PDMenuItemCallbackFunction", head # System sdktype: type PlaydateSys* {.importc: "const struct playdate_sys", header: "pd_api.h".} = object - realloc {.importc: "realloc".}: proc (`ptr`: pointer; size: csize_t): pointer {. - cdecl, raises: [].} + realloc {.importc: "realloc".}: proc (`ptr`: pointer; size: csize_t): pointer {.cdecl, raises: [], tags: [], gcsafe.} formatString {.importc: "formatString".}: proc (ret: cstringArray; fmt: cstring): cint {. cdecl, varargs, raises: [].} logToConsole {.importc: "logToConsole".}: proc (fmt: cstring) {.cdecl, varargs, raises: [].} diff --git a/src/playdate/bindings/utils.nim b/src/playdate/bindings/utils.nim index 43df1b8..f2cb4ce 100644 --- a/src/playdate/bindings/utils.nim +++ b/src/playdate/bindings/utils.nim @@ -1,7 +1,5 @@ import macros -var realloc*: proc(p: pointer, size: csize_t): pointer {.cdecl.} - func toNimSymbol(typeSymbol: string): string = case typeSymbol: of "cint": diff --git a/src/playdate/build/config.nim b/src/playdate/build/config.nim index 865513a..4940af2 100644 --- a/src/playdate/build/config.nim +++ b/src/playdate/build/config.nim @@ -1,4 +1,5 @@ -import os +import os, strutils + when defined(device): import strformat @@ -13,6 +14,16 @@ const headlessTesting = defined(simulator) and declared(test) const nimbleTesting = not defined(simulator) and not defined(devide) and declared(test) const testing = headlessTesting or nimbleTesting +# Path to the playdate src directory when checked out locally +const localPlaydatePath = currentSourcePath / "../../../../src" + +# The path to the nimble playdate package +let nimblePlaydatePath = + if dirExists(localPlaydatePath / "playdate"): + localPlaydatePath + else: + gorgeEx("nimble path playdate").output.split("\n")[0] + if not testing: switch("noMain", "on") switch("backend", "c") @@ -34,8 +45,12 @@ switch("passC", "-Wno-unknown-pragmas") switch("passC", "-Wdouble-promotion") switch("passC", "-I" & sdkPath() / "C_API") +switch("os", "any") +switch("define", "useMalloc") +switch("define", "standalone") +switch("threads", "off") + when defined(device): - switch("os", "any") switch("gcc.options.always", "") switch("nimcache", nimcacheDir() / "device") @@ -43,11 +58,8 @@ when defined(device): switch("app", "console") switch("cpu", "arm") switch("checks", "off") - switch("threads", "off") switch("assertions", "off") switch("hotCodeReloading", "off") - switch("define", "useMalloc") - switch("define", "standalone") let heapSize = 8388208 let stackSize = 61800 @@ -114,8 +126,6 @@ when defined(simulator): switch("opt", "none") switch("define", "debug") - switch("define", "nimAllocPagesViaMalloc") - switch("define", "nimPage256") switch("passC", "-DTARGET_SIMULATOR=1") switch("passC", "-Wstrict-prototypes") @@ -154,8 +164,11 @@ if nimbleTesting: switch("passC", "-DTARGET_SIMULATOR=1") switch("passC", "-Wstrict-prototypes") else: - # Add extra files to compile last, so that + # Add extra files to compile last, so that # they get compiled in the correct nimcache folder. # Windows doesn't like having setup.c compiled. if defined(device) or not defined(windows): - switch("compile", sdkPath() / "C_API" / "buildsupport" / "setup.c") \ No newline at end of file + switch("compile", sdkPath() / "C_API" / "buildsupport" / "setup.c") + + # Overrides the nim memory management code to ensure it uses the playdate allocator + patchFile("stdlib", "malloc", nimblePlaydatePath / "playdate/bindings/malloc") \ No newline at end of file diff --git a/src/playdate/types.nim b/src/playdate/types.nim index dc36ee3..2d9db5f 100644 --- a/src/playdate/types.nim +++ b/src/playdate/types.nim @@ -1,4 +1,3 @@ -import bindings/utils type SDKArrayObj[T] = object len: int @@ -7,7 +6,7 @@ type SDKArray*[T] = ref SDKArrayObj[T] proc `=destroy`*[T](this: var SDKArrayObj[T]) = if this.data != nil: - discard utils.realloc(this.data, 0) + deallocImpl(this.data) proc `[]`*[T](this: SDKArray[T]; i: Natural): lent T = assert i < this.len From fb78c12089e1a80289e41c5886c9aa1d1ac87a11 Mon Sep 17 00:00:00 2001 From: Nycto Date: Tue, 19 Mar 2024 18:43:17 -0700 Subject: [PATCH 010/101] Use 'before' for running clean task This allows the default clean task to run, while adding custom behavior specifically for playdate cleaning --- src/playdate/build/nimble.nim | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/playdate/build/nimble.nim b/src/playdate/build/nimble.nim index 0887918..422e461 100644 --- a/src/playdate/build/nimble.nim +++ b/src/playdate/build/nimble.nim @@ -34,8 +34,7 @@ proc postBuild(target: Target) = mvFile(projectName(), "source" / "pdex.elf") rmFile("game.map") - -task clean, "Clean the project files and folders": +before clean: let args = taskArgs("clean") # Used to remove debug (_d) and release (_r) cache folders. let baseCacheDir = nimcacheDir()[0..^2] From 44e663dc415eb876a1c9c54dc109a28e9b8365ba Mon Sep 17 00:00:00 2001 From: Nycto Date: Tue, 19 Mar 2024 18:55:20 -0700 Subject: [PATCH 011/101] Abstract out shared workflow logic --- .github/actions/build-setup/action.yml | 34 +++++++++ .github/workflows/build.yml | 102 ++++++++----------------- 2 files changed, 64 insertions(+), 72 deletions(-) create mode 100644 .github/actions/build-setup/action.yml diff --git a/.github/actions/build-setup/action.yml b/.github/actions/build-setup/action.yml new file mode 100644 index 0000000..09f54e9 --- /dev/null +++ b/.github/actions/build-setup/action.yml @@ -0,0 +1,34 @@ +name: Common build setup +runs: + using: "composite" + steps: + + - name: Git safe directory + shell: bash + run: git config --global --add safe.directory "$(pwd)" + + # Some of the apt dependencies require input from the installer. This disables those + # prompts so we can do a headless install + - name: Force non-interactive apt installations + shell: bash + run: echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections + + - name: Update Apt dependencies + shell: bash + run: apt-get update + + - name: Install apt dependencies + shell: bash + run: apt-get install -y libpng16-16 gcc-arm-none-eabi wget + + - name: Download playdate SDK + shell: bash + run: wget -qO- https://download.panic.com/playdate_sdk/linux/playdatesdk-latest.tar.gz | tar xvz + + - name: Set PLAYDATE_SDK_PATH + shell: bash + run: echo "PLAYDATE_SDK_PATH=$(readlink -f $(find PlaydateSDK-* -maxdepth 0 -type d))" >> "$GITHUB_ENV" + + - name: Locally publish playdate nimble package + shell: bash + run: nimble develop \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ecf2c30..90ed24a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,63 +1,46 @@ name: Build on: [push, pull_request] jobs: - build: + + example-project: runs-on: ubuntu-latest container: nimlang/nim + strategy: + matrix: + target: [ device, simulator ] steps: - - # Some of the apt dependencies require input from the installer. This disables those - # prompts so we can do a headless install - - name: Force non-interactive apt installations - run: echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections - - - name: Update dependencies - run: apt-get update - - name: Install dependencies - run: apt-get install -y libpng16-16 gcc-arm-none-eabi - - uses: actions/checkout@v1 - - name: Download playdate SDK - run: wget https://download.panic.com/playdate_sdk/Linux/PlaydateSDK-latest.tar.gz - - name: Extract playdate SDK - run: tar -xvzf PlaydateSDK-latest.tar.gz - - name: Local publish playdate - run: nimble develop - - name: Tests - run: | - export PLAYDATE_SDK_PATH=$(readlink -f $(find PlaydateSDK-* -maxdepth 0 -type d)); - nimble test; - - name: Setup - run: | - export PLAYDATE_SDK_PATH=$(readlink -f $(find PlaydateSDK-* -maxdepth 0 -type d)); - cd playdate_example; - nimble playdateSetup; - - name: Install dependencies - working-directory: ./playdate_example - run: nimble install --depsOnly --accept - - name: Simulator - working-directory: ./playdate_example - run: nimble simulator - - name: Device + - uses: actions/checkout@v3 + - uses: ./.github/actions/build-setup + - uses: ./.github/actions/project-setup + with: + working-directory: ./playdate_example + - run: nimble ${{ matrix.target }} working-directory: ./playdate_example - run: nimble device - simulate: + tests: + runs-on: ubuntu-latest + container: nimlang/nim + steps: + - uses: actions/checkout@v3 + - uses: ./.github/actions/build-setup + - run: nimble test + + headless-tests: runs-on: ubuntu-latest timeout-minutes: 5 container: nimlang/nim - env: - HOME: /config steps: - # Some of the apt dependencies require input from the installer. This disables those - # prompts so we can do a headless install - - name: Force non-interactive apt installations - run: echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections + - uses: actions/checkout@v3 + + - uses: ./.github/actions/build-setup + + - uses: ./.github/actions/project-setup + with: + working-directory: ./tests - - name: Update dependencies - run: apt-get update - name: Install dependencies - run: apt-get install -y libpng16-16 gcc-arm-none-eabi xvfb libgtk-3-0 sudo libwebkit2gtk-4.0 libwebkit2gtk-4.0-dev libsdl2-dev pulseaudio + run: apt-get install -y xvfb libgtk-3-0 sudo libwebkit2gtk-4.0 libwebkit2gtk-4.0-dev libsdl2-dev pulseaudio # Because we are headless there is no audio driver to interact with by default, which causes a set # of warnings to be emitted. This set of commands sets up a dummy audio sink that silences those warnings. @@ -66,32 +49,8 @@ jobs: pulseaudio -D --exit-idle-time=-1 pactl load-module module-null-sink sink_name=SpeakerOutput sink_properties=device.description="Dummy_Output" - - name: Checkout commit - uses: actions/checkout@v1 - - - name: Download playdate SDK - run: wget https://download.panic.com/playdate_sdk/Linux/PlaydateSDK-latest.tar.gz - - name: Extract playdate SDK - run: tar -xvzf PlaydateSDK-latest.tar.gz - - - name: Local publish playdate - run: nimble develop - - - name: Install dependencies - working-directory: ./tests - run: nimble install --depsOnly --accept - - # The tests need to be told where the SDK is. Running `setup` with the SDK path configured - # will fill that in - - name: Setup tests - run: | - export PLAYDATE_SDK_PATH=$(readlink -f $(find PlaydateSDK-* -maxdepth 0 -type d)); - cd tests; - nimble playdateSetup; - - - name: Compile for simulator + - run: nimble simulator working-directory: ./tests - run: nimble simulator # The first time the simulator runs, it prompts the user with an alert. Obviously, we're running headless, # so this prevents the tests from running without closing that alert. Creating this ini file will stop that @@ -105,6 +64,5 @@ jobs: echo "ShowElist=0" >> $PD_INI_FILE echo "LastRelease=$(cat PlaydateSDK-*/VERSION.txt)" >> $PD_INI_FILE - - name: Run headless test + - run: xvfb-run ../PlaydateSDK-*/bin/PlaydateSimulator tests.pdx working-directory: ./tests - run: xvfb-run ../PlaydateSDK-*/bin/PlaydateSimulator tests.pdx From d6dff6e91e8937bf5722582476fd61c537f56acc Mon Sep 17 00:00:00 2001 From: Nycto Date: Tue, 19 Mar 2024 19:23:40 -0700 Subject: [PATCH 012/101] Nim 2 support Fixes #17 --- .github/actions/build-setup/action.yml | 22 +++++++++++++++++---- .github/workflows/build.yml | 27 +++++++++++++++++++++----- README.md | 2 +- playdate_example/nimble.develop | 7 +++++++ tests/nimble.develop | 7 +++++++ 5 files changed, 55 insertions(+), 10 deletions(-) create mode 100644 playdate_example/nimble.develop create mode 100644 tests/nimble.develop diff --git a/.github/actions/build-setup/action.yml b/.github/actions/build-setup/action.yml index 09f54e9..f6453b9 100644 --- a/.github/actions/build-setup/action.yml +++ b/.github/actions/build-setup/action.yml @@ -1,4 +1,7 @@ name: Common build setup +inputs: + nim-version: + required: true runs: using: "composite" steps: @@ -7,6 +10,21 @@ runs: shell: bash run: git config --global --add safe.directory "$(pwd)" + - name: Install Nim + shell: bash + run: choosenim -y update ${{ inputs.nim-version }} + + - run: nimble --accept refresh + shell: bash + + - run: nimble install + shell: bash + + - name: Locally publish playdate nimble package + shell: bash + if: ${{ startsWith(inputs.nim-version, '1.') }} + run: nimble develop + # Some of the apt dependencies require input from the installer. This disables those # prompts so we can do a headless install - name: Force non-interactive apt installations @@ -28,7 +46,3 @@ runs: - name: Set PLAYDATE_SDK_PATH shell: bash run: echo "PLAYDATE_SDK_PATH=$(readlink -f $(find PlaydateSDK-* -maxdepth 0 -type d))" >> "$GITHUB_ENV" - - - name: Locally publish playdate nimble package - shell: bash - run: nimble develop \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 90ed24a..2aac1c5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,13 +4,16 @@ jobs: example-project: runs-on: ubuntu-latest - container: nimlang/nim + container: nimlang/choosenim strategy: matrix: target: [ device, simulator ] + nim-version: [ 1.6.16, 2.0.2 ] steps: - uses: actions/checkout@v3 - uses: ./.github/actions/build-setup + with: + nim-version: ${{ matrix.nim-version }} - uses: ./.github/actions/project-setup with: working-directory: ./playdate_example @@ -19,21 +22,31 @@ jobs: tests: runs-on: ubuntu-latest - container: nimlang/nim + container: nimlang/choosenim + strategy: + matrix: + nim-version: [ 1.6.16, 2.0.2 ] steps: - uses: actions/checkout@v3 - uses: ./.github/actions/build-setup + with: + nim-version: ${{ matrix.nim-version }} - run: nimble test headless-tests: runs-on: ubuntu-latest timeout-minutes: 5 - container: nimlang/nim + container: nimlang/choosenim + strategy: + matrix: + nim-version: [ 1.6.16, 2.0.2 ] steps: - uses: actions/checkout@v3 - uses: ./.github/actions/build-setup + with: + nim-version: ${{ matrix.nim-version }} - uses: ./.github/actions/project-setup with: @@ -46,6 +59,7 @@ jobs: # of warnings to be emitted. This set of commands sets up a dummy audio sink that silences those warnings. - name: Setup audio sink run: | + export HOME="/config" pulseaudio -D --exit-idle-time=-1 pactl load-module module-null-sink sink_name=SpeakerOutput sink_properties=device.description="Dummy_Output" @@ -57,12 +71,15 @@ jobs: # alert from showing in the first place - name: Create simulator ini run: | - export PD_INI_DIR="$HOME/.config/Playdate Simulator" + export PD_INI_DIR="/config/.config/Playdate Simulator" mkdir -p "$PD_INI_DIR" export PD_INI_FILE="$PD_INI_DIR/Playdate Simulator.ini" echo "ShowPerfWarning=0" > $PD_INI_FILE echo "ShowElist=0" >> $PD_INI_FILE echo "LastRelease=$(cat PlaydateSDK-*/VERSION.txt)" >> $PD_INI_FILE - - run: xvfb-run ../PlaydateSDK-*/bin/PlaydateSimulator tests.pdx + - name: Run headless test working-directory: ./tests + run: | + export HOME="/config" + xvfb-run ../PlaydateSDK-*/bin/PlaydateSimulator tests.pdx \ No newline at end of file diff --git a/README.md b/README.md index caca804..37411c2 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ This package is an independent bindings library, not affiliated with Panic. ### Prerequisites - Playdate SDK -- Nim 1.6.10+ (check with `nim -v`, untested with 2.0+) ([recommended extension for VSCode](https://marketplace.visualstudio.com/items?itemName=nimsaem.nimvscode)) +- Nim 1.6.10+ or Nim 2+ ([recommended extension for VSCode](https://marketplace.visualstudio.com/items?itemName=nimsaem.nimvscode)) - Nimble 0.13.1 (check with `nimble -v`) - `PLAYDATE_SDK_PATH` environment variable - [SDK Prerequisites](https://sdk.play.date/Inside%20Playdate%20with%20C.html#_prerequisites) based on OS, and [MinGW on Windows](https://code.visualstudio.com/docs/cpp/config-mingw). diff --git a/playdate_example/nimble.develop b/playdate_example/nimble.develop new file mode 100644 index 0000000..49def8e --- /dev/null +++ b/playdate_example/nimble.develop @@ -0,0 +1,7 @@ +{ + "version": 1, + "includes": [], + "dependencies": [ + ".." + ] +} diff --git a/tests/nimble.develop b/tests/nimble.develop new file mode 100644 index 0000000..49def8e --- /dev/null +++ b/tests/nimble.develop @@ -0,0 +1,7 @@ +{ + "version": 1, + "includes": [], + "dependencies": [ + ".." + ] +} From c5ef811a76122e152b44951fb423af27c19abad2 Mon Sep 17 00:00:00 2001 From: James Date: Wed, 20 Mar 2024 05:12:19 -0700 Subject: [PATCH 013/101] Various files API improvements * Add file tests, fix file exists, fix write length 0 * Centralize file error handling * Add proc for writing a string --- src/playdate/file.nim | 89 +++++++++++++++--------------------- tests/src/playdate_tests.nim | 3 +- tests/t_files.nim | 51 +++++++++++++++++++++ 3 files changed, 90 insertions(+), 53 deletions(-) create mode 100644 tests/t_files.nim diff --git a/src/playdate/file.nim b/src/playdate/file.nim index 5c075a8..4d0cf74 100644 --- a/src/playdate/file.nim +++ b/src/playdate/file.nim @@ -15,7 +15,19 @@ type SDFileObj {.requiresinit.} = object resource: SDFilePtr path: string - SDFile* = ref SDFileObj + SDFile* = ref SDFileObj + +proc requireValidStatus(res: SomeInteger): int {.raises: [IOError], discardable.} = + privateAccess(PlaydateFile) + if res < 0: + raise newException(IOError, $playdate.file.geterr()) + return res.int + +proc requireNotNil[T: pointer](res: T): T {.raises: [IOError].} = + privateAccess(PlaydateFile) + if res == nil: + raise newException(IOError, $playdate.file.geterr()) + return res proc `=destroy`(this: var SDFileObj) = privateAccess(PlaydateFile) @@ -29,105 +41,78 @@ proc fileCallback(filename: ConstChar, userdata: pointer) {.cdecl.} = proc listFiles*(this: ptr PlaydateFile, path: string, showHidden: bool = false): seq[string] {.raises: [IOError]} = privateAccess(PlaydateFile) var files = newSeq[string]() - var res = this.listfiles(toC(path.cstring), fileCallback, addr(files), if showHidden: 1 else: 0) - if res != 0: - raise newException(IOError, $playdate.file.geterr()) + this.listfiles(toC(path.cstring), fileCallback, addr(files), if showHidden: 1 else: 0).requireValidStatus return files proc stat*(this: ptr PlaydateFile, path: string): FileStat {.raises: [IOError]} = privateAccess(PlaydateFile) var info: FileStat = FileStat() - let res = this.stat(path.cstring, addr(info[])) - if res != 0: - raise newException(IOError, $playdate.file.geterr()) + this.stat(path.cstring, addr(info[])).requireValidStatus return info proc exists*(this: ptr PlaydateFile, path: string): bool = privateAccess(PlaydateFile) - var info: FileStat = FileStat() - let res = this.stat(path.cstring, addr(info[])) - return res != 0 + var info: FileStatRaw + return this.stat(path.cstring, addr(info)) == 0 proc unlink*(this: ptr PlaydateFile, path: string, recursive: bool) {.raises: [IOError]} = privateAccess(PlaydateFile) - let res = this.unlink(path.cstring, if recursive: 1 else: 0) - if res != 0: - raise newException(IOError, $playdate.file.geterr()) + this.unlink(path.cstring, if recursive: 1 else: 0).requireValidStatus proc mkdir*(this: ptr PlaydateFile, path: string) {.raises: [IOError]} = privateAccess(PlaydateFile) - let res = this.mkdir(path.cstring) - if res != 0: - raise newException(IOError, $playdate.file.geterr()) + this.mkdir(path.cstring).requireValidStatus proc rename*(this: ptr PlaydateFile, fromName: string, to: string) {.raises: [IOError]} = privateAccess(PlaydateFile) - let res = this.rename(fromName.cstring, to.cstring) - if res != 0: - raise newException(IOError, $playdate.file.geterr()) + this.rename(fromName.cstring, to.cstring).requireValidStatus proc close*(this: SDFile) {.raises: [IOError]} = privateAccess(PlaydateFile) - let res = playdate.file.close(this.resource) - if res != 0: - raise newException(IOError, $playdate.file.geterr()) + discard playdate.file.close(this.resource).requireValidStatus -proc flush*(this: SDFile): int {.raises: [IOError]} = +proc flush*(this: SDFile): int {.raises: [IOError], discardable} = privateAccess(PlaydateFile) - let res = playdate.file.flush(this.resource) - if res < 0: - raise newException(IOError, $playdate.file.geterr()) - return res + return playdate.file.flush(this.resource).requireValidStatus proc open*(this: ptr PlaydateFile, path: string, mode: FileOptions): SDFile {.raises: [IOError]} = privateAccess(PlaydateFile) - let res = this.open(path.cstring, mode) - if res == nil: - raise newException(IOError, $playdate.file.geterr()) - return SDFile(resource: res, path: path) + return SDFile(resource: this.open(path.cstring, mode).requireNotNil, path: path) proc read*(this: SDFile, length: uint): tuple[bytes: seq[byte], length: int] {.raises: [IOError]} = privateAccess(PlaydateFile) var buffer = newSeq[byte](length) - let res = playdate.file.read(this.resource, addr(buffer[0]), length.cuint) - if res < 0: - raise newException(IOError, $playdate.file.geterr()) + let res = playdate.file.read(this.resource, addr(buffer[0]), length.cuint).requireValidStatus return (bytes: buffer, length: res.int) proc read*(this: SDFile): seq[byte] {.raises: [IOError]} = let size = playdate.file.stat(this.path).size privateAccess(PlaydateFile) var buffer = newSeq[byte](size) - let res = playdate.file.read(this.resource, addr(buffer[0]), size.cuint) - if res < 0: - raise newException(IOError, $playdate.file.geterr()) + playdate.file.read(this.resource, addr(buffer[0]), size.cuint).requireValidStatus return buffer proc readString*(this: SDFile): string {.raises: [IOError].} = let size = playdate.file.stat(this.path).size privateAccess(PlaydateFile) var str = newString(size) - let res = playdate.file.read(this.resource, addr(str[0]), size.cuint) - if res < 0: - raise newException(IOError, $playdate.file.geterr()) + playdate.file.read(this.resource, addr(str[0]), size.cuint).requireValidStatus return str proc seek*(this: SDFile, pos: int, whence: int) {.raises: [IOError]} = privateAccess(PlaydateFile) - let res = playdate.file.seek(this.resource, pos.cint, whence.cint) - if res != 0: - raise newException(IOError, $playdate.file.geterr()) + playdate.file.seek(this.resource, pos.cint, whence.cint).requireValidStatus proc tell*(this: SDFile): int {.raises: [IOError]} = privateAccess(PlaydateFile) - let res = playdate.file.tell(this.resource) - if res < 0: - raise newException(IOError, $playdate.file.geterr()) - return res + return playdate.file.tell(this.resource).requireValidStatus -proc write*(this: SDFile, buffer: seq[byte], length: uint): int {.raises: [IOError]} = +proc write*(this: SDFile, buffer: seq[byte], length: uint): int {.raises: [IOError], discardable} = privateAccess(PlaydateFile) - let res = playdate.file.write(this.resource, unsafeAddr(buffer[0]), length.cuint) - if res < 0: - raise newException(IOError, $playdate.file.geterr()) - return res \ No newline at end of file + if length > 0: + return playdate.file.write(this.resource, unsafeAddr(buffer[0]), length.cuint).requireValidStatus + +proc write*(this: SDFile, content: string): int {.raises: [IOError], discardable} = + privateAccess(PlaydateFile) + if content.len > 0: + return playdate.file.write(this.resource, unsafeAddr(content[0]), content.len.cuint).requireValidStatus diff --git a/tests/src/playdate_tests.nim b/tests/src/playdate_tests.nim index 107cc07..1a7ecfa 100644 --- a/tests/src/playdate_tests.nim +++ b/tests/src/playdate_tests.nim @@ -5,13 +5,14 @@ ## import playdate/api -import ../[t_buttons, t_graphics, t_nineslice] +import ../[t_buttons, t_graphics, t_nineslice, t_files] proc runTests() {.raises: [].} = try: execButtonsTests() execGraphicsTests(true) execNineSliceTests(true) + execFilesTest() except Exception as e: quit(e.msg & "\n" & e.getStackTrace) diff --git a/tests/t_files.nim b/tests/t_files.nim new file mode 100644 index 0000000..3d4a410 --- /dev/null +++ b/tests/t_files.nim @@ -0,0 +1,51 @@ +import unittest, playdate/api + +proc createFile(name: string, body: string = "") = + var handle = playdate.file.open(name, kFileWrite) + check(handle.write(cast[seq[byte]](body), body.len.uint) >= 0) + +proc execFilesTest*() = + suite "File loading": + test "Writing and reading files": + createFile("test_data.txt", "foo") + var handle = playdate.file.open("test_data.txt", kFileReadData) + check(handle.readString() == "foo") + + test "Writing strings to files": + block: + playdate.file.open("test_data.txt", kFileWrite).write("file content") + check(playdate.file.open("test_data.txt", kFileReadData).readString() == "file content") + + test "Listing files": + createFile("list_files.txt") + check("list_files.txt" in playdate.file.listFiles("/")) + + test "Stating missing file": + expect IOError: + discard playdate.file.stat("not_real.txt") + + test "Stating existing file": + createFile("stat_file.txt", "some content") + let stat = playdate.file.stat("stat_file.txt") + check(stat.isdir == 0) + check(stat.size == 12) + + test "Checking if files exists": + check(playdate.file.exists("not_a_file.txt") == false) + + createFile("real_file.txt") + check(playdate.file.exists("real_file.txt")) + + test "Unlinking files": + createFile("delete_me.txt") + playdate.file.unlink("delete_me.txt", false) + check(playdate.file.exists("delete_me.txt") == false) + + test "mkdir": + playdate.file.mkdir("my_dir") + check(playdate.file.stat("my_dir").isdir == 1) + + test "Renaming file": + createFile("original_file.txt") + playdate.file.rename("original_file.txt", "renamed_file.txt") + check(playdate.file.exists("renamed_file.txt")) \ No newline at end of file From 44898f0f026ed6871e78701e5e3cd7c11aef337a Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Sun, 7 Apr 2024 12:54:23 +0200 Subject: [PATCH 014/101] Add finishCallback to SamplePlayer --- src/playdate/bindings/sound.nim | 18 ++++++++----- src/playdate/sound.nim | 46 ++++++++++++++++++++++++++++++--- 2 files changed, 53 insertions(+), 11 deletions(-) diff --git a/src/playdate/bindings/sound.nim b/src/playdate/bindings/sound.nim index 6b28d57..d6a8c12 100644 --- a/src/playdate/bindings/sound.nim +++ b/src/playdate/bindings/sound.nim @@ -5,6 +5,10 @@ import utils type FilePlayerPtr = pointer type AudioSamplePtr = pointer type SamplePlayerPtr = pointer +type SoundSourcePtr = pointer + +type PDSndCallbackProcRaw {.importc: "sndCallbackProc", header: "pd_api.h".} = proc(soundSource: SoundSourcePtr, userData: pointer): void {.cdecl.} + type PlaydateSoundFileplayer {.importc: "const struct playdate_sound_fileplayer", header: "pd_api.h", bycopy.} = object @@ -79,15 +83,15 @@ type PlaydateSoundSampleplayer {.importc: "const struct playdate_sound_samplepla getLength {.importc: "getLength".}: proc (player: SamplePlayerPtr): cfloat {.cdecl, raises: [].} setRate {.importc: "setRate".}: proc (player: SamplePlayerPtr; rate: cfloat) {.cdecl, raises: [].} getRate {.importc: "getRate".}: proc (player: SamplePlayerPtr): cfloat {.cdecl, raises: [].} - # setOffset* {.importc: "setOffset".}: proc (player: SamplePlayerPtr; offset: cfloat) {. - # cdecl.} - # setPlayRange* {.importc: "setPlayRange".}: proc (player: ptr SamplePlayer; - # start: cint; `end`: cint) {.cdecl.} - # setFinishCallback* {.importc: "setFinishCallback".}: proc ( - # player: ptr SamplePlayer; callback: SndCallbackProc) {.cdecl.} + setPlayRange* {.importc: "setPlayRange".}: proc (player: SamplePlayerPtr; + start: cint; `end`: cint) {.cdecl, raises: [].} + setFinishCallback* {.importc: "setFinishCallback".}: proc ( + player: SamplePlayerPtr; callback: PDSndCallbackProcRaw, userData: pointer = nil) {.cdecl, raises: [].} # setLoopCallback* {.importc: "setLoopCallback".}: proc (player: ptr SamplePlayer; # callback: SndCallbackProc) {.cdecl.} - # getOffset* {.importc: "getOffset".}: proc (player: ptr SamplePlayer): cfloat {.cdecl.} + getOffset* {.importc: "getOffset".}: proc (player: SamplePlayerPtr): cfloat {.cdecl , raises: [].} + setOffset {.importc: "setOffset".}: proc (player: SamplePlayerPtr; offset: cfloat) {. + cdecl, raises: [].} setPaused {.importc: "setPaused".}: proc (player: SamplePlayerPtr; flag: cint) {. cdecl, raises: [].} # type PlaydateSoundSampleplayer* = ptr PlaydateSoundSampleplayerRaw diff --git a/src/playdate/sound.nim b/src/playdate/sound.nim index 26dfba9..4aa5607 100644 --- a/src/playdate/sound.nim +++ b/src/playdate/sound.nim @@ -16,6 +16,8 @@ type resource: AudioSamplePtr AudioSample* = ref AudioSampleObj + PDSoundCallbackFunction* = proc(userData: pointer) {.raises: [].} + proc `=destroy`(this: var AudioSampleObj) = privateAccess(PlaydateSound) privateAccess(PlaydateSoundSample) @@ -47,6 +49,7 @@ proc getLength*(this: AudioSample): float32 = # AudioSource type SoundSourceObj {.requiresinit.} = object of RootObj resource: pointer + callback: PDSoundCallbackFunction type SoundSource* = ref SoundSourceObj # FilePlayer @@ -62,12 +65,12 @@ proc `=destroy`(this: var FilePlayerObj) = proc newFilePlayer*(this: ptr PlaydateSound): FilePlayer = privateAccess(PlaydateSound) privateAccess(PlaydateSoundFileplayer) - result = FilePlayer(resource: this.fileplayer.newPlayer()) + result = FilePlayer(resource: this.fileplayer.newPlayer(), callback: nil) proc newFilePlayer*(this: ptr PlaydateSound, path: string): FilePlayer {.raises: [IOError].} = privateAccess(PlaydateSound) privateAccess(PlaydateSoundFileplayer) - result = FilePlayer(resource: this.fileplayer.newPlayer()) + result = FilePlayer(resource: this.fileplayer.newPlayer(), callback: nil) if this.fileplayer.loadIntoPlayer(result.resource, path.cstring) == 0: raise newException(IOError, fmt"file {path} not found: No such file") @@ -144,7 +147,7 @@ proc `=destroy`(this: var SamplePlayerObj) = proc newSamplePlayer*(this: ptr PlaydateSound): SamplePlayer = privateAccess(PlaydateSound) privateAccess(PlaydateSoundSampleplayer) - result = SamplePlayer(resource: this.sampleplayer.newPlayer()) + result = SamplePlayer(resource: this.sampleplayer.newPlayer(), callback: nil) proc sample*(this: SamplePlayer): AudioSample = return this.sample @@ -158,7 +161,7 @@ proc `sample=`*(this: SamplePlayer, sample: AudioSample) = proc newSamplePlayer*(this: ptr PlaydateSound, path: string): SamplePlayer {.raises: [IOError].} = privateAccess(PlaydateSound) privateAccess(PlaydateSoundSampleplayer) - result = SamplePlayer(resource: this.sampleplayer.newPlayer()) + result = SamplePlayer(resource: this.sampleplayer.newPlayer(), callback: nil) result.`sample=`(this.newAudioSample(path)) proc volume*(this: SamplePlayer): tuple[left: float32, right: float32] = @@ -178,6 +181,16 @@ proc setVolume*(this: SamplePlayer, left: float32, right: float32) = privateAccess(PlaydateSoundSampleplayer) playdate.sound.sampleplayer.setVolume(this.resource, left.cfloat, right.cfloat) +proc `offset=`*(this: SamplePlayer, offset: float32) = + privateAccess(PlaydateSound) + privateAccess(PlaydateSoundSampleplayer) + playdate.sound.sampleplayer.setOffset(this.resource, offset.cfloat) + +proc offset*(this: SamplePlayer): float32 = + privateAccess(PlaydateSound) + privateAccess(PlaydateSoundSamplePlayer) + return playdate.sound.sampleplayer.getOffset(this.resource).float32 + proc play*(this: SamplePlayer, repeat: int, rate: float32) = privateAccess(PlaydateSound) privateAccess(PlaydateSoundSampleplayer) @@ -208,6 +221,31 @@ proc rate*(this: SamplePlayer): float32 = privateAccess(PlaydateSoundSampleplayer) return playdate.sound.sampleplayer.getRate(this.resource).float32 +proc privateSampleFinishCallback(soundSourcePtr: SoundSourcePtr, userData: pointer) {.cdecl, raises: [].} = + try: + let samplePlayer = cast[SamplePlayer](userdata)[] + if samplePlayer.callback != nil: + samplePlayer.callback(userData) + except: + echo "Error while calling SamplePlayer finish callback" + +proc setFinishCallback*(this: SamplePlayer, callback: PDSoundCallbackFunction) = + privateAccess(PlaydateSound) + privateAccess(PlaydateSoundSampleplayer) + try: + this.callback = callback + if callback == nil: + playdate.sound.sampleplayer.setFinishCallback(this.resource, nil, nil) + else: + playdate.sound.sampleplayer.setFinishCallback(this.resource, privateSampleFinishCallback, cast[pointer](this)) + except: + echo "Error setting finish callback" + +proc setPlayRange*(this: SamplePlayer, start: int32, `end`: int32) = + privateAccess(PlaydateSound) + privateAccess(PlaydateSoundSampleplayer) + playdate.sound.sampleplayer.setPlayRange(this.resource, start.cint, `end`.cint) + # PlaydateSound var headphoneChanged: proc(headphone: bool, microphone: bool) = nil From 7d7eabf463e23fb8f2838965cdce833d5aa3939f Mon Sep 17 00:00:00 2001 From: Samuele Zolfanelli Date: Sat, 13 Apr 2024 19:49:39 +0200 Subject: [PATCH 015/101] Fix finishCallback not compiling and pass the player to the callback Add a finishCallback usage to the example project --- playdate_example/src/playdate_example.nim | 3 + src/playdate/bindings/sound.nim | 9 +-- src/playdate/sound.nim | 67 ++++++++++++++++------- 3 files changed, 54 insertions(+), 25 deletions(-) diff --git a/playdate_example/src/playdate_example.nim b/playdate_example/src/playdate_example.nim index 2b4c352..99c4ec7 100644 --- a/playdate_example/src/playdate_example.nim +++ b/playdate_example/src/playdate_example.nim @@ -74,6 +74,9 @@ proc handler(event: PDSystemEvent, keycode: uint) {.raises: [].} = # Errors are handled through exceptions try: samplePlayer = playdate.sound.newSamplePlayer("/audio/jingle") + + samplePlayer.finishCallback = proc(player: SamplePlayer) = + playdate.system.logToConsole("Sound finished playing.") except: playdate.system.logToConsole(getCurrentExceptionMsg()) # Inline try/except diff --git a/src/playdate/bindings/sound.nim b/src/playdate/bindings/sound.nim index d6a8c12..16a9bda 100644 --- a/src/playdate/bindings/sound.nim +++ b/src/playdate/bindings/sound.nim @@ -5,9 +5,10 @@ import utils type FilePlayerPtr = pointer type AudioSamplePtr = pointer type SamplePlayerPtr = pointer -type SoundSourcePtr = pointer +type SoundSourceRaw {.importc: "SoundSource", header: "pd_api.h".} = object +type SoundSourcePtr = ptr SoundSourceRaw -type PDSndCallbackProcRaw {.importc: "sndCallbackProc", header: "pd_api.h".} = proc(soundSource: SoundSourcePtr, userData: pointer): void {.cdecl.} +type PDSndCallbackProcRaw {.importc: "sndCallbackProc", header: "pd_api.h".} = proc(soundSource: SoundSourcePtr, userdata: pointer) {.cdecl.} type PlaydateSoundFileplayer {.importc: "const struct playdate_sound_fileplayer", @@ -33,8 +34,8 @@ type PlaydateSoundFileplayer {.importc: "const struct playdate_sound_fileplayer" # setLoopRange* {.importc: "setLoopRange".}: proc (player: ptr FilePlayer; # start: cfloat; `end`: cfloat) {.cdecl.} # didUnderrun* {.importc: "didUnderrun".}: proc (player: ptr FilePlayer): cint {.cdecl.} - # setFinishCallback* {.importc: "setFinishCallback".}: proc ( - # player: ptr FilePlayer; callback: SndCallbackProc) {.cdecl.} + setFinishCallback* {.importc: "setFinishCallback".}: proc ( + player: FilePlayerPtr; callback: PDSndCallbackProcRaw, userData: pointer = nil) {.cdecl, raises: [].} # setLoopCallback* {.importc: "setLoopCallback".}: proc (player: ptr FilePlayer; # callback: SndCallbackProc) {.cdecl.} getOffset {.importc: "getOffset".}: proc (player: FilePlayerPtr): cfloat {.cdecl, raises: [].} diff --git a/src/playdate/sound.nim b/src/playdate/sound.nim index 4aa5607..3c526eb 100644 --- a/src/playdate/sound.nim +++ b/src/playdate/sound.nim @@ -49,14 +49,16 @@ proc getLength*(this: AudioSample): float32 = # AudioSource type SoundSourceObj {.requiresinit.} = object of RootObj resource: pointer - callback: PDSoundCallbackFunction type SoundSource* = ref SoundSourceObj # FilePlayer type FilePlayerObj = object of SoundSourceObj + finishCallback: PDFilePlayerCallbackFunction FilePlayer* = ref FilePlayerObj + PDFilePlayerCallbackFunction* = proc(player: FilePlayer) {.raises: [].} + proc `=destroy`(this: var FilePlayerObj) = privateAccess(PlaydateSound) privateAccess(PlaydateSoundFileplayer) @@ -65,12 +67,12 @@ proc `=destroy`(this: var FilePlayerObj) = proc newFilePlayer*(this: ptr PlaydateSound): FilePlayer = privateAccess(PlaydateSound) privateAccess(PlaydateSoundFileplayer) - result = FilePlayer(resource: this.fileplayer.newPlayer(), callback: nil) + result = FilePlayer(resource: this.fileplayer.newPlayer(), finishCallback: nil) proc newFilePlayer*(this: ptr PlaydateSound, path: string): FilePlayer {.raises: [IOError].} = privateAccess(PlaydateSound) privateAccess(PlaydateSoundFileplayer) - result = FilePlayer(resource: this.fileplayer.newPlayer(), callback: nil) + result = FilePlayer(resource: this.fileplayer.newPlayer(), finishCallback: nil) if this.fileplayer.loadIntoPlayer(result.resource, path.cstring) == 0: raise newException(IOError, fmt"file {path} not found: No such file") @@ -132,12 +134,35 @@ proc `offset=`*(this: FilePlayer, offset: float32) = privateAccess(PlaydateSoundFileplayer) playdate.sound.fileplayer.setOffset(this.resource, offset.cfloat) +proc privateFilePlayerFinishCallback(soundSource: SoundSourcePtr, userdata: pointer) {.cdecl, raises: [].} = + let filePlayer = cast[FilePlayer](userdata) + if filePlayer.finishCallback != nil: + filePlayer.finishCallback(filePlayer) + +proc setFinishCallback*(this: FilePlayer, callback: PDFilePlayerCallbackFunction) = + privateAccess(PlaydateSound) + privateAccess(PlaydateSoundFileplayer) + this.finishCallback = callback + if callback == nil: + playdate.sound.fileplayer.setFinishCallback(this.resource, nil, nil) + else: + playdate.sound.fileplayer.setFinishCallback(this.resource, privateFilePlayerFinishCallback, cast[pointer](this)) + +proc finishCallback*(this: FilePlayer): PDFilePlayerCallbackFunction = + return this.finishCallback + +proc `finishCallback=`*(this: FilePlayer, callback: PDFilePlayerCallbackFunction) = + this.setFinishCallback(callback) + # SamplePlayer type SamplePlayerObj = object of SoundSourceObj sample: AudioSample + finishCallback: PDSamplePlayerCallbackFunction SamplePlayer* = ref SamplePlayerObj + PDSamplePlayerCallbackFunction* = proc(player: SamplePlayer) {.raises: [].} + proc `=destroy`(this: var SamplePlayerObj) = privateAccess(PlaydateSound) privateAccess(PlaydateSoundSampleplayer) @@ -147,7 +172,7 @@ proc `=destroy`(this: var SamplePlayerObj) = proc newSamplePlayer*(this: ptr PlaydateSound): SamplePlayer = privateAccess(PlaydateSound) privateAccess(PlaydateSoundSampleplayer) - result = SamplePlayer(resource: this.sampleplayer.newPlayer(), callback: nil) + result = SamplePlayer(resource: this.sampleplayer.newPlayer(), finishCallback: nil) proc sample*(this: SamplePlayer): AudioSample = return this.sample @@ -161,7 +186,7 @@ proc `sample=`*(this: SamplePlayer, sample: AudioSample) = proc newSamplePlayer*(this: ptr PlaydateSound, path: string): SamplePlayer {.raises: [IOError].} = privateAccess(PlaydateSound) privateAccess(PlaydateSoundSampleplayer) - result = SamplePlayer(resource: this.sampleplayer.newPlayer(), callback: nil) + result = SamplePlayer(resource: this.sampleplayer.newPlayer(), finishCallback: nil) result.`sample=`(this.newAudioSample(path)) proc volume*(this: SamplePlayer): tuple[left: float32, right: float32] = @@ -221,25 +246,25 @@ proc rate*(this: SamplePlayer): float32 = privateAccess(PlaydateSoundSampleplayer) return playdate.sound.sampleplayer.getRate(this.resource).float32 -proc privateSampleFinishCallback(soundSourcePtr: SoundSourcePtr, userData: pointer) {.cdecl, raises: [].} = - try: - let samplePlayer = cast[SamplePlayer](userdata)[] - if samplePlayer.callback != nil: - samplePlayer.callback(userData) - except: - echo "Error while calling SamplePlayer finish callback" +proc privateSamplePlayerFinishCallback(soundSource: SoundSourcePtr, userdata: pointer) {.cdecl, raises: [].} = + let samplePlayer = cast[SamplePlayer](userdata) + if samplePlayer.finishCallback != nil: + samplePlayer.finishCallback(samplePlayer) -proc setFinishCallback*(this: SamplePlayer, callback: PDSoundCallbackFunction) = +proc setFinishCallback*(this: SamplePlayer, callback: PDSamplePlayerCallbackFunction) = privateAccess(PlaydateSound) privateAccess(PlaydateSoundSampleplayer) - try: - this.callback = callback - if callback == nil: - playdate.sound.sampleplayer.setFinishCallback(this.resource, nil, nil) - else: - playdate.sound.sampleplayer.setFinishCallback(this.resource, privateSampleFinishCallback, cast[pointer](this)) - except: - echo "Error setting finish callback" + this.finishCallback = callback + if callback == nil: + playdate.sound.sampleplayer.setFinishCallback(this.resource, nil, nil) + else: + playdate.sound.sampleplayer.setFinishCallback(this.resource, privateSamplePlayerFinishCallback, cast[pointer](this)) + +proc finishCallback*(this: SamplePlayer): PDSamplePlayerCallbackFunction = + return this.finishCallback + +proc `finishCallback=`*(this: SamplePlayer, callback: PDSamplePlayerCallbackFunction) = + this.setFinishCallback(callback) proc setPlayRange*(this: SamplePlayer, start: int32, `end`: int32) = privateAccess(PlaydateSound) From 13a06b23d5a73a51f6aad2d2f3ac58112cdb1134 Mon Sep 17 00:00:00 2001 From: Samuele Zolfanelli Date: Tue, 16 Apr 2024 01:25:26 +0200 Subject: [PATCH 016/101] Fix pdxName not returning the correct pdx name in nimble simulate --- src/playdate/build/utils.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/playdate/build/utils.nim b/src/playdate/build/utils.nim index ba92eef..d78f95f 100644 --- a/src/playdate/build/utils.nim +++ b/src/playdate/build/utils.nim @@ -22,8 +22,8 @@ proc nimble*(args: varargs[string]) = exec @["nimble"].concat(args.toSeq).join(" ") proc pdxName*(): string = - ## The name of the pdx file to generate - projectDir() & ".pdx" + ## The name of the pdx file to generate, same as the project folder name + getCurrentDir().splitPath.tail & ".pdx" proc sdkPath*(): string = ## Returns the path of the playdate SDK From a5f8a9847b1d90d90e4db9d664a74397e808528f Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Sat, 28 Sep 2024 03:10:26 +0200 Subject: [PATCH 017/101] Change fillPolygon to openArray This allows fillPolygon to be used with seqs and arrays, which have much better performance --- src/playdate/graphics.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/playdate/graphics.nim b/src/playdate/graphics.nim index f7df425..427bea5 100644 --- a/src/playdate/graphics.nim +++ b/src/playdate/graphics.nim @@ -342,7 +342,7 @@ proc createPattern*(this: ptr PlaydateGraphics, bitmap: LCDBitmap, x: int, y: in import macros -proc fillPolygon*[Int32x2](this: ptr PlaydateGraphics, points: seq[Int32x2], color: LCDColor, fillRule: LCDPolygonFillRule) = +proc fillPolygon*[Int32x2](this: ptr PlaydateGraphics, points: openArray[Int32x2], color: LCDColor, fillRule: LCDPolygonFillRule) = when sizeof(Int32x2) != sizeof(int32) * 2: {.error: "size of points is not sizeof(int32) * 2".} privateAccess(PlaydateGraphics) From d23a91e5a1dafb62328734ac686373856528060f Mon Sep 17 00:00:00 2001 From: Nycto Date: Mon, 6 May 2024 18:34:43 -0700 Subject: [PATCH 018/101] Reduce allocations for removeSprites --- src/playdate/sprite.nim | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/playdate/sprite.nim b/src/playdate/sprite.nim index 700f741..ebeda11 100644 --- a/src/playdate/sprite.nim +++ b/src/playdate/sprite.nim @@ -84,10 +84,20 @@ proc remove*(this: LCDSprite) = # spritesData.remove(dataNode[]) playdate.sprite.setUserdata(this.resource, nil) -proc removeSprites*(this: ptr PlaydateSprite, sprites: seq[LCDSprite]) = +proc removeSprites*(this: ptr PlaydateSprite, sprites: openarray[LCDSprite]) = privateAccess(PlaydateSprite) - let spritePointers = sprites.map(proc(s: LCDSprite): LCDSpritePtr = return s.resource) - this.removeSprites(cast[ptr LCDSpritePtr](unsafeAddr(spritePointers[0])), spritePointers.len.cint) + + var count = 0 + var spritePointers: array[10, LCDSpritePtr] + for sprite in sprites: + if count == 10: + count = 0 + this.removeSprites(addr spritePointers[0], count.cint) + spritePointers[count] = sprite.resource + count += 1 + if count > 0: + this.removeSprites(addr spritePointers[0], count.cint) + for i, s in sprites: let dataNode = cast[ptr DoublyLinkedNodeObj[LCDSprite]](this.getUserdata(s.resource)) if dataNode == nil: From 096f771ebec4975fb601cd0e9ac8f1fcdff1b14b Mon Sep 17 00:00:00 2001 From: Nycto Date: Mon, 6 May 2024 18:54:41 -0700 Subject: [PATCH 019/101] Dont alloc for width and height --- src/playdate/graphics.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/playdate/graphics.nim b/src/playdate/graphics.nim index 427bea5..2e4ef9c 100644 --- a/src/playdate/graphics.nim +++ b/src/playdate/graphics.nim @@ -363,9 +363,9 @@ proc drawRotated*(this: LCDBitmap, x: int, y: int, rotation: float32, centerX: f playdate.graphics.drawRotatedBitmap(this.resource, x.cint, y.cint, rotation.cfloat, centerX.cfloat, centerY.cfloat, xScale.cfloat, yScale.cfloat) -proc width*(this: LCDBitmap): int = this.getData.width +proc width*(this: LCDBitmap): int = this.getSize.width -proc height*(this: LCDBitmap): int = this.getData.height +proc height*(this: LCDBitmap): int = this.getSize.height proc setBitmapMask*( this: LCDBitmap, From 8f850a86f8a18f176253d5191a8a1636a23fb36f Mon Sep 17 00:00:00 2001 From: Nycto Date: Mon, 6 May 2024 19:21:15 -0700 Subject: [PATCH 020/101] Allow bitmap data access without allocation --- src/playdate/graphics.nim | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/src/playdate/graphics.nim b/src/playdate/graphics.nim index 2e4ef9c..0739633 100644 --- a/src/playdate/graphics.nim +++ b/src/playdate/graphics.nim @@ -126,35 +126,43 @@ proc load*(this: LCDBitmap, path: string) {.raises: [IOError]} = if err != nil: raise newException(IOError, $err) -type BitmapData* = ref object - width*: int - height*: int - rowbytes: int - data: ptr UncheckedArray[uint8] +type + BitmapDataObj* = object + width*: int + height*: int + rowbytes: int + data: ptr UncheckedArray[uint8] + + BitmapData* = ref BitmapDataObj + + AnyBitmapData* = BitmapDataObj | BitmapData proc index(x, y, rowbytes: int): int = y * rowbytes + x div 8 ## Returns the index of an (x, y) coordinate in a flattened array. -template read(bitmap: BitmapData, x, y: int): untyped = +template read(bitmap: AnyBitmapData, x, y: int): untyped = ## Read a pixel from a bitmap. assert(bitmap.data != nil) bitmap.data[index(x, y, bitmap.rowbytes)] -proc getData*(this: LCDBitmap): BitmapData = +proc getDataObj*(this: LCDBitmap): BitmapDataObj = ## Fetch the underlying bitmap data for an image. privateAccess(PlaydateGraphics) assert(this != nil) assert(this.resource != nil) - var bitmapData = BitmapData() playdate.graphics.getBitmapData( this.resource, - cast[ptr cint](addr(bitmapData.width)), - cast[ptr cint](addr(bitmapData.height)), - cast[ptr cint](addr(bitmapData.rowbytes)), + cast[ptr cint](addr(result.width)), + cast[ptr cint](addr(result.height)), + cast[ptr cint](addr(result.rowbytes)), nil, - cast[ptr ptr uint8](addr(bitmapData.data)) + cast[ptr ptr uint8](addr(result.data)) ) - return bitmapData + +proc getData*(this: LCDBitmap): BitmapData = + ## Fetch the underlying bitmap data for an image. + result = new(BitmapData) + result[] = getDataObj(this) proc getSize*(this: LCDBitmap): tuple[width: int, height: int] = privateAccess(PlaydateGraphics) @@ -274,7 +282,7 @@ type DisplayFrame* = distinct ptr array[LCD_ROWSIZE * LCD_ROWS, uint8] ## The raw bytes in a display frame buffer. - BitmapView* = DisplayFrame | BitmapData + BitmapView* = DisplayFrame | AnyBitmapData ## Types that allow the manipulation of individual pixels. proc getFrame*(this: ptr PlaydateGraphics): DisplayFrame = From 49e5224e90a3aa6e47fe1a9549415de0aa9939d8 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Sat, 10 Aug 2024 19:18:57 +0200 Subject: [PATCH 021/101] CHANGE GCC optimization from O3 to O2 --- src/playdate/build/config.nim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/playdate/build/config.nim b/src/playdate/build/config.nim index 4940af2..6cd3a8e 100644 --- a/src/playdate/build/config.nim +++ b/src/playdate/build/config.nim @@ -80,7 +80,10 @@ when defined(device): if defined(release): switch("define", "release") - switch("opt", "speed") + # Normally, one would use opt = speed, which implies O3 (optimization level 3), + # but O2 outperforms O3 on the Playdate + switch("opt", "none") + switch("passC", "-O2") switch("debuginfo", "off") switch("index", "off") switch("stackTrace", "off") From 8e516caf701094c94092bcf2b6db8d638a95c71c Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Sat, 28 Sep 2024 03:20:40 +0200 Subject: [PATCH 022/101] Add getBitmapTableInfo --- src/playdate/bindings/graphics.nim | 2 ++ src/playdate/graphics.nim | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/src/playdate/bindings/graphics.nim b/src/playdate/bindings/graphics.nim index adb9262..97cbfee 100644 --- a/src/playdate/bindings/graphics.nim +++ b/src/playdate/bindings/graphics.nim @@ -189,6 +189,8 @@ sdktype: table: LCDBitmapTablePtr; outerr: ptr cstring) {.cdecl, raises: [].} getTableBitmap {.importc: "getTableBitmap".}: proc (table: LCDBitmapTablePtr; idx: cint): LCDBitmapPtr {.cdecl, raises: [].} + getBitmapTableInfo {.importc: "getBitmapTableInfo".}: proc (table: LCDBitmapTablePtr; + outCount: ptr cint; outCellsWide: ptr cint) {.cdecl, raises: [].} loadFont {.importc: "loadFont".}: proc (path: cstring, outErr: ptr cstring): LCDFontPtr {.cdecl, raises: [].} diff --git a/src/playdate/graphics.nim b/src/playdate/graphics.nim index 0739633..5691420 100644 --- a/src/playdate/graphics.nim +++ b/src/playdate/graphics.nim @@ -235,6 +235,12 @@ proc getBitmap*(this: LCDBitmapTable, index: int): LCDBitmap = return LCDTableBitmap(resource: resource, free: false, table: this) return nil +proc getBitmapTableInfo*(this: LCDBitmapTable): tuple[count: int, cellsWide: int] = + privateAccess(PlaydateGraphics) + var count, cellsWide: cint + playdate.graphics.getBitmapTableInfo(this.resource, addr(count), addr(cellsWide)) + return (count.int, cellsWide.int) + proc newFont*(this: ptr PlaydateGraphics, path: string): LCDFont {.raises: [IOError]} = privateAccess(PlaydateGraphics) privateAccess(LCDFont) From cc8b5604cf5cad76c4ca2daeecee465c079b25c6 Mon Sep 17 00:00:00 2001 From: Nycto Date: Wed, 11 Sep 2024 08:55:34 -0700 Subject: [PATCH 023/101] Mark git dir safe in workflow --- .github/workflows/build.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2c81a3c..2a491d5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,6 +16,8 @@ jobs: - name: Install dependencies run: apt-get install -y libpng16-16 gcc-arm-none-eabi - uses: actions/checkout@v1 + - name: Safe git directory + run: git config --global --add safe.directory "$(pwd)" - name: Download playdate SDK run: wget https://download.panic.com/playdate_sdk/Linux/PlaydateSDK-latest.tar.gz - name: Extract playdate SDK @@ -69,6 +71,9 @@ jobs: - name: Checkout commit uses: actions/checkout@v1 + - name: Safe git directory + run: git config --global --add safe.directory "$(pwd)" + - name: Download playdate SDK run: wget https://download.panic.com/playdate_sdk/Linux/PlaydateSDK-latest.tar.gz - name: Extract playdate SDK From fd7bede7cf92e9a18efa7c8f3063e5f1c2ceef71 Mon Sep 17 00:00:00 2001 From: Nycto Date: Fri, 13 Sep 2024 18:14:57 -0700 Subject: [PATCH 024/101] Add nimble.develop files to subprojects --- playdate_example/nimble.develop | 7 +++++++ tests/nimble.develop | 7 +++++++ 2 files changed, 14 insertions(+) create mode 100644 playdate_example/nimble.develop create mode 100644 tests/nimble.develop diff --git a/playdate_example/nimble.develop b/playdate_example/nimble.develop new file mode 100644 index 0000000..49def8e --- /dev/null +++ b/playdate_example/nimble.develop @@ -0,0 +1,7 @@ +{ + "version": 1, + "includes": [], + "dependencies": [ + ".." + ] +} diff --git a/tests/nimble.develop b/tests/nimble.develop new file mode 100644 index 0000000..49def8e --- /dev/null +++ b/tests/nimble.develop @@ -0,0 +1,7 @@ +{ + "version": 1, + "includes": [], + "dependencies": [ + ".." + ] +} From db4f392dda74d2f5d88f91a3508b1f0b806f0636 Mon Sep 17 00:00:00 2001 From: Nycto Date: Tue, 7 May 2024 18:00:45 -0700 Subject: [PATCH 025/101] Directly call reallocImpl from realloc0Impl --- src/playdate/bindings/malloc.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/playdate/bindings/malloc.nim b/src/playdate/bindings/malloc.nim index 02e786d..3173f30 100644 --- a/src/playdate/bindings/malloc.nim +++ b/src/playdate/bindings/malloc.nim @@ -43,7 +43,7 @@ proc reallocImpl(p: pointer, newSize: Natural): pointer = return pdrealloc(p, newSize.csize_t) proc realloc0Impl(p: pointer, oldsize, newSize: Natural): pointer = - result = realloc(p, newSize.csize_t) + result = reallocImpl(p, newSize.csize_t) if newSize > oldSize: zeroMem(cast[pointer](cast[uint](result) + uint(oldSize)), newSize - oldSize) From a74791a5aae601f3c4b7a57f716fca4228168491 Mon Sep 17 00:00:00 2001 From: Nycto Date: Mon, 20 May 2024 19:13:21 -0700 Subject: [PATCH 026/101] Memory profiler integration --- src/playdate/bindings/malloc.nim | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/playdate/bindings/malloc.nim b/src/playdate/bindings/malloc.nim index 3173f30..15bb4c9 100644 --- a/src/playdate/bindings/malloc.nim +++ b/src/playdate/bindings/malloc.nim @@ -17,6 +17,10 @@ when defined(memtrace): import system/ansi_c +# Forward declaration for memory profiling support +when defined(memProfiler): + proc nimProfile(requestedSize: int) + type PDRealloc = proc (p: pointer; size: csize_t): pointer {.tags: [], raises: [], cdecl, gcsafe.} var pdrealloc: PDRealloc @@ -29,6 +33,15 @@ proc setupRealloc*(allocator: PDRealloc) = proc allocImpl(size: Natural): pointer = when defined(memtrace): cfprintf(cstderr, "Allocating %d\n", size) + + # Integrage with: https://nim-lang.org/docs/estp.html + when defined(memProfiler): + {.cast(tags: []).}: + try: + nimProfile(size.int) + except: + discard + result = pdrealloc(nil, size.csize_t) when defined(memtrace): cfprintf(cstderr, " At %p\n", result) From 9a16a29a109a3e75bd6bbc82abdd4e2022504439 Mon Sep 17 00:00:00 2001 From: Nycto Date: Mon, 20 May 2024 19:31:39 -0700 Subject: [PATCH 027/101] Memory tracing --- src/playdate/bindings/malloc.nim | 38 ++-- src/playdate/bindings/memtrace.nim | 292 ++++++++++++++++++++++++++++ src/playdate/bindings/sparsemap.nim | 69 +++++++ tests/t_sparsemap.nim | 71 +++++++ 4 files changed, 454 insertions(+), 16 deletions(-) create mode 100644 src/playdate/bindings/memtrace.nim create mode 100644 src/playdate/bindings/sparsemap.nim create mode 100644 tests/t_sparsemap.nim diff --git a/src/playdate/bindings/malloc.nim b/src/playdate/bindings/malloc.nim index 15bb4c9..b352c80 100644 --- a/src/playdate/bindings/malloc.nim +++ b/src/playdate/bindings/malloc.nim @@ -14,26 +14,38 @@ {.push stackTrace: off.} -when defined(memtrace): - import system/ansi_c - # Forward declaration for memory profiling support when defined(memProfiler): proc nimProfile(requestedSize: int) +import memtrace +import system/ansi_c + type PDRealloc = proc (p: pointer; size: csize_t): pointer {.tags: [], raises: [], cdecl, gcsafe.} +proc nativeAlloc(p: pointer; size: csize_t): pointer {.tags: [], raises: [], cdecl, gcsafe.} = + if p == nil: + return c_malloc(size) + elif size == 0: + c_free(p) + return nil + else: + return c_realloc(p, size) + var pdrealloc: PDRealloc +var trace: MemTrace + + proc setupRealloc*(allocator: PDRealloc) = when defined(memtrace): cfprintf(cstderr, "Setting up playdate allocator") - pdrealloc = allocator + when defined(nativeAlloc): + pdrealloc = nativeAlloc + else: + pdrealloc = allocator proc allocImpl(size: Natural): pointer = - when defined(memtrace): - cfprintf(cstderr, "Allocating %d\n", size) - # Integrage with: https://nim-lang.org/docs/estp.html when defined(memProfiler): {.cast(tags: []).}: @@ -42,18 +54,14 @@ proc allocImpl(size: Natural): pointer = except: discard - result = pdrealloc(nil, size.csize_t) - when defined(memtrace): - cfprintf(cstderr, " At %p\n", result) + return trace.alloc(pdrealloc, size.csize_t) proc alloc0Impl(size: Natural): pointer = result = allocImpl(size) zeroMem(result, size) proc reallocImpl(p: pointer, newSize: Natural): pointer = - when defined(memtrace): - cfprintf(cstderr, "Reallocating %p with size %d\n", p, newSize) - return pdrealloc(p, newSize.csize_t) + return trace.realloc(pdrealloc, p, newSize) proc realloc0Impl(p: pointer, oldsize, newSize: Natural): pointer = result = reallocImpl(p, newSize.csize_t) @@ -61,9 +69,7 @@ proc realloc0Impl(p: pointer, oldsize, newSize: Natural): pointer = zeroMem(cast[pointer](cast[uint](result) + uint(oldSize)), newSize - oldSize) proc deallocImpl(p: pointer) = - when defined(memtrace): - cfprintf(cstderr, "Freeing %p\n", p) - discard pdrealloc(p, 0) + trace.dealloc(pdrealloc, p) # The shared allocators map on the regular ones diff --git a/src/playdate/bindings/memtrace.nim b/src/playdate/bindings/memtrace.nim new file mode 100644 index 0000000..f82fcad --- /dev/null +++ b/src/playdate/bindings/memtrace.nim @@ -0,0 +1,292 @@ +import system/ansi_c, sparsemap + +proc mprotect(a1: pointer, a2: int, a3: cint): cint {.importc, header: "".} + +proc fopen(filename, mode: cstring): CFilePtr {.importc: "fopen", nodecl.} + +proc fclose(file: CFilePtr) {.importc: "fclose", nodecl.} + +const SLOTS = 20_000 + +const STACK_SIZE = 12 + +const BUFFER = sizeof(byte) * 8 + +type + Allocator* = proc (p: pointer; size: csize_t): pointer {.tags: [], raises: [], cdecl, gcsafe.} + + StackString[N : static int] = object + data: array[N, char] + len: int32 + + StackFrame = object + used: bool + procname: StackString[50] + filename: StackString[200] + line: int32 + + Allocation {.byref.} = object + realPointer: pointer + realSize: int32 + reported: bool + resized: bool + originalSize: int32 + protected: bool + stack: array[STACK_SIZE, StackFrame] + + MemTrace* = object + allocs: StaticSparseMap[SLOTS, uint64, Allocation] + deleted: StaticSparseMap[SLOTS, uint64, Allocation] + totalAllocs: int + +proc toStackStr(input: cstring, N: static int): StackString[N] = + var i = 0'i32 + for c in input: + if i >= N - 1: + break + result.data[i] = c + i += 1 + result.data[i] = '\0' + result.len = i + +proc endsWith(a, b: cstring): bool = + false + +proc createStackFrame[N: static int](frame: PFrame): array[N, StackFrame] = + var current = frame + var i = 0 + while i < N: + if current == nil: + break + + if not current.filename.endsWith("/arc.nim"): + result[i] = StackFrame( + used: true, + procname: current.procname.toStackStr(50), + filename: current.filename.toStackStr(200), + line: current.line.int32 + ) + i += 1 + + current = current.prev + +proc printStack[N: static int](frames: array[N, StackFrame]) = + for i in 0.. thisP and pInt - thisP < distance: + found = alloc + distance = pInt - thisP + + if distance != high(uint64): + found.print("Preceding allocation") + cfprintf(cstderr, " Distance: %i\n", distance) + +proc check(trace: var MemTrace) = + if trace.totalAllocs mod 100 == 0: + cfprintf(cstderr, "Allocations count: %i (active: %i)\n", trace.totalAllocs, trace.allocs.size) + + for (_, alloc) in trace.allocs: + if not alloc.protected and not alloc.reported and isInvalid(alloc.realPointer, alloc.realSize): + alloc.reported = true + alloc.print("CORRUPT! ") + trace.printPrior(alloc.realPointer) + +proc memRange(alloc: Allocation): Slice[uint64] = + return cast[uint64](alloc.realPointer)..(cast[uint64](alloc.realPointer) + alloc.realSize.uint64) + +proc checkOverlaps(trace: var MemTrace, title: cstring, newAlloc: Allocation) = + let newRange = newAlloc.memRange + for (_, alloc) in trace.allocs: + let existingRange = alloc.memRange + if existingRange.a in newRange or existingRange.b in newRange: + cfprintf(cstderr, "%s overlaps with existing allocation!\n", title) + newAlloc.print(title) + alloc.print("Overlaps with:") + +proc unprotect(p: pointer, size: Natural) = + discard mprotect(p, BUFFER, 7) + discard mprotect(p + size + BUFFER, BUFFER, 7) + +proc protect(p: pointer, size: Natural): bool = + if mprotect(p, BUFFER, 1) != 0: + return false + + if mprotect(p + size + BUFFER, BUFFER, 1) != 0: + discard mprotect(p, BUFFER, 7) + return false + + return true + +proc zeroBuffers(p: pointer, size: Natural) = + zeroMem(p, BUFFER) + zeroMem(p + size + BUFFER, BUFFER) + if p.isInvalid(size.realSize): + cfprintf(cstderr, "Zeroing failed! ") + p.printMem(size.realSize) + +proc record[N: static int](stack: array[N, StackFrame] = createStackFrame[N](getFrame())) {.inline.} = + when defined(memrecord): + let handle = fopen("memrecord.txt", "a") + defer: fclose(handle) + for i in 0.. 0: + c_fputc('|', handle) + discard c_fwrite(addr stack[i].filename, 1, stack[i].filename.len.csize_t, handle) + c_fputc(':', handle) + discard c_fwrite(addr stack[i].procname, 1, stack[i].procname.len.csize_t, handle) + c_fputc('\n', handle) + +proc traceAlloc(trace: var MemTrace, alloc: Allocator, size: Natural): pointer {.inline.} = + trace.totalAllocs += 1 + trace.check + + let realPointer = alloc(nil, size.realSize.csize_t) + result = realPointer.output + + zeroBuffers(realPointer, size) + let protected = protect(realPointer, size) + + let entry = Allocation( + realSize: size.realSize.int32, + realPointer: realPointer, + protected: protected, + stack: createStackFrame[STACK_SIZE](getFrame()), + ) + + trace.checkOverlaps("New allocation", entry) + + trace.allocs[realPointer.ord] = entry + +proc alloc*(trace: var MemTrace, alloc: Allocator, size: Natural): pointer {.inline.} = + record[5]() + when defined(memtrace): return traceAlloc(trace, alloc, size) else: return alloc(nil, size.csize_t) + +proc traceRealloc(trace: var MemTrace, alloc: Allocator, p: pointer, newSize: Natural): pointer {.inline.} = + trace.check + + let realInPointer = p.input + let origSize = trace.allocs[realInPointer.ord].realSize + unprotect(realInPointer, origSize) + + let realOutPointer = alloc(realInPointer, newSize.realSize.csize_t) + result = realOutPointer.output + + zeroBuffers(realOutPointer, newSize) + let protected = protect(realOutPointer, newSize) + + trace.allocs.delete(realInPointer.ord) + + let entry = Allocation( + realSize: newSize.realSize.int32, + realPointer: realOutPointer, + stack: createStackFrame[STACK_SIZE](getFrame()), + resized: true, + protected: protected, + originalSize: origSize, + ) + + trace.checkOverlaps("Resized allocation", entry) + + trace.allocs[realOutPointer.ord] = entry + +proc realloc*(trace: var MemTrace, alloc: Allocator, p: pointer, newSize: Natural): pointer {.inline.} = + when defined(memtrace): return traceRealloc(trace, alloc, p, newSize) else: return alloc(p, newSize.csize_t) + +proc traceDealloc(trace: var MemTrace, alloc: Allocator, p: pointer) {.inline.} = + trace.check + let realPointer = p.input + let entry = trace.allocs[realPointer.ord] + if entry == nil: + cfprintf(cstderr, "Attempting to dealloc unmanaged memory! %p\n", p) + createStackFrame[STACK_SIZE](getFrame()).printStack() + let deleted = trace.deleted[realPointer.ord] + if deleted == nil: + trace.printPrior(p) + else: + deleted[].print("Previously deallocated", printMem = false) + return + else: + var local = entry[] + local.stack = createStackFrame[STACK_SIZE](getFrame()) + + unprotect(realPointer, entry.realSize) + discard alloc(realPointer, 0) + trace.deleted[realPointer.ord] = local + trace.allocs.delete(realPointer.ord) + +proc dealloc*(trace: var MemTrace, alloc: Allocator, p: pointer) {.inline.} = + when defined(memtrace): traceDealloc(trace, alloc, p) else: discard alloc(p, 0) \ No newline at end of file diff --git a/src/playdate/bindings/sparsemap.nim b/src/playdate/bindings/sparsemap.nim new file mode 100644 index 0000000..1374c27 --- /dev/null +++ b/src/playdate/bindings/sparsemap.nim @@ -0,0 +1,69 @@ +type + Pair*[K, V] = tuple[key: K, value: V] + + Entry[K, V] = object + pair: Pair[K, V] + sparseIdx: int32 + + StaticSparseMap*[N : static int, K, V] {.byref.} = object + ## A sparse map implemented on the stack + dense: array[N, Entry[K, V]] + sparse: array[N, int32] + size: int32 + +proc `=copy`[N : static int, K, V](a: var StaticSparseMap[N, K, V], b: StaticSparseMap[N, K, V]) {.error.} + +proc size*[N : static int, K, V](m: var StaticSparseMap[N, K, V]): auto {.inline.} = m.size + +proc bestIndex[N : static int, K](key: K): int32 {.inline.} = + ## Returns the best index a key can be at for a given key + (ord(key).int32 * 7) mod (N).int32 + +iterator possibleSparseIdxs[N : static int, K](key: K): int32 = + ## Iterates through the possible indexes at which a key could be set + let start = bestIndex[N, K](key) + for i in start..= m.size or m.dense[denseIdx].sparseIdx != i: + m.dense[m.size] = Entry[K, V](pair: (key, value), sparseIdx: i) + m.sparse[i] = m.size + m.size.inc + return + +iterator items*[N : static int, K, V](m: var StaticSparseMap[N, K, V]): var Pair[K, V] = + ## Iterates through all entries in this map + for i in 0..= m.size: + break + var entry {.inject.} = m.dense[denseIdx] + if entry.sparseIdx != sparseIdx: + break + elif entry.pair.key == key: + exec + +proc `[]`*[N : static int, K, V](m: StaticSparseMap[N, K, V], key: sink K): ptr V = + ## Get a pointer to a key in this map + m.find(key): + return addr entry.pair.value + +proc delete*[N : static int, K, V](m: var StaticSparseMap[N, K, V], key: sink K) = + ## Remove a key and its value from this map + if m.size > 0: + m.find(key): + m.size.dec + swap(m.dense[denseIdx], m.dense[m.size]) + m.sparse[m.dense[denseIdx].sparseIdx] = denseIdx + m.dense[m.size] = Entry[K, V]() diff --git a/tests/t_sparsemap.nim b/tests/t_sparsemap.nim new file mode 100644 index 0000000..df64a4f --- /dev/null +++ b/tests/t_sparsemap.nim @@ -0,0 +1,71 @@ +import unittest, random, algorithm, sequtils, playdate/bindings/sparsemap + +proc randomData[T](N: int, maxVal: T): seq[T] = + result = newSeq[T](N) + for i in 0 ..< N: + result[i] = rand(maxVal-1) + +randomize(123) + +proc expectData[N : static int](map: var StaticSparseMap[N, int, string], expect: openarray[int]) = + check(map.toSeq.mapIt(it.key).sorted() == expect.toSeq.sorted()) + check(map.toSeq.mapIt(it.value).sorted() == expect.toSeq.mapIt($it).sorted()) + + for key in expect: + checkpoint("Checking key " & $key) + check(map[key] != nil) + if map[key] != nil: + check(map[key][] == $key) + + for key in 5000..5100: + check(map[key] == nil) + +suite "StaticSparseMap": + + for size in [0, 1, 10, 100]: + test "Setting of size " & $size: + var m: StaticSparseMap[200, int, string] + + let data = randomData(size, 500) + + for value in data: + m[value] = $value + + expectData[200](m, data) + + test "Adding more data than capacity": + var m: StaticSparseMap[5, int, string] + let data = randomData(5, 100) + for value in data: + m[value] = $value + + m[400] = "ignored" + m[500] = "also ignored" + + expectData[5](m, data) + + test "Deleting values": + var m: StaticSparseMap[10, int, string] + for i in 0..5: + m[i] = $i + + m.delete(3) + expectData[10](m, [0, 1, 2, 4, 5]) + + m.delete(0) + expectData[10](m, [1, 2, 4, 5]) + + m.delete(4) + expectData[10](m, [1, 2, 5]) + + m.delete(2) + expectData[10](m, [1, 5]) + + m.delete(1) + expectData[10](m, [5]) + + m.delete(5) + expectData[10](m, []) + + m.delete(500) + expectData[10](m, []) \ No newline at end of file From 70ffca80451c1d8692a70ec726d5312fba9aaaae Mon Sep 17 00:00:00 2001 From: Nycto Date: Fri, 13 Sep 2024 18:35:08 -0700 Subject: [PATCH 028/101] Add sequence APIs --- src/playdate/bindings/sound.nim | 26 ++++++++- src/playdate/sound.nim | 74 +++++++++++++++++++++++- tests/source/deliberate_concealment.mid | Bin 0 -> 18444 bytes tests/src/playdate_tests.nim | 3 +- tests/t_midi.nim | 27 +++++++++ 5 files changed, 126 insertions(+), 4 deletions(-) create mode 100644 tests/source/deliberate_concealment.mid create mode 100644 tests/t_midi.nim diff --git a/src/playdate/bindings/sound.nim b/src/playdate/bindings/sound.nim index 16a9bda..dff9fbc 100644 --- a/src/playdate/bindings/sound.nim +++ b/src/playdate/bindings/sound.nim @@ -7,7 +7,9 @@ type AudioSamplePtr = pointer type SamplePlayerPtr = pointer type SoundSourceRaw {.importc: "SoundSource", header: "pd_api.h".} = object type SoundSourcePtr = ptr SoundSourceRaw +type SoundSequencePtr = pointer +type SequenceFinishedCallback = proc(soundSource: SoundSourcePtr, userdata: pointer) {.cdecl.} type PDSndCallbackProcRaw {.importc: "sndCallbackProc", header: "pd_api.h".} = proc(soundSource: SoundSourcePtr, userdata: pointer) {.cdecl.} @@ -97,6 +99,28 @@ type PlaydateSoundSampleplayer {.importc: "const struct playdate_sound_samplepla cdecl, raises: [].} # type PlaydateSoundSampleplayer* = ptr PlaydateSoundSampleplayerRaw +type PlaydateSoundSequence {.importc: "const struct playdate_sound_sequence", + header: "pd_api.h", bycopy.} = object + newSequence {.importc: "newSequence".}: proc (): SoundSequencePtr {.cdecl, raises: [].} + freeSequence {.importc: "freeSequence".}: proc (player: SoundSequencePtr) {.cdecl, raises: [].} + loadMIDIFile {.importc: "loadMIDIFile".}: proc(soundSeq: SoundSequencePtr, path: cstring): cint {.cdecl, raises: [].} + getTime {.importc: "getTime".}: proc(soundSeq: SoundSequencePtr): cuint {.cdecl, raises: [].} + setTime {.importc: "setTime".}: proc(soundSeq: SoundSequencePtr, time: cuint): void {.cdecl, raises: [].} + setLoops {.importc: "setLoops".}: proc(soundSeq: SoundSequencePtr, loopstart: cint, loopend: cint, loops: cint): void {.cdecl, raises: [].} + setTempo {.importc: "setTempo".}: proc(soundSeq: SoundSequencePtr, stepsPerSecond: cfloat): void {.cdecl, raises: [].} + # getTrackCount {.importc: "getTrackCount".}: proc(soundSeq: SoundSequencePtr): cint {.cdecl, raises: [].} + # addTrack {.importc: "addTrack".}: proc(soundSeq: SoundSequencePtr): SequenceTrackPtr {.cdecl, raises: [].} + # getTrackAtIndex {.importc: "getTrackAtIndex".}: proc(soundSeq: SoundSequencePtr, track: cuint): SequenceTrackPtr {.cdecl, raises: [].} + # setTrackAtIndex {.importc: "setTrackAtIndex".}: proc(soundSeq: SoundSequencePtr, track: SequenceTrackPtr, idx: cuint): void {.cdecl, raises: [].} + allNotesOff {.importc: "allNotesOff".}: proc(soundSeq: SoundSequencePtr): void {.cdecl, raises: [].} + isPlaying {.importc: "isPlaying".}: proc(soundSeq: SoundSequencePtr): cint {.cdecl, raises: [].} + getLength {.importc: "getLength".}: proc(soundSeq: SoundSequencePtr): cuint {.cdecl, raises: [].} + play {.importc: "play".}: proc(soundSeq: SoundSequencePtr, finishCallback: SequenceFinishedCallback = nil, userdata: pointer = nil): void {.cdecl, raises: [].} + stop {.importc: "stop".}: proc(soundSeq: SoundSequencePtr): void {.cdecl, raises: [].} + getCurrentStep {.importc: "getCurrentStep".}: proc(soundSeq: SoundSequencePtr, timeOffset: ptr cint): cint {.cdecl, raises: [].} + setCurrentStep {.importc: "setCurrentStep".}: proc(soundSeq: SoundSequencePtr, step: cint, timeOffset: cint, playNotes: cint): void {.cdecl, raises: [].} + getTempo {.importc: "getTempo".}: proc(soundSeq: SoundSequencePtr): cfloat {.cdecl, raises: [].} + sdktype: type PlaydateSound* {.importc: "const struct playdate_sound", header: "pd_api.h".} = object # channel* {.importc: "channel".}: ptr PlaydateSoundChannel @@ -104,7 +128,7 @@ sdktype: sample {.importc: "sample".}: ptr PlaydateSoundSample sampleplayer {.importc: "sampleplayer".}: ptr PlaydateSoundSampleplayer # synth* {.importc: "synth".}: ptr PlaydateSoundSynth - # sequence* {.importc: "sequence".}: ptr PlaydateSoundSequence + sequence* {.importc: "sequence".}: ptr PlaydateSoundSequence # effect* {.importc: "effect".}: ptr PlaydateSoundEffect # lfo* {.importc: "lfo".}: ptr PlaydateSoundLfo # envelope* {.importc: "envelope".}: ptr PlaydateSoundEnvelope diff --git a/src/playdate/sound.nim b/src/playdate/sound.nim index 3c526eb..687415a 100644 --- a/src/playdate/sound.nim +++ b/src/playdate/sound.nim @@ -1,6 +1,6 @@ {.push raises: [].} -import std/importutils +import std/[importutils, macros] import bindings/sound import bindings/api import system @@ -294,4 +294,74 @@ proc getHeadphoneState*(this: ptr PlaydateSound): tuple[headphone: bool, microph proc setOutputsActive*(this: ptr PlaydateSound, headphone: bool, speaker: bool) = privateAccess(PlaydateSound) - this.setOutputsActive(if headphone: 1 else: 0, if speaker: 1 else: 0) \ No newline at end of file + this.setOutputsActive(if headphone: 1 else: 0, if speaker: 1 else: 0) + +type + SoundSequenceObj = object + resource: SoundSequencePtr + + SoundSequence* = ref SoundSequenceObj + +proc `=destroy`*(this: var SoundSequenceObj) = + privateAccess(PlaydateSoundSequence) + playdate.sound.sequence.freeSequence(this.resource) + +proc newSequence*(this: ptr PlaydateSoundSequence): SoundSequence = + privateAccess(PlaydateSoundSequence) + return SoundSequence(resource: this.newSequence()) + +template checkZero(code: typed) = + if code == 0: + raise newException(CatchableError, astToStr(code)) + +proc loadMIDIFile*(this: var SoundSequence, path: string) {.raises: [CatchableError].} = + privateAccess(PlaydateSoundSequence) + checkZero(playdate.sound.sequence.loadMIDIFile(this.resource, path.cstring)) + +proc getTime*(this: SoundSequence): uint32 = + privateAccess(PlaydateSoundSequence) + return playdate.sound.sequence.getTime(this.resource).uint32 + +proc setTime*(this: SoundSequence, time: uint32) = + privateAccess(PlaydateSoundSequence) + playdate.sound.sequence.setTime(this.resource, time) + +proc setLoops*(this: SoundSequence, loopstart, loopend, loops: int32) = + privateAccess(PlaydateSoundSequence) + playdate.sound.sequence.setLoops(this.resource, loopstart.cint, loopend.cint, loops.cint) + +proc allNotesOff*(this: SoundSequence) = + privateAccess(PlaydateSoundSequence) + playdate.sound.sequence.allNotesOff(this.resource) + +proc isPlaying*(this: SoundSequence): bool = + privateAccess(PlaydateSoundSequence) + return playdate.sound.sequence.isPlaying(this.resource) == 1 + +proc getLength*(this: SoundSequence): uint32 = + privateAccess(PlaydateSoundSequence) + return playdate.sound.sequence.getLength(this.resource).uint32 + +proc play*(this: SoundSequence, finishCallback: SequenceFinishedCallback = nil) = + privateAccess(PlaydateSoundSequence) + playdate.sound.sequence.play(this.resource, finishCallback, nil) + +proc stop*(this: SoundSequence) = + privateAccess(PlaydateSoundSequence) + playdate.sound.sequence.stop(this.resource) + +proc getCurrentStep*(this: SoundSequence): int32 = + privateAccess(PlaydateSoundSequence) + return playdate.sound.sequence.getCurrentStep(this.resource, nil).int32 + +proc setCurrentStep*(this: SoundSequence, step, timeOffset, playNotes: int32) = + privateAccess(PlaydateSoundSequence) + playdate.sound.sequence.setCurrentStep(this.resource, step.cint, timeOffset.cint, playNotes.cint) + +proc getTempo*(this: SoundSequence): float32 = + privateAccess(PlaydateSoundSequence) + return playdate.sound.sequence.getTempo(this.resource).float32 + +proc setTempo*(this: SoundSequence, stepsPerSecond: float32) = + privateAccess(PlaydateSoundSequence) + playdate.sound.sequence.setTempo(this.resource, stepsPerSecond) diff --git a/tests/source/deliberate_concealment.mid b/tests/source/deliberate_concealment.mid new file mode 100644 index 0000000000000000000000000000000000000000..1a638338ec7a264a3eb6f3055a17f6760b5cea67 GIT binary patch literal 18444 zcmeHNOK($06#i~ZaTL`G?1;MH)es0yjFmtIRpcZBr;)KUwy|tnAfOweN?jDwh1EsX zx=}Fr8W9XHSSBf$6xX`KQlu?LFX&H*n3HL5m-6 z0teZ(-onp^Is7Hhn&y++^t=o6X_*kks2CrO!YWHGCd7$Q0+wL2fE5#`*2ZvZeYKRy z{$iQ~)3Ek);C?kmCCTlIE^vZI3dY`BejK4OcAGMiep|4sNv&;kHZ=!#IPee#zx}m z9dK~t9K^9&T#B_>r8v~_7XL+gqY~7J8>`Xv;-iG&?nfvxBG)lK%5^v*BkWbpYI(X= zInzL{rApebp<_V-p-p6}0YYQ8-o>FWtm{;ndn<8j}Nh zwnHcFM2(Qanhv1kiB0D;ldjYC9z}88JBF4Km+KYI9X=frCt5=Y4vO)iL9`8skKY}@ zV_&`2$@kMDmxebbaw&KdBA0+yh@5~oCUP-&BO(`pcUa_x;SGyVyTT}3eMOP}mvyD> zJWZRnMiAsC4Gp7B*Jv3#1|RKaN8zg;GO;y+_PK{B%(;iuK~XEiY5L687~1JG_Fni% z>Y*gsNb%Mbg7g_X3m<*P&cLS|wIGt%PRhoKttqtE9jU?SA+2$#bip2mPYWW4TVn{) zLxu#}=ooffO4pbLI|W}QrnVqMR%;qTdcsfwZ5m~6-3xXEJ}sU6m9@DiD0`CkcDQ<; z-XlGoythRym|FtrZYQLbltyXs$?J@_4ngsuCg=ka^!q+MkOb{_6ZFZksgS^+Kv;Y> z5&{N+FdoHg+X`0(+*DJH^FR}?aHZdYnGBU-X4c`!l|wGiBRa)Y4}(b$tQ`y{J78_+ zd9a;Q>$P59-61AMI$-%(_+fRk=!O+!5roylf;hUS`#Oo*3G11k=jS@9QOQrHI;jd* z9bge~H0ouoSK4V}gm%(3t!)>lcfp$Xya4A>LW%EFOJ=1PQro4rZiko*(N~-Ru;MlC zcsCdT9yjBL3;-Xv0>H1U&Ll)$C3AUo#O766G4nej^6Gfc^UznnFUFVugnx1ofi#^e z0x(_*fdi}v-~gwa#pTr{?>?g% zW%9^I=4TisP!bre0?G)Cu_ptJ$&3<5S;+!NWnSs(saRHA;2`D2Wx}uI@k(&U==YTN zZ~2q`(!e}*m7yUy+LKiAEk0nE&4is?BI8FGGT#zPr$;0ih8*H@iiM0zS`mKRg$ z%xb}xSDjx(_fyU+FM`sU)uBpxM!yBSU*-NeSFJTJCjN2kd|2dpY1}RHyI~EA{9xtp zkjRH%^@)5REcN?heECl({1}|w|9;1FV3JD%^W3GGsDtC0A2%6wzU;!y>YEO3vExY> zZq;<$X2(~4+^+6uFy6KN?P8{Sa8rM-;%tuqulc;^fMnbuZ&~uT!z&iAEv}w!fn9vG z=mvJlydQn61OZaFVpuJJy!uG!1p}1VwqO9Wf)EolvkS%sh6ggF{XY-X35K&On4Jif zqTx<~Jq(RIfjv4-mU}9qVXr_xLt`({Up1^2Kt7kqK)YaoC0K#V70oFj4?4pNhuDS{ zjix^)dzr~D7cql#-V$4qI?=tug!$`s+^J5OahDz6yo$Ru9rxJrZ9DE&cNBi>pX}g% z^T~1piw&^aS+vWy`|(jWI<-X`(n)!Ib>G5bixj(Pf*R1stfl@27`rrLm(m$Jsg0#Q zXEO=CS$-o@U&Nf6;{0L^>7qP-lk&6Rm#t@MEv0kSL>nilR(h3TPx-LXPEyHa!=9=G zx{^KS+$^)l*ronir5RFb9w)V2yHTc={71+8OccLkQJpB_T&KWB0hy;UU6U{yfh~Zl zu*cn8Zo?*l?uwpG0H0Z%{zlQZ36#WZz-oiGQR|+A{P*8wlvEnm zHm+@4+qic5KJHws&Ba^3JE&&@6C+KGG%?b|NE0K~^Jv|y*ThH@BTbAnG1A0H6C?S> a&b&wJuS!_R=RfmFk>81*yAQSeRQ@0IP%oMQ literal 0 HcmV?d00001 diff --git a/tests/src/playdate_tests.nim b/tests/src/playdate_tests.nim index 1a7ecfa..ef68018 100644 --- a/tests/src/playdate_tests.nim +++ b/tests/src/playdate_tests.nim @@ -5,7 +5,7 @@ ## import playdate/api -import ../[t_buttons, t_graphics, t_nineslice, t_files] +import ../[t_buttons, t_graphics, t_nineslice, t_files, t_midi] proc runTests() {.raises: [].} = try: @@ -13,6 +13,7 @@ proc runTests() {.raises: [].} = execGraphicsTests(true) execNineSliceTests(true) execFilesTest() + execMidiTests(true) except Exception as e: quit(e.msg & "\n" & e.getStackTrace) diff --git a/tests/t_midi.nim b/tests/t_midi.nim new file mode 100644 index 0000000..fa4737b --- /dev/null +++ b/tests/t_midi.nim @@ -0,0 +1,27 @@ +import std/unittest, playdate/api + +proc execMidiTests*(runnable: bool) = + suite "Loading midi files": + + test "Creating sequences from files": + if runnable: + var sq = playdate.sound.sequence.newSequence() + sq.loadMIDIFile("deliberate_concealment.mid") + + sq.setTime(sq.getTime) + + check(sq.getLength == 132961) + check(sq.getCurrentStep() == 0) + + check(sq.getTempo() == 831.9986572265625) + sq.setTempo(900.0) + check(sq.getTempo() == 900.0) + + check(not sq.isPlaying) + sq.play + check(sq.isPlaying) + sq.stop + check(not sq.isPlaying) + + +execMidiTests(false) \ No newline at end of file From 25f8baad5cc0d428bde93750515e2fbfa1f871ae Mon Sep 17 00:00:00 2001 From: Samuele Zolfanelli Date: Tue, 1 Oct 2024 17:02:50 +0200 Subject: [PATCH 029/101] Fix SoundSequence finish callback incompatible pointer types on macOS --- src/playdate/bindings/sound.nim | 5 +++-- src/playdate/sound.nim | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/playdate/bindings/sound.nim b/src/playdate/bindings/sound.nim index dff9fbc..9edaabd 100644 --- a/src/playdate/bindings/sound.nim +++ b/src/playdate/bindings/sound.nim @@ -7,9 +7,10 @@ type AudioSamplePtr = pointer type SamplePlayerPtr = pointer type SoundSourceRaw {.importc: "SoundSource", header: "pd_api.h".} = object type SoundSourcePtr = ptr SoundSourceRaw -type SoundSequencePtr = pointer +type SoundSequenceRaw {.importc: "SoundSequence", header: "pd_api.h".} = object +type SoundSequencePtr = ptr SoundSequenceRaw -type SequenceFinishedCallback = proc(soundSource: SoundSourcePtr, userdata: pointer) {.cdecl.} +type SequenceFinishedCallback = proc(soundSource: SoundSequencePtr, userdata: pointer) {.cdecl.} type PDSndCallbackProcRaw {.importc: "sndCallbackProc", header: "pd_api.h".} = proc(soundSource: SoundSourcePtr, userdata: pointer) {.cdecl.} diff --git a/src/playdate/sound.nim b/src/playdate/sound.nim index 687415a..90cde0a 100644 --- a/src/playdate/sound.nim +++ b/src/playdate/sound.nim @@ -302,6 +302,8 @@ type SoundSequence* = ref SoundSequenceObj + PDSoundSequenceCallbackFunction* = proc(sequence: SoundSequence) {.raises: [].} + proc `=destroy`*(this: var SoundSequenceObj) = privateAccess(PlaydateSoundSequence) playdate.sound.sequence.freeSequence(this.resource) From 5216c666593410d6f1aaecbda29a102f37b41ea0 Mon Sep 17 00:00:00 2001 From: Samuele Zolfanelli Date: Tue, 1 Oct 2024 17:03:46 +0200 Subject: [PATCH 030/101] Update actions to Nim versions 2.0.8 and 1.6.20 --- .github/workflows/build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2aac1c5..1bc1c4b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,7 +8,7 @@ jobs: strategy: matrix: target: [ device, simulator ] - nim-version: [ 1.6.16, 2.0.2 ] + nim-version: [ 1.6.20, 2.0.8 ] steps: - uses: actions/checkout@v3 - uses: ./.github/actions/build-setup @@ -25,7 +25,7 @@ jobs: container: nimlang/choosenim strategy: matrix: - nim-version: [ 1.6.16, 2.0.2 ] + nim-version: [ 1.6.20, 2.0.8 ] steps: - uses: actions/checkout@v3 - uses: ./.github/actions/build-setup @@ -39,7 +39,7 @@ jobs: container: nimlang/choosenim strategy: matrix: - nim-version: [ 1.6.16, 2.0.2 ] + nim-version: [ 1.6.20, 2.0.8 ] steps: - uses: actions/checkout@v3 From efe0e2d58420fff061877dd707879b707a8edd29 Mon Sep 17 00:00:00 2001 From: Samuele Zolfanelli Date: Tue, 1 Oct 2024 17:27:14 +0200 Subject: [PATCH 031/101] Only support and test Nim 2.0+ --- .github/workflows/build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1bc1c4b..c5f6e02 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,7 +8,7 @@ jobs: strategy: matrix: target: [ device, simulator ] - nim-version: [ 1.6.20, 2.0.8 ] + nim-version: [ 2.0.8 ] steps: - uses: actions/checkout@v3 - uses: ./.github/actions/build-setup @@ -25,7 +25,7 @@ jobs: container: nimlang/choosenim strategy: matrix: - nim-version: [ 1.6.20, 2.0.8 ] + nim-version: [ 2.0.8 ] steps: - uses: actions/checkout@v3 - uses: ./.github/actions/build-setup @@ -39,7 +39,7 @@ jobs: container: nimlang/choosenim strategy: matrix: - nim-version: [ 1.6.20, 2.0.8 ] + nim-version: [ 2.0.8 ] steps: - uses: actions/checkout@v3 From 1a752d3bbd0c10382b90091b032e76512e05445d Mon Sep 17 00:00:00 2001 From: Samuele Zolfanelli Date: Tue, 1 Oct 2024 17:42:34 +0200 Subject: [PATCH 032/101] Update package version, Nim version requirement and README --- README.md | 6 +++--- playdate.nimble | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 37411c2..19f9293 100644 --- a/README.md +++ b/README.md @@ -32,8 +32,8 @@ This package is an independent bindings library, not affiliated with Panic. ### Prerequisites - Playdate SDK -- Nim 1.6.10+ or Nim 2+ ([recommended extension for VSCode](https://marketplace.visualstudio.com/items?itemName=nimsaem.nimvscode)) -- Nimble 0.13.1 (check with `nimble -v`) +- Nim 2+ ([recommended extension for VSCode](https://marketplace.visualstudio.com/items?itemName=NimLang.nimlang)) +- Nimble 0.14.2+ (check with `nimble -v`) - `PLAYDATE_SDK_PATH` environment variable - [SDK Prerequisites](https://sdk.play.date/Inside%20Playdate%20with%20C.html#_prerequisites) based on OS, and [MinGW on Windows](https://code.visualstudio.com/docs/cpp/config-mingw). @@ -175,7 +175,7 @@ except: --- This project is a work in progress, here's what is missing right now: -- various playdate.sound funcionalities (but FilePlayer and SamplePlayer are available) +- various playdate.sound funcionalities (but FilePlayer, SamplePlayer and SoundSequence are available) - playdate.json, but you can use Nim std/json, which is very convenient - advanced playdate.lua features, but basic Lua interop is available - playdate.scoreboards, undocumented even in the official C API docs diff --git a/playdate.nimble b/playdate.nimble index 7dc43d1..196ab55 100644 --- a/playdate.nimble +++ b/playdate.nimble @@ -1,6 +1,6 @@ # Package -version = "0.13.0" +version = "0.20.0" author = "Samuele Zolfanelli" description = "Playdate Nim bindings with extra features." license = "MIT" @@ -9,5 +9,5 @@ srcDir = "src" # Dependencies -requires "nim >= 1.6.10" +requires "nim >= 2.0.0" # requires "nimble < 0.14.0" From 520878232a97271fe595d1e1e0d2284eba667aae Mon Sep 17 00:00:00 2001 From: Samuele Zolfanelli Date: Sat, 12 Oct 2024 11:51:43 +0200 Subject: [PATCH 033/101] Fix setStencilImage not able to set stencil to nil, give default value to tile argument --- src/playdate/graphics.nim | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/playdate/graphics.nim b/src/playdate/graphics.nim index 5691420..76f877f 100644 --- a/src/playdate/graphics.nim +++ b/src/playdate/graphics.nim @@ -411,9 +411,12 @@ proc set*(this: var LCDBitmap, x, y: int, color: LCDSolidColor = kColorBlack) = var data = this.getData data.set(x, y, color) -proc setStencilImage*(this: ptr PlaydateGraphics, bitmap: LCDBitmap, tile: bool) = +proc setStencilImage*(this: ptr PlaydateGraphics, bitmap: LCDBitmap, tile: bool = false) = privateAccess(PlaydateGraphics) - this.setStencilImage(bitmap.resource, if tile: 1 else: 0) + if bitmap == nil: + this.setStencilImage(nil, if tile: 1 else: 0) + else: + this.setStencilImage(bitmap.resource, if tile: 1 else: 0) proc makeFont*(this: LCDFontData, wide: bool): LCDFont = privateAccess(PlaydateGraphics) From 321bb886991187c22658c88206b464fd0dee1fac Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Sat, 12 Oct 2024 22:59:34 +0200 Subject: [PATCH 034/101] FIX debug bitmap should not be free'd (#80) * FIX debug bitmap should not be free'd * ADD no-free comment to getDebugBitmap * ADD getDebugBitmap test --- src/playdate/graphics.nim | 2 +- tests/t_graphics.nim | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/playdate/graphics.nim b/src/playdate/graphics.nim index 76f877f..f7f934c 100644 --- a/src/playdate/graphics.nim +++ b/src/playdate/graphics.nim @@ -341,7 +341,7 @@ proc set*(view: var BitmapView, x, y: int, color: LCDSolidColor) = proc getDebugBitmap*(this: ptr PlaydateGraphics): LCDBitmap = privateAccess(PlaydateGraphics) - return LCDBitmap(resource: this.getDebugBitmap(), free: true) # Who should manage this memory? Not clear. Auto-managed. + return LCDBitmap(resource: this.getDebugBitmap(), free: false) # do not free: system owns this proc copyFrameBufferBitmap*(this: ptr PlaydateGraphics): LCDBitmap = privateAccess(PlaydateGraphics) diff --git a/tests/t_graphics.nim b/tests/t_graphics.nim index 3d2fe07..2702ba7 100644 --- a/tests/t_graphics.nim +++ b/tests/t_graphics.nim @@ -51,6 +51,12 @@ proc execGraphicsTests*(runnable: bool) = let img = playdate.graphics.newBitmap(10, 10, kColorWhite) discard playdate.graphics.createPattern(img, 0, 0) + test "DebugBitmap should not be freed after use": + if runnable: + discard playdate.graphics.getDebugBitmap() + # if the bitmap was freed, this would crash + discard playdate.graphics.getDebugBitmap() + test "Bitmaps should be loadable from files": if runnable: let img = playdate.graphics.newBitmap("boxes.png") From 476415b4858262195983381b13eeb30321a6cd52 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Sat, 19 Oct 2024 12:15:48 +0200 Subject: [PATCH 035/101] REMOVE scoreboards as missing feature from readme --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 19f9293..97552ae 100644 --- a/README.md +++ b/README.md @@ -178,4 +178,3 @@ This project is a work in progress, here's what is missing right now: - various playdate.sound funcionalities (but FilePlayer, SamplePlayer and SoundSequence are available) - playdate.json, but you can use Nim std/json, which is very convenient - advanced playdate.lua features, but basic Lua interop is available -- playdate.scoreboards, undocumented even in the official C API docs From 3bb03bd6f2675e193f5e95b9672d4ddd99974a72 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Sat, 19 Oct 2024 13:34:38 +0200 Subject: [PATCH 036/101] ADD expose scoreboards in api --- src/playdate/api.nim | 4 ++-- src/playdate/bindings/api.nim | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/playdate/api.nim b/src/playdate/api.nim index 80ad787..262eafc 100644 --- a/src/playdate/api.nim +++ b/src/playdate/api.nim @@ -6,8 +6,8 @@ import std/importutils import bindings/api export api -import graphics, system, file, sprite, display, sound, lua, json, utils, types, nineslice -export graphics, system, file, sprite, display, sound, lua, json, utils, types, nineslice +import graphics, system, file, sprite, display, sound, scoreboards, lua, json, utils, types, nineslice +export graphics, system, file, sprite, display, sound, scoreboards, lua, json, utils, types, nineslice macro initSDK*() = return quote do: diff --git a/src/playdate/bindings/api.nim b/src/playdate/bindings/api.nim index a86f0d1..e055675 100644 --- a/src/playdate/bindings/api.nim +++ b/src/playdate/bindings/api.nim @@ -1,6 +1,6 @@ {.push raises: [].} -import graphics, system, file, display, sprite, sound, lua +import graphics, system, file, display, sprite, sound, scoreboards, lua type PlaydateAPI* {.importc: "PlaydateAPI", header: "pd_api.h".} = object system* {.importc: "system".}: ptr PlaydateSys @@ -9,6 +9,7 @@ type PlaydateAPI* {.importc: "PlaydateAPI", header: "pd_api.h".} = object sprite* {.importc: "sprite".}: ptr PlaydateSprite display* {.importc: "display".}: ptr PlaydateDisplay sound* {.importc: "sound".}: ptr PlaydateSound + scoreboards* {.importc: "scoreboards".}: ptr PlaydateScoreboards lua* {.importc: "lua".}: ptr PlaydateLua # json* {.importc: "json".}: ptr PlaydateJSON # Unavailable, use std/json From 96d5e83f35666341b3d061a8dfb1d5a6bb697ef1 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Sat, 19 Oct 2024 13:35:17 +0200 Subject: [PATCH 037/101] ADD src/scorbeoards --- src/playdate/bindings/scoreboards.nim | 19 +++++++++------- src/playdate/scoreboards.nim | 31 +++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 8 deletions(-) create mode 100644 src/playdate/scoreboards.nim diff --git a/src/playdate/bindings/scoreboards.nim b/src/playdate/bindings/scoreboards.nim index 2af9ddb..82f8555 100644 --- a/src/playdate/bindings/scoreboards.nim +++ b/src/playdate/bindings/scoreboards.nim @@ -24,23 +24,26 @@ type PDBoardsList* {.importc: "PDBoardsList", header: "pd_api_scoreboards.h", by lastUpdated* {.importc: "lastUpdated".}: uint32 boards* {.importc: "boards".}: ptr PDBoard -type AddScoreCallback* = proc (score: ptr PDScore; errorMessage: cstring) {.cdecl.} -type PersonalBestCallback* = proc (score: ptr PDScore; errorMessage: cstring) {.cdecl.} -type BoardsListCallback* = proc (boards: ptr PDBoardsList; errorMessage: cstring) {.cdecl.} -type ScoresCallback* = proc (scores: ptr PDScoresList; errorMessage: cstring) {.cdecl.} + # todo register free functions + + +type AddScoreCallbackRaw* = proc (score: ptr PDScore; errorMessage: cstring) {.cdecl.} +type PersonalBestCallbackRaw* = proc (score: ptr PDScore; errorMessage: cstring) {.cdecl.} +type BoardsListCallbackRaw* = proc (boards: ptr PDBoardsList; errorMessage: cstring) {.cdecl.} +type ScoresCallbackRaw* = proc (scores: ptr PDScoresList; errorMessage: cstring) {.cdecl.} sdktype: type PlaydateScoreboards* {.importc: "const struct playdate_scoreboards", header: "pd_api.h".} = object addScore* {.importc: "addScore".}: proc (boardId: cstring; value: uint32; - callback: AddScoreCallback): cint {.cdecl.} + callback: AddScoreCallbackRaw): cint {.cdecl.} getPersonalBest* {.importc: "getPersonalBest".}: proc (boardId: cstring; - callback: PersonalBestCallback): cint {.cdecl.} + callback: PersonalBestCallbackRaw): cint {.cdecl.} freeScore* {.importc: "freeScore".}: proc (score: ptr PDScore) {.cdecl.} getScoreboards* {.importc: "getScoreboards".}: proc ( - callback: BoardsListCallback): cint {.cdecl.} + callback: BoardsListCallbackRaw): cint {.cdecl.} freeBoardsList* {.importc: "freeBoardsList".}: proc ( boardsList: ptr PDBoardsList) {.cdecl.} getScores* {.importc: "getScores".}: proc (boardId: cstring; - callback: ScoresCallback): cint {.cdecl.} + callback: ScoresCallbackRaw): cint {.cdecl.} freeScoresList* {.importc: "freeScoresList".}: proc ( scoresList: ptr PDScoresList) {.cdecl.} \ No newline at end of file diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim new file mode 100644 index 0000000..0b6f314 --- /dev/null +++ b/src/playdate/scoreboards.nim @@ -0,0 +1,31 @@ +{.push raises: [].} + +import std/importutils + +import system +import bindings/[api, types] +import bindings/scoreboards + +# Only export public symbols, then import all +export scoreboards +{.hint[DuplicateModuleImport]: off.} +import bindings/scoreboards {.all.} + +type + AddScoreCallback* = proc(score: ptr PDScore, errorMessage: string) + PersonalBestCallback* = proc(score: ptr PDScore, errorMessage: string) + BoardsListCallback* = proc(boards: ptr PDBoardsList, errorMessage: string) + ScoresCallback* = proc(scores: ptr PDScoresList, errorMessage: string) + +proc addScore*(this: ptr PlaydateScoreboards, boardID: string, value: uint32, callback: AddScoreCallback): int32 = + privateAccess(PlaydateScoreboards) +proc getPersonalBest*(this: ptr PlaydateScoreboards, boardID: string, callback: PersonalBestCallback): int32 = + privateAccess(PlaydateScoreboards) + +# proc freeScore*(score: ptr PDScore) +proc getScoreboards*(this: ptr PlaydateScoreboards, callback: BoardsListCallback): int32 = + privateAccess(PlaydateScoreboards) +# proc freeBoardsList*(boardsList: ptr PDBoardsList) +proc getScores*(this: ptr PlaydateScoreboards, boardID: string, callback: ScoresCallback): int32 = + privateAccess(PlaydateScoreboards) +# proc freeScoresList*(scoresList: ptr PDScoresList) \ No newline at end of file From b392079b46654e7e12866cd10790e9dd5dfd3417 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Sat, 19 Oct 2024 15:27:30 +0200 Subject: [PATCH 038/101] WIP Add getPersonalBest --- src/playdate/bindings/scoreboards.nim | 57 ++++++++++++++------------- src/playdate/scoreboards.nim | 32 +++++++++------ 2 files changed, 50 insertions(+), 39 deletions(-) diff --git a/src/playdate/bindings/scoreboards.nim b/src/playdate/bindings/scoreboards.nim index 82f8555..78701b4 100644 --- a/src/playdate/bindings/scoreboards.nim +++ b/src/playdate/bindings/scoreboards.nim @@ -2,48 +2,51 @@ import utils -type PDScore* {.importc: "PDScore", header: "pd_api_scoreboards.h", bycopy.} = object - rank* {.importc: "rank".}: uint32 - value* {.importc: "value".}: uint32 +type PDScoreRaw* {.importc: "PDScore", header: "pd_api.h", bycopy.} = object + rank* {.importc: "rank".}: cuint + value* {.importc: "value".}: cuint player* {.importc: "player".}: cstring -type PDScoresList* {.importc: "PDScoresList", header: "pd_api_scoreboards.h", bycopy.} = object +type PDScorePtr* = ptr PDScoreRaw +type PDScore* = ref PDScoreRaw + +type PDScoresListRaw* {.importc: "PDScoresList", header: "pd_api.h", bycopy.} = object boardID* {.importc: "boardID".}: cstring count* {.importc: "count".}: cuint - lastUpdated* {.importc: "lastUpdated".}: uint32 + lastUpdated* {.importc: "lastUpdated".}: cuint playerIncluded* {.importc: "playerIncluded".}: cint limit* {.importc: "limit".}: cuint - scores* {.importc: "scores".}: ptr PDScore + scores* {.importc: "scores".}: ptr PDScoreRaw -type PDBoard* {.importc: "PDBoard", header: "pd_api_scoreboards.h", bycopy.} = object +type PDBoardRaw* {.importc: "PDBoard", header: "pd_api.h", bycopy.} = object boardID* {.importc: "boardID".}: cstring name* {.importc: "name".}: cstring -type PDBoardsList* {.importc: "PDBoardsList", header: "pd_api_scoreboards.h", bycopy.} = object +type PDBoardsListRaw* {.importc: "PDBoardsList", header: "pd_api.h", bycopy.} = object count* {.importc: "count".}: cuint - lastUpdated* {.importc: "lastUpdated".}: uint32 - boards* {.importc: "boards".}: ptr PDBoard + lastUpdated* {.importc: "lastUpdated".}: cuint + boards* {.importc: "boards".}: ptr PDBoardRaw # todo register free functions -type AddScoreCallbackRaw* = proc (score: ptr PDScore; errorMessage: cstring) {.cdecl.} -type PersonalBestCallbackRaw* = proc (score: ptr PDScore; errorMessage: cstring) {.cdecl.} -type BoardsListCallbackRaw* = proc (boards: ptr PDBoardsList; errorMessage: cstring) {.cdecl.} -type ScoresCallbackRaw* = proc (scores: ptr PDScoresList; errorMessage: cstring) {.cdecl.} +type PersonalBestCallbackRaw* {.importc: "PersonalBestCallback", header: "pd_api.h".} = proc (score: PDScorePtr; errorMessage: cstring) {.cdecl.} +# type AddScoreCallbackRaw* = proc (score: ptr PDScoreRaw; errorMessage: cstring) {.cdecl.} +# type BoardsListCallbackRaw* = proc (boards: ptr PDBoardsListRaw; errorMessage: cstring) {.cdecl.} +# type ScoresCallbackRaw* = proc (scores: ptr PDScoresListRaw; errorMessage: cstring) {.cdecl.} sdktype: type PlaydateScoreboards* {.importc: "const struct playdate_scoreboards", header: "pd_api.h".} = object - addScore* {.importc: "addScore".}: proc (boardId: cstring; value: uint32; - callback: AddScoreCallbackRaw): cint {.cdecl.} - getPersonalBest* {.importc: "getPersonalBest".}: proc (boardId: cstring; - callback: PersonalBestCallbackRaw): cint {.cdecl.} - freeScore* {.importc: "freeScore".}: proc (score: ptr PDScore) {.cdecl.} - getScoreboards* {.importc: "getScoreboards".}: proc ( - callback: BoardsListCallbackRaw): cint {.cdecl.} - freeBoardsList* {.importc: "freeBoardsList".}: proc ( - boardsList: ptr PDBoardsList) {.cdecl.} - getScores* {.importc: "getScores".}: proc (boardId: cstring; - callback: ScoresCallbackRaw): cint {.cdecl.} - freeScoresList* {.importc: "freeScoresList".}: proc ( - scoresList: ptr PDScoresList) {.cdecl.} \ No newline at end of file + getPersonalBestBinding* {.importc: "getPersonalBest".}: proc (boardId: cstring; + callback: PersonalBestCallbackRaw): cint {.cdecl, raises: [].} + # addScore* {.importc: "addScore".}: proc (boardId: cstring; value: cuint; + # callback: AddScoreCallbackRaw): cint {.cdecl.} + # freeScore* {.importc: "freeScore".}: proc (score: ptr PDScore) {.cdecl.} + # getScoreboards* {.importc: "getScoreboards".}: proc ( + # callback: BoardsListCallbackRaw): cint {.cdecl.} + # freeBoardsList* {.importc: "freeBoardsList".}: proc ( + # boardsList: ptr PDBoardsList) {.cdecl.} + # getScores* {.importc: "getScores".}: proc (boardId: cstring; + # callback: ScoresCallbackRaw): cint {.cdecl.} + # freeScoresList* {.importc: "freeScoresList".}: proc ( + # scoresList: ptr PDScoresList) {.cdecl.} \ No newline at end of file diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index 0b6f314..4d4de51 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -12,20 +12,28 @@ export scoreboards import bindings/scoreboards {.all.} type - AddScoreCallback* = proc(score: ptr PDScore, errorMessage: string) - PersonalBestCallback* = proc(score: ptr PDScore, errorMessage: string) - BoardsListCallback* = proc(boards: ptr PDBoardsList, errorMessage: string) - ScoresCallback* = proc(scores: ptr PDScoresList, errorMessage: string) + # AddScoreCallback* = proc(score: ptr PDScore, errorMessage: string) + PersonalBestCallback* = proc(score: PDScore, errorMessage: string) + # BoardsListCallback* = proc(boards: ptr PDBoardsList, errorMessage: string) + # ScoresCallback* = proc(scores: ptr PDScoresList, errorMessage: string) + +var privatePersonalBestCallback: PersonalBestCallback + +proc invokePersonalBestCallback(score: PDScorePtr, errorMessage: cstring) {.cdecl, raises: [].} = + privatePersonalBestCallback(cast[PDScore](score), $errorMessage) + +# proc addScore*(this: ptr PlaydateScoreboards, boardID: string, value: uint32, callback: AddScoreCallback): int32 = +# privateAccess(PlaydateScoreboards) -proc addScore*(this: ptr PlaydateScoreboards, boardID: string, value: uint32, callback: AddScoreCallback): int32 = - privateAccess(PlaydateScoreboards) proc getPersonalBest*(this: ptr PlaydateScoreboards, boardID: string, callback: PersonalBestCallback): int32 = privateAccess(PlaydateScoreboards) + privatePersonalBestCallback = callback + return this.getPersonalBestBinding(boardID.cstring, invokePersonalBestCallback) # proc freeScore*(score: ptr PDScore) -proc getScoreboards*(this: ptr PlaydateScoreboards, callback: BoardsListCallback): int32 = - privateAccess(PlaydateScoreboards) -# proc freeBoardsList*(boardsList: ptr PDBoardsList) -proc getScores*(this: ptr PlaydateScoreboards, boardID: string, callback: ScoresCallback): int32 = - privateAccess(PlaydateScoreboards) -# proc freeScoresList*(scoresList: ptr PDScoresList) \ No newline at end of file +# proc getScoreboards*(this: ptr PlaydateScoreboards, callback: BoardsListCallback): int32 = +# privateAccess(PlaydateScoreboards) +# # proc freeBoardsList*(boardsList: ptr PDBoardsList) +# proc getScores*(this: ptr PlaydateScoreboards, boardID: string, callback: ScoresCallback): int32 = +# privateAccess(PlaydateScoreboards) +# # proc freeScoresList*(scoresList: ptr PDScoresList) \ No newline at end of file From 3068e0f528e99aeb859cdb2708de57b0ffe461cd Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Sat, 19 Oct 2024 18:25:36 +0200 Subject: [PATCH 039/101] FIX scoreboards invokeCallback signature --- src/playdate/scoreboards.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index 4d4de51..a9881a0 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -19,7 +19,7 @@ type var privatePersonalBestCallback: PersonalBestCallback -proc invokePersonalBestCallback(score: PDScorePtr, errorMessage: cstring) {.cdecl, raises: [].} = +proc invokePersonalBestCallback(score: PDScorePtr, errorMessage: ConstChar) {.cdecl, raises: [].} = privatePersonalBestCallback(cast[PDScore](score), $errorMessage) # proc addScore*(this: ptr PlaydateScoreboards, boardID: string, value: uint32, callback: AddScoreCallback): int32 = From e07b3438856e608e9a525a22bdc1ada3bf30995a Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Sat, 19 Oct 2024 20:15:56 +0200 Subject: [PATCH 040/101] FIX crash and use domain Score --- src/playdate/bindings/scoreboards.nim | 4 ++-- src/playdate/scoreboards.nim | 22 +++++++++++++++++++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/playdate/bindings/scoreboards.nim b/src/playdate/bindings/scoreboards.nim index 78701b4..019df0f 100644 --- a/src/playdate/bindings/scoreboards.nim +++ b/src/playdate/bindings/scoreboards.nim @@ -8,7 +8,7 @@ type PDScoreRaw* {.importc: "PDScore", header: "pd_api.h", bycopy.} = object player* {.importc: "player".}: cstring type PDScorePtr* = ptr PDScoreRaw -type PDScore* = ref PDScoreRaw +# type PDScore* = ref PDScoreRaw type PDScoresListRaw* {.importc: "PDScoresList", header: "pd_api.h", bycopy.} = object boardID* {.importc: "boardID".}: cstring @@ -39,9 +39,9 @@ sdktype: type PlaydateScoreboards* {.importc: "const struct playdate_scoreboards", header: "pd_api.h".} = object getPersonalBestBinding* {.importc: "getPersonalBest".}: proc (boardId: cstring; callback: PersonalBestCallbackRaw): cint {.cdecl, raises: [].} + freeScore* {.importc: "freeScore".}: proc (score: PDScorePtr) {.cdecl, raises: [].} # addScore* {.importc: "addScore".}: proc (boardId: cstring; value: cuint; # callback: AddScoreCallbackRaw): cint {.cdecl.} - # freeScore* {.importc: "freeScore".}: proc (score: ptr PDScore) {.cdecl.} # getScoreboards* {.importc: "getScoreboards".}: proc ( # callback: BoardsListCallbackRaw): cint {.cdecl.} # freeBoardsList* {.importc: "freeBoardsList".}: proc ( diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index a9881a0..281559b 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -11,6 +11,20 @@ export scoreboards {.hint[DuplicateModuleImport]: off.} import bindings/scoreboards {.all.} +# type PDScoreObj = object of RootObj +# # resource {.requiresinit.}: PDScorePtr +# rank*: int32 +# value*: int32 +# player*: string + +# proc `=destroy`(this: PDScoreObj) = +# privateaccess(PlaydateScoreboards) +# playdate.scoreboards.freeScore(this.resource) +type PDScore* = object of RootObj + value*: int32 + rank*: int32 + player*: string + type # AddScoreCallback* = proc(score: ptr PDScore, errorMessage: string) PersonalBestCallback* = proc(score: PDScore, errorMessage: string) @@ -20,7 +34,13 @@ type var privatePersonalBestCallback: PersonalBestCallback proc invokePersonalBestCallback(score: PDScorePtr, errorMessage: ConstChar) {.cdecl, raises: [].} = - privatePersonalBestCallback(cast[PDScore](score), $errorMessage) + if errorMessage != nil: + privatePersonalBestCallback(PDScore(value: 0, rank: 0, player: ""), $errorMessage) + return + + let domainScore = PDScore(value: score.value.int32, rank: score.rank.int32, player: $score.player) + playdate.scoreboards.freeScore(score) + privatePersonalBestCallback(domainScore, $errorMessage) # proc addScore*(this: ptr PlaydateScoreboards, boardID: string, value: uint32, callback: AddScoreCallback): int32 = # privateAccess(PlaydateScoreboards) From bdbfa3dad673e05c497701d6b5bc89e24d6c041f Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Sat, 19 Oct 2024 22:27:57 +0200 Subject: [PATCH 041/101] CHANGE use domain models for score and add addScore --- src/playdate/bindings/scoreboards.nim | 9 +++------ src/playdate/scoreboards.nim | 25 ++++++++++++++++++------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/playdate/bindings/scoreboards.nim b/src/playdate/bindings/scoreboards.nim index 019df0f..8e69c41 100644 --- a/src/playdate/bindings/scoreboards.nim +++ b/src/playdate/bindings/scoreboards.nim @@ -27,11 +27,8 @@ type PDBoardsListRaw* {.importc: "PDBoardsList", header: "pd_api.h", bycopy.} = lastUpdated* {.importc: "lastUpdated".}: cuint boards* {.importc: "boards".}: ptr PDBoardRaw - # todo register free functions - - type PersonalBestCallbackRaw* {.importc: "PersonalBestCallback", header: "pd_api.h".} = proc (score: PDScorePtr; errorMessage: cstring) {.cdecl.} -# type AddScoreCallbackRaw* = proc (score: ptr PDScoreRaw; errorMessage: cstring) {.cdecl.} +type AddScoreCallbackRaw* {.importc: "AddScoreCallback", header: "pd_api.h".} = proc (score: PDScorePtr; errorMessage: cstring) {.cdecl.} # type BoardsListCallbackRaw* = proc (boards: ptr PDBoardsListRaw; errorMessage: cstring) {.cdecl.} # type ScoresCallbackRaw* = proc (scores: ptr PDScoresListRaw; errorMessage: cstring) {.cdecl.} @@ -39,9 +36,9 @@ sdktype: type PlaydateScoreboards* {.importc: "const struct playdate_scoreboards", header: "pd_api.h".} = object getPersonalBestBinding* {.importc: "getPersonalBest".}: proc (boardId: cstring; callback: PersonalBestCallbackRaw): cint {.cdecl, raises: [].} + addScoreBinding* {.importc: "addScore".}: proc (boardId: cstring; value: cuint; + callback: AddScoreCallbackRaw): cint {.cdecl, raises: [].} freeScore* {.importc: "freeScore".}: proc (score: PDScorePtr) {.cdecl, raises: [].} - # addScore* {.importc: "addScore".}: proc (boardId: cstring; value: cuint; - # callback: AddScoreCallbackRaw): cint {.cdecl.} # getScoreboards* {.importc: "getScoreboards".}: proc ( # callback: BoardsListCallbackRaw): cint {.cdecl.} # freeBoardsList* {.importc: "freeBoardsList".}: proc ( diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index 281559b..a4792f6 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -21,36 +21,47 @@ import bindings/scoreboards {.all.} # privateaccess(PlaydateScoreboards) # playdate.scoreboards.freeScore(this.resource) type PDScore* = object of RootObj - value*: int32 - rank*: int32 + value*: uint32 + rank*: uint32 player*: string type - # AddScoreCallback* = proc(score: ptr PDScore, errorMessage: string) PersonalBestCallback* = proc(score: PDScore, errorMessage: string) + AddScoreCallback* = proc(score: PDScore, errorMessage: string) # BoardsListCallback* = proc(boards: ptr PDBoardsList, errorMessage: string) # ScoresCallback* = proc(scores: ptr PDScoresList, errorMessage: string) var privatePersonalBestCallback: PersonalBestCallback +var privateAddScoreCallback: AddScoreCallback proc invokePersonalBestCallback(score: PDScorePtr, errorMessage: ConstChar) {.cdecl, raises: [].} = if errorMessage != nil: privatePersonalBestCallback(PDScore(value: 0, rank: 0, player: ""), $errorMessage) return - let domainScore = PDScore(value: score.value.int32, rank: score.rank.int32, player: $score.player) + let domainScore = PDScore(value: score.value.uint32, rank: score.rank.uint32, player: $score.player) playdate.scoreboards.freeScore(score) privatePersonalBestCallback(domainScore, $errorMessage) -# proc addScore*(this: ptr PlaydateScoreboards, boardID: string, value: uint32, callback: AddScoreCallback): int32 = -# privateAccess(PlaydateScoreboards) +proc invokeAddScoreCallback(score: PDScorePtr, errorMessage: ConstChar) {.cdecl, raises: [].} = + if errorMessage != nil: + privateAddScoreCallback(PDScore(value: 0, rank: 0, player: ""), $errorMessage) + return + + let domainScore = PDScore(value: score.value.uint32, rank: score.rank.uint32, player: $score.player) + playdate.scoreboards.freeScore(score) + privateAddScoreCallback(domainScore, $errorMessage) proc getPersonalBest*(this: ptr PlaydateScoreboards, boardID: string, callback: PersonalBestCallback): int32 = privateAccess(PlaydateScoreboards) privatePersonalBestCallback = callback return this.getPersonalBestBinding(boardID.cstring, invokePersonalBestCallback) -# proc freeScore*(score: ptr PDScore) +proc addScore*(this: ptr PlaydateScoreboards, boardID: string, value: int32, callback: AddScoreCallback): int32 = + privateAccess(PlaydateScoreboards) + privateAddScoreCallback = callback + return this.addScoreBinding(boardID.cstring, value.uint32, invokeAddScoreCallback) + # proc getScoreboards*(this: ptr PlaydateScoreboards, callback: BoardsListCallback): int32 = # privateAccess(PlaydateScoreboards) # # proc freeBoardsList*(boardsList: ptr PDBoardsList) From 2249683daa877a448b0e8e7c23f3c71394641879 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Sat, 19 Oct 2024 23:44:33 +0200 Subject: [PATCH 042/101] CHANGE int32 to uint32 for addScore --- src/playdate/scoreboards.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index a4792f6..0299a8c 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -57,10 +57,10 @@ proc getPersonalBest*(this: ptr PlaydateScoreboards, boardID: string, callback: privatePersonalBestCallback = callback return this.getPersonalBestBinding(boardID.cstring, invokePersonalBestCallback) -proc addScore*(this: ptr PlaydateScoreboards, boardID: string, value: int32, callback: AddScoreCallback): int32 = +proc addScore*(this: ptr PlaydateScoreboards, boardID: string, value: uint32, callback: AddScoreCallback): int32 = privateAccess(PlaydateScoreboards) privateAddScoreCallback = callback - return this.addScoreBinding(boardID.cstring, value.uint32, invokeAddScoreCallback) + return this.addScoreBinding(boardID.cstring, value.cuint, invokeAddScoreCallback) # proc getScoreboards*(this: ptr PlaydateScoreboards, callback: BoardsListCallback): int32 = # privateAccess(PlaydateScoreboards) From 3d85dc8ea2b1df3b217e43ccba861c2aa878e975 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Tue, 22 Oct 2024 13:48:54 +0200 Subject: [PATCH 043/101] FIX guard against nil score in getPersonalBest --- src/playdate/scoreboards.nim | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index 0299a8c..57a80d6 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -38,6 +38,10 @@ proc invokePersonalBestCallback(score: PDScorePtr, errorMessage: ConstChar) {.cd if errorMessage != nil: privatePersonalBestCallback(PDScore(value: 0, rank: 0, player: ""), $errorMessage) return + + if score == nil: + privatePersonalBestCallback(PDScore(), "Playdate-nim: No personal best") + return let domainScore = PDScore(value: score.value.uint32, rank: score.rank.uint32, player: $score.player) playdate.scoreboards.freeScore(score) From e8f2304cf868b6675c57fc630b605b22f93841e0 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Thu, 24 Oct 2024 11:43:55 +0200 Subject: [PATCH 044/101] ADD getScores (domain approach) --- src/playdate/bindings/scoreboards.nim | 14 +++--- src/playdate/scoreboards.nim | 69 ++++++++++++++++++++++----- 2 files changed, 66 insertions(+), 17 deletions(-) diff --git a/src/playdate/bindings/scoreboards.nim b/src/playdate/bindings/scoreboards.nim index 8e69c41..917111f 100644 --- a/src/playdate/bindings/scoreboards.nim +++ b/src/playdate/bindings/scoreboards.nim @@ -14,10 +14,12 @@ type PDScoresListRaw* {.importc: "PDScoresList", header: "pd_api.h", bycopy.} = boardID* {.importc: "boardID".}: cstring count* {.importc: "count".}: cuint lastUpdated* {.importc: "lastUpdated".}: cuint - playerIncluded* {.importc: "playerIncluded".}: cint + playerIncluded* {.importc: "playerIncluded".}: cuint limit* {.importc: "limit".}: cuint scores* {.importc: "scores".}: ptr PDScoreRaw +type PDScoresListPtr* = ptr PDScoresListRaw + type PDBoardRaw* {.importc: "PDBoard", header: "pd_api.h", bycopy.} = object boardID* {.importc: "boardID".}: cstring name* {.importc: "name".}: cstring @@ -30,7 +32,7 @@ type PDBoardsListRaw* {.importc: "PDBoardsList", header: "pd_api.h", bycopy.} = type PersonalBestCallbackRaw* {.importc: "PersonalBestCallback", header: "pd_api.h".} = proc (score: PDScorePtr; errorMessage: cstring) {.cdecl.} type AddScoreCallbackRaw* {.importc: "AddScoreCallback", header: "pd_api.h".} = proc (score: PDScorePtr; errorMessage: cstring) {.cdecl.} # type BoardsListCallbackRaw* = proc (boards: ptr PDBoardsListRaw; errorMessage: cstring) {.cdecl.} -# type ScoresCallbackRaw* = proc (scores: ptr PDScoresListRaw; errorMessage: cstring) {.cdecl.} +type ScoresCallbackRaw* = proc (scores: ptr PDScoresListRaw; errorMessage: cstring) {.cdecl.} sdktype: type PlaydateScoreboards* {.importc: "const struct playdate_scoreboards", header: "pd_api.h".} = object @@ -43,7 +45,7 @@ sdktype: # callback: BoardsListCallbackRaw): cint {.cdecl.} # freeBoardsList* {.importc: "freeBoardsList".}: proc ( # boardsList: ptr PDBoardsList) {.cdecl.} - # getScores* {.importc: "getScores".}: proc (boardId: cstring; - # callback: ScoresCallbackRaw): cint {.cdecl.} - # freeScoresList* {.importc: "freeScoresList".}: proc ( - # scoresList: ptr PDScoresList) {.cdecl.} \ No newline at end of file + getScoresBinding* {.importc: "getScores".}: proc (boardId: cstring; + callback: ScoresCallbackRaw): cint {.cdecl, raises: [].} + freeScoresList* {.importc: "freeScoresList".}: proc ( + scoresList: PDScoresListPtr) {.cdecl, raises: [].} \ No newline at end of file diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index 57a80d6..40286ca 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -2,7 +2,7 @@ import std/importutils -import system +import types {.all.} import bindings/[api, types] import bindings/scoreboards @@ -25,40 +25,86 @@ type PDScore* = object of RootObj rank*: uint32 player*: string +type PDScoresList* = object of RootObj + boardID*: string + lastUpdated*: uint32 + scores*: seq[PDScore] + # these properties are not implemented yet in the Playdate API + # playerIncluded*: uint32 + # limit*: uint32 + type PersonalBestCallback* = proc(score: PDScore, errorMessage: string) AddScoreCallback* = proc(score: PDScore, errorMessage: string) # BoardsListCallback* = proc(boards: ptr PDBoardsList, errorMessage: string) - # ScoresCallback* = proc(scores: ptr PDScoresList, errorMessage: string) + ScoresCallback* = proc(scores: PDScoresList, errorMessage: string) -var privatePersonalBestCallback: PersonalBestCallback +var privatePersonalBestCallbacks = newSeq[PersonalBestCallback]() var privateAddScoreCallback: AddScoreCallback +var privateScoresCallbacks = newSeq[ScoresCallback]() + +proc newPDScoresList(boardID: string, lastUpdated: uint32, scores: seq[PDScore]): PDScoresList = + result.boardID = boardID + result.lastUpdated = lastUpdated + result.scores = scores proc invokePersonalBestCallback(score: PDScorePtr, errorMessage: ConstChar) {.cdecl, raises: [].} = - if errorMessage != nil: - privatePersonalBestCallback(PDScore(value: 0, rank: 0, player: ""), $errorMessage) + let callback = privatePersonalBestCallbacks.pop() # first in, first out + if score == nil and errorMessage == nil: + callback(PDScore(), "Playdate-nim: No personal best") return if score == nil: - privatePersonalBestCallback(PDScore(), "Playdate-nim: No personal best") + callback(PDScore(), $errorMessage) return let domainScore = PDScore(value: score.value.uint32, rank: score.rank.uint32, player: $score.player) playdate.scoreboards.freeScore(score) - privatePersonalBestCallback(domainScore, $errorMessage) + callback(domainScore, $errorMessage) proc invokeAddScoreCallback(score: PDScorePtr, errorMessage: ConstChar) {.cdecl, raises: [].} = if errorMessage != nil: privateAddScoreCallback(PDScore(value: 0, rank: 0, player: ""), $errorMessage) return + # todo create newPDSCore constructor let domainScore = PDScore(value: score.value.uint32, rank: score.rank.uint32, player: $score.player) playdate.scoreboards.freeScore(score) privateAddScoreCallback(domainScore, $errorMessage) +proc invokeScoresCallback(scoresList: PDScoresListPtr, errorMessage: ConstChar) {.cdecl, raises: [].} = + privateAccess(PlaydateScoreboards) + let callback = privateScoresCallbacks.pop() # first in, first out + if scoresList == nil and errorMessage == nil: + let domainObject = newPDScoresList(boardID = "", lastUpdated = 0, scores = @[]) + callback(domainObject, "Playdate-nim: No scores") + return + + if scoresList == nil: + let domainObject = newPDScoresList(boardID = "", lastUpdated = 0, scores = @[]) + callback(domainObject, $errorMessage) + return + + privateAccess(SDKArray) + let length = scoresList.count.cint + let cArray = SDKArray[PDScoreRaw](data: cast[ptr UncheckedArray[PDScoreRaw]](scoresList.scores), len: length) + + var scoresSeq = newSeq[PDScore](length) + for i in 0 ..< length: + let score = cArray[i] + scoresSeq[i] = PDScore(value: score.value.uint32, rank: score.rank.uint32, player: $score.player) + + # todo enabling this cleanup code freezes the simulator. Should we free individual scores? With or without: both freeze + # for i in 0 ..< length: + # playdate.scoreboards.freeScore(addr cArray[i]) + # playdate.scoreboards.freeScoresList(scoresList) + + let domainObject = newPDScoresList(boardID = $scoresList.boardID, lastUpdated = scoresList.lastUpdated, scores = scoresSeq) + callback(domainObject, $errorMessage) + proc getPersonalBest*(this: ptr PlaydateScoreboards, boardID: string, callback: PersonalBestCallback): int32 = privateAccess(PlaydateScoreboards) - privatePersonalBestCallback = callback + privatePersonalBestCallbacks.insert(callback) return this.getPersonalBestBinding(boardID.cstring, invokePersonalBestCallback) proc addScore*(this: ptr PlaydateScoreboards, boardID: string, value: uint32, callback: AddScoreCallback): int32 = @@ -69,6 +115,7 @@ proc addScore*(this: ptr PlaydateScoreboards, boardID: string, value: uint32, ca # proc getScoreboards*(this: ptr PlaydateScoreboards, callback: BoardsListCallback): int32 = # privateAccess(PlaydateScoreboards) # # proc freeBoardsList*(boardsList: ptr PDBoardsList) -# proc getScores*(this: ptr PlaydateScoreboards, boardID: string, callback: ScoresCallback): int32 = -# privateAccess(PlaydateScoreboards) -# # proc freeScoresList*(scoresList: ptr PDScoresList) \ No newline at end of file +proc getScores*(this: ptr PlaydateScoreboards, boardID: string, callback: ScoresCallback): int32 = + privateAccess(PlaydateScoreboards) + privateScoresCallbacks.insert(callback) + return this.getScoresBinding(boardID.cstring, invokeScoresCallback) \ No newline at end of file From 80dc3a13e95094af58f5600bcf1b5adaab9757d3 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Thu, 24 Oct 2024 12:18:28 +0200 Subject: [PATCH 045/101] ADD free for individual scores and fix use after free --- src/playdate/scoreboards.nim | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index 40286ca..d202e6b 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -94,13 +94,14 @@ proc invokeScoresCallback(scoresList: PDScoresListPtr, errorMessage: ConstChar) let score = cArray[i] scoresSeq[i] = PDScore(value: score.value.uint32, rank: score.rank.uint32, player: $score.player) - # todo enabling this cleanup code freezes the simulator. Should we free individual scores? With or without: both freeze - # for i in 0 ..< length: - # playdate.scoreboards.freeScore(addr cArray[i]) - # playdate.scoreboards.freeScoresList(scoresList) + for i in 0 ..< length: + playdate.scoreboards.freeScore(addr cArray[i]) + cArray.data = nil let domainObject = newPDScoresList(boardID = $scoresList.boardID, lastUpdated = scoresList.lastUpdated, scores = scoresSeq) callback(domainObject, $errorMessage) + # todo enabling this cleanup code freezes the simulator. In this correct to free individual score first, right? + # playdate.scoreboards.freeScoresList(scoresList) proc getPersonalBest*(this: ptr PlaydateScoreboards, boardID: string, callback: PersonalBestCallback): int32 = privateAccess(PlaydateScoreboards) From c9408c42158a5bb3daf4afbf59a888b48a94a295 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Thu, 24 Oct 2024 13:23:12 +0200 Subject: [PATCH 046/101] FIX freeScoresList --- src/playdate/scoreboards.nim | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index d202e6b..1e427b4 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -88,20 +88,15 @@ proc invokeScoresCallback(scoresList: PDScoresListPtr, errorMessage: ConstChar) privateAccess(SDKArray) let length = scoresList.count.cint let cArray = SDKArray[PDScoreRaw](data: cast[ptr UncheckedArray[PDScoreRaw]](scoresList.scores), len: length) - var scoresSeq = newSeq[PDScore](length) for i in 0 ..< length: let score = cArray[i] scoresSeq[i] = PDScore(value: score.value.uint32, rank: score.rank.uint32, player: $score.player) - - for i in 0 ..< length: - playdate.scoreboards.freeScore(addr cArray[i]) - cArray.data = nil + cArray.data = nil # no need for SDKArray to free the data, freeScoresList() will do it let domainObject = newPDScoresList(boardID = $scoresList.boardID, lastUpdated = scoresList.lastUpdated, scores = scoresSeq) callback(domainObject, $errorMessage) - # todo enabling this cleanup code freezes the simulator. In this correct to free individual score first, right? - # playdate.scoreboards.freeScoresList(scoresList) + playdate.scoreboards.freeScoresList(scoresList) proc getPersonalBest*(this: ptr PlaydateScoreboards, boardID: string, callback: PersonalBestCallback): int32 = privateAccess(PlaydateScoreboards) From c9f3d26abcc81ef905f49ab331bd800902b9b644 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Thu, 24 Oct 2024 13:30:32 +0200 Subject: [PATCH 047/101] ADD newPDScore constructor --- src/playdate/scoreboards.nim | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index 1e427b4..beca4cc 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -11,15 +11,6 @@ export scoreboards {.hint[DuplicateModuleImport]: off.} import bindings/scoreboards {.all.} -# type PDScoreObj = object of RootObj -# # resource {.requiresinit.}: PDScorePtr -# rank*: int32 -# value*: int32 -# player*: string - -# proc `=destroy`(this: PDScoreObj) = -# privateaccess(PlaydateScoreboards) -# playdate.scoreboards.freeScore(this.resource) type PDScore* = object of RootObj value*: uint32 rank*: uint32 @@ -43,6 +34,11 @@ var privatePersonalBestCallbacks = newSeq[PersonalBestCallback]() var privateAddScoreCallback: AddScoreCallback var privateScoresCallbacks = newSeq[ScoresCallback]() +proc newPDScore(value: uint32, rank: uint32, player: string): PDScore = + result.value = value + result.rank = rank + result.player = player + proc newPDScoresList(boardID: string, lastUpdated: uint32, scores: seq[PDScore]): PDScoresList = result.boardID = boardID result.lastUpdated = lastUpdated @@ -51,24 +47,23 @@ proc newPDScoresList(boardID: string, lastUpdated: uint32, scores: seq[PDScore]) proc invokePersonalBestCallback(score: PDScorePtr, errorMessage: ConstChar) {.cdecl, raises: [].} = let callback = privatePersonalBestCallbacks.pop() # first in, first out if score == nil and errorMessage == nil: - callback(PDScore(), "Playdate-nim: No personal best") + callback(newPDScore(value = 0, rank = 0, player = ""), "Playdate-nim: No personal best") return if score == nil: - callback(PDScore(), $errorMessage) + callback(newPDScore(value = 0, rank = 0, player = ""), $errorMessage) return - let domainScore = PDScore(value: score.value.uint32, rank: score.rank.uint32, player: $score.player) + let domainScore = newPDScore(value = score.value.uint32, rank = score.rank.uint32, player = $score.player) playdate.scoreboards.freeScore(score) callback(domainScore, $errorMessage) proc invokeAddScoreCallback(score: PDScorePtr, errorMessage: ConstChar) {.cdecl, raises: [].} = if errorMessage != nil: - privateAddScoreCallback(PDScore(value: 0, rank: 0, player: ""), $errorMessage) + privateAddScoreCallback(newPDScore(value = 0, rank = 0, player = ""), $errorMessage) return - # todo create newPDSCore constructor - let domainScore = PDScore(value: score.value.uint32, rank: score.rank.uint32, player: $score.player) + let domainScore = newPDScore(value = score.value.uint32, rank = score.rank.uint32, player = $score.player) playdate.scoreboards.freeScore(score) privateAddScoreCallback(domainScore, $errorMessage) From 60ba05dd47661c546d8c97fc34d292dc31288445 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Thu, 24 Oct 2024 13:35:06 +0200 Subject: [PATCH 048/101] FIX use a seq of callbacks for addScore --- src/playdate/scoreboards.nim | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index beca4cc..d10614b 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -31,7 +31,7 @@ type ScoresCallback* = proc(scores: PDScoresList, errorMessage: string) var privatePersonalBestCallbacks = newSeq[PersonalBestCallback]() -var privateAddScoreCallback: AddScoreCallback +var privateAddScoreCallbacks = newSeq[AddScoreCallback]() var privateScoresCallbacks = newSeq[ScoresCallback]() proc newPDScore(value: uint32, rank: uint32, player: string): PDScore = @@ -59,13 +59,14 @@ proc invokePersonalBestCallback(score: PDScorePtr, errorMessage: ConstChar) {.cd callback(domainScore, $errorMessage) proc invokeAddScoreCallback(score: PDScorePtr, errorMessage: ConstChar) {.cdecl, raises: [].} = + let callback = privateAddScoreCallbacks.pop() # first in, first out if errorMessage != nil: - privateAddScoreCallback(newPDScore(value = 0, rank = 0, player = ""), $errorMessage) + callback(newPDScore(value = 0, rank = 0, player = ""), $errorMessage) return let domainScore = newPDScore(value = score.value.uint32, rank = score.rank.uint32, player = $score.player) playdate.scoreboards.freeScore(score) - privateAddScoreCallback(domainScore, $errorMessage) + callback(domainScore, $errorMessage) proc invokeScoresCallback(scoresList: PDScoresListPtr, errorMessage: ConstChar) {.cdecl, raises: [].} = privateAccess(PlaydateScoreboards) @@ -95,12 +96,12 @@ proc invokeScoresCallback(scoresList: PDScoresListPtr, errorMessage: ConstChar) proc getPersonalBest*(this: ptr PlaydateScoreboards, boardID: string, callback: PersonalBestCallback): int32 = privateAccess(PlaydateScoreboards) - privatePersonalBestCallbacks.insert(callback) + privatePersonalBestCallbacks.insert(callback) # by inserting the callback at the start, it will be popped last: first in, first out return this.getPersonalBestBinding(boardID.cstring, invokePersonalBestCallback) proc addScore*(this: ptr PlaydateScoreboards, boardID: string, value: uint32, callback: AddScoreCallback): int32 = privateAccess(PlaydateScoreboards) - privateAddScoreCallback = callback + privateAddScoreCallbacks.insert(callback) # by inserting the callback at the start, it will be popped last: first in, first out return this.addScoreBinding(boardID.cstring, value.cuint, invokeAddScoreCallback) # proc getScoreboards*(this: ptr PlaydateScoreboards, callback: BoardsListCallback): int32 = @@ -108,5 +109,5 @@ proc addScore*(this: ptr PlaydateScoreboards, boardID: string, value: uint32, ca # # proc freeBoardsList*(boardsList: ptr PDBoardsList) proc getScores*(this: ptr PlaydateScoreboards, boardID: string, callback: ScoresCallback): int32 = privateAccess(PlaydateScoreboards) - privateScoresCallbacks.insert(callback) + privateScoresCallbacks.insert(callback) # by inserting the callback at the start, it will be popped last: first in, first out return this.getScoresBinding(boardID.cstring, invokeScoresCallback) \ No newline at end of file From 9e3f3a3b7aaa51b425847551ead93ce2ff90f10b Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Thu, 24 Oct 2024 13:58:13 +0200 Subject: [PATCH 049/101] ADD getScoreBoards call --- src/playdate/bindings/scoreboards.nim | 12 ++--- src/playdate/scoreboards.nim | 68 ++++++++++++++++++++++----- 2 files changed, 62 insertions(+), 18 deletions(-) diff --git a/src/playdate/bindings/scoreboards.nim b/src/playdate/bindings/scoreboards.nim index 917111f..29307e7 100644 --- a/src/playdate/bindings/scoreboards.nim +++ b/src/playdate/bindings/scoreboards.nim @@ -17,7 +17,6 @@ type PDScoresListRaw* {.importc: "PDScoresList", header: "pd_api.h", bycopy.} = playerIncluded* {.importc: "playerIncluded".}: cuint limit* {.importc: "limit".}: cuint scores* {.importc: "scores".}: ptr PDScoreRaw - type PDScoresListPtr* = ptr PDScoresListRaw type PDBoardRaw* {.importc: "PDBoard", header: "pd_api.h", bycopy.} = object @@ -28,10 +27,11 @@ type PDBoardsListRaw* {.importc: "PDBoardsList", header: "pd_api.h", bycopy.} = count* {.importc: "count".}: cuint lastUpdated* {.importc: "lastUpdated".}: cuint boards* {.importc: "boards".}: ptr PDBoardRaw +type PDBoardsListPtr* = ptr PDBoardsListRaw type PersonalBestCallbackRaw* {.importc: "PersonalBestCallback", header: "pd_api.h".} = proc (score: PDScorePtr; errorMessage: cstring) {.cdecl.} type AddScoreCallbackRaw* {.importc: "AddScoreCallback", header: "pd_api.h".} = proc (score: PDScorePtr; errorMessage: cstring) {.cdecl.} -# type BoardsListCallbackRaw* = proc (boards: ptr PDBoardsListRaw; errorMessage: cstring) {.cdecl.} +type BoardsListCallbackRaw* = proc (boards: ptr PDBoardsListRaw; errorMessage: cstring) {.cdecl.} type ScoresCallbackRaw* = proc (scores: ptr PDScoresListRaw; errorMessage: cstring) {.cdecl.} sdktype: @@ -41,10 +41,10 @@ sdktype: addScoreBinding* {.importc: "addScore".}: proc (boardId: cstring; value: cuint; callback: AddScoreCallbackRaw): cint {.cdecl, raises: [].} freeScore* {.importc: "freeScore".}: proc (score: PDScorePtr) {.cdecl, raises: [].} - # getScoreboards* {.importc: "getScoreboards".}: proc ( - # callback: BoardsListCallbackRaw): cint {.cdecl.} - # freeBoardsList* {.importc: "freeBoardsList".}: proc ( - # boardsList: ptr PDBoardsList) {.cdecl.} + getScoreboardsBinding* {.importc: "getScoreboards".}: proc ( + callback: BoardsListCallbackRaw): cint {.cdecl, raises: [].} + freeBoardsList* {.importc: "freeBoardsList".}: proc ( + boardsList: PDBoardsListPtr) {.cdecl, raises: [].} getScoresBinding* {.importc: "getScores".}: proc (boardId: cstring; callback: ScoresCallbackRaw): cint {.cdecl, raises: [].} freeScoresList* {.importc: "freeScoresList".}: proc ( diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index d10614b..66aeb73 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -24,34 +24,54 @@ type PDScoresList* = object of RootObj # playerIncluded*: uint32 # limit*: uint32 +type PDBoard* = object of RootObj + boardID*: string + name*: string + +type PDBoardsList* = object of RootObj + lastUpdated*: uint32 + boards*: seq[PDBoard] + type PersonalBestCallback* = proc(score: PDScore, errorMessage: string) AddScoreCallback* = proc(score: PDScore, errorMessage: string) - # BoardsListCallback* = proc(boards: ptr PDBoardsList, errorMessage: string) + BoardsListCallback* = proc(boards: PDBoardsList, errorMessage: string) ScoresCallback* = proc(scores: PDScoresList, errorMessage: string) var privatePersonalBestCallbacks = newSeq[PersonalBestCallback]() var privateAddScoreCallbacks = newSeq[AddScoreCallback]() var privateScoresCallbacks = newSeq[ScoresCallback]() +var privateBoardsListCallbacks = newSeq[BoardsListCallback]() proc newPDScore(value: uint32, rank: uint32, player: string): PDScore = result.value = value result.rank = rank result.player = player +let emptyPDScore = newPDScore(value = 0, rank = 0, player = "") proc newPDScoresList(boardID: string, lastUpdated: uint32, scores: seq[PDScore]): PDScoresList = result.boardID = boardID result.lastUpdated = lastUpdated result.scores = scores +let emptyPDScoresList = newPDScoresList(boardID = "", lastUpdated = 0, scores = @[]) + +proc newPDBoard(boardID: string, name: string): PDBoard = + result.boardID = boardID + result.name = name + +proc newPDBoardsList(lastUpdated: uint32, boards: seq[PDBoard]): PDBoardsList = + result.lastUpdated = lastUpdated + result.boards = boards +let emptyPDBoardsList = newPDBoardsList(lastUpdated = 0, boards = @[]) proc invokePersonalBestCallback(score: PDScorePtr, errorMessage: ConstChar) {.cdecl, raises: [].} = let callback = privatePersonalBestCallbacks.pop() # first in, first out if score == nil and errorMessage == nil: - callback(newPDScore(value = 0, rank = 0, player = ""), "Playdate-nim: No personal best") + callback(emptyPDScore, "Playdate-nim: No personal best") return if score == nil: - callback(newPDScore(value = 0, rank = 0, player = ""), $errorMessage) + callback(emptyPDScore, $errorMessage) return let domainScore = newPDScore(value = score.value.uint32, rank = score.rank.uint32, player = $score.player) @@ -61,7 +81,7 @@ proc invokePersonalBestCallback(score: PDScorePtr, errorMessage: ConstChar) {.cd proc invokeAddScoreCallback(score: PDScorePtr, errorMessage: ConstChar) {.cdecl, raises: [].} = let callback = privateAddScoreCallbacks.pop() # first in, first out if errorMessage != nil: - callback(newPDScore(value = 0, rank = 0, player = ""), $errorMessage) + callback(emptyPDScore, $errorMessage) return let domainScore = newPDScore(value = score.value.uint32, rank = score.rank.uint32, player = $score.player) @@ -72,13 +92,11 @@ proc invokeScoresCallback(scoresList: PDScoresListPtr, errorMessage: ConstChar) privateAccess(PlaydateScoreboards) let callback = privateScoresCallbacks.pop() # first in, first out if scoresList == nil and errorMessage == nil: - let domainObject = newPDScoresList(boardID = "", lastUpdated = 0, scores = @[]) - callback(domainObject, "Playdate-nim: No scores") + callback(emptyPDScoresList, "Playdate-nim: No scores") return if scoresList == nil: - let domainObject = newPDScoresList(boardID = "", lastUpdated = 0, scores = @[]) - callback(domainObject, $errorMessage) + callback(emptyPDScoresList, $errorMessage) return privateAccess(SDKArray) @@ -87,13 +105,37 @@ proc invokeScoresCallback(scoresList: PDScoresListPtr, errorMessage: ConstChar) var scoresSeq = newSeq[PDScore](length) for i in 0 ..< length: let score = cArray[i] - scoresSeq[i] = PDScore(value: score.value.uint32, rank: score.rank.uint32, player: $score.player) + scoresSeq[i] = newPDScore(value = score.value.uint32, rank = score.rank.uint32, player = $score.player) cArray.data = nil # no need for SDKArray to free the data, freeScoresList() will do it let domainObject = newPDScoresList(boardID = $scoresList.boardID, lastUpdated = scoresList.lastUpdated, scores = scoresSeq) callback(domainObject, $errorMessage) playdate.scoreboards.freeScoresList(scoresList) +proc invokeBoardsListCallback(boardsList: PDBoardsListPtr, errorMessage: ConstChar) {.cdecl, raises: [].} = + let callback = privateBoardsListCallbacks.pop() # first in, first out + if boardsList == nil and errorMessage == nil: + callback(emptyPDBoardsList, "Playdate-nim: No boards") + return + + if boardsList == nil: + callback(emptyPDBoardsList, $errorMessage) + return + + privateAccess(SDKArray) + let length = boardsList.count.cint + let cArray = SDKArray[PDBoardRaw](data: cast[ptr UncheckedArray[PDBoardRaw]](boardsList.boards), len: length) + var boardsSeq = newSeq[PDBoard](length) + for i in 0 ..< length: + let board = cArray[i] + boardsSeq[i] = newPDBoard(boardID = $board.boardID, name = $board.name) + cArray.data = nil # no need for SDKArray to free the data, freeBoardsList() will do it + + let domainObject = newPDBoardsList(lastUpdated = boardsList.lastUpdated, boards = boardsSeq) + + callback(domainObject, $errorMessage) + playdate.scoreboards.freeBoardsList(boardsList) + proc getPersonalBest*(this: ptr PlaydateScoreboards, boardID: string, callback: PersonalBestCallback): int32 = privateAccess(PlaydateScoreboards) privatePersonalBestCallbacks.insert(callback) # by inserting the callback at the start, it will be popped last: first in, first out @@ -104,9 +146,11 @@ proc addScore*(this: ptr PlaydateScoreboards, boardID: string, value: uint32, ca privateAddScoreCallbacks.insert(callback) # by inserting the callback at the start, it will be popped last: first in, first out return this.addScoreBinding(boardID.cstring, value.cuint, invokeAddScoreCallback) -# proc getScoreboards*(this: ptr PlaydateScoreboards, callback: BoardsListCallback): int32 = -# privateAccess(PlaydateScoreboards) -# # proc freeBoardsList*(boardsList: ptr PDBoardsList) +proc getScoreboards*(this: ptr PlaydateScoreboards, callback: BoardsListCallback): int32 = + privateAccess(PlaydateScoreboards) + privateBoardsListCallbacks.insert(callback) # by inserting the callback at the start, it will be popped last: first in, first out + return this.getScoreboardsBinding(invokeBoardsListCallback) + proc getScores*(this: ptr PlaydateScoreboards, boardID: string, callback: ScoresCallback): int32 = privateAccess(PlaydateScoreboards) privateScoresCallbacks.insert(callback) # by inserting the callback at the start, it will be popped last: first in, first out From 932039d525d1ced28f4e0b9b01521f9c66ca13c0 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Thu, 24 Oct 2024 18:23:40 +0200 Subject: [PATCH 050/101] CHANGE PR feedback low hanging fruit --- src/playdate/bindings/scoreboards.nim | 1 - src/playdate/scoreboards.nim | 73 ++++++++++++--------------- 2 files changed, 33 insertions(+), 41 deletions(-) diff --git a/src/playdate/bindings/scoreboards.nim b/src/playdate/bindings/scoreboards.nim index 29307e7..551db7d 100644 --- a/src/playdate/bindings/scoreboards.nim +++ b/src/playdate/bindings/scoreboards.nim @@ -8,7 +8,6 @@ type PDScoreRaw* {.importc: "PDScore", header: "pd_api.h", bycopy.} = object player* {.importc: "player".}: cstring type PDScorePtr* = ptr PDScoreRaw -# type PDScore* = ref PDScoreRaw type PDScoresListRaw* {.importc: "PDScoresList", header: "pd_api.h", bycopy.} = object boardID* {.importc: "boardID".}: cstring diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index 66aeb73..1128875 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -11,57 +11,50 @@ export scoreboards {.hint[DuplicateModuleImport]: off.} import bindings/scoreboards {.all.} -type PDScore* = object of RootObj - value*: uint32 - rank*: uint32 - player*: string - -type PDScoresList* = object of RootObj - boardID*: string - lastUpdated*: uint32 - scores*: seq[PDScore] - # these properties are not implemented yet in the Playdate API - # playerIncluded*: uint32 - # limit*: uint32 - -type PDBoard* = object of RootObj - boardID*: string - name*: string - -type PDBoardsList* = object of RootObj - lastUpdated*: uint32 - boards*: seq[PDBoard] - -type +type + PDScore* = object of RootObj + value*, rank*: uint32 + player*: string + + PDScoresList* = object of RootObj + boardID*: string + lastUpdated*: uint32 + scores*: seq[PDScore] + # these properties are not implemented yet in the Playdate API + # playerIncluded*: uint32 + # limit*: uint32 + + PDBoard* = object of RootObj + boardID*, name*: string + + PDBoardsList* = object of RootObj + lastUpdated*: uint32 + boards*: seq[PDBoard] + PersonalBestCallback* = proc(score: PDScore, errorMessage: string) AddScoreCallback* = proc(score: PDScore, errorMessage: string) BoardsListCallback* = proc(boards: PDBoardsList, errorMessage: string) ScoresCallback* = proc(scores: PDScoresList, errorMessage: string) -var privatePersonalBestCallbacks = newSeq[PersonalBestCallback]() -var privateAddScoreCallbacks = newSeq[AddScoreCallback]() -var privateScoresCallbacks = newSeq[ScoresCallback]() -var privateBoardsListCallbacks = newSeq[BoardsListCallback]() +var + privatePersonalBestCallbacks = newSeq[PersonalBestCallback]() + privateAddScoreCallbacks = newSeq[AddScoreCallback]() + privateScoresCallbacks = newSeq[ScoresCallback]() + privateBoardsListCallbacks = newSeq[BoardsListCallback]() proc newPDScore(value: uint32, rank: uint32, player: string): PDScore = - result.value = value - result.rank = rank - result.player = player + PDSCore(value: value, rank: rank, player: player) let emptyPDScore = newPDScore(value = 0, rank = 0, player = "") proc newPDScoresList(boardID: string, lastUpdated: uint32, scores: seq[PDScore]): PDScoresList = - result.boardID = boardID - result.lastUpdated = lastUpdated - result.scores = scores + PDScoresList(boardID: boardID, lastUpdated: lastUpdated, scores: scores) let emptyPDScoresList = newPDScoresList(boardID = "", lastUpdated = 0, scores = @[]) proc newPDBoard(boardID: string, name: string): PDBoard = - result.boardID = boardID - result.name = name + PDBoard(boardID: boardID, name: name) proc newPDBoardsList(lastUpdated: uint32, boards: seq[PDBoard]): PDBoardsList = - result.lastUpdated = lastUpdated - result.boards = boards + PDBoardsList(lastUpdated: lastUpdated, boards: boards) let emptyPDBoardsList = newPDBoardsList(lastUpdated = 0, boards = @[]) proc invokePersonalBestCallback(score: PDScorePtr, errorMessage: ConstChar) {.cdecl, raises: [].} = @@ -136,22 +129,22 @@ proc invokeBoardsListCallback(boardsList: PDBoardsListPtr, errorMessage: ConstCh callback(domainObject, $errorMessage) playdate.scoreboards.freeBoardsList(boardsList) -proc getPersonalBest*(this: ptr PlaydateScoreboards, boardID: string, callback: PersonalBestCallback): int32 = +proc getPersonalBest*(this: ptr PlaydateScoreboards, boardID: string, callback: PersonalBestCallback): int32 {.discardable.} = privateAccess(PlaydateScoreboards) privatePersonalBestCallbacks.insert(callback) # by inserting the callback at the start, it will be popped last: first in, first out return this.getPersonalBestBinding(boardID.cstring, invokePersonalBestCallback) -proc addScore*(this: ptr PlaydateScoreboards, boardID: string, value: uint32, callback: AddScoreCallback): int32 = +proc addScore*(this: ptr PlaydateScoreboards, boardID: string, value: uint32, callback: AddScoreCallback): int32 {.discardable.} = privateAccess(PlaydateScoreboards) privateAddScoreCallbacks.insert(callback) # by inserting the callback at the start, it will be popped last: first in, first out return this.addScoreBinding(boardID.cstring, value.cuint, invokeAddScoreCallback) -proc getScoreboards*(this: ptr PlaydateScoreboards, callback: BoardsListCallback): int32 = +proc getScoreboards*(this: ptr PlaydateScoreboards, callback: BoardsListCallback): int32 {.discardable.} = privateAccess(PlaydateScoreboards) privateBoardsListCallbacks.insert(callback) # by inserting the callback at the start, it will be popped last: first in, first out return this.getScoreboardsBinding(invokeBoardsListCallback) -proc getScores*(this: ptr PlaydateScoreboards, boardID: string, callback: ScoresCallback): int32 = +proc getScores*(this: ptr PlaydateScoreboards, boardID: string, callback: ScoresCallback): int32 {.discardable.} = privateAccess(PlaydateScoreboards) privateScoresCallbacks.insert(callback) # by inserting the callback at the start, it will be popped last: first in, first out return this.getScoresBinding(boardID.cstring, invokeScoresCallback) \ No newline at end of file From 02739bd4989ec8bdcbdc0f15d8a47598094d44b0 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Thu, 24 Oct 2024 18:26:57 +0200 Subject: [PATCH 051/101] CHANGE use UncheckedArray for c-array types --- src/playdate/bindings/scoreboards.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/playdate/bindings/scoreboards.nim b/src/playdate/bindings/scoreboards.nim index 551db7d..ffe058a 100644 --- a/src/playdate/bindings/scoreboards.nim +++ b/src/playdate/bindings/scoreboards.nim @@ -15,7 +15,7 @@ type PDScoresListRaw* {.importc: "PDScoresList", header: "pd_api.h", bycopy.} = lastUpdated* {.importc: "lastUpdated".}: cuint playerIncluded* {.importc: "playerIncluded".}: cuint limit* {.importc: "limit".}: cuint - scores* {.importc: "scores".}: ptr PDScoreRaw + scores* {.importc: "scores".}: ptr UncheckedArray[PDScoreRaw] type PDScoresListPtr* = ptr PDScoresListRaw type PDBoardRaw* {.importc: "PDBoard", header: "pd_api.h", bycopy.} = object @@ -25,7 +25,7 @@ type PDBoardRaw* {.importc: "PDBoard", header: "pd_api.h", bycopy.} = object type PDBoardsListRaw* {.importc: "PDBoardsList", header: "pd_api.h", bycopy.} = object count* {.importc: "count".}: cuint lastUpdated* {.importc: "lastUpdated".}: cuint - boards* {.importc: "boards".}: ptr PDBoardRaw + boards* {.importc: "boards".}: ptr UncheckedArray[PDBoardRaw] type PDBoardsListPtr* = ptr PDBoardsListRaw type PersonalBestCallbackRaw* {.importc: "PersonalBestCallback", header: "pd_api.h".} = proc (score: PDScorePtr; errorMessage: cstring) {.cdecl.} From dad36503e7cbb1fc203d389492c96122f85fa4f1 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Thu, 24 Oct 2024 18:31:18 +0200 Subject: [PATCH 052/101] ADD documentation for callback seqs --- src/playdate/scoreboards.nim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index 1128875..097dbc7 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -36,7 +36,10 @@ type BoardsListCallback* = proc(boards: PDBoardsList, errorMessage: string) ScoresCallback* = proc(scores: PDScoresList, errorMessage: string) -var +var + # The sdk callbacks unfortunately don't provide a userdata field to tag the callback with eg. the boardID + # So we need to keep track of the callbacks in the order they were called, which luckily is guaranteed by the Playdate API + # By inserting the callback at the start, it will be popped last: first in, first out privatePersonalBestCallbacks = newSeq[PersonalBestCallback]() privateAddScoreCallbacks = newSeq[AddScoreCallback]() privateScoresCallbacks = newSeq[ScoresCallback]() From 9f3bd556070f0c7b09cdebc1cd0c8ddc43c3c380 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Thu, 24 Oct 2024 18:51:02 +0200 Subject: [PATCH 053/101] CHANGE use a template for addScore and getPersonalBest --- src/playdate/scoreboards.nim | 61 ++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index 097dbc7..746b1a5 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -45,6 +45,23 @@ var privateScoresCallbacks = newSeq[ScoresCallback]() privateBoardsListCallbacks = newSeq[BoardsListCallback]() +template invokeCallback(callbackSeqs, value, errorMessage, freeValue, build, emptyValue: untyped) = + let callback = callbackSeqs.pop() + if value == nil and errorMessage == nil: + callback(emptyValue, "Playdate-nim: No value provided for callback") + return + + if value == nil: + callback(default(build.type), $errorMessage) + return + + try: + let nimObj = build + callback(nimObj, $errorMessage) + finally: + freeValue(score) + + proc newPDScore(value: uint32, rank: uint32, player: string): PDScore = PDSCore(value: value, rank: rank, player: player) let emptyPDScore = newPDScore(value = 0, rank = 0, player = "") @@ -61,28 +78,32 @@ proc newPDBoardsList(lastUpdated: uint32, boards: seq[PDBoard]): PDBoardsList = let emptyPDBoardsList = newPDBoardsList(lastUpdated = 0, boards = @[]) proc invokePersonalBestCallback(score: PDScorePtr, errorMessage: ConstChar) {.cdecl, raises: [].} = - let callback = privatePersonalBestCallbacks.pop() # first in, first out - if score == nil and errorMessage == nil: - callback(emptyPDScore, "Playdate-nim: No personal best") - return - - if score == nil: - callback(emptyPDScore, $errorMessage) - return - - let domainScore = newPDScore(value = score.value.uint32, rank = score.rank.uint32, player = $score.player) - playdate.scoreboards.freeScore(score) - callback(domainScore, $errorMessage) + invokeCallback( + callbackSeqs = privatePersonalBestCallbacks, + value = score, + errorMessage = errorMessage, + freeValue = playdate.scoreboards.freeScore, + build = newPDScore( + value = score.value.uint32, + rank = score.rank.uint32, + player = $score.player + ), + emptyValue = emptyPDScore + ) proc invokeAddScoreCallback(score: PDScorePtr, errorMessage: ConstChar) {.cdecl, raises: [].} = - let callback = privateAddScoreCallbacks.pop() # first in, first out - if errorMessage != nil: - callback(emptyPDScore, $errorMessage) - return - - let domainScore = newPDScore(value = score.value.uint32, rank = score.rank.uint32, player = $score.player) - playdate.scoreboards.freeScore(score) - callback(domainScore, $errorMessage) + invokeCallback( + callbackSeqs = privateAddScoreCallbacks, + value = score, + errorMessage = errorMessage, + freeValue = playdate.scoreboards.freeScore, + build = newPDScore( + value = score.value.uint32, + rank = score.rank.uint32, + player = $score.player + ), + emptyValue = emptyPDScore + ) proc invokeScoresCallback(scoresList: PDScoresListPtr, errorMessage: ConstChar) {.cdecl, raises: [].} = privateAccess(PlaydateScoreboards) From edf4e96bcd9b4b52cb235bf8e66b8db713523d46 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Thu, 24 Oct 2024 19:18:03 +0200 Subject: [PATCH 054/101] CHANGE deduplicate scoreBuilder --- src/playdate/scoreboards.nim | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index 746b1a5..3260fe0 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -45,18 +45,18 @@ var privateScoresCallbacks = newSeq[ScoresCallback]() privateBoardsListCallbacks = newSeq[BoardsListCallback]() -template invokeCallback(callbackSeqs, value, errorMessage, freeValue, build, emptyValue: untyped) = +template invokeCallback(callbackSeqs, value, errorMessage, freeValue, builder, emptyValue: untyped) = let callback = callbackSeqs.pop() if value == nil and errorMessage == nil: callback(emptyValue, "Playdate-nim: No value provided for callback") return if value == nil: - callback(default(build.type), $errorMessage) + callback(emptyValue, $errorMessage) return try: - let nimObj = build + let nimObj = builder(value) callback(nimObj, $errorMessage) finally: freeValue(score) @@ -77,17 +77,20 @@ proc newPDBoardsList(lastUpdated: uint32, boards: seq[PDBoard]): PDBoardsList = PDBoardsList(lastUpdated: lastUpdated, boards: boards) let emptyPDBoardsList = newPDBoardsList(lastUpdated = 0, boards = @[]) +proc scoreBuilder(score: PDScorePtr): PDScore = + newPDScore( + value = score.value.uint32, + rank = score.rank.uint32, + player = $score.player + ) + proc invokePersonalBestCallback(score: PDScorePtr, errorMessage: ConstChar) {.cdecl, raises: [].} = invokeCallback( callbackSeqs = privatePersonalBestCallbacks, value = score, errorMessage = errorMessage, freeValue = playdate.scoreboards.freeScore, - build = newPDScore( - value = score.value.uint32, - rank = score.rank.uint32, - player = $score.player - ), + builder = scoreBuilder, emptyValue = emptyPDScore ) @@ -97,11 +100,7 @@ proc invokeAddScoreCallback(score: PDScorePtr, errorMessage: ConstChar) {.cdecl, value = score, errorMessage = errorMessage, freeValue = playdate.scoreboards.freeScore, - build = newPDScore( - value = score.value.uint32, - rank = score.rank.uint32, - player = $score.player - ), + builder = scoreBuilder, emptyValue = emptyPDScore ) From c7dcfc2cd635fc8eee361feb009a04e866b3fb5d Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Thu, 24 Oct 2024 19:23:28 +0200 Subject: [PATCH 055/101] CHANGE use invokeCallback for scoresCallback --- src/playdate/scoreboards.nim | 42 ++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index 3260fe0..a95bce1 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -59,7 +59,7 @@ template invokeCallback(callbackSeqs, value, errorMessage, freeValue, builder, e let nimObj = builder(value) callback(nimObj, $errorMessage) finally: - freeValue(score) + freeValue(value) proc newPDScore(value: uint32, rank: uint32, player: string): PDScore = @@ -105,28 +105,24 @@ proc invokeAddScoreCallback(score: PDScorePtr, errorMessage: ConstChar) {.cdecl, ) proc invokeScoresCallback(scoresList: PDScoresListPtr, errorMessage: ConstChar) {.cdecl, raises: [].} = - privateAccess(PlaydateScoreboards) - let callback = privateScoresCallbacks.pop() # first in, first out - if scoresList == nil and errorMessage == nil: - callback(emptyPDScoresList, "Playdate-nim: No scores") - return - - if scoresList == nil: - callback(emptyPDScoresList, $errorMessage) - return - - privateAccess(SDKArray) - let length = scoresList.count.cint - let cArray = SDKArray[PDScoreRaw](data: cast[ptr UncheckedArray[PDScoreRaw]](scoresList.scores), len: length) - var scoresSeq = newSeq[PDScore](length) - for i in 0 ..< length: - let score = cArray[i] - scoresSeq[i] = newPDScore(value = score.value.uint32, rank = score.rank.uint32, player = $score.player) - cArray.data = nil # no need for SDKArray to free the data, freeScoresList() will do it - - let domainObject = newPDScoresList(boardID = $scoresList.boardID, lastUpdated = scoresList.lastUpdated, scores = scoresSeq) - callback(domainObject, $errorMessage) - playdate.scoreboards.freeScoresList(scoresList) + invokeCallback( + callbackSeqs = privateScoresCallbacks, + value = scoresList, + errorMessage = errorMessage, + freeValue = playdate.scoreboards.freeScoresList, + builder = proc (scoresList: PDScoresListPtr): PDScoresList = + privateAccess(SDKArray) + let length = scoresList.count.cint + let cArray = SDKArray[PDScoreRaw](data: cast[ptr UncheckedArray[PDScoreRaw]](scoresList.scores), len: length) + var scoresSeq = newSeq[PDScore](length) + for i in 0 ..< length: + let score = cArray[i] + scoresSeq[i] = newPDScore(value = score.value.uint32, rank = score.rank.uint32, player = $score.player) + cArray.data = nil # no need for SDKArray to free the data, freeScoresList() will do it + + return newPDScoresList(boardID = $scoresList.boardID, lastUpdated = scoresList.lastUpdated, scores = scoresSeq), + emptyValue = emptyPDScoresList + ) proc invokeBoardsListCallback(boardsList: PDBoardsListPtr, errorMessage: ConstChar) {.cdecl, raises: [].} = let callback = privateBoardsListCallbacks.pop() # first in, first out From 02e2d502c0d3830f8d564abefa1977dee9cf3bb0 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Thu, 24 Oct 2024 19:25:17 +0200 Subject: [PATCH 056/101] CHANGE use invokeCallback for invokeBoardsListCallback --- src/playdate/scoreboards.nim | 38 ++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index a95bce1..07edecb 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -125,28 +125,24 @@ proc invokeScoresCallback(scoresList: PDScoresListPtr, errorMessage: ConstChar) ) proc invokeBoardsListCallback(boardsList: PDBoardsListPtr, errorMessage: ConstChar) {.cdecl, raises: [].} = - let callback = privateBoardsListCallbacks.pop() # first in, first out - if boardsList == nil and errorMessage == nil: - callback(emptyPDBoardsList, "Playdate-nim: No boards") - return - - if boardsList == nil: - callback(emptyPDBoardsList, $errorMessage) - return - - privateAccess(SDKArray) - let length = boardsList.count.cint - let cArray = SDKArray[PDBoardRaw](data: cast[ptr UncheckedArray[PDBoardRaw]](boardsList.boards), len: length) - var boardsSeq = newSeq[PDBoard](length) - for i in 0 ..< length: - let board = cArray[i] - boardsSeq[i] = newPDBoard(boardID = $board.boardID, name = $board.name) - cArray.data = nil # no need for SDKArray to free the data, freeBoardsList() will do it - - let domainObject = newPDBoardsList(lastUpdated = boardsList.lastUpdated, boards = boardsSeq) + invokeCallback( + callbackSeqs = privateBoardsListCallbacks, + value = boardsList, + errorMessage = errorMessage, + freeValue = playdate.scoreboards.freeBoardsList, + builder = proc (boardsList: PDBoardsListPtr): PDBoardsList = + privateAccess(SDKArray) + let length = boardsList.count.cint + let cArray = SDKArray[PDBoardRaw](data: cast[ptr UncheckedArray[PDBoardRaw]](boardsList.boards), len: length) + var boardsSeq = newSeq[PDBoard](length) + for i in 0 ..< length: + let board = cArray[i] + boardsSeq[i] = newPDBoard(boardID = $board.boardID, name = $board.name) + cArray.data = nil # no need for SDKArray to free the data, freeBoardsList() will do it - callback(domainObject, $errorMessage) - playdate.scoreboards.freeBoardsList(boardsList) + return newPDBoardsList(lastUpdated = boardsList.lastUpdated, boards = boardsSeq), + emptyValue = emptyPDBoardsList + ) proc getPersonalBest*(this: ptr PlaydateScoreboards, boardID: string, callback: PersonalBestCallback): int32 {.discardable.} = privateAccess(PlaydateScoreboards) From 50cb0c0e544e03c63211d97fa6259b9d624bac50 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Thu, 24 Oct 2024 20:19:38 +0200 Subject: [PATCH 057/101] ADD buildList proc --- src/playdate/scoreboards.nim | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index 07edecb..2675e21 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -104,6 +104,24 @@ proc invokeAddScoreCallback(score: PDScorePtr, errorMessage: ConstChar) {.cdecl, emptyValue = emptyPDScore ) +proc rawScoreBuilder(score: PDScoreRaw): PDScore = + newPDScore( + value = score.value.uint32, + rank = score.rank.uint32, + player = $score.player + ) + +proc buildList[T, U](rawField: ptr UncheckedArray[T], itemBuilder: proc (item: T): U {.raises: [].}): seq[U] = + let length = 10 # todo + privateAccess(SDKArray) + let cArray = SDKArray[T](data: rawField, len: length) + var newSeq = newSeq[U](length) + for i in 0 ..< length: + let item = cArray[i] + newSeq[i] = itemBuilder(item) + cArray.data = nil # no need for SDKArray to free the data, free function will do it + return newSeq + proc invokeScoresCallback(scoresList: PDScoresListPtr, errorMessage: ConstChar) {.cdecl, raises: [].} = invokeCallback( callbackSeqs = privateScoresCallbacks, @@ -112,13 +130,10 @@ proc invokeScoresCallback(scoresList: PDScoresListPtr, errorMessage: ConstChar) freeValue = playdate.scoreboards.freeScoresList, builder = proc (scoresList: PDScoresListPtr): PDScoresList = privateAccess(SDKArray) - let length = scoresList.count.cint - let cArray = SDKArray[PDScoreRaw](data: cast[ptr UncheckedArray[PDScoreRaw]](scoresList.scores), len: length) - var scoresSeq = newSeq[PDScore](length) - for i in 0 ..< length: - let score = cArray[i] - scoresSeq[i] = newPDScore(value = score.value.uint32, rank = score.rank.uint32, player = $score.player) - cArray.data = nil # no need for SDKArray to free the data, freeScoresList() will do it + var scoresSeq = buildList[PDScoreRaw, PDScore]( + rawField = scoresList.scores, + itemBuilder = rawScoreBuilder + ) return newPDScoresList(boardID = $scoresList.boardID, lastUpdated = scoresList.lastUpdated, scores = scoresSeq), emptyValue = emptyPDScoresList @@ -139,7 +154,7 @@ proc invokeBoardsListCallback(boardsList: PDBoardsListPtr, errorMessage: ConstCh let board = cArray[i] boardsSeq[i] = newPDBoard(boardID = $board.boardID, name = $board.name) cArray.data = nil # no need for SDKArray to free the data, freeBoardsList() will do it - + return newPDBoardsList(lastUpdated = boardsList.lastUpdated, boards = boardsSeq), emptyValue = emptyPDBoardsList ) From 9474bdd468757429142b9eecaefbf659fa7ca907 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Thu, 24 Oct 2024 20:23:42 +0200 Subject: [PATCH 058/101] CHANGE deduplicate scorebuilder --- src/playdate/scoreboards.nim | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index 2675e21..04f9724 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -84,6 +84,13 @@ proc scoreBuilder(score: PDScorePtr): PDScore = player = $score.player ) +proc scoreBuilder(score: PDScoreRaw): PDScore = + newPDScore( + value = score.value.uint32, + rank = score.rank.uint32, + player = $score.player + ) + proc invokePersonalBestCallback(score: PDScorePtr, errorMessage: ConstChar) {.cdecl, raises: [].} = invokeCallback( callbackSeqs = privatePersonalBestCallbacks, @@ -104,13 +111,6 @@ proc invokeAddScoreCallback(score: PDScorePtr, errorMessage: ConstChar) {.cdecl, emptyValue = emptyPDScore ) -proc rawScoreBuilder(score: PDScoreRaw): PDScore = - newPDScore( - value = score.value.uint32, - rank = score.rank.uint32, - player = $score.player - ) - proc buildList[T, U](rawField: ptr UncheckedArray[T], itemBuilder: proc (item: T): U {.raises: [].}): seq[U] = let length = 10 # todo privateAccess(SDKArray) @@ -132,7 +132,7 @@ proc invokeScoresCallback(scoresList: PDScoresListPtr, errorMessage: ConstChar) privateAccess(SDKArray) var scoresSeq = buildList[PDScoreRaw, PDScore]( rawField = scoresList.scores, - itemBuilder = rawScoreBuilder + itemBuilder = scoreBuilder ) return newPDScoresList(boardID = $scoresList.boardID, lastUpdated = scoresList.lastUpdated, scores = scoresSeq), From 61ceb0589e56e0f1b71980c207bbb0b3f409f68e Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Thu, 24 Oct 2024 20:26:07 +0200 Subject: [PATCH 059/101] CHANGE use seqBuilder for boardslist --- src/playdate/scoreboards.nim | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index 04f9724..881f53b 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -111,7 +111,7 @@ proc invokeAddScoreCallback(score: PDScorePtr, errorMessage: ConstChar) {.cdecl, emptyValue = emptyPDScore ) -proc buildList[T, U](rawField: ptr UncheckedArray[T], itemBuilder: proc (item: T): U {.raises: [].}): seq[U] = +proc seqBuilder[T, U](rawField: ptr UncheckedArray[T], itemBuilder: proc (item: T): U {.raises: [].}): seq[U] = let length = 10 # todo privateAccess(SDKArray) let cArray = SDKArray[T](data: rawField, len: length) @@ -130,7 +130,7 @@ proc invokeScoresCallback(scoresList: PDScoresListPtr, errorMessage: ConstChar) freeValue = playdate.scoreboards.freeScoresList, builder = proc (scoresList: PDScoresListPtr): PDScoresList = privateAccess(SDKArray) - var scoresSeq = buildList[PDScoreRaw, PDScore]( + var scoresSeq = seqBuilder[PDScoreRaw, PDScore]( rawField = scoresList.scores, itemBuilder = scoreBuilder ) @@ -147,14 +147,12 @@ proc invokeBoardsListCallback(boardsList: PDBoardsListPtr, errorMessage: ConstCh freeValue = playdate.scoreboards.freeBoardsList, builder = proc (boardsList: PDBoardsListPtr): PDBoardsList = privateAccess(SDKArray) - let length = boardsList.count.cint - let cArray = SDKArray[PDBoardRaw](data: cast[ptr UncheckedArray[PDBoardRaw]](boardsList.boards), len: length) - var boardsSeq = newSeq[PDBoard](length) - for i in 0 ..< length: - let board = cArray[i] - boardsSeq[i] = newPDBoard(boardID = $board.boardID, name = $board.name) - cArray.data = nil # no need for SDKArray to free the data, freeBoardsList() will do it - + var boardsSeq = seqBuilder[PDBoardRaw, PDBoard]( + rawField = cast[ptr UncheckedArray[PDBoardRaw]](boardsList.boards), + itemBuilder = proc (board: PDBoardRaw): PDBoard = + newPDBoard(boardID = $board.boardID, name = $board.name) + ) + return newPDBoardsList(lastUpdated = boardsList.lastUpdated, boards = boardsSeq), emptyValue = emptyPDBoardsList ) From 19efc78a3adb8ac27403a7930474f726bec8e126 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Thu, 24 Oct 2024 20:27:35 +0200 Subject: [PATCH 060/101] REMOVE redundant explicit types --- src/playdate/scoreboards.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index 881f53b..24e401e 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -130,7 +130,7 @@ proc invokeScoresCallback(scoresList: PDScoresListPtr, errorMessage: ConstChar) freeValue = playdate.scoreboards.freeScoresList, builder = proc (scoresList: PDScoresListPtr): PDScoresList = privateAccess(SDKArray) - var scoresSeq = seqBuilder[PDScoreRaw, PDScore]( + var scoresSeq = seqBuilder( rawField = scoresList.scores, itemBuilder = scoreBuilder ) @@ -147,7 +147,7 @@ proc invokeBoardsListCallback(boardsList: PDBoardsListPtr, errorMessage: ConstCh freeValue = playdate.scoreboards.freeBoardsList, builder = proc (boardsList: PDBoardsListPtr): PDBoardsList = privateAccess(SDKArray) - var boardsSeq = seqBuilder[PDBoardRaw, PDBoard]( + var boardsSeq = seqBuilder( rawField = cast[ptr UncheckedArray[PDBoardRaw]](boardsList.boards), itemBuilder = proc (board: PDBoardRaw): PDBoard = newPDBoard(boardID = $board.boardID, name = $board.name) From 5c20364d0a1b20488a74820638d15701b14d82d0 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Thu, 24 Oct 2024 20:35:47 +0200 Subject: [PATCH 061/101] FIX hardcoded length --- src/playdate/scoreboards.nim | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index 24e401e..ff2c79c 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -111,10 +111,9 @@ proc invokeAddScoreCallback(score: PDScorePtr, errorMessage: ConstChar) {.cdecl, emptyValue = emptyPDScore ) -proc seqBuilder[T, U](rawField: ptr UncheckedArray[T], itemBuilder: proc (item: T): U {.raises: [].}): seq[U] = - let length = 10 # todo +proc seqBuilder[T, U](rawField: ptr UncheckedArray[T], length: cuint, itemBuilder: proc (item: T): U {.raises: [].}): seq[U] = privateAccess(SDKArray) - let cArray = SDKArray[T](data: rawField, len: length) + let cArray = SDKArray[T](data: rawField, len: length.int) var newSeq = newSeq[U](length) for i in 0 ..< length: let item = cArray[i] @@ -132,6 +131,7 @@ proc invokeScoresCallback(scoresList: PDScoresListPtr, errorMessage: ConstChar) privateAccess(SDKArray) var scoresSeq = seqBuilder( rawField = scoresList.scores, + length = scoresList.count, itemBuilder = scoreBuilder ) @@ -149,6 +149,7 @@ proc invokeBoardsListCallback(boardsList: PDBoardsListPtr, errorMessage: ConstCh privateAccess(SDKArray) var boardsSeq = seqBuilder( rawField = cast[ptr UncheckedArray[PDBoardRaw]](boardsList.boards), + length = boardsList.count, itemBuilder = proc (board: PDBoardRaw): PDBoard = newPDBoard(boardID = $board.boardID, name = $board.name) ) From 5600a4e2a12109ab6199dc77cfacdd331eb7f6d6 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Thu, 24 Oct 2024 20:40:42 +0200 Subject: [PATCH 062/101] CHANGE cuint by SomeInteger --- src/playdate/scoreboards.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index ff2c79c..445e60e 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -111,7 +111,7 @@ proc invokeAddScoreCallback(score: PDScorePtr, errorMessage: ConstChar) {.cdecl, emptyValue = emptyPDScore ) -proc seqBuilder[T, U](rawField: ptr UncheckedArray[T], length: cuint, itemBuilder: proc (item: T): U {.raises: [].}): seq[U] = +proc seqBuilder[T, U](rawField: ptr UncheckedArray[T], length: SomeInteger, itemBuilder: proc (item: T): U {.raises: [].}): seq[U] = privateAccess(SDKArray) let cArray = SDKArray[T](data: rawField, len: length.int) var newSeq = newSeq[U](length) From ce8fe96e50f53799beec8bacbe7e1dcc24c76c97 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Thu, 24 Oct 2024 20:51:21 +0200 Subject: [PATCH 063/101] CHANGE deduplicate scoreBuilder --- src/playdate/scoreboards.nim | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index 445e60e..b03fb7e 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -77,13 +77,6 @@ proc newPDBoardsList(lastUpdated: uint32, boards: seq[PDBoard]): PDBoardsList = PDBoardsList(lastUpdated: lastUpdated, boards: boards) let emptyPDBoardsList = newPDBoardsList(lastUpdated = 0, boards = @[]) -proc scoreBuilder(score: PDScorePtr): PDScore = - newPDScore( - value = score.value.uint32, - rank = score.rank.uint32, - player = $score.player - ) - proc scoreBuilder(score: PDScoreRaw): PDScore = newPDScore( value = score.value.uint32, @@ -91,6 +84,9 @@ proc scoreBuilder(score: PDScoreRaw): PDScore = player = $score.player ) +proc scoreBuilder(score: PDScorePtr): PDScore = + scoreBuilder(score[]) + proc invokePersonalBestCallback(score: PDScorePtr, errorMessage: ConstChar) {.cdecl, raises: [].} = invokeCallback( callbackSeqs = privatePersonalBestCallbacks, From ea6f237fbd10632dedc550005ccb13b4dbfa0a70 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Thu, 24 Oct 2024 20:57:04 +0200 Subject: [PATCH 064/101] CHANGE clarify callback seqs a bit --- src/playdate/scoreboards.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index b03fb7e..02a4cc7 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -38,7 +38,7 @@ type var # The sdk callbacks unfortunately don't provide a userdata field to tag the callback with eg. the boardID - # So we need to keep track of the callbacks in the order they were called, which luckily is guaranteed by the Playdate API + # Scoreboard responses are handled in order of request, however, so if we keep track of request order everything should be fine. # By inserting the callback at the start, it will be popped last: first in, first out privatePersonalBestCallbacks = newSeq[PersonalBestCallback]() privateAddScoreCallbacks = newSeq[AddScoreCallback]() From 89275b2bc8d7557e541fbd56d395fd489dad52cf Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Thu, 24 Oct 2024 21:02:35 +0200 Subject: [PATCH 065/101] REFACTOR tiny bit of code refactoring --- src/playdate/scoreboards.nim | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index 02a4cc7..b24e1eb 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -87,6 +87,17 @@ proc scoreBuilder(score: PDScoreRaw): PDScore = proc scoreBuilder(score: PDScorePtr): PDScore = scoreBuilder(score[]) +proc seqBuilder[T, U](rawField: ptr UncheckedArray[T], length: SomeInteger, itemBuilder: proc (item: T): U {.raises: [].}): seq[U] = + ## Coverts a C array to a Nim seq + privateAccess(SDKArray) + let cArray = SDKArray[T](data: rawField, len: length.int) + var newSeq = newSeq[U](length) + for i in 0 ..< length: + let item = cArray[i] + newSeq[i] = itemBuilder(item) + cArray.data = nil # no need for SDKArray to free the data, free function will do it + return newSeq + proc invokePersonalBestCallback(score: PDScorePtr, errorMessage: ConstChar) {.cdecl, raises: [].} = invokeCallback( callbackSeqs = privatePersonalBestCallbacks, @@ -107,16 +118,6 @@ proc invokeAddScoreCallback(score: PDScorePtr, errorMessage: ConstChar) {.cdecl, emptyValue = emptyPDScore ) -proc seqBuilder[T, U](rawField: ptr UncheckedArray[T], length: SomeInteger, itemBuilder: proc (item: T): U {.raises: [].}): seq[U] = - privateAccess(SDKArray) - let cArray = SDKArray[T](data: rawField, len: length.int) - var newSeq = newSeq[U](length) - for i in 0 ..< length: - let item = cArray[i] - newSeq[i] = itemBuilder(item) - cArray.data = nil # no need for SDKArray to free the data, free function will do it - return newSeq - proc invokeScoresCallback(scoresList: PDScoresListPtr, errorMessage: ConstChar) {.cdecl, raises: [].} = invokeCallback( callbackSeqs = privateScoresCallbacks, @@ -130,7 +131,6 @@ proc invokeScoresCallback(scoresList: PDScoresListPtr, errorMessage: ConstChar) length = scoresList.count, itemBuilder = scoreBuilder ) - return newPDScoresList(boardID = $scoresList.boardID, lastUpdated = scoresList.lastUpdated, scores = scoresSeq), emptyValue = emptyPDScoresList ) @@ -142,14 +142,12 @@ proc invokeBoardsListCallback(boardsList: PDBoardsListPtr, errorMessage: ConstCh errorMessage = errorMessage, freeValue = playdate.scoreboards.freeBoardsList, builder = proc (boardsList: PDBoardsListPtr): PDBoardsList = - privateAccess(SDKArray) var boardsSeq = seqBuilder( rawField = cast[ptr UncheckedArray[PDBoardRaw]](boardsList.boards), length = boardsList.count, itemBuilder = proc (board: PDBoardRaw): PDBoard = newPDBoard(boardID = $board.boardID, name = $board.name) ) - return newPDBoardsList(lastUpdated = boardsList.lastUpdated, boards = boardsSeq), emptyValue = emptyPDBoardsList ) From 29a87f13fb3d30617b9c61e5b9605e9142287e45 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Fri, 25 Oct 2024 11:11:57 +0200 Subject: [PATCH 066/101] REFACTOR merge type blocks in scoreboard bindings --- src/playdate/bindings/scoreboards.nim | 63 ++++++++++++++------------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/src/playdate/bindings/scoreboards.nim b/src/playdate/bindings/scoreboards.nim index ffe058a..8484034 100644 --- a/src/playdate/bindings/scoreboards.nim +++ b/src/playdate/bindings/scoreboards.nim @@ -2,36 +2,39 @@ import utils -type PDScoreRaw* {.importc: "PDScore", header: "pd_api.h", bycopy.} = object - rank* {.importc: "rank".}: cuint - value* {.importc: "value".}: cuint - player* {.importc: "player".}: cstring - -type PDScorePtr* = ptr PDScoreRaw - -type PDScoresListRaw* {.importc: "PDScoresList", header: "pd_api.h", bycopy.} = object - boardID* {.importc: "boardID".}: cstring - count* {.importc: "count".}: cuint - lastUpdated* {.importc: "lastUpdated".}: cuint - playerIncluded* {.importc: "playerIncluded".}: cuint - limit* {.importc: "limit".}: cuint - scores* {.importc: "scores".}: ptr UncheckedArray[PDScoreRaw] -type PDScoresListPtr* = ptr PDScoresListRaw - -type PDBoardRaw* {.importc: "PDBoard", header: "pd_api.h", bycopy.} = object - boardID* {.importc: "boardID".}: cstring - name* {.importc: "name".}: cstring - -type PDBoardsListRaw* {.importc: "PDBoardsList", header: "pd_api.h", bycopy.} = object - count* {.importc: "count".}: cuint - lastUpdated* {.importc: "lastUpdated".}: cuint - boards* {.importc: "boards".}: ptr UncheckedArray[PDBoardRaw] -type PDBoardsListPtr* = ptr PDBoardsListRaw - -type PersonalBestCallbackRaw* {.importc: "PersonalBestCallback", header: "pd_api.h".} = proc (score: PDScorePtr; errorMessage: cstring) {.cdecl.} -type AddScoreCallbackRaw* {.importc: "AddScoreCallback", header: "pd_api.h".} = proc (score: PDScorePtr; errorMessage: cstring) {.cdecl.} -type BoardsListCallbackRaw* = proc (boards: ptr PDBoardsListRaw; errorMessage: cstring) {.cdecl.} -type ScoresCallbackRaw* = proc (scores: ptr PDScoresListRaw; errorMessage: cstring) {.cdecl.} +type + PDScoreRaw* {.importc: "PDScore", header: "pd_api.h", bycopy.} = object + rank* {.importc: "rank".}: cuint + value* {.importc: "value".}: cuint + player* {.importc: "player".}: cstring + + PDScorePtr* = ptr PDScoreRaw + + PDScoresListRaw* {.importc: "PDScoresList", header: "pd_api.h", bycopy.} = object + boardID* {.importc: "boardID".}: cstring + count* {.importc: "count".}: cuint + lastUpdated* {.importc: "lastUpdated".}: cuint + playerIncluded* {.importc: "playerIncluded".}: cuint + limit* {.importc: "limit".}: cuint + scores* {.importc: "scores".}: ptr UncheckedArray[PDScoreRaw] + + PDScoresListPtr* = ptr PDScoresListRaw + + PDBoardRaw* {.importc: "PDBoard", header: "pd_api.h", bycopy.} = object + boardID* {.importc: "boardID".}: cstring + name* {.importc: "name".}: cstring + + PDBoardsListRaw* {.importc: "PDBoardsList", header: "pd_api.h", bycopy.} = object + count* {.importc: "count".}: cuint + lastUpdated* {.importc: "lastUpdated".}: cuint + boards* {.importc: "boards".}: ptr UncheckedArray[PDBoardRaw] + + PDBoardsListPtr* = ptr PDBoardsListRaw + + PersonalBestCallbackRaw* {.importc: "PersonalBestCallback", header: "pd_api.h".} = proc (score: PDScorePtr; errorMessage: cstring) {.cdecl.} + AddScoreCallbackRaw* {.importc: "AddScoreCallback", header: "pd_api.h".} = proc (score: PDScorePtr; errorMessage: cstring) {.cdecl.} + BoardsListCallbackRaw* = proc (boards: ptr PDBoardsListRaw; errorMessage: cstring) {.cdecl.} + ScoresCallbackRaw* = proc (scores: ptr PDScoresListRaw; errorMessage: cstring) {.cdecl.} sdktype: type PlaydateScoreboards* {.importc: "const struct playdate_scoreboards", header: "pd_api.h".} = object From 43b06bab1548beaefb7b0b0c0ba58f6d830e46e4 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Fri, 25 Oct 2024 11:32:29 +0200 Subject: [PATCH 067/101] CHANGE seqBuilder to iterator and other small refactors --- src/playdate/bindings/utils.nim | 7 +++++++ src/playdate/scoreboards.nim | 29 ++++++----------------------- 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/src/playdate/bindings/utils.nim b/src/playdate/bindings/utils.nim index f2cb4ce..a4cb91a 100644 --- a/src/playdate/bindings/utils.nim +++ b/src/playdate/bindings/utils.nim @@ -1,5 +1,12 @@ import macros +iterator items*[T](rawField: ptr UncheckedArray[T], len: Natural): T = + ## iterate through a C array + ## To convert to a Nim seq: + ## `cArray.items(count).toSeq` + for i in 0.. Date: Fri, 25 Oct 2024 11:57:48 +0200 Subject: [PATCH 068/101] combine scorebuilder procs --- src/playdate/scoreboards.nim | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index ea94cc8..1d89461 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -78,16 +78,13 @@ proc newPDBoardsList(lastUpdated: uint32, boards: seq[PDBoard]): PDBoardsList = PDBoardsList(lastUpdated: lastUpdated, boards: boards) let emptyPDBoardsList = newPDBoardsList(lastUpdated = 0, boards = @[]) -proc scoreBuilder(score: PDScoreRaw): PDScore = +proc scoreBuilder(score: PDScoreRaw | PDScorePtr): PDScore = newPDScore( value = score.value.uint32, rank = score.rank.uint32, player = $score.player ) -proc scoreBuilder(score: PDScorePtr): PDScore = - scoreBuilder(score[]) - proc invokePersonalBestCallback(score: PDScorePtr, errorMessage: ConstChar) {.cdecl, raises: [].} = invokeCallback( callbackSeqs = privatePersonalBestCallbacks, From ff2322cda9e473961ca806c17a27914ee99154ba Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Fri, 25 Oct 2024 14:35:15 +0200 Subject: [PATCH 069/101] CHANGE convert indent size from 2 to 4 --- src/playdate/scoreboards.nim | 204 +++++++++++++++++------------------ 1 file changed, 102 insertions(+), 102 deletions(-) diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index 1d89461..ad83fb7 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -13,141 +13,141 @@ export scoreboards import bindings/scoreboards {.all.} type - PDScore* = object of RootObj - value*, rank*: uint32 - player*: string - - PDScoresList* = object of RootObj - boardID*: string - lastUpdated*: uint32 - scores*: seq[PDScore] - # these properties are not implemented yet in the Playdate API - # playerIncluded*: uint32 - # limit*: uint32 - - PDBoard* = object of RootObj - boardID*, name*: string - - PDBoardsList* = object of RootObj - lastUpdated*: uint32 - boards*: seq[PDBoard] - - PersonalBestCallback* = proc(score: PDScore, errorMessage: string) - AddScoreCallback* = proc(score: PDScore, errorMessage: string) - BoardsListCallback* = proc(boards: PDBoardsList, errorMessage: string) - ScoresCallback* = proc(scores: PDScoresList, errorMessage: string) + PDScore* = object of RootObj + value*, rank*: uint32 + player*: string + + PDScoresList* = object of RootObj + boardID*: string + lastUpdated*: uint32 + scores*: seq[PDScore] + # these properties are not implemented yet in the Playdate API + # playerIncluded*: uint32 + # limit*: uint32 + + PDBoard* = object of RootObj + boardID*, name*: string + + PDBoardsList* = object of RootObj + lastUpdated*: uint32 + boards*: seq[PDBoard] + + PersonalBestCallback* = proc(score: PDScore, errorMessage: string) + AddScoreCallback* = proc(score: PDScore, errorMessage: string) + BoardsListCallback* = proc(boards: PDBoardsList, errorMessage: string) + ScoresCallback* = proc(scores: PDScoresList, errorMessage: string) var - # The sdk callbacks unfortunately don't provide a userdata field to tag the callback with eg. the boardID - # Scoreboard responses are handled in order of request, however, so if we keep track of request order everything should be fine. - # By inserting the callback at the start, it will be popped last: first in, first out - privatePersonalBestCallbacks = newSeq[PersonalBestCallback]() - privateAddScoreCallbacks = newSeq[AddScoreCallback]() - privateScoresCallbacks = newSeq[ScoresCallback]() - privateBoardsListCallbacks = newSeq[BoardsListCallback]() + # The sdk callbacks unfortunately don't provide a userdata field to tag the callback with eg. the boardID + # Scoreboard responses are handled in order of request, however, so if we keep track of request order everything should be fine. + # By inserting the callback at the start, it will be popped last: first in, first out + privatePersonalBestCallbacks = newSeq[PersonalBestCallback]() + privateAddScoreCallbacks = newSeq[AddScoreCallback]() + privateScoresCallbacks = newSeq[ScoresCallback]() + privateBoardsListCallbacks = newSeq[BoardsListCallback]() template invokeCallback(callbackSeqs, value, errorMessage, freeValue, builder, emptyValue: untyped) = - let callback = callbackSeqs.pop() - if value == nil and errorMessage == nil: - callback(emptyValue, "Playdate-nim: No value provided for callback") - return + let callback = callbackSeqs.pop() + if value == nil and errorMessage == nil: + callback(emptyValue, "Playdate-nim: No value provided for callback") + return - if value == nil: - callback(emptyValue, $errorMessage) - return + if value == nil: + callback(emptyValue, $errorMessage) + return - try: - let nimObj = builder(value) - callback(nimObj, $errorMessage) - finally: - freeValue(value) + try: + let nimObj = builder(value) + callback(nimObj, $errorMessage) + finally: + freeValue(value) proc newPDScore(value: uint32, rank: uint32, player: string): PDScore = - PDSCore(value: value, rank: rank, player: player) + PDSCore(value: value, rank: rank, player: player) let emptyPDScore = newPDScore(value = 0, rank = 0, player = "") proc newPDScoresList(boardID: string, lastUpdated: uint32, scores: seq[PDScore]): PDScoresList = - PDScoresList(boardID: boardID, lastUpdated: lastUpdated, scores: scores) + PDScoresList(boardID: boardID, lastUpdated: lastUpdated, scores: scores) let emptyPDScoresList = newPDScoresList(boardID = "", lastUpdated = 0, scores = @[]) proc newPDBoard(boardID: string, name: string): PDBoard = - PDBoard(boardID: boardID, name: name) + PDBoard(boardID: boardID, name: name) proc newPDBoardsList(lastUpdated: uint32, boards: seq[PDBoard]): PDBoardsList = - PDBoardsList(lastUpdated: lastUpdated, boards: boards) + PDBoardsList(lastUpdated: lastUpdated, boards: boards) let emptyPDBoardsList = newPDBoardsList(lastUpdated = 0, boards = @[]) proc scoreBuilder(score: PDScoreRaw | PDScorePtr): PDScore = - newPDScore( - value = score.value.uint32, - rank = score.rank.uint32, - player = $score.player - ) + newPDScore( + value = score.value.uint32, + rank = score.rank.uint32, + player = $score.player + ) proc invokePersonalBestCallback(score: PDScorePtr, errorMessage: ConstChar) {.cdecl, raises: [].} = - invokeCallback( - callbackSeqs = privatePersonalBestCallbacks, - value = score, - errorMessage = errorMessage, - freeValue = playdate.scoreboards.freeScore, - builder = scoreBuilder, - emptyValue = emptyPDScore - ) + invokeCallback( + callbackSeqs = privatePersonalBestCallbacks, + value = score, + errorMessage = errorMessage, + freeValue = playdate.scoreboards.freeScore, + builder = scoreBuilder, + emptyValue = emptyPDScore + ) proc invokeAddScoreCallback(score: PDScorePtr, errorMessage: ConstChar) {.cdecl, raises: [].} = - invokeCallback( - callbackSeqs = privateAddScoreCallbacks, - value = score, - errorMessage = errorMessage, - freeValue = playdate.scoreboards.freeScore, - builder = scoreBuilder, - emptyValue = emptyPDScore - ) + invokeCallback( + callbackSeqs = privateAddScoreCallbacks, + value = score, + errorMessage = errorMessage, + freeValue = playdate.scoreboards.freeScore, + builder = scoreBuilder, + emptyValue = emptyPDScore + ) proc invokeScoresCallback(scoresList: PDScoresListPtr, errorMessage: ConstChar) {.cdecl, raises: [].} = - invokeCallback( - callbackSeqs = privateScoresCallbacks, - value = scoresList, - errorMessage = errorMessage, - freeValue = playdate.scoreboards.freeScoresList, - builder = proc (scoresList: PDScoresListPtr): PDScoresList = - privateAccess(SDKArray) - let scoresSeq = scoresList.scores.items(scoresList.count).toSeq.mapIt(scoreBuilder(it)) - return newPDScoresList(boardID = $scoresList.boardID, lastUpdated = scoresList.lastUpdated, scores = scoresSeq), - emptyValue = emptyPDScoresList - ) + invokeCallback( + callbackSeqs = privateScoresCallbacks, + value = scoresList, + errorMessage = errorMessage, + freeValue = playdate.scoreboards.freeScoresList, + builder = proc (scoresList: PDScoresListPtr): PDScoresList = + privateAccess(SDKArray) + let scoresSeq = scoresList.scores.items(scoresList.count).toSeq.mapIt(scoreBuilder(it)) + return newPDScoresList(boardID = $scoresList.boardID, lastUpdated = scoresList.lastUpdated, scores = scoresSeq), + emptyValue = emptyPDScoresList + ) proc invokeBoardsListCallback(boardsList: PDBoardsListPtr, errorMessage: ConstChar) {.cdecl, raises: [].} = - invokeCallback( - callbackSeqs = privateBoardsListCallbacks, - value = boardsList, - errorMessage = errorMessage, - freeValue = playdate.scoreboards.freeBoardsList, - builder = proc (boardsList: PDBoardsListPtr): PDBoardsList = - let boardsSeq: seq[PDBoard] = boardsList.boards.items(boardsList.count).toSeq.mapIt( - newPDBoard(boardID = $it.boardID, name = $it.name) - ) - return newPDBoardsList(lastUpdated = boardsList.lastUpdated, boards = boardsSeq), - emptyValue = emptyPDBoardsList - ) + invokeCallback( + callbackSeqs = privateBoardsListCallbacks, + value = boardsList, + errorMessage = errorMessage, + freeValue = playdate.scoreboards.freeBoardsList, + builder = proc (boardsList: PDBoardsListPtr): PDBoardsList = + let boardsSeq: seq[PDBoard] = boardsList.boards.items(boardsList.count).toSeq.mapIt( + newPDBoard(boardID = $it.boardID, name = $it.name) + ) + return newPDBoardsList(lastUpdated = boardsList.lastUpdated, boards = boardsSeq), + emptyValue = emptyPDBoardsList + ) proc getPersonalBest*(this: ptr PlaydateScoreboards, boardID: string, callback: PersonalBestCallback): int32 {.discardable.} = - privateAccess(PlaydateScoreboards) - privatePersonalBestCallbacks.insert(callback) # by inserting the callback at the start, it will be popped last: first in, first out - return this.getPersonalBestBinding(boardID.cstring, invokePersonalBestCallback) + privateAccess(PlaydateScoreboards) + privatePersonalBestCallbacks.insert(callback) # by inserting the callback at the start, it will be popped last: first in, first out + return this.getPersonalBestBinding(boardID.cstring, invokePersonalBestCallback) proc addScore*(this: ptr PlaydateScoreboards, boardID: string, value: uint32, callback: AddScoreCallback): int32 {.discardable.} = - privateAccess(PlaydateScoreboards) - privateAddScoreCallbacks.insert(callback) # by inserting the callback at the start, it will be popped last: first in, first out - return this.addScoreBinding(boardID.cstring, value.cuint, invokeAddScoreCallback) + privateAccess(PlaydateScoreboards) + privateAddScoreCallbacks.insert(callback) # by inserting the callback at the start, it will be popped last: first in, first out + return this.addScoreBinding(boardID.cstring, value.cuint, invokeAddScoreCallback) proc getScoreboards*(this: ptr PlaydateScoreboards, callback: BoardsListCallback): int32 {.discardable.} = - privateAccess(PlaydateScoreboards) - privateBoardsListCallbacks.insert(callback) # by inserting the callback at the start, it will be popped last: first in, first out - return this.getScoreboardsBinding(invokeBoardsListCallback) + privateAccess(PlaydateScoreboards) + privateBoardsListCallbacks.insert(callback) # by inserting the callback at the start, it will be popped last: first in, first out + return this.getScoreboardsBinding(invokeBoardsListCallback) proc getScores*(this: ptr PlaydateScoreboards, boardID: string, callback: ScoresCallback): int32 {.discardable.} = - privateAccess(PlaydateScoreboards) - privateScoresCallbacks.insert(callback) # by inserting the callback at the start, it will be popped last: first in, first out - return this.getScoresBinding(boardID.cstring, invokeScoresCallback) \ No newline at end of file + privateAccess(PlaydateScoreboards) + privateScoresCallbacks.insert(callback) # by inserting the callback at the start, it will be popped last: first in, first out + return this.getScoresBinding(boardID.cstring, invokeScoresCallback) \ No newline at end of file From 5b1ca8d8c972d732c357be6349d3258b4ddd4ae7 Mon Sep 17 00:00:00 2001 From: Nycto Date: Fri, 25 Oct 2024 08:17:30 -0700 Subject: [PATCH 070/101] Add scoreboard api shape tests --- tests/src/playdate_tests.nim | 3 ++- tests/t_scoreboards.nim | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 tests/t_scoreboards.nim diff --git a/tests/src/playdate_tests.nim b/tests/src/playdate_tests.nim index ef68018..a3f505b 100644 --- a/tests/src/playdate_tests.nim +++ b/tests/src/playdate_tests.nim @@ -5,7 +5,7 @@ ## import playdate/api -import ../[t_buttons, t_graphics, t_nineslice, t_files, t_midi] +import ../[t_buttons, t_graphics, t_nineslice, t_files, t_midi, t_scoreboards] proc runTests() {.raises: [].} = try: @@ -14,6 +14,7 @@ proc runTests() {.raises: [].} = execNineSliceTests(true) execFilesTest() execMidiTests(true) + execScoreboardTests() except Exception as e: quit(e.msg & "\n" & e.getStackTrace) diff --git a/tests/t_scoreboards.nim b/tests/t_scoreboards.nim new file mode 100644 index 0000000..0e4454c --- /dev/null +++ b/tests/t_scoreboards.nim @@ -0,0 +1,23 @@ +import unittest, playdate/api + +proc execScoreboardTests*() = + + # We can't actually invoke the real scoreboard endpoints, so the best we can do is run the + # nim functions and ensure everything compiles + suite "Scoreboards API verification": + + test "getPersonalBest": + playdate.scoreboards.getPersonalBest("some_board") do (score: PDScore, errorMessage: string) -> void: + discard + + test "addScore": + playdate.scoreboards.addScore("some_board", 123) do (score: PDScore, errorMessage: string) -> void: + discard + + test "getScoreboards": + playdate.scoreboards.getScoreboards() do (boards: PDBoardsList, errorMessage: string) -> void: + discard + + test "getScores": + playdate.scoreboards.getScores("some_board") do (boards: PDScoresList, errorMessage: string) -> void: + discard From a28d5cb32e262142012479786e7da812e8e8f931 Mon Sep 17 00:00:00 2001 From: Nycto Date: Fri, 25 Oct 2024 08:17:49 -0700 Subject: [PATCH 071/101] Use untyped for scorebord callback --- src/playdate/scoreboards.nim | 109 ++++++++++------------------------- 1 file changed, 30 insertions(+), 79 deletions(-) diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index ad83fb7..0c3f4ef 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -1,7 +1,6 @@ {.push raises: [].} -import std/importutils -import std/sequtils +import std/[importutils, sequtils] import types {.all.} import bindings/[api, types, utils] @@ -32,10 +31,10 @@ type lastUpdated*: uint32 boards*: seq[PDBoard] - PersonalBestCallback* = proc(score: PDScore, errorMessage: string) - AddScoreCallback* = proc(score: PDScore, errorMessage: string) - BoardsListCallback* = proc(boards: PDBoardsList, errorMessage: string) - ScoresCallback* = proc(scores: PDScoresList, errorMessage: string) + PersonalBestCallback* = proc(score: PDScore, errorMessage: string) {.raises: [].} + AddScoreCallback* = proc(score: PDScore, errorMessage: string) {.raises: [].} + BoardsListCallback* = proc(boards: PDBoardsList, errorMessage: string) {.raises: [].} + ScoresCallback* = proc(scores: PDScoresList, errorMessage: string) {.raises: [].} var # The sdk callbacks unfortunately don't provide a userdata field to tag the callback with eg. the boardID @@ -46,91 +45,43 @@ var privateScoresCallbacks = newSeq[ScoresCallback]() privateBoardsListCallbacks = newSeq[BoardsListCallback]() -template invokeCallback(callbackSeqs, value, errorMessage, freeValue, builder, emptyValue: untyped) = - let callback = callbackSeqs.pop() - if value == nil and errorMessage == nil: - callback(emptyValue, "Playdate-nim: No value provided for callback") - return +template invokeCallback(callbackSeqs, value, errorMessage, freeValue, builder: untyped) = + let callback = callbackSeqs.pop() + if value == nil and errorMessage == nil: + callback(default(typeof(builder)), "Playdate-nim: No value provided for callback") + return - if value == nil: - callback(emptyValue, $errorMessage) - return + if value == nil: + callback(default(typeof(builder)), $errorMessage) + return - try: - let nimObj = builder(value) - callback(nimObj, $errorMessage) - finally: - freeValue(value) - - -proc newPDScore(value: uint32, rank: uint32, player: string): PDScore = - PDSCore(value: value, rank: rank, player: player) -let emptyPDScore = newPDScore(value = 0, rank = 0, player = "") - -proc newPDScoresList(boardID: string, lastUpdated: uint32, scores: seq[PDScore]): PDScoresList = - PDScoresList(boardID: boardID, lastUpdated: lastUpdated, scores: scores) -let emptyPDScoresList = newPDScoresList(boardID = "", lastUpdated = 0, scores = @[]) - -proc newPDBoard(boardID: string, name: string): PDBoard = - PDBoard(boardID: boardID, name: name) - -proc newPDBoardsList(lastUpdated: uint32, boards: seq[PDBoard]): PDBoardsList = - PDBoardsList(lastUpdated: lastUpdated, boards: boards) -let emptyPDBoardsList = newPDBoardsList(lastUpdated = 0, boards = @[]) + try: + let nimObj = builder + callback(nimObj, $errorMessage) + finally: + freeValue(value) proc scoreBuilder(score: PDScoreRaw | PDScorePtr): PDScore = - newPDScore( - value = score.value.uint32, - rank = score.rank.uint32, - player = $score.player - ) + PDSCore(value: score.value.uint32, rank: score.rank.uint32, player: $score.player) proc invokePersonalBestCallback(score: PDScorePtr, errorMessage: ConstChar) {.cdecl, raises: [].} = - invokeCallback( - callbackSeqs = privatePersonalBestCallbacks, - value = score, - errorMessage = errorMessage, - freeValue = playdate.scoreboards.freeScore, - builder = scoreBuilder, - emptyValue = emptyPDScore - ) + invokeCallback(privatePersonalBestCallbacks, score, errorMessage, playdate.scoreboards.freeScore): + scoreBuilder(score) proc invokeAddScoreCallback(score: PDScorePtr, errorMessage: ConstChar) {.cdecl, raises: [].} = - invokeCallback( - callbackSeqs = privateAddScoreCallbacks, - value = score, - errorMessage = errorMessage, - freeValue = playdate.scoreboards.freeScore, - builder = scoreBuilder, - emptyValue = emptyPDScore - ) + invokeCallback(privateAddScoreCallbacks, score, errorMessage, playdate.scoreboards.freeScore): + scoreBuilder(score) proc invokeScoresCallback(scoresList: PDScoresListPtr, errorMessage: ConstChar) {.cdecl, raises: [].} = - invokeCallback( - callbackSeqs = privateScoresCallbacks, - value = scoresList, - errorMessage = errorMessage, - freeValue = playdate.scoreboards.freeScoresList, - builder = proc (scoresList: PDScoresListPtr): PDScoresList = - privateAccess(SDKArray) - let scoresSeq = scoresList.scores.items(scoresList.count).toSeq.mapIt(scoreBuilder(it)) - return newPDScoresList(boardID = $scoresList.boardID, lastUpdated = scoresList.lastUpdated, scores = scoresSeq), - emptyValue = emptyPDScoresList - ) + invokeCallback(privateScoresCallbacks, scoresList, errorMessage, playdate.scoreboards.freeScoresList): + let scoresSeq = scoresList.scores.items(scoresList.count).toSeq.mapIt(scoreBuilder(it)) + PDScoresList(boardID: $scoresList.boardID, lastUpdated: scoresList.lastUpdated, scores: scoresSeq) proc invokeBoardsListCallback(boardsList: PDBoardsListPtr, errorMessage: ConstChar) {.cdecl, raises: [].} = - invokeCallback( - callbackSeqs = privateBoardsListCallbacks, - value = boardsList, - errorMessage = errorMessage, - freeValue = playdate.scoreboards.freeBoardsList, - builder = proc (boardsList: PDBoardsListPtr): PDBoardsList = - let boardsSeq: seq[PDBoard] = boardsList.boards.items(boardsList.count).toSeq.mapIt( - newPDBoard(boardID = $it.boardID, name = $it.name) - ) - return newPDBoardsList(lastUpdated = boardsList.lastUpdated, boards = boardsSeq), - emptyValue = emptyPDBoardsList - ) + invokeCallback(privateBoardsListCallbacks, boardsList, errorMessage, playdate.scoreboards.freeBoardsList): + let boardsSeq = boardsList.boards.items(boardsList.count).toSeq + .mapIt(PDBoard(boardID: $it.boardID, name: $it.name)) + PDBoardsList(lastUpdated: boardsList.lastUpdated, boards: boardsSeq) proc getPersonalBest*(this: ptr PlaydateScoreboards, boardID: string, callback: PersonalBestCallback): int32 {.discardable.} = privateAccess(PlaydateScoreboards) From 7e91b32477659874fa28744b973b4be007ac2d86 Mon Sep 17 00:00:00 2001 From: Nycto Date: Fri, 25 Oct 2024 08:39:02 -0700 Subject: [PATCH 072/101] Use PDResult for scoreboard callbacks --- src/playdate/scoreboards.nim | 40 ++++++++++++++++++++---------------- tests/t_scoreboards.nim | 12 ++++++----- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index 0c3f4ef..a45e004 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -31,10 +31,17 @@ type lastUpdated*: uint32 boards*: seq[PDBoard] - PersonalBestCallback* = proc(score: PDScore, errorMessage: string) {.raises: [].} - AddScoreCallback* = proc(score: PDScore, errorMessage: string) {.raises: [].} - BoardsListCallback* = proc(boards: PDBoardsList, errorMessage: string) {.raises: [].} - ScoresCallback* = proc(scores: PDScoresList, errorMessage: string) {.raises: [].} + PDResultKind* = enum PDResultSuccess, PDResultError + + PDResult*[T] = object + case kind*: PDResultKind + of PDResultSuccess: result*: T + of PDResultError: message*: string + + PersonalBestCallback* = proc(result: PDResult[PDScore]) {.raises: [].} + AddScoreCallback* = proc(result: PDResult[PDScore]) {.raises: [].} + BoardsListCallback* = proc(result: PDResult[PDBoardsList]) {.raises: [].} + ScoresCallback* = proc(result: PDResult[PDScoresList]) {.raises: [].} var # The sdk callbacks unfortunately don't provide a userdata field to tag the callback with eg. the boardID @@ -46,20 +53,17 @@ var privateBoardsListCallbacks = newSeq[BoardsListCallback]() template invokeCallback(callbackSeqs, value, errorMessage, freeValue, builder: untyped) = - let callback = callbackSeqs.pop() - if value == nil and errorMessage == nil: - callback(default(typeof(builder)), "Playdate-nim: No value provided for callback") - return - - if value == nil: - callback(default(typeof(builder)), $errorMessage) - return - - try: - let nimObj = builder - callback(nimObj, $errorMessage) - finally: - freeValue(value) + type ResultType = typeof(builder) + let callback = callbackSeqs.pop() + if value == nil: + let message = if errorMessage == nil: "Playdate-nim: No value provided for callback" else: $errorMessage + callback(PDResult[ResultType](kind: PDResultError, message: message)) + else: + try: + let built = builder + callback(PDResult[ResultType](kind: PDResultSuccess, result: built)) + finally: + freeValue(value) proc scoreBuilder(score: PDScoreRaw | PDScorePtr): PDScore = PDSCore(value: score.value.uint32, rank: score.rank.uint32, player: $score.player) diff --git a/tests/t_scoreboards.nim b/tests/t_scoreboards.nim index 0e4454c..314507c 100644 --- a/tests/t_scoreboards.nim +++ b/tests/t_scoreboards.nim @@ -7,17 +7,19 @@ proc execScoreboardTests*() = suite "Scoreboards API verification": test "getPersonalBest": - playdate.scoreboards.getPersonalBest("some_board") do (score: PDScore, errorMessage: string) -> void: - discard + playdate.scoreboards.getPersonalBest("some_board") do (score: PDResult[PDScore]) -> void: + case score.kind + of PDResultSuccess: echo $score.result + of PDResultError: echo $score.message test "addScore": - playdate.scoreboards.addScore("some_board", 123) do (score: PDScore, errorMessage: string) -> void: + playdate.scoreboards.addScore("some_board", 123) do (score: PDResult[PDScore]) -> void: discard test "getScoreboards": - playdate.scoreboards.getScoreboards() do (boards: PDBoardsList, errorMessage: string) -> void: + playdate.scoreboards.getScoreboards() do (boards: PDResult[PDBoardsList]) -> void: discard test "getScores": - playdate.scoreboards.getScores("some_board") do (boards: PDScoresList, errorMessage: string) -> void: + playdate.scoreboards.getScores("some_board") do (scores: PDResult[PDScoresList]) -> void: discard From 09e76714bccd69be481f19570dec15459f5bfedd Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Tue, 29 Oct 2024 15:40:37 +0100 Subject: [PATCH 073/101] ADD PDResultSuccessEmpty --- src/playdate/scoreboards.nim | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index a45e004..62bd88d 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -31,11 +31,16 @@ type lastUpdated*: uint32 boards*: seq[PDBoard] - PDResultKind* = enum PDResultSuccess, PDResultError + PDResultKind* = enum + PDResultSuccess, + PDResultSuccessEmpty + ## The operation completed successfully, but the response had no data + PDResultError, PDResult*[T] = object case kind*: PDResultKind of PDResultSuccess: result*: T + of PDResultSuccessEmpty: discard of PDResultError: message*: string PersonalBestCallback* = proc(result: PDResult[PDScore]) {.raises: [].} @@ -56,8 +61,7 @@ template invokeCallback(callbackSeqs, value, errorMessage, freeValue, builder: u type ResultType = typeof(builder) let callback = callbackSeqs.pop() if value == nil: - let message = if errorMessage == nil: "Playdate-nim: No value provided for callback" else: $errorMessage - callback(PDResult[ResultType](kind: PDResultError, message: message)) + callback(PDResult[ResultType](kind: PDResultSuccessEmpty)) else: try: let built = builder @@ -88,11 +92,13 @@ proc invokeBoardsListCallback(boardsList: PDBoardsListPtr, errorMessage: ConstCh PDBoardsList(lastUpdated: boardsList.lastUpdated, boards: boardsSeq) proc getPersonalBest*(this: ptr PlaydateScoreboards, boardID: string, callback: PersonalBestCallback): int32 {.discardable.} = + ## Responds with PDResultSuccessEmpty if no score exists for the current player. privateAccess(PlaydateScoreboards) privatePersonalBestCallbacks.insert(callback) # by inserting the callback at the start, it will be popped last: first in, first out return this.getPersonalBestBinding(boardID.cstring, invokePersonalBestCallback) proc addScore*(this: ptr PlaydateScoreboards, boardID: string, value: uint32, callback: AddScoreCallback): int32 {.discardable.} = + ## Responds with PDResultSuccessEmpty if the score was qeued for later submission. Probably, Wi-Fi is not available. privateAccess(PlaydateScoreboards) privateAddScoreCallbacks.insert(callback) # by inserting the callback at the start, it will be popped last: first in, first out return this.addScoreBinding(boardID.cstring, value.cuint, invokeAddScoreCallback) From 9ed2a93310b69bbb7d520979d8bf0fcf64275494 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Tue, 29 Oct 2024 15:51:33 +0100 Subject: [PATCH 074/101] FIX scoreboard unittest --- tests/t_scoreboards.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/t_scoreboards.nim b/tests/t_scoreboards.nim index 314507c..5055aaf 100644 --- a/tests/t_scoreboards.nim +++ b/tests/t_scoreboards.nim @@ -11,6 +11,7 @@ proc execScoreboardTests*() = case score.kind of PDResultSuccess: echo $score.result of PDResultError: echo $score.message + of PDResultSuccessEmpty: echo "SuccessEmpty" test "addScore": playdate.scoreboards.addScore("some_board", 123) do (score: PDResult[PDScore]) -> void: From bcdf181321ef5f078cb9e6486d37a610b69089dc Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Wed, 6 Nov 2024 22:07:58 +0100 Subject: [PATCH 075/101] CHANGE PDResultSuccessEmpty to PDResultUnavailable --- src/playdate/scoreboards.nim | 16 ++++++++-------- tests/t_scoreboards.nim | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index 62bd88d..fdfbcf9 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -32,15 +32,15 @@ type boards*: seq[PDBoard] PDResultKind* = enum - PDResultSuccess, - PDResultSuccessEmpty - ## The operation completed successfully, but the response had no data - PDResultError, + PDResultSuccess, + PDResultUnavailable, + ## The operation completed successfully, but the response had no data + PDResultError, PDResult*[T] = object case kind*: PDResultKind of PDResultSuccess: result*: T - of PDResultSuccessEmpty: discard + of PDResultUnavailable: discard of PDResultError: message*: string PersonalBestCallback* = proc(result: PDResult[PDScore]) {.raises: [].} @@ -61,7 +61,7 @@ template invokeCallback(callbackSeqs, value, errorMessage, freeValue, builder: u type ResultType = typeof(builder) let callback = callbackSeqs.pop() if value == nil: - callback(PDResult[ResultType](kind: PDResultSuccessEmpty)) + callback(PDResult[ResultType](kind: PDResultUnavailable)) else: try: let built = builder @@ -92,13 +92,13 @@ proc invokeBoardsListCallback(boardsList: PDBoardsListPtr, errorMessage: ConstCh PDBoardsList(lastUpdated: boardsList.lastUpdated, boards: boardsSeq) proc getPersonalBest*(this: ptr PlaydateScoreboards, boardID: string, callback: PersonalBestCallback): int32 {.discardable.} = - ## Responds with PDResultSuccessEmpty if no score exists for the current player. + ## Responds with PDResultUnavailable if no score exists for the current player. privateAccess(PlaydateScoreboards) privatePersonalBestCallbacks.insert(callback) # by inserting the callback at the start, it will be popped last: first in, first out return this.getPersonalBestBinding(boardID.cstring, invokePersonalBestCallback) proc addScore*(this: ptr PlaydateScoreboards, boardID: string, value: uint32, callback: AddScoreCallback): int32 {.discardable.} = - ## Responds with PDResultSuccessEmpty if the score was qeued for later submission. Probably, Wi-Fi is not available. + ## Responds with PDResultUnavailable if the score was queued for later submission. Probably, Wi-Fi is not available. privateAccess(PlaydateScoreboards) privateAddScoreCallbacks.insert(callback) # by inserting the callback at the start, it will be popped last: first in, first out return this.addScoreBinding(boardID.cstring, value.cuint, invokeAddScoreCallback) diff --git a/tests/t_scoreboards.nim b/tests/t_scoreboards.nim index 5055aaf..4fe41f9 100644 --- a/tests/t_scoreboards.nim +++ b/tests/t_scoreboards.nim @@ -11,7 +11,7 @@ proc execScoreboardTests*() = case score.kind of PDResultSuccess: echo $score.result of PDResultError: echo $score.message - of PDResultSuccessEmpty: echo "SuccessEmpty" + of PDResultUnavailable: echo "SuccessEmpty" test "addScore": playdate.scoreboards.addScore("some_board", 123) do (score: PDResult[PDScore]) -> void: From 50cec6cf46ce277b7a045466f96f3407cc537577 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Fri, 8 Nov 2024 19:11:05 +0100 Subject: [PATCH 076/101] FIX PDResultError never used --- src/playdate/scoreboards.nim | 5 ++++- tests/t_scoreboards.nim | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/playdate/scoreboards.nim b/src/playdate/scoreboards.nim index fdfbcf9..5c6b24a 100644 --- a/src/playdate/scoreboards.nim +++ b/src/playdate/scoreboards.nim @@ -61,7 +61,10 @@ template invokeCallback(callbackSeqs, value, errorMessage, freeValue, builder: u type ResultType = typeof(builder) let callback = callbackSeqs.pop() if value == nil: - callback(PDResult[ResultType](kind: PDResultUnavailable)) + if errorMessage == nil: + callback(PDResult[ResultType](kind: PDResultUnavailable)) + else: + callback(PDResult[ResultType](kind: PDResultError, message: $errorMessage)) else: try: let built = builder diff --git a/tests/t_scoreboards.nim b/tests/t_scoreboards.nim index 4fe41f9..cb76acc 100644 --- a/tests/t_scoreboards.nim +++ b/tests/t_scoreboards.nim @@ -11,7 +11,7 @@ proc execScoreboardTests*() = case score.kind of PDResultSuccess: echo $score.result of PDResultError: echo $score.message - of PDResultUnavailable: echo "SuccessEmpty" + of PDResultUnavailable: echo "PDResultUnavailable" test "addScore": playdate.scoreboards.addScore("some_board", 123) do (score: PDResult[PDScore]) -> void: From 7ec9871811f3737d849b59695c3be81912c3cea9 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Fri, 8 Nov 2024 22:37:29 +0100 Subject: [PATCH 077/101] ADD fadeVolume --- src/playdate/bindings/sound.nim | 8 ++++---- src/playdate/sound.nim | 17 ++++++++++++++++- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/playdate/bindings/sound.nim b/src/playdate/bindings/sound.nim index 9edaabd..f9081a1 100644 --- a/src/playdate/bindings/sound.nim +++ b/src/playdate/bindings/sound.nim @@ -38,15 +38,15 @@ type PlaydateSoundFileplayer {.importc: "const struct playdate_sound_fileplayer" # start: cfloat; `end`: cfloat) {.cdecl.} # didUnderrun* {.importc: "didUnderrun".}: proc (player: ptr FilePlayer): cint {.cdecl.} setFinishCallback* {.importc: "setFinishCallback".}: proc ( - player: FilePlayerPtr; callback: PDSndCallbackProcRaw, userData: pointer = nil) {.cdecl, raises: [].} + player: FilePlayerPtr; callback: PDSndCallbackProcRaw, userdata: pointer = nil) {.cdecl, raises: [].} # setLoopCallback* {.importc: "setLoopCallback".}: proc (player: ptr FilePlayer; # callback: SndCallbackProc) {.cdecl.} getOffset {.importc: "getOffset".}: proc (player: FilePlayerPtr): cfloat {.cdecl, raises: [].} # getRate* {.importc: "getRate".}: proc (player: ptr FilePlayer): cfloat {.cdecl.} # setStopOnUnderrun* {.importc: "setStopOnUnderrun".}: proc ( # player: ptr FilePlayer; flag: cint) {.cdecl.} - # fadeVolume* {.importc: "fadeVolume".}: proc (player: ptr FilePlayer; left: cfloat; - # right: cfloat; len: int32T; finishCallback: SndCallbackProc) {.cdecl.} + fadeVolume* {.importc: "fadeVolume".}: proc (player: FilePlayerPtr; left: cfloat; + right: cfloat; len: cint; finishCallback: PDSndCallbackProcRaw, userdata: pointer = nil) {.cdecl, raises:[].} # setMP3StreamSource* {.importc: "setMP3StreamSource".}: proc ( # player: ptr FilePlayer; dataSource: proc (data: ptr uint8T; bytes: cint; # userdata: pointer): cint {.cdecl.}; userdata: pointer; bufferLen: cfloat) {. @@ -90,7 +90,7 @@ type PlaydateSoundSampleplayer {.importc: "const struct playdate_sound_samplepla setPlayRange* {.importc: "setPlayRange".}: proc (player: SamplePlayerPtr; start: cint; `end`: cint) {.cdecl, raises: [].} setFinishCallback* {.importc: "setFinishCallback".}: proc ( - player: SamplePlayerPtr; callback: PDSndCallbackProcRaw, userData: pointer = nil) {.cdecl, raises: [].} + player: SamplePlayerPtr; callback: PDSndCallbackProcRaw, userdata: pointer = nil) {.cdecl, raises: [].} # setLoopCallback* {.importc: "setLoopCallback".}: proc (player: ptr SamplePlayer; # callback: SndCallbackProc) {.cdecl.} getOffset* {.importc: "getOffset".}: proc (player: SamplePlayerPtr): cfloat {.cdecl , raises: [].} diff --git a/src/playdate/sound.nim b/src/playdate/sound.nim index 90cde0a..4293184 100644 --- a/src/playdate/sound.nim +++ b/src/playdate/sound.nim @@ -16,7 +16,7 @@ type resource: AudioSamplePtr AudioSample* = ref AudioSampleObj - PDSoundCallbackFunction* = proc(userData: pointer) {.raises: [].} + PDSoundCallbackFunction* = proc(userdata: pointer) {.raises: [].} proc `=destroy`(this: var AudioSampleObj) = privateAccess(PlaydateSound) @@ -55,6 +55,7 @@ type SoundSource* = ref SoundSourceObj type FilePlayerObj = object of SoundSourceObj finishCallback: PDFilePlayerCallbackFunction + fadeVolumeCallback: PDFilePlayerCallbackFunction FilePlayer* = ref FilePlayerObj PDFilePlayerCallbackFunction* = proc(player: FilePlayer) {.raises: [].} @@ -139,6 +140,11 @@ proc privateFilePlayerFinishCallback(soundSource: SoundSourcePtr, userdata: poin if filePlayer.finishCallback != nil: filePlayer.finishCallback(filePlayer) +proc privateFilePlayerFadeVolumeCallback(soundSource: SoundSourcePtr, userdata: pointer) {.cdecl, raises: [].} = + let filePlayer = cast[FilePlayer](userdata) + if filePlayer.fadeVolumeCallback != nil: + filePlayer.fadeVolumeCallback(filePlayer) + proc setFinishCallback*(this: FilePlayer, callback: PDFilePlayerCallbackFunction) = privateAccess(PlaydateSound) privateAccess(PlaydateSoundFileplayer) @@ -148,6 +154,15 @@ proc setFinishCallback*(this: FilePlayer, callback: PDFilePlayerCallbackFunction else: playdate.sound.fileplayer.setFinishCallback(this.resource, privateFilePlayerFinishCallback, cast[pointer](this)) +proc fadeVolume*(this: FilePlayer, left, right: float32, len: int32, callback: PDFilePlayerCallbackFunction) = + privateAccess(PlaydateSound) + privateAccess(PlaydateSoundFileplayer) + this.fadeVolumeCallback = callback + if callback == nil: + playdate.sound.fileplayer.fadeVolume(this.resource, left.cfloat, right.cfloat, len.cint , nil, nil) + else: + playdate.sound.fileplayer.fadeVolume(this.resource, left.cfloat, right.cfloat, len.cint , privateFilePlayerFadeVolumeCallback, cast[pointer](this)) + proc finishCallback*(this: FilePlayer): PDFilePlayerCallbackFunction = return this.finishCallback From 0962e655797324e66188fea34d9a1d62ed180232 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Fri, 8 Nov 2024 23:15:09 +0100 Subject: [PATCH 078/101] ADD background music fade in to playdate_example.nim --- playdate_example/src/playdate_example.nim | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/playdate_example/src/playdate_example.nim b/playdate_example/src/playdate_example.nim index 99c4ec7..c068a0b 100644 --- a/playdate_example/src/playdate_example.nim +++ b/playdate_example/src/playdate_example.nim @@ -3,6 +3,10 @@ import playdate/api const FONT_PATH = "/System/Fonts/Asheville-Sans-14-Bold.pft" const NIM_IMAGE_PATH = "/images/nim_logo" const PLAYDATE_NIM_IMAGE_PATH = "/images/playdate_nim" +const BACKGROUND_MUSIC_PATH = "/audio/finally_see_the_light" +const BACKGROUND_MUSIC_SAMPLE_RATE = 48_000 +const BACKGROUND_MUSIC_FADE_IN_SECONDS = 4.0 +const BACKGROUND_MUSIC_FADE_IN_SAMPLES = (BACKGROUND_MUSIC_SAMPLE_RATE * BACKGROUND_MUSIC_FADE_IN_SECONDS).int32 var font: LCDFont @@ -80,9 +84,11 @@ proc handler(event: PDSystemEvent, keycode: uint) {.raises: [].} = except: playdate.system.logToConsole(getCurrentExceptionMsg()) # Inline try/except - filePlayer = try: playdate.sound.newFilePlayer("/audio/finally_see_the_light") except: nil + filePlayer = try: playdate.sound.newFilePlayer(BACKGROUND_MUSIC_PATH) except: nil filePlayer.play(0) + fileplayer.volume = 0.0 # first set folume to 0% + filePlayer.fadeVolume(1.0, 1.0, BACKGROUND_MUSIC_FADE_IN_SAMPLES, nil) # then fade to 100% # Add a checkmark menu item that plays a sound when switched and unpaused discard playdate.system.addCheckmarkMenuItem("Checkmark", false, From 6044a174a78221f5e3d60a369dbe47b8020d3c53 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Thu, 28 Nov 2024 21:54:14 +0100 Subject: [PATCH 079/101] FIX typo in nimbleTesting logic --- src/playdate/build/config.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/playdate/build/config.nim b/src/playdate/build/config.nim index 6cd3a8e..8b1fc54 100644 --- a/src/playdate/build/config.nim +++ b/src/playdate/build/config.nim @@ -11,7 +11,7 @@ when not compiles(task): import system/nimscript const headlessTesting = defined(simulator) and declared(test) -const nimbleTesting = not defined(simulator) and not defined(devide) and declared(test) +const nimbleTesting = not defined(simulator) and not defined(device) and declared(test) const testing = headlessTesting or nimbleTesting # Path to the playdate src directory when checked out locally From 7efad74f393b8e9af99f3e161eddd668a5939843 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Thu, 28 Nov 2024 21:55:16 +0100 Subject: [PATCH 080/101] ADD useHostOS flag to make the os module available --- src/playdate/build/config.nim | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/playdate/build/config.nim b/src/playdate/build/config.nim index 8b1fc54..298acf2 100644 --- a/src/playdate/build/config.nim +++ b/src/playdate/build/config.nim @@ -14,6 +14,10 @@ const headlessTesting = defined(simulator) and declared(test) const nimbleTesting = not defined(simulator) and not defined(device) and declared(test) const testing = headlessTesting or nimbleTesting +# Use the host OS for compilation. This is useful when running supporting development tools that import the playdate SDK or where the os module needs to be available. +# This does not make the playdate api callable, only the types (header files) are available. +const useHostOS = defined(useHostOS) + # Path to the playdate src directory when checked out locally const localPlaydatePath = currentSourcePath / "../../../../src" @@ -45,7 +49,9 @@ switch("passC", "-Wno-unknown-pragmas") switch("passC", "-Wdouble-promotion") switch("passC", "-I" & sdkPath() / "C_API") -switch("os", "any") +if not useHostOS: + echo "Setting os to any" + switch("os", "any") switch("define", "useMalloc") switch("define", "standalone") switch("threads", "off") @@ -133,8 +139,8 @@ when defined(simulator): switch("passC", "-DTARGET_SIMULATOR=1") switch("passC", "-Wstrict-prototypes") -if nimbleTesting: - # Compiling for tests. +if useHostOS or nimbleTesting: + # Compiling for host system environment. switch("define", "simulator") switch("nimcache", nimcacheDir() / "simulator") From ecd67e73c17859c92678fa5b852a316dea5aaa70 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Thu, 28 Nov 2024 22:05:02 +0100 Subject: [PATCH 081/101] ADD make main available when useHostOS is set --- src/playdate/build/config.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/playdate/build/config.nim b/src/playdate/build/config.nim index 298acf2..4f396fe 100644 --- a/src/playdate/build/config.nim +++ b/src/playdate/build/config.nim @@ -28,7 +28,7 @@ let nimblePlaydatePath = else: gorgeEx("nimble path playdate").output.split("\n")[0] -if not testing: +if not testing and not useHostOS: switch("noMain", "on") switch("backend", "c") switch("mm", "arc") From 2c4ce20e03b459e268871a9300ff34e16c4ccf5f Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Mon, 16 Dec 2024 18:22:55 +0100 Subject: [PATCH 082/101] CHANGE version to 0.21.0 --- playdate.nimble | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playdate.nimble b/playdate.nimble index 196ab55..1e9a35d 100644 --- a/playdate.nimble +++ b/playdate.nimble @@ -1,6 +1,6 @@ # Package -version = "0.20.0" +version = "0.21.0" author = "Samuele Zolfanelli" description = "Playdate Nim bindings with extra features." license = "MIT" From 55246d6b4e0b76494fb3c36306a775aa2764b345 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Sat, 28 Dec 2024 19:26:16 +0100 Subject: [PATCH 083/101] ADD getRefreshRate --- src/playdate/bindings/display.nim | 11 +++++++---- src/playdate/display.nim | 16 +++++++++++++++- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/playdate/bindings/display.nim b/src/playdate/bindings/display.nim index 26d3527..52a8ade 100644 --- a/src/playdate/bindings/display.nim +++ b/src/playdate/bindings/display.nim @@ -4,11 +4,14 @@ import utils sdktype: type PlaydateDisplay* {.importc: "const struct playdate_display", header: "pd_api.h".} = object + # directly mapped to C api getWidth {.importsdk.}: proc (): cint getHeight {.importsdk.}: proc (): cint - setRefreshRate {.importsdk.}: proc (rate: cfloat) - setInverted {.importc: "setInverted".}: proc (flag: cint) {.cdecl, raises: [].} setScale {.importsdk.}: proc (s: cuint) setMosaic {.importsdk.}: proc (x: cuint; y: cuint) - setFlipped {.importc: "setFlipped".}: proc (x: cint; y: cint) {.cdecl, raises: [].} - setOffset {.importsdk.}: proc (x: cint; y: cint) \ No newline at end of file + setOffset* {.importsdk.}: proc (x: cint; y: cint) + + # Called from Nim (src/playdate/display.nim) + setRefreshRate {.importc: "setRefreshRate".}: proc (rate: cfloat) {.cdecl, raises: [].} + setInverted {.importc: "setInverted".}: proc (flag: cint) {.cdecl, raises: [].} + setFlipped {.importc: "setFlipped".}: proc (x: cint; y: cint) {.cdecl, raises: [].} \ No newline at end of file diff --git a/src/playdate/display.nim b/src/playdate/display.nim index 5733c57..56c6d0a 100644 --- a/src/playdate/display.nim +++ b/src/playdate/display.nim @@ -9,10 +9,24 @@ export display {.hint[DuplicateModuleImport]: off.} import bindings/display {.all.} +var + refreshRate = 30f + ## bookkeeping variable for refresh rate, because API does not provide a getter. + ## Initial value is the rate that is set on device boot + proc setInverted* (this: ptr PlaydateDisplay, inverted: bool) = privateAccess(PlaydateDisplay) this.setInverted(if inverted: 1 else: 0) proc setFlipped* (this: ptr PlaydateDisplay, x: bool, y: bool) = privateAccess(PlaydateDisplay) - this.setFlipped(if x: 1 else: 0, if y: 1 else: 0) \ No newline at end of file + this.setFlipped(if x: 1 else: 0, if y: 1 else: 0) + + +proc getRefreshRate* (this: ptr PlaydateDisplay): float32 = + refreshRate + +proc setRefreshRate* (this: ptr PlaydateDisplay, rate: float32) = + privateAccess(PlaydateDisplay) + refreshRate = rate + this.setRefreshRate(rate) \ No newline at end of file From 862ce3564932e1f5c4d7857f146995e623c07dbf Mon Sep 17 00:00:00 2001 From: Nycto Date: Sun, 13 Oct 2024 16:48:59 -0700 Subject: [PATCH 084/101] Don't use refs for unmanaged bitmaps --- playdate_example/src/playdate_example.nim | 4 +- src/playdate/graphics.nim | 81 +++++++++++++++-------- src/playdate/sprite.nim | 6 +- 3 files changed, 59 insertions(+), 32 deletions(-) diff --git a/playdate_example/src/playdate_example.nim b/playdate_example/src/playdate_example.nim index c068a0b..0789bc6 100644 --- a/playdate_example/src/playdate_example.nim +++ b/playdate_example/src/playdate_example.nim @@ -99,8 +99,8 @@ proc handler(event: PDSystemEvent, keycode: uint) {.raises: [].} = font = try: playdate.graphics.newFont(FONT_PATH) except: nil playdate.graphics.setFont(font) - playdateNimBitmap = try: playdate.graphics.newBitmap(PLAYDATE_NIM_IMAGE_PATH) except: nil - nimLogoBitmap = try: playdate.graphics.newBitmap(NIM_IMAGE_PATH) except: nil + playdateNimBitmap = try: playdate.graphics.newBitmap(PLAYDATE_NIM_IMAGE_PATH) except: return + nimLogoBitmap = try: playdate.graphics.newBitmap(NIM_IMAGE_PATH) except: return sprite = playdate.sprite.newSprite() sprite.add() diff --git a/src/playdate/graphics.nim b/src/playdate/graphics.nim index f7f934c..5238f23 100644 --- a/src/playdate/graphics.nim +++ b/src/playdate/graphics.nim @@ -11,22 +11,49 @@ export graphics {.hint[DuplicateModuleImport]: off.} import bindings/graphics {.all.} -type LCDBitmapObj = object of RootObj - resource {.requiresinit.}: LCDBitmapPtr - free: bool +type + LCDBitmapObj = object of RootObj + res {.requiresinit.}: LCDBitmapPtr + + LCDBitmapObjRef = ref LCDBitmapObj + + LCDBitmap* = object + case managed: bool + of true: + obj: LCDBitmapObjRef + of false: + res: LCDBitmapPtr + proc `=destroy`(this: var LCDBitmapObj) = privateAccess(PlaydateGraphics) - if this.free: - playdate.graphics.freeBitmap(this.resource) -type LCDBitmap* = ref LCDBitmapObj + if this.res != nil: + playdate.graphics.freeBitmap(this.res) + +proc `=copy`(a: var LCDBitmapObj, b: LCDBitmapObj) {.error.} + +proc bitmapPtr(point: LCDBitmapPtr): auto = + LCDBitmap(managed: false, res: point) + +proc bitmapRef(point: LCDBitmapPtr): auto = + LCDBitmap(managed: true, obj: LCDBitmapObjRef(res: point)) + +proc resource*(bitmap: LCDBitmap): LCDBitmapPtr = + if bitmap.managed: + return if bitmap.obj != nil: bitmap.obj.res else: nil + else: + return bitmap.res + +proc isNil*(bitmap: LCDBitmap): bool = + return bitmap.resource == nil type LCDVideoPlayerObj = object of RootObj resource {.requiresinit.}: LCDVideoPlayerPtr context: LCDBitmap + proc `=destroy`(this: var LCDVideoPlayerObj) = privateAccess(PlaydateVideo) playdate.graphics.video.freePlayer(this.resource) - this.context = nil + this.context.reset() type LCDVideoPlayer* = ref LCDVideoPlayerObj proc newVideoPlayer*(this: ptr PlaydateVideo, path: string): LCDVideoPlayer {.raises: [IOError]} = @@ -38,14 +65,14 @@ proc newVideoPlayer*(this: ptr PlaydateVideo, path: string): LCDVideoPlayer {.ra proc setContext*(this: LCDVideoPlayer, context: LCDBitmap) {.raises: [CatchableError]} = privateAccess(PlaydateVideo) - if playdate.graphics.video.setContext(this.resource, if context != nil: context.resource else: nil) == 0: + if playdate.graphics.video.setContext(this.resource, context.resource) == 0: raise newException(CatchableError, $playdate.graphics.video.getError(this.resource)) this.context = context proc useScreenContext*(this: LCDVideoPlayer) = privateAccess(PlaydateVideo) playdate.graphics.video.useScreenContext(this.resource) - this.context = nil + this.context.reset() proc renderFrame*(this: LCDVideoPlayer, index: int) {.raises: [CatchableError]} = privateAccess(PlaydateVideo) @@ -63,8 +90,8 @@ proc getContext*(this: LCDVideoPlayer): LCDBitmap = privateAccess(PlaydateVideo) let bitmapPtr = playdate.graphics.video.getContext(this.resource) playdate.system.logToConsole(fmt"video context: {bitmapPtr.repr}") - if this.context == nil or this.context.resource != bitmapPtr: - this.context = LCDBitmap(resource: bitmapPtr, free: false) + if this.context.isNil or this.context.resource != bitmapPtr: + this.context = bitmapPtr(bitmapPtr) return this.context var currentFont: LCDFont @@ -80,7 +107,7 @@ proc getFont*(this: ptr PlaydateGraphics): LCDFont = proc pushContext*(this: ptr PlaydateGraphics, target: LCDBitmap) = privateAccess(PlaydateGraphics) - this.pushContext(if target != nil: target.resource else: nil) + this.pushContext(target.resource) proc draw*(this: LCDBitmap, x: int, y: int, flip: LCDBitmapFlip) = privateAccess(PlaydateGraphics) @@ -105,19 +132,19 @@ proc drawText*( proc newBitmap*(this: ptr PlaydateGraphics, width: int, height: int, color: LCDColor): LCDBitmap = privateAccess(PlaydateGraphics) - return LCDBitmap(resource: this.newBitmap(width.cint, height.cint, color.convert), free: true) + return bitmapRef(this.newBitmap(width.cint, height.cint, color.convert)) proc newBitmap*(this: ptr PlaydateGraphics, path: string): LCDBitmap {.raises: [IOError]} = privateAccess(PlaydateGraphics) var err: ConstChar = nil - let bitmap = LCDBitmap(resource: this.loadBitmap(path, addr(err)), free: true) + let bitmap = bitmapRef(this.loadBitmap(path, addr(err))) if bitmap.resource == nil: raise newException(IOError, $err) return bitmap proc copy*(this: LCDBitmap): LCDBitmap = privateAccess(PlaydateGraphics) - return LCDBitmap(resource: playdate.graphics.copyBitmap(this.resource), free: true) + return bitmapRef(playdate.graphics.copyBitmap(this.resource)) proc load*(this: LCDBitmap, path: string) {.raises: [IOError]} = privateAccess(PlaydateGraphics) @@ -148,7 +175,7 @@ template read(bitmap: AnyBitmapData, x, y: int): untyped = proc getDataObj*(this: LCDBitmap): BitmapDataObj = ## Fetch the underlying bitmap data for an image. privateAccess(PlaydateGraphics) - assert(this != nil) + assert(not this.isNil) assert(this.resource != nil) playdate.graphics.getBitmapData( this.resource, @@ -166,7 +193,7 @@ proc getData*(this: LCDBitmap): BitmapData = proc getSize*(this: LCDBitmap): tuple[width: int, height: int] = privateAccess(PlaydateGraphics) - assert(this != nil) + assert(not this.isNil) assert(this.resource != nil) var width, height: cint playdate.graphics.getBitmapData(this.resource, addr(width), addr(height), nil, @@ -181,8 +208,8 @@ proc rotated*(this: LCDBitmap, rotation: float32, xScale: float32, yScale: float tuple[bitmap: LCDBitmap, allocatedSize: int] = privateAccess(PlaydateGraphics) var allocatedSize: cint - let bitmap = LCDBitmap(resource: playdate.graphics.rotatedBitmap(this.resource, rotation.cfloat, xScale.cfloat, yScale.cfloat, - addr(allocatedSize)), free: true) + let bitmap = bitmapRef(playdate.graphics.rotatedBitmap(this.resource, rotation.cfloat, xScale.cfloat, yScale.cfloat, + addr(allocatedSize))) return (bitmap, allocatedSize.int) proc rotated*(this: LCDBitmap, rotation: float32, scale: float32): @@ -232,8 +259,8 @@ proc getBitmap*(this: LCDBitmapTable, index: int): LCDBitmap = privateAccess(PlaydateGraphics) let resource = playdate.graphics.getTableBitmap(this.resource, index.cint) if resource != nil: - return LCDTableBitmap(resource: resource, free: false, table: this) - return nil + return bitmapPtr(resource) + return default(LCDBitmap) proc getBitmapTableInfo*(this: LCDBitmapTable): tuple[count: int, cellsWide: int] = privateAccess(PlaydateGraphics) @@ -341,11 +368,11 @@ proc set*(view: var BitmapView, x, y: int, color: LCDSolidColor) = proc getDebugBitmap*(this: ptr PlaydateGraphics): LCDBitmap = privateAccess(PlaydateGraphics) - return LCDBitmap(resource: this.getDebugBitmap(), free: false) # do not free: system owns this + return bitmapPtr(this.getDebugBitmap()) # do not free: system owns this proc copyFrameBufferBitmap*(this: ptr PlaydateGraphics): LCDBitmap = privateAccess(PlaydateGraphics) - return LCDBitmap(resource: this.copyFrameBufferBitmap(), free: true) + return bitmapRef(this.copyFrameBufferBitmap()) proc createPattern*(this: ptr PlaydateGraphics, bitmap: LCDBitmap, x: int, y: int): LCDPattern = privateAccess(PlaydateGraphics) @@ -369,7 +396,7 @@ proc getFontHeight*(this: LCDFont): uint = proc getDisplayBufferBitmap*(this: ptr PlaydateGraphics): LCDBitmap = privateAccess(PlaydateGraphics) - return LCDBitmap(resource: this.getDisplayBufferBitmap(), free: false) + return bitmapPtr(this.getDisplayBufferBitmap()) proc drawRotated*(this: LCDBitmap, x: int, y: int, rotation: float32, centerX: float32, centerY: float32, xScale: float32, yScale: float32) = @@ -390,7 +417,7 @@ proc setBitmapMask*( proc getBitmapMask*(this: LCDBitmap): LCDBitmap = privateAccess(PlaydateGraphics) - return LCDBitmap(resource: playdate.graphics.getBitmapMask(this.resource), free: false) # Who should manage this memory? Not clear. Not auto-managed right now. + return bitmapRef(playdate.graphics.getBitmapMask(this.resource)) proc get*(this: LCDBitmap, x, y: int): LCDSolidColor = ## Reads the color of a bitmap, taking into account the color mask @@ -413,7 +440,7 @@ proc set*(this: var LCDBitmap, x, y: int, color: LCDSolidColor = kColorBlack) = proc setStencilImage*(this: ptr PlaydateGraphics, bitmap: LCDBitmap, tile: bool = false) = privateAccess(PlaydateGraphics) - if bitmap == nil: + if bitmap.isNil: this.setStencilImage(nil, if tile: 1 else: 0) else: this.setStencilImage(bitmap.resource, if tile: 1 else: 0) @@ -445,7 +472,7 @@ proc getTextSize*(this: LCDFont, text: string, lineHeightAdjustment: int = 0): t for line in lines: width = max(this.getTextWidth(line), width) - + return (width, height) type TextAlignment* = enum diff --git a/src/playdate/sprite.nim b/src/playdate/sprite.nim index ebeda11..b24fcd8 100644 --- a/src/playdate/sprite.nim +++ b/src/playdate/sprite.nim @@ -127,7 +127,7 @@ proc bounds*(this: LCDSprite): PDRect = proc setImage*(this: LCDSprite, image: LCDBitmap, flip: LCDBitmapFlip) = privateAccess(PlaydateSprite) privateAccess(LCDBitmap) - playdate.sprite.setImage(this.resource, if image != nil: image.resource else: nil, flip) + playdate.sprite.setImage(this.resource, image.resource, flip) this.bitmap = image proc getImage*(this: LCDSprite): LCDBitmap = @@ -404,12 +404,12 @@ proc setStencilPattern*(this: LCDSprite, pattern: array[8, uint8]) = proc clearStencil*(this: LCDSprite) = privateAccess(PlaydateSprite) playdate.sprite.clearStencil(this.resource) - this.stencil = nil + this.stencil.reset() proc setStencilImage*(this: LCDSprite, stencil: LCDBitmap, tile: bool) = privateAccess(PlaydateSprite) privateAccess(LCDBitmap) - playdate.sprite.setStencilImage(this.resource, if stencil != nil: stencil.resource else: nil, if tile: 1 else: 0) + playdate.sprite.setStencilImage(this.resource, stencil.resource, if tile: 1 else: 0) this.stencil = stencil proc setCenter*(this: LCDSprite, x: float32, y: float32) = From 93ed0caabd0518e19f688cd6b7483fee22421c20 Mon Sep 17 00:00:00 2001 From: Nycto Date: Wed, 6 Nov 2024 18:56:12 -0800 Subject: [PATCH 085/101] Test mem profiling modes in build --- .github/workflows/build.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c5f6e02..feee96f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -40,6 +40,7 @@ jobs: strategy: matrix: nim-version: [ 2.0.8 ] + build-flags: [ noflag, memProfiler, memtrace, memrecord ] steps: - uses: actions/checkout@v3 @@ -63,6 +64,9 @@ jobs: pulseaudio -D --exit-idle-time=-1 pactl load-module module-null-sink sink_name=SpeakerOutput sink_properties=device.description="Dummy_Output" + - run: echo 'switch("d", "${{ matrix.build-flags }}")' >> configs.nims + working-directory: ./tests + - run: nimble simulator working-directory: ./tests From 5f29c9cc11510ccf85222d7be49f4e74ba547ad3 Mon Sep 17 00:00:00 2001 From: Nycto Date: Sun, 13 Oct 2024 18:06:15 -0700 Subject: [PATCH 086/101] Move sparsemap to util directory --- src/playdate/bindings/memtrace.nim | 2 +- src/playdate/{bindings => util}/sparsemap.nim | 0 tests/t_sparsemap.nim | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename src/playdate/{bindings => util}/sparsemap.nim (100%) diff --git a/src/playdate/bindings/memtrace.nim b/src/playdate/bindings/memtrace.nim index f82fcad..a8a5a77 100644 --- a/src/playdate/bindings/memtrace.nim +++ b/src/playdate/bindings/memtrace.nim @@ -1,4 +1,4 @@ -import system/ansi_c, sparsemap +import system/ansi_c, ../util/sparsemap proc mprotect(a1: pointer, a2: int, a3: cint): cint {.importc, header: "".} diff --git a/src/playdate/bindings/sparsemap.nim b/src/playdate/util/sparsemap.nim similarity index 100% rename from src/playdate/bindings/sparsemap.nim rename to src/playdate/util/sparsemap.nim diff --git a/tests/t_sparsemap.nim b/tests/t_sparsemap.nim index df64a4f..10b0423 100644 --- a/tests/t_sparsemap.nim +++ b/tests/t_sparsemap.nim @@ -1,4 +1,4 @@ -import unittest, random, algorithm, sequtils, playdate/bindings/sparsemap +import unittest, random, algorithm, sequtils, playdate/util/sparsemap proc randomData[T](N: int, maxVal: T): seq[T] = result = newSeq[T](N) From 4fbeace1f8152d28637c1e890717d3e88fb84d52 Mon Sep 17 00:00:00 2001 From: Nycto Date: Sun, 13 Oct 2024 18:32:19 -0700 Subject: [PATCH 087/101] Fix unfindable entry in sparse map --- src/playdate/bindings/memtrace.nim | 12 +- src/playdate/util/sparsemap.nim | 81 +- tests/sparsemap_ops.txt | 2640 ++++++++++++++++++++++++++++ tests/t_sparsemap.nim | 117 +- 4 files changed, 2785 insertions(+), 65 deletions(-) create mode 100644 tests/sparsemap_ops.txt diff --git a/src/playdate/bindings/memtrace.nim b/src/playdate/bindings/memtrace.nim index a8a5a77..840be1e 100644 --- a/src/playdate/bindings/memtrace.nim +++ b/src/playdate/bindings/memtrace.nim @@ -269,21 +269,19 @@ proc realloc*(trace: var MemTrace, alloc: Allocator, p: pointer, newSize: Natura proc traceDealloc(trace: var MemTrace, alloc: Allocator, p: pointer) {.inline.} = trace.check let realPointer = p.input - let entry = trace.allocs[realPointer.ord] - if entry == nil: + if realPointer.ord notin trace.allocs: cfprintf(cstderr, "Attempting to dealloc unmanaged memory! %p\n", p) createStackFrame[STACK_SIZE](getFrame()).printStack() - let deleted = trace.deleted[realPointer.ord] - if deleted == nil: + if realPointer.ord notin trace.deleted: trace.printPrior(p) else: - deleted[].print("Previously deallocated", printMem = false) + trace.deleted[realPointer.ord].print("Previously deallocated", printMem = false) return else: - var local = entry[] + var local = trace.allocs[realPointer.ord] local.stack = createStackFrame[STACK_SIZE](getFrame()) - unprotect(realPointer, entry.realSize) + unprotect(realPointer, local.realSize) discard alloc(realPointer, 0) trace.deleted[realPointer.ord] = local trace.allocs.delete(realPointer.ord) diff --git a/src/playdate/util/sparsemap.nim b/src/playdate/util/sparsemap.nim index 1374c27..d20a179 100644 --- a/src/playdate/util/sparsemap.nim +++ b/src/playdate/util/sparsemap.nim @@ -3,38 +3,46 @@ type Entry[K, V] = object pair: Pair[K, V] - sparseIdx: int32 + sparseIdx: uint32 + + DenseIdx = distinct uint32 StaticSparseMap*[N : static int, K, V] {.byref.} = object ## A sparse map implemented on the stack dense: array[N, Entry[K, V]] - sparse: array[N, int32] - size: int32 + sparse: array[N, DenseIdx] + size: uint32 + +const UnusedDenseIdx = DenseIdx(0) + +const TombstonedIdx = DenseIdx(1) + +proc toUInt(idx: DenseIdx): auto {.inline.} = uint32(idx) - 2 + +proc toDenseIdx(num: uint32): auto {.inline.} = DenseIdx(num + 2) + +proc `==`(a, b: DenseIdx): bool {.inline.} = uint32(a) == uint32(b) proc `=copy`[N : static int, K, V](a: var StaticSparseMap[N, K, V], b: StaticSparseMap[N, K, V]) {.error.} proc size*[N : static int, K, V](m: var StaticSparseMap[N, K, V]): auto {.inline.} = m.size -proc bestIndex[N : static int, K](key: K): int32 {.inline.} = - ## Returns the best index a key can be at for a given key - (ord(key).int32 * 7) mod (N).int32 - -iterator possibleSparseIdxs[N : static int, K](key: K): int32 = +iterator possibleSparseIdxs[N : static int, K](key: K): uint32 = ## Iterates through the possible indexes at which a key could be set - let start = bestIndex[N, K](key) + let start = (ord(key).uint32 * 7) mod N.uint32 for i in start..= m.size or m.dense[denseIdx].sparseIdx != i: + if denseIdx == UnusedDenseIdx or denseIdx == TombstonedIdx: m.dense[m.size] = Entry[K, V](pair: (key, value), sparseIdx: i) - m.sparse[i] = m.size + m.sparse[i] = m.size.toDenseIdx m.size.inc return @@ -43,27 +51,48 @@ iterator items*[N : static int, K, V](m: var StaticSparseMap[N, K, V]): var Pair for i in 0..= m.size: - break - var entry {.inject.} = m.dense[denseIdx] - if entry.sparseIdx != sparseIdx: + + if denseIdx == UnusedDenseIdx: break - elif entry.pair.key == key: - exec + elif not(denseIdx == TombstonedIdx): + var entry {.inject.} = m.dense[denseIdx.toUInt] + if entry.pair.key == key: + exec -proc `[]`*[N : static int, K, V](m: StaticSparseMap[N, K, V], key: sink K): ptr V = +proc contains*[N : static int, K, V](m: var StaticSparseMap[N, K, V], key: K): bool = + ## Whethera key is in this table + m.find(key): + return true + return false + +proc `[]`*[N : static int, K, V](m: var StaticSparseMap[N, K, V], key: K): V = ## Get a pointer to a key in this map m.find(key): - return addr entry.pair.value + return entry.pair.value -proc delete*[N : static int, K, V](m: var StaticSparseMap[N, K, V], key: sink K) = +proc delete*[N : static int, K, V](m: var StaticSparseMap[N, K, V], key: K) = ## Remove a key and its value from this map if m.size > 0: m.find(key): + + # Invalidate the existing index + m.sparse[sparseIdx] = TombstonedIdx + + # Reduce the total number of stored values m.size.dec - swap(m.dense[denseIdx], m.dense[m.size]) - m.sparse[m.dense[denseIdx].sparseIdx] = denseIdx - m.dense[m.size] = Entry[K, V]() + + # If the dense index is already at the end of the list, we just need to clear it + if denseIdx.toUInt == m.size: + m.dense[m.size] = Entry[K, V]() + + else: + # Move the last dense value to ensure everything is tightly packed + m.dense[denseIdx.toUInt] = move(m.dense[m.size]) + + # Updated the sparse index of the moved value to point to its new location + m.sparse[m.dense[denseIdx.toUInt].sparseIdx] = denseIdx + + return diff --git a/tests/sparsemap_ops.txt b/tests/sparsemap_ops.txt new file mode 100644 index 0000000..c49bda1 --- /dev/null +++ b/tests/sparsemap_ops.txt @@ -0,0 +1,2640 @@ +alloc,0x55bd03cb3058,0x55bd03cb3058,648 +alloc,0x55bd03cb32f8,0x55bd03cb32f8,904 +alloc,0x55bd03cb3698,0x55bd03cb3698,32 +alloc,0x55bd03cb36d8,0x55bd03cb36d8,32 +alloc,0x55bd03cb3718,0x55bd03cb3718,40 +alloc,0x55bd03cb3758,0x55bd03cb3758,32 +alloc,0x55bd03cb3798,0x55bd03cb3798,32 +alloc,0x55bd03cb37d8,0x55bd03cb37d8,32 +alloc,0x55bd03cb3818,0x55bd03cb3818,32 +alloc,0x55bd03cb3858,0x55bd03cb3858,32 +alloc,0x55bd03cb3898,0x55bd03cb3898,32 +alloc,0x55bd03cb38d8,0x55bd03cb38d8,32 +alloc,0x55bd03cb3918,0x55bd03cb3918,32 +alloc,0x55bd03cb3958,0x55bd03cb3958,32 +alloc,0x55bd03cb3998,0x55bd03cb3998,32 +alloc,0x55bd03cb39d8,0x55bd03cb39d8,32 +alloc,0x55bd03cb3a18,0x55bd03cb3a18,32 +alloc,0x55bd03cb3a58,0x55bd03cb3a58,32 +alloc,0x55bd03cb3a98,0x55bd03cb3a98,40 +alloc,0x55bd03cb3ad8,0x55bd03cb3ad8,32 +alloc,0x55bd03cb3b18,0x55bd03cb3b18,2056 +dealloc,0x55bd03cb3b18,0x55bd03cb3b18,0 +alloc,0x55bd03cb3b18,0x55bd03cb3b18,32 +alloc,0x55bd03cb3b58,0x55bd03cb3b58,32 +alloc,0x55bd03cb3b98,0x55bd03cb3b98,32 +alloc,0x55bd03cb3bd8,0x55bd03cb3bd8,136 +alloc,0x55bd03cb3c78,0x55bd03cb3c78,56 +alloc,0x55bd03cb3cc8,0x55bd03cb3cc8,96 +alloc,0x55bd03cb3d48,0x55bd03cb3d48,8200 +alloc,0x55bd03cb5d68,0x55bd03cb5d68,40008 +alloc,0x55bd03cbf9c8,0x55bd03cbf9c8,96 +alloc,0x55bd03cbfa48,0x55bd03cbfa48,4104 +alloc,0x55bd03cc0a68,0x55bd03cc0a68,44808 +alloc,0x55bd03ccb988,0x55bd03ccb988,96 +alloc,0x55bd03ccba08,0x55bd03ccba08,4104 +alloc,0x55bd03ccca28,0x55bd03ccca28,48008 +alloc,0x55bd03cd85c8,0x55bd03cd85c8,96 +alloc,0x55bd03cd8648,0x55bd03cd8648,4104 +alloc,0x55bd03cd9668,0x55bd03cd9668,64008 +alloc,0x55bd03ce9088,0x55bd03ce9088,96 +alloc,0x55bd03ce9108,0x55bd03ce9108,4104 +alloc,0x55bd03cea128,0x55bd03cea128,48008 +alloc,0x55bd03cf5cc8,0x55bd03cf5cc8,96 +alloc,0x55bd03cf5d48,0x55bd03cf5d48,4104 +alloc,0x55bd03cf6d68,0x55bd03cf6d68,32008 +alloc,0x55bd03cfea88,0x55bd03cfea88,96 +alloc,0x55bd03cfeb08,0x55bd03cfeb08,4104 +alloc,0x55bd03cffb28,0x55bd03cffb28,12808 +alloc,0x55bd03d02d48,0x55bd03d02d48,96 +alloc,0x55bd03d02dc8,0x55bd03d02dc8,4104 +alloc,0x55bd03d03de8,0x55bd03d03de8,38408 +alloc,0x55bd03d0d408,0x55bd03d0d408,96 +alloc,0x55bd03d0d488,0x55bd03d0d488,4104 +alloc,0x55bd03d0e4a8,0x55bd03d0e4a8,38408 +alloc,0x55bd03d17ac8,0x55bd03d17ac8,96 +alloc,0x55bd03d17b48,0x55bd03d17b48,4104 +alloc,0x55bd03d18b68,0x55bd03d18b68,35208 +alloc,0x55bd03d21508,0x55bd03d21508,96 +alloc,0x55bd03d21588,0x55bd03d21588,4104 +alloc,0x55bd03d225a8,0x55bd03d225a8,35208 +alloc,0x55bd03d2af48,0x55bd03d2af48,96 +alloc,0x55bd03d2afc8,0x55bd03d2afc8,4104 +alloc,0x55bd03d2bfe8,0x55bd03d2bfe8,83208 +alloc,0x55bd03d40508,0x55bd03d40508,96 +alloc,0x55bd03d40588,0x55bd03d40588,4104 +alloc,0x55bd03d415a8,0x55bd03d415a8,48008 +alloc,0x55bd03d4d148,0x55bd03d4d148,96 +alloc,0x55bd03d4d1c8,0x55bd03d4d1c8,4104 +alloc,0x55bd03d4e1e8,0x55bd03d4e1e8,86408 +alloc,0x55bd03d63388,0x55bd03d63388,96 +alloc,0x55bd03d63408,0x55bd03d63408,4104 +alloc,0x55bd03d64428,0x55bd03d64428,48008 +alloc,0x55bd03d6ffc8,0x55bd03d6ffc8,96 +alloc,0x55bd03d70048,0x55bd03d70048,4104 +alloc,0x55bd03d71068,0x55bd03d71068,48008 +alloc,0x55bd03d7cc08,0x55bd03d7cc08,96 +alloc,0x55bd03d7cc88,0x55bd03d7cc88,4104 +alloc,0x55bd03d7dca8,0x55bd03d7dca8,80008 +alloc,0x55bd03d91548,0x55bd03d91548,96 +alloc,0x55bd03d915c8,0x55bd03d915c8,4104 +alloc,0x55bd03d925e8,0x55bd03d925e8,60808 +alloc,0x55bd03da1388,0x55bd03da1388,96 +alloc,0x55bd03da1408,0x55bd03da1408,4104 +alloc,0x55bd03da2428,0x55bd03da2428,41608 +alloc,0x55bd03dac6c8,0x55bd03dac6c8,96 +alloc,0x55bd03dac748,0x55bd03dac748,4104 +alloc,0x55bd03dad768,0x55bd03dad768,48008 +alloc,0x55bd03db9308,0x55bd03db9308,96 +alloc,0x55bd03db9388,0x55bd03db9388,4104 +alloc,0x55bd03dba3a8,0x55bd03dba3a8,51208 +alloc,0x55bd03dc6bc8,0x55bd03dc6bc8,96 +alloc,0x55bd03dc6c48,0x55bd03dc6c48,4104 +alloc,0x55bd03dc7c68,0x55bd03dc7c68,38408 +alloc,0x55bd03dd1288,0x55bd03dd1288,96 +alloc,0x55bd03dd1308,0x55bd03dd1308,4104 +alloc,0x55bd03dd2328,0x55bd03dd2328,57608 +alloc,0x55bd03de0448,0x55bd03de0448,96 +alloc,0x55bd03de04c8,0x55bd03de04c8,4104 +alloc,0x55bd03de14e8,0x55bd03de14e8,38408 +alloc,0x55bd03deab08,0x55bd03deab08,96 +alloc,0x55bd03deab88,0x55bd03deab88,4104 +alloc,0x55bd03debba8,0x55bd03debba8,60808 +alloc,0x55bd03dfa948,0x55bd03dfa948,96 +alloc,0x55bd03dfa9c8,0x55bd03dfa9c8,4104 +alloc,0x55bd03dfb9e8,0x55bd03dfb9e8,38408 +alloc,0x55bd03e05008,0x55bd03e05008,96 +alloc,0x55bd03e05088,0x55bd03e05088,4104 +alloc,0x55bd03e060a8,0x55bd03e060a8,38408 +alloc,0x55bd03e0f6c8,0x55bd03e0f6c8,96 +alloc,0x55bd03e0f748,0x55bd03e0f748,4104 +alloc,0x55bd03e10768,0x55bd03e10768,80008 +alloc,0x55bd03e24008,0x55bd03e24008,96 +alloc,0x55bd03e24088,0x55bd03e24088,4104 +alloc,0x55bd03e250a8,0x55bd03e250a8,35208 +alloc,0x55bd03e2da48,0x55bd03e2da48,96 +alloc,0x55bd03e2dac8,0x55bd03e2dac8,4104 +alloc,0x55bd03e2eae8,0x55bd03e2eae8,41608 +alloc,0x55bd03e38d88,0x55bd03e38d88,96 +alloc,0x55bd03e38e08,0x55bd03e38e08,4104 +alloc,0x55bd03e39e28,0x55bd03e39e28,57608 +alloc,0x55bd03e47f48,0x55bd03e47f48,96 +alloc,0x55bd03e47fc8,0x55bd03e47fc8,4104 +alloc,0x55bd03e48fe8,0x55bd03e48fe8,83208 +alloc,0x55bd03e5d508,0x55bd03e5d508,96 +alloc,0x55bd03e5d588,0x55bd03e5d588,4104 +alloc,0x55bd03e5e5a8,0x55bd03e5e5a8,38408 +alloc,0x55bd03e67bc8,0x55bd03e67bc8,96 +alloc,0x55bd03e67c48,0x55bd03e67c48,4104 +alloc,0x55bd03e68c68,0x55bd03e68c68,48008 +alloc,0x55bd03e74808,0x55bd03e74808,96 +alloc,0x55bd03e74888,0x55bd03e74888,4104 +alloc,0x55bd03e758a8,0x55bd03e758a8,83208 +alloc,0x55bd03e89dc8,0x55bd03e89dc8,96 +alloc,0x55bd03e89e48,0x55bd03e89e48,4104 +alloc,0x55bd03e8ae68,0x55bd03e8ae68,12808 +alloc,0x55bd03e8e088,0x55bd03e8e088,96 +alloc,0x55bd03e8e108,0x55bd03e8e108,4104 +alloc,0x55bd03e8f128,0x55bd03e8f128,38408 +alloc,0x55bd03e98748,0x55bd03e98748,96 +alloc,0x55bd03e987c8,0x55bd03e987c8,4104 +alloc,0x55bd03e997e8,0x55bd03e997e8,38408 +alloc,0x55bd03ea2e08,0x55bd03ea2e08,96 +alloc,0x55bd03ea2e88,0x55bd03ea2e88,4104 +alloc,0x55bd03ea3ea8,0x55bd03ea3ea8,38408 +alloc,0x55bd03ead4c8,0x55bd03ead4c8,96 +alloc,0x55bd03ead548,0x55bd03ead548,4104 +alloc,0x55bd03eae568,0x55bd03eae568,41608 +alloc,0x55bd03eb8808,0x55bd03eb8808,96 +alloc,0x55bd03eb8888,0x55bd03eb8888,4104 +alloc,0x55bd03eb98a8,0x55bd03eb98a8,28808 +alloc,0x55bd03ec0948,0x55bd03ec0948,96 +alloc,0x55bd03ec09c8,0x55bd03ec09c8,4104 +alloc,0x55bd03ec19e8,0x55bd03ec19e8,38408 +alloc,0x55bd03ecb008,0x55bd03ecb008,96 +alloc,0x55bd03ecb088,0x55bd03ecb088,4104 +alloc,0x55bd03ecc0a8,0x55bd03ecc0a8,80008 +alloc,0x55bd03edf948,0x55bd03edf948,96 +alloc,0x55bd03edf9c8,0x55bd03edf9c8,4104 +alloc,0x55bd03ee09e8,0x55bd03ee09e8,64008 +alloc,0x55bd03ef0408,0x55bd03ef0408,96 +alloc,0x55bd03ef0488,0x55bd03ef0488,4104 +alloc,0x55bd03ef14a8,0x55bd03ef14a8,86408 +alloc,0x55bd03f06648,0x55bd03f06648,24 +alloc,0x55bd03f06678,0x55bd03f06678,24 +alloc,0x55bd03f066a8,0x55bd03f066a8,24 +alloc,0x55bd03f066d8,0x55bd03f066d8,24 +alloc,0x55bd03f06708,0x55bd03f06708,24 +alloc,0x55bd03f06738,0x55bd03f06738,24 +alloc,0x55bd03f06768,0x55bd03f06768,24 +alloc,0x55bd03f06798,0x55bd03f06798,24 +alloc,0x55bd03f067c8,0x55bd03f067c8,32 +alloc,0x55bd03f06808,0x55bd03f06808,32 +alloc,0x55bd03f06848,0x55bd03f06848,32 +alloc,0x55bd03f06888,0x55bd03f06888,32 +alloc,0x55bd03f068c8,0x55bd03f068c8,32 +alloc,0x55bd03f06908,0x55bd03f06908,32 +alloc,0x55bd03f06948,0x55bd03f06948,32 +alloc,0x55bd03f06988,0x55bd03f06988,32 +alloc,0x55bd03f069c8,0x55bd03f069c8,32 +alloc,0x55bd03f06a08,0x55bd03f06a08,32 +alloc,0x55bd03f06a48,0x55bd03f06a48,32 +alloc,0x55bd03f06a88,0x55bd03f06a88,32 +alloc,0x55bd03f06ac8,0x55bd03f06ac8,32 +alloc,0x55bd03f06b08,0x55bd03f06b08,32 +alloc,0x55bd03f06b48,0x55bd03f06b48,32 +alloc,0x55bd03f06b88,0x55bd03f06b88,32 +alloc,0x55bd03f06bc8,0x55bd03f06bc8,32 +alloc,0x55bd03f06c08,0x55bd03f06c08,32 +alloc,0x55bd03f06c48,0x55bd03f06c48,32 +alloc,0x55bd03f06c88,0x55bd03f06c88,32 +alloc,0x55bd03f06cc8,0x55bd03f06cc8,32 +alloc,0x55bd03f06d08,0x55bd03f06d08,32 +alloc,0x55bd03f06d48,0x55bd03f06d48,32 +alloc,0x55bd03f06d88,0x55bd03f06d88,32 +alloc,0x55bd03f06dc8,0x55bd03f06dc8,32 +alloc,0x55bd03f06e08,0x55bd03f06e08,32 +alloc,0x55bd03f06e48,0x55bd03f06e48,32 +alloc,0x55bd03f06e88,0x55bd03f06e88,32 +alloc,0x55bd03f06ec8,0x55bd03f06ec8,32 +alloc,0x55bd03f06f08,0x55bd03f06f08,32 +alloc,0x55bd03f06f48,0x55bd03f06f48,32 +alloc,0x55bd03f06f88,0x55bd03f06f88,32 +alloc,0x55bd03f06fc8,0x55bd03f06fc8,32 +alloc,0x55bd03f07008,0x55bd03f07008,32 +alloc,0x55bd03f07048,0x55bd03f07048,32 +alloc,0x55bd03f07088,0x55bd03f07088,32 +alloc,0x55bd03f070c8,0x55bd03f070c8,32 +alloc,0x55bd03f07108,0x55bd03f07108,32 +alloc,0x55bd03f07148,0x55bd03f07148,32 +alloc,0x55bd03f07188,0x55bd03f07188,32 +alloc,0x55bd03f071c8,0x55bd03f071c8,32 +alloc,0x55bd03f07208,0x55bd03f07208,32 +alloc,0x55bd03f07248,0x55bd03f07248,32 +alloc,0x55bd03f07288,0x55bd03f07288,32 +alloc,0x55bd03f072c8,0x55bd03f072c8,32 +alloc,0x55bd03f07308,0x55bd03f07308,32 +alloc,0x55bd03f07348,0x55bd03f07348,32 +alloc,0x55bd03f07388,0x55bd03f07388,32 +alloc,0x55bd03f073c8,0x55bd03f073c8,32 +alloc,0x55bd03f07408,0x55bd03f07408,32 +alloc,0x55bd03f07448,0x55bd03f07448,32 +alloc,0x55bd03f07488,0x55bd03f07488,32 +alloc,0x55bd03f074c8,0x55bd03f074c8,32 +alloc,0x55bd03f07508,0x55bd03f07508,32 +alloc,0x55bd03f07548,0x55bd03f07548,32 +alloc,0x55bd03f07588,0x55bd03f07588,32 +alloc,0x55bd03f075c8,0x55bd03f075c8,32 +alloc,0x55bd03f07608,0x55bd03f07608,32 +alloc,0x55bd03f07648,0x55bd03f07648,32 +alloc,0x55bd03f07688,0x55bd03f07688,32 +alloc,0x55bd03f076c8,0x55bd03f076c8,32 +alloc,0x55bd03f07708,0x55bd03f07708,32 +alloc,0x55bd03f07748,0x55bd03f07748,32 +alloc,0x55bd03f07788,0x55bd03f07788,32 +alloc,0x55bd03f077c8,0x55bd03f077c8,32 +alloc,0x55bd03f07808,0x55bd03f07808,32 +alloc,0x55bd03f07848,0x55bd03f07848,32 +alloc,0x55bd03f07888,0x55bd03f07888,32 +alloc,0x55bd03f078c8,0x55bd03f078c8,32 +alloc,0x55bd03f07908,0x55bd03f07908,32 +alloc,0x55bd03f07948,0x55bd03f07948,32 +alloc,0x55bd03f07988,0x55bd03f07988,32 +alloc,0x55bd03f079c8,0x55bd03f079c8,32 +alloc,0x55bd03f07a08,0x55bd03f07a08,32 +alloc,0x55bd03f07a48,0x55bd03f07a48,32 +alloc,0x55bd03f07a88,0x55bd03f07a88,32 +alloc,0x55bd03f07ac8,0x55bd03f07ac8,32 +alloc,0x55bd03f07b08,0x55bd03f07b08,32 +alloc,0x55bd03f07b48,0x55bd03f07b48,32 +alloc,0x55bd03f07b88,0x55bd03f07b88,32 +alloc,0x55bd03f07bc8,0x55bd03f07bc8,24 +alloc,0x55bd03f07bf8,0x55bd03f07bf8,24 +alloc,0x55bd03f07c28,0x55bd03f07c28,24 +alloc,0x55bd03f07c58,0x55bd03f07c58,24 +alloc,0x55bd03f07c88,0x55bd03f07c88,24 +alloc,0x55bd03f07cb8,0x55bd03f07cb8,24 +alloc,0x55bd03f07ce8,0x55bd03f07ce8,24 +alloc,0x55bd03f07d18,0x55bd03f07d18,24 +alloc,0x55bd03f07d48,0x55bd03f07d48,24 +alloc,0x55bd03f07d78,0x55bd03f07d78,24 +alloc,0x55bd03f07da8,0x55bd03f07da8,24 +alloc,0x55bd03f07dd8,0x55bd03f07dd8,24 +alloc,0x55bd03f07e08,0x55bd03f07e08,24 +alloc,0x55bd03f07e38,0x55bd03f07e38,24 +alloc,0x55bd03f07e68,0x55bd03f07e68,24 +alloc,0x55bd03f07e98,0x55bd03f07e98,24 +alloc,0x55bd03f07ec8,0x55bd03f07ec8,24 +alloc,0x55bd03f07ef8,0x55bd03f07ef8,24 +alloc,0x55bd03f07f28,0x55bd03f07f28,24 +alloc,0x55bd03f07f58,0x55bd03f07f58,24 +alloc,0x55bd03f07f88,0x55bd03f07f88,24 +alloc,0x55bd03f07fb8,0x55bd03f07fb8,24 +alloc,0x55bd03f07fe8,0x55bd03f07fe8,24 +alloc,0x55bd03f08018,0x55bd03f08018,24 +alloc,0x55bd03f08048,0x55bd03f08048,24 +alloc,0x55bd03f08078,0x55bd03f08078,24 +alloc,0x55bd03f080a8,0x55bd03f080a8,24 +alloc,0x55bd03f080d8,0x55bd03f080d8,24 +alloc,0x55bd03f08108,0x55bd03f08108,24 +alloc,0x55bd03f08138,0x55bd03f08138,24 +alloc,0x55bd03f08168,0x55bd03f08168,24 +alloc,0x55bd03f08198,0x55bd03f08198,24 +alloc,0x55bd03f081c8,0x55bd03f081c8,24 +alloc,0x55bd03f081f8,0x55bd03f081f8,24 +alloc,0x55bd03f08228,0x55bd03f08228,24 +alloc,0x55bd03f08258,0x55bd03f08258,24 +alloc,0x55bd03f08288,0x55bd03f08288,24 +alloc,0x55bd03f082b8,0x55bd03f082b8,24 +alloc,0x55bd03f082e8,0x55bd03f082e8,24 +alloc,0x55bd03f08318,0x55bd03f08318,24 +alloc,0x55bd03f08348,0x55bd03f08348,24 +alloc,0x55bd03f08378,0x55bd03f08378,24 +alloc,0x55bd03f083a8,0x55bd03f083a8,24 +alloc,0x55bd03f083d8,0x55bd03f083d8,24 +alloc,0x55bd03f08408,0x55bd03f08408,24 +alloc,0x55bd03f08438,0x55bd03f08438,24 +alloc,0x55bd03f08468,0x55bd03f08468,24 +alloc,0x55bd03f08498,0x55bd03f08498,24 +alloc,0x55bd03f084c8,0x55bd03f084c8,24 +alloc,0x55bd03f084f8,0x55bd03f084f8,24 +alloc,0x55bd03f08528,0x55bd03f08528,24 +alloc,0x55bd03f08558,0x55bd03f08558,24 +alloc,0x55bd03f08588,0x55bd03f08588,24 +alloc,0x55bd03f085b8,0x55bd03f085b8,24 +alloc,0x55bd03f085e8,0x55bd03f085e8,24 +alloc,0x55bd03f08618,0x55bd03f08618,24 +alloc,0x55bd03f08648,0x55bd03f08648,24 +alloc,0x55bd03f08678,0x55bd03f08678,24 +alloc,0x55bd03f086a8,0x55bd03f086a8,24 +alloc,0x55bd03f086d8,0x55bd03f086d8,24 +alloc,0x55bd03f08708,0x55bd03f08708,24 +alloc,0x55bd03f08738,0x55bd03f08738,24 +alloc,0x55bd03f08768,0x55bd03f08768,24 +alloc,0x55bd03f08798,0x55bd03f08798,24 +alloc,0x55bd03f087c8,0x55bd03f087c8,24 +alloc,0x55bd03f087f8,0x55bd03f087f8,24 +alloc,0x55bd03f08828,0x55bd03f08828,24 +alloc,0x55bd03f08858,0x55bd03f08858,24 +alloc,0x55bd03f08888,0x55bd03f08888,24 +alloc,0x55bd03f088b8,0x55bd03f088b8,24 +alloc,0x55bd03f088e8,0x55bd03f088e8,24 +alloc,0x55bd03f08918,0x55bd03f08918,24 +alloc,0x55bd03f08948,0x55bd03f08948,24 +alloc,0x55bd03f08978,0x55bd03f08978,24 +alloc,0x55bd03f089a8,0x55bd03f089a8,24 +alloc,0x55bd03f089d8,0x55bd03f089d8,24 +alloc,0x55bd03f08a08,0x55bd03f08a08,24 +alloc,0x55bd03f08a38,0x55bd03f08a38,24 +alloc,0x55bd03f08a68,0x55bd03f08a68,24 +alloc,0x55bd03f08a98,0x55bd03f08a98,24 +alloc,0x55bd03f08ac8,0x55bd03f08ac8,24 +alloc,0x55bd03f08af8,0x55bd03f08af8,24 +alloc,0x55bd03f08b28,0x55bd03f08b28,24 +alloc,0x55bd03f08b58,0x55bd03f08b58,24 +alloc,0x55bd03f08b88,0x55bd03f08b88,24 +alloc,0x55bd03f08bb8,0x55bd03f08bb8,24 +alloc,0x55bd03f08be8,0x55bd03f08be8,24 +alloc,0x55bd03f08c18,0x55bd03f08c18,24 +alloc,0x55bd03f08c48,0x55bd03f08c48,24 +alloc,0x55bd03f08c78,0x55bd03f08c78,24 +alloc,0x55bd03f08ca8,0x55bd03f08ca8,24 +alloc,0x55bd03f08cd8,0x55bd03f08cd8,24 +alloc,0x55bd03f08d08,0x55bd03f08d08,24 +alloc,0x55bd03f08d38,0x55bd03f08d38,24 +alloc,0x55bd03f08d68,0x55bd03f08d68,24 +alloc,0x55bd03f08d98,0x55bd03f08d98,24 +alloc,0x55bd03f08dc8,0x55bd03f08dc8,24 +alloc,0x55bd03f08df8,0x55bd03f08df8,24 +alloc,0x55bd03f08e28,0x55bd03f08e28,24 +alloc,0x55bd03f08e58,0x55bd03f08e58,24 +alloc,0x55bd03f08e88,0x55bd03f08e88,24 +alloc,0x55bd03f08eb8,0x55bd03f08eb8,24 +alloc,0x55bd03f08ee8,0x55bd03f08ee8,24 +alloc,0x55bd03f08f18,0x55bd03f08f18,24 +alloc,0x55bd03f08f48,0x55bd03f08f48,24 +alloc,0x55bd03f08f78,0x55bd03f08f78,24 +alloc,0x55bd03f08fa8,0x55bd03f08fa8,24 +alloc,0x55bd03f08fd8,0x55bd03f08fd8,24 +alloc,0x55bd03f09008,0x55bd03f09008,24 +alloc,0x55bd03f09038,0x55bd03f09038,24 +alloc,0x55bd03f09068,0x55bd03f09068,24 +alloc,0x55bd03f09098,0x55bd03f09098,24 +alloc,0x55bd03f090c8,0x55bd03f090c8,152 +alloc,0x55bd03f09178,0x55bd03f09178,64 +alloc,0x55bd03f091d8,0x55bd03f091d8,72 +alloc,0x55bd03f09238,0x55bd03f09238,48 +alloc,0x55bd03f09288,0x55bd03f09288,56 +alloc,0x55bd03f092d8,0x55bd03f092d8,48 +alloc,0x55bd03f09328,0x55bd03f09328,56 +alloc,0x55bd03f09378,0x55bd03f09378,72 +alloc,0x55bd03f093d8,0x55bd03f093d8,32 +alloc,0x55bd03f09418,0x55bd03f09418,80 +alloc,0x55bd03f09488,0x55bd03f09488,32 +alloc,0x55bd03f094c8,0x55bd03f094c8,40 +alloc,0x55bd03f09508,0x55bd03f09508,150 +dealloc,0x55bd03f094c8,0x55bd03f094c8,0 +alloc,0x55bd03f095b8,0x55bd03f095b8,151 +alloc,0x55bd03f09668,0x55bd03f09668,151 +alloc,0x55bd03f09718,0x55bd03f09718,120 +alloc,0x55bd03f097a8,0x55bd03f097a8,8201 +alloc,0x55bd03f094c8,0x55bd03f094c8,9 +alloc,0x55bd03f0b7d8,0x55bd03f0b7d8,56 +alloc,0x55bd03f0b828,0x55bd03f0b828,328 +alloc,0x55bd03f0b988,0x55bd03f0b988,10 +realloc,0x55bd03f0b988,0x55bd03f0b988,11 +realloc,0x55bd03f0b988,0x55bd03f0b988,13 +realloc,0x55bd03f0b988,0x55bd03f0b988,17 +alloc,0x55bd03f0b9b8,0x55bd03f0b9b8,15 +alloc,0x55bd03f0b9e8,0x55bd03f0b9e8,56 +alloc,0x55bd03f0ba38,0x55bd03f0ba38,328 +realloc,0x55bd03f0b988,0x55bd03f0bb98,25 +alloc,0x55bd03f0b988,0x55bd03f0b988,20 +alloc,0x55bd03f0bbd8,0x55bd03f0bbd8,56 +alloc,0x55bd03f0bc28,0x55bd03f0bc28,56 +alloc,0x55bd03f0bc78,0x55bd03f0bc78,16 +alloc,0x55bd03f0bca8,0x55bd03f0bca8,56 +realloc,0x55bd03f0bc78,0x55bd03f0bc78,24 +alloc,0x55bd03f0bcf8,0x55bd03f0bcf8,56 +realloc,0x55bd03f0bc78,0x55bd03f0bd48,40 +alloc,0x55bd03f0bd88,0x55bd03f0bd88,56 +alloc,0x55bd03f0bdd8,0x55bd03f0bdd8,56 +realloc,0x55bd03f0bd48,0x55bd03f0be28,72 +alloc,0x55bd03f0be88,0x55bd03f0be88,56 +alloc,0x55bd03f0bc78,0x55bd03f0bc78,20 +dealloc,0x55bd03f0b988,0x55bd03f0b988,0 +alloc,0x55bd03f0b988,0x55bd03f0b988,22 +alloc,0x55bd03f0bed8,0x55bd03f0bed8,56 +alloc,0x55bd03f0bf28,0x55bd03f0bf28,56 +alloc,0x55bd03f0bd48,0x55bd03f0bd48,16 +alloc,0x55bd03f0bf78,0x55bd03f0bf78,56 +realloc,0x55bd03f0bd48,0x55bd03f0bd48,24 +alloc,0x55bd03f0bfc8,0x55bd03f0bfc8,56 +realloc,0x55bd03f0bd48,0x55bd03f0bd48,40 +alloc,0x55bd03f0c018,0x55bd03f0c018,56 +alloc,0x55bd03f0c068,0x55bd03f0c068,56 +realloc,0x55bd03f0bd48,0x55bd03f0c0b8,72 +alloc,0x55bd03f0c118,0x55bd03f0c118,56 +alloc,0x55bd03f0bd48,0x55bd03f0bd48,22 +dealloc,0x55bd03f0b988,0x55bd03f0b988,0 +alloc,0x55bd03f0b988,0x55bd03f0b988,23 +alloc,0x55bd03f0c168,0x55bd03f0c168,56 +alloc,0x55bd03f0c1b8,0x55bd03f0c1b8,23 +dealloc,0x55bd03f0b988,0x55bd03f0b988,0 +alloc,0x55bd03f0b988,0x55bd03f0b988,15 +dealloc,0x55bd03f0b9b8,0x55bd03f0b9b8,0 +alloc,0x55bd03f0b9b8,0x55bd03f0b9b8,21 +alloc,0x55bd03f0c1e8,0x55bd03f0c1e8,56 +alloc,0x55bd03f0c238,0x55bd03f0c238,21 +dealloc,0x55bd03f0b9b8,0x55bd03f0b9b8,0 +alloc,0x55bd03f0b9b8,0x55bd03f0b9b8,18 +alloc,0x55bd03f0c268,0x55bd03f0c268,56 +alloc,0x55bd03f0c2b8,0x55bd03f0c2b8,18 +dealloc,0x55bd03f0b9b8,0x55bd03f0b9b8,0 +alloc,0x55bd03f0b9b8,0x55bd03f0b9b8,21 +alloc,0x55bd03f0c2e8,0x55bd03f0c2e8,56 +alloc,0x55bd03f0c338,0x55bd03f0c338,21 +dealloc,0x55bd03f0b9b8,0x55bd03f0b9b8,0 +dealloc,0x55bd03f09668,0x55bd03f09668,0 +dealloc,0x55bd03f097a8,0x55bd03f097a8,0 +dealloc,0x55bd03f0bb98,0x55bd03f0bb98,0 +dealloc,0x55bd03f094c8,0x55bd03f094c8,0 +dealloc,0x55bd03f09718,0x55bd03f09718,0 +alloc,0x55bd03f09668,0x55bd03f09668,136 +alloc,0x55bd03f0b9b8,0x55bd03f0b9b8,10 +realloc,0x55bd03f0b9b8,0x55bd03f0b9b8,11 +alloc,0x55bd03f09708,0x55bd03f09708,328 +alloc,0x55bd03f094c8,0x55bd03f094c8,20 +alloc,0x55bd03f0bb98,0x55bd03f0bb98,22 +alloc,0x55bd03f09868,0x55bd03f09868,23 +alloc,0x55bd03f09898,0x55bd03f09898,20 +alloc,0x55bd03f098c8,0x55bd03f098c8,11 +realloc,0x55bd03f0b9b8,0x55bd03f0b9b8,13 +dealloc,0x55bd03f098c8,0x55bd03f098c8,0 +realloc,0x55bd03f0b9b8,0x55bd03f0b9b8,17 +realloc,0x55bd03f0b9b8,0x55bd03f098f8,25 +realloc,0x55bd03f098f8,0x55bd03f098f8,41 +alloc,0x55bd03f0b9b8,0x55bd03f0b9b8,13 +dealloc,0x55bd03f0b9b8,0x55bd03f0b9b8,0 +alloc,0x55bd03f0b9b8,0x55bd03f0b9b8,13 +dealloc,0x55bd03f0b9b8,0x55bd03f0b9b8,0 +realloc,0x55bd03f098f8,0x55bd03f098f8,73 +alloc,0x55bd03f0b9b8,0x55bd03f0b9b8,13 +dealloc,0x55bd03f0b9b8,0x55bd03f0b9b8,0 +alloc,0x55bd03f0b9b8,0x55bd03f0b9b8,13 +dealloc,0x55bd03f0b9b8,0x55bd03f0b9b8,0 +alloc,0x55bd03f0b9b8,0x55bd03f0b9b8,13 +dealloc,0x55bd03f0b9b8,0x55bd03f0b9b8,0 +alloc,0x55bd03f0b9b8,0x55bd03f0b9b8,13 +dealloc,0x55bd03f0b9b8,0x55bd03f0b9b8,0 +alloc,0x55bd03f0b9b8,0x55bd03f0b9b8,11 +dealloc,0x55bd03f0b9b8,0x55bd03f0b9b8,0 +realloc,0x55bd03f098f8,0x55bd03f098f8,137 +dealloc,0x55bd03f09898,0x55bd03f09898,0 +alloc,0x55bd03f09898,0x55bd03f09898,22 +alloc,0x55bd03f0b9b8,0x55bd03f0b9b8,11 +dealloc,0x55bd03f0b9b8,0x55bd03f0b9b8,0 +alloc,0x55bd03f0b9b8,0x55bd03f0b9b8,13 +dealloc,0x55bd03f0b9b8,0x55bd03f0b9b8,0 +alloc,0x55bd03f0b9b8,0x55bd03f0b9b8,13 +dealloc,0x55bd03f0b9b8,0x55bd03f0b9b8,0 +alloc,0x55bd03f0b9b8,0x55bd03f0b9b8,13 +dealloc,0x55bd03f0b9b8,0x55bd03f0b9b8,0 +alloc,0x55bd03f0b9b8,0x55bd03f0b9b8,13 +dealloc,0x55bd03f0b9b8,0x55bd03f0b9b8,0 +alloc,0x55bd03f0b9b8,0x55bd03f0b9b8,13 +dealloc,0x55bd03f0b9b8,0x55bd03f0b9b8,0 +alloc,0x55bd03f0b9b8,0x55bd03f0b9b8,13 +dealloc,0x55bd03f0b9b8,0x55bd03f0b9b8,0 +realloc,0x55bd03f098f8,0x55bd03f098f8,265 +alloc,0x55bd03f0b9b8,0x55bd03f0b9b8,11 +dealloc,0x55bd03f0b9b8,0x55bd03f0b9b8,0 +dealloc,0x55bd03f09898,0x55bd03f09898,0 +alloc,0x55bd03f09898,0x55bd03f09898,23 +alloc,0x55bd03f0b9b8,0x55bd03f0b9b8,11 +dealloc,0x55bd03f0b9b8,0x55bd03f0b9b8,0 +dealloc,0x55bd03f094c8,0x55bd03f094c8,0 +dealloc,0x55bd03f0bb98,0x55bd03f0bb98,0 +dealloc,0x55bd03f09868,0x55bd03f09868,0 +dealloc,0x55bd03f09708,0x55bd03f09708,0 +dealloc,0x55bd03f09898,0x55bd03f09898,0 +alloc,0x55bd03f09708,0x55bd03f09708,82 +realloc,0x55bd03f09708,0x55bd03f09708,206 +alloc,0x55bd03f097f8,0x55bd03f097f8,72 +alloc,0x55bd03f09a28,0x55bd03f09a28,220 +alloc,0x55bd03f09b28,0x55bd03f09b28,272 +dealloc,0x55bd03f0b988,0x55bd03f0b988,0 +dealloc,0x55bd03f0bc78,0x55bd03f0bc78,0 +dealloc,0x55bd03f0bc28,0x55bd03f0bc28,0 +dealloc,0x55bd03f0bca8,0x55bd03f0bca8,0 +dealloc,0x55bd03f0bcf8,0x55bd03f0bcf8,0 +dealloc,0x55bd03f0bd88,0x55bd03f0bd88,0 +dealloc,0x55bd03f0bdd8,0x55bd03f0bdd8,0 +dealloc,0x55bd03f0be88,0x55bd03f0be88,0 +dealloc,0x55bd03f0be28,0x55bd03f0be28,0 +dealloc,0x55bd03f0bbd8,0x55bd03f0bbd8,0 +dealloc,0x55bd03f0bd48,0x55bd03f0bd48,0 +dealloc,0x55bd03f0bf28,0x55bd03f0bf28,0 +dealloc,0x55bd03f0bf78,0x55bd03f0bf78,0 +dealloc,0x55bd03f0bfc8,0x55bd03f0bfc8,0 +dealloc,0x55bd03f0c018,0x55bd03f0c018,0 +dealloc,0x55bd03f0c068,0x55bd03f0c068,0 +dealloc,0x55bd03f0c118,0x55bd03f0c118,0 +dealloc,0x55bd03f0c0b8,0x55bd03f0c0b8,0 +dealloc,0x55bd03f0bed8,0x55bd03f0bed8,0 +dealloc,0x55bd03f0c1b8,0x55bd03f0c1b8,0 +dealloc,0x55bd03f0c168,0x55bd03f0c168,0 +dealloc,0x55bd03f0ba38,0x55bd03f0ba38,0 +dealloc,0x55bd03f0b9e8,0x55bd03f0b9e8,0 +dealloc,0x55bd03f0c2b8,0x55bd03f0c2b8,0 +dealloc,0x55bd03f0c268,0x55bd03f0c268,0 +dealloc,0x55bd03f0c338,0x55bd03f0c338,0 +dealloc,0x55bd03f0c2e8,0x55bd03f0c2e8,0 +dealloc,0x55bd03f0c238,0x55bd03f0c238,0 +dealloc,0x55bd03f0c1e8,0x55bd03f0c1e8,0 +dealloc,0x55bd03f0b828,0x55bd03f0b828,0 +dealloc,0x55bd03f0b7d8,0x55bd03f0b7d8,0 +dealloc,0x55bd03f09668,0x55bd03f09668,0 +dealloc,0x55bd03f09a28,0x55bd03f09a28,0 +dealloc,0x55bd03f09b28,0x55bd03f09b28,0 +dealloc,0x55bd03f097f8,0x55bd03f097f8,0 +dealloc,0x55bd03f09508,0x55bd03f09508,0 +dealloc,0x55bd03f095b8,0x55bd03f095b8,0 +dealloc,0x55bd03f09488,0x55bd03f09488,0 +alloc,0x55bd03f0c238,0x55bd03f0c238,10 +alloc,0x55bd03f0c338,0x55bd03f0c338,10 +alloc,0x55bd03f0c268,0x55bd03f0c268,24 +alloc,0x55bd03f0c298,0x55bd03f0c298,24 +alloc,0x55bd03f09828,0x55bd03f09828,48 +alloc,0x55bd03f0b398,0x55bd03f0b398,96 +alloc,0x55bd03f0b418,0x55bd03f0b418,32 +dealloc,0x55bd03f0c298,0x55bd03f0c298,0 +alloc,0x55bd03f0c298,0x55bd03f0c298,24 +alloc,0x55bd03f12348,0x55bd03f12348,24 +alloc,0x55bd03f12378,0x55bd03f12378,48 +alloc,0x55bd03f12478,0x55bd03f12478,96 +alloc,0x55bd03f0b458,0x55bd03f0b458,32 +alloc,0x55bd03f0b498,0x55bd03f0b498,32 +alloc,0x55bd03f0b4d8,0x55bd03f0b4d8,48 +alloc,0x55bd03f0b5d8,0x55bd03f0b5d8,96 +alloc,0x55bd03f124f8,0x55bd03f124f8,24 +alloc,0x55bd03f0b748,0x55bd03f0b748,32 +alloc,0x55bd03f0b788,0x55bd03f0b788,16 +alloc,0x55bd03f0b7b8,0x55bd03f0b7b8,40 +alloc,0x55bd03f0b7f8,0x55bd03f0b7f8,24 +alloc,0x55bd03f0b828,0x55bd03f0b828,16 +realloc,0x55bd03f0b828,0x55bd03f0b828,24 +realloc,0x55bd03f0b828,0x55bd03f0b828,40 +realloc,0x55bd03f0b828,0x55bd03f0b828,72 +realloc,0x55bd03f0b828,0x55bd03f0b828,136 +alloc,0x55bd03f0b8c8,0x55bd03f0b8c8,24 +alloc,0x55bd03f0b8f8,0x55bd03f0b8f8,16 +realloc,0x55bd03f0b8f8,0x55bd03f0b8f8,24 +realloc,0x55bd03f0b8f8,0x55bd03f0b8f8,40 +realloc,0x55bd03f0b8f8,0x55bd03f0b8f8,72 +realloc,0x55bd03f0b8f8,0x55bd03f0b8f8,136 +alloc,0x55bd03f0b998,0x55bd03f0b998,16 +realloc,0x55bd03f0b998,0x55bd03f0b998,24 +realloc,0x55bd03f0b998,0x55bd03f0b998,40 +realloc,0x55bd03f0b998,0x55bd03f0b998,72 +realloc,0x55bd03f0b998,0x55bd03f0b998,136 +realloc,0x55bd03f0b998,0x55bd03f0b998,264 +alloc,0x55bd03f0bab8,0x55bd03f0bab8,24 +alloc,0x55bd03f0bae8,0x55bd03f0bae8,16 +realloc,0x55bd03f0bae8,0x55bd03f0bae8,24 +realloc,0x55bd03f0bae8,0x55bd03f0bae8,40 +realloc,0x55bd03f0bae8,0x55bd03f0bae8,72 +realloc,0x55bd03f0bae8,0x55bd03f0bae8,136 +alloc,0x55bd03f0bb88,0x55bd03f0bb88,24 +alloc,0x55bd03f0bbb8,0x55bd03f0bbb8,24 +alloc,0x55bd03f0bbe8,0x55bd03f0bbe8,16 +realloc,0x55bd03f0bbe8,0x55bd03f0bbe8,24 +realloc,0x55bd03f0bbe8,0x55bd03f0bbe8,40 +realloc,0x55bd03f0bbe8,0x55bd03f0bbe8,72 +realloc,0x55bd03f0bbe8,0x55bd03f0bbe8,136 +alloc,0x55bd03f0bc88,0x55bd03f0bc88,16 +realloc,0x55bd03f0bc88,0x55bd03f0bc88,24 +realloc,0x55bd03f0bc88,0x55bd03f0bc88,40 +realloc,0x55bd03f0bc88,0x55bd03f0bc88,72 +realloc,0x55bd03f0bc88,0x55bd03f0bc88,136 +realloc,0x55bd03f0bc88,0x55bd03f0bc88,264 +alloc,0x55bd03f0bda8,0x55bd03f0bda8,24 +alloc,0x55bd03f0bdd8,0x55bd03f0bdd8,16 +realloc,0x55bd03f0bdd8,0x55bd03f0bdd8,24 +realloc,0x55bd03f0bdd8,0x55bd03f0bdd8,40 +realloc,0x55bd03f0bdd8,0x55bd03f0bdd8,72 +realloc,0x55bd03f0bdd8,0x55bd03f0bdd8,136 +alloc,0x55bd03f0be78,0x55bd03f0be78,24 +alloc,0x55bd03f0bea8,0x55bd03f0bea8,24 +alloc,0x55bd03f0bed8,0x55bd03f0bed8,16 +realloc,0x55bd03f0bed8,0x55bd03f0bed8,24 +realloc,0x55bd03f0bed8,0x55bd03f0bed8,40 +realloc,0x55bd03f0bed8,0x55bd03f0bed8,72 +alloc,0x55bd03f0bf38,0x55bd03f0bf38,24 +alloc,0x55bd03f0bf68,0x55bd03f0bf68,16 +realloc,0x55bd03f0bf68,0x55bd03f0bf68,24 +realloc,0x55bd03f0bf68,0x55bd03f0bf68,40 +realloc,0x55bd03f0bf68,0x55bd03f0bf68,72 +realloc,0x55bd03f0bf68,0x55bd03f0bf68,136 +realloc,0x55bd03f0bf68,0x55bd03f0bf68,264 +alloc,0x55bd03f0c088,0x55bd03f0c088,24 +alloc,0x55bd03f0c0b8,0x55bd03f0c0b8,24 +alloc,0x55bd03f0c0e8,0x55bd03f0c0e8,24 +alloc,0x55bd03f0c118,0x55bd03f0c118,16 +realloc,0x55bd03f0c118,0x55bd03f0c118,24 +realloc,0x55bd03f0c118,0x55bd03f0c118,40 +realloc,0x55bd03f0c118,0x55bd03f0c118,72 +realloc,0x55bd03f0c118,0x55bd03f0c118,136 +alloc,0x55bd03f0c1b8,0x55bd03f0c1b8,24 +alloc,0x55bd03f0c1e8,0x55bd03f0c1e8,24 +alloc,0x55bd03f1cec8,0x55bd03f1cec8,16 +realloc,0x55bd03f1cec8,0x55bd03f1cec8,24 +realloc,0x55bd03f1cec8,0x55bd03f1cec8,40 +realloc,0x55bd03f1cec8,0x55bd03f1cec8,72 +alloc,0x55bd03f1cf28,0x55bd03f1cf28,24 +alloc,0x55bd03f1cf58,0x55bd03f1cf58,24 +alloc,0x55bd03f1cf88,0x55bd03f1cf88,16 +realloc,0x55bd03f1cf88,0x55bd03f1cf88,24 +realloc,0x55bd03f1cf88,0x55bd03f1cf88,40 +realloc,0x55bd03f1cf88,0x55bd03f1cf88,72 +alloc,0x55bd03f1cfe8,0x55bd03f1cfe8,24 +alloc,0x55bd03f1d018,0x55bd03f1d018,16 +realloc,0x55bd03f1d018,0x55bd03f1d018,24 +realloc,0x55bd03f1d018,0x55bd03f1d018,40 +realloc,0x55bd03f1d018,0x55bd03f1d018,72 +realloc,0x55bd03f1d018,0x55bd03f1d018,136 +realloc,0x55bd03f1d018,0x55bd03f1d018,264 +realloc,0x55bd03f1d018,0x55bd03f1d018,520 +alloc,0x55bd03f1d238,0x55bd03f1d238,24 +alloc,0x55bd03f1d268,0x55bd03f1d268,24 +alloc,0x55bd03f1d298,0x55bd03f1d298,24 +alloc,0x55bd03f1d2c8,0x55bd03f1d2c8,24 +alloc,0x55bd03f1d2f8,0x55bd03f1d2f8,24 +alloc,0x55bd03f1d328,0x55bd03f1d328,16 +realloc,0x55bd03f1d328,0x55bd03f1d328,24 +realloc,0x55bd03f1d328,0x55bd03f1d328,40 +realloc,0x55bd03f1d328,0x55bd03f1d328,72 +realloc,0x55bd03f1d328,0x55bd03f1d328,136 +alloc,0x55bd03f1d3c8,0x55bd03f1d3c8,16 +realloc,0x55bd03f1d3c8,0x55bd03f1d3c8,24 +realloc,0x55bd03f1d3c8,0x55bd03f1d3c8,40 +realloc,0x55bd03f1d3c8,0x55bd03f1d3c8,72 +realloc,0x55bd03f1d3c8,0x55bd03f1d3c8,136 +realloc,0x55bd03f1d3c8,0x55bd03f1d3c8,264 +realloc,0x55bd03f1d3c8,0x55bd03f1d3c8,520 +realloc,0x55bd03f1d3c8,0x55bd03f1d3c8,1032 +alloc,0x55bd03f1d7e8,0x55bd03f1d7e8,16 +realloc,0x55bd03f1d7e8,0x55bd03f1d7e8,24 +realloc,0x55bd03f1d7e8,0x55bd03f1d7e8,40 +realloc,0x55bd03f1d7e8,0x55bd03f1d7e8,72 +realloc,0x55bd03f1d7e8,0x55bd03f1d7e8,136 +realloc,0x55bd03f1d7e8,0x55bd03f1d7e8,264 +realloc,0x55bd03f1d7e8,0x55bd03f1d7e8,520 +realloc,0x55bd03f1d7e8,0x55bd03f1d7e8,1032 +alloc,0x55bd03f1dc08,0x55bd03f1dc08,24 +alloc,0x55bd03f1dc38,0x55bd03f1dc38,24 +alloc,0x55bd03f1dc68,0x55bd03f1dc68,16 +realloc,0x55bd03f1dc68,0x55bd03f1dc68,24 +realloc,0x55bd03f1dc68,0x55bd03f1dc68,40 +realloc,0x55bd03f1dc68,0x55bd03f1dc68,72 +realloc,0x55bd03f1dc68,0x55bd03f1dc68,136 +alloc,0x55bd03f1dd08,0x55bd03f1dd08,24 +alloc,0x55bd03f1dd38,0x55bd03f1dd38,16 +realloc,0x55bd03f1dd38,0x55bd03f1dd38,24 +realloc,0x55bd03f1dd38,0x55bd03f1dd38,40 +realloc,0x55bd03f1dd38,0x55bd03f1dd38,72 +alloc,0x55bd03f1dd98,0x55bd03f1dd98,16 +realloc,0x55bd03f1dd98,0x55bd03f1dd98,24 +realloc,0x55bd03f1dd98,0x55bd03f1dd98,40 +realloc,0x55bd03f1dd98,0x55bd03f1dd98,72 +realloc,0x55bd03f1dd98,0x55bd03f1dd98,136 +realloc,0x55bd03f1dd98,0x55bd03f1dd98,264 +alloc,0x55bd03f1deb8,0x55bd03f1deb8,24 +alloc,0x55bd03f1dee8,0x55bd03f1dee8,24 +alloc,0x55bd03f1df18,0x55bd03f1df18,16 +realloc,0x55bd03f1df18,0x55bd03f1df18,24 +realloc,0x55bd03f1df18,0x55bd03f1df18,40 +realloc,0x55bd03f1df18,0x55bd03f1df18,72 +realloc,0x55bd03f1df18,0x55bd03f1df18,136 +alloc,0x55bd03f1dfb8,0x55bd03f1dfb8,24 +alloc,0x55bd03f1dfe8,0x55bd03f1dfe8,16 +realloc,0x55bd03f1dfe8,0x55bd03f1dfe8,24 +realloc,0x55bd03f1dfe8,0x55bd03f1dfe8,40 +realloc,0x55bd03f1dfe8,0x55bd03f1dfe8,72 +realloc,0x55bd03f1dfe8,0x55bd03f1dfe8,136 +realloc,0x55bd03f1dfe8,0x55bd03f1dfe8,264 +realloc,0x55bd03f1dfe8,0x55bd03f1dfe8,520 +realloc,0x55bd03f1dfe8,0x55bd03f1dfe8,1032 +alloc,0x55bd03f1e408,0x55bd03f1e408,24 +alloc,0x55bd03f1e438,0x55bd03f1e438,16 +realloc,0x55bd03f1e438,0x55bd03f1e438,24 +realloc,0x55bd03f1e438,0x55bd03f1e438,40 +realloc,0x55bd03f1e438,0x55bd03f1e438,72 +realloc,0x55bd03f1e438,0x55bd03f1e438,136 +realloc,0x55bd03f1e438,0x55bd03f1e438,264 +realloc,0x55bd03f1e438,0x55bd03f1e438,520 +realloc,0x55bd03f1e438,0x55bd03f1e438,1032 +alloc,0x55bd03f1e858,0x55bd03f1e858,24 +alloc,0x55bd03f1e888,0x55bd03f1e888,16 +realloc,0x55bd03f1e888,0x55bd03f1e888,24 +realloc,0x55bd03f1e888,0x55bd03f1e888,40 +realloc,0x55bd03f1e888,0x55bd03f1e888,72 +alloc,0x55bd03f1e8e8,0x55bd03f1e8e8,24 +alloc,0x55bd03f1e918,0x55bd03f1e918,16 +realloc,0x55bd03f1e918,0x55bd03f1e918,24 +realloc,0x55bd03f1e918,0x55bd03f1e918,40 +realloc,0x55bd03f1e918,0x55bd03f1e918,72 +realloc,0x55bd03f1e918,0x55bd03f1e918,136 +alloc,0x55bd03f1e9b8,0x55bd03f1e9b8,24 +alloc,0x55bd03f1e9e8,0x55bd03f1e9e8,16 +realloc,0x55bd03f1e9e8,0x55bd03f1e9e8,24 +realloc,0x55bd03f1e9e8,0x55bd03f1e9e8,40 +realloc,0x55bd03f1e9e8,0x55bd03f1e9e8,72 +alloc,0x55bd03f1ea48,0x55bd03f1ea48,24 +alloc,0x55bd03f1ea78,0x55bd03f1ea78,24 +alloc,0x55bd03f1eaa8,0x55bd03f1eaa8,16 +realloc,0x55bd03f1eaa8,0x55bd03f1eaa8,24 +realloc,0x55bd03f1eaa8,0x55bd03f1eaa8,40 +realloc,0x55bd03f1eaa8,0x55bd03f1eaa8,72 +realloc,0x55bd03f1eaa8,0x55bd03f1eaa8,136 +realloc,0x55bd03f1eaa8,0x55bd03f1eaa8,264 +realloc,0x55bd03f1eaa8,0x55bd03f1eaa8,520 +alloc,0x55bd03f1ecc8,0x55bd03f1ecc8,16 +realloc,0x55bd03f1ecc8,0x55bd03f1ecc8,24 +realloc,0x55bd03f1ecc8,0x55bd03f1ecc8,40 +realloc,0x55bd03f1ecc8,0x55bd03f1ecc8,72 +realloc,0x55bd03f1ecc8,0x55bd03f1ecc8,136 +realloc,0x55bd03f1ecc8,0x55bd03f1ecc8,264 +realloc,0x55bd03f1ecc8,0x55bd03f1ecc8,520 +alloc,0x55bd03f1eee8,0x55bd03f1eee8,24 +alloc,0x55bd03f1ef18,0x55bd03f1ef18,24 +alloc,0x55bd03f1ef48,0x55bd03f1ef48,24 +alloc,0x55bd03f1ef78,0x55bd03f1ef78,24 +alloc,0x55bd03f1efa8,0x55bd03f1efa8,24 +alloc,0x55bd03f1efd8,0x55bd03f1efd8,24 +alloc,0x55bd03f1f008,0x55bd03f1f008,24 +alloc,0x55bd03f1f038,0x55bd03f1f038,16 +realloc,0x55bd03f1f038,0x55bd03f1f038,24 +realloc,0x55bd03f1f038,0x55bd03f1f038,40 +realloc,0x55bd03f1f038,0x55bd03f1f038,72 +alloc,0x55bd03f1f098,0x55bd03f1f098,16 +realloc,0x55bd03f1f098,0x55bd03f1f098,24 +realloc,0x55bd03f1f098,0x55bd03f1f098,40 +realloc,0x55bd03f1f098,0x55bd03f1f098,72 +realloc,0x55bd03f1f098,0x55bd03f1f098,136 +realloc,0x55bd03f1f098,0x55bd03f1f098,264 +realloc,0x55bd03f1f098,0x55bd03f1f098,520 +alloc,0x55bd03f1f2b8,0x55bd03f1f2b8,24 +alloc,0x55bd03f1f2e8,0x55bd03f1f2e8,16 +realloc,0x55bd03f1f2e8,0x55bd03f1f2e8,24 +realloc,0x55bd03f1f2e8,0x55bd03f1f2e8,40 +realloc,0x55bd03f1f2e8,0x55bd03f1f2e8,72 +realloc,0x55bd03f1f2e8,0x55bd03f1f2e8,136 +realloc,0x55bd03f1f2e8,0x55bd03f1f2e8,264 +realloc,0x55bd03f1f2e8,0x55bd03f1f2e8,520 +realloc,0x55bd03f1f2e8,0x55bd03f1f2e8,1032 +alloc,0x55bd03f1f708,0x55bd03f1f708,200 +alloc,0x55bd03f1f7e8,0x55bd03f1f7e8,48 +alloc,0x55bd03f1f838,0x55bd03f1f838,200 +realloc,0x55bd03f1f7e8,0x55bd03f1f918,88 +alloc,0x55bd03f1f988,0x55bd03f1f988,168 +realloc,0x55bd03f1f918,0x55bd03f1fa48,168 +alloc,0x55bd03f1fb08,0x55bd03f1fb08,280 +alloc,0x55bd03f1fc38,0x55bd03f1fc38,584 +realloc,0x55bd03f1fa48,0x55bd03f1fe98,328 +alloc,0x55bd03f1fff8,0x55bd03f1fff8,216 +alloc,0x55bd03f200e8,0x55bd03f200e8,920 +alloc,0x55bd03f20498,0x55bd03f20498,520 +alloc,0x55bd03f206b8,0x55bd03f206b8,568 +realloc,0x55bd03f1fe98,0x55bd03f20908,648 +alloc,0x55bd03f1fe98,0x55bd03f1fe98,200 +realloc,0x55bd03f1fe98,0x55bd03f20ba8,392 +realloc,0x55bd03f20ba8,0x55bd03f20ba8,776 +realloc,0x55bd03f20ba8,0x55bd03f20ba8,1544 +dealloc,0x55bd03f20ba8,0x55bd03f20ba8,0 +dealloc,0x55bd03f1f2e8,0x55bd03f1f2e8,0 +dealloc,0x55bd03f1f2b8,0x55bd03f1f2b8,0 +dealloc,0x55bd03f1f098,0x55bd03f1f098,0 +dealloc,0x55bd03f1f038,0x55bd03f1f038,0 +dealloc,0x55bd03f1f008,0x55bd03f1f008,0 +dealloc,0x55bd03f1efd8,0x55bd03f1efd8,0 +dealloc,0x55bd03f1efa8,0x55bd03f1efa8,0 +dealloc,0x55bd03f1ef78,0x55bd03f1ef78,0 +dealloc,0x55bd03f1ef48,0x55bd03f1ef48,0 +dealloc,0x55bd03f1ef18,0x55bd03f1ef18,0 +dealloc,0x55bd03f1eee8,0x55bd03f1eee8,0 +dealloc,0x55bd03f1ecc8,0x55bd03f1ecc8,0 +dealloc,0x55bd03f1eaa8,0x55bd03f1eaa8,0 +dealloc,0x55bd03f1ea78,0x55bd03f1ea78,0 +dealloc,0x55bd03f1ea48,0x55bd03f1ea48,0 +dealloc,0x55bd03f1e9e8,0x55bd03f1e9e8,0 +dealloc,0x55bd03f1e9b8,0x55bd03f1e9b8,0 +dealloc,0x55bd03f1e918,0x55bd03f1e918,0 +dealloc,0x55bd03f1e8e8,0x55bd03f1e8e8,0 +dealloc,0x55bd03f1e888,0x55bd03f1e888,0 +dealloc,0x55bd03f1e858,0x55bd03f1e858,0 +dealloc,0x55bd03f1e438,0x55bd03f1e438,0 +dealloc,0x55bd03f1e408,0x55bd03f1e408,0 +dealloc,0x55bd03f1dfe8,0x55bd03f1dfe8,0 +dealloc,0x55bd03f1dfb8,0x55bd03f1dfb8,0 +dealloc,0x55bd03f1df18,0x55bd03f1df18,0 +dealloc,0x55bd03f1dee8,0x55bd03f1dee8,0 +dealloc,0x55bd03f1deb8,0x55bd03f1deb8,0 +dealloc,0x55bd03f1dd98,0x55bd03f1dd98,0 +dealloc,0x55bd03f1dd38,0x55bd03f1dd38,0 +dealloc,0x55bd03f1dd08,0x55bd03f1dd08,0 +dealloc,0x55bd03f1dc68,0x55bd03f1dc68,0 +dealloc,0x55bd03f1dc38,0x55bd03f1dc38,0 +dealloc,0x55bd03f1dc08,0x55bd03f1dc08,0 +dealloc,0x55bd03f1d7e8,0x55bd03f1d7e8,0 +dealloc,0x55bd03f1d3c8,0x55bd03f1d3c8,0 +dealloc,0x55bd03f1d328,0x55bd03f1d328,0 +dealloc,0x55bd03f1d2f8,0x55bd03f1d2f8,0 +dealloc,0x55bd03f1d2c8,0x55bd03f1d2c8,0 +dealloc,0x55bd03f1d298,0x55bd03f1d298,0 +dealloc,0x55bd03f1d268,0x55bd03f1d268,0 +dealloc,0x55bd03f1d238,0x55bd03f1d238,0 +dealloc,0x55bd03f1d018,0x55bd03f1d018,0 +dealloc,0x55bd03f1cfe8,0x55bd03f1cfe8,0 +dealloc,0x55bd03f1cf88,0x55bd03f1cf88,0 +dealloc,0x55bd03f1cf58,0x55bd03f1cf58,0 +dealloc,0x55bd03f1cf28,0x55bd03f1cf28,0 +dealloc,0x55bd03f1cec8,0x55bd03f1cec8,0 +dealloc,0x55bd03f0c1e8,0x55bd03f0c1e8,0 +dealloc,0x55bd03f0c1b8,0x55bd03f0c1b8,0 +dealloc,0x55bd03f0c118,0x55bd03f0c118,0 +dealloc,0x55bd03f0c0e8,0x55bd03f0c0e8,0 +dealloc,0x55bd03f0c0b8,0x55bd03f0c0b8,0 +dealloc,0x55bd03f0c088,0x55bd03f0c088,0 +dealloc,0x55bd03f0bf68,0x55bd03f0bf68,0 +dealloc,0x55bd03f0bf38,0x55bd03f0bf38,0 +dealloc,0x55bd03f0bed8,0x55bd03f0bed8,0 +dealloc,0x55bd03f0bea8,0x55bd03f0bea8,0 +dealloc,0x55bd03f0be78,0x55bd03f0be78,0 +dealloc,0x55bd03f0bdd8,0x55bd03f0bdd8,0 +dealloc,0x55bd03f0bda8,0x55bd03f0bda8,0 +dealloc,0x55bd03f0bc88,0x55bd03f0bc88,0 +dealloc,0x55bd03f0bbe8,0x55bd03f0bbe8,0 +dealloc,0x55bd03f0bbb8,0x55bd03f0bbb8,0 +dealloc,0x55bd03f0bb88,0x55bd03f0bb88,0 +dealloc,0x55bd03f0bae8,0x55bd03f0bae8,0 +dealloc,0x55bd03f0bab8,0x55bd03f0bab8,0 +dealloc,0x55bd03f0b998,0x55bd03f0b998,0 +dealloc,0x55bd03f0b8f8,0x55bd03f0b8f8,0 +dealloc,0x55bd03f0b8c8,0x55bd03f0b8c8,0 +dealloc,0x55bd03f0b828,0x55bd03f0b828,0 +dealloc,0x55bd03f0b7f8,0x55bd03f0b7f8,0 +alloc,0x55bd03f0b7f8,0x55bd03f0b7f8,368 +alloc,0x55bd03f1fe98,0x55bd03f1fe98,200 +alloc,0x55bd03f0b988,0x55bd03f0b988,200 +alloc,0x55bd03f1fa48,0x55bd03f1fa48,168 +alloc,0x55bd03f0ba68,0x55bd03f0ba68,280 +alloc,0x55bd03f0bb98,0x55bd03f0bb98,584 +alloc,0x55bd03f0bdf8,0x55bd03f0bdf8,216 +alloc,0x55bd03f1cec8,0x55bd03f1cec8,920 +alloc,0x55bd03f0bee8,0x55bd03f0bee8,520 +alloc,0x55bd03f1d278,0x55bd03f1d278,568 +dealloc,0x55bd03f1fe98,0x55bd03f1fe98,0 +dealloc,0x55bd03f0b988,0x55bd03f0b988,0 +dealloc,0x55bd03f1fa48,0x55bd03f1fa48,0 +dealloc,0x55bd03f0ba68,0x55bd03f0ba68,0 +dealloc,0x55bd03f0bb98,0x55bd03f0bb98,0 +dealloc,0x55bd03f0bdf8,0x55bd03f0bdf8,0 +dealloc,0x55bd03f1cec8,0x55bd03f1cec8,0 +dealloc,0x55bd03f0bee8,0x55bd03f0bee8,0 +dealloc,0x55bd03f1d278,0x55bd03f1d278,0 +dealloc,0x55bd03f0b7f8,0x55bd03f0b7f8,0 +alloc,0x55bd03f1f7e8,0x55bd03f1f7e8,48 +alloc,0x55bd03f1fac8,0x55bd03f1fac8,16 +alloc,0x55bd03f0b7f8,0x55bd03f0b7f8,2056 +alloc,0x55bd03f1cec8,0x55bd03f1cec8,2056 +alloc,0x55bd03f1fe98,0x55bd03f1fe98,48 +alloc,0x55bd03f0c018,0x55bd03f0c018,96 +alloc,0x55bd03f0c188,0x55bd03f0c188,24 +alloc,0x55bd03f0c1b8,0x55bd03f0c1b8,32 +alloc,0x55bd03f1d6e8,0x55bd03f1d6e8,368 +alloc,0x55bd03f1d878,0x55bd03f1d878,200 +alloc,0x55bd03f1d958,0x55bd03f1d958,200 +alloc,0x55bd03f1da38,0x55bd03f1da38,168 +alloc,0x55bd03f1daf8,0x55bd03f1daf8,280 +alloc,0x55bd03f1dc28,0x55bd03f1dc28,584 +alloc,0x55bd03f1de88,0x55bd03f1de88,216 +alloc,0x55bd03f1df78,0x55bd03f1df78,920 +alloc,0x55bd03f1e328,0x55bd03f1e328,520 +alloc,0x55bd03f1e548,0x55bd03f1e548,568 +dealloc,0x55bd03f1d878,0x55bd03f1d878,0 +dealloc,0x55bd03f1d958,0x55bd03f1d958,0 +dealloc,0x55bd03f1da38,0x55bd03f1da38,0 +dealloc,0x55bd03f1daf8,0x55bd03f1daf8,0 +dealloc,0x55bd03f1dc28,0x55bd03f1dc28,0 +dealloc,0x55bd03f1de88,0x55bd03f1de88,0 +dealloc,0x55bd03f1df78,0x55bd03f1df78,0 +dealloc,0x55bd03f1e328,0x55bd03f1e328,0 +dealloc,0x55bd03f1e548,0x55bd03f1e548,0 +dealloc,0x55bd03f1d6e8,0x55bd03f1d6e8,0 +alloc,0x55bd03f1d6e8,0x55bd03f1d6e8,4104 +dealloc,0x55bd03f1cec8,0x55bd03f1cec8,0 +alloc,0x55bd03f20ba8,0x55bd03f20ba8,4104 +dealloc,0x55bd03f0b7f8,0x55bd03f0b7f8,0 +alloc,0x55bd03f0c1f8,0x55bd03f0c1f8,32 +alloc,0x55bd03f1ff98,0x55bd03f1ff98,24 +alloc,0x55bd03f0bba8,0x55bd03f0bba8,368 +alloc,0x55bd03f0bd38,0x55bd03f0bd38,200 +alloc,0x55bd03f0be18,0x55bd03f0be18,200 +alloc,0x55bd03f0bef8,0x55bd03f0bef8,168 +alloc,0x55bd03f1cec8,0x55bd03f1cec8,280 +alloc,0x55bd03f1cff8,0x55bd03f1cff8,584 +alloc,0x55bd03f1d258,0x55bd03f1d258,216 +alloc,0x55bd03f1e708,0x55bd03f1e708,920 +alloc,0x55bd03f1d348,0x55bd03f1d348,520 +alloc,0x55bd03f1eab8,0x55bd03f1eab8,568 +dealloc,0x55bd03f0bd38,0x55bd03f0bd38,0 +dealloc,0x55bd03f0be18,0x55bd03f0be18,0 +dealloc,0x55bd03f0bef8,0x55bd03f0bef8,0 +dealloc,0x55bd03f1cec8,0x55bd03f1cec8,0 +dealloc,0x55bd03f1cff8,0x55bd03f1cff8,0 +dealloc,0x55bd03f1d258,0x55bd03f1d258,0 +dealloc,0x55bd03f1e708,0x55bd03f1e708,0 +dealloc,0x55bd03f1d348,0x55bd03f1d348,0 +dealloc,0x55bd03f1eab8,0x55bd03f1eab8,0 +dealloc,0x55bd03f0bba8,0x55bd03f0bba8,0 +alloc,0x55bd03f1ffc8,0x55bd03f1ffc8,24 +alloc,0x55bd03f0bc08,0x55bd03f0bc08,368 +alloc,0x55bd03f0bd98,0x55bd03f0bd98,200 +alloc,0x55bd03f0be78,0x55bd03f0be78,200 +alloc,0x55bd03f0bf58,0x55bd03f0bf58,168 +alloc,0x55bd03f1cec8,0x55bd03f1cec8,280 +alloc,0x55bd03f1cff8,0x55bd03f1cff8,584 +alloc,0x55bd03f1d258,0x55bd03f1d258,216 +alloc,0x55bd03f1e708,0x55bd03f1e708,920 +alloc,0x55bd03f1d348,0x55bd03f1d348,520 +alloc,0x55bd03f1eab8,0x55bd03f1eab8,568 +dealloc,0x55bd03f0bd98,0x55bd03f0bd98,0 +dealloc,0x55bd03f0be78,0x55bd03f0be78,0 +dealloc,0x55bd03f0bf58,0x55bd03f0bf58,0 +dealloc,0x55bd03f1cec8,0x55bd03f1cec8,0 +dealloc,0x55bd03f1cff8,0x55bd03f1cff8,0 +dealloc,0x55bd03f1d258,0x55bd03f1d258,0 +dealloc,0x55bd03f1e708,0x55bd03f1e708,0 +dealloc,0x55bd03f1d348,0x55bd03f1d348,0 +dealloc,0x55bd03f1eab8,0x55bd03f1eab8,0 +dealloc,0x55bd03f0bc08,0x55bd03f0bc08,0 +alloc,0x55bd03f0bc08,0x55bd03f0bc08,24 +alloc,0x55bd03f0bc38,0x55bd03f0bc38,368 +alloc,0x55bd03f0bdc8,0x55bd03f0bdc8,200 +alloc,0x55bd03f0bea8,0x55bd03f0bea8,200 +alloc,0x55bd03f1cec8,0x55bd03f1cec8,168 +alloc,0x55bd03f1cf88,0x55bd03f1cf88,280 +alloc,0x55bd03f1d0b8,0x55bd03f1d0b8,584 +alloc,0x55bd03f1d318,0x55bd03f1d318,216 +alloc,0x55bd03f1e708,0x55bd03f1e708,920 +alloc,0x55bd03f1d408,0x55bd03f1d408,520 +alloc,0x55bd03f1eab8,0x55bd03f1eab8,568 +dealloc,0x55bd03f0bdc8,0x55bd03f0bdc8,0 +dealloc,0x55bd03f0bea8,0x55bd03f0bea8,0 +dealloc,0x55bd03f1cec8,0x55bd03f1cec8,0 +dealloc,0x55bd03f1cf88,0x55bd03f1cf88,0 +dealloc,0x55bd03f1d0b8,0x55bd03f1d0b8,0 +dealloc,0x55bd03f1d318,0x55bd03f1d318,0 +dealloc,0x55bd03f1e708,0x55bd03f1e708,0 +dealloc,0x55bd03f1d408,0x55bd03f1d408,0 +dealloc,0x55bd03f1eab8,0x55bd03f1eab8,0 +dealloc,0x55bd03f0bc38,0x55bd03f0bc38,0 +alloc,0x55bd03f0bd08,0x55bd03f0bd08,24 +alloc,0x55bd03f0bd38,0x55bd03f0bd38,368 +alloc,0x55bd03f0bec8,0x55bd03f0bec8,200 +alloc,0x55bd03f1cec8,0x55bd03f1cec8,200 +alloc,0x55bd03f1cfa8,0x55bd03f1cfa8,168 +alloc,0x55bd03f1d068,0x55bd03f1d068,280 +alloc,0x55bd03f1d198,0x55bd03f1d198,584 +alloc,0x55bd03f1d3f8,0x55bd03f1d3f8,216 +alloc,0x55bd03f1e708,0x55bd03f1e708,920 +alloc,0x55bd03f1eab8,0x55bd03f1eab8,520 +alloc,0x55bd03f1ecd8,0x55bd03f1ecd8,568 +dealloc,0x55bd03f0bec8,0x55bd03f0bec8,0 +dealloc,0x55bd03f1cec8,0x55bd03f1cec8,0 +dealloc,0x55bd03f1cfa8,0x55bd03f1cfa8,0 +dealloc,0x55bd03f1d068,0x55bd03f1d068,0 +dealloc,0x55bd03f1d198,0x55bd03f1d198,0 +dealloc,0x55bd03f1d3f8,0x55bd03f1d3f8,0 +dealloc,0x55bd03f1e708,0x55bd03f1e708,0 +dealloc,0x55bd03f1eab8,0x55bd03f1eab8,0 +dealloc,0x55bd03f1ecd8,0x55bd03f1ecd8,0 +dealloc,0x55bd03f0bd38,0x55bd03f0bd38,0 +alloc,0x55bd03f0bdf8,0x55bd03f0bdf8,24 +alloc,0x55bd03f0be28,0x55bd03f0be28,368 +alloc,0x55bd03f1cec8,0x55bd03f1cec8,200 +alloc,0x55bd03f1cfa8,0x55bd03f1cfa8,200 +alloc,0x55bd03f1d088,0x55bd03f1d088,168 +alloc,0x55bd03f1d148,0x55bd03f1d148,280 +alloc,0x55bd03f1d278,0x55bd03f1d278,584 +alloc,0x55bd03f1d4d8,0x55bd03f1d4d8,216 +alloc,0x55bd03f1e708,0x55bd03f1e708,920 +alloc,0x55bd03f1eab8,0x55bd03f1eab8,520 +alloc,0x55bd03f1ecd8,0x55bd03f1ecd8,568 +dealloc,0x55bd03f1cec8,0x55bd03f1cec8,0 +dealloc,0x55bd03f1cfa8,0x55bd03f1cfa8,0 +dealloc,0x55bd03f1d088,0x55bd03f1d088,0 +dealloc,0x55bd03f1d148,0x55bd03f1d148,0 +dealloc,0x55bd03f1d278,0x55bd03f1d278,0 +dealloc,0x55bd03f1d4d8,0x55bd03f1d4d8,0 +dealloc,0x55bd03f1e708,0x55bd03f1e708,0 +dealloc,0x55bd03f1eab8,0x55bd03f1eab8,0 +dealloc,0x55bd03f1ecd8,0x55bd03f1ecd8,0 +dealloc,0x55bd03f0be28,0x55bd03f0be28,0 +alloc,0x55bd03f0bef8,0x55bd03f0bef8,24 +alloc,0x55bd03f1cec8,0x55bd03f1cec8,368 +alloc,0x55bd03f0bf28,0x55bd03f0bf28,200 +alloc,0x55bd03f1d058,0x55bd03f1d058,200 +alloc,0x55bd03f1d138,0x55bd03f1d138,168 +alloc,0x55bd03f1d1f8,0x55bd03f1d1f8,280 +alloc,0x55bd03f1d328,0x55bd03f1d328,584 +alloc,0x55bd03f1d588,0x55bd03f1d588,216 +alloc,0x55bd03f1e708,0x55bd03f1e708,920 +alloc,0x55bd03f1eab8,0x55bd03f1eab8,520 +alloc,0x55bd03f1ecd8,0x55bd03f1ecd8,568 +dealloc,0x55bd03f0bf28,0x55bd03f0bf28,0 +dealloc,0x55bd03f1d058,0x55bd03f1d058,0 +dealloc,0x55bd03f1d138,0x55bd03f1d138,0 +dealloc,0x55bd03f1d1f8,0x55bd03f1d1f8,0 +dealloc,0x55bd03f1d328,0x55bd03f1d328,0 +dealloc,0x55bd03f1d588,0x55bd03f1d588,0 +dealloc,0x55bd03f1e708,0x55bd03f1e708,0 +dealloc,0x55bd03f1eab8,0x55bd03f1eab8,0 +dealloc,0x55bd03f1ecd8,0x55bd03f1ecd8,0 +dealloc,0x55bd03f1cec8,0x55bd03f1cec8,0 +alloc,0x55bd03f1cec8,0x55bd03f1cec8,24 +alloc,0x55bd03f1cef8,0x55bd03f1cef8,368 +alloc,0x55bd03f1d088,0x55bd03f1d088,200 +alloc,0x55bd03f1d168,0x55bd03f1d168,200 +alloc,0x55bd03f1d248,0x55bd03f1d248,168 +alloc,0x55bd03f1d308,0x55bd03f1d308,280 +alloc,0x55bd03f1d438,0x55bd03f1d438,584 +alloc,0x55bd03f1e708,0x55bd03f1e708,216 +alloc,0x55bd03f1e7f8,0x55bd03f1e7f8,920 +alloc,0x55bd03f1eba8,0x55bd03f1eba8,520 +alloc,0x55bd03f1edc8,0x55bd03f1edc8,568 +dealloc,0x55bd03f1d088,0x55bd03f1d088,0 +dealloc,0x55bd03f1d168,0x55bd03f1d168,0 +dealloc,0x55bd03f1d248,0x55bd03f1d248,0 +dealloc,0x55bd03f1d308,0x55bd03f1d308,0 +dealloc,0x55bd03f1d438,0x55bd03f1d438,0 +dealloc,0x55bd03f1e708,0x55bd03f1e708,0 +dealloc,0x55bd03f1e7f8,0x55bd03f1e7f8,0 +dealloc,0x55bd03f1eba8,0x55bd03f1eba8,0 +dealloc,0x55bd03f1edc8,0x55bd03f1edc8,0 +dealloc,0x55bd03f1cef8,0x55bd03f1cef8,0 +alloc,0x55bd03f1cfc8,0x55bd03f1cfc8,24 +alloc,0x55bd03f1cff8,0x55bd03f1cff8,368 +alloc,0x55bd03f1d188,0x55bd03f1d188,200 +alloc,0x55bd03f1d268,0x55bd03f1d268,200 +alloc,0x55bd03f1d348,0x55bd03f1d348,168 +alloc,0x55bd03f1d408,0x55bd03f1d408,280 +alloc,0x55bd03f1e708,0x55bd03f1e708,584 +alloc,0x55bd03f1d538,0x55bd03f1d538,216 +alloc,0x55bd03f1e968,0x55bd03f1e968,920 +alloc,0x55bd03f1ed18,0x55bd03f1ed18,520 +alloc,0x55bd03f1ef38,0x55bd03f1ef38,568 +dealloc,0x55bd03f1d188,0x55bd03f1d188,0 +dealloc,0x55bd03f1d268,0x55bd03f1d268,0 +dealloc,0x55bd03f1d348,0x55bd03f1d348,0 +dealloc,0x55bd03f1d408,0x55bd03f1d408,0 +dealloc,0x55bd03f1e708,0x55bd03f1e708,0 +dealloc,0x55bd03f1d538,0x55bd03f1d538,0 +dealloc,0x55bd03f1e968,0x55bd03f1e968,0 +dealloc,0x55bd03f1ed18,0x55bd03f1ed18,0 +dealloc,0x55bd03f1ef38,0x55bd03f1ef38,0 +dealloc,0x55bd03f1cff8,0x55bd03f1cff8,0 +alloc,0x55bd03f1d0c8,0x55bd03f1d0c8,24 +alloc,0x55bd03f1d0f8,0x55bd03f1d0f8,368 +alloc,0x55bd03f1d288,0x55bd03f1d288,200 +alloc,0x55bd03f1d368,0x55bd03f1d368,200 +alloc,0x55bd03f1d448,0x55bd03f1d448,168 +alloc,0x55bd03f1d508,0x55bd03f1d508,280 +alloc,0x55bd03f1e708,0x55bd03f1e708,584 +alloc,0x55bd03f1e968,0x55bd03f1e968,216 +alloc,0x55bd03f1ea58,0x55bd03f1ea58,920 +alloc,0x55bd03f1ee08,0x55bd03f1ee08,520 +alloc,0x55bd03f1f028,0x55bd03f1f028,568 +dealloc,0x55bd03f1d288,0x55bd03f1d288,0 +dealloc,0x55bd03f1d368,0x55bd03f1d368,0 +dealloc,0x55bd03f1d448,0x55bd03f1d448,0 +dealloc,0x55bd03f1d508,0x55bd03f1d508,0 +dealloc,0x55bd03f1e708,0x55bd03f1e708,0 +dealloc,0x55bd03f1e968,0x55bd03f1e968,0 +dealloc,0x55bd03f1ea58,0x55bd03f1ea58,0 +dealloc,0x55bd03f1ee08,0x55bd03f1ee08,0 +dealloc,0x55bd03f1f028,0x55bd03f1f028,0 +dealloc,0x55bd03f1d0f8,0x55bd03f1d0f8,0 +alloc,0x55bd03f1d1c8,0x55bd03f1d1c8,24 +alloc,0x55bd03f1d1f8,0x55bd03f1d1f8,368 +alloc,0x55bd03f1d388,0x55bd03f1d388,200 +alloc,0x55bd03f1d468,0x55bd03f1d468,200 +alloc,0x55bd03f1d548,0x55bd03f1d548,168 +alloc,0x55bd03f1e708,0x55bd03f1e708,280 +alloc,0x55bd03f1e838,0x55bd03f1e838,584 +alloc,0x55bd03f1ea98,0x55bd03f1ea98,216 +alloc,0x55bd03f1eb88,0x55bd03f1eb88,920 +alloc,0x55bd03f1ef38,0x55bd03f1ef38,520 +alloc,0x55bd03f1f158,0x55bd03f1f158,568 +dealloc,0x55bd03f1d388,0x55bd03f1d388,0 +dealloc,0x55bd03f1d468,0x55bd03f1d468,0 +dealloc,0x55bd03f1d548,0x55bd03f1d548,0 +dealloc,0x55bd03f1e708,0x55bd03f1e708,0 +dealloc,0x55bd03f1e838,0x55bd03f1e838,0 +dealloc,0x55bd03f1ea98,0x55bd03f1ea98,0 +dealloc,0x55bd03f1eb88,0x55bd03f1eb88,0 +dealloc,0x55bd03f1ef38,0x55bd03f1ef38,0 +dealloc,0x55bd03f1f158,0x55bd03f1f158,0 +dealloc,0x55bd03f1d1f8,0x55bd03f1d1f8,0 +alloc,0x55bd03f1d2c8,0x55bd03f1d2c8,24 +alloc,0x55bd03f1d2f8,0x55bd03f1d2f8,368 +alloc,0x55bd03f1d488,0x55bd03f1d488,200 +alloc,0x55bd03f1d568,0x55bd03f1d568,200 +alloc,0x55bd03f1e708,0x55bd03f1e708,168 +alloc,0x55bd03f1e7c8,0x55bd03f1e7c8,280 +alloc,0x55bd03f1e8f8,0x55bd03f1e8f8,584 +alloc,0x55bd03f1eb58,0x55bd03f1eb58,216 +alloc,0x55bd03f1ec48,0x55bd03f1ec48,920 +alloc,0x55bd03f1eff8,0x55bd03f1eff8,520 +alloc,0x55bd03f1f218,0x55bd03f1f218,568 +dealloc,0x55bd03f1d488,0x55bd03f1d488,0 +dealloc,0x55bd03f1d568,0x55bd03f1d568,0 +dealloc,0x55bd03f1e708,0x55bd03f1e708,0 +dealloc,0x55bd03f1e7c8,0x55bd03f1e7c8,0 +dealloc,0x55bd03f1e8f8,0x55bd03f1e8f8,0 +dealloc,0x55bd03f1eb58,0x55bd03f1eb58,0 +dealloc,0x55bd03f1ec48,0x55bd03f1ec48,0 +dealloc,0x55bd03f1eff8,0x55bd03f1eff8,0 +dealloc,0x55bd03f1f218,0x55bd03f1f218,0 +dealloc,0x55bd03f1d2f8,0x55bd03f1d2f8,0 +alloc,0x55bd03f1d3c8,0x55bd03f1d3c8,24 +alloc,0x55bd03f1d3f8,0x55bd03f1d3f8,368 +alloc,0x55bd03f1d588,0x55bd03f1d588,200 +alloc,0x55bd03f1e708,0x55bd03f1e708,200 +alloc,0x55bd03f1e7e8,0x55bd03f1e7e8,168 +alloc,0x55bd03f1e8a8,0x55bd03f1e8a8,280 +alloc,0x55bd03f1e9d8,0x55bd03f1e9d8,584 +alloc,0x55bd03f1ec38,0x55bd03f1ec38,216 +alloc,0x55bd03f1ed28,0x55bd03f1ed28,920 +alloc,0x55bd03f1f0d8,0x55bd03f1f0d8,520 +alloc,0x55bd03f1f2f8,0x55bd03f1f2f8,568 +dealloc,0x55bd03f1d588,0x55bd03f1d588,0 +dealloc,0x55bd03f1e708,0x55bd03f1e708,0 +dealloc,0x55bd03f1e7e8,0x55bd03f1e7e8,0 +dealloc,0x55bd03f1e8a8,0x55bd03f1e8a8,0 +dealloc,0x55bd03f1e9d8,0x55bd03f1e9d8,0 +dealloc,0x55bd03f1ec38,0x55bd03f1ec38,0 +dealloc,0x55bd03f1ed28,0x55bd03f1ed28,0 +dealloc,0x55bd03f1f0d8,0x55bd03f1f0d8,0 +dealloc,0x55bd03f1f2f8,0x55bd03f1f2f8,0 +dealloc,0x55bd03f1d3f8,0x55bd03f1d3f8,0 +alloc,0x55bd03f1d4a8,0x55bd03f1d4a8,24 +alloc,0x55bd03f1d4d8,0x55bd03f1d4d8,368 +alloc,0x55bd03f1e708,0x55bd03f1e708,200 +alloc,0x55bd03f1e7e8,0x55bd03f1e7e8,200 +alloc,0x55bd03f1e8c8,0x55bd03f1e8c8,168 +alloc,0x55bd03f1e988,0x55bd03f1e988,280 +alloc,0x55bd03f1eab8,0x55bd03f1eab8,584 +alloc,0x55bd03f1ed18,0x55bd03f1ed18,216 +alloc,0x55bd03f1ee08,0x55bd03f1ee08,920 +alloc,0x55bd03f1f1b8,0x55bd03f1f1b8,520 +alloc,0x55bd03f1f3d8,0x55bd03f1f3d8,568 +dealloc,0x55bd03f1e708,0x55bd03f1e708,0 +dealloc,0x55bd03f1e7e8,0x55bd03f1e7e8,0 +dealloc,0x55bd03f1e8c8,0x55bd03f1e8c8,0 +dealloc,0x55bd03f1e988,0x55bd03f1e988,0 +dealloc,0x55bd03f1eab8,0x55bd03f1eab8,0 +dealloc,0x55bd03f1ed18,0x55bd03f1ed18,0 +dealloc,0x55bd03f1ee08,0x55bd03f1ee08,0 +dealloc,0x55bd03f1f1b8,0x55bd03f1f1b8,0 +dealloc,0x55bd03f1f3d8,0x55bd03f1f3d8,0 +dealloc,0x55bd03f1d4d8,0x55bd03f1d4d8,0 +alloc,0x55bd03f1d558,0x55bd03f1d558,24 +alloc,0x55bd03f1e708,0x55bd03f1e708,368 +alloc,0x55bd03f1d588,0x55bd03f1d588,200 +alloc,0x55bd03f1e898,0x55bd03f1e898,200 +alloc,0x55bd03f1e978,0x55bd03f1e978,168 +alloc,0x55bd03f1ea38,0x55bd03f1ea38,280 +alloc,0x55bd03f1eb68,0x55bd03f1eb68,584 +alloc,0x55bd03f1edc8,0x55bd03f1edc8,216 +alloc,0x55bd03f1eeb8,0x55bd03f1eeb8,920 +alloc,0x55bd03f1f268,0x55bd03f1f268,520 +alloc,0x55bd03f1f488,0x55bd03f1f488,568 +dealloc,0x55bd03f1d588,0x55bd03f1d588,0 +dealloc,0x55bd03f1e898,0x55bd03f1e898,0 +dealloc,0x55bd03f1e978,0x55bd03f1e978,0 +dealloc,0x55bd03f1ea38,0x55bd03f1ea38,0 +dealloc,0x55bd03f1eb68,0x55bd03f1eb68,0 +dealloc,0x55bd03f1edc8,0x55bd03f1edc8,0 +dealloc,0x55bd03f1eeb8,0x55bd03f1eeb8,0 +dealloc,0x55bd03f1f268,0x55bd03f1f268,0 +dealloc,0x55bd03f1f488,0x55bd03f1f488,0 +dealloc,0x55bd03f1e708,0x55bd03f1e708,0 +alloc,0x55bd03f1d698,0x55bd03f1d698,24 +alloc,0x55bd03f1e708,0x55bd03f1e708,368 +alloc,0x55bd03f1e898,0x55bd03f1e898,200 +alloc,0x55bd03f1e978,0x55bd03f1e978,200 +alloc,0x55bd03f1ea58,0x55bd03f1ea58,168 +alloc,0x55bd03f1eb18,0x55bd03f1eb18,280 +alloc,0x55bd03f1ec48,0x55bd03f1ec48,584 +alloc,0x55bd03f1eea8,0x55bd03f1eea8,216 +alloc,0x55bd03f1ef98,0x55bd03f1ef98,920 +alloc,0x55bd03f1f348,0x55bd03f1f348,520 +alloc,0x55bd03f33258,0x55bd03f33258,568 +dealloc,0x55bd03f1e898,0x55bd03f1e898,0 +dealloc,0x55bd03f1e978,0x55bd03f1e978,0 +dealloc,0x55bd03f1ea58,0x55bd03f1ea58,0 +dealloc,0x55bd03f1eb18,0x55bd03f1eb18,0 +dealloc,0x55bd03f1ec48,0x55bd03f1ec48,0 +dealloc,0x55bd03f1eea8,0x55bd03f1eea8,0 +dealloc,0x55bd03f1ef98,0x55bd03f1ef98,0 +dealloc,0x55bd03f1f348,0x55bd03f1f348,0 +dealloc,0x55bd03f33258,0x55bd03f33258,0 +dealloc,0x55bd03f1e708,0x55bd03f1e708,0 +alloc,0x55bd03f1e7d8,0x55bd03f1e7d8,24 +alloc,0x55bd03f1e808,0x55bd03f1e808,368 +alloc,0x55bd03f1e998,0x55bd03f1e998,200 +alloc,0x55bd03f1ea78,0x55bd03f1ea78,200 +alloc,0x55bd03f1eb58,0x55bd03f1eb58,168 +alloc,0x55bd03f1ec18,0x55bd03f1ec18,280 +alloc,0x55bd03f1ed48,0x55bd03f1ed48,584 +alloc,0x55bd03f1efa8,0x55bd03f1efa8,216 +alloc,0x55bd03f1f098,0x55bd03f1f098,920 +alloc,0x55bd03f1f448,0x55bd03f1f448,520 +alloc,0x55bd03f33258,0x55bd03f33258,568 +dealloc,0x55bd03f1e998,0x55bd03f1e998,0 +dealloc,0x55bd03f1ea78,0x55bd03f1ea78,0 +dealloc,0x55bd03f1eb58,0x55bd03f1eb58,0 +dealloc,0x55bd03f1ec18,0x55bd03f1ec18,0 +dealloc,0x55bd03f1ed48,0x55bd03f1ed48,0 +dealloc,0x55bd03f1efa8,0x55bd03f1efa8,0 +dealloc,0x55bd03f1f098,0x55bd03f1f098,0 +dealloc,0x55bd03f1f448,0x55bd03f1f448,0 +dealloc,0x55bd03f33258,0x55bd03f33258,0 +dealloc,0x55bd03f1e808,0x55bd03f1e808,0 +alloc,0x55bd03f1e808,0x55bd03f1e808,24 +alloc,0x55bd03f1e838,0x55bd03f1e838,368 +alloc,0x55bd03f1e9c8,0x55bd03f1e9c8,200 +alloc,0x55bd03f1eaa8,0x55bd03f1eaa8,200 +alloc,0x55bd03f1eb88,0x55bd03f1eb88,168 +alloc,0x55bd03f1ec48,0x55bd03f1ec48,280 +alloc,0x55bd03f1ed78,0x55bd03f1ed78,584 +alloc,0x55bd03f1efd8,0x55bd03f1efd8,216 +alloc,0x55bd03f1f0c8,0x55bd03f1f0c8,920 +alloc,0x55bd03f1f478,0x55bd03f1f478,520 +alloc,0x55bd03f34378,0x55bd03f34378,568 +dealloc,0x55bd03f1e9c8,0x55bd03f1e9c8,0 +dealloc,0x55bd03f1eaa8,0x55bd03f1eaa8,0 +dealloc,0x55bd03f1eb88,0x55bd03f1eb88,0 +dealloc,0x55bd03f1ec48,0x55bd03f1ec48,0 +dealloc,0x55bd03f1ed78,0x55bd03f1ed78,0 +dealloc,0x55bd03f1efd8,0x55bd03f1efd8,0 +dealloc,0x55bd03f1f0c8,0x55bd03f1f0c8,0 +dealloc,0x55bd03f1f478,0x55bd03f1f478,0 +dealloc,0x55bd03f34378,0x55bd03f34378,0 +dealloc,0x55bd03f1e838,0x55bd03f1e838,0 +alloc,0x55bd03f1ead8,0x55bd03f1ead8,24 +alloc,0x55bd03f1eb08,0x55bd03f1eb08,368 +alloc,0x55bd03f1ec98,0x55bd03f1ec98,200 +alloc,0x55bd03f1ed78,0x55bd03f1ed78,200 +alloc,0x55bd03f1ee58,0x55bd03f1ee58,168 +alloc,0x55bd03f1ef18,0x55bd03f1ef18,280 +alloc,0x55bd03f1f048,0x55bd03f1f048,584 +alloc,0x55bd03f1f2a8,0x55bd03f1f2a8,216 +alloc,0x55bd03f34378,0x55bd03f34378,920 +alloc,0x55bd03f1f398,0x55bd03f1f398,520 +alloc,0x55bd03f34728,0x55bd03f34728,568 +dealloc,0x55bd03f1ec98,0x55bd03f1ec98,0 +dealloc,0x55bd03f1ed78,0x55bd03f1ed78,0 +dealloc,0x55bd03f1ee58,0x55bd03f1ee58,0 +dealloc,0x55bd03f1ef18,0x55bd03f1ef18,0 +dealloc,0x55bd03f1f048,0x55bd03f1f048,0 +dealloc,0x55bd03f1f2a8,0x55bd03f1f2a8,0 +dealloc,0x55bd03f34378,0x55bd03f34378,0 +dealloc,0x55bd03f1f398,0x55bd03f1f398,0 +dealloc,0x55bd03f34728,0x55bd03f34728,0 +dealloc,0x55bd03f1eb08,0x55bd03f1eb08,0 +alloc,0x55bd03f1f5a8,0x55bd03f1f5a8,16 +alloc,0x55bd03f34378,0x55bd03f34378,368 +alloc,0x55bd03f1f5d8,0x55bd03f1f5d8,200 +alloc,0x55bd03f34508,0x55bd03f34508,200 +alloc,0x55bd03f345e8,0x55bd03f345e8,168 +alloc,0x55bd03f346a8,0x55bd03f346a8,280 +alloc,0x55bd03f347d8,0x55bd03f347d8,584 +alloc,0x55bd03f34a38,0x55bd03f34a38,216 +alloc,0x55bd03f34b28,0x55bd03f34b28,920 +alloc,0x55bd03f34ed8,0x55bd03f34ed8,520 +alloc,0x55bd03f350f8,0x55bd03f350f8,568 +dealloc,0x55bd03f1f5d8,0x55bd03f1f5d8,0 +dealloc,0x55bd03f34508,0x55bd03f34508,0 +dealloc,0x55bd03f345e8,0x55bd03f345e8,0 +dealloc,0x55bd03f346a8,0x55bd03f346a8,0 +dealloc,0x55bd03f347d8,0x55bd03f347d8,0 +dealloc,0x55bd03f34a38,0x55bd03f34a38,0 +dealloc,0x55bd03f34b28,0x55bd03f34b28,0 +dealloc,0x55bd03f34ed8,0x55bd03f34ed8,0 +dealloc,0x55bd03f350f8,0x55bd03f350f8,0 +dealloc,0x55bd03f34378,0x55bd03f34378,0 +alloc,0x55bd03f1f5d8,0x55bd03f1f5d8,16 +alloc,0x55bd03f34b88,0x55bd03f34b88,368 +alloc,0x55bd03f1f608,0x55bd03f1f608,200 +alloc,0x55bd03f34d18,0x55bd03f34d18,200 +alloc,0x55bd03f34df8,0x55bd03f34df8,168 +alloc,0x55bd03f34eb8,0x55bd03f34eb8,280 +alloc,0x55bd03f34fe8,0x55bd03f34fe8,584 +alloc,0x55bd03f35248,0x55bd03f35248,216 +alloc,0x55bd03f35338,0x55bd03f35338,920 +alloc,0x55bd03f356e8,0x55bd03f356e8,520 +alloc,0x55bd03f35908,0x55bd03f35908,568 +dealloc,0x55bd03f1f608,0x55bd03f1f608,0 +dealloc,0x55bd03f34d18,0x55bd03f34d18,0 +dealloc,0x55bd03f34df8,0x55bd03f34df8,0 +dealloc,0x55bd03f34eb8,0x55bd03f34eb8,0 +dealloc,0x55bd03f34fe8,0x55bd03f34fe8,0 +dealloc,0x55bd03f35248,0x55bd03f35248,0 +dealloc,0x55bd03f35338,0x55bd03f35338,0 +dealloc,0x55bd03f356e8,0x55bd03f356e8,0 +dealloc,0x55bd03f35908,0x55bd03f35908,0 +dealloc,0x55bd03f34b88,0x55bd03f34b88,0 +alloc,0x55bd03f1f608,0x55bd03f1f608,16 +alloc,0x55bd03f36468,0x55bd03f36468,368 +alloc,0x55bd03f365f8,0x55bd03f365f8,200 +alloc,0x55bd03f366d8,0x55bd03f366d8,200 +alloc,0x55bd03f1f638,0x55bd03f1f638,168 +alloc,0x55bd03f367b8,0x55bd03f367b8,280 +alloc,0x55bd03f368e8,0x55bd03f368e8,584 +alloc,0x55bd03f36b48,0x55bd03f36b48,216 +alloc,0x55bd03f36c38,0x55bd03f36c38,920 +alloc,0x55bd03f36fe8,0x55bd03f36fe8,520 +alloc,0x55bd03f37208,0x55bd03f37208,568 +dealloc,0x55bd03f365f8,0x55bd03f365f8,0 +dealloc,0x55bd03f366d8,0x55bd03f366d8,0 +dealloc,0x55bd03f1f638,0x55bd03f1f638,0 +dealloc,0x55bd03f367b8,0x55bd03f367b8,0 +dealloc,0x55bd03f368e8,0x55bd03f368e8,0 +dealloc,0x55bd03f36b48,0x55bd03f36b48,0 +dealloc,0x55bd03f36c38,0x55bd03f36c38,0 +dealloc,0x55bd03f36fe8,0x55bd03f36fe8,0 +dealloc,0x55bd03f37208,0x55bd03f37208,0 +dealloc,0x55bd03f36468,0x55bd03f36468,0 +alloc,0x55bd03f1f638,0x55bd03f1f638,16 +alloc,0x55bd03f372e8,0x55bd03f372e8,368 +alloc,0x55bd03f37478,0x55bd03f37478,200 +alloc,0x55bd03f37558,0x55bd03f37558,200 +alloc,0x55bd03f37638,0x55bd03f37638,168 +alloc,0x55bd03f376f8,0x55bd03f376f8,280 +alloc,0x55bd03f37828,0x55bd03f37828,584 +alloc,0x55bd03f37a88,0x55bd03f37a88,216 +alloc,0x55bd03f37b78,0x55bd03f37b78,920 +alloc,0x55bd03f37f28,0x55bd03f37f28,520 +alloc,0x55bd03f38148,0x55bd03f38148,568 +dealloc,0x55bd03f37478,0x55bd03f37478,0 +dealloc,0x55bd03f37558,0x55bd03f37558,0 +dealloc,0x55bd03f37638,0x55bd03f37638,0 +dealloc,0x55bd03f376f8,0x55bd03f376f8,0 +dealloc,0x55bd03f37828,0x55bd03f37828,0 +dealloc,0x55bd03f37a88,0x55bd03f37a88,0 +dealloc,0x55bd03f37b78,0x55bd03f37b78,0 +dealloc,0x55bd03f37f28,0x55bd03f37f28,0 +dealloc,0x55bd03f38148,0x55bd03f38148,0 +dealloc,0x55bd03f372e8,0x55bd03f372e8,0 +alloc,0x55bd03f1f668,0x55bd03f1f668,16 +alloc,0x55bd03f39c08,0x55bd03f39c08,368 +alloc,0x55bd03f39d98,0x55bd03f39d98,200 +alloc,0x55bd03f39e78,0x55bd03f39e78,200 +alloc,0x55bd03f39f58,0x55bd03f39f58,168 +alloc,0x55bd03f3a018,0x55bd03f3a018,280 +alloc,0x55bd03f3a148,0x55bd03f3a148,584 +alloc,0x55bd03f3a3a8,0x55bd03f3a3a8,216 +alloc,0x55bd03f3a498,0x55bd03f3a498,920 +alloc,0x55bd03f3a848,0x55bd03f3a848,520 +alloc,0x55bd03f3aa68,0x55bd03f3aa68,568 +dealloc,0x55bd03f39d98,0x55bd03f39d98,0 +dealloc,0x55bd03f39e78,0x55bd03f39e78,0 +dealloc,0x55bd03f39f58,0x55bd03f39f58,0 +dealloc,0x55bd03f3a018,0x55bd03f3a018,0 +dealloc,0x55bd03f3a148,0x55bd03f3a148,0 +dealloc,0x55bd03f3a3a8,0x55bd03f3a3a8,0 +dealloc,0x55bd03f3a498,0x55bd03f3a498,0 +dealloc,0x55bd03f3a848,0x55bd03f3a848,0 +dealloc,0x55bd03f3aa68,0x55bd03f3aa68,0 +dealloc,0x55bd03f39c08,0x55bd03f39c08,0 +alloc,0x55bd03f1f698,0x55bd03f1f698,16 +alloc,0x55bd03f3b4c8,0x55bd03f3b4c8,368 +alloc,0x55bd03f3b658,0x55bd03f3b658,200 +alloc,0x55bd03f3b738,0x55bd03f3b738,200 +alloc,0x55bd03f3b818,0x55bd03f3b818,168 +alloc,0x55bd03f3b8d8,0x55bd03f3b8d8,280 +alloc,0x55bd03f3ba08,0x55bd03f3ba08,584 +alloc,0x55bd03f3bc68,0x55bd03f3bc68,216 +alloc,0x55bd03f3bd58,0x55bd03f3bd58,920 +alloc,0x55bd03f3c108,0x55bd03f3c108,520 +alloc,0x55bd03f3c328,0x55bd03f3c328,568 +dealloc,0x55bd03f3b658,0x55bd03f3b658,0 +dealloc,0x55bd03f3b738,0x55bd03f3b738,0 +dealloc,0x55bd03f3b818,0x55bd03f3b818,0 +dealloc,0x55bd03f3b8d8,0x55bd03f3b8d8,0 +dealloc,0x55bd03f3ba08,0x55bd03f3ba08,0 +dealloc,0x55bd03f3bc68,0x55bd03f3bc68,0 +dealloc,0x55bd03f3bd58,0x55bd03f3bd58,0 +dealloc,0x55bd03f3c108,0x55bd03f3c108,0 +dealloc,0x55bd03f3c328,0x55bd03f3c328,0 +dealloc,0x55bd03f3b4c8,0x55bd03f3b4c8,0 +alloc,0x55bd03f1f6c8,0x55bd03f1f6c8,16 +alloc,0x55bd03f3cfd8,0x55bd03f3cfd8,368 +alloc,0x55bd03f3d168,0x55bd03f3d168,200 +alloc,0x55bd03f3d248,0x55bd03f3d248,200 +alloc,0x55bd03f3d328,0x55bd03f3d328,168 +alloc,0x55bd03f3d3e8,0x55bd03f3d3e8,280 +alloc,0x55bd03f3d518,0x55bd03f3d518,584 +alloc,0x55bd03f3d778,0x55bd03f3d778,216 +alloc,0x55bd03f3d868,0x55bd03f3d868,920 +alloc,0x55bd03f3dc18,0x55bd03f3dc18,520 +alloc,0x55bd03f3de38,0x55bd03f3de38,568 +dealloc,0x55bd03f3d168,0x55bd03f3d168,0 +dealloc,0x55bd03f3d248,0x55bd03f3d248,0 +dealloc,0x55bd03f3d328,0x55bd03f3d328,0 +dealloc,0x55bd03f3d3e8,0x55bd03f3d3e8,0 +dealloc,0x55bd03f3d518,0x55bd03f3d518,0 +dealloc,0x55bd03f3d778,0x55bd03f3d778,0 +dealloc,0x55bd03f3d868,0x55bd03f3d868,0 +dealloc,0x55bd03f3dc18,0x55bd03f3dc18,0 +dealloc,0x55bd03f3de38,0x55bd03f3de38,0 +dealloc,0x55bd03f3cfd8,0x55bd03f3cfd8,0 +alloc,0x55bd03f3e638,0x55bd03f3e638,16 +alloc,0x55bd03f3e668,0x55bd03f3e668,368 +alloc,0x55bd03f3e7f8,0x55bd03f3e7f8,200 +alloc,0x55bd03f3e8d8,0x55bd03f3e8d8,200 +alloc,0x55bd03f3e9b8,0x55bd03f3e9b8,168 +alloc,0x55bd03f3ea78,0x55bd03f3ea78,280 +alloc,0x55bd03f3eba8,0x55bd03f3eba8,584 +alloc,0x55bd03f3ee08,0x55bd03f3ee08,216 +alloc,0x55bd03f3eef8,0x55bd03f3eef8,920 +alloc,0x55bd03f3f2a8,0x55bd03f3f2a8,520 +alloc,0x55bd03f3f4c8,0x55bd03f3f4c8,568 +dealloc,0x55bd03f3e7f8,0x55bd03f3e7f8,0 +dealloc,0x55bd03f3e8d8,0x55bd03f3e8d8,0 +dealloc,0x55bd03f3e9b8,0x55bd03f3e9b8,0 +dealloc,0x55bd03f3ea78,0x55bd03f3ea78,0 +dealloc,0x55bd03f3eba8,0x55bd03f3eba8,0 +dealloc,0x55bd03f3ee08,0x55bd03f3ee08,0 +dealloc,0x55bd03f3eef8,0x55bd03f3eef8,0 +dealloc,0x55bd03f3f2a8,0x55bd03f3f2a8,0 +dealloc,0x55bd03f3f4c8,0x55bd03f3f4c8,0 +dealloc,0x55bd03f3e668,0x55bd03f3e668,0 +alloc,0x55bd03f41ea8,0x55bd03f41ea8,16 +alloc,0x55bd03f41ed8,0x55bd03f41ed8,368 +alloc,0x55bd03f42068,0x55bd03f42068,200 +alloc,0x55bd03f42148,0x55bd03f42148,200 +alloc,0x55bd03f42228,0x55bd03f42228,168 +alloc,0x55bd03f422e8,0x55bd03f422e8,280 +alloc,0x55bd03f42418,0x55bd03f42418,584 +alloc,0x55bd03f42678,0x55bd03f42678,216 +alloc,0x55bd03f42768,0x55bd03f42768,920 +alloc,0x55bd03f42b18,0x55bd03f42b18,520 +alloc,0x55bd03f42d38,0x55bd03f42d38,568 +dealloc,0x55bd03f42068,0x55bd03f42068,0 +dealloc,0x55bd03f42148,0x55bd03f42148,0 +dealloc,0x55bd03f42228,0x55bd03f42228,0 +dealloc,0x55bd03f422e8,0x55bd03f422e8,0 +dealloc,0x55bd03f42418,0x55bd03f42418,0 +dealloc,0x55bd03f42678,0x55bd03f42678,0 +dealloc,0x55bd03f42768,0x55bd03f42768,0 +dealloc,0x55bd03f42b18,0x55bd03f42b18,0 +dealloc,0x55bd03f42d38,0x55bd03f42d38,0 +dealloc,0x55bd03f41ed8,0x55bd03f41ed8,0 +alloc,0x55bd03f41fb8,0x55bd03f41fb8,16 +alloc,0x55bd03f41fe8,0x55bd03f41fe8,368 +alloc,0x55bd03f42178,0x55bd03f42178,200 +alloc,0x55bd03f42258,0x55bd03f42258,200 +alloc,0x55bd03f42338,0x55bd03f42338,168 +alloc,0x55bd03f423f8,0x55bd03f423f8,280 +alloc,0x55bd03f42528,0x55bd03f42528,584 +alloc,0x55bd03f42788,0x55bd03f42788,216 +alloc,0x55bd03f42878,0x55bd03f42878,920 +alloc,0x55bd03f42c28,0x55bd03f42c28,520 +alloc,0x55bd03f42e48,0x55bd03f42e48,568 +dealloc,0x55bd03f42178,0x55bd03f42178,0 +dealloc,0x55bd03f42258,0x55bd03f42258,0 +dealloc,0x55bd03f42338,0x55bd03f42338,0 +dealloc,0x55bd03f423f8,0x55bd03f423f8,0 +dealloc,0x55bd03f42528,0x55bd03f42528,0 +dealloc,0x55bd03f42788,0x55bd03f42788,0 +dealloc,0x55bd03f42878,0x55bd03f42878,0 +dealloc,0x55bd03f42c28,0x55bd03f42c28,0 +dealloc,0x55bd03f42e48,0x55bd03f42e48,0 +dealloc,0x55bd03f41fe8,0x55bd03f41fe8,0 +alloc,0x55bd03f45348,0x55bd03f45348,16 +alloc,0x55bd03f45378,0x55bd03f45378,368 +alloc,0x55bd03f45508,0x55bd03f45508,200 +alloc,0x55bd03f455e8,0x55bd03f455e8,200 +alloc,0x55bd03f456c8,0x55bd03f456c8,168 +alloc,0x55bd03f45788,0x55bd03f45788,280 +alloc,0x55bd03f458b8,0x55bd03f458b8,584 +alloc,0x55bd03f45b18,0x55bd03f45b18,216 +alloc,0x55bd03f45c08,0x55bd03f45c08,920 +alloc,0x55bd03f45fb8,0x55bd03f45fb8,520 +alloc,0x55bd03f461d8,0x55bd03f461d8,568 +dealloc,0x55bd03f45508,0x55bd03f45508,0 +dealloc,0x55bd03f455e8,0x55bd03f455e8,0 +dealloc,0x55bd03f456c8,0x55bd03f456c8,0 +dealloc,0x55bd03f45788,0x55bd03f45788,0 +dealloc,0x55bd03f458b8,0x55bd03f458b8,0 +dealloc,0x55bd03f45b18,0x55bd03f45b18,0 +dealloc,0x55bd03f45c08,0x55bd03f45c08,0 +dealloc,0x55bd03f45fb8,0x55bd03f45fb8,0 +dealloc,0x55bd03f461d8,0x55bd03f461d8,0 +dealloc,0x55bd03f45378,0x55bd03f45378,0 +alloc,0x55bd03f47438,0x55bd03f47438,16 +alloc,0x55bd03f47468,0x55bd03f47468,368 +alloc,0x55bd03f475f8,0x55bd03f475f8,200 +alloc,0x55bd03f476d8,0x55bd03f476d8,200 +alloc,0x55bd03f477b8,0x55bd03f477b8,168 +alloc,0x55bd03f47878,0x55bd03f47878,280 +alloc,0x55bd03f479a8,0x55bd03f479a8,584 +alloc,0x55bd03f47c08,0x55bd03f47c08,216 +alloc,0x55bd03f47cf8,0x55bd03f47cf8,920 +alloc,0x55bd03f480a8,0x55bd03f480a8,520 +alloc,0x55bd03f482c8,0x55bd03f482c8,568 +dealloc,0x55bd03f475f8,0x55bd03f475f8,0 +dealloc,0x55bd03f476d8,0x55bd03f476d8,0 +dealloc,0x55bd03f477b8,0x55bd03f477b8,0 +dealloc,0x55bd03f47878,0x55bd03f47878,0 +dealloc,0x55bd03f479a8,0x55bd03f479a8,0 +dealloc,0x55bd03f47c08,0x55bd03f47c08,0 +dealloc,0x55bd03f47cf8,0x55bd03f47cf8,0 +dealloc,0x55bd03f480a8,0x55bd03f480a8,0 +dealloc,0x55bd03f482c8,0x55bd03f482c8,0 +dealloc,0x55bd03f47468,0x55bd03f47468,0 +alloc,0x55bd03f4c018,0x55bd03f4c018,16 +alloc,0x55bd03f4c048,0x55bd03f4c048,368 +alloc,0x55bd03f4c1d8,0x55bd03f4c1d8,200 +alloc,0x55bd03f4c2b8,0x55bd03f4c2b8,200 +alloc,0x55bd03f4c398,0x55bd03f4c398,168 +alloc,0x55bd03f4c458,0x55bd03f4c458,280 +alloc,0x55bd03f4c588,0x55bd03f4c588,584 +alloc,0x55bd03f4c7e8,0x55bd03f4c7e8,216 +alloc,0x55bd03f4c8d8,0x55bd03f4c8d8,920 +alloc,0x55bd03f4cc88,0x55bd03f4cc88,520 +alloc,0x55bd03f4cea8,0x55bd03f4cea8,568 +dealloc,0x55bd03f4c1d8,0x55bd03f4c1d8,0 +dealloc,0x55bd03f4c2b8,0x55bd03f4c2b8,0 +dealloc,0x55bd03f4c398,0x55bd03f4c398,0 +dealloc,0x55bd03f4c458,0x55bd03f4c458,0 +dealloc,0x55bd03f4c588,0x55bd03f4c588,0 +dealloc,0x55bd03f4c7e8,0x55bd03f4c7e8,0 +dealloc,0x55bd03f4c8d8,0x55bd03f4c8d8,0 +dealloc,0x55bd03f4cc88,0x55bd03f4cc88,0 +dealloc,0x55bd03f4cea8,0x55bd03f4cea8,0 +dealloc,0x55bd03f4c048,0x55bd03f4c048,0 +alloc,0x55bd03f51278,0x55bd03f51278,16 +alloc,0x55bd03f512a8,0x55bd03f512a8,368 +alloc,0x55bd03f51438,0x55bd03f51438,200 +alloc,0x55bd03f51518,0x55bd03f51518,200 +alloc,0x55bd03f515f8,0x55bd03f515f8,168 +alloc,0x55bd03f516b8,0x55bd03f516b8,280 +alloc,0x55bd03f517e8,0x55bd03f517e8,584 +alloc,0x55bd03f51a48,0x55bd03f51a48,216 +alloc,0x55bd03f51b38,0x55bd03f51b38,920 +alloc,0x55bd03f51ee8,0x55bd03f51ee8,520 +alloc,0x55bd03f52108,0x55bd03f52108,568 +dealloc,0x55bd03f51438,0x55bd03f51438,0 +dealloc,0x55bd03f51518,0x55bd03f51518,0 +dealloc,0x55bd03f515f8,0x55bd03f515f8,0 +dealloc,0x55bd03f516b8,0x55bd03f516b8,0 +dealloc,0x55bd03f517e8,0x55bd03f517e8,0 +dealloc,0x55bd03f51a48,0x55bd03f51a48,0 +dealloc,0x55bd03f51b38,0x55bd03f51b38,0 +dealloc,0x55bd03f51ee8,0x55bd03f51ee8,0 +dealloc,0x55bd03f52108,0x55bd03f52108,0 +dealloc,0x55bd03f512a8,0x55bd03f512a8,0 +alloc,0x55bd03f56378,0x55bd03f56378,16 +alloc,0x55bd03f563a8,0x55bd03f563a8,368 +alloc,0x55bd03f56538,0x55bd03f56538,200 +alloc,0x55bd03f56618,0x55bd03f56618,200 +alloc,0x55bd03f566f8,0x55bd03f566f8,168 +alloc,0x55bd03f567b8,0x55bd03f567b8,280 +alloc,0x55bd03f568e8,0x55bd03f568e8,584 +alloc,0x55bd03f56b48,0x55bd03f56b48,216 +alloc,0x55bd03f56c38,0x55bd03f56c38,920 +alloc,0x55bd03f56fe8,0x55bd03f56fe8,520 +alloc,0x55bd03f57208,0x55bd03f57208,568 +dealloc,0x55bd03f56538,0x55bd03f56538,0 +dealloc,0x55bd03f56618,0x55bd03f56618,0 +dealloc,0x55bd03f566f8,0x55bd03f566f8,0 +dealloc,0x55bd03f567b8,0x55bd03f567b8,0 +dealloc,0x55bd03f568e8,0x55bd03f568e8,0 +dealloc,0x55bd03f56b48,0x55bd03f56b48,0 +dealloc,0x55bd03f56c38,0x55bd03f56c38,0 +dealloc,0x55bd03f56fe8,0x55bd03f56fe8,0 +dealloc,0x55bd03f57208,0x55bd03f57208,0 +dealloc,0x55bd03f563a8,0x55bd03f563a8,0 +alloc,0x55bd03f578d8,0x55bd03f578d8,16 +alloc,0x55bd03f57908,0x55bd03f57908,368 +alloc,0x55bd03f57a98,0x55bd03f57a98,200 +alloc,0x55bd03f57b78,0x55bd03f57b78,200 +alloc,0x55bd03f57c58,0x55bd03f57c58,168 +alloc,0x55bd03f57d18,0x55bd03f57d18,280 +alloc,0x55bd03f57e48,0x55bd03f57e48,584 +alloc,0x55bd03f580a8,0x55bd03f580a8,216 +alloc,0x55bd03f58198,0x55bd03f58198,920 +alloc,0x55bd03f58548,0x55bd03f58548,520 +alloc,0x55bd03f58768,0x55bd03f58768,568 +dealloc,0x55bd03f57a98,0x55bd03f57a98,0 +dealloc,0x55bd03f57b78,0x55bd03f57b78,0 +dealloc,0x55bd03f57c58,0x55bd03f57c58,0 +dealloc,0x55bd03f57d18,0x55bd03f57d18,0 +dealloc,0x55bd03f57e48,0x55bd03f57e48,0 +dealloc,0x55bd03f580a8,0x55bd03f580a8,0 +dealloc,0x55bd03f58198,0x55bd03f58198,0 +dealloc,0x55bd03f58548,0x55bd03f58548,0 +dealloc,0x55bd03f58768,0x55bd03f58768,0 +dealloc,0x55bd03f57908,0x55bd03f57908,0 +alloc,0x55bd03f58048,0x55bd03f58048,16 +alloc,0x55bd03f58078,0x55bd03f58078,368 +alloc,0x55bd03f58208,0x55bd03f58208,200 +alloc,0x55bd03f582e8,0x55bd03f582e8,200 +alloc,0x55bd03f583c8,0x55bd03f583c8,168 +alloc,0x55bd03f58488,0x55bd03f58488,280 +alloc,0x55bd03f585b8,0x55bd03f585b8,584 +alloc,0x55bd03f58818,0x55bd03f58818,216 +alloc,0x55bd03f58908,0x55bd03f58908,920 +alloc,0x55bd03f58cb8,0x55bd03f58cb8,520 +alloc,0x55bd03f58ed8,0x55bd03f58ed8,568 +dealloc,0x55bd03f58208,0x55bd03f58208,0 +dealloc,0x55bd03f582e8,0x55bd03f582e8,0 +dealloc,0x55bd03f583c8,0x55bd03f583c8,0 +dealloc,0x55bd03f58488,0x55bd03f58488,0 +dealloc,0x55bd03f585b8,0x55bd03f585b8,0 +dealloc,0x55bd03f58818,0x55bd03f58818,0 +dealloc,0x55bd03f58908,0x55bd03f58908,0 +dealloc,0x55bd03f58cb8,0x55bd03f58cb8,0 +dealloc,0x55bd03f58ed8,0x55bd03f58ed8,0 +dealloc,0x55bd03f58078,0x55bd03f58078,0 +alloc,0x55bd03f58368,0x55bd03f58368,16 +alloc,0x55bd03f58398,0x55bd03f58398,368 +alloc,0x55bd03f58528,0x55bd03f58528,200 +alloc,0x55bd03f58608,0x55bd03f58608,200 +alloc,0x55bd03f586e8,0x55bd03f586e8,168 +alloc,0x55bd03f587a8,0x55bd03f587a8,280 +alloc,0x55bd03f588d8,0x55bd03f588d8,584 +alloc,0x55bd03f58b38,0x55bd03f58b38,216 +alloc,0x55bd03f58c28,0x55bd03f58c28,920 +alloc,0x55bd03f58fd8,0x55bd03f58fd8,520 +alloc,0x55bd03f591f8,0x55bd03f591f8,568 +dealloc,0x55bd03f58528,0x55bd03f58528,0 +dealloc,0x55bd03f58608,0x55bd03f58608,0 +dealloc,0x55bd03f586e8,0x55bd03f586e8,0 +dealloc,0x55bd03f587a8,0x55bd03f587a8,0 +dealloc,0x55bd03f588d8,0x55bd03f588d8,0 +dealloc,0x55bd03f58b38,0x55bd03f58b38,0 +dealloc,0x55bd03f58c28,0x55bd03f58c28,0 +dealloc,0x55bd03f58fd8,0x55bd03f58fd8,0 +dealloc,0x55bd03f591f8,0x55bd03f591f8,0 +dealloc,0x55bd03f58398,0x55bd03f58398,0 +alloc,0x55bd03f5db98,0x55bd03f5db98,16 +alloc,0x55bd03f5dbc8,0x55bd03f5dbc8,368 +alloc,0x55bd03f5dd58,0x55bd03f5dd58,200 +alloc,0x55bd03f5de38,0x55bd03f5de38,200 +alloc,0x55bd03f5df18,0x55bd03f5df18,168 +alloc,0x55bd03f5dfd8,0x55bd03f5dfd8,280 +alloc,0x55bd03f5e108,0x55bd03f5e108,584 +alloc,0x55bd03f5e368,0x55bd03f5e368,216 +alloc,0x55bd03f5e458,0x55bd03f5e458,920 +alloc,0x55bd03f5e808,0x55bd03f5e808,520 +alloc,0x55bd03f5ea28,0x55bd03f5ea28,568 +dealloc,0x55bd03f5dd58,0x55bd03f5dd58,0 +dealloc,0x55bd03f5de38,0x55bd03f5de38,0 +dealloc,0x55bd03f5df18,0x55bd03f5df18,0 +dealloc,0x55bd03f5dfd8,0x55bd03f5dfd8,0 +dealloc,0x55bd03f5e108,0x55bd03f5e108,0 +dealloc,0x55bd03f5e368,0x55bd03f5e368,0 +dealloc,0x55bd03f5e458,0x55bd03f5e458,0 +dealloc,0x55bd03f5e808,0x55bd03f5e808,0 +dealloc,0x55bd03f5ea28,0x55bd03f5ea28,0 +dealloc,0x55bd03f5dbc8,0x55bd03f5dbc8,0 +alloc,0x55bd03f62578,0x55bd03f62578,16 +alloc,0x55bd03f625a8,0x55bd03f625a8,368 +alloc,0x55bd03f62738,0x55bd03f62738,200 +alloc,0x55bd03f62818,0x55bd03f62818,200 +alloc,0x55bd03f628f8,0x55bd03f628f8,168 +alloc,0x55bd03f629b8,0x55bd03f629b8,280 +alloc,0x55bd03f62ae8,0x55bd03f62ae8,584 +alloc,0x55bd03f62d48,0x55bd03f62d48,216 +alloc,0x55bd03f62e38,0x55bd03f62e38,920 +alloc,0x55bd03f631e8,0x55bd03f631e8,520 +alloc,0x55bd03f63408,0x55bd03f63408,568 +dealloc,0x55bd03f62738,0x55bd03f62738,0 +dealloc,0x55bd03f62818,0x55bd03f62818,0 +dealloc,0x55bd03f628f8,0x55bd03f628f8,0 +dealloc,0x55bd03f629b8,0x55bd03f629b8,0 +dealloc,0x55bd03f62ae8,0x55bd03f62ae8,0 +dealloc,0x55bd03f62d48,0x55bd03f62d48,0 +dealloc,0x55bd03f62e38,0x55bd03f62e38,0 +dealloc,0x55bd03f631e8,0x55bd03f631e8,0 +dealloc,0x55bd03f63408,0x55bd03f63408,0 +dealloc,0x55bd03f625a8,0x55bd03f625a8,0 +alloc,0x55bd03f62648,0x55bd03f62648,24 +alloc,0x55bd03f62678,0x55bd03f62678,24 +alloc,0x55bd03f626a8,0x55bd03f626a8,40 +alloc,0x55bd03f626e8,0x55bd03f626e8,56 +alloc,0x55bd03f62738,0x55bd03f62738,400 +alloc,0x55bd03f628e8,0x55bd03f628e8,400 +alloc,0x55bd03f62a98,0x55bd03f62a98,400 +alloc,0x55bd03f62c48,0x55bd03f62c48,9 +alloc,0x55bd03f62c78,0x55bd03f62c78,15 +alloc,0x55bd03f62ca8,0x55bd03f62ca8,9 +alloc,0x55bd03f62cd8,0x55bd03f62cd8,9 +alloc,0x55bd03f62d08,0x55bd03f62d08,15 +alloc,0x55bd03f62d38,0x55bd03f62d38,9 +alloc,0x55bd03f62d68,0x55bd03f62d68,9 +alloc,0x55bd03f62d98,0x55bd03f62d98,15 +alloc,0x55bd03f62dc8,0x55bd03f62dc8,9 +alloc,0x55bd03f62df8,0x55bd03f62df8,9 +alloc,0x55bd03f62e28,0x55bd03f62e28,15 +alloc,0x55bd03f62e58,0x55bd03f62e58,9 +alloc,0x55bd03f62e88,0x55bd03f62e88,9 +alloc,0x55bd03f62eb8,0x55bd03f62eb8,15 +alloc,0x55bd03f62ee8,0x55bd03f62ee8,9 +alloc,0x55bd03f62f18,0x55bd03f62f18,9 +alloc,0x55bd03f62f48,0x55bd03f62f48,15 +alloc,0x55bd03f62f78,0x55bd03f62f78,9 +alloc,0x55bd03f62fa8,0x55bd03f62fa8,9 +alloc,0x55bd03f62fd8,0x55bd03f62fd8,15 +alloc,0x55bd03f63008,0x55bd03f63008,9 +alloc,0x55bd03f63038,0x55bd03f63038,9 +alloc,0x55bd03f63068,0x55bd03f63068,15 +alloc,0x55bd03f63098,0x55bd03f63098,9 +alloc,0x55bd03f630c8,0x55bd03f630c8,9 +alloc,0x55bd03f630f8,0x55bd03f630f8,15 +alloc,0x55bd03f63128,0x55bd03f63128,9 +alloc,0x55bd03f63158,0x55bd03f63158,9 +alloc,0x55bd03f63188,0x55bd03f63188,15 +alloc,0x55bd03f631b8,0x55bd03f631b8,9 +alloc,0x55bd03f631e8,0x55bd03f631e8,9 +alloc,0x55bd03f63218,0x55bd03f63218,15 +alloc,0x55bd03f63248,0x55bd03f63248,9 +alloc,0x55bd03f63278,0x55bd03f63278,9 +alloc,0x55bd03f632a8,0x55bd03f632a8,15 +alloc,0x55bd03f632d8,0x55bd03f632d8,9 +alloc,0x55bd03f63308,0x55bd03f63308,9 +alloc,0x55bd03f63338,0x55bd03f63338,15 +alloc,0x55bd03f63368,0x55bd03f63368,9 +alloc,0x55bd03f63398,0x55bd03f63398,9 +alloc,0x55bd03f633c8,0x55bd03f633c8,15 +alloc,0x55bd03f633f8,0x55bd03f633f8,9 +alloc,0x55bd03f63428,0x55bd03f63428,9 +alloc,0x55bd03f63458,0x55bd03f63458,15 +alloc,0x55bd03f63488,0x55bd03f63488,9 +alloc,0x55bd03f634b8,0x55bd03f634b8,9 +alloc,0x55bd03f634e8,0x55bd03f634e8,15 +alloc,0x55bd03f63518,0x55bd03f63518,9 +alloc,0x55bd03f63548,0x55bd03f63548,9 +alloc,0x55bd03f63578,0x55bd03f63578,15 +alloc,0x55bd03f635a8,0x55bd03f635a8,9 +alloc,0x55bd03f635d8,0x55bd03f635d8,9 +alloc,0x55bd03f63608,0x55bd03f63608,15 +alloc,0x55bd03f63638,0x55bd03f63638,9 +alloc,0x55bd03f63668,0x55bd03f63668,9 +alloc,0x55bd03f63698,0x55bd03f63698,15 +alloc,0x55bd03f636c8,0x55bd03f636c8,9 +alloc,0x55bd03f636f8,0x55bd03f636f8,9 +alloc,0x55bd03f63728,0x55bd03f63728,15 +alloc,0x55bd03f63758,0x55bd03f63758,9 +alloc,0x55bd03f63788,0x55bd03f63788,9 +alloc,0x55bd03f637b8,0x55bd03f637b8,15 +alloc,0x55bd03f637e8,0x55bd03f637e8,9 +alloc,0x55bd03f63878,0x55bd03f63878,40 +alloc,0x55bd03f638b8,0x55bd03f638b8,56 +alloc,0x55bd03f63908,0x55bd03f63908,400 +alloc,0x55bd03f63ab8,0x55bd03f63ab8,400 +alloc,0x55bd03f63c68,0x55bd03f63c68,400 +alloc,0x55bd03f63e18,0x55bd03f63e18,9 +alloc,0x55bd03f63e48,0x55bd03f63e48,15 +alloc,0x55bd03f63e78,0x55bd03f63e78,9 +alloc,0x55bd03f63ea8,0x55bd03f63ea8,9 +alloc,0x55bd03f63ed8,0x55bd03f63ed8,15 +alloc,0x55bd03f63f08,0x55bd03f63f08,9 +alloc,0x55bd03f63f38,0x55bd03f63f38,9 +alloc,0x55bd03f63f68,0x55bd03f63f68,15 +alloc,0x55bd03f63f98,0x55bd03f63f98,9 +alloc,0x55bd03f63fc8,0x55bd03f63fc8,9 +alloc,0x55bd03f63ff8,0x55bd03f63ff8,15 +alloc,0x55bd03f64028,0x55bd03f64028,9 +alloc,0x55bd03f64058,0x55bd03f64058,9 +alloc,0x55bd03f64088,0x55bd03f64088,15 +alloc,0x55bd03f640b8,0x55bd03f640b8,9 +alloc,0x55bd03f640e8,0x55bd03f640e8,9 +alloc,0x55bd03f64118,0x55bd03f64118,15 +alloc,0x55bd03f64148,0x55bd03f64148,9 +alloc,0x55bd03f64178,0x55bd03f64178,9 +alloc,0x55bd03f641a8,0x55bd03f641a8,15 +alloc,0x55bd03f641d8,0x55bd03f641d8,9 +alloc,0x55bd03f64208,0x55bd03f64208,9 +alloc,0x55bd03f64238,0x55bd03f64238,15 +alloc,0x55bd03f64268,0x55bd03f64268,9 +alloc,0x55bd03f64298,0x55bd03f64298,9 +alloc,0x55bd03f642c8,0x55bd03f642c8,15 +alloc,0x55bd03f642f8,0x55bd03f642f8,9 +alloc,0x55bd03f64328,0x55bd03f64328,9 +alloc,0x55bd03f64358,0x55bd03f64358,15 +alloc,0x55bd03f64388,0x55bd03f64388,9 +alloc,0x55bd03f643b8,0x55bd03f643b8,9 +alloc,0x55bd03f643e8,0x55bd03f643e8,15 +alloc,0x55bd03f64418,0x55bd03f64418,9 +alloc,0x55bd03f64448,0x55bd03f64448,9 +alloc,0x55bd03f64478,0x55bd03f64478,15 +alloc,0x55bd03f644a8,0x55bd03f644a8,9 +alloc,0x55bd03f644d8,0x55bd03f644d8,9 +alloc,0x55bd03f64508,0x55bd03f64508,15 +alloc,0x55bd03f64538,0x55bd03f64538,9 +alloc,0x55bd03f64568,0x55bd03f64568,9 +alloc,0x55bd03f64598,0x55bd03f64598,15 +alloc,0x55bd03f645c8,0x55bd03f645c8,9 +alloc,0x55bd03f645f8,0x55bd03f645f8,9 +alloc,0x55bd03f64628,0x55bd03f64628,15 +alloc,0x55bd03f64658,0x55bd03f64658,9 +alloc,0x55bd03f64688,0x55bd03f64688,9 +alloc,0x55bd03f646b8,0x55bd03f646b8,15 +alloc,0x55bd03f646e8,0x55bd03f646e8,9 +alloc,0x55bd03f64718,0x55bd03f64718,9 +alloc,0x55bd03f64748,0x55bd03f64748,15 +alloc,0x55bd03f64778,0x55bd03f64778,9 +alloc,0x55bd03f647a8,0x55bd03f647a8,9 +alloc,0x55bd03f647d8,0x55bd03f647d8,15 +alloc,0x55bd03f64808,0x55bd03f64808,9 +alloc,0x55bd03f64838,0x55bd03f64838,9 +alloc,0x55bd03f64868,0x55bd03f64868,15 +alloc,0x55bd03f64898,0x55bd03f64898,9 +alloc,0x55bd03f648c8,0x55bd03f648c8,9 +alloc,0x55bd03f648f8,0x55bd03f648f8,15 +alloc,0x55bd03f64928,0x55bd03f64928,9 +alloc,0x55bd03f64958,0x55bd03f64958,9 +alloc,0x55bd03f64988,0x55bd03f64988,15 +alloc,0x55bd03f649b8,0x55bd03f649b8,9 +dealloc,0x55bd03f63878,0x55bd03f63878,0 +dealloc,0x55bd03f626a8,0x55bd03f626a8,0 +dealloc,0x55bd03f62648,0x55bd03f62648,0 +alloc,0x55bd03f649e8,0x55bd03f649e8,368 +alloc,0x55bd03f64b78,0x55bd03f64b78,200 +alloc,0x55bd03f64c58,0x55bd03f64c58,200 +alloc,0x55bd03f625a8,0x55bd03f625a8,168 +alloc,0x55bd03f64d38,0x55bd03f64d38,280 +alloc,0x55bd03f64e68,0x55bd03f64e68,584 +alloc,0x55bd03f650c8,0x55bd03f650c8,216 +alloc,0x55bd03f651b8,0x55bd03f651b8,920 +alloc,0x55bd03f65568,0x55bd03f65568,520 +alloc,0x55bd03f65788,0x55bd03f65788,568 +dealloc,0x55bd03f64b78,0x55bd03f64b78,0 +dealloc,0x55bd03f64c58,0x55bd03f64c58,0 +dealloc,0x55bd03f625a8,0x55bd03f625a8,0 +dealloc,0x55bd03f64d38,0x55bd03f64d38,0 +dealloc,0x55bd03f64e68,0x55bd03f64e68,0 +dealloc,0x55bd03f650c8,0x55bd03f650c8,0 +dealloc,0x55bd03f651b8,0x55bd03f651b8,0 +dealloc,0x55bd03f65568,0x55bd03f65568,0 +dealloc,0x55bd03f65788,0x55bd03f65788,0 +dealloc,0x55bd03f649e8,0x55bd03f649e8,0 +alloc,0x55bd03f626a8,0x55bd03f626a8,24 +alloc,0x55bd03f63878,0x55bd03f63878,24 +alloc,0x55bd03f625a8,0x55bd03f625a8,40 +alloc,0x55bd03f625e8,0x55bd03f625e8,56 +alloc,0x55bd03f64d68,0x55bd03f64d68,1352 +alloc,0x55bd03f652c8,0x55bd03f652c8,1352 +alloc,0x55bd03f65828,0x55bd03f65828,1352 +alloc,0x55bd03f62638,0x55bd03f62638,10 +realloc,0x55bd03f62638,0x55bd03f62638,12 +alloc,0x55bd03f65d88,0x55bd03f65d88,24 +alloc,0x55bd03f65db8,0x55bd03f65db8,10 +alloc,0x55bd03f65de8,0x55bd03f65de8,10 +realloc,0x55bd03f65de8,0x55bd03f65de8,12 +alloc,0x55bd03f65e18,0x55bd03f65e18,24 +alloc,0x55bd03f65e48,0x55bd03f65e48,10 +alloc,0x55bd03f65e78,0x55bd03f65e78,10 +realloc,0x55bd03f65e78,0x55bd03f65e78,12 +alloc,0x55bd03f65ea8,0x55bd03f65ea8,24 +alloc,0x55bd03f65ed8,0x55bd03f65ed8,10 +alloc,0x55bd03f65f08,0x55bd03f65f08,10 +realloc,0x55bd03f65f08,0x55bd03f65f08,12 +alloc,0x55bd03f65f38,0x55bd03f65f38,24 +alloc,0x55bd03f65f68,0x55bd03f65f68,10 +alloc,0x55bd03f65f98,0x55bd03f65f98,10 +realloc,0x55bd03f65f98,0x55bd03f65f98,12 +alloc,0x55bd03f65fc8,0x55bd03f65fc8,24 +alloc,0x55bd03f65ff8,0x55bd03f65ff8,10 +alloc,0x55bd03f66028,0x55bd03f66028,10 +realloc,0x55bd03f66028,0x55bd03f66028,12 +alloc,0x55bd03f66058,0x55bd03f66058,24 +alloc,0x55bd03f66088,0x55bd03f66088,10 +alloc,0x55bd03f660b8,0x55bd03f660b8,10 +realloc,0x55bd03f660b8,0x55bd03f660b8,12 +alloc,0x55bd03f660e8,0x55bd03f660e8,24 +alloc,0x55bd03f66118,0x55bd03f66118,10 +alloc,0x55bd03f66148,0x55bd03f66148,10 +realloc,0x55bd03f66148,0x55bd03f66148,12 +alloc,0x55bd03f66178,0x55bd03f66178,24 +alloc,0x55bd03f661a8,0x55bd03f661a8,10 +alloc,0x55bd03f661d8,0x55bd03f661d8,10 +realloc,0x55bd03f661d8,0x55bd03f661d8,12 +alloc,0x55bd03f66208,0x55bd03f66208,24 +alloc,0x55bd03f66238,0x55bd03f66238,10 +alloc,0x55bd03f66268,0x55bd03f66268,10 +realloc,0x55bd03f66268,0x55bd03f66268,12 +alloc,0x55bd03f66298,0x55bd03f66298,24 +alloc,0x55bd03f662c8,0x55bd03f662c8,10 +alloc,0x55bd03f662f8,0x55bd03f662f8,10 +realloc,0x55bd03f662f8,0x55bd03f662f8,12 +alloc,0x55bd03f66328,0x55bd03f66328,24 +alloc,0x55bd03f66358,0x55bd03f66358,10 +alloc,0x55bd03f66388,0x55bd03f66388,10 +realloc,0x55bd03f66388,0x55bd03f66388,12 +alloc,0x55bd03f663b8,0x55bd03f663b8,24 +alloc,0x55bd03f663e8,0x55bd03f663e8,10 +alloc,0x55bd03f66418,0x55bd03f66418,10 +realloc,0x55bd03f66418,0x55bd03f66418,12 +alloc,0x55bd03f66448,0x55bd03f66448,24 +alloc,0x55bd03f66478,0x55bd03f66478,10 +alloc,0x55bd03f664a8,0x55bd03f664a8,10 +realloc,0x55bd03f664a8,0x55bd03f664a8,12 +alloc,0x55bd03f664d8,0x55bd03f664d8,24 +alloc,0x55bd03f66508,0x55bd03f66508,10 +alloc,0x55bd03f66538,0x55bd03f66538,10 +realloc,0x55bd03f66538,0x55bd03f66538,12 +alloc,0x55bd03f66568,0x55bd03f66568,24 +alloc,0x55bd03f66598,0x55bd03f66598,10 +alloc,0x55bd03f665c8,0x55bd03f665c8,10 +realloc,0x55bd03f665c8,0x55bd03f665c8,12 +alloc,0x55bd03f665f8,0x55bd03f665f8,24 +alloc,0x55bd03f66628,0x55bd03f66628,10 +alloc,0x55bd03f66658,0x55bd03f66658,10 +realloc,0x55bd03f66658,0x55bd03f66658,12 +alloc,0x55bd03f66688,0x55bd03f66688,24 +alloc,0x55bd03f666b8,0x55bd03f666b8,10 +alloc,0x55bd03f666e8,0x55bd03f666e8,10 +realloc,0x55bd03f666e8,0x55bd03f666e8,12 +alloc,0x55bd03f66718,0x55bd03f66718,24 +alloc,0x55bd03f66748,0x55bd03f66748,10 +alloc,0x55bd03f66778,0x55bd03f66778,10 +realloc,0x55bd03f66778,0x55bd03f66778,12 +alloc,0x55bd03f667a8,0x55bd03f667a8,24 +alloc,0x55bd03f667d8,0x55bd03f667d8,10 +alloc,0x55bd03f66808,0x55bd03f66808,10 +realloc,0x55bd03f66808,0x55bd03f66808,12 +alloc,0x55bd03f66838,0x55bd03f66838,24 +alloc,0x55bd03f66868,0x55bd03f66868,10 +alloc,0x55bd03f66898,0x55bd03f66898,10 +realloc,0x55bd03f66898,0x55bd03f66898,12 +alloc,0x55bd03f668c8,0x55bd03f668c8,24 +alloc,0x55bd03f668f8,0x55bd03f668f8,10 +alloc,0x55bd03f66928,0x55bd03f66928,10 +realloc,0x55bd03f66928,0x55bd03f66928,12 +alloc,0x55bd03f66958,0x55bd03f66958,24 +alloc,0x55bd03f66988,0x55bd03f66988,10 +alloc,0x55bd03f669b8,0x55bd03f669b8,10 +realloc,0x55bd03f669b8,0x55bd03f669b8,12 +alloc,0x55bd03f669e8,0x55bd03f669e8,24 +alloc,0x55bd03f66a18,0x55bd03f66a18,10 +alloc,0x55bd03f66a48,0x55bd03f66a48,10 +realloc,0x55bd03f66a48,0x55bd03f66a48,12 +alloc,0x55bd03f66a78,0x55bd03f66a78,24 +alloc,0x55bd03f66aa8,0x55bd03f66aa8,10 +alloc,0x55bd03f66ad8,0x55bd03f66ad8,10 +realloc,0x55bd03f66ad8,0x55bd03f66ad8,12 +alloc,0x55bd03f66b08,0x55bd03f66b08,24 +alloc,0x55bd03f66b38,0x55bd03f66b38,10 +alloc,0x55bd03f66b68,0x55bd03f66b68,10 +realloc,0x55bd03f66b68,0x55bd03f66b68,12 +alloc,0x55bd03f66b98,0x55bd03f66b98,24 +alloc,0x55bd03f66bc8,0x55bd03f66bc8,10 +alloc,0x55bd03f66bf8,0x55bd03f66bf8,10 +realloc,0x55bd03f66bf8,0x55bd03f66bf8,12 +alloc,0x55bd03f66c28,0x55bd03f66c28,24 +alloc,0x55bd03f66c58,0x55bd03f66c58,10 +alloc,0x55bd03f66c88,0x55bd03f66c88,10 +realloc,0x55bd03f66c88,0x55bd03f66c88,12 +alloc,0x55bd03f66cb8,0x55bd03f66cb8,24 +alloc,0x55bd03f66ce8,0x55bd03f66ce8,10 +alloc,0x55bd03f66d18,0x55bd03f66d18,10 +realloc,0x55bd03f66d18,0x55bd03f66d18,12 +alloc,0x55bd03f66d48,0x55bd03f66d48,24 +alloc,0x55bd03f66d78,0x55bd03f66d78,10 +alloc,0x55bd03f66da8,0x55bd03f66da8,10 +realloc,0x55bd03f66da8,0x55bd03f66da8,12 +alloc,0x55bd03f66dd8,0x55bd03f66dd8,24 +alloc,0x55bd03f66e08,0x55bd03f66e08,10 +alloc,0x55bd03f66e38,0x55bd03f66e38,10 +realloc,0x55bd03f66e38,0x55bd03f66e38,12 +alloc,0x55bd03f66e68,0x55bd03f66e68,24 +alloc,0x55bd03f66e98,0x55bd03f66e98,10 +alloc,0x55bd03f66ec8,0x55bd03f66ec8,10 +realloc,0x55bd03f66ec8,0x55bd03f66ec8,12 +alloc,0x55bd03f66ef8,0x55bd03f66ef8,24 +alloc,0x55bd03f66f28,0x55bd03f66f28,10 +alloc,0x55bd03f66f58,0x55bd03f66f58,10 +realloc,0x55bd03f66f58,0x55bd03f66f58,12 +alloc,0x55bd03f66f88,0x55bd03f66f88,24 +alloc,0x55bd03f66fb8,0x55bd03f66fb8,10 +alloc,0x55bd03f66fe8,0x55bd03f66fe8,10 +realloc,0x55bd03f66fe8,0x55bd03f66fe8,12 +alloc,0x55bd03f67018,0x55bd03f67018,24 +alloc,0x55bd03f67048,0x55bd03f67048,10 +alloc,0x55bd03f67078,0x55bd03f67078,10 +realloc,0x55bd03f67078,0x55bd03f67078,12 +alloc,0x55bd03f670a8,0x55bd03f670a8,24 +alloc,0x55bd03f670d8,0x55bd03f670d8,10 +alloc,0x55bd03f67108,0x55bd03f67108,10 +realloc,0x55bd03f67108,0x55bd03f67108,12 +alloc,0x55bd03f67138,0x55bd03f67138,24 +alloc,0x55bd03f67168,0x55bd03f67168,10 +alloc,0x55bd03f67198,0x55bd03f67198,10 +realloc,0x55bd03f67198,0x55bd03f67198,12 +alloc,0x55bd03f671c8,0x55bd03f671c8,24 +alloc,0x55bd03f671f8,0x55bd03f671f8,10 +alloc,0x55bd03f67228,0x55bd03f67228,10 +realloc,0x55bd03f67228,0x55bd03f67228,12 +alloc,0x55bd03f67258,0x55bd03f67258,24 +alloc,0x55bd03f67288,0x55bd03f67288,10 +alloc,0x55bd03f672b8,0x55bd03f672b8,10 +realloc,0x55bd03f672b8,0x55bd03f672b8,12 +alloc,0x55bd03f672e8,0x55bd03f672e8,24 +alloc,0x55bd03f67318,0x55bd03f67318,10 +alloc,0x55bd03f67348,0x55bd03f67348,10 +realloc,0x55bd03f67348,0x55bd03f67348,12 +alloc,0x55bd03f67378,0x55bd03f67378,24 +alloc,0x55bd03f673a8,0x55bd03f673a8,10 +alloc,0x55bd03f673d8,0x55bd03f673d8,10 +realloc,0x55bd03f673d8,0x55bd03f673d8,12 +alloc,0x55bd03f67408,0x55bd03f67408,24 +alloc,0x55bd03f67438,0x55bd03f67438,10 +alloc,0x55bd03f67468,0x55bd03f67468,10 +realloc,0x55bd03f67468,0x55bd03f67468,12 +alloc,0x55bd03f67498,0x55bd03f67498,24 +alloc,0x55bd03f674c8,0x55bd03f674c8,10 +alloc,0x55bd03f674f8,0x55bd03f674f8,10 +realloc,0x55bd03f674f8,0x55bd03f674f8,12 +alloc,0x55bd03f67528,0x55bd03f67528,24 +alloc,0x55bd03f67558,0x55bd03f67558,10 +alloc,0x55bd03f67588,0x55bd03f67588,10 +realloc,0x55bd03f67588,0x55bd03f67588,12 +alloc,0x55bd03f675b8,0x55bd03f675b8,24 +alloc,0x55bd03f675e8,0x55bd03f675e8,10 +alloc,0x55bd03f67618,0x55bd03f67618,10 +realloc,0x55bd03f67618,0x55bd03f67618,12 +alloc,0x55bd03f67648,0x55bd03f67648,24 +alloc,0x55bd03f67678,0x55bd03f67678,10 +alloc,0x55bd03f676a8,0x55bd03f676a8,10 +realloc,0x55bd03f676a8,0x55bd03f676a8,12 +alloc,0x55bd03f676d8,0x55bd03f676d8,24 +alloc,0x55bd03f67708,0x55bd03f67708,10 +alloc,0x55bd03f67738,0x55bd03f67738,10 +realloc,0x55bd03f67738,0x55bd03f67738,12 +alloc,0x55bd03f67768,0x55bd03f67768,24 +alloc,0x55bd03f67798,0x55bd03f67798,10 +alloc,0x55bd03f677c8,0x55bd03f677c8,10 +realloc,0x55bd03f677c8,0x55bd03f677c8,12 +alloc,0x55bd03f677f8,0x55bd03f677f8,24 +alloc,0x55bd03f67828,0x55bd03f67828,10 +alloc,0x55bd03f67858,0x55bd03f67858,10 +realloc,0x55bd03f67858,0x55bd03f67858,12 +alloc,0x55bd03f67888,0x55bd03f67888,24 +alloc,0x55bd03f678b8,0x55bd03f678b8,10 +alloc,0x55bd03f678e8,0x55bd03f678e8,10 +realloc,0x55bd03f678e8,0x55bd03f678e8,12 +alloc,0x55bd03f67918,0x55bd03f67918,24 +alloc,0x55bd03f67948,0x55bd03f67948,10 +alloc,0x55bd03f67978,0x55bd03f67978,10 +realloc,0x55bd03f67978,0x55bd03f67978,12 +alloc,0x55bd03f679a8,0x55bd03f679a8,24 +alloc,0x55bd03f679d8,0x55bd03f679d8,10 +alloc,0x55bd03f67a08,0x55bd03f67a08,10 +realloc,0x55bd03f67a08,0x55bd03f67a08,12 +alloc,0x55bd03f67a38,0x55bd03f67a38,24 +alloc,0x55bd03f67a68,0x55bd03f67a68,10 +alloc,0x55bd03f67a98,0x55bd03f67a98,10 +realloc,0x55bd03f67a98,0x55bd03f67a98,12 +alloc,0x55bd03f67ac8,0x55bd03f67ac8,24 +alloc,0x55bd03f67af8,0x55bd03f67af8,10 +alloc,0x55bd03f67b28,0x55bd03f67b28,10 +realloc,0x55bd03f67b28,0x55bd03f67b28,12 +alloc,0x55bd03f67b58,0x55bd03f67b58,24 +alloc,0x55bd03f67b88,0x55bd03f67b88,10 +alloc,0x55bd03f67bb8,0x55bd03f67bb8,10 +realloc,0x55bd03f67bb8,0x55bd03f67bb8,12 +alloc,0x55bd03f67be8,0x55bd03f67be8,24 +alloc,0x55bd03f67c18,0x55bd03f67c18,10 +alloc,0x55bd03f67c48,0x55bd03f67c48,10 +realloc,0x55bd03f67c48,0x55bd03f67c48,12 +alloc,0x55bd03f67c78,0x55bd03f67c78,24 +alloc,0x55bd03f67ca8,0x55bd03f67ca8,10 +alloc,0x55bd03f67cd8,0x55bd03f67cd8,10 +realloc,0x55bd03f67cd8,0x55bd03f67cd8,12 +alloc,0x55bd03f67d08,0x55bd03f67d08,24 +alloc,0x55bd03f67d38,0x55bd03f67d38,10 +alloc,0x55bd03f67d68,0x55bd03f67d68,10 +realloc,0x55bd03f67d68,0x55bd03f67d68,12 +alloc,0x55bd03f67d98,0x55bd03f67d98,24 +alloc,0x55bd03f67dc8,0x55bd03f67dc8,10 +alloc,0x55bd03f67df8,0x55bd03f67df8,10 +realloc,0x55bd03f67df8,0x55bd03f67df8,12 +alloc,0x55bd03f67e28,0x55bd03f67e28,24 +alloc,0x55bd03f67e58,0x55bd03f67e58,10 +alloc,0x55bd03f67e88,0x55bd03f67e88,10 +realloc,0x55bd03f67e88,0x55bd03f67e88,12 +alloc,0x55bd03f67eb8,0x55bd03f67eb8,24 +alloc,0x55bd03f67ee8,0x55bd03f67ee8,10 +alloc,0x55bd03f67f18,0x55bd03f67f18,10 +realloc,0x55bd03f67f18,0x55bd03f67f18,12 +alloc,0x55bd03f67f48,0x55bd03f67f48,24 +alloc,0x55bd03f67f78,0x55bd03f67f78,10 +alloc,0x55bd03f67fa8,0x55bd03f67fa8,10 +realloc,0x55bd03f67fa8,0x55bd03f67fa8,12 +alloc,0x55bd03f67fd8,0x55bd03f67fd8,24 +alloc,0x55bd03f68008,0x55bd03f68008,10 +alloc,0x55bd03f68038,0x55bd03f68038,10 +realloc,0x55bd03f68038,0x55bd03f68038,12 +alloc,0x55bd03f68068,0x55bd03f68068,24 +alloc,0x55bd03f68098,0x55bd03f68098,10 +alloc,0x55bd03f680c8,0x55bd03f680c8,10 +realloc,0x55bd03f680c8,0x55bd03f680c8,12 +alloc,0x55bd03f680f8,0x55bd03f680f8,24 +alloc,0x55bd03f68128,0x55bd03f68128,10 +alloc,0x55bd03f68158,0x55bd03f68158,10 +realloc,0x55bd03f68158,0x55bd03f68158,12 +alloc,0x55bd03f68188,0x55bd03f68188,24 +alloc,0x55bd03f681b8,0x55bd03f681b8,10 +alloc,0x55bd03f681e8,0x55bd03f681e8,10 +realloc,0x55bd03f681e8,0x55bd03f681e8,12 +alloc,0x55bd03f68218,0x55bd03f68218,24 +alloc,0x55bd03f68248,0x55bd03f68248,10 +alloc,0x55bd03f68278,0x55bd03f68278,10 +realloc,0x55bd03f68278,0x55bd03f68278,12 +alloc,0x55bd03f682a8,0x55bd03f682a8,24 +alloc,0x55bd03f682d8,0x55bd03f682d8,10 +alloc,0x55bd03f68308,0x55bd03f68308,10 +realloc,0x55bd03f68308,0x55bd03f68308,12 +alloc,0x55bd03f68338,0x55bd03f68338,24 +alloc,0x55bd03f68368,0x55bd03f68368,10 +alloc,0x55bd03f68398,0x55bd03f68398,10 +realloc,0x55bd03f68398,0x55bd03f68398,12 +alloc,0x55bd03f683c8,0x55bd03f683c8,24 +alloc,0x55bd03f683f8,0x55bd03f683f8,10 +alloc,0x55bd03f68428,0x55bd03f68428,10 +realloc,0x55bd03f68428,0x55bd03f68428,12 +alloc,0x55bd03f68458,0x55bd03f68458,24 +alloc,0x55bd03f68488,0x55bd03f68488,10 +alloc,0x55bd03f684b8,0x55bd03f684b8,10 +realloc,0x55bd03f684b8,0x55bd03f684b8,12 +alloc,0x55bd03f684e8,0x55bd03f684e8,24 +alloc,0x55bd03f68518,0x55bd03f68518,10 +alloc,0x55bd03f68548,0x55bd03f68548,10 +realloc,0x55bd03f68548,0x55bd03f68548,12 +alloc,0x55bd03f68578,0x55bd03f68578,24 +alloc,0x55bd03f685a8,0x55bd03f685a8,10 +alloc,0x55bd03f68638,0x55bd03f68638,40 +alloc,0x55bd03f68678,0x55bd03f68678,56 +alloc,0x55bd03f686c8,0x55bd03f686c8,1352 +alloc,0x55bd03f68c28,0x55bd03f68c28,1352 +alloc,0x55bd03f69188,0x55bd03f69188,1352 +alloc,0x55bd03f696e8,0x55bd03f696e8,10 +realloc,0x55bd03f696e8,0x55bd03f696e8,12 +alloc,0x55bd03f69718,0x55bd03f69718,24 +alloc,0x55bd03f69748,0x55bd03f69748,10 +alloc,0x55bd03f69778,0x55bd03f69778,10 +realloc,0x55bd03f69778,0x55bd03f69778,12 +alloc,0x55bd03f697a8,0x55bd03f697a8,24 +alloc,0x55bd03f697d8,0x55bd03f697d8,10 +alloc,0x55bd03f69808,0x55bd03f69808,10 +realloc,0x55bd03f69808,0x55bd03f69808,12 +alloc,0x55bd03f69838,0x55bd03f69838,24 +alloc,0x55bd03f69868,0x55bd03f69868,10 +alloc,0x55bd03f69898,0x55bd03f69898,10 +realloc,0x55bd03f69898,0x55bd03f69898,12 +alloc,0x55bd03f698c8,0x55bd03f698c8,24 +alloc,0x55bd03f698f8,0x55bd03f698f8,10 +alloc,0x55bd03f69928,0x55bd03f69928,10 +realloc,0x55bd03f69928,0x55bd03f69928,12 +alloc,0x55bd03f69958,0x55bd03f69958,24 +alloc,0x55bd03f69988,0x55bd03f69988,10 +alloc,0x55bd03f699b8,0x55bd03f699b8,10 +realloc,0x55bd03f699b8,0x55bd03f699b8,12 +alloc,0x55bd03f699e8,0x55bd03f699e8,24 +alloc,0x55bd03f69a18,0x55bd03f69a18,10 +alloc,0x55bd03f69a48,0x55bd03f69a48,10 +realloc,0x55bd03f69a48,0x55bd03f69a48,12 +alloc,0x55bd03f69a78,0x55bd03f69a78,24 +alloc,0x55bd03f69aa8,0x55bd03f69aa8,10 +alloc,0x55bd03f69ad8,0x55bd03f69ad8,10 +realloc,0x55bd03f69ad8,0x55bd03f69ad8,12 +alloc,0x55bd03f69b08,0x55bd03f69b08,24 +alloc,0x55bd03f69b38,0x55bd03f69b38,10 +alloc,0x55bd03f69b68,0x55bd03f69b68,10 +realloc,0x55bd03f69b68,0x55bd03f69b68,12 +alloc,0x55bd03f69b98,0x55bd03f69b98,24 +alloc,0x55bd03f69bc8,0x55bd03f69bc8,10 +alloc,0x55bd03f69bf8,0x55bd03f69bf8,10 +realloc,0x55bd03f69bf8,0x55bd03f69bf8,12 +alloc,0x55bd03f69c28,0x55bd03f69c28,24 +alloc,0x55bd03f69c58,0x55bd03f69c58,10 +alloc,0x55bd03f69c88,0x55bd03f69c88,10 +realloc,0x55bd03f69c88,0x55bd03f69c88,12 +alloc,0x55bd03f69cb8,0x55bd03f69cb8,24 +alloc,0x55bd03f69ce8,0x55bd03f69ce8,10 +alloc,0x55bd03f69d18,0x55bd03f69d18,10 +realloc,0x55bd03f69d18,0x55bd03f69d18,12 +alloc,0x55bd03f69d48,0x55bd03f69d48,24 +alloc,0x55bd03f69d78,0x55bd03f69d78,10 +alloc,0x55bd03f69da8,0x55bd03f69da8,10 +realloc,0x55bd03f69da8,0x55bd03f69da8,12 +alloc,0x55bd03f69dd8,0x55bd03f69dd8,24 +alloc,0x55bd03f69e08,0x55bd03f69e08,10 +alloc,0x55bd03f69e38,0x55bd03f69e38,10 +realloc,0x55bd03f69e38,0x55bd03f69e38,12 +alloc,0x55bd03f69e68,0x55bd03f69e68,24 +alloc,0x55bd03f69e98,0x55bd03f69e98,10 +alloc,0x55bd03f69ec8,0x55bd03f69ec8,10 +realloc,0x55bd03f69ec8,0x55bd03f69ec8,12 +alloc,0x55bd03f69ef8,0x55bd03f69ef8,24 +alloc,0x55bd03f69f28,0x55bd03f69f28,10 +alloc,0x55bd03f69f58,0x55bd03f69f58,10 +realloc,0x55bd03f69f58,0x55bd03f69f58,12 +alloc,0x55bd03f69f88,0x55bd03f69f88,24 +alloc,0x55bd03f69fb8,0x55bd03f69fb8,10 +alloc,0x55bd03f69fe8,0x55bd03f69fe8,10 +realloc,0x55bd03f69fe8,0x55bd03f69fe8,12 +alloc,0x55bd03f6a018,0x55bd03f6a018,24 +alloc,0x55bd03f6a048,0x55bd03f6a048,10 +alloc,0x55bd03f6a078,0x55bd03f6a078,10 +realloc,0x55bd03f6a078,0x55bd03f6a078,12 +alloc,0x55bd03f6a0a8,0x55bd03f6a0a8,24 +alloc,0x55bd03f6a0d8,0x55bd03f6a0d8,10 +alloc,0x55bd03f6a108,0x55bd03f6a108,10 +realloc,0x55bd03f6a108,0x55bd03f6a108,12 +alloc,0x55bd03f6a138,0x55bd03f6a138,24 +alloc,0x55bd03f6a168,0x55bd03f6a168,10 +alloc,0x55bd03f6a198,0x55bd03f6a198,10 +realloc,0x55bd03f6a198,0x55bd03f6a198,12 +alloc,0x55bd03f6a1c8,0x55bd03f6a1c8,24 +alloc,0x55bd03f6a1f8,0x55bd03f6a1f8,10 +alloc,0x55bd03f6a228,0x55bd03f6a228,10 +realloc,0x55bd03f6a228,0x55bd03f6a228,12 +alloc,0x55bd03f6a258,0x55bd03f6a258,24 +alloc,0x55bd03f6a288,0x55bd03f6a288,10 +alloc,0x55bd03f6a2b8,0x55bd03f6a2b8,10 +realloc,0x55bd03f6a2b8,0x55bd03f6a2b8,12 +alloc,0x55bd03f6a2e8,0x55bd03f6a2e8,24 +alloc,0x55bd03f6a318,0x55bd03f6a318,10 +alloc,0x55bd03f6a348,0x55bd03f6a348,10 +realloc,0x55bd03f6a348,0x55bd03f6a348,12 +alloc,0x55bd03f6a378,0x55bd03f6a378,24 +alloc,0x55bd03f6a3a8,0x55bd03f6a3a8,10 +alloc,0x55bd03f6a3d8,0x55bd03f6a3d8,10 +realloc,0x55bd03f6a3d8,0x55bd03f6a3d8,12 +alloc,0x55bd03f6a408,0x55bd03f6a408,24 +alloc,0x55bd03f6a438,0x55bd03f6a438,10 +alloc,0x55bd03f6a468,0x55bd03f6a468,10 +realloc,0x55bd03f6a468,0x55bd03f6a468,12 +alloc,0x55bd03f6a498,0x55bd03f6a498,24 +alloc,0x55bd03f6a4c8,0x55bd03f6a4c8,10 +alloc,0x55bd03f6a4f8,0x55bd03f6a4f8,10 +realloc,0x55bd03f6a4f8,0x55bd03f6a4f8,12 +alloc,0x55bd03f6a528,0x55bd03f6a528,24 +alloc,0x55bd03f6a558,0x55bd03f6a558,10 +alloc,0x55bd03f6a588,0x55bd03f6a588,10 +realloc,0x55bd03f6a588,0x55bd03f6a588,12 +alloc,0x55bd03f6a5b8,0x55bd03f6a5b8,24 +alloc,0x55bd03f6a5e8,0x55bd03f6a5e8,10 +alloc,0x55bd03f6a618,0x55bd03f6a618,10 +realloc,0x55bd03f6a618,0x55bd03f6a618,12 +alloc,0x55bd03f6a648,0x55bd03f6a648,24 +alloc,0x55bd03f6a678,0x55bd03f6a678,10 +alloc,0x55bd03f6a6a8,0x55bd03f6a6a8,10 +realloc,0x55bd03f6a6a8,0x55bd03f6a6a8,12 +alloc,0x55bd03f6a6d8,0x55bd03f6a6d8,24 +alloc,0x55bd03f6a708,0x55bd03f6a708,10 +alloc,0x55bd03f6a738,0x55bd03f6a738,10 +realloc,0x55bd03f6a738,0x55bd03f6a738,12 +alloc,0x55bd03f6a768,0x55bd03f6a768,24 +alloc,0x55bd03f6a798,0x55bd03f6a798,10 +alloc,0x55bd03f6a7c8,0x55bd03f6a7c8,10 +realloc,0x55bd03f6a7c8,0x55bd03f6a7c8,12 +alloc,0x55bd03f6a7f8,0x55bd03f6a7f8,24 +alloc,0x55bd03f6a828,0x55bd03f6a828,10 +alloc,0x55bd03f6a858,0x55bd03f6a858,10 +realloc,0x55bd03f6a858,0x55bd03f6a858,12 +alloc,0x55bd03f6a888,0x55bd03f6a888,24 +alloc,0x55bd03f6a8b8,0x55bd03f6a8b8,10 +alloc,0x55bd03f6a8e8,0x55bd03f6a8e8,10 +realloc,0x55bd03f6a8e8,0x55bd03f6a8e8,12 +alloc,0x55bd03f6a918,0x55bd03f6a918,24 +alloc,0x55bd03f6a948,0x55bd03f6a948,10 +alloc,0x55bd03f6a978,0x55bd03f6a978,10 +realloc,0x55bd03f6a978,0x55bd03f6a978,12 +alloc,0x55bd03f6a9a8,0x55bd03f6a9a8,24 +alloc,0x55bd03f6a9d8,0x55bd03f6a9d8,10 +alloc,0x55bd03f6aa08,0x55bd03f6aa08,10 +realloc,0x55bd03f6aa08,0x55bd03f6aa08,12 +alloc,0x55bd03f6aa38,0x55bd03f6aa38,24 +alloc,0x55bd03f6aa68,0x55bd03f6aa68,10 +alloc,0x55bd03f6aa98,0x55bd03f6aa98,10 +realloc,0x55bd03f6aa98,0x55bd03f6aa98,12 +alloc,0x55bd03f6aac8,0x55bd03f6aac8,24 +alloc,0x55bd03f6aaf8,0x55bd03f6aaf8,10 +alloc,0x55bd03f6ab28,0x55bd03f6ab28,10 +realloc,0x55bd03f6ab28,0x55bd03f6ab28,12 +alloc,0x55bd03f6ab58,0x55bd03f6ab58,24 +alloc,0x55bd03f6ab88,0x55bd03f6ab88,10 +alloc,0x55bd03f6abb8,0x55bd03f6abb8,10 +realloc,0x55bd03f6abb8,0x55bd03f6abb8,12 +alloc,0x55bd03f6abe8,0x55bd03f6abe8,24 +alloc,0x55bd03f6ac18,0x55bd03f6ac18,10 +alloc,0x55bd03f6ac48,0x55bd03f6ac48,10 +realloc,0x55bd03f6ac48,0x55bd03f6ac48,12 +alloc,0x55bd03f6ac78,0x55bd03f6ac78,24 +alloc,0x55bd03f6aca8,0x55bd03f6aca8,10 +alloc,0x55bd03f6acd8,0x55bd03f6acd8,10 +realloc,0x55bd03f6acd8,0x55bd03f6acd8,12 +alloc,0x55bd03f6ad08,0x55bd03f6ad08,24 +alloc,0x55bd03f6ad38,0x55bd03f6ad38,10 +alloc,0x55bd03f6ad68,0x55bd03f6ad68,10 +realloc,0x55bd03f6ad68,0x55bd03f6ad68,12 +alloc,0x55bd03f6ad98,0x55bd03f6ad98,24 +alloc,0x55bd03f6adc8,0x55bd03f6adc8,10 +alloc,0x55bd03f6adf8,0x55bd03f6adf8,10 +realloc,0x55bd03f6adf8,0x55bd03f6adf8,12 +alloc,0x55bd03f6ae28,0x55bd03f6ae28,24 +alloc,0x55bd03f6ae58,0x55bd03f6ae58,10 +alloc,0x55bd03f6ae88,0x55bd03f6ae88,10 +realloc,0x55bd03f6ae88,0x55bd03f6ae88,12 +alloc,0x55bd03f6aeb8,0x55bd03f6aeb8,24 +alloc,0x55bd03f6aee8,0x55bd03f6aee8,10 +alloc,0x55bd03f6af18,0x55bd03f6af18,10 +realloc,0x55bd03f6af18,0x55bd03f6af18,12 +alloc,0x55bd03f6af48,0x55bd03f6af48,24 +alloc,0x55bd03f6af78,0x55bd03f6af78,10 +alloc,0x55bd03f6afa8,0x55bd03f6afa8,10 +realloc,0x55bd03f6afa8,0x55bd03f6afa8,12 +alloc,0x55bd03f6afd8,0x55bd03f6afd8,24 +alloc,0x55bd03f6b008,0x55bd03f6b008,10 +alloc,0x55bd03f6b038,0x55bd03f6b038,10 +realloc,0x55bd03f6b038,0x55bd03f6b038,12 +alloc,0x55bd03f6b068,0x55bd03f6b068,24 +alloc,0x55bd03f6b098,0x55bd03f6b098,10 +alloc,0x55bd03f6b0c8,0x55bd03f6b0c8,10 +realloc,0x55bd03f6b0c8,0x55bd03f6b0c8,12 +alloc,0x55bd03f6b0f8,0x55bd03f6b0f8,24 +alloc,0x55bd03f6b128,0x55bd03f6b128,10 +alloc,0x55bd03f6b158,0x55bd03f6b158,10 +realloc,0x55bd03f6b158,0x55bd03f6b158,12 +alloc,0x55bd03f6b188,0x55bd03f6b188,24 +alloc,0x55bd03f6b1b8,0x55bd03f6b1b8,10 +alloc,0x55bd03f6b1e8,0x55bd03f6b1e8,10 +realloc,0x55bd03f6b1e8,0x55bd03f6b1e8,12 +alloc,0x55bd03f6b218,0x55bd03f6b218,24 +alloc,0x55bd03f6b248,0x55bd03f6b248,10 +alloc,0x55bd03f6b278,0x55bd03f6b278,10 +realloc,0x55bd03f6b278,0x55bd03f6b278,12 +alloc,0x55bd03f6b2a8,0x55bd03f6b2a8,24 +alloc,0x55bd03f6b2d8,0x55bd03f6b2d8,10 +alloc,0x55bd03f6b308,0x55bd03f6b308,10 +realloc,0x55bd03f6b308,0x55bd03f6b308,12 +alloc,0x55bd03f6b338,0x55bd03f6b338,24 +alloc,0x55bd03f6b368,0x55bd03f6b368,10 +alloc,0x55bd03f6b398,0x55bd03f6b398,10 +realloc,0x55bd03f6b398,0x55bd03f6b398,12 +alloc,0x55bd03f6b3c8,0x55bd03f6b3c8,24 +alloc,0x55bd03f6b3f8,0x55bd03f6b3f8,10 +alloc,0x55bd03f6b428,0x55bd03f6b428,10 +realloc,0x55bd03f6b428,0x55bd03f6b428,12 +alloc,0x55bd03f6b458,0x55bd03f6b458,24 +alloc,0x55bd03f6b488,0x55bd03f6b488,10 +alloc,0x55bd03f6b4b8,0x55bd03f6b4b8,10 +realloc,0x55bd03f6b4b8,0x55bd03f6b4b8,12 +alloc,0x55bd03f6b4e8,0x55bd03f6b4e8,24 +alloc,0x55bd03f6b518,0x55bd03f6b518,10 +alloc,0x55bd03f6b548,0x55bd03f6b548,10 +realloc,0x55bd03f6b548,0x55bd03f6b548,12 +alloc,0x55bd03f6b578,0x55bd03f6b578,24 +alloc,0x55bd03f6b5a8,0x55bd03f6b5a8,10 +alloc,0x55bd03f6b5d8,0x55bd03f6b5d8,10 +realloc,0x55bd03f6b5d8,0x55bd03f6b5d8,12 +alloc,0x55bd03f6b608,0x55bd03f6b608,24 +alloc,0x55bd03f6b638,0x55bd03f6b638,10 +alloc,0x55bd03f6b668,0x55bd03f6b668,10 +realloc,0x55bd03f6b668,0x55bd03f6b668,12 +alloc,0x55bd03f6b698,0x55bd03f6b698,24 +alloc,0x55bd03f6b6c8,0x55bd03f6b6c8,10 +alloc,0x55bd03f6b6f8,0x55bd03f6b6f8,10 +realloc,0x55bd03f6b6f8,0x55bd03f6b6f8,12 +alloc,0x55bd03f6b728,0x55bd03f6b728,24 +alloc,0x55bd03f6b758,0x55bd03f6b758,10 +alloc,0x55bd03f6b788,0x55bd03f6b788,10 +realloc,0x55bd03f6b788,0x55bd03f6b788,12 +alloc,0x55bd03f6b7b8,0x55bd03f6b7b8,24 +alloc,0x55bd03f6b7e8,0x55bd03f6b7e8,10 +alloc,0x55bd03f6b818,0x55bd03f6b818,10 +realloc,0x55bd03f6b818,0x55bd03f6b818,12 +alloc,0x55bd03f6b848,0x55bd03f6b848,24 +alloc,0x55bd03f6b878,0x55bd03f6b878,10 +alloc,0x55bd03f6b8a8,0x55bd03f6b8a8,10 +realloc,0x55bd03f6b8a8,0x55bd03f6b8a8,12 +alloc,0x55bd03f6b8d8,0x55bd03f6b8d8,24 +alloc,0x55bd03f6b908,0x55bd03f6b908,10 +alloc,0x55bd03f6b938,0x55bd03f6b938,10 +realloc,0x55bd03f6b938,0x55bd03f6b938,12 +alloc,0x55bd03f6b968,0x55bd03f6b968,24 +alloc,0x55bd03f6b998,0x55bd03f6b998,10 +alloc,0x55bd03f6b9c8,0x55bd03f6b9c8,10 +realloc,0x55bd03f6b9c8,0x55bd03f6b9c8,12 +alloc,0x55bd03f6b9f8,0x55bd03f6b9f8,24 +alloc,0x55bd03f6ba28,0x55bd03f6ba28,10 +alloc,0x55bd03f6ba58,0x55bd03f6ba58,10 +realloc,0x55bd03f6ba58,0x55bd03f6ba58,12 +alloc,0x55bd03f6ba88,0x55bd03f6ba88,24 +alloc,0x55bd03f6bab8,0x55bd03f6bab8,10 +alloc,0x55bd03f6bae8,0x55bd03f6bae8,10 +realloc,0x55bd03f6bae8,0x55bd03f6bae8,12 +alloc,0x55bd03f6bb18,0x55bd03f6bb18,24 +alloc,0x55bd03f6bb48,0x55bd03f6bb48,10 +alloc,0x55bd03f6bb78,0x55bd03f6bb78,10 +realloc,0x55bd03f6bb78,0x55bd03f6bb78,12 +alloc,0x55bd03f6bba8,0x55bd03f6bba8,24 +alloc,0x55bd03f6bbd8,0x55bd03f6bbd8,10 +alloc,0x55bd03f6bc08,0x55bd03f6bc08,10 +realloc,0x55bd03f6bc08,0x55bd03f6bc08,12 +alloc,0x55bd03f6bc38,0x55bd03f6bc38,24 +alloc,0x55bd03f6bc68,0x55bd03f6bc68,10 +alloc,0x55bd03f6bc98,0x55bd03f6bc98,10 +realloc,0x55bd03f6bc98,0x55bd03f6bc98,12 +alloc,0x55bd03f6bcc8,0x55bd03f6bcc8,24 +alloc,0x55bd03f6bcf8,0x55bd03f6bcf8,10 +alloc,0x55bd03f6bd28,0x55bd03f6bd28,10 +realloc,0x55bd03f6bd28,0x55bd03f6bd28,12 +alloc,0x55bd03f6bd58,0x55bd03f6bd58,24 +alloc,0x55bd03f6bd88,0x55bd03f6bd88,10 +alloc,0x55bd03f6bdb8,0x55bd03f6bdb8,10 +realloc,0x55bd03f6bdb8,0x55bd03f6bdb8,12 +alloc,0x55bd03f6bde8,0x55bd03f6bde8,24 +alloc,0x55bd03f6be18,0x55bd03f6be18,10 +alloc,0x55bd03f6be48,0x55bd03f6be48,10 +realloc,0x55bd03f6be48,0x55bd03f6be48,12 +alloc,0x55bd03f6be78,0x55bd03f6be78,24 +alloc,0x55bd03f6bea8,0x55bd03f6bea8,10 +alloc,0x55bd03f6bed8,0x55bd03f6bed8,10 +realloc,0x55bd03f6bed8,0x55bd03f6bed8,12 +alloc,0x55bd03f6bf08,0x55bd03f6bf08,24 +alloc,0x55bd03f6bf38,0x55bd03f6bf38,10 +dealloc,0x55bd03f68638,0x55bd03f68638,0 +dealloc,0x55bd03f625a8,0x55bd03f625a8,0 +dealloc,0x55bd03f626a8,0x55bd03f626a8,0 +alloc,0x55bd03f649e8,0x55bd03f649e8,368 +alloc,0x55bd03f64b78,0x55bd03f64b78,200 +alloc,0x55bd03f64c58,0x55bd03f64c58,200 +alloc,0x55bd03f6bf68,0x55bd03f6bf68,168 +alloc,0x55bd03f6c028,0x55bd03f6c028,280 +alloc,0x55bd03f6c158,0x55bd03f6c158,584 +alloc,0x55bd03f6c3b8,0x55bd03f6c3b8,216 +alloc,0x55bd03f6c4a8,0x55bd03f6c4a8,920 +alloc,0x55bd03f6c858,0x55bd03f6c858,520 +alloc,0x55bd03f6ca78,0x55bd03f6ca78,568 +dealloc,0x55bd03f64b78,0x55bd03f64b78,0 +dealloc,0x55bd03f64c58,0x55bd03f64c58,0 +dealloc,0x55bd03f6bf68,0x55bd03f6bf68,0 +dealloc,0x55bd03f6c028,0x55bd03f6c028,0 +dealloc,0x55bd03f6c158,0x55bd03f6c158,0 +dealloc,0x55bd03f6c3b8,0x55bd03f6c3b8,0 +dealloc,0x55bd03f6c4a8,0x55bd03f6c4a8,0 +dealloc,0x55bd03f6c858,0x55bd03f6c858,0 +dealloc,0x55bd03f6ca78,0x55bd03f6ca78,0 +dealloc,0x55bd03f649e8,0x55bd03f649e8,0 +alloc,0x55bd03f626a8,0x55bd03f626a8,16 +alloc,0x55bd03f649e8,0x55bd03f649e8,368 +alloc,0x55bd03f64b78,0x55bd03f64b78,200 +alloc,0x55bd03f64c58,0x55bd03f64c58,200 +alloc,0x55bd03f6cfa8,0x55bd03f6cfa8,168 +alloc,0x55bd03f6d068,0x55bd03f6d068,280 +alloc,0x55bd03f6d198,0x55bd03f6d198,584 +alloc,0x55bd03f6d3f8,0x55bd03f6d3f8,216 +alloc,0x55bd03f6d4e8,0x55bd03f6d4e8,920 +alloc,0x55bd03f6d898,0x55bd03f6d898,520 +alloc,0x55bd03f6dab8,0x55bd03f6dab8,568 +dealloc,0x55bd03f64b78,0x55bd03f64b78,0 +dealloc,0x55bd03f64c58,0x55bd03f64c58,0 +dealloc,0x55bd03f6cfa8,0x55bd03f6cfa8,0 +dealloc,0x55bd03f6d068,0x55bd03f6d068,0 +dealloc,0x55bd03f6d198,0x55bd03f6d198,0 +dealloc,0x55bd03f6d3f8,0x55bd03f6d3f8,0 +dealloc,0x55bd03f6d4e8,0x55bd03f6d4e8,0 +dealloc,0x55bd03f6d898,0x55bd03f6d898,0 +dealloc,0x55bd03f6dab8,0x55bd03f6dab8,0 +dealloc,0x55bd03f649e8,0x55bd03f649e8,0 +alloc,0x55bd03f625a8,0x55bd03f625a8,16 +alloc,0x55bd03f649e8,0x55bd03f649e8,368 +alloc,0x55bd03f64b78,0x55bd03f64b78,200 +alloc,0x55bd03f64c58,0x55bd03f64c58,200 +alloc,0x55bd03f6fbe8,0x55bd03f6fbe8,168 +alloc,0x55bd03f6fca8,0x55bd03f6fca8,280 +alloc,0x55bd03f6fdd8,0x55bd03f6fdd8,584 +alloc,0x55bd03f70038,0x55bd03f70038,216 +alloc,0x55bd03f70128,0x55bd03f70128,920 +alloc,0x55bd03f704d8,0x55bd03f704d8,520 +alloc,0x55bd03f706f8,0x55bd03f706f8,568 +dealloc,0x55bd03f64b78,0x55bd03f64b78,0 +dealloc,0x55bd03f64c58,0x55bd03f64c58,0 +dealloc,0x55bd03f6fbe8,0x55bd03f6fbe8,0 +dealloc,0x55bd03f6fca8,0x55bd03f6fca8,0 +dealloc,0x55bd03f6fdd8,0x55bd03f6fdd8,0 +dealloc,0x55bd03f70038,0x55bd03f70038,0 +dealloc,0x55bd03f70128,0x55bd03f70128,0 +dealloc,0x55bd03f704d8,0x55bd03f704d8,0 +dealloc,0x55bd03f706f8,0x55bd03f706f8,0 +dealloc,0x55bd03f649e8,0x55bd03f649e8,0 +alloc,0x55bd03f68638,0x55bd03f68638,16 +alloc,0x55bd03f649e8,0x55bd03f649e8,368 +alloc,0x55bd03f64b78,0x55bd03f64b78,200 +alloc,0x55bd03f64c58,0x55bd03f64c58,200 +alloc,0x55bd03f72428,0x55bd03f72428,168 +alloc,0x55bd03f724e8,0x55bd03f724e8,280 +alloc,0x55bd03f72618,0x55bd03f72618,584 +alloc,0x55bd03f72878,0x55bd03f72878,216 +alloc,0x55bd03f72968,0x55bd03f72968,920 +alloc,0x55bd03f72d18,0x55bd03f72d18,520 +alloc,0x55bd03f72f38,0x55bd03f72f38,568 +dealloc,0x55bd03f64b78,0x55bd03f64b78,0 +dealloc,0x55bd03f64c58,0x55bd03f64c58,0 +dealloc,0x55bd03f72428,0x55bd03f72428,0 +dealloc,0x55bd03f724e8,0x55bd03f724e8,0 +dealloc,0x55bd03f72618,0x55bd03f72618,0 +dealloc,0x55bd03f72878,0x55bd03f72878,0 +dealloc,0x55bd03f72968,0x55bd03f72968,0 +dealloc,0x55bd03f72d18,0x55bd03f72d18,0 +dealloc,0x55bd03f72f38,0x55bd03f72f38,0 +dealloc,0x55bd03f649e8,0x55bd03f649e8,0 +alloc,0x55bd03f649e8,0x55bd03f649e8,16 +alloc,0x55bd03f64a18,0x55bd03f64a18,368 +alloc,0x55bd03f64ba8,0x55bd03f64ba8,200 +alloc,0x55bd03f64c88,0x55bd03f64c88,200 +alloc,0x55bd03f77c68,0x55bd03f77c68,168 +alloc,0x55bd03f77d28,0x55bd03f77d28,280 +alloc,0x55bd03f77e58,0x55bd03f77e58,584 +alloc,0x55bd03f780b8,0x55bd03f780b8,216 +alloc,0x55bd03f781a8,0x55bd03f781a8,920 +alloc,0x55bd03f78558,0x55bd03f78558,520 +alloc,0x55bd03f78778,0x55bd03f78778,568 +dealloc,0x55bd03f64ba8,0x55bd03f64ba8,0 +dealloc,0x55bd03f64c88,0x55bd03f64c88,0 +dealloc,0x55bd03f77c68,0x55bd03f77c68,0 +dealloc,0x55bd03f77d28,0x55bd03f77d28,0 +dealloc,0x55bd03f77e58,0x55bd03f77e58,0 +dealloc,0x55bd03f780b8,0x55bd03f780b8,0 +dealloc,0x55bd03f781a8,0x55bd03f781a8,0 +dealloc,0x55bd03f78558,0x55bd03f78558,0 +dealloc,0x55bd03f78778,0x55bd03f78778,0 +dealloc,0x55bd03f64a18,0x55bd03f64a18,0 +alloc,0x55bd03f64a18,0x55bd03f64a18,16 +alloc,0x55bd03f64a48,0x55bd03f64a48,368 +alloc,0x55bd03f64bd8,0x55bd03f64bd8,200 +alloc,0x55bd03f7d0a8,0x55bd03f7d0a8,200 +alloc,0x55bd03f7d188,0x55bd03f7d188,168 +alloc,0x55bd03f7d248,0x55bd03f7d248,280 +alloc,0x55bd03f7d378,0x55bd03f7d378,584 +alloc,0x55bd03f7d5d8,0x55bd03f7d5d8,216 +alloc,0x55bd03f7d6c8,0x55bd03f7d6c8,920 +alloc,0x55bd03f7da78,0x55bd03f7da78,520 +alloc,0x55bd03f7dc98,0x55bd03f7dc98,568 +dealloc,0x55bd03f64bd8,0x55bd03f64bd8,0 +dealloc,0x55bd03f7d0a8,0x55bd03f7d0a8,0 +dealloc,0x55bd03f7d188,0x55bd03f7d188,0 +dealloc,0x55bd03f7d248,0x55bd03f7d248,0 +dealloc,0x55bd03f7d378,0x55bd03f7d378,0 +dealloc,0x55bd03f7d5d8,0x55bd03f7d5d8,0 +dealloc,0x55bd03f7d6c8,0x55bd03f7d6c8,0 +dealloc,0x55bd03f7da78,0x55bd03f7da78,0 +dealloc,0x55bd03f7dc98,0x55bd03f7dc98,0 +dealloc,0x55bd03f64a48,0x55bd03f64a48,0 +alloc,0x55bd03f64a48,0x55bd03f64a48,16 +alloc,0x55bd03f64a78,0x55bd03f64a78,368 +alloc,0x55bd03f64c08,0x55bd03f64c08,200 +alloc,0x55bd03f820e8,0x55bd03f820e8,200 +alloc,0x55bd03f821c8,0x55bd03f821c8,168 +alloc,0x55bd03f82288,0x55bd03f82288,280 +alloc,0x55bd03f823b8,0x55bd03f823b8,584 +alloc,0x55bd03f82618,0x55bd03f82618,216 +alloc,0x55bd03f82708,0x55bd03f82708,920 +alloc,0x55bd03f82ab8,0x55bd03f82ab8,520 +alloc,0x55bd03f82cd8,0x55bd03f82cd8,568 +dealloc,0x55bd03f64c08,0x55bd03f64c08,0 +dealloc,0x55bd03f820e8,0x55bd03f820e8,0 +dealloc,0x55bd03f821c8,0x55bd03f821c8,0 +dealloc,0x55bd03f82288,0x55bd03f82288,0 +dealloc,0x55bd03f823b8,0x55bd03f823b8,0 +dealloc,0x55bd03f82618,0x55bd03f82618,0 +dealloc,0x55bd03f82708,0x55bd03f82708,0 +dealloc,0x55bd03f82ab8,0x55bd03f82ab8,0 +dealloc,0x55bd03f82cd8,0x55bd03f82cd8,0 +dealloc,0x55bd03f64a78,0x55bd03f64a78,0 +alloc,0x55bd03f64a78,0x55bd03f64a78,16 +alloc,0x55bd03f64aa8,0x55bd03f64aa8,368 +alloc,0x55bd03f64c38,0x55bd03f64c38,200 +alloc,0x55bd03f87128,0x55bd03f87128,200 +alloc,0x55bd03f87208,0x55bd03f87208,168 +alloc,0x55bd03f872c8,0x55bd03f872c8,280 +alloc,0x55bd03f873f8,0x55bd03f873f8,584 +alloc,0x55bd03f87658,0x55bd03f87658,216 +alloc,0x55bd03f87748,0x55bd03f87748,920 +alloc,0x55bd03f87af8,0x55bd03f87af8,520 +alloc,0x55bd03f87d18,0x55bd03f87d18,568 +dealloc,0x55bd03f64c38,0x55bd03f64c38,0 +dealloc,0x55bd03f87128,0x55bd03f87128,0 +dealloc,0x55bd03f87208,0x55bd03f87208,0 +dealloc,0x55bd03f872c8,0x55bd03f872c8,0 +dealloc,0x55bd03f873f8,0x55bd03f873f8,0 +dealloc,0x55bd03f87658,0x55bd03f87658,0 +dealloc,0x55bd03f87748,0x55bd03f87748,0 +dealloc,0x55bd03f87af8,0x55bd03f87af8,0 +dealloc,0x55bd03f87d18,0x55bd03f87d18,0 +dealloc,0x55bd03f64aa8,0x55bd03f64aa8,0 +alloc,0x55bd03f64aa8,0x55bd03f64aa8,16 +alloc,0x55bd03f64ad8,0x55bd03f64ad8,368 +alloc,0x55bd03f64c68,0x55bd03f64c68,200 +alloc,0x55bd03f8bd68,0x55bd03f8bd68,200 \ No newline at end of file diff --git a/tests/t_sparsemap.nim b/tests/t_sparsemap.nim index 10b0423..a793cd3 100644 --- a/tests/t_sparsemap.nim +++ b/tests/t_sparsemap.nim @@ -1,4 +1,10 @@ -import unittest, random, algorithm, sequtils, playdate/util/sparsemap +import unittest, random, algorithm, sequtils, playdate/util/sparsemap {.all.}, strutils, tables + +iterator allPermutations[T](input: openarray[T]): seq[T] = + var input = input.toSeq + yield input + while input.nextPermutation(): + yield input proc randomData[T](N: int, maxVal: T): seq[T] = result = newSeq[T](N) @@ -8,20 +14,41 @@ proc randomData[T](N: int, maxVal: T): seq[T] = randomize(123) proc expectData[N : static int](map: var StaticSparseMap[N, int, string], expect: openarray[int]) = - check(map.toSeq.mapIt(it.key).sorted() == expect.toSeq.sorted()) - check(map.toSeq.mapIt(it.value).sorted() == expect.toSeq.mapIt($it).sorted()) + require(map.toSeq.mapIt(it.key).sorted() == expect.toSeq.sorted()) + require(map.toSeq.mapIt(it.value).sorted() == expect.toSeq.mapIt($it).sorted()) for key in expect: checkpoint("Checking key " & $key) - check(map[key] != nil) - if map[key] != nil: - check(map[key][] == $key) + require(key in map) + require(map[key] == $key) for key in 5000..5100: - check(map[key] == nil) + require(key notin map) + +proc compareTables(map: var StaticSparseMap, expect: Table) = + for key, value in expect: + require(key in map) + require(map[key] == value) + + for (key, value) in map: + require(key in expect) + require(expect[key] == value) + + require(map.size.int == expect.len) suite "StaticSparseMap": + test "All possible sparse index keys should be covered": + proc visitAllKeys[N: static int](startKey: int32) = + var visitedKeys = newSeq[uint32]() + for key in possibleSparseIdxs[N, int32](startKey): + visitedKeys.add key + visitedKeys.sort + require(visitedKeys == toSeq(0'u32.. Date: Sat, 28 Dec 2024 13:15:10 -0800 Subject: [PATCH 088/101] Improve sparsemap documentation, remove optional return --- src/playdate/util/sparsemap.nim | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/playdate/util/sparsemap.nim b/src/playdate/util/sparsemap.nim index d20a179..0148bbc 100644 --- a/src/playdate/util/sparsemap.nim +++ b/src/playdate/util/sparsemap.nim @@ -1,3 +1,15 @@ +## +## A very basic sparse hashmap implementation. This implementation... +## +## * ...stores all memory on the stack, so it is non-resizeable +## * ...uses a very simple linear open addressing scheme for managing collisions +## * ...tombstones deleted entries +## * ...silently rejects adding new values when at capacity +## +## An artical about the basic strategy for this implementation can be found here: +## https://tristanpenman.com/blog/posts/2017/10/11/sparsehash-internals/ +## + type Pair*[K, V] = tuple[key: K, value: V] @@ -7,8 +19,11 @@ type DenseIdx = distinct uint32 - StaticSparseMap*[N : static int, K, V] {.byref.} = object + StaticSparseMap*[N : static int, K, V] = object ## A sparse map implemented on the stack + ## * `N` is the maximum capacity of the map + ## * `K` is the type of the key + ## * `V` is the type for values stored in the map dense: array[N, Entry[K, V]] sparse: array[N, DenseIdx] size: uint32 @@ -52,6 +67,7 @@ iterator items*[N : static int, K, V](m: var StaticSparseMap[N, K, V]): var Pair yield m.dense[i].pair template find[N, K, V](m: var StaticSparseMap[N, K, V], key: K, exec: untyped): untyped = + ## Internal template for walking the Open Addressing indexes internal used to organize the keys for sparseIdx {.inject.} in possibleSparseIdxs[N, K](key): let denseIdx {.inject.} = m.sparse[sparseIdx] @@ -63,10 +79,9 @@ template find[N, K, V](m: var StaticSparseMap[N, K, V], key: K, exec: untyped): exec proc contains*[N : static int, K, V](m: var StaticSparseMap[N, K, V], key: K): bool = - ## Whethera key is in this table + ## Whether a key is in this table m.find(key): return true - return false proc `[]`*[N : static int, K, V](m: var StaticSparseMap[N, K, V], key: K): V = ## Get a pointer to a key in this map From 0bcb31d6fecc2e34dd521decaaa860b683ee7216 Mon Sep 17 00:00:00 2001 From: Nycto Date: Thu, 23 Jan 2025 18:20:59 -0800 Subject: [PATCH 089/101] Support nil LCDBitmap conversion --- playdate_example/src/playdate_example.nim | 4 ++-- src/playdate/graphics.nim | 19 +++++++++++-------- src/playdate/sprite.nim | 4 ++-- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/playdate_example/src/playdate_example.nim b/playdate_example/src/playdate_example.nim index 0789bc6..c068a0b 100644 --- a/playdate_example/src/playdate_example.nim +++ b/playdate_example/src/playdate_example.nim @@ -99,8 +99,8 @@ proc handler(event: PDSystemEvent, keycode: uint) {.raises: [].} = font = try: playdate.graphics.newFont(FONT_PATH) except: nil playdate.graphics.setFont(font) - playdateNimBitmap = try: playdate.graphics.newBitmap(PLAYDATE_NIM_IMAGE_PATH) except: return - nimLogoBitmap = try: playdate.graphics.newBitmap(NIM_IMAGE_PATH) except: return + playdateNimBitmap = try: playdate.graphics.newBitmap(PLAYDATE_NIM_IMAGE_PATH) except: nil + nimLogoBitmap = try: playdate.graphics.newBitmap(NIM_IMAGE_PATH) except: nil sprite = playdate.sprite.newSprite() sprite.add() diff --git a/src/playdate/graphics.nim b/src/playdate/graphics.nim index 5238f23..5ffda7a 100644 --- a/src/playdate/graphics.nim +++ b/src/playdate/graphics.nim @@ -31,12 +31,15 @@ proc `=destroy`(this: var LCDBitmapObj) = proc `=copy`(a: var LCDBitmapObj, b: LCDBitmapObj) {.error.} -proc bitmapPtr(point: LCDBitmapPtr): auto = +converter bitmapPtr*(point: LCDBitmapPtr): auto = LCDBitmap(managed: false, res: point) proc bitmapRef(point: LCDBitmapPtr): auto = LCDBitmap(managed: true, obj: LCDBitmapObjRef(res: point)) +proc `==`*(bitmap: LCDBitmap, point: LCDBitmapPtr): bool = + not bitmap.managed and bitmap.res == point + proc resource*(bitmap: LCDBitmap): LCDBitmapPtr = if bitmap.managed: return if bitmap.obj != nil: bitmap.obj.res else: nil @@ -53,7 +56,7 @@ type LCDVideoPlayerObj = object of RootObj proc `=destroy`(this: var LCDVideoPlayerObj) = privateAccess(PlaydateVideo) playdate.graphics.video.freePlayer(this.resource) - this.context.reset() + this.context = nil type LCDVideoPlayer* = ref LCDVideoPlayerObj proc newVideoPlayer*(this: ptr PlaydateVideo, path: string): LCDVideoPlayer {.raises: [IOError]} = @@ -72,7 +75,7 @@ proc setContext*(this: LCDVideoPlayer, context: LCDBitmap) {.raises: [CatchableE proc useScreenContext*(this: LCDVideoPlayer) = privateAccess(PlaydateVideo) playdate.graphics.video.useScreenContext(this.resource) - this.context.reset() + this.context = nil proc renderFrame*(this: LCDVideoPlayer, index: int) {.raises: [CatchableError]} = privateAccess(PlaydateVideo) @@ -90,7 +93,7 @@ proc getContext*(this: LCDVideoPlayer): LCDBitmap = privateAccess(PlaydateVideo) let bitmapPtr = playdate.graphics.video.getContext(this.resource) playdate.system.logToConsole(fmt"video context: {bitmapPtr.repr}") - if this.context.isNil or this.context.resource != bitmapPtr: + if this.context == nil or this.context.resource != bitmapPtr: this.context = bitmapPtr(bitmapPtr) return this.context @@ -107,7 +110,7 @@ proc getFont*(this: ptr PlaydateGraphics): LCDFont = proc pushContext*(this: ptr PlaydateGraphics, target: LCDBitmap) = privateAccess(PlaydateGraphics) - this.pushContext(target.resource) + this.pushContext(if target != nil: target.resource else: nil) proc draw*(this: LCDBitmap, x: int, y: int, flip: LCDBitmapFlip) = privateAccess(PlaydateGraphics) @@ -175,7 +178,7 @@ template read(bitmap: AnyBitmapData, x, y: int): untyped = proc getDataObj*(this: LCDBitmap): BitmapDataObj = ## Fetch the underlying bitmap data for an image. privateAccess(PlaydateGraphics) - assert(not this.isNil) + assert(this != nil) assert(this.resource != nil) playdate.graphics.getBitmapData( this.resource, @@ -193,7 +196,7 @@ proc getData*(this: LCDBitmap): BitmapData = proc getSize*(this: LCDBitmap): tuple[width: int, height: int] = privateAccess(PlaydateGraphics) - assert(not this.isNil) + assert(this != nil) assert(this.resource != nil) var width, height: cint playdate.graphics.getBitmapData(this.resource, addr(width), addr(height), nil, @@ -440,7 +443,7 @@ proc set*(this: var LCDBitmap, x, y: int, color: LCDSolidColor = kColorBlack) = proc setStencilImage*(this: ptr PlaydateGraphics, bitmap: LCDBitmap, tile: bool = false) = privateAccess(PlaydateGraphics) - if bitmap.isNil: + if bitmap == nil: this.setStencilImage(nil, if tile: 1 else: 0) else: this.setStencilImage(bitmap.resource, if tile: 1 else: 0) diff --git a/src/playdate/sprite.nim b/src/playdate/sprite.nim index b24fcd8..9ca7e66 100644 --- a/src/playdate/sprite.nim +++ b/src/playdate/sprite.nim @@ -404,12 +404,12 @@ proc setStencilPattern*(this: LCDSprite, pattern: array[8, uint8]) = proc clearStencil*(this: LCDSprite) = privateAccess(PlaydateSprite) playdate.sprite.clearStencil(this.resource) - this.stencil.reset() + this.stencil = nil proc setStencilImage*(this: LCDSprite, stencil: LCDBitmap, tile: bool) = privateAccess(PlaydateSprite) privateAccess(LCDBitmap) - playdate.sprite.setStencilImage(this.resource, stencil.resource, if tile: 1 else: 0) + playdate.sprite.setStencilImage(this.resource, if stencil != nil: stencil.resource else: nil, if tile: 1 else: 0) this.stencil = stencil proc setCenter*(this: LCDSprite, x: float32, y: float32) = From b4757546a1bfcc433662c19f43f4fa0f3c855a6c Mon Sep 17 00:00:00 2001 From: Nycto Date: Sun, 20 Oct 2024 16:32:04 -0700 Subject: [PATCH 090/101] Organize utility code --- src/playdate/api.nim | 5 ++-- src/playdate/bindings/graphics.nim | 2 +- src/playdate/bindings/malloc.nim | 25 +------------------- src/playdate/types.nim | 1 - src/playdate/util/initreqs.nim | 21 ++++++++++++++++ src/playdate/{bindings => util}/memtrace.nim | 0 6 files changed, 25 insertions(+), 29 deletions(-) create mode 100644 src/playdate/util/initreqs.nim rename src/playdate/{bindings => util}/memtrace.nim (100%) diff --git a/src/playdate/api.nim b/src/playdate/api.nim index 262eafc..c31f492 100644 --- a/src/playdate/api.nim +++ b/src/playdate/api.nim @@ -1,7 +1,7 @@ {.push raises: [].} import macros -import std/importutils +import std/importutils, util/initreqs import bindings/api export api @@ -16,8 +16,7 @@ macro initSDK*() = proc eventHandler(playdateAPI: ptr PlaydateAPI, event: PDSystemEvent, arg: uint32): cint {.cdecl, exportc.} = privateAccess(PlaydateSys) if event == kEventInit: - when declared(setupRealloc): - setupRealloc(playdateAPI.system.realloc) + initPrereqs(playdateAPI.system.realloc, playdateAPI.system.logToConsole) NimMain() api.playdate = playdateAPI handler(event, arg) diff --git a/src/playdate/bindings/graphics.nim b/src/playdate/bindings/graphics.nim index 97cbfee..5cca074 100644 --- a/src/playdate/bindings/graphics.nim +++ b/src/playdate/bindings/graphics.nim @@ -1,6 +1,6 @@ {.push raises: [].} -import utils, types +import utils, types, ../util/initreqs type LCDRect* {.importc: "LCDRect", header: "pd_api.h".} = object left* {.importc.}: int # int32? diff --git a/src/playdate/bindings/malloc.nim b/src/playdate/bindings/malloc.nim index b352c80..8923638 100644 --- a/src/playdate/bindings/malloc.nim +++ b/src/playdate/bindings/malloc.nim @@ -18,33 +18,10 @@ when defined(memProfiler): proc nimProfile(requestedSize: int) -import memtrace -import system/ansi_c - -type PDRealloc = proc (p: pointer; size: csize_t): pointer {.tags: [], raises: [], cdecl, gcsafe.} - -proc nativeAlloc(p: pointer; size: csize_t): pointer {.tags: [], raises: [], cdecl, gcsafe.} = - if p == nil: - return c_malloc(size) - elif size == 0: - c_free(p) - return nil - else: - return c_realloc(p, size) - -var pdrealloc: PDRealloc +import ../util/[memtrace, initreqs] var trace: MemTrace - -proc setupRealloc*(allocator: PDRealloc) = - when defined(memtrace): - cfprintf(cstderr, "Setting up playdate allocator") - when defined(nativeAlloc): - pdrealloc = nativeAlloc - else: - pdrealloc = allocator - proc allocImpl(size: Natural): pointer = # Integrage with: https://nim-lang.org/docs/estp.html when defined(memProfiler): diff --git a/src/playdate/types.nim b/src/playdate/types.nim index 2d9db5f..8e2f2ae 100644 --- a/src/playdate/types.nim +++ b/src/playdate/types.nim @@ -1,4 +1,3 @@ - type SDKArrayObj[T] = object len: int data: ptr UncheckedArray[T] diff --git a/src/playdate/util/initreqs.nim b/src/playdate/util/initreqs.nim new file mode 100644 index 0000000..ccd5c96 --- /dev/null +++ b/src/playdate/util/initreqs.nim @@ -0,0 +1,21 @@ +## +## Contains direct references to playdate apis that are required to be usable before the +## full API is itself available. +## +## This file gets used _very_ early in the Nim initialization process. That means it gets +## imported and used before most of the Nim stdlib is available, so it needs to be almost +## completely self contained. +## + +type + PDRealloc* = proc (p: pointer; size: csize_t): pointer {.tags: [], raises: [], cdecl, gcsafe.} + PDLog* = proc (fmt: cstring) {.cdecl, varargs, raises: [].} + +var pdrealloc*: PDRealloc +var pdlog*: PDLog + +proc initPrereqs*(realloc: PDRealloc, log: PDLog) = + ## Sets pointers to functions from the playdate stdlib that are needed to initialize Nim integrations + log("Initializing Nim playdate globals") + pdrealloc = realloc + pdlog = log diff --git a/src/playdate/bindings/memtrace.nim b/src/playdate/util/memtrace.nim similarity index 100% rename from src/playdate/bindings/memtrace.nim rename to src/playdate/util/memtrace.nim From 2fcd02b18d7e649e0e93f74fffd02de75f91bb2e Mon Sep 17 00:00:00 2001 From: Nycto Date: Sun, 20 Oct 2024 16:57:47 -0700 Subject: [PATCH 091/101] Use playdate realloc directly for SDK allocated pointers This resolves the memory tracer reporting calls to deallocate unmanaged memory --- src/playdate/api.nim | 3 ++- src/playdate/bindings/graphics.nim | 9 ++++++--- src/playdate/bindings/initreqs.nim | 10 ++++++++++ src/playdate/types.nim | 4 +++- 4 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 src/playdate/bindings/initreqs.nim diff --git a/src/playdate/api.nim b/src/playdate/api.nim index c31f492..30be87c 100644 --- a/src/playdate/api.nim +++ b/src/playdate/api.nim @@ -3,7 +3,7 @@ import macros import std/importutils, util/initreqs -import bindings/api +import bindings/[api, initreqs] export api import graphics, system, file, sprite, display, sound, scoreboards, lua, json, utils, types, nineslice @@ -15,6 +15,7 @@ macro initSDK*() = proc eventHandler(playdateAPI: ptr PlaydateAPI, event: PDSystemEvent, arg: uint32): cint {.cdecl, exportc.} = privateAccess(PlaydateSys) + privateAccess(PlaydateFile) if event == kEventInit: initPrereqs(playdateAPI.system.realloc, playdateAPI.system.logToConsole) NimMain() diff --git a/src/playdate/bindings/graphics.nim b/src/playdate/bindings/graphics.nim index 5cca074..2b2c6cb 100644 --- a/src/playdate/bindings/graphics.nim +++ b/src/playdate/bindings/graphics.nim @@ -74,7 +74,8 @@ type LCDFontPtr {.importc: "LCDFont*", header: "pd_api.h".} = pointer type LCDFontObj = object resource: LCDFontPtr -proc `=destroy`(this: var LCDFontObj) = deallocImpl(this.resource) +proc `=destroy`(this: var LCDFontObj) = + discard pdrealloc(this.resource, 0) type LCDFont* = ref LCDFontObj @@ -85,7 +86,8 @@ type LCDFontPagePtr {.importc: "LCDFontPage*", header: "pd_api.h".} = pointer type LCDFontPageObj = object resource: LCDFontPagePtr -proc `=destroy`(this: var LCDFontPageObj) = deallocImpl(this.resource) +proc `=destroy`(this: var LCDFontPageObj) = + discard pdrealloc(this.resource, 0) type LCDFontPage* = ref LCDFontPageObj @@ -93,7 +95,8 @@ type LCDFontGlyphPtr {.importc: "LCDFontGlyph*", header: "pd_api.h".} = pointer type LCDFontGlyphObj = object resource: LCDFontGlyphPtr -proc `=destroy`(this: var LCDFontGlyphObj) = deallocImpl(this.resource) +proc `=destroy`(this: var LCDFontGlyphObj) = + discard pdrealloc(this.resource, 0) type LCDFontGlyph* = ref LCDFontGlyphObj diff --git a/src/playdate/bindings/initreqs.nim b/src/playdate/bindings/initreqs.nim new file mode 100644 index 0000000..6142dd9 --- /dev/null +++ b/src/playdate/bindings/initreqs.nim @@ -0,0 +1,10 @@ +## +## Contains direct references to playdate apis that are required to be usable before the +## full API is itself available. +## + +var pdrealloc*: proc (p: pointer; size: csize_t): pointer {.tags: [], raises: [], cdecl, gcsafe.} + +proc initPrereqs*(realloc: auto) = + ## Sets pointers to functions that are needed early in the initialization process + pdrealloc = realloc diff --git a/src/playdate/types.nim b/src/playdate/types.nim index 8e2f2ae..b4ba3ad 100644 --- a/src/playdate/types.nim +++ b/src/playdate/types.nim @@ -1,3 +1,5 @@ +import util/initreqs + type SDKArrayObj[T] = object len: int data: ptr UncheckedArray[T] @@ -5,7 +7,7 @@ type SDKArray*[T] = ref SDKArrayObj[T] proc `=destroy`*[T](this: var SDKArrayObj[T]) = if this.data != nil: - deallocImpl(this.data) + discard pdrealloc(this.data, 0) proc `[]`*[T](this: SDKArray[T]; i: Natural): lent T = assert i < this.len From eaad3a48eb61f4c8fa33d0ac72baa4c9608b36c2 Mon Sep 17 00:00:00 2001 From: Nycto Date: Mon, 13 Jan 2025 18:40:32 -0800 Subject: [PATCH 092/101] Completely elid memtrace when disabled --- src/playdate/bindings/malloc.nim | 46 ++++++++++++++++++++++---------- src/playdate/util/memtrace.nim | 19 +++---------- 2 files changed, 36 insertions(+), 29 deletions(-) diff --git a/src/playdate/bindings/malloc.nim b/src/playdate/bindings/malloc.nim index 8923638..5748bcd 100644 --- a/src/playdate/bindings/malloc.nim +++ b/src/playdate/bindings/malloc.nim @@ -14,31 +14,48 @@ {.push stackTrace: off.} -# Forward declaration for memory profiling support +import ../util/initreqs + when defined(memProfiler): + + # Forward declaration for memory profiling support proc nimProfile(requestedSize: int) -import ../util/[memtrace, initreqs] + template rawAlloc(size): untyped = + # Integrage with: https://nim-lang.org/docs/estp.html + try: + nimProfile(size.int) + except: + discard + pdrealloc(nil, size) -var trace: MemTrace + template rawRealloc(p, size): untyped = pdrealloc(p, size) + template rawDealloc(p) = discard pdrealloc(p, 0) -proc allocImpl(size: Natural): pointer = - # Integrage with: https://nim-lang.org/docs/estp.html - when defined(memProfiler): - {.cast(tags: []).}: - try: - nimProfile(size.int) - except: - discard +elif defined(memtrace): + import ../util/memtrace + var trace: MemTrace - return trace.alloc(pdrealloc, size.csize_t) + template rawAlloc(size): untyped = traceAlloc(trace, pdrealloc, size) + template rawRealloc(p, size): untyped = traceRealloc(trace, pdrealloc, p, size) + template rawDealloc(p) = traceDealloc(trace, pdrealloc, p) + +else: + template rawAlloc(size): untyped = pdrealloc(nil, size) + template rawRealloc(p, size): untyped = pdrealloc(p, size) + template rawDealloc(p) = discard pdrealloc(p, 0) + +proc allocImpl(size: Natural): pointer = + {.cast(tags: []).}: + return rawAlloc(size.csize_t) proc alloc0Impl(size: Natural): pointer = result = allocImpl(size) zeroMem(result, size) proc reallocImpl(p: pointer, newSize: Natural): pointer = - return trace.realloc(pdrealloc, p, newSize) + {.cast(tags: []).}: + return rawRealloc(p, newSize.csize_t) proc realloc0Impl(p: pointer, oldsize, newSize: Natural): pointer = result = reallocImpl(p, newSize.csize_t) @@ -46,7 +63,8 @@ proc realloc0Impl(p: pointer, oldsize, newSize: Natural): pointer = zeroMem(cast[pointer](cast[uint](result) + uint(oldSize)), newSize - oldSize) proc deallocImpl(p: pointer) = - trace.dealloc(pdrealloc, p) + {.cast(tags: []).}: + rawDealloc(p) # The shared allocators map on the regular ones diff --git a/src/playdate/util/memtrace.nim b/src/playdate/util/memtrace.nim index 840be1e..0d41c34 100644 --- a/src/playdate/util/memtrace.nim +++ b/src/playdate/util/memtrace.nim @@ -1,4 +1,4 @@ -import system/ansi_c, ../util/sparsemap +import system/ansi_c, sparsemap, initreqs proc mprotect(a1: pointer, a2: int, a3: cint): cint {.importc, header: "".} @@ -13,8 +13,6 @@ const STACK_SIZE = 12 const BUFFER = sizeof(byte) * 8 type - Allocator* = proc (p: pointer; size: csize_t): pointer {.tags: [], raises: [], cdecl, gcsafe.} - StackString[N : static int] = object data: array[N, char] len: int32 @@ -210,7 +208,7 @@ proc record[N: static int](stack: array[N, StackFrame] = createStackFrame[N](get discard c_fwrite(addr stack[i].procname, 1, stack[i].procname.len.csize_t, handle) c_fputc('\n', handle) -proc traceAlloc(trace: var MemTrace, alloc: Allocator, size: Natural): pointer {.inline.} = +proc traceAlloc*(trace: var MemTrace, alloc: PDRealloc, size: Natural): pointer {.inline.} = trace.totalAllocs += 1 trace.check @@ -231,11 +229,8 @@ proc traceAlloc(trace: var MemTrace, alloc: Allocator, size: Natural): pointer { trace.allocs[realPointer.ord] = entry -proc alloc*(trace: var MemTrace, alloc: Allocator, size: Natural): pointer {.inline.} = +proc traceRealloc*(trace: var MemTrace, alloc: PDRealloc, p: pointer, newSize: Natural): pointer {.inline.} = record[5]() - when defined(memtrace): return traceAlloc(trace, alloc, size) else: return alloc(nil, size.csize_t) - -proc traceRealloc(trace: var MemTrace, alloc: Allocator, p: pointer, newSize: Natural): pointer {.inline.} = trace.check let realInPointer = p.input @@ -263,10 +258,7 @@ proc traceRealloc(trace: var MemTrace, alloc: Allocator, p: pointer, newSize: Na trace.allocs[realOutPointer.ord] = entry -proc realloc*(trace: var MemTrace, alloc: Allocator, p: pointer, newSize: Natural): pointer {.inline.} = - when defined(memtrace): return traceRealloc(trace, alloc, p, newSize) else: return alloc(p, newSize.csize_t) - -proc traceDealloc(trace: var MemTrace, alloc: Allocator, p: pointer) {.inline.} = +proc traceDealloc*(trace: var MemTrace, alloc: PDRealloc, p: pointer) {.inline.} = trace.check let realPointer = p.input if realPointer.ord notin trace.allocs: @@ -285,6 +277,3 @@ proc traceDealloc(trace: var MemTrace, alloc: Allocator, p: pointer) {.inline.} discard alloc(realPointer, 0) trace.deleted[realPointer.ord] = local trace.allocs.delete(realPointer.ord) - -proc dealloc*(trace: var MemTrace, alloc: Allocator, p: pointer) {.inline.} = - when defined(memtrace): traceDealloc(trace, alloc, p) else: discard alloc(p, 0) \ No newline at end of file From abbd913925211247d9fc6c755663f2853131e5a8 Mon Sep 17 00:00:00 2001 From: Nycto Date: Tue, 4 Feb 2025 18:37:44 -0800 Subject: [PATCH 093/101] Fix PlaydateSys.logToConsole argument type This was causing an error in GCC 14 related to incompatible pointer types -- 'void (*)(char *, ...)' instead of 'void (* const)(const char *, ...)' --- src/playdate/bindings/system.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/playdate/bindings/system.nim b/src/playdate/bindings/system.nim index 1f774d5..96798ec 100644 --- a/src/playdate/bindings/system.nim +++ b/src/playdate/bindings/system.nim @@ -37,7 +37,7 @@ sdktype: realloc {.importc: "realloc".}: proc (`ptr`: pointer; size: csize_t): pointer {.cdecl, raises: [], tags: [], gcsafe.} formatString {.importc: "formatString".}: proc (ret: cstringArray; fmt: cstring): cint {. cdecl, varargs, raises: [].} - logToConsole {.importc: "logToConsole".}: proc (fmt: cstring) {.cdecl, varargs, raises: [].} + logToConsole {.importc: "logToConsole".}: proc (fmt: ConstChar) {.cdecl, varargs, raises: [].} error {.importc: "error".}: proc (fmt: cstring) {.cdecl, varargs, raises: [].} getLanguage {.importsdk.}: proc (): PDLanguage getCurrentTimeMilliseconds {.importsdk.}: proc (): cuint From 49b709ee0ddf6c3b97f4744880dcdb2368ff42fe Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Sun, 9 Feb 2025 18:42:36 +0100 Subject: [PATCH 094/101] CHANGE separate macos compile step --- .github/actions/macos-build-setup/action.yml | 39 ++++++++++++++++++++ .github/workflows/build.yml | 17 ++++++++- 2 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 .github/actions/macos-build-setup/action.yml diff --git a/.github/actions/macos-build-setup/action.yml b/.github/actions/macos-build-setup/action.yml new file mode 100644 index 0000000..86b40b7 --- /dev/null +++ b/.github/actions/macos-build-setup/action.yml @@ -0,0 +1,39 @@ +name: macos build setup +inputs: + nim-version: + required: true +runs: + using: "composite" + steps: + + - name: Git safe directory + shell: bash + run: git config --global --add safe.directory "$(pwd)" + + - uses: iffy/install-nim@v5 + with: + version: ${{ inputs.nim-version }} + - run: nimble --accept refresh + shell: bash + + - run: nimble install + shell: bash + + - name: Locally publish playdate nimble package + shell: bash + if: ${{ startsWith(inputs.nim-version, '1.') }} + run: nimble develop + + - name: Install Playdate SDK + id: playdate + uses: pd-rs/get-playdate-sdk@0.4 + with: + version: latest # possible values: version `x.x.x` or `latest` by default + + - name: print playdate sdk info + shell: bash + run: | + echo "SDK path env: $PLAYDATE_SDK_PATH" + echo "SDK root out: ${{ steps.playdate.outputs.root }}" + echo "SDK version: ${{ steps.playdate.outputs.version }}" + pdc --version # because SDK/bin already in PATH \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index feee96f..cc25881 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,13 +2,26 @@ name: Build on: [push, pull_request] jobs: + compile-example-project-macos: + runs-on: macos-latest + steps: + - uses: actions/checkout@v3 + - uses: ./.github/actions/macos-build-setup + with: + nim-version: 2.0.8 + - uses: ./.github/actions/project-setup + with: + working-directory: ./playdate_example + - run: nimble simulator + working-directory: ./playdate_example + example-project: - runs-on: ubuntu-latest - container: nimlang/choosenim strategy: matrix: target: [ device, simulator ] nim-version: [ 2.0.8 ] + runs-on: ubuntu-latest + container: nimlang/choosenim steps: - uses: actions/checkout@v3 - uses: ./.github/actions/build-setup From 65ecc3c30f2134927d667174c608e97b0238ab62 Mon Sep 17 00:00:00 2001 From: Nycto Date: Mon, 10 Feb 2025 21:05:01 -0800 Subject: [PATCH 095/101] Fix incompatible function pointer errors in clang --- src/playdate/bindings/system.nim | 4 ++-- src/playdate/bindings/types.nim | 14 ++++++++++---- src/playdate/util/initreqs.nim | 4 +--- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/playdate/bindings/system.nim b/src/playdate/bindings/system.nim index 96798ec..d4ead8a 100644 --- a/src/playdate/bindings/system.nim +++ b/src/playdate/bindings/system.nim @@ -34,10 +34,10 @@ type PDMenuItemCallbackFunctionRaw {.importc: "PDMenuItemCallbackFunction", head # System sdktype: type PlaydateSys* {.importc: "const struct playdate_sys", header: "pd_api.h".} = object - realloc {.importc: "realloc".}: proc (`ptr`: pointer; size: csize_t): pointer {.cdecl, raises: [], tags: [], gcsafe.} + realloc {.importc: "realloc".}: PDRealloc formatString {.importc: "formatString".}: proc (ret: cstringArray; fmt: cstring): cint {. cdecl, varargs, raises: [].} - logToConsole {.importc: "logToConsole".}: proc (fmt: ConstChar) {.cdecl, varargs, raises: [].} + logToConsole {.importc: "logToConsole".}: PDLog error {.importc: "error".}: proc (fmt: cstring) {.cdecl, varargs, raises: [].} getLanguage {.importsdk.}: proc (): PDLanguage getCurrentTimeMilliseconds {.importsdk.}: proc (): cuint diff --git a/src/playdate/bindings/types.nim b/src/playdate/bindings/types.nim index 3ab3773..30aa349 100644 --- a/src/playdate/bindings/types.nim +++ b/src/playdate/bindings/types.nim @@ -1,5 +1,11 @@ -type ConstChar* {.importc: "const char*".} = cstring -type ConstCharPtr* {.importc: "const char**".} = cstring -type Char* {.importc: "char*".} = cstring +type + ConstChar* {.importc: "const char*".} = cstring + ConstCharPtr* {.importc: "const char**".} = cstring + Char* {.importc: "char*".} = cstring + LCDBitmapPtr* {.importc: "LCDBitmap*", header: "pd_api.h".} = pointer -type LCDBitmapPtr* {.importc: "LCDBitmap*", header: "pd_api.h".} = pointer \ No newline at end of file + PDLog* = proc (fmt: ConstChar) {.cdecl, varargs, raises: [].} + ## The type signature for playdate.system.logToConsole + + PDRealloc* = proc (p: pointer; size: csize_t): pointer {.tags: [], raises: [], cdecl, gcsafe.} + ## The type signature for playdate.system.realloc \ No newline at end of file diff --git a/src/playdate/util/initreqs.nim b/src/playdate/util/initreqs.nim index ccd5c96..9a25cc8 100644 --- a/src/playdate/util/initreqs.nim +++ b/src/playdate/util/initreqs.nim @@ -7,9 +7,7 @@ ## completely self contained. ## -type - PDRealloc* = proc (p: pointer; size: csize_t): pointer {.tags: [], raises: [], cdecl, gcsafe.} - PDLog* = proc (fmt: cstring) {.cdecl, varargs, raises: [].} +import ../bindings/types var pdrealloc*: PDRealloc var pdlog*: PDLog From f5fd41e17e3cd409af31d3510ce43ce93c31ee36 Mon Sep 17 00:00:00 2001 From: Nycto Date: Tue, 11 Feb 2025 18:49:52 -0800 Subject: [PATCH 096/101] Simplify patch file location --- src/playdate/build/config.nim | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/playdate/build/config.nim b/src/playdate/build/config.nim index 4f396fe..56f9bd9 100644 --- a/src/playdate/build/config.nim +++ b/src/playdate/build/config.nim @@ -18,16 +18,6 @@ const testing = headlessTesting or nimbleTesting # This does not make the playdate api callable, only the types (header files) are available. const useHostOS = defined(useHostOS) -# Path to the playdate src directory when checked out locally -const localPlaydatePath = currentSourcePath / "../../../../src" - -# The path to the nimble playdate package -let nimblePlaydatePath = - if dirExists(localPlaydatePath / "playdate"): - localPlaydatePath - else: - gorgeEx("nimble path playdate").output.split("\n")[0] - if not testing and not useHostOS: switch("noMain", "on") switch("backend", "c") @@ -180,4 +170,4 @@ else: switch("compile", sdkPath() / "C_API" / "buildsupport" / "setup.c") # Overrides the nim memory management code to ensure it uses the playdate allocator - patchFile("stdlib", "malloc", nimblePlaydatePath / "playdate/bindings/malloc") \ No newline at end of file + patchFile("stdlib", "malloc", currentSourcePath().parentDir() /../ "bindings" / "malloc") \ No newline at end of file From 775bf90b9db97160e6aa38afb6a5ae4342737785 Mon Sep 17 00:00:00 2001 From: Nycto Date: Wed, 12 Feb 2025 18:22:50 -0800 Subject: [PATCH 097/101] Fix memtrace build action failure --- src/playdate/util/memtrace.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/playdate/util/memtrace.nim b/src/playdate/util/memtrace.nim index 0d41c34..eb8ec78 100644 --- a/src/playdate/util/memtrace.nim +++ b/src/playdate/util/memtrace.nim @@ -1,4 +1,4 @@ -import system/ansi_c, sparsemap, initreqs +import system/ansi_c, sparsemap, initreqs, ../bindings/types proc mprotect(a1: pointer, a2: int, a3: cint): cint {.importc, header: "".} From aae61bd3a304baaa52d0708b4f7558793f2e4b96 Mon Sep 17 00:00:00 2001 From: Nycto Date: Wed, 12 Feb 2025 18:32:30 -0800 Subject: [PATCH 098/101] Implement pdn (#98) --- .github/actions/build-setup/action.yml | 8 +- .github/actions/project-setup/action.yml | 5 - .github/workflows/build.yml | 13 +- .gitignore | 8 +- README.md | 64 ++++--- config.nims | 4 + playdate.nimble | 4 +- playdate_example/.gitignore | 3 + playdate_example/source/pdxinfo | 4 - src/pdn.nim | 66 +++++++ src/playdate/bindings/malloc.nim | 6 +- src/playdate/build/actions.nim | 211 +++++++++++++++++++++++ src/playdate/build/config.nim | 14 +- src/playdate/build/nimble.nim | 138 +-------------- src/playdate/build/utils.nim | 92 +++------- tests/.gitignore | 3 + tests/source/pdxinfo | 4 - 17 files changed, 379 insertions(+), 268 deletions(-) create mode 100644 config.nims delete mode 100644 playdate_example/source/pdxinfo create mode 100644 src/pdn.nim create mode 100644 src/playdate/build/actions.nim delete mode 100644 tests/source/pdxinfo diff --git a/.github/actions/build-setup/action.yml b/.github/actions/build-setup/action.yml index f6453b9..a47da01 100644 --- a/.github/actions/build-setup/action.yml +++ b/.github/actions/build-setup/action.yml @@ -17,7 +17,13 @@ runs: - run: nimble --accept refresh shell: bash - - run: nimble install + - run: nimble install --verbose + shell: bash + + - run: echo "/github/home/.nimble/bin" >> $GITHUB_PATH + shell: bash + + - run: which pdn shell: bash - name: Locally publish playdate nimble package diff --git a/.github/actions/project-setup/action.yml b/.github/actions/project-setup/action.yml index e441e7e..21e721d 100644 --- a/.github/actions/project-setup/action.yml +++ b/.github/actions/project-setup/action.yml @@ -6,11 +6,6 @@ runs: using: "composite" steps: - - name: Nimble example setup - shell: bash - working-directory: ${{ inputs.working-directory }} - run: nimble configure; - - name: Install dependencies shell: bash working-directory: ${{ inputs.working-directory }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cc25881..7859aea 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,9 +12,9 @@ jobs: - uses: ./.github/actions/project-setup with: working-directory: ./playdate_example - - run: nimble simulator + - run: pdn simulator working-directory: ./playdate_example - + example-project: strategy: matrix: @@ -30,7 +30,7 @@ jobs: - uses: ./.github/actions/project-setup with: working-directory: ./playdate_example - - run: nimble ${{ matrix.target }} + - run: pdn ${{ matrix.target }} working-directory: ./playdate_example tests: @@ -77,10 +77,7 @@ jobs: pulseaudio -D --exit-idle-time=-1 pactl load-module module-null-sink sink_name=SpeakerOutput sink_properties=device.description="Dummy_Output" - - run: echo 'switch("d", "${{ matrix.build-flags }}")' >> configs.nims - working-directory: ./tests - - - run: nimble simulator + - run: pdn simulator -d:${{ matrix.build-flags }} working-directory: ./tests # The first time the simulator runs, it prompts the user with an alert. Obviously, we're running headless, @@ -99,4 +96,4 @@ jobs: working-directory: ./tests run: | export HOME="/config" - xvfb-run ../PlaydateSDK-*/bin/PlaydateSimulator tests.pdx \ No newline at end of file + xvfb-run ../PlaydateSDK-*/bin/PlaydateSimulator playdate_tests.pdx \ No newline at end of file diff --git a/.gitignore b/.gitignore index 637f30c..0cc1747 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ htmldocs/ src/tests/ pdex.bin *.pdx +tests/source/pdxinfo # macOS general .DS_Store @@ -58,4 +59,9 @@ tests/t_* tests/playdate_tests # IntelliJ IDEA -.idea \ No newline at end of file +.idea +nimble.develop +nimble.paths + +# Binaries +pdn diff --git a/README.md b/README.md index 97552ae..1e0046f 100644 --- a/README.md +++ b/README.md @@ -47,42 +47,31 @@ If you want to start from scratch, here are the steps to follow: 1. If you haven't done it already, start creating a folder (snake_case) and initializing your nimble package inside it running: -``` -nimble init -``` -Choose `binary` as the package type. + ```shell + nimble init + ``` + + Choose `binary` as the package type. 2. Install the `playdate` package: -``` -nimble install playdate -``` + ```shell + nimble install playdate + ``` -3. Add the `playdate` package as a dependency and configure the build tasks by running the following: +3. Add the `playdate` package as a dependency in your nimble file: -``` -echo 'requires "playdate"' >> *.nimble; -echo 'include playdate/build/nimble' >> *.nimble; -echo 'include playdate/build/config' > config.nims; -``` - -4. Finally, run this command to setup the structure of the project, which prepares your application to be compiled and bundled correctly: - -``` -nimble configure -``` + ```shell + echo 'requires "playdate"' >> *.nimble; + ``` ## Usage -If you haven't done it already, install the package: -``` -nimble install playdate -``` - `playdate_example` contains a basic example of the bindings utilization. The example code is in `playdate_example/src/playdate_example.nim`. Here's also a minimal snippet to make a Nim application: + ```nim import playdate/api @@ -96,35 +85,38 @@ proc handler(event: PDSystemEvent, keycode: uint) {.raises: [].} = if event == kEventInit: # Errors are handled through exceptions, this is an inline try/except nimLogoBitmap = try: playdate.graphics.newBitmap("/images/nim_logo") except: nil - # playdate is the global PlaydateAPI instance, available when playdate/api is imported + # playdate is the global PlaydateAPI instance, available when playdate/api is imported playdate.system.setUpdateCallback(update) # Used to setup the SDK entrypoint initSDK() ``` -Compile the project (pdx) for the simulator using: +Compile the project (pdx) for the simulator using the `pdn` binary that gets added when +you ran `nimble install playdate`: + ```sh -nimble simulator +pdn simulator ``` + For the device (pdx): + ```sh -nimble device -``` -For simulator + device (pdx): -```sh -nimble all +pdn device ``` You can also build for simulator and launch it in one command: + ```sh -nimble simulate +pdn simulate ``` The example project `playdate_example` also contains VSCode launch configurations to build, start and debug your Nim application from the editor. -Each project contains a `config.nims` file that can be edited to customize how the project should be built, e.g. adding libraries or other external code.
+Each project contains a `config.nims` file that can be edited to customize how the project should be built, e.g. adding libraries or other external code. + Here's an example of a `config.nims` that links a pre-built static library called chipmunk: + ```nim include playdate/build/config @@ -151,6 +143,7 @@ There are two ways you can use Nim and Lua in the same project: 2. The main loop is defined in Lua, but you want to call Nim functions. Either way, you can provide Lua with your Nim functions during Lua initialization: + ```nim proc nimInsideLua(state: LuaStatePtr): cint {.cdecl, raises: [].} = ... @@ -164,9 +157,10 @@ proc handler(event: PDSystemEvent, keycode: uint) {.raises: [].} = ``` Calling a Lua function from Nim: + ```nim try: - # Push the argument first + # Push the argument first playdate.lua.pushInt(5) playdate.lua.callFunction("funcWithOneArgument", 1) except: diff --git a/config.nims b/config.nims new file mode 100644 index 0000000..8ee48d2 --- /dev/null +++ b/config.nims @@ -0,0 +1,4 @@ +# begin Nimble config (version 2) +when withDir(thisDir(), system.fileExists("nimble.paths")): + include "nimble.paths" +# end Nimble config diff --git a/playdate.nimble b/playdate.nimble index 1e9a35d..134a215 100644 --- a/playdate.nimble +++ b/playdate.nimble @@ -5,9 +5,9 @@ author = "Samuele Zolfanelli" description = "Playdate Nim bindings with extra features." license = "MIT" srcDir = "src" - +installExt = @["nim"] +bin = @["pdn"] # Dependencies requires "nim >= 2.0.0" -# requires "nimble < 0.14.0" diff --git a/playdate_example/.gitignore b/playdate_example/.gitignore index b74210d..74a53b5 100644 --- a/playdate_example/.gitignore +++ b/playdate_example/.gitignore @@ -1,3 +1,6 @@ *.pdx source/pdex.* *.dSYM +playdate_example.pdx.zip +playdate_example.pdx +source/pdxinfo \ No newline at end of file diff --git a/playdate_example/source/pdxinfo b/playdate_example/source/pdxinfo deleted file mode 100644 index 9942484..0000000 --- a/playdate_example/source/pdxinfo +++ /dev/null @@ -1,4 +0,0 @@ -name=Playdate Example -author=Samuele Zolfanelli -description=An example application using the Playdate Nim bindings -bundleId=com.samdze.playdate_example \ No newline at end of file diff --git a/src/pdn.nim b/src/pdn.nim new file mode 100644 index 0000000..23182ed --- /dev/null +++ b/src/pdn.nim @@ -0,0 +1,66 @@ +import std/[parseopt, strutils, os, macros, options] +import playdate/build/[utils, actions] + +type + BuildCommand = enum simulate, simulator, device, clean, bundle + ## The various actions that can be executed by this script + + CliConfig = object + ## Configurations collected from the Cli + command: BuildCommand + noAutoConfig: bool + sdkPath: Option[string] + extraArgs: seq[string] + +proc getCliConfig(): CliConfig = + ## Parses the build configuration from the input options + for kind, key, val in getopt(): + template addExtraArg() = + var command = if kind == cmdLongOption: "--" else: "-" + command &= key + if val != "": + command &= ":" & val + result.extraArgs.add(command) + + case kind + of cmdArgument: + result.command = parseEnum[BuildCommand](key) + of cmdLongOption, cmdShortOption: + case key + of "sdk-path": result.sdkPath = some(val) + of "no-auto-config": result.noAutoConfig = true + else: addExtraArg() + of cmdEnd: + discard + +let build = getCliConfig() + +let dump = getNimbleDump() + +let conf = PlaydateConf( + dump: dump, + kind: if build.command == device: DeviceBuild else: SimulatorBuild, + sdkPath: sdkPath(build.sdkPath), + pdxName: dump.name & ".pdx", + nimbleArgs: build.extraArgs, + noAutoConfig: build.noAutoConfig +) + +case build.command +of device, simulate, simulator: + conf.configureBuild() +of clean, bundle: + discard + +case build.command +of simulator: + conf.simulatorBuild() +of simulate: + conf.simulatorBuild() + conf.runSimulator() +of device: + conf.deviceBuild() +of clean: + conf.runClean() +of bundle: + conf.bundlePDX() diff --git a/src/playdate/bindings/malloc.nim b/src/playdate/bindings/malloc.nim index 5748bcd..35cb89d 100644 --- a/src/playdate/bindings/malloc.nim +++ b/src/playdate/bindings/malloc.nim @@ -14,7 +14,11 @@ {.push stackTrace: off.} -import ../util/initreqs +when (compiles do: + import playdate/util/initreqs): + import playdate/util/initreqs +else: + import ../util/initreqs when defined(memProfiler): diff --git a/src/playdate/build/actions.nim b/src/playdate/build/actions.nim new file mode 100644 index 0000000..1c23e07 --- /dev/null +++ b/src/playdate/build/actions.nim @@ -0,0 +1,211 @@ +import std/[sequtils, strutils, os, times, strformat, osproc, sets, json, jsonutils], utils + +type + BuildKind* = enum SimulatorBuild, DeviceBuild + + PlaydateConf* {.requiresInit.} = object + kind*: BuildKind + sdkPath*, pdxName*: string + nimbleArgs*: seq[string] + dump*: NimbleDump + noAutoConfig*: bool + + NimbleDump* = ref object + ## The data pulled from running `nimble dump --json` + name*, version*, nimblePath*, author*, desc*, license*: string + +proc getNimbleDump*(): NimbleDump = + ## Executes nimble with the given set of arguments + let (output, exitCode) = execCmdEx("nimble dump --json") + if exitCode != 0: + echo output + raise BuildFail.newException(fmt"Unable to extract nimble dump for package") + return parseJson(output).jsonTo(NimbleDump, Joptions(allowExtraKeys: true)) + +proc exec*(command: string, args: varargs[string]) = + ## Executes nimble with the given set of arguments + let process = startProcess( + command = command, + args = args, + options = {poUsePath, poParentStreams, poEchoCmd} + ) + if process.waitForExit() != 0: + raise BuildFail.newException(fmt"Command failed: {command} {args}") + +proc nimble*(conf: PlaydateConf, args: varargs[string]) = + ## Executes nimble with the given set of arguments + exec( + "nimble", + @[ "-d:playdateSdkPath=" & conf.sdkPath ].concat(conf.nimbleArgs).concat(args.toSeq) + ) + +proc pdcPath*(conf: PlaydateConf): string = + ## Returns the path of the pdc playdate utility + return conf.sdkPath / "bin" / "pdc" + +proc fileAppend*(path, content: string) = + ## Appends a string to a file + var handle: File + doAssert handle.open(path, fmAppend) + try: + handle.write(content) + finally: + handle.close + +proc updateGitIgnore(conf: PlaydateConf) = + ## Adds entries to the gitignore file + + var toAdd = toHashSet([ + conf.pdxName, + conf.pdxName & ".zip", + "source/pdxinfo", + "source/pdex.*", + "*.dSYM" + ]) + + const gitIgnore = ".gitignore" + + if not fileExists(gitIgnore): + writeFile(gitIgnore, "") + + for line in lines(gitIgnore): + toAdd.excl(line) + + if toAdd.len > 0: + gitIgnore.fileAppend(toAdd.items.toSeq.join("\n")) + +proc updateConfig(conf: PlaydateConf) = + ## Updates the config.nims file for the project if required + + const configFile = "playdate/build/config" + + if fileExists("config.nims"): + for line in lines("config.nims"): + if configFile in line: + echo "config.nims already references ", configFile, "; skipping build configuration" + return + + echo "Updating config.nims to include build configurations" + + "configs.nims".fileAppend(fmt"\n\n# Added by pdn\nimport {configFile}\n") + +proc writePdxInfo(conf: PlaydateConf) = + ## Writes the pdx info file + + let buildId = now().format("yyyyMMddhhmmss") + + let (output, exitCode) = execCmdEx("git rev-parse HEAD") + let commit = if exitCode == 0: output[0..<8] else: conf.dump.version + + let cartridgeName = conf.dump.name + .replace("_", " ") + .split(" ") + .map(proc(s: string): string = s.capitalizeAscii()) + .join(" ") + let bundleAuthor = conf.dump.author + .toLower() + .replace(" ", "") + .replace("-", "") + .replace("_", "") + let bundleProjectName = conf.dump.name + .toLower() + .replace(" ", "") + .replace("-", "") + .replace("_", "") + + let pdx = fmt""" + name={cartridgeName} + author={conf.dump.author} + description={conf.dump.desc} + bundleId=com.{bundleAuthor}.{bundleProjectName} + imagePath=launcher + version={commit} + buildNumber={buildId} + """.dedent() + + createDir("source") + writeFile("source" / "pdxinfo", pdx) + +proc configureBuild*(conf: PlaydateConf) = + if not conf.noAutoConfig: + conf.updateConfig + conf.writePdxInfo + conf.updateGitIgnore + +proc bundlePDX*(conf: PlaydateConf) = + ## Bundles pdx file using parent directory name. + exec(conf.pdcPath, "--version") + exec(conf.pdcPath, "--verbose", "-sdkpath", conf.sdkPath, "source", conf.dump.name) + +proc mv(source, target: string) = + echo fmt"Moving {source} to {target}" + if not source.fileExists and not source.dirExists: + raise BuildFail.newException(fmt"Expecting the '{source}' to exist, but it doesn't") + moveFile(source, target) + +proc rm(target: string) = + echo fmt"Removing {target}" + removeFile(target) + +proc rmdir(target: string) = + echo fmt"Removing {target}" + removeDir(target) + +proc simulatorBuild*(conf: PlaydateConf) = + ## Performs a build for running on the simulator + + conf.nimble("build", "-d:simulator", "-d:debug") + + if defined(windows): + mv(conf.dump.name & ".exe", "source" / "pdex.dll") + elif defined(macosx): + mv(conf.dump.name, "source" / "pdex.dylib") + rmdir("source" / "pdex.dSYM") + mv(conf.dump.name & ".dSYM", "source" / "pdex.dSYM") + elif defined(linux): + mv(conf.dump.name, "source" / "pdex.so") + else: + raise BuildFail.newException(fmt"Unsupported host platform") + + conf.bundlePDX() + +proc runSimulator*(conf: PlaydateConf) = + ## Executes the simulator + if not conf.pdxName.dirExists: + raise BuildFail.newException(fmt"PDX does not exist: {conf.pdxName.absolutePath}") + + when defined(windows): + exec(conf.sdkPath / "bin" / "PlaydateSimulator.exe", conf.pdxName) + elif defined(macosx): + exec("open", conf.sdkPath / "bin" / "Playdate\\ Simulator.app", conf.pdxName) + else: + exec(conf.sdkPath / "bin" / "PlaydateSimulator", conf.pdxName) + +proc deviceBuild*(conf: PlaydateConf) = + ## Performs a build for running on device + + conf.nimble("build", "-d:device", "-d:release") + + let artifact = when defined(windows): conf.dump.name & ".exe" else: conf.dump.name + mv(artifact, "source" / "pdex.elf") + rm("game.map") + + conf.bundlePDX() + + let zip = findExe("zip") + if zip != "": + exec(zip, "-r", fmt"{conf.pdxName}.zip", conf.pdxName, "-x", "*.so") + +proc runClean*(conf: PlaydateConf) = + ## Removes all cache files and build artifacts + rmdir("source" / "pdex.dSYM") + rm("source" / "pdex.dylib") + rm("source" / "pdex.dll") + rm("source" / "pdex.so") + rm("source" / "pdex.bin") + rm("source" / "pdex.elf") + rmdir(conf.pdxName) + rm("source" / "pdex.elf") + rm(conf.dump.name) + rm(conf.dump.name & ".exe") + exec("nimble", "clean") diff --git a/src/playdate/build/config.nim b/src/playdate/build/config.nim index 56f9bd9..9d90db7 100644 --- a/src/playdate/build/config.nim +++ b/src/playdate/build/config.nim @@ -1,10 +1,8 @@ -import os, strutils +import std/[os, strutils], utils when defined(device): import strformat -import utils - # This file is designed to be `included` directly from a `config.nims` file, which will make `switch` and `task` # implicitly available. This block just fixes auto-complete in IDEs. when not compiles(task): @@ -18,6 +16,8 @@ const testing = headlessTesting or nimbleTesting # This does not make the playdate api callable, only the types (header files) are available. const useHostOS = defined(useHostOS) +let playdateSdkPath = sdkPath() + if not testing and not useHostOS: switch("noMain", "on") switch("backend", "c") @@ -37,7 +37,7 @@ switch("passC", "-DTARGET_EXTENSION=1") switch("passC", "-Wall") switch("passC", "-Wno-unknown-pragmas") switch("passC", "-Wdouble-promotion") -switch("passC", "-I" & sdkPath() / "C_API") +switch("passC", "-I" & playdateSdkPath / "C_API") if not useHostOS: echo "Setting os to any" @@ -69,7 +69,7 @@ when defined(device): switch("passL", "-nostartfiles") switch("passL", "-mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-sp-d16 -D__FPU_USED=1") - switch("passL", "-T" & sdkPath() / "C_API" / "buildsupport" / "link_map.ld") + switch("passL", "-T" & playdateSdkPath / "C_API" / "buildsupport" / "link_map.ld") switch("passL", "-Wl,-Map=game.map,--cref,--gc-sections,--emit-relocs") switch("passL", "--entry eventHandlerShim") switch("passL", "-lc -lm -lgcc") @@ -167,7 +167,7 @@ else: # they get compiled in the correct nimcache folder. # Windows doesn't like having setup.c compiled. if defined(device) or not defined(windows): - switch("compile", sdkPath() / "C_API" / "buildsupport" / "setup.c") + switch("compile", playdateSdkPath / "C_API" / "buildsupport" / "setup.c") # Overrides the nim memory management code to ensure it uses the playdate allocator - patchFile("stdlib", "malloc", currentSourcePath().parentDir() /../ "bindings" / "malloc") \ No newline at end of file + patchFile("stdlib", "malloc", currentSourcePath().parentDir() /../ "bindings" / "malloc") diff --git a/src/playdate/build/nimble.nim b/src/playdate/build/nimble.nim index 422e461..c05345e 100644 --- a/src/playdate/build/nimble.nim +++ b/src/playdate/build/nimble.nim @@ -1,146 +1,18 @@ -import sequtils, strutils, os, strformat - -import utils # This file is designed to be `included` directly from a nimble file, which will make `switch` and `task` # implicitly available. This block just fixes auto-complete in IDEs when not compiles(task): import system/nimscript - -proc bundlePDX() = - ## Bundles pdx file using parent directory name. - echo("pdc version:") - exec(pdcPath() & " --version") - exec(pdcPath() & " --verbose -sdkpath " & sdkPath() & " source " & - thisDir().splitPath.tail) - -proc postBuild(target: Target) = - ## Performs post-build cleanup and prepares files for bundling. - case target: - of simulator: - if defined(windows): - mvFile(projectName() & ".exe", "source" / "pdex.dll") - elif defined(macosx): - mvFile(projectName(), "source" / "pdex.dylib") - rmDir("source" / "pdex.dSYM") - mvFile(projectName() & ".dSYM", "source" / "pdex.dSYM") - elif defined(linux): - mvFile(projectName(), "source" / "pdex.so") - of device: - if defined(windows): - mvFile(projectName() & ".exe", "source" / "pdex.elf") - else: - mvFile(projectName(), "source" / "pdex.elf") - rmFile("game.map") - -before clean: - let args = taskArgs("clean") - # Used to remove debug (_d) and release (_r) cache folders. - let baseCacheDir = nimcacheDir()[0..^2] - if args.contains("simulator"): - rmDir((baseCacheDir & "d") / $Target.simulator) - rmDir((baseCacheDir & "r") / $Target.simulator) - rmDir("source" / "pdex.dSYM") - rmFile("source" / "pdex.dylib") - rmFile("source" / "pdex.dll") - rmFile("source" / "pdex.so") - elif args.contains("device"): - rmDir((baseCacheDir & "d") / $Target.device) - rmDir((baseCacheDir & "r") / $Target.device) - rmFile("source" / "pdex.bin") - rmFile("source" / "pdex.elf") - else: - rmDir((baseCacheDir & "d")) - rmDir((baseCacheDir & "r")) - rmDir(nimcacheDir()) - rmDir(pdxName()) - rmDir("source" / "pdex.dSYM") - rmFile("source" / "pdex.bin") - rmFile("source" / "pdex.dylib") - rmFile("source" / "pdex.dll") - rmFile("source" / "pdex.so") - rmFile("source" / "pdex.elf") - rmFile("game.map") - rmFile(projectName()) - rmFile(projectName() & ".exe") - task simulator, "Build for the simulator": - let args = taskArgs("simulator") - if args.contains("release"): - nimble "-d:simulator", "-d:release", "build", "--verbose" - else: - nimble "-d:simulator", "-d:debug", "build", "--verbose" - postBuild(Target.simulator) - bundlePDX() + exec "pdn simulator" task simulate, "Build and run in the simulator": - nimble "simulator" - exec (simulatorPath(open = true) & " " & pdxName()) + exec "pdn simulate" task device, "Build for the device": - let args = taskArgs("device") - if args.contains("debug"): - nimble "-d:device", "-d:debug", "build", "--verbose" - else: - nimble "-d:device", "-d:release", "build", "--verbose" - postBuild(Target.device) - bundlePDX() - -task all, "Build for both the simulator and the device": - let args = taskArgs("all") - var simulatorBuild = "debug" - var deviceBuild = "release" - # Only release device build are supported on macOS at the moment. - if args.contains("debug") and not defined(macosx): - deviceBuild = "debug" - elif args.contains("release"): - simulatorBuild = "release" - nimble "-d:simulator", fmt"-d:{simulatorBuild}", "build", "--verbose" - postBuild(Target.simulator) - nimble "-d:device", fmt"-d:{deviceBuild}", "build", "--verbose" - postBuild(Target.device) - bundlePDX() + exec "pdn device" task configure, "Initialize the build structure": - ## Creates a default source directory if it doesn't already exist - - # Calling `sdkPath` will ensure the SDK environment variable is saved - # to the config path - discard sdkPath() - - if not dirExists("source"): - mkDir "source" - - if not fileExists("source/pdxinfo"): - let cartridgeName = projectName() - .replace("_", " ") - .split(" ") - .map(proc(s: string): string = s.capitalizeAscii()) - .join(" ") - let bundleAuthor = author - .toLower() - .replace(" ", "") - .replace("-", "") - .replace("_", "") - let bundleProjectName = projectName() - .toLower() - .replace(" ", "") - .replace("-", "") - .replace("_", "") - writeFile( - "source/pdxinfo", - [ - "name=" & cartridgeName, - "author=" & author, - "description=" & description, - "bundleId=com." & bundleAuthor & "." & bundleProjectName - ].join("\n") - ) - - if not fileExists( ".gitignore"): - ".gitignore".writeFile([ - pdxName(), - "source/pdex.*", - "*.dSYM" - ].join("\n")) + # No longer required + discard diff --git a/src/playdate/build/utils.nim b/src/playdate/build/utils.nim index d78f95f..a54b994 100644 --- a/src/playdate/build/utils.nim +++ b/src/playdate/build/utils.nim @@ -1,74 +1,32 @@ -import sequtils, strutils, os, json +import std/[os, options] -when not compiles(task): - import system/nimscript - -type Target* = enum - ## Target of the compilation process, simulator or device - simulator = "simulator" - device = "device" - -type CompileInstructions* = object - compile: seq[array[2, string]] - -type BuildFail* = object of Defect +type + BuildFail* = object of Defect +# This file is used by both nim proper and nimscript. They have different names +# for the `createDir` method, so we need to map between them +when not declared(mkDir): + template mkDir(dir) = createDir(dir) const SDK_ENV_VAR* = "PLAYDATE_SDK_PATH" +const playdateSdkPath {.strDefine.} = "" -proc nimble*(args: varargs[string]) = - ## Executes nimble with the given set of arguments - exec @["nimble"].concat(args.toSeq).join(" ") - -proc pdxName*(): string = - ## The name of the pdx file to generate, same as the project folder name - getCurrentDir().splitPath.tail & ".pdx" - -proc sdkPath*(): string = +proc sdkPath*(inputParam: Option[string] = none(string)): string = ## Returns the path of the playdate SDK - let fromEnv = getEnv(SDK_ENV_VAR) - let sdkPathCache = getConfigDir() / projectName() / SDK_ENV_VAR - - if fromEnv != "": - mkDir(sdkPathCache.parentDir) - writeFile(sdkPathCache, fromEnv) - return fromEnv - - if fileExists(sdkPathCache): - let fromFile = readFile(sdkPathCache) - if fromFile != "": - echo "Read SDK path from file: " & sdkPathCache - echo "SDK Path: " & fromFile - return fromFile - - raise BuildFail.newException("SDK environment variable is not set: " & SDK_ENV_VAR) - -proc simulatorPath*(open: bool = false): string = - ## Returns the path of the playdate simulator - if defined(windows): - return sdkPath() / "bin" / "PlaydateSimulator.exe" - elif defined(macosx): - return (if open: "open " else: "") & sdkPath() / "bin" / "Playdate\\ Simulator.app" - else: - return sdkPath() / "bin" / "PlaydateSimulator" - -proc pdcPath*(): string = - ## Returns the path of the pdc playdate utility - return sdkPath() / "bin" / "pdc" - -proc filesToCompile*(target: Target): seq[string] = - ## Returns the list of C files that have to be compiled - let jsonString = readFile(nimcacheDir() / $target / projectName() & ".json") - let instructions = parseJson(jsonString).to(CompileInstructions) - - return instructions.compile.map( - proc(entry: array[2, string]): string = - return entry[0] - ) - -proc taskArgs*(taskName: string): seq[string] = - ## Returns the arguments the current task `taskName` has received - let args = command_line_params() - let argStart = args.find(taskName) + 1 - return args[argStart..^1] \ No newline at end of file + let sdkPathCache = getConfigDir() / "playdate-nim" / SDK_ENV_VAR + + if inputParam.isSome: + result = inputParam.get + elif playdateSdkPath != "": + result = playdateSdkPath + elif getEnv(SDK_ENV_VAR) != "": + result = getEnv(SDK_ENV_VAR) + elif sdkPathCache.fileExists: + result = readFile(sdkPathCache) + + if result == "": + raise BuildFail.newException("Unable to determine the path to the playdate SDK") + + mkDir(sdkPathCache.parentDir) + writeFile(sdkPathCache, result) diff --git a/tests/.gitignore b/tests/.gitignore index b74210d..6aa4a90 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1,3 +1,6 @@ *.pdx source/pdex.* *.dSYM +playdate_tests.pdx.zip +playdate_tests.pdx +source/pdxinfo \ No newline at end of file diff --git a/tests/source/pdxinfo b/tests/source/pdxinfo deleted file mode 100644 index 0dd241d..0000000 --- a/tests/source/pdxinfo +++ /dev/null @@ -1,4 +0,0 @@ -name=Playdate Tests -author=Samuele Zolfanelli -description=Unit tests for the Playdate Nim bindings -bundleId=com.samdze.playdate_tests \ No newline at end of file From 35cbb83fefc57a160ad970e3b1800a45e7fe6fc7 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Thu, 13 Feb 2025 18:57:55 +0100 Subject: [PATCH 099/101] FIX Mac simulator path --- src/playdate/build/actions.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/playdate/build/actions.nim b/src/playdate/build/actions.nim index 1c23e07..3c2e2a4 100644 --- a/src/playdate/build/actions.nim +++ b/src/playdate/build/actions.nim @@ -177,7 +177,7 @@ proc runSimulator*(conf: PlaydateConf) = when defined(windows): exec(conf.sdkPath / "bin" / "PlaydateSimulator.exe", conf.pdxName) elif defined(macosx): - exec("open", conf.sdkPath / "bin" / "Playdate\\ Simulator.app", conf.pdxName) + exec("open", conf.sdkPath / "bin" / "Playdate Simulator.app", conf.pdxName) else: exec(conf.sdkPath / "bin" / "PlaydateSimulator", conf.pdxName) From f599e905f33fccd8838f1ee00a9fbdcee2483fd5 Mon Sep 17 00:00:00 2001 From: Nycto Date: Fri, 14 Feb 2025 17:20:10 -0800 Subject: [PATCH 100/101] Update readme to mention pdn auto-config --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 1e0046f..4099698 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,13 @@ You can also build for simulator and launch it in one command: pdn simulate ``` +Note that the `pdn` command attempts to configure your environment as needed to +complete the build. This includes creating a `pdxinfo` file automatically, updating your +`config.nims`, and adding entries to your `.gitignore`. If you don't want this behavior, you +can add the `--no-auto-config` flag, which will disable this. + +## Examples + The example project `playdate_example` also contains VSCode launch configurations to build, start and debug your Nim application from the editor. Each project contains a `config.nims` file that can be edited to customize how the project should be built, e.g. adding libraries or other external code. From d95cd14174bb881516df8c2716ca7c3e818b0f1e Mon Sep 17 00:00:00 2001 From: Nycto Date: Thu, 13 Feb 2025 21:51:45 -0800 Subject: [PATCH 101/101] Change version to 0.22.0 --- playdate.nimble | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playdate.nimble b/playdate.nimble index 134a215..2bc923f 100644 --- a/playdate.nimble +++ b/playdate.nimble @@ -1,6 +1,6 @@ # Package -version = "0.21.0" +version = "0.22.0" author = "Samuele Zolfanelli" description = "Playdate Nim bindings with extra features." license = "MIT"