From 4ada634130ea495a21d5d55e7e3e19d5e5650082 Mon Sep 17 00:00:00 2001 From: Christian Treffs Date: Tue, 31 Oct 2017 11:32:07 +0100 Subject: [PATCH] Fix sparse component set performance --- Sources/FirebladeECS/SparseSet.swift | 66 ++++++++++------------------ 1 file changed, 22 insertions(+), 44 deletions(-) diff --git a/Sources/FirebladeECS/SparseSet.swift b/Sources/FirebladeECS/SparseSet.swift index 0777144..8248e84 100644 --- a/Sources/FirebladeECS/SparseSet.swift +++ b/Sources/FirebladeECS/SparseSet.swift @@ -7,43 +7,34 @@ public class SparseComponentSet { public typealias Element = Component - public let chunkSize: Int = 4096 fileprivate typealias ComponentIdx = Int fileprivate var size: Int = 0 - - fileprivate class Pair { - let key: EntityIndex - let value: Element - init(key: EntityIndex, value: Element) { - self.key = key - self.value = value - } - } - fileprivate var dense: ContiguousArray fileprivate var sparse: [EntityIndex: ComponentIdx] + fileprivate typealias Pair = (key: EntityIndex, value: Element) public init() { dense = ContiguousArray() - dense.reserveCapacity(chunkSize) - sparse = [EntityIndex: ComponentIdx].init(minimumCapacity: chunkSize) + sparse = [EntityIndex: ComponentIdx]() + } + + deinit { + clear() } public var count: Int { return size } - internal var capacitySparse: Int { return sparse.count } - internal var capacityDense: Int { return dense.count } + internal var capacitySparse: Int { return sparse.capacity } + internal var capacityDense: Int { return dense.capacity } public func contains(_ entityIdx: EntityIndex ) -> Bool { - guard let compIdx: ComponentIdx = sparse[entityIdx] else { return false } - return compIdx < count && dense[compIdx] != nil + return sparse[entityIdx] != nil && + sparse[entityIdx]! < count && + dense[sparse[entityIdx]!] != nil } @discardableResult public func add(_ element: Element, with entityIdx: EntityIndex ) -> Bool { if contains(entityIdx) { return false } - if needsToGrow(entityIdx) { - grow(including: entityIdx) - } sparse[entityIdx] = count let entry: Pair = Pair(key: entityIdx, value: element) dense.append(entry) @@ -52,52 +43,39 @@ public class SparseComponentSet { } public func get(at entityIdx: EntityIndex) -> Element? { - guard let compIdx: ComponentIdx = sparse[entityIdx] else { return nil } - return dense[compIdx]!.value + guard contains(entityIdx) else { return nil } + return dense[sparse[entityIdx]!]!.value } @discardableResult public func remove(_ entityIdx: EntityIndex ) -> Element? { - guard let compIdx: ComponentIdx = sparse[entityIdx] else { return nil } - let last: Int = count-1 - dense.swapAt(compIdx, last) + guard contains(entityIdx) else { return nil } + let compIdx: ComponentIdx = sparse[entityIdx]! + let lastIdx: ComponentIdx = count-1 + dense.swapAt(compIdx, lastIdx) sparse[entityIdx] = nil let swapped: Pair = dense[compIdx]! sparse[swapped.key] = compIdx let removed: Pair = dense.popLast()!! size -= 1 + if size == 0 { + clear(keepingCapacity: false) + } return removed.value } public func clear(keepingCapacity: Bool = false) { + size = 0 dense.removeAll(keepingCapacity: keepingCapacity) + sparse.removeAll(keepingCapacity: keepingCapacity) } - fileprivate func needsToGrow(_ index: Int) -> Bool { - return index > count - 1 - } - - fileprivate func grow(including index: Int) { - let newCapacity: Int = nearest(to: index) - //let newCount: Int = newCapacity-count - dense.reserveCapacity(newCapacity) - /*for _ in 0.. Int { - let delta = Float(index) / Float(chunkSize) - let multiplier = Int(delta) + 1 - return multiplier * chunkSize - } } extension SparseComponentSet: Sequence { public func makeIterator() -> AnyIterator { var iterator = dense.makeIterator() - return AnyIterator { iterator.next()??.value }