Brought performance of TypedFamily en par to Family implementation
This commit is contained in:
parent
f6f8f5e5a2
commit
7f9ab6dcac
|
|
@ -103,7 +103,7 @@ public extension Nexus {
|
|||
}
|
||||
|
||||
private extension Nexus {
|
||||
func get<C>(componentId: ComponentIdentifier, entityIdx: EntityIndex) -> C? where C: Component {
|
||||
final func get<C>(componentId: ComponentIdentifier, entityIdx: EntityIndex) -> C? where C: Component {
|
||||
guard let uniformComponents: UniformComponents = componentsByType[componentId] else {
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,29 +38,8 @@ public protocol FamilyMembersProtocol: LazySequenceProtocol {
|
|||
public protocol ComponentIteratorProtocol: IteratorProtocol {
|
||||
associatedtype TypedFamily: TypedFamilyProtocol
|
||||
|
||||
var memberIds: UniformEntityIdentifiers { get }
|
||||
var memberIdsIterator: UnorderedSparseSetIterator<EntityIdentifier> { get }
|
||||
var nexus: Nexus? { get }
|
||||
var index: Int { get set }
|
||||
|
||||
init(_ nexus: Nexus?, _ family: TypedFamily)
|
||||
}
|
||||
|
||||
internal extension ComponentIteratorProtocol {
|
||||
internal mutating func nextIndex() -> Int? {
|
||||
let nextIndex: Int = memberIds.index(after: index)
|
||||
guard nextIndex < memberIds.endIndex else {
|
||||
return nil
|
||||
}
|
||||
|
||||
index = nextIndex
|
||||
return nextIndex
|
||||
}
|
||||
|
||||
internal mutating func nextEntityId() -> EntityIdentifier? {
|
||||
guard let index: Int = nextIndex() else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return memberIds[index]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,26 +39,19 @@ public struct FamilyMembers1<A>: FamilyMembersProtocol where A: Component {
|
|||
public struct ComponentIterator1<A>: ComponentIteratorProtocol where A: Component {
|
||||
|
||||
public private(set) weak var nexus: Nexus?
|
||||
public let memberIds: UniformEntityIdentifiers
|
||||
public var index: Int = -1
|
||||
public var memberIdsIterator: UnorderedSparseSetIterator<EntityIdentifier>
|
||||
|
||||
public init(_ nexus: Nexus?, _ family: TypedFamily1<A>) {
|
||||
self.nexus = nexus
|
||||
memberIds = family.memberIds
|
||||
memberIdsIterator = family.memberIds.makeIterator()
|
||||
}
|
||||
|
||||
public mutating func next() -> A? {
|
||||
guard let entityId: EntityIdentifier = nextEntityId() else {
|
||||
guard let entityId = memberIdsIterator.next() else {
|
||||
return nil
|
||||
}
|
||||
|
||||
guard
|
||||
let compA: A = nexus?.get(for: entityId)
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return compA
|
||||
return nexus?.get(for: entityId)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,16 +39,15 @@ public struct FamilyMembers2<A, B>: FamilyMembersProtocol where A: Component, B:
|
|||
public struct ComponentIterator2<A, B>: ComponentIteratorProtocol where A: Component, B: Component {
|
||||
|
||||
public private(set) weak var nexus: Nexus?
|
||||
public let memberIds: UniformEntityIdentifiers
|
||||
public var index: Int = -1
|
||||
public var memberIdsIterator: UnorderedSparseSetIterator<EntityIdentifier>
|
||||
|
||||
public init(_ nexus: Nexus?, _ family: TypedFamily2<A, B>) {
|
||||
self.nexus = nexus
|
||||
memberIds = family.memberIds
|
||||
memberIdsIterator = family.memberIds.makeIterator()
|
||||
}
|
||||
|
||||
public mutating func next() -> (A, B)? {
|
||||
guard let entityId: EntityIdentifier = nextEntityId() else {
|
||||
guard let entityId: EntityIdentifier = memberIdsIterator.next() else {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,16 +40,15 @@ public struct FamilyMembers3<A, B, C>: FamilyMembersProtocol where A: Component,
|
|||
public struct ComponentIterator3<A, B, C>: ComponentIteratorProtocol where A: Component, B: Component, C: Component {
|
||||
|
||||
public private(set) weak var nexus: Nexus?
|
||||
public let memberIds: UniformEntityIdentifiers
|
||||
public var index: Int = -1
|
||||
public var memberIdsIterator: UnorderedSparseSetIterator<EntityIdentifier>
|
||||
|
||||
public init(_ nexus: Nexus?, _ family: TypedFamily3<A, B, C>) {
|
||||
self.nexus = nexus
|
||||
memberIds = family.memberIds
|
||||
memberIdsIterator = family.memberIds.makeIterator()
|
||||
}
|
||||
|
||||
public mutating func next() -> (A, B, C)? {
|
||||
guard let entityId: EntityIdentifier = nextEntityId() else {
|
||||
guard let entityId: EntityIdentifier = memberIdsIterator.next() else {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,16 +40,15 @@ public struct FamilyMembers4<A, B, C, D>: FamilyMembersProtocol where A: Compone
|
|||
public struct ComponentIterator4<A, B, C, D>: ComponentIteratorProtocol where A: Component, B: Component, C: Component, D: Component {
|
||||
|
||||
public private(set) weak var nexus: Nexus?
|
||||
public let memberIds: UniformEntityIdentifiers
|
||||
public var index: Int = -1
|
||||
public var memberIdsIterator: UnorderedSparseSetIterator<EntityIdentifier>
|
||||
|
||||
public init(_ nexus: Nexus?, _ family: TypedFamily4<A, B, C, D>) {
|
||||
self.nexus = nexus
|
||||
memberIds = family.memberIds
|
||||
memberIdsIterator = family.memberIds.makeIterator()
|
||||
}
|
||||
|
||||
public mutating func next() -> (A, B, C, D)? {
|
||||
guard let entityId: EntityIdentifier = nextEntityId() else {
|
||||
guard let entityId: EntityIdentifier = memberIdsIterator.next() else {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,16 +40,15 @@ public struct FamilyMembers5<A, B, C, D, E>: FamilyMembersProtocol where A: Comp
|
|||
public struct ComponentIterator5<A, B, C, D, E>: ComponentIteratorProtocol where A: Component, B: Component, C: Component, D: Component, E: Component {
|
||||
|
||||
public private(set) weak var nexus: Nexus?
|
||||
public let memberIds: UniformEntityIdentifiers
|
||||
public var index: Int = -1
|
||||
public var memberIdsIterator: UnorderedSparseSetIterator<EntityIdentifier>
|
||||
|
||||
public init(_ nexus: Nexus?, _ family: TypedFamily5<A, B, C, D, E>) {
|
||||
self.nexus = nexus
|
||||
memberIds = family.memberIds
|
||||
memberIdsIterator = family.memberIds.makeIterator()
|
||||
}
|
||||
|
||||
public mutating func next() -> (A, B, C, D, E)? {
|
||||
guard let entityId: EntityIdentifier = nextEntityId() else {
|
||||
guard let entityId: EntityIdentifier = memberIdsIterator.next() else {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -120,19 +120,19 @@ public class UnorderedSparseSet<Element> {
|
|||
return (denseIndex, entry.element)
|
||||
}
|
||||
|
||||
// MARK: - UnorderedSparseSetIterator
|
||||
}
|
||||
|
||||
public struct UnorderedSparseSetIterator<Element>: IteratorProtocol {
|
||||
// MARK: - UnorderedSparseSetIterator
|
||||
public struct UnorderedSparseSetIterator<Element>: IteratorProtocol {
|
||||
|
||||
public private(set) var iterator: IndexingIterator<ContiguousArray<UnorderedSparseSet<Element>.Entry>>
|
||||
public private(set) var iterator: IndexingIterator<ContiguousArray<UnorderedSparseSet<Element>.Entry>>
|
||||
|
||||
public init(_ sparseSet: UnorderedSparseSet<Element>) {
|
||||
iterator = sparseSet.dense.makeIterator()
|
||||
}
|
||||
public init(_ sparseSet: UnorderedSparseSet<Element>) {
|
||||
iterator = sparseSet.dense.makeIterator()
|
||||
}
|
||||
|
||||
public mutating func next() -> Element? {
|
||||
return iterator.next()?.element
|
||||
}
|
||||
public mutating func next() -> Element? {
|
||||
return iterator.next()?.element
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,82 +9,154 @@ import FirebladeECS
|
|||
import XCTest
|
||||
|
||||
class FamilyPerformanceTests: XCTestCase {
|
||||
|
||||
|
||||
let numEntities: Int = 10_000
|
||||
var nexus: Nexus!
|
||||
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
nexus = Nexus()
|
||||
|
||||
for i in 0..<numEntities {
|
||||
nexus.create(entity: "\(i)").assign(Position(x: 1 + i, y: 2 + i),
|
||||
Name(name: "myName\(i)"),
|
||||
Velocity(a: 3.14),
|
||||
EmptyComponent(),
|
||||
Color())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override func tearDown() {
|
||||
nexus = nil
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
|
||||
func testMeasureIterateMembers() {
|
||||
|
||||
let number: Int = 10_000
|
||||
|
||||
for i in 0..<number {
|
||||
nexus.create(entity: "\(i)").assign(Position(x: 1 + i, y: 2 + i), Name(name: "myName\(i)"), Velocity(a: 3.14), EmptyComponent())
|
||||
}
|
||||
|
||||
|
||||
let family = nexus.family(requiresAll: [Position.self, Velocity.self],
|
||||
excludesAll: [Party.self],
|
||||
needsAtLeastOne: [Name.self, EmptyComponent.self])
|
||||
|
||||
XCTAssertEqual(family.count, number)
|
||||
XCTAssertEqual(nexus.numEntities, number)
|
||||
|
||||
|
||||
XCTAssertEqual(family.count, numEntities)
|
||||
XCTAssertEqual(nexus.numEntities, numEntities)
|
||||
|
||||
var loopCount: Int = 0
|
||||
|
||||
measure {
|
||||
family.iterate { (entityId: EntityIdentifier) in
|
||||
_ = entityId
|
||||
|
||||
loopCount += 1
|
||||
}
|
||||
}
|
||||
|
||||
XCTAssertEqual(loopCount, family.count * 10)
|
||||
}
|
||||
|
||||
|
||||
func testMeasureFamilyIterationOne() {
|
||||
|
||||
let number: Int = 10_000
|
||||
|
||||
for i in 0..<number {
|
||||
nexus.create(entity: "\(i)").assign(Position(x: 1 + i, y: 2 + i), Name(name: "myName\(i)"), Velocity(a: 3.14), EmptyComponent())
|
||||
}
|
||||
|
||||
let family = nexus.family(requiresAll: [Position.self, Velocity.self], excludesAll: [Party.self], needsAtLeastOne: [Name.self, EmptyComponent.self])
|
||||
|
||||
XCTAssert(family.count == number)
|
||||
XCTAssert(nexus.numEntities == number)
|
||||
|
||||
let family = nexus.family(requiresAll: [Position.self], excludesAll: [Party.self])
|
||||
|
||||
XCTAssert(family.count == numEntities)
|
||||
XCTAssert(nexus.numEntities == numEntities)
|
||||
|
||||
var loopCount: Int = 0
|
||||
|
||||
measure {
|
||||
family.iterate { (velocity: Velocity!) in
|
||||
_ = velocity
|
||||
|
||||
loopCount += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
XCTAssertEqual(loopCount, family.count * 10)
|
||||
}
|
||||
func testMeasureFamilyIterationThree() {
|
||||
|
||||
let number: Int = 10_000
|
||||
|
||||
for i in 0..<number {
|
||||
nexus.create(entity: "\(i)").assign(Position(x: 1 + i, y: 2 + i), Name(name: "myName\(i)"), Velocity(a: 3.14), EmptyComponent())
|
||||
}
|
||||
|
||||
let family = nexus.family(requiresAll: [Position.self, Velocity.self], excludesAll: [Party.self], needsAtLeastOne: [Name.self, EmptyComponent.self])
|
||||
|
||||
XCTAssert(family.count == number)
|
||||
XCTAssert(nexus.numEntities == number)
|
||||
|
||||
|
||||
func testMeasureFamilyIterationTwo() {
|
||||
let family = nexus.family(requiresAll: [Position.self, Velocity.self], excludesAll: [Party.self])
|
||||
|
||||
XCTAssert(family.count == numEntities)
|
||||
XCTAssert(nexus.numEntities == numEntities)
|
||||
|
||||
var loopCount: Int = 0
|
||||
|
||||
measure {
|
||||
family.iterate { (entity: Entity!, position: Position!, velocity: Velocity!, name: Name?) in
|
||||
position.x += entity.identifier.index
|
||||
family.iterate { (position: Position!, velocity: Velocity!) in
|
||||
_ = velocity
|
||||
_ = position
|
||||
|
||||
loopCount += 1
|
||||
}
|
||||
}
|
||||
|
||||
XCTAssertEqual(loopCount, family.count * 10)
|
||||
|
||||
}
|
||||
|
||||
func testMeasureFamilyIterationThree() {
|
||||
let family = nexus.family(requiresAll: [Position.self, Velocity.self, Name.self], excludesAll: [Party.self])
|
||||
|
||||
XCTAssert(family.count == numEntities)
|
||||
XCTAssert(nexus.numEntities == numEntities)
|
||||
|
||||
var loopCount: Int = 0
|
||||
|
||||
measure {
|
||||
family.iterate { (position: Position!, velocity: Velocity!, name: Name!) in
|
||||
_ = position
|
||||
_ = velocity
|
||||
_ = name
|
||||
|
||||
loopCount += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
XCTAssertEqual(loopCount, family.count * 10)
|
||||
}
|
||||
|
||||
|
||||
func testMeasureFamilyIterationFour() {
|
||||
let family = nexus.family(requiresAll: [Position.self, Velocity.self, Name.self, Color.self], excludesAll: [Party.self])
|
||||
|
||||
XCTAssert(family.count == numEntities)
|
||||
XCTAssert(nexus.numEntities == numEntities)
|
||||
|
||||
var loopCount: Int = 0
|
||||
|
||||
measure {
|
||||
family.iterate { (position: Position!, velocity: Velocity!, name: Name!, color: Color!) in
|
||||
_ = position
|
||||
_ = velocity
|
||||
_ = name
|
||||
_ = color
|
||||
|
||||
loopCount += 1
|
||||
}
|
||||
}
|
||||
|
||||
XCTAssertEqual(loopCount, family.count * 10)
|
||||
}
|
||||
|
||||
func testMeasureFamilyIterationFive() {
|
||||
let family = nexus.family(requiresAll: [Position.self, Velocity.self, Name.self, Color.self, EmptyComponent.self], excludesAll: [Party.self])
|
||||
|
||||
XCTAssert(family.count == numEntities)
|
||||
XCTAssert(nexus.numEntities == numEntities)
|
||||
|
||||
var loopCount: Int = 0
|
||||
|
||||
measure {
|
||||
family.iterate { (position: Position!, velocity: Velocity!, name: Name!, color: Color!, empty: EmptyComponent!) in
|
||||
_ = position
|
||||
_ = velocity
|
||||
_ = name
|
||||
_ = color
|
||||
_ = empty
|
||||
|
||||
loopCount += 1
|
||||
}
|
||||
}
|
||||
|
||||
XCTAssertEqual(loopCount, family.count * 10)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,138 @@
|
|||
//
|
||||
// TypedFamilyPerformanceTests.swift
|
||||
// FirebladeECS
|
||||
//
|
||||
// Created by Christian Treffs on 29.09.18.
|
||||
//
|
||||
|
||||
import FirebladeECS
|
||||
import XCTest
|
||||
|
||||
class TypedFamilyPerformanceTests: XCTestCase {
|
||||
|
||||
let numEntities: Int = 10_000
|
||||
var nexus: Nexus!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
nexus = Nexus()
|
||||
|
||||
for i in 0..<numEntities {
|
||||
nexus.create(entity: "\(i)").assign(Position(x: 1 + i, y: 2 + i),
|
||||
Name(name: "myName\(i)"),
|
||||
Velocity(a: 3.14),
|
||||
EmptyComponent(),
|
||||
Color())
|
||||
}
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
nexus = nil
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func testPerformanceTypedFamilyOneComponent() {
|
||||
let family = nexus.family(requires: Position.self, excludesAll: Party.self)
|
||||
|
||||
XCTAssertEqual(family.count, numEntities)
|
||||
XCTAssertEqual(nexus.numEntities, numEntities)
|
||||
|
||||
var loopCount: Int = 0
|
||||
|
||||
measure {
|
||||
family.members.forEach { (position: Position) in
|
||||
_ = position
|
||||
|
||||
loopCount += 1
|
||||
}
|
||||
}
|
||||
|
||||
XCTAssertEqual(loopCount, family.count * 10)
|
||||
}
|
||||
|
||||
func testPerformanceTypedFamilyTwoComponents() {
|
||||
let family = nexus.family(requiresAll: Position.self, Velocity.self, excludesAll: Party.self)
|
||||
|
||||
XCTAssertEqual(family.count, numEntities)
|
||||
XCTAssertEqual(nexus.numEntities, numEntities)
|
||||
|
||||
var loopCount: Int = 0
|
||||
|
||||
measure {
|
||||
family.members.forEach { (position: Position, velocity: Velocity) in
|
||||
_ = position
|
||||
_ = velocity
|
||||
|
||||
loopCount += 1
|
||||
}
|
||||
}
|
||||
|
||||
XCTAssertEqual(loopCount, family.count * 10)
|
||||
}
|
||||
|
||||
func testPerformanceTypedFamilyThreeComponents() {
|
||||
let family = nexus.family(requiresAll: Position.self, Velocity.self, Name.self, excludesAll: Party.self)
|
||||
|
||||
XCTAssertEqual(family.count, numEntities)
|
||||
XCTAssertEqual(nexus.numEntities, numEntities)
|
||||
|
||||
var loopCount: Int = 0
|
||||
|
||||
measure {
|
||||
family.members.forEach { (position: Position, velocity: Velocity, name: Name) in
|
||||
_ = position
|
||||
_ = velocity
|
||||
_ = name
|
||||
|
||||
loopCount += 1
|
||||
}
|
||||
}
|
||||
|
||||
XCTAssertEqual(loopCount, family.count * 10)
|
||||
}
|
||||
|
||||
func testPerformanceTypedFamilyFourComponents() {
|
||||
let family = nexus.family(requiresAll: Position.self, Velocity.self, Name.self, Color.self, excludesAll: Party.self)
|
||||
|
||||
XCTAssertEqual(family.count, numEntities)
|
||||
XCTAssertEqual(nexus.numEntities, numEntities)
|
||||
|
||||
var loopCount: Int = 0
|
||||
|
||||
measure {
|
||||
family.members.forEach { (position: Position, velocity: Velocity, name: Name, color: Color) in
|
||||
_ = position
|
||||
_ = velocity
|
||||
_ = name
|
||||
_ = color
|
||||
|
||||
loopCount += 1
|
||||
}
|
||||
}
|
||||
|
||||
XCTAssertEqual(loopCount, family.count * 10)
|
||||
}
|
||||
|
||||
func testPerformanceTypedFamilyFiveComponents() {
|
||||
let family = nexus.family(requiresAll: Position.self, Velocity.self, Name.self, Color.self, EmptyComponent.self, excludesAll: Party.self)
|
||||
|
||||
XCTAssertEqual(family.count, numEntities)
|
||||
XCTAssertEqual(nexus.numEntities, numEntities)
|
||||
|
||||
var loopCount: Int = 0
|
||||
|
||||
measure {
|
||||
family.members.forEach { (position: Position, velocity: Velocity, name: Name, color: Color, empty: EmptyComponent) in
|
||||
_ = position
|
||||
_ = velocity
|
||||
_ = name
|
||||
_ = color
|
||||
_ = empty
|
||||
|
||||
loopCount += 1
|
||||
}
|
||||
}
|
||||
|
||||
XCTAssertEqual(loopCount, family.count * 10)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue