builtin: support a.flags.set(.noslices | .noshrink), use it in the particles example (#13818)
parent
a4ab3c1f14
commit
5b492e26dd
|
@ -19,8 +19,8 @@ mut:
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut s System) init(sc SystemConfig) {
|
pub fn (mut s System) init(sc SystemConfig) {
|
||||||
unsafe { s.pool.flags.set(.noslices) }
|
unsafe { s.pool.flags.set(.noslices | .noshrink) }
|
||||||
unsafe { s.bin.flags.set(.noslices) }
|
unsafe { s.bin.flags.set(.noslices | .noshrink) }
|
||||||
for i := 0; i < sc.pool; i++ {
|
for i := 0; i < sc.pool; i++ {
|
||||||
p := new(vec2.Vec2{f32(s.width) * 0.5, f32(s.height) * 0.5})
|
p := new(vec2.Vec2{f32(s.width) * 0.5, f32(s.height) * 0.5})
|
||||||
s.bin << p
|
s.bin << p
|
||||||
|
@ -29,12 +29,19 @@ pub fn (mut s System) init(sc SystemConfig) {
|
||||||
|
|
||||||
pub fn (mut s System) update(dt f64) {
|
pub fn (mut s System) update(dt f64) {
|
||||||
mut p := &Particle(0)
|
mut p := &Particle(0)
|
||||||
|
mut moved := 0
|
||||||
for i := 0; i < s.pool.len; i++ {
|
for i := 0; i < s.pool.len; i++ {
|
||||||
p = s.pool[i]
|
p = s.pool[i]
|
||||||
p.update(dt)
|
p.update(dt)
|
||||||
if p.is_dead() {
|
if p.is_dead() {
|
||||||
s.bin << p
|
s.bin << p
|
||||||
s.pool.delete(i)
|
s.pool.delete(i)
|
||||||
|
moved++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$if trace_moves_spool_to_sbin ? {
|
||||||
|
if moved != 0 {
|
||||||
|
eprintln('${moved:4} particles s.pool -> s.bin')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,6 +71,7 @@ pub fn (mut s System) explode(x f32, y f32) {
|
||||||
mut reserve := 500
|
mut reserve := 500
|
||||||
center := vec2.Vec2{x, y}
|
center := vec2.Vec2{x, y}
|
||||||
mut p := &Particle(0)
|
mut p := &Particle(0)
|
||||||
|
mut moved := 0
|
||||||
for i := 0; i < s.bin.len && reserve > 0; i++ {
|
for i := 0; i < s.bin.len && reserve > 0; i++ {
|
||||||
p = s.bin[i]
|
p = s.bin[i]
|
||||||
p.reset()
|
p.reset()
|
||||||
|
@ -75,8 +83,14 @@ pub fn (mut s System) explode(x f32, y f32) {
|
||||||
p.life_time = rand.f64_in_range(500, 2000) or { 500 }
|
p.life_time = rand.f64_in_range(500, 2000) or { 500 }
|
||||||
s.pool << p
|
s.pool << p
|
||||||
s.bin.delete(i)
|
s.bin.delete(i)
|
||||||
|
moved++
|
||||||
reserve--
|
reserve--
|
||||||
}
|
}
|
||||||
|
$if trace_moves_sbin_to_spool ? {
|
||||||
|
if moved != 0 {
|
||||||
|
eprintln('${moved:4} particles s.bin -> s.pool')
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut s System) free() {
|
pub fn (mut s System) free() {
|
||||||
|
|
|
@ -22,7 +22,8 @@ pub mut:
|
||||||
|
|
||||||
[flag]
|
[flag]
|
||||||
pub enum ArrayFlags {
|
pub enum ArrayFlags {
|
||||||
noslices
|
noslices // when <<, `.noslices` will free the old data block immediately (you have to be sure, that there are *no slices* to that specific array). TODO: integrate with reference counting/compiler support for the static cases.
|
||||||
|
noshrink // when `.noslices` and `.noshrink` are *both set*, .delete(x) will NOT allocate new memory and free the old. It will just move the elements in place, and adjust .len.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal function, used by V (`nums := []int`)
|
// Internal function, used by V (`nums := []int`)
|
||||||
|
@ -283,6 +284,14 @@ pub fn (mut a array) delete_many(i int, size int) {
|
||||||
panic('array.delete: index out of range (i == $i$endidx, a.len == $a.len)')
|
panic('array.delete: index out of range (i == $i$endidx, a.len == $a.len)')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if a.flags.all(.noshrink | .noslices) {
|
||||||
|
unsafe {
|
||||||
|
vmemmove(&byte(a.data) + i * a.element_size, &byte(a.data) + (i + size) * a.element_size,
|
||||||
|
(a.len - i - size) * a.element_size)
|
||||||
|
}
|
||||||
|
a.len -= size
|
||||||
|
return
|
||||||
|
}
|
||||||
// Note: if a is [12,34], a.len = 2, a.delete(0)
|
// Note: if a is [12,34], a.len = 2, a.delete(0)
|
||||||
// should move (2-0-1) elements = 1 element (the 34) forward
|
// should move (2-0-1) elements = 1 element (the 34) forward
|
||||||
old_data := a.data
|
old_data := a.data
|
||||||
|
@ -441,6 +450,8 @@ fn (a array) slice(start int, _end int) array {
|
||||||
panic('array.slice: slice bounds out of range ($start < 0)')
|
panic('array.slice: slice bounds out of range ($start < 0)')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// TODO: integrate reference counting
|
||||||
|
// a.flags.clear(.noslices)
|
||||||
offset := start * a.element_size
|
offset := start * a.element_size
|
||||||
data := unsafe { &byte(a.data) + offset }
|
data := unsafe { &byte(a.data) + offset }
|
||||||
l := end - start
|
l := end - start
|
||||||
|
@ -461,6 +472,7 @@ fn (a array) slice(start int, _end int) array {
|
||||||
// that get the last 3 elements of the array otherwise it return an empty array.
|
// that get the last 3 elements of the array otherwise it return an empty array.
|
||||||
// This function always return a valid array.
|
// This function always return a valid array.
|
||||||
fn (a array) slice_ni(_start int, _end int) array {
|
fn (a array) slice_ni(_start int, _end int) array {
|
||||||
|
// a.flags.clear(.noslices)
|
||||||
mut end := _end
|
mut end := _end
|
||||||
mut start := _start
|
mut start := _start
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
fn show_array(name string, a []int) {
|
||||||
|
eprintln('${name:10} .flags: ${a.flags:34} | .cap: ${a.cap:2} | .len: ${a.len:2} | .data: $a.data | $a')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trace_delete_elements(name string, mut a []int) int {
|
||||||
|
a.delete_many(5, 3)
|
||||||
|
show_array(name, a)
|
||||||
|
a << 55
|
||||||
|
show_array(name, a)
|
||||||
|
a << 66
|
||||||
|
show_array(name, a)
|
||||||
|
a << 77
|
||||||
|
res := a.cap
|
||||||
|
eprintln(' << ${name:10} .cap: $a.cap >>')
|
||||||
|
show_array(name, a)
|
||||||
|
a << 88
|
||||||
|
show_array(name, a)
|
||||||
|
a << 99
|
||||||
|
show_array(name, a)
|
||||||
|
eprintln('-------------------------------')
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_array_cap_shrinkage_after_deletion() {
|
||||||
|
mut a := [0]
|
||||||
|
mut middle_cap := 0
|
||||||
|
|
||||||
|
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||||
|
middle_cap = trace_delete_elements('normal', mut a)
|
||||||
|
assert middle_cap == 14
|
||||||
|
assert a.len == 12
|
||||||
|
assert a.cap == 14
|
||||||
|
|
||||||
|
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||||
|
unsafe { a.flags.set(.noslices) }
|
||||||
|
middle_cap = dump(trace_delete_elements('noslices', mut a))
|
||||||
|
assert middle_cap == 14
|
||||||
|
assert a.len == 12
|
||||||
|
assert a.cap == 14
|
||||||
|
|
||||||
|
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||||
|
unsafe { a.flags.set(.noshrink) }
|
||||||
|
middle_cap = dump(trace_delete_elements('noshrink', mut a))
|
||||||
|
assert middle_cap == 14
|
||||||
|
assert a.len == 12
|
||||||
|
assert a.cap == 14
|
||||||
|
|
||||||
|
// Note: when *both* flags are set, the memory block for the array
|
||||||
|
// should NOT shrink on deleting array elements, thus << after the
|
||||||
|
// deletion, will still have space (till .cap is reached).
|
||||||
|
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||||
|
unsafe { a.flags.set(.noslices | .noshrink) }
|
||||||
|
middle_cap = dump(trace_delete_elements('both', mut a))
|
||||||
|
assert middle_cap == 10
|
||||||
|
assert a.len == 12
|
||||||
|
assert a.cap == 20
|
||||||
|
}
|
Loading…
Reference in New Issue