mirror of
				https://github.com/Ukendio/jecs.git
				synced 2025-11-04 02:49:18 +00:00 
			
		
		
		
	Remove archetype recycling
This commit is contained in:
		
							parent
							
								
									210d62d463
								
							
						
					
					
						commit
						7b253e1c2a
					
				
					 2 changed files with 113 additions and 138 deletions
				
			
		
							
								
								
									
										238
									
								
								jecs.luau
									
									
									
									
									
								
							
							
						
						
									
										238
									
								
								jecs.luau
									
									
									
									
									
								
							| 
						 | 
					@ -19,8 +19,7 @@ export type Archetype = {
 | 
				
			||||||
	type: string,
 | 
						type: string,
 | 
				
			||||||
	entities: { Entity },
 | 
						entities: { Entity },
 | 
				
			||||||
	columns: { Column },
 | 
						columns: { Column },
 | 
				
			||||||
	columns_map: { [Id]: Column },
 | 
						columns_map: { [Id]: Column }
 | 
				
			||||||
	dead: boolean,
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type QueryInner = {
 | 
					export type QueryInner = {
 | 
				
			||||||
| 
						 | 
					@ -861,8 +860,7 @@ local function archetype_create(world: World, id_types: { Id }, ty, prev: i53?):
 | 
				
			||||||
		entities = {},
 | 
							entities = {},
 | 
				
			||||||
		id = archetype_id,
 | 
							id = archetype_id,
 | 
				
			||||||
		type = ty,
 | 
							type = ty,
 | 
				
			||||||
		types = id_types,
 | 
							types = id_types
 | 
				
			||||||
		dead = false,
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	archetype_register(world, archetype, false)
 | 
						archetype_register(world, archetype, false)
 | 
				
			||||||
| 
						 | 
					@ -901,10 +899,6 @@ local function archetype_ensure(world: World, id_types: { Id }): Archetype
 | 
				
			||||||
	local ty = hash(id_types)
 | 
						local ty = hash(id_types)
 | 
				
			||||||
	local archetype = world.archetype_index[ty]
 | 
						local archetype = world.archetype_index[ty]
 | 
				
			||||||
	if archetype then
 | 
						if archetype then
 | 
				
			||||||
		if archetype.dead then
 | 
					 | 
				
			||||||
			archetype_register(world, archetype)
 | 
					 | 
				
			||||||
			archetype.dead = false :: any
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
		return archetype
 | 
							return archetype
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1076,14 +1070,16 @@ local function archetype_destroy(world: World, archetype: Archetype)
 | 
				
			||||||
	local component_index = world.component_index
 | 
						local component_index = world.component_index
 | 
				
			||||||
	local archetype_edges = world.archetype_edges
 | 
						local archetype_edges = world.archetype_edges
 | 
				
			||||||
	local edges = archetype_edges[archetype.id]
 | 
						local edges = archetype_edges[archetype.id]
 | 
				
			||||||
 | 
						print("delete archetype id", archetype.id, archetype.type)
 | 
				
			||||||
	for id, node in edges do
 | 
						for id, node in edges do
 | 
				
			||||||
 | 
							print("node id", node.id)
 | 
				
			||||||
		archetype_edges[node.id][id] = nil
 | 
							archetype_edges[node.id][id] = nil
 | 
				
			||||||
		edges[id] = nil
 | 
							edges[id] = nil
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	local archetype_id = archetype.id
 | 
						local archetype_id = archetype.id
 | 
				
			||||||
	-- world.archetypes[archetype_id] = nil :: any
 | 
						world.archetypes[archetype_id] = nil :: any
 | 
				
			||||||
	-- world.archetype_index[archetype.type] = nil :: any
 | 
						world.archetype_index[archetype.type] = nil :: any
 | 
				
			||||||
	local columns_map = archetype.columns_map
 | 
						local columns_map = archetype.columns_map
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for id in columns_map do
 | 
						for id in columns_map do
 | 
				
			||||||
| 
						 | 
					@ -1104,8 +1100,6 @@ local function archetype_destroy(world: World, archetype: Archetype)
 | 
				
			||||||
			end
 | 
								end
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
					 | 
				
			||||||
	archetype.dead = true
 | 
					 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local function NOOP() end
 | 
					local function NOOP() end
 | 
				
			||||||
| 
						 | 
					@ -2307,23 +2301,31 @@ local function world_new()
 | 
				
			||||||
		return r
 | 
							return r
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	local function inner_world_add<T, a>(
 | 
						local function inner_world_set<T, a>(world: World, entity: Entity<T>, id: Id<a>, data: a): ()
 | 
				
			||||||
		world: World,
 | 
					 | 
				
			||||||
		entity: Entity<T>,
 | 
					 | 
				
			||||||
		id: Id<a>
 | 
					 | 
				
			||||||
	): ()
 | 
					 | 
				
			||||||
		local entity_index = world.entity_index
 | 
					 | 
				
			||||||
		local record = inner_entity_index_try_get_unsafe(entity :: number)
 | 
							local record = inner_entity_index_try_get_unsafe(entity :: number)
 | 
				
			||||||
		if not record then
 | 
							if not record then
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		local from = record.archetype
 | 
							local from: Archetype = record.archetype
 | 
				
			||||||
		if ECS_IS_PAIR(id::number) then
 | 
					 | 
				
			||||||
		local src = from or ROOT_ARCHETYPE
 | 
							local src = from or ROOT_ARCHETYPE
 | 
				
			||||||
			local edge = archetype_edges[src.id]
 | 
							local column = src.columns_map[id]
 | 
				
			||||||
			local to = edge[id]
 | 
							if column then
 | 
				
			||||||
 | 
								local idr = component_index[id]
 | 
				
			||||||
 | 
								column[record.row] = data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								-- If the archetypes are the same it can avoid moving the entity
 | 
				
			||||||
 | 
								-- and just set the data directly.
 | 
				
			||||||
 | 
								local on_change = idr.on_change
 | 
				
			||||||
 | 
								if on_change then
 | 
				
			||||||
 | 
									on_change(entity, id, data)
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								local to: Archetype
 | 
				
			||||||
			local idr: ComponentRecord
 | 
								local idr: ComponentRecord
 | 
				
			||||||
 | 
								if ECS_IS_PAIR(id::number) then
 | 
				
			||||||
 | 
									local edge = archetype_edges[src.id]
 | 
				
			||||||
 | 
									to = edge[id]
 | 
				
			||||||
				if not to then
 | 
									if not to then
 | 
				
			||||||
					local first = ECS_PAIR_FIRST(id::number)
 | 
										local first = ECS_PAIR_FIRST(id::number)
 | 
				
			||||||
					local wc = ECS_PAIR(first, EcsWildcard)
 | 
										local wc = ECS_PAIR(first, EcsWildcard)
 | 
				
			||||||
| 
						 | 
					@ -2351,38 +2353,105 @@ local function world_new()
 | 
				
			||||||
						idr = component_index[id]
 | 
											idr = component_index[id]
 | 
				
			||||||
					end
 | 
										end
 | 
				
			||||||
					edge[id] = to
 | 
										edge[id] = to
 | 
				
			||||||
			else
 | 
					 | 
				
			||||||
				if to.dead then
 | 
					 | 
				
			||||||
					archetype_register(world, to, true)
 | 
					 | 
				
			||||||
					edge[id] = to
 | 
					 | 
				
			||||||
					archetype_edges[to.id][id] = src
 | 
										archetype_edges[to.id][id] = src
 | 
				
			||||||
					to.dead = false
 | 
									else
 | 
				
			||||||
 | 
										idr = component_index[id]
 | 
				
			||||||
 | 
									end
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									local edges = archetype_edges
 | 
				
			||||||
 | 
									local edge = edges[src.id]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									to = edge[id] :: Archetype
 | 
				
			||||||
 | 
									if not to then
 | 
				
			||||||
 | 
										to = find_archetype_with(world, id, src)
 | 
				
			||||||
 | 
										edge[id] = to
 | 
				
			||||||
 | 
										edges[to.id][id] = src
 | 
				
			||||||
				end
 | 
									end
 | 
				
			||||||
				idr = component_index[id]
 | 
									idr = component_index[id]
 | 
				
			||||||
			end
 | 
								end
 | 
				
			||||||
			if from == to then
 | 
					
 | 
				
			||||||
				return
 | 
					 | 
				
			||||||
			end
 | 
					 | 
				
			||||||
			if from then
 | 
								if from then
 | 
				
			||||||
 | 
									-- If there was a previous archetype, then the entity needs to move the archetype
 | 
				
			||||||
				inner_entity_move(entity_index, entity, record, to)
 | 
									inner_entity_move(entity_index, entity, record, to)
 | 
				
			||||||
			else
 | 
								else
 | 
				
			||||||
				if #to.types > 0 then
 | 
					 | 
				
			||||||
				new_entity(entity, record, to)
 | 
									new_entity(entity, record, to)
 | 
				
			||||||
			end
 | 
								end
 | 
				
			||||||
			end
 | 
					
 | 
				
			||||||
 | 
								column = to.columns_map[id]
 | 
				
			||||||
 | 
								column[record.row] = data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			local on_add = idr.on_add
 | 
								local on_add = idr.on_add
 | 
				
			||||||
 | 
					 | 
				
			||||||
			if on_add then
 | 
								if on_add then
 | 
				
			||||||
				on_add(entity, id)
 | 
									on_add(entity, id, data)
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						local function inner_world_add<T, a>(
 | 
				
			||||||
 | 
							world: World,
 | 
				
			||||||
 | 
							entity: Entity<T>,
 | 
				
			||||||
 | 
							id: Id<a>
 | 
				
			||||||
 | 
						): ()
 | 
				
			||||||
 | 
							local entity_index = world.entity_index
 | 
				
			||||||
 | 
							local record = inner_entity_index_try_get_unsafe(entity :: number)
 | 
				
			||||||
 | 
							if not record then
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
		local to = archetype_traverse_add(world, id, from)
 | 
					
 | 
				
			||||||
		if from == to then
 | 
							local from = record.archetype
 | 
				
			||||||
 | 
							local src = from or ROOT_ARCHETYPE
 | 
				
			||||||
 | 
							if src.columns_map[id] then
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
 | 
							local to: Archetype
 | 
				
			||||||
 | 
							local idr: ComponentRecord
 | 
				
			||||||
 | 
							if ECS_IS_PAIR(id::number) then
 | 
				
			||||||
 | 
								local edge = archetype_edges[src.id]
 | 
				
			||||||
 | 
								to = edge[id]
 | 
				
			||||||
 | 
								if not to then
 | 
				
			||||||
 | 
									local first = ECS_PAIR_FIRST(id::number)
 | 
				
			||||||
 | 
									local wc = ECS_PAIR(first, EcsWildcard)
 | 
				
			||||||
 | 
									idr = component_index[wc]
 | 
				
			||||||
 | 
									if idr and bit32.btest(idr.flags, ECS_ID_IS_EXCLUSIVE) then
 | 
				
			||||||
 | 
										local cr = idr.records[src.id]
 | 
				
			||||||
 | 
										if cr then
 | 
				
			||||||
 | 
											local on_remove = idr.on_remove
 | 
				
			||||||
 | 
											local id_types = src.types
 | 
				
			||||||
 | 
											if on_remove then
 | 
				
			||||||
 | 
												on_remove(entity, id_types[cr])
 | 
				
			||||||
 | 
												src = record.archetype
 | 
				
			||||||
 | 
												id_types = src.types
 | 
				
			||||||
 | 
												cr = idr.records[src.id]
 | 
				
			||||||
 | 
											end
 | 
				
			||||||
 | 
											local dst = table.clone(id_types)
 | 
				
			||||||
 | 
											dst[cr] = id
 | 
				
			||||||
 | 
											to = archetype_ensure(world, dst)
 | 
				
			||||||
 | 
										else
 | 
				
			||||||
 | 
											to = find_archetype_with(world, id, src)
 | 
				
			||||||
 | 
											idr = component_index[id]
 | 
				
			||||||
 | 
										end
 | 
				
			||||||
 | 
									else
 | 
				
			||||||
 | 
										to = find_archetype_with(world, id, src)
 | 
				
			||||||
 | 
										idr = component_index[id]
 | 
				
			||||||
 | 
									end
 | 
				
			||||||
 | 
									edge[id] = to
 | 
				
			||||||
 | 
									archetype_edges[to.id][id] = src
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									idr = component_index[id]
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								local edges = archetype_edges
 | 
				
			||||||
 | 
								local edge = edges[src.id]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								to = edge[id] :: Archetype
 | 
				
			||||||
 | 
								if not to then
 | 
				
			||||||
 | 
									to = find_archetype_with(world, id, src)
 | 
				
			||||||
 | 
									edge[id] = to
 | 
				
			||||||
 | 
									edges[to.id][id] = src
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
								idr = component_index[id]
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if from then
 | 
							if from then
 | 
				
			||||||
			inner_entity_move(entity_index, entity, record, to)
 | 
								inner_entity_move(entity_index, entity, record, to)
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
| 
						 | 
					@ -2391,7 +2460,6 @@ local function world_new()
 | 
				
			||||||
			end
 | 
								end
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		local idr = component_index[id]
 | 
					 | 
				
			||||||
		local on_add = idr.on_add
 | 
							local on_add = idr.on_add
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if on_add then
 | 
							if on_add then
 | 
				
			||||||
| 
						 | 
					@ -2495,102 +2563,6 @@ local function world_new()
 | 
				
			||||||
		return inner_world_target(world, entity, EcsChildOf, 0)
 | 
							return inner_world_target(world, entity, EcsChildOf, 0)
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	local function inner_archetype_traverse_add(id: Id, from: Archetype): Archetype
 | 
					 | 
				
			||||||
		from = from or ROOT_ARCHETYPE
 | 
					 | 
				
			||||||
		if from.columns_map[id] then
 | 
					 | 
				
			||||||
			return from
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
		local edges = archetype_edges
 | 
					 | 
				
			||||||
		local edge = edges[from.id]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		local to = edge[id] :: Archetype
 | 
					 | 
				
			||||||
		if not to then
 | 
					 | 
				
			||||||
			to = find_archetype_with(world, id, from)
 | 
					 | 
				
			||||||
			edge[id] = to
 | 
					 | 
				
			||||||
			edges[to.id][id] = from
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return to
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	local function inner_world_set<T, a>(world: World, entity: Entity<T>, id: Id<a>, data: a): ()
 | 
					 | 
				
			||||||
		local record = inner_entity_index_try_get_unsafe(entity :: number)
 | 
					 | 
				
			||||||
		if not record then
 | 
					 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		local from: Archetype = record.archetype
 | 
					 | 
				
			||||||
		local src = from or ROOT_ARCHETYPE
 | 
					 | 
				
			||||||
		local column = src.columns_map[id]
 | 
					 | 
				
			||||||
		if column then
 | 
					 | 
				
			||||||
			local idr = component_index[id]
 | 
					 | 
				
			||||||
			column[record.row] = data
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			-- If the archetypes are the same it can avoid moving the entity
 | 
					 | 
				
			||||||
			-- and just set the data directly.
 | 
					 | 
				
			||||||
			local on_change = idr.on_change
 | 
					 | 
				
			||||||
			if on_change then
 | 
					 | 
				
			||||||
				on_change(entity, id, data)
 | 
					 | 
				
			||||||
			end
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			local to: Archetype
 | 
					 | 
				
			||||||
			local idr: ComponentRecord
 | 
					 | 
				
			||||||
			if ECS_IS_PAIR(id::number) then
 | 
					 | 
				
			||||||
				local edge = archetype_edges[src.id]
 | 
					 | 
				
			||||||
				to = edge[id]
 | 
					 | 
				
			||||||
				if not to then
 | 
					 | 
				
			||||||
					local first = ECS_PAIR_FIRST(id::number)
 | 
					 | 
				
			||||||
					local wc = ECS_PAIR(first, EcsWildcard)
 | 
					 | 
				
			||||||
					idr = component_index[wc]
 | 
					 | 
				
			||||||
					if idr and bit32.btest(idr.flags, ECS_ID_IS_EXCLUSIVE) then
 | 
					 | 
				
			||||||
						local cr = idr.records[src.id]
 | 
					 | 
				
			||||||
						if cr then
 | 
					 | 
				
			||||||
							local on_remove = idr.on_remove
 | 
					 | 
				
			||||||
							local id_types = src.types
 | 
					 | 
				
			||||||
							if on_remove then
 | 
					 | 
				
			||||||
								on_remove(entity, id_types[cr])
 | 
					 | 
				
			||||||
								src = record.archetype
 | 
					 | 
				
			||||||
								id_types = src.types
 | 
					 | 
				
			||||||
								cr = idr.records[src.id]
 | 
					 | 
				
			||||||
							end
 | 
					 | 
				
			||||||
							local dst = table.clone(id_types)
 | 
					 | 
				
			||||||
							dst[cr] = id
 | 
					 | 
				
			||||||
							to = archetype_ensure(world, dst)
 | 
					 | 
				
			||||||
						else
 | 
					 | 
				
			||||||
							to = find_archetype_with(world, id, src)
 | 
					 | 
				
			||||||
							idr = component_index[id]
 | 
					 | 
				
			||||||
						end
 | 
					 | 
				
			||||||
					else
 | 
					 | 
				
			||||||
						to = find_archetype_with(world, id, src)
 | 
					 | 
				
			||||||
						idr = component_index[id]
 | 
					 | 
				
			||||||
					end
 | 
					 | 
				
			||||||
					edge[id] = to
 | 
					 | 
				
			||||||
					archetype_edges[to.id][id] = src
 | 
					 | 
				
			||||||
				else
 | 
					 | 
				
			||||||
					idr = component_index[id]
 | 
					 | 
				
			||||||
				end
 | 
					 | 
				
			||||||
			else
 | 
					 | 
				
			||||||
				to = inner_archetype_traverse_add(id, from)
 | 
					 | 
				
			||||||
				idr = component_index[id]
 | 
					 | 
				
			||||||
			end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if from then
 | 
					 | 
				
			||||||
				-- If there was a previous archetype, then the entity needs to move the archetype
 | 
					 | 
				
			||||||
				inner_entity_move(entity_index, entity, record, to)
 | 
					 | 
				
			||||||
			else
 | 
					 | 
				
			||||||
				new_entity(entity, record, to)
 | 
					 | 
				
			||||||
			end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			column = to.columns_map[id]
 | 
					 | 
				
			||||||
			column[record.row] = data
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			local on_add = idr.on_add
 | 
					 | 
				
			||||||
			if on_add then
 | 
					 | 
				
			||||||
				on_add(entity, id, data)
 | 
					 | 
				
			||||||
			end
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	local function inner_world_entity<T>(world: World, entity: Entity<T>?): Entity<T>
 | 
						local function inner_world_entity<T>(world: World, entity: Entity<T>?): Entity<T>
 | 
				
			||||||
		if entity then
 | 
							if entity then
 | 
				
			||||||
			local index = ECS_ID(entity :: number)
 | 
								local index = ECS_ID(entity :: number)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -129,6 +129,7 @@ TEST("repeated pairs", function()
 | 
				
			||||||
	CHECK(count == 1)
 | 
						CHECK(count == 1)
 | 
				
			||||||
	CHECK(world:each(p2)() == e2) -- Fails
 | 
						CHECK(world:each(p2)() == e2) -- Fails
 | 
				
			||||||
end)
 | 
					end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST("repro", function()
 | 
					TEST("repro", function()
 | 
				
			||||||
	local world = jecs.world()
 | 
						local world = jecs.world()
 | 
				
			||||||
	local data = world:component()
 | 
						local data = world:component()
 | 
				
			||||||
| 
						 | 
					@ -157,6 +158,7 @@ TEST("repro", function()
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
	CHECK(count == 1)
 | 
						CHECK(count == 1)
 | 
				
			||||||
	count = 0
 | 
						count = 0
 | 
				
			||||||
 | 
						print("----")
 | 
				
			||||||
	world:add(e2v1, jecs.pair(relation, e1v1))
 | 
						world:add(e2v1, jecs.pair(relation, e1v1))
 | 
				
			||||||
	CHECK(world:has(e2v1, jecs.pair(relation, e1v1)))
 | 
						CHECK(world:has(e2v1, jecs.pair(relation, e1v1)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -164,6 +166,7 @@ TEST("repro", function()
 | 
				
			||||||
		count += 1
 | 
							count += 1
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						print(count)
 | 
				
			||||||
	CHECK(count==1)
 | 
						CHECK(count==1)
 | 
				
			||||||
end)
 | 
					end)
 | 
				
			||||||
TEST("bulk", function()
 | 
					TEST("bulk", function()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue