fix(ludic.physics): a removed walker's place is taken again, and phys_close keeps the lists it empties - nothing grows per horse called or per world swap

tests/reuse_test: 200 walkers made and removed hold one place and 0 bytes of heap (Os.heap_bytes);
twenty closes and opens keep the same shape and walker lists.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-28 13:05:28 +03:00
parent e6729b3123
commit 6e132d25c8
3 changed files with 55 additions and 4 deletions

View file

@ -16,14 +16,15 @@ export function phys_is_open(physics_st: PhysicsState) -> bool { return physics_
# which world this is: a body, shape or walker id kept from an older one means nothing now
export function phys_generation(physics_st: PhysicsState) -> int { return physics_st.ph_gen }
# everything let go: the world, every body in it and every shape (a world swap, a quit)
# everything let go: the world, every body in it and every shape (a world swap, a quit); the lists
# that held them are emptied and kept, since nothing is given back
export function phys_close(physics_st: mut PhysicsState) -> void {
if physics_st.ph_walkers != null {
for i in 0 .. len(physics_st.ph_walkers) {
if physics_st.ph_walkers[i] != null { jph_char_free(physics_st.ph_walkers[i]) }
}
}
physics_st.ph_walkers = new []pointer
if physics_st.ph_walkers != null { List.clear(physics_st.ph_walkers) }
if physics_st.ph_world != null { jph_world_free(physics_st.ph_world) }
physics_st.ph_world = null
if physics_st.ph_shapes != null {
@ -31,7 +32,7 @@ export function phys_close(physics_st: mut PhysicsState) -> void {
if physics_st.ph_shapes[i] != null { jph_shape_free(physics_st.ph_shapes[i]) }
}
}
physics_st.ph_shapes = new []pointer
if physics_st.ph_shapes != null { List.clear(physics_st.ph_shapes) }
List.clear(physics_st.ph_spare)
List.clear(physics_st.ph_floats)
List.clear(physics_st.ph_float_k)

View file

@ -0,0 +1,42 @@
# reuse_test.ludic - what is taken away is given back: a walker made and removed two hundred times
# holds one place in the list and no more heap, and a world closed and opened again keeps its lists
import "ludic.physics"
import "ludic.base"
program ReuseTest {
numbers float
test "a walker made and removed takes the same place and grows nothing" (physics_st: mut PhysicsState) {
expect(phys_open(physics_st, 64, 1))
let w = phys_walker_add(physics_st, 0.4, 1.8, 0.0, 0.0, 0.0, 50.0, 80.0)
phys_walker_remove(physics_st, w)
let before = Os.heap_bytes()
for k in 0 .. 200 {
let id = phys_walker_add(physics_st, 0.4, 1.8, float(k), 0.0, 0.0, 50.0, 80.0)
expect_eq(id, w)
phys_walker_remove(physics_st, id)
}
let grew = Os.heap_bytes() - before
print(`reuse: 200 walkers made and removed, {len(physics_st.ph_walkers)} place, heap {grew} bytes`)
expect_eq(len(physics_st.ph_walkers), 1)
expect(grew < long(1024))
phys_close(physics_st)
}
test "a world closed and opened again keeps the lists it held" (physics_st: mut PhysicsState) {
expect(phys_open(physics_st, 64, 1))
phys_box(physics_st, 1.0, 1.0, 1.0)
phys_walker_add(physics_st, 0.4, 1.8, 0.0, 0.0, 0.0, 50.0, 80.0)
let shapes = physics_st.ph_shapes
let walkers = physics_st.ph_walkers
for k in 0 .. 20 {
phys_close(physics_st)
expect(phys_open(physics_st, 64, 1))
phys_box(physics_st, 1.0, 1.0, 1.0)
phys_walker_add(physics_st, 0.4, 1.8, 0.0, 0.0, 0.0, 50.0, 80.0)
}
expect(physics_st.ph_shapes == shapes)
expect(physics_st.ph_walkers == walkers)
expect_eq(phys_shapes(physics_st), 1)
phys_close(physics_st)
}
}

View file

@ -27,7 +27,15 @@ function ph_walker(physics_st: PhysicsState, id: int) -> pointer {
export function phys_walker_add(physics_st: mut PhysicsState, r: float, h: float, x: float, y: float, z: float, max_slope: float, mass: float) -> int {
if physics_st.ph_world == null { return -1 }
ph_buffers()
push(physics_st.ph_walkers, jph_char_new(physics_st.ph_world, r, h, x, y, z, max_slope, mass))
let k = jph_char_new(physics_st.ph_world, r, h, x, y, z, max_slope, mass)
# a removed walker's place is taken again, so a horse called and sent away grows nothing
for i in 0 .. len(physics_st.ph_walkers) {
if physics_st.ph_walkers[i] == null {
physics_st.ph_walkers[i] = k
return i
}
}
push(physics_st.ph_walkers, k)
return len(physics_st.ph_walkers) - 1
}