commit
68b79de729
|
|
@ -0,0 +1,102 @@
|
|||
//
|
||||
// ManagedContiguousArray.swift
|
||||
// FirebladeECS
|
||||
//
|
||||
// Created by Christian Treffs on 28.10.17.
|
||||
//
|
||||
public struct ManagedContiguousArray<Element> {
|
||||
public typealias Index = Int
|
||||
|
||||
@usableFromInline let chunkSize: Int
|
||||
@usableFromInline var size: Int = 0
|
||||
@usableFromInline var store: ContiguousArray<Element?> = []
|
||||
|
||||
public init(minCount: Int = 4096) {
|
||||
chunkSize = minCount
|
||||
store = ContiguousArray<Element?>(repeating: nil, count: minCount)
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
public var count: Int {
|
||||
size
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
@inlinable
|
||||
public mutating func insert(_ element: Element, at index: Int) -> Bool {
|
||||
if needsToGrow(index) {
|
||||
grow(to: index)
|
||||
}
|
||||
if store[index] == nil {
|
||||
size += 1
|
||||
}
|
||||
store[index] = element
|
||||
return true
|
||||
}
|
||||
|
||||
@inlinable
|
||||
public func contains(_ index: Index) -> Bool {
|
||||
if store.count <= index {
|
||||
return false
|
||||
}
|
||||
return store[index] != nil
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
public func get(at index: Index) -> Element? {
|
||||
store[index]
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
public func get(unsafeAt index: Index) -> Element {
|
||||
store[index].unsafelyUnwrapped
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
@inlinable
|
||||
public mutating func remove(at index: Index) -> Bool {
|
||||
if store[index] != nil {
|
||||
size -= 1
|
||||
}
|
||||
store[index] = nil
|
||||
if size == 0 {
|
||||
clear()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@inlinable
|
||||
public mutating func clear(keepingCapacity: Bool = false) {
|
||||
size = 0
|
||||
store.removeAll(keepingCapacity: keepingCapacity)
|
||||
}
|
||||
|
||||
@inlinable
|
||||
func needsToGrow(_ index: Index) -> Bool {
|
||||
index > store.count - 1
|
||||
}
|
||||
|
||||
@inlinable
|
||||
mutating func grow(to index: Index) {
|
||||
let newCapacity: Int = calculateCapacity(to: index)
|
||||
let newCount: Int = newCapacity - store.count
|
||||
store += ContiguousArray<Element?>(repeating: nil, count: newCount)
|
||||
}
|
||||
|
||||
@inlinable
|
||||
func calculateCapacity(to index: Index) -> Int {
|
||||
let delta = Float(index) / Float(chunkSize)
|
||||
let multiplier = Int(delta.rounded(.up)) + 1
|
||||
return multiplier * chunkSize
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Equatable
|
||||
extension ManagedContiguousArray: Equatable where Element: Equatable {
|
||||
public static func == (lhs: ManagedContiguousArray<Element>, rhs: ManagedContiguousArray<Element>) -> Bool {
|
||||
lhs.store == rhs.store
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Codable
|
||||
extension ManagedContiguousArray: Codable where Element: Codable { }
|
||||
|
|
@ -34,7 +34,7 @@ extension Nexus {
|
|||
|
||||
// add component instances to uniform component stores
|
||||
if componentsByType[componentId] == nil {
|
||||
componentsByType[componentId] = UnorderedSparseSet<Component>()
|
||||
componentsByType[componentId] = ManagedContiguousArray<Component>()
|
||||
}
|
||||
componentsByType[componentId]?.insert(component, at: entityId.id)
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ public final class Nexus {
|
|||
/// - Key: ComponentIdentifier aka component type.
|
||||
/// - Value: Array of component instances of same type (uniform).
|
||||
/// New component instances are appended.
|
||||
@usableFromInline final var componentsByType: [ComponentIdentifier: UnorderedSparseSet<Component>]
|
||||
@usableFromInline final var componentsByType: [ComponentIdentifier: ManagedContiguousArray<Component>]
|
||||
|
||||
/// - Key: EntityIdentifier aka entity index
|
||||
/// - Value: Set of unique component types (ComponentIdentifier).
|
||||
|
|
@ -43,7 +43,7 @@ public final class Nexus {
|
|||
}
|
||||
|
||||
internal init(entityStorage: UnorderedSparseSet<EntityIdentifier>,
|
||||
componentsByType: [ComponentIdentifier: UnorderedSparseSet<Component>],
|
||||
componentsByType: [ComponentIdentifier: ManagedContiguousArray<Component>],
|
||||
componentsByEntity: [EntityIdentifier: Set<ComponentIdentifier>],
|
||||
freeEntities: [EntityIdentifier],
|
||||
familyMembersByTraits: [FamilyTraitSet: UnorderedSparseSet<EntityIdentifier>],
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ import XCTest
|
|||
|
||||
class ComponentIdentifierTests: XCTestCase {
|
||||
|
||||
/// debug: 0.456 sec
|
||||
/// release: 0.034 sec
|
||||
/// debug: 0.456 sec
|
||||
func testMeasureStaticComponentIdentifier() {
|
||||
let number: Int = 1_000_000
|
||||
measure {
|
||||
|
|
@ -21,7 +22,8 @@ class ComponentIdentifierTests: XCTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
/// debug: 0.413 sec
|
||||
/// release: 0.036 sec
|
||||
/// debug: 0.413 sec
|
||||
func testMeasureComponentIdentifier() {
|
||||
let number: Int = 1_000_000
|
||||
let pos = Position(x: 1, y: 2)
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ class TypedFamilyPerformanceTests: XCTestCase {
|
|||
super.tearDown()
|
||||
}
|
||||
|
||||
/// release: 0.011 sec
|
||||
/// release: 0.007 sec
|
||||
/// debug: 0.017 sec
|
||||
func testMeasureTraitMatching() {
|
||||
let a = nexus.createEntity()
|
||||
|
|
@ -92,7 +92,7 @@ class TypedFamilyPerformanceTests: XCTestCase {
|
|||
XCTAssertEqual(loopCount, numEntities * 10)
|
||||
}
|
||||
|
||||
/// release: 0.003 sec
|
||||
/// release: 0.002 sec
|
||||
/// debug: 0.010 sec
|
||||
func testPerformanceTypedFamilyOneComponent() {
|
||||
let family = nexus.family(requires: Position.self, excludesAll: Party.self)
|
||||
|
|
@ -116,7 +116,7 @@ class TypedFamilyPerformanceTests: XCTestCase {
|
|||
XCTAssertEqual(loopCount, family.count * 10)
|
||||
}
|
||||
|
||||
/// release: 0.004 sec
|
||||
/// release: 0.002 sec
|
||||
/// debug: 0.016 sec
|
||||
func testPerformanceTypedFamilyEntityOneComponent() {
|
||||
let family = nexus.family(requires: Position.self, excludesAll: Party.self)
|
||||
|
|
@ -142,7 +142,7 @@ class TypedFamilyPerformanceTests: XCTestCase {
|
|||
XCTAssertEqual(loopCount, family.count * 10)
|
||||
}
|
||||
|
||||
/// release: 0.005 sec
|
||||
/// release: 0.002 sec
|
||||
/// debug: 0.016 sec
|
||||
func testPerformanceTypedFamilyTwoComponents() {
|
||||
let family = nexus.family(requiresAll: Position.self, Velocity.self, excludesAll: Party.self)
|
||||
|
|
@ -167,7 +167,7 @@ class TypedFamilyPerformanceTests: XCTestCase {
|
|||
XCTAssertEqual(loopCount, family.count * 10)
|
||||
}
|
||||
|
||||
/// release: 0.006 sec
|
||||
/// release: 0.003 sec
|
||||
func testPerformanceTypedFamilyEntityTwoComponents() {
|
||||
let family = nexus.family(requiresAll: Position.self, Velocity.self, excludesAll: Party.self)
|
||||
|
||||
|
|
@ -193,7 +193,7 @@ class TypedFamilyPerformanceTests: XCTestCase {
|
|||
XCTAssertEqual(loopCount, family.count * 10)
|
||||
}
|
||||
|
||||
/// release: 0.007 sec
|
||||
/// release: 0.004 sec
|
||||
func testPerformanceTypedFamilyThreeComponents() {
|
||||
let family = nexus.family(requiresAll: Position.self, Velocity.self, Name.self, excludesAll: Party.self)
|
||||
|
||||
|
|
@ -218,7 +218,7 @@ class TypedFamilyPerformanceTests: XCTestCase {
|
|||
XCTAssertEqual(loopCount, family.count * 10)
|
||||
}
|
||||
|
||||
/// release: 0.008 sec
|
||||
/// release: 0.004 sec
|
||||
func testPerformanceTypedFamilyEntityThreeComponents() {
|
||||
let family = nexus.family(requiresAll: Position.self, Velocity.self, Name.self, excludesAll: Party.self)
|
||||
|
||||
|
|
@ -245,7 +245,7 @@ class TypedFamilyPerformanceTests: XCTestCase {
|
|||
XCTAssertEqual(loopCount, family.count * 10)
|
||||
}
|
||||
|
||||
/// release: 0.009 sec
|
||||
/// release: 0.004 sec
|
||||
func testPerformanceTypedFamilyFourComponents() {
|
||||
let family = nexus.family(requiresAll: Position.self, Velocity.self, Name.self, Color.self, excludesAll: Party.self)
|
||||
|
||||
|
|
@ -271,7 +271,7 @@ class TypedFamilyPerformanceTests: XCTestCase {
|
|||
XCTAssertEqual(loopCount, family.count * 10)
|
||||
}
|
||||
|
||||
/// release: 0.010 sec
|
||||
/// release: 0.005 sec
|
||||
func testPerformanceTypedFamilyEntityFourComponents() {
|
||||
let family = nexus.family(requiresAll: Position.self, Velocity.self, Name.self, Color.self, excludesAll: Party.self)
|
||||
|
||||
|
|
@ -299,7 +299,7 @@ class TypedFamilyPerformanceTests: XCTestCase {
|
|||
XCTAssertEqual(loopCount, family.count * 10)
|
||||
}
|
||||
|
||||
/// release: 0.012 sec
|
||||
/// release: 0.005 sec
|
||||
func testPerformanceTypedFamilyFiveComponents() {
|
||||
let family = nexus.family(requiresAll: Position.self, Velocity.self, Name.self, Color.self, EmptyComponent.self, excludesAll: Party.self)
|
||||
|
||||
|
|
@ -325,7 +325,7 @@ class TypedFamilyPerformanceTests: XCTestCase {
|
|||
XCTAssertEqual(loopCount, family.count * 10)
|
||||
}
|
||||
|
||||
/// release: 0.012 sec
|
||||
/// release: 0.006 sec
|
||||
func testPerformanceTypedFamilyEntityFiveComponents() {
|
||||
let family = nexus.family(requiresAll: Position.self, Velocity.self, Name.self, Color.self, EmptyComponent.self, excludesAll: Party.self)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue