Fix some reference counting

This commit is contained in:
Christian Treffs 2017-11-02 17:48:46 +01:00
parent 5dd149dd82
commit 78c248ab0a
11 changed files with 105 additions and 64 deletions

View File

@ -0,0 +1,11 @@
//
// Activatable.swift
// FirebladeECSPackageDescription
//
// Created by Christian Treffs on 02.11.17.
//
public protocol Activatable {
func activate()
func deactivate()
}

View File

@ -5,7 +5,7 @@
// Created by Christian Treffs on 08.10.17.
//
public protocol Component: class, UniqueComponentIdentifiable {}
public protocol Component: class, UniqueComponentIdentifiable, Activatable {}
// MARK: UCI
extension Component {
@ -15,6 +15,12 @@ extension Component {
public var identifier: ComponentIdentifier { return Self.identifier }
}
// MARK: - activatable protocol
extension Component {
public func activate() { /* default does nothing */ }
public func deactivate() { /* default does nothing */ }
}
// MARK: - entity component hashable
internal extension Component {

View File

@ -9,11 +9,11 @@
public extension Entity {
public final func get<C>() -> C? where C: Component {
return nexus.get(for: identifier)
return delegate.get(for: identifier)
}
public func get<A>(component compType: A.Type = A.self) -> A? where A: Component {
return nexus.get(for: identifier)
return delegate.get(for: identifier)
}
public func getComponent<A>() -> () -> A? where A: Component {

View File

@ -10,25 +10,35 @@ public final class Entity: UniqueEntityIdentifiable {
internal(set) public var identifier: EntityIdentifier = EntityIdentifier.invalid
public var name: String?
internal let nexus: Nexus
internal unowned let delegate: Nexus
internal init(nexus: Nexus, id: EntityIdentifier, name: String? = nil) {
self.nexus = nexus
self.delegate = nexus
self.identifier = id
self.name = name
}
}
// MARK: - activatable protocol
extension Entity: Activatable {
public func activate() {
//TODO: nexus.activate(entity: self)
}
public func deactivate() {
//TODO: nexus.deactivate(entity: self)
}
}
// MARK: - Invalidate
extension Entity {
public var isValid: Bool {
return nexus.isValid(entity: self)
return delegate.isValid(entity: self)
}
internal func invalidate() {
assert(nexus.isValid(entity: identifier), "Invalid entity \(self) is being invalidated.")
assert(delegate.isValid(entity: identifier), "Invalid entity \(self) is being invalidated.")
identifier = EntityIdentifier.invalid
name = nil
}
@ -42,7 +52,7 @@ public func ==(lhs: Entity, rhs: Entity) -> Bool {
// MARK: - number of components
public extension Entity {
public final var numComponents: Int {
return nexus.count(components: identifier)
return delegate.count(components: identifier)
}
}
@ -54,11 +64,11 @@ public extension Entity {
}
public final func has(_ uct: ComponentIdentifier) -> Bool {
return nexus.has(componentId: uct, entityIdx: identifier.index)
return delegate.has(componentId: uct, entityIdx: identifier.index)
}
public final var hasComponents: Bool {
return nexus.count(components: identifier) > 0
return delegate.count(components: identifier) > 0
}
}
@ -76,13 +86,13 @@ public extension Entity {
@discardableResult
public final func assign(_ component: Component) -> Entity {
nexus.assign(component: component, to: self)
delegate.assign(component: component, to: self)
return self
}
@discardableResult
public final func assign<C>(_ component: C) -> Entity where C: Component {
nexus.assign(component: component, to: self)
delegate.assign(component: component, to: self)
return self
}
@ -112,12 +122,12 @@ public extension Entity {
@discardableResult
public final func remove(_ uct: ComponentIdentifier) -> Entity {
nexus.remove(component: uct, from: identifier)
delegate.remove(component: uct, from: identifier)
return self
}
public final func clear() {
nexus.clear(componentes: identifier)
delegate.clear(componentes: identifier)
}
@discardableResult
@ -134,6 +144,6 @@ public extension Entity {
// MARK: - destroy/deinit entity
extension Entity {
public final func destroy() {
nexus.destroy(entity: self)
delegate.destroy(entity: self)
}
}

View File

@ -18,7 +18,7 @@ extension Family {
public func iterate<A>(components _: A.Type, _ apply: @escaping (EntityIdentifier, A?) -> Void)
where A: Component {
for entityId in memberIds {
let a: A? = self.nexus.get(for: entityId)
let a: A? = self.delegate.get(for: entityId)
apply(entityId, a)
}
}
@ -26,8 +26,8 @@ extension Family {
public func iterate<A, B>(components _: A.Type, _: B.Type, _ apply: @escaping (EntityIdentifier, A?, B?) -> Void)
where A: Component, B: Component {
for entityId in memberIds {
let a: A? = self.nexus.get(for: entityId)
let b: B? = self.nexus.get(for: entityId)
let a: A? = self.delegate.get(for: entityId)
let b: B? = self.delegate.get(for: entityId)
apply(entityId, a, b)
}
}
@ -35,9 +35,9 @@ extension Family {
public func iterate<A, B, C>(components _: A.Type, _: B.Type, _: C.Type, _ apply: @escaping (EntityIdentifier, A?, B?, C?) -> Void)
where A: Component, B: Component, C: Component {
for entityId in memberIds {
let a: A? = self.nexus.get(for: entityId)
let b: B? = self.nexus.get(for: entityId)
let c: C? = self.nexus.get(for: entityId)
let a: A? = self.delegate.get(for: entityId)
let b: B? = self.delegate.get(for: entityId)
let c: C? = self.delegate.get(for: entityId)
apply(entityId, a, b, c)
}
}
@ -45,21 +45,21 @@ extension Family {
public func iterate<A, B, C, D>(components _: A.Type, _: B.Type, _: C.Type, _: D.Type, _ apply: @escaping (EntityIdentifier, A?, B?, C?, D?) -> Void)
where A: Component, B: Component, C: Component, D: Component {
for entityId in memberIds {
let a: A? = self.nexus.get(for: entityId)
let b: B? = self.nexus.get(for: entityId)
let c: C? = self.nexus.get(for: entityId)
let d: D? = self.nexus.get(for: entityId)
let a: A? = self.delegate.get(for: entityId)
let b: B? = self.delegate.get(for: entityId)
let c: C? = self.delegate.get(for: entityId)
let d: D? = self.delegate.get(for: entityId)
apply(entityId, a, b, c, d)
}
}
public func iterate<A, B, C, D, E>(components _: A.Type, _: B.Type, _: C.Type, _: D.Type, _: E.Type, _ apply: @escaping (EntityIdentifier, A?, B?, C?, D?, E?) -> Void)
where A: Component, B: Component, C: Component, D: Component, E: Component {
for entityId in memberIds {
let a: A? = self.nexus.get(for: entityId)
let b: B? = self.nexus.get(for: entityId)
let c: C? = self.nexus.get(for: entityId)
let d: D? = self.nexus.get(for: entityId)
let e: E? = self.nexus.get(for: entityId)
let a: A? = self.delegate.get(for: entityId)
let b: B? = self.delegate.get(for: entityId)
let c: C? = self.delegate.get(for: entityId)
let d: D? = self.delegate.get(for: entityId)
let e: E? = self.delegate.get(for: entityId)
apply(entityId, a, b, c, d, e)
}
}
@ -68,12 +68,12 @@ extension Family {
_ apply: @escaping (EntityIdentifier, A?, B?, C?, D?, E?, F?) -> Void)
where A: Component, B: Component, C: Component, D: Component, E: Component, F: Component {
for entityId in memberIds {
let a: A? = self.nexus.get(for: entityId)
let b: B? = self.nexus.get(for: entityId)
let c: C? = self.nexus.get(for: entityId)
let d: D? = self.nexus.get(for: entityId)
let e: E? = self.nexus.get(for: entityId)
let f: F? = self.nexus.get(for: entityId)
let a: A? = self.delegate.get(for: entityId)
let b: B? = self.delegate.get(for: entityId)
let c: C? = self.delegate.get(for: entityId)
let d: D? = self.delegate.get(for: entityId)
let e: E? = self.delegate.get(for: entityId)
let f: F? = self.delegate.get(for: entityId)
apply(entityId, a, b, c, d, e, f)
}
}

View File

@ -7,40 +7,42 @@
// MARK: - family
public final class Family {
internal var nexus: Nexus
internal unowned var delegate: Nexus
// members of this Family must conform to these traits
public let traits: FamilyTraitSet
internal init(_ nexus: Nexus, traits: FamilyTraitSet) {
self.nexus = nexus
self.delegate = nexus
self.traits = traits
defer {
nexus.onFamilyCreated(family: self)
}
}
deinit {
delegate.onFamilyRemove(family: self)
}
}
extension Family {
public var count: Int {
return nexus.members(of: self).count
return delegate.members(of: self).count
}
public final func canBecomeMember(_ entity: Entity) -> Bool {
return nexus.canBecomeMember(entity, in: self)
return delegate.canBecomeMember(entity, in: self)
}
public final func isMember(_ entity: Entity) -> Bool {
return nexus.isMember(entity, in: self)
return delegate.isMember(entity, in: self)
}
public final func isMember(_ entityId: EntityIdentifier) -> Bool {
return nexus.isMember(entityId, in: self)
return delegate.isMember(entityId, in: self)
}
internal var memberIds: UniformEntityIdentifiers {
return nexus.members(of: self)
return delegate.members(of: self)
}
}

View File

@ -108,7 +108,7 @@ extension Nexus {
// relocate remaining indices pointing in the componentsByEntity map
if let remainingComponents: ComponentIdentifiers = componentIdsByEntity[entityIdx] {
// FIXME: may be expensive but is cheap for small entities
// FIXME: may be expensive but is cheap for small entities -> may be fixed with a sparse set?!
for (index, compId) in remainingComponents.enumerated() {
let cHash: EntityComponentHash = compId.hashValue(using: entityIdx)
assert(cHash != hash)

View File

@ -64,17 +64,24 @@ extension Nexus {
let family = Family(self, traits: traits)
let replaced = familiyByTraitHash.updateValue(family, forKey: traitHash)
assert(replaced == nil, "Family with exact trait hash already exists: \(traitHash)")
// FIXME: this is costly for many entities
for entity: Entity in entityStorage {
update(membership: family, for: entity.identifier)
}
notify(FamilyCreated(family: traits))
return family
}
// FIXME: remove families?!
/// will be called on family init defer
internal func onFamilyCreated(family: Family) {
// FIXME: this is costly for many entities
for entity: Entity in entityStorage {
update(membership: family, for: entity.identifier)
}
}
internal func onFamilyRemove(family: Family) {
let traitHash: FamilyTraitSetHash = family.traits.hashValue
for member in members(of: family) {
remove(from: traitHash, entityId: member, entityIdx: member.index)
}
}
// MARK: - update family membership

View File

@ -33,7 +33,7 @@ public class Nexus {
/// - Key: entity id as index
/// - Value: each element is a component identifier associated with this entity
var componentIdsByEntity: [EntityIndex: ComponentIdentifiers]
var componentIdsByEntity: [EntityIndex: ComponentIdentifiers] // TODO: sparse set?!
/// - Key 'entity id' - 'component type' hash that uniquely links both
/// - Value: each element is an index pointing to the component identifier per entity in the componentIdsByEntity map
@ -56,6 +56,11 @@ public class Nexus {
}
deinit {
// FIXME: clear all things and cleanup
print("nexus deinit")
}
}
extension Nexus {

View File

@ -39,19 +39,19 @@ public class SparseSet<Element>: UniformStorage, Sequence {
size += 1
}
public func get(at entityIdx: Index) -> Element? {
guard has(entityIdx) else { return nil }
return dense[sparse[entityIdx]!]!.value
public func get(at index: Index) -> Element? {
guard has(index) else { return nil }
return dense[sparse[index]!]!.value
}
public func remove(at index: Index) {
guard has(index) else { return }
let compIdx: DenseIndex = sparse[index]!
let removeIdx: DenseIndex = sparse[index]!
let lastIdx: DenseIndex = count-1
dense.swapAt(compIdx, lastIdx)
dense.swapAt(removeIdx, lastIdx)
sparse[index] = nil
let swapped: Pair = dense[compIdx]!
sparse[swapped.key] = compIdx
let swapped: Pair = dense[removeIdx]!
sparse[swapped.key] = removeIdx
_ = dense.popLast()!!
size -= 1
if size == 0 {

View File

@ -1,5 +1,5 @@
//
// SparseComponentSetTests.swift
// SparseSetTests.swift
// FirebladeECSTests
//
// Created by Christian Treffs on 31.10.17.
@ -8,9 +8,9 @@
import XCTest
@testable import FirebladeECS
class SparseComponentSetTests: XCTestCase {
class SparseSetTests: XCTestCase {
func testSet() {
func testSparseComponentSet() {
let s = SparseComponentSet()
let num: Int = 100