Fix entity id default generation + add tests

This commit is contained in:
Christian Treffs 2020-08-21 11:46:48 +02:00
parent fcf5f4eaf3
commit bb02f301c8
No known key found for this signature in database
GPG Key ID: 49A4B4B460BE3ED4
3 changed files with 106 additions and 6 deletions

View File

@ -17,7 +17,7 @@ public protocol EntityIdentifierGenerator {
/// Entity ids provided should be passed to `nextId()` in last out order up until the collection is empty.
/// The default is an empty collection.
/// - Parameter initialEntityIds: The entity ids to start providing up until the collection is empty (in last out order).
init<EntityIds>(startProviding initialEntityIds: EntityIds) where EntityIds: BidirectionalCollection, EntityIds.Element == EntityIdentifier
init<EntityIds>(startProviding initialEntityIds: EntityIds) where EntityIds: BidirectionalCollection & MutableCollection, EntityIds.Element == EntityIdentifier
/// Provides the next unused entity identifier.
///
@ -41,8 +41,19 @@ public struct DefaultEntityIdGenerator: EntityIdentifierGenerator {
@usableFromInline var count: Int { stack.count }
@usableFromInline
init<EntityIds>(startProviding initialEntityIds: EntityIds) where EntityIds: BidirectionalCollection, EntityIds.Element == EntityIdentifier {
stack = initialEntityIds.map { $0.id }
init<EntityIds>(startProviding initialEntityIds: EntityIds) where EntityIds: BidirectionalCollection & MutableCollection, EntityIds.Element == EntityIdentifier {
let initialInUse: [EntityIdentifier.Identifier] = initialEntityIds.map { $0.id }
let maxInUseValue = initialInUse.max() ?? 0
let inUseSet = Set(initialInUse) // a set of all eIds in use
let allSet = Set(0...maxInUseValue) // all eIds from 0 to including maxInUseValue
let freeSet = allSet.subtracting(inUseSet) // all "holes" / unused / free eIds
let initialFree = Array(freeSet).sorted().reversed() // order them to provide them linear increasing after all initially used are provided.
stack = initialFree + initialInUse
}
@usableFromInline
init() {
stack = [0]
}
@usableFromInline
@ -65,16 +76,16 @@ public struct DefaultEntityIdGenerator: EntityIdentifierGenerator {
@usableFromInline var count: Int { storage.count }
@inlinable
public init<EntityIds>(startProviding initialEntityIds: EntityIds) where EntityIds: BidirectionalCollection, EntityIds.Element == EntityIdentifier {
public init<EntityIds>(startProviding initialEntityIds: EntityIds) where EntityIds: BidirectionalCollection & MutableCollection, EntityIds.Element == EntityIdentifier {
self.storage = Storage(startProviding: initialEntityIds)
}
@inlinable
public init() {
self.init(startProviding: [EntityIdentifier(0)])
self.storage = Storage()
}
@inline(__always)
//@inline(__always)
public func nextId() -> EntityIdentifier {
storage.nextId()
}

View File

@ -0,0 +1,76 @@
//
// EntityIdGenTests.swift
//
//
// Created by Christian Treffs on 21.08.20.
//
import FirebladeECS
import XCTest
final class EntityIdGenTests: XCTestCase {
var gen: EntityIdentifierGenerator!
override func setUp() {
super.setUp()
gen = DefaultEntityIdGenerator()
}
func testGeneratorDefaultInit() {
XCTAssertEqual(gen.nextId(), 0)
}
func testLinearIncrement() {
for i in 0..<1_000_000 {
XCTAssertEqual(gen.nextId(), EntityIdentifier(EntityIdentifier.Identifier(i)))
}
}
func testGenerateWithInitialIds() {
let initialIds: [EntityIdentifier] = [2, 4, 11, 3, 0, 304]
gen = DefaultEntityIdGenerator(startProviding: initialIds)
let generatedIds: [EntityIdentifier] = (0..<initialIds.count).map { _ in gen.nextId() }.reversed()
XCTAssertEqual(initialIds, generatedIds)
XCTAssertEqual(gen.nextId(), 1)
XCTAssertEqual(gen.nextId(), 5)
XCTAssertEqual(gen.nextId(), 6)
XCTAssertEqual(gen.nextId(), 7)
XCTAssertEqual(gen.nextId(), 8)
XCTAssertEqual(gen.nextId(), 9)
XCTAssertEqual(gen.nextId(), 10)
XCTAssertEqual(gen.nextId(), 12)
for i in 13...304 {
XCTAssertEqual(gen.nextId(), EntityIdentifier(EntityIdentifier.Identifier(i)))
}
XCTAssertEqual(gen.nextId(), 305)
}
func testGeneratorMarkUnused() {
XCTAssertEqual(gen.nextId(), 0)
XCTAssertEqual(gen.nextId(), 1)
XCTAssertEqual(gen.nextId(), 2)
gen.markUnused(entityId: EntityIdentifier(1))
XCTAssertEqual(gen.nextId(), 1)
XCTAssertEqual(gen.nextId(), 3)
XCTAssertEqual(gen.nextId(), 4)
gen.markUnused(entityId: 3)
gen.markUnused(entityId: 0)
XCTAssertEqual(gen.nextId(), 0)
XCTAssertEqual(gen.nextId(), 3)
gen.markUnused(entityId: 3)
XCTAssertEqual(gen.nextId(), 3)
XCTAssertEqual(gen.nextId(), 5)
XCTAssertEqual(gen.nextId(), 6)
XCTAssertEqual(gen.nextId(), 7)
XCTAssertEqual(gen.nextId(), 8)
}
}

View File

@ -32,6 +32,18 @@ extension EntityCreationTests {
]
}
extension EntityIdGenTests {
// DO NOT MODIFY: This is autogenerated, use:
// `swift test --generate-linuxmain`
// to regenerate.
static let __allTests__EntityIdGenTests = [
("testGenerateWithInitialIds", testGenerateWithInitialIds),
("testGeneratorDefaultInit", testGeneratorDefaultInit),
("testGeneratorMarkUnused", testGeneratorMarkUnused),
("testLinearIncrement", testLinearIncrement)
]
}
extension EntityTests {
// DO NOT MODIFY: This is autogenerated, use:
// `swift test --generate-linuxmain`
@ -292,6 +304,7 @@ public func __allTests() -> [XCTestCaseEntry] {
testCase(ComponentIdentifierTests.__allTests__ComponentIdentifierTests),
testCase(ComponentTests.__allTests__ComponentTests),
testCase(EntityCreationTests.__allTests__EntityCreationTests),
testCase(EntityIdGenTests.__allTests__EntityIdGenTests),
testCase(EntityTests.__allTests__EntityTests),
testCase(Family1Tests.__allTests__Family1Tests),
testCase(Family2Tests.__allTests__Family2Tests),