// // SparseSet.swift // FirebladeECS // // Created by Christian Treffs on 30.10.17. // public class SparseSet: UniformStorage, Sequence { public typealias Index = Int private typealias DenseIndex = Int private var size: Int = 0 private var dense: ContiguousArray private var sparse: [Index: DenseIndex] private typealias Pair = (key: Index, value: Element) public init() { dense = ContiguousArray() sparse = [Index: DenseIndex]() } deinit { clear() } public var count: Int { return size } var capacitySparse: Int { return sparse.capacity } var capacityDense: Int { return dense.capacity } public func has(_ index: Index) -> Bool { return sparse[index] ?? Int.max < count && dense[sparse[index]!] != nil } public func add(_ element: Element, at index: Index) { if has(index) { return } sparse[index] = count let entry: Pair = Pair(key: index, value: element) dense.append(entry) size += 1 } public func get(at index: Index) -> Element? { guard has(index) else { return nil } guard let sIdx = sparse[index] else { return nil } return dense[sIdx]?.value } public func remove(at index: Index) { guard has(index) else { return } guard let removeIdx: DenseIndex = sparse[index] else { return } let lastIdx: DenseIndex = count - 1 dense.swapAt(removeIdx, lastIdx) sparse[index] = nil guard let swapped: Pair = dense[removeIdx] else { return } sparse[swapped.key] = removeIdx dense.removeLast() size -= 1 if size == 0 { clear(keepingCapacity: false) } } public func clear(keepingCapacity: Bool = false) { size = 0 dense.removeAll(keepingCapacity: keepingCapacity) sparse.removeAll(keepingCapacity: keepingCapacity) } public func makeIterator() -> SparseSetIterator { return SparseSetIterator(self) } // MARK: - SparseIterator public struct SparseSetIterator: IteratorProtocol { private let sparseSet: SparseSet private var iterator: IndexingIterator> init(_ sparseSet: SparseSet) { self.sparseSet = sparseSet self.iterator = sparseSet.dense.makeIterator() } mutating public func next() -> Element? { guard let next: Pair = iterator.next() as? Pair else { return nil } return next.value as? Element } } } // MARK: - specialized sparse sets public class SparseComponentSet: SparseSet { public typealias Index = EntityIndex } public class SparseEntityIdentifierSet: SparseSet { public typealias Index = EntityIndex }