diff --git a/develop/testing/realloc_tests.lua b/develop/testing/realloc_tests.lua index 3863316..c7a755d 100644 --- a/develop/testing/realloc_tests.lua +++ b/develop/testing/realloc_tests.lua @@ -19,10 +19,18 @@ local DOUBLE_TYPEOF = ffi.typeof('double') local DOUBLE_SIZEOF = ffi.sizeof(DOUBLE_TYPEOF) local DOUBLE_STORAGE_TYPEOF = ffi.typeof('$[?]', DOUBLE_TYPEOF) +local STORAGE_SIZES = {} + ---@type evolved.realloc local function float_realloc(old_storage, old_size, new_size) + if old_storage then + assert(STORAGE_SIZES[old_storage] == old_size) + end + local new_storage = ffi.new(FLOAT_STORAGE_TYPEOF, new_size + 1) + STORAGE_SIZES[new_storage] = new_size + if old_storage then ffi.copy(new_storage + 1, old_storage + 1, math.min(old_size, new_size) * FLOAT_SIZEOF) end @@ -32,8 +40,14 @@ end ---@type evolved.realloc local function double_realloc(old_storage, old_size, new_size) + if old_storage then + assert(STORAGE_SIZES[old_storage] == old_size) + end + local new_storage = ffi.new(DOUBLE_STORAGE_TYPEOF, new_size + 1) + STORAGE_SIZES[new_storage] = new_size + if old_storage then ffi.copy(new_storage + 1, old_storage + 1, math.min(old_size, new_size) * DOUBLE_SIZEOF) end @@ -299,3 +313,89 @@ do assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 42) end end + +do + evo.collect_garbage() + + local f1 = evo.builder():name('f1'):realloc(double_realloc):compmove(double_compmove):build() + local f2 = evo.builder():name('f2'):realloc(double_realloc):compmove(double_compmove):build() + + local q1 = evo.builder():include(f1):build() + local q2 = evo.builder():include(f2):build() + + do + local es, ec = evo.multi_spawn(40, { [f2] = 2 }) + for i = 1, ec do + assert(not evo.has(es[i], f1)) + assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 2) + end + evo.batch_destroy(q2) + end + + do + local es, ec = evo.multi_spawn(50, { [f1] = 1, [f2] = 2 }) + for i = 1, ec do + assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 1) + assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 2) + end + + evo.batch_remove(q1, f1) + for i = 1, ec do + assert(not evo.has(es[i], f1)) + assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 2) + end + + evo.batch_destroy(q1, q2) + end + + do + evo.spawn({ [f1] = 1 }) + evo.spawn({ [f2] = 2 }) + evo.spawn({ [f1] = 1, [f2] = 2 }) + end + + evo.collect_garbage() +end + +do + evo.collect_garbage() + + local f1 = evo.builder():name('f1'):realloc(double_realloc):compmove(double_compmove):build() + local f2 = evo.builder():name('f2'):realloc(double_realloc):compmove(double_compmove):build() + + local q1 = evo.builder():include(f1):build() + local q2 = evo.builder():include(f2):build() + + do + local es, ec = evo.multi_spawn(40, { [f1] = 1, [f2] = 2 }) + for i = 1, ec do + assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 1) + assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 2) + end + evo.batch_destroy(q2) + end + + do + local es, ec = evo.multi_spawn(50, { [f1] = 1 }) + for i = 1, ec do + assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 1) + assert(not evo.has(es[i], f2)) + end + + evo.batch_set(q1, f2, 2) + for i = 1, ec do + assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 1) + assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 2) + end + + evo.batch_destroy(q1, q2) + end + + do + evo.spawn({ [f1] = 1 }) + evo.spawn({ [f2] = 2 }) + evo.spawn({ [f1] = 1, [f2] = 2 }) + end + + evo.collect_garbage() +end diff --git a/evolved.lua b/evolved.lua index ca5f11a..9e2b434 100644 --- a/evolved.lua +++ b/evolved.lua @@ -2900,10 +2900,6 @@ function __expand_chunk(chunk, min_capacity) __error_fmt('this operation should be deferred') end - if min_capacity < 4 then - min_capacity = 4 - end - local entity_count = chunk.__entity_count if min_capacity < entity_count then @@ -2922,6 +2918,10 @@ function __expand_chunk(chunk, min_capacity) new_capacity = min_capacity end + if new_capacity < 4 then + new_capacity = 4 + end + if chunk.__has_storage_reallocs then local component_count = chunk.__component_count local component_storages = chunk.__component_storages @@ -2945,13 +2945,12 @@ function __expand_chunk(chunk, min_capacity) end ---@param chunk evolved.chunk -function __shrink_chunk(chunk) +---@param min_capacity integer +function __shrink_chunk(chunk, min_capacity) if __defer_depth <= 0 then __error_fmt('this operation should be deferred') end - local min_capacity = 4 - local entity_count = chunk.__entity_count if min_capacity < entity_count then @@ -3349,10 +3348,28 @@ function __chunk_set(old_chunk, fragment, component) for old_ci = 1, old_component_count do local old_f = old_component_fragments[old_ci] - local new_ci = new_component_indices[old_f] - old_component_storages[old_ci], new_component_storages[new_ci] = - new_component_storages[new_ci], old_component_storages[old_ci] + local new_ci = new_component_indices[old_f] + local new_cr = new_component_reallocs[new_ci] + + if new_cr then + local old_cs = old_component_storages[old_ci] + + local new_cs = new_component_storages[new_ci] + local new_cm = new_component_compmoves[new_ci] + + if new_cm then + new_cm(old_cs, 1, old_entity_count, new_entity_count + 1, new_cs) + else + for old_place = 1, old_entity_count do + local new_place = new_entity_count + old_place + new_cs[new_place] = old_cs[old_place] + end + end + else + old_component_storages[old_ci], new_component_storages[new_ci] = + new_component_storages[new_ci], old_component_storages[old_ci] + end end new_chunk.__entity_count = sum_entity_count @@ -3364,14 +3381,17 @@ function __chunk_set(old_chunk, fragment, component) local new_ci = new_component_indices[old_f] local new_cs = new_component_storages[new_ci] local new_cr = new_component_reallocs[new_ci] - local new_cm = new_component_compmoves[new_ci] - if new_cm then - new_cm(old_cs, 1, old_entity_count, new_entity_count + 1, new_cs) - elseif new_cr then - for old_place = 1, old_entity_count do - local new_place = new_entity_count + old_place - new_cs[new_place] = old_cs[old_place] + if new_cr then + local new_cm = new_component_compmoves[new_ci] + + if new_cm then + new_cm(old_cs, 1, old_entity_count, new_entity_count + 1, new_cs) + else + for old_place = 1, old_entity_count do + local new_place = new_entity_count + old_place + new_cs[new_place] = old_cs[old_place] + end end else __lua_table_move(old_cs, 1, old_entity_count, new_entity_count + 1, new_cs) @@ -3677,10 +3697,28 @@ function __chunk_remove(old_chunk, ...) for new_ci = 1, new_component_count do local new_f = new_component_fragments[new_ci] + local new_cr = new_component_reallocs[new_ci] + local old_ci = old_component_indices[new_f] - old_component_storages[old_ci], new_component_storages[new_ci] = - new_component_storages[new_ci], old_component_storages[old_ci] + if new_cr then + local new_cs = new_component_storages[new_ci] + local new_cm = new_component_compmoves[new_ci] + + local old_cs = old_component_storages[old_ci] + + if new_cm then + new_cm(old_cs, 1, old_entity_count, new_entity_count + 1, new_cs) + else + for old_place = 1, old_entity_count do + local new_place = new_entity_count + old_place + new_cs[new_place] = old_cs[old_place] + end + end + else + old_component_storages[old_ci], new_component_storages[new_ci] = + new_component_storages[new_ci], old_component_storages[old_ci] + end end new_chunk.__entity_count = sum_entity_count @@ -3689,17 +3727,20 @@ function __chunk_remove(old_chunk, ...) local new_f = new_component_fragments[new_ci] local new_cs = new_component_storages[new_ci] local new_cr = new_component_reallocs[new_ci] - local new_cm = new_component_compmoves[new_ci] local old_ci = old_component_indices[new_f] local old_cs = old_component_storages[old_ci] - if new_cm then - new_cm(old_cs, 1, old_entity_count, new_entity_count + 1, new_cs) - elseif new_cr then - for old_place = 1, old_entity_count do - local new_place = new_entity_count + old_place - new_cs[new_place] = old_cs[old_place] + if new_cr then + local new_cm = new_component_compmoves[new_ci] + + if new_cm then + new_cm(old_cs, 1, old_entity_count, new_entity_count + 1, new_cs) + else + for old_place = 1, old_entity_count do + local new_place = new_entity_count + old_place + new_cs[new_place] = old_cs[old_place] + end end else __lua_table_move(old_cs, 1, old_entity_count, new_entity_count + 1, new_cs) @@ -5669,7 +5710,7 @@ function __evolved_collect_garbage() if should_be_purged then __purge_chunk(postorder_chunk) else - __shrink_chunk(postorder_chunk) + __shrink_chunk(postorder_chunk, 0) end end