fireblade-ecs/Sources/FirebladeECS/ManagedContiguousArray.swift

132 lines
3.3 KiB
Swift

//
// ManagedContiguousArray.swift
// FirebladeECS
//
// Created by Christian Treffs on 28.10.17.
//
private let pow2: [Int] = [ 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824, 2147483648, 4294967296
]
private func nearestToPow2(_ value: Int) -> Int {
let exp = (value.bitWidth-value.leadingZeroBitCount)
return pow2[exp]
}
public protocol ManagedContiguousArrayProtocol: class {
associatedtype Element
static var chunkSize: Int { get }
init(minCount: Int)
var count: Int { get }
func insert(_ element: Element, at index: Int)
func has(_ index: Int) -> Bool
func get(at index: Int) -> Element?
func remove(at index: Int)
}
public class ManagedContiguousArray: ManagedContiguousArrayProtocol {
public static var chunkSize: Int = 4096
public typealias Element = Any
var _count: Int = 0
var _store: ContiguousArray<Element?> = []
public required init(minCount: Int = chunkSize) {
_store = ContiguousArray<Element?>(repeating: nil, count: minCount)
}
public var count: Int {
return _count
}
public func insert(_ element: Element, at index: Int) {
if needsToGrow(index) {
grow(including: index)
}
if _store[index] == nil {
_count += 1
}
_store[index] = element
}
public func has(_ index: Int) -> Bool {
if _store.count <= index { return false }
return _store[index] != nil
}
public func get(at index: Int) -> Element? {
return _store[index]
}
public func remove(at index: Int) {
if _store[index] != nil {
_count -= 1
}
return _store[index] = nil
}
internal func needsToGrow(_ index: Int) -> Bool {
return index > _store.count - 1
}
internal func grow(including index: Int) {
//var t = Timer()
//t.start()
let newCapacity: Int = nearest(to: index)
let count: Int = newCapacity-_store.count
//_store.reserveCapacity(newCapacity)
for _ in 0..<count {
_store.append(nil)
}
//t.stop()
//print("did grow to \(newCapacity) in \(t.milliSeconds)ms")
}
internal func nearest(to index: Int) -> Int {
let delta = Float(index) / Float(ManagedContiguousArray.chunkSize)
let multiplier = Int(delta) + 1
return multiplier * ManagedContiguousArray.chunkSize
}
}
public class ContiguousComponentArray: ManagedContiguousArray {
public typealias Element = Component
}
public class ContiguousEntityIdArray: ManagedContiguousArray {
public typealias Element = EntityIdentifier
}
/*
public func insert(_ element: Element, at entityIdx: EntityIndex) {
super.insert(element, at: entityIdx)
}
public func has(_ entityIdx: EntityIndex) -> Bool {
if _store.count <= entityIdx { return false }
return _store[entityIdx] != nil
}
public func get(at entityIdx: EntityIndex) -> Element? {
return _store[entityIdx]
}
public func remove(at entityIdx: EntityIndex) {
return _store[entityIdx] = nil
}
fileprivate func needsToGrow(_ entityId: EntityIndex) -> Bool {
return entityId > _store.count - 1
}
fileprivate func grow(to minIndex: Int) {
let newCapacity: Int = nearestToPow2(minIndex)
let count: Int = newCapacity-_store.count
let nilElements: ContiguousArray<Element?> = ContiguousArray<Element?>.init(repeating: nil, count: count)
_store.reserveCapacity(newCapacity)
_store.append(contentsOf: nilElements)
}
*/