Merge branch 'develop' into feature/classdojo_fixHashingOverflow
This commit is contained in:
commit
3dd3d7fc10
|
|
@ -8,12 +8,14 @@
|
|||
public struct EntityIdentifier {
|
||||
static let invalid = EntityIdentifier(.max)
|
||||
|
||||
public typealias Id = Int
|
||||
|
||||
/// provides 4294967295 unique identifiers since it's constrained to UInt32 - invalid.
|
||||
@usableFromInline let id: Int
|
||||
@usableFromInline let id: Id
|
||||
|
||||
@usableFromInline
|
||||
init(_ uint32: UInt32) {
|
||||
self.id = Int(uint32)
|
||||
self.id = Id(uint32)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ public struct Family<R> where R: FamilyRequirementsManaging {
|
|||
nexus.onFamilyInit(traits: traits)
|
||||
}
|
||||
|
||||
@inlinable public var memberIds: UnorderedSparseSet<EntityIdentifier> {
|
||||
@inlinable public var memberIds: UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Id> {
|
||||
nexus.members(withFamilyTraits: traits)
|
||||
}
|
||||
|
||||
|
|
@ -58,7 +58,7 @@ extension Family: LazySequenceProtocol { }
|
|||
// MARK: - components iterator
|
||||
extension Family {
|
||||
public struct ComponentsIterator: IteratorProtocol {
|
||||
@usableFromInline var memberIdsIterator: UnorderedSparseSet<EntityIdentifier>.ElementIterator
|
||||
@usableFromInline var memberIdsIterator: UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Id>.ElementIterator
|
||||
@usableFromInline unowned let nexus: Nexus
|
||||
|
||||
public init(family: Family<R>) {
|
||||
|
|
@ -85,7 +85,7 @@ extension Family {
|
|||
}
|
||||
|
||||
public struct EntityIterator: IteratorProtocol {
|
||||
@usableFromInline var memberIdsIterator: UnorderedSparseSet<EntityIdentifier>.ElementIterator
|
||||
@usableFromInline var memberIdsIterator: UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Id>.ElementIterator
|
||||
@usableFromInline unowned let nexus: Nexus
|
||||
|
||||
public init(family: Family<R>) {
|
||||
|
|
@ -111,7 +111,7 @@ extension Family {
|
|||
}
|
||||
|
||||
public struct EntityComponentIterator: IteratorProtocol {
|
||||
@usableFromInline var memberIdsIterator: UnorderedSparseSet<EntityIdentifier>.ElementIterator
|
||||
@usableFromInline var memberIdsIterator: UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Id>.ElementIterator
|
||||
@usableFromInline unowned let nexus: Nexus
|
||||
|
||||
public init(family: Family<R>) {
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ extension Nexus {
|
|||
return traits.isMatch(components: componentIds)
|
||||
}
|
||||
|
||||
public func members(withFamilyTraits traits: FamilyTraitSet) -> UnorderedSparseSet<EntityIdentifier> {
|
||||
familyMembersByTraits[traits] ?? UnorderedSparseSet<EntityIdentifier>()
|
||||
public func members(withFamilyTraits traits: FamilyTraitSet) -> UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Id> {
|
||||
familyMembersByTraits[traits] ?? UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Id>()
|
||||
}
|
||||
|
||||
public func isMember(_ entity: Entity, in family: FamilyTraitSet) -> Bool {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ extension Nexus {
|
|||
return
|
||||
}
|
||||
|
||||
familyMembersByTraits[traits] = UnorderedSparseSet<EntityIdentifier>()
|
||||
familyMembersByTraits[traits] = UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Id>()
|
||||
update(familyMembership: traits)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
public final class Nexus {
|
||||
/// Main entity storage.
|
||||
/// Entities are tightly packed by EntityIdentifier.
|
||||
@usableFromInline final var entityStorage: UnorderedSparseSet<EntityIdentifier>
|
||||
@usableFromInline final var entityStorage: UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Id>
|
||||
|
||||
/// Entity ids that are currently not used.
|
||||
@usableFromInline final var freeEntities: [EntityIdentifier]
|
||||
|
|
@ -29,12 +29,12 @@ public final class Nexus {
|
|||
|
||||
/// - Key: FamilyTraitSet aka component types that make up one distinct family.
|
||||
/// - Value: Tightly packed EntityIdentifiers that represent the association of an entity to the family.
|
||||
@usableFromInline final var familyMembersByTraits: [FamilyTraitSet: UnorderedSparseSet<EntityIdentifier>]
|
||||
@usableFromInline final var familyMembersByTraits: [FamilyTraitSet: UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Id>]
|
||||
|
||||
public final weak var delegate: NexusEventDelegate?
|
||||
|
||||
public convenience init() {
|
||||
self.init(entityStorage: UnorderedSparseSet<EntityIdentifier>(),
|
||||
self.init(entityStorage: UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Id>(),
|
||||
componentsByType: [:],
|
||||
componentsByEntity: [:],
|
||||
freeEntities: [],
|
||||
|
|
@ -42,11 +42,11 @@ public final class Nexus {
|
|||
childrenByParentEntity: [:])
|
||||
}
|
||||
|
||||
internal init(entityStorage: UnorderedSparseSet<EntityIdentifier>,
|
||||
internal init(entityStorage: UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Id>,
|
||||
componentsByType: [ComponentIdentifier: ManagedContiguousArray<Component>],
|
||||
componentsByEntity: [EntityIdentifier: Set<ComponentIdentifier>],
|
||||
freeEntities: [EntityIdentifier],
|
||||
familyMembersByTraits: [FamilyTraitSet: UnorderedSparseSet<EntityIdentifier>],
|
||||
familyMembersByTraits: [FamilyTraitSet: UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Id>],
|
||||
childrenByParentEntity: [EntityIdentifier: Set<EntityIdentifier>]) {
|
||||
self.entityStorage = entityStorage
|
||||
self.componentsByType = componentsByType
|
||||
|
|
|
|||
|
|
@ -5,23 +5,36 @@
|
|||
// Created by Christian Treffs on 30.10.17.
|
||||
//
|
||||
|
||||
public struct UnorderedSparseSet<Element> {
|
||||
public typealias Index = Int
|
||||
public typealias Key = Int
|
||||
/// An (unordered) sparse set.
|
||||
///
|
||||
/// - `Element`: the element (instance) to store.
|
||||
/// - `Key`: the unique, hashable datastructure to use as a key to retrieve
|
||||
/// an element from the sparse set.
|
||||
///
|
||||
/// See <https://github.com/bombela/sparseset/blob/master/src/lib.rs> for a reference implementation.
|
||||
public struct UnorderedSparseSet<Element, Key: Hashable & Codable> {
|
||||
/// An index into the dense store.
|
||||
public typealias DenseIndex = Int
|
||||
|
||||
/// A sparse store holding indices into the dense mapped to key.
|
||||
public typealias SparseStore = [Key: DenseIndex]
|
||||
|
||||
/// A dense store holding all the entries.
|
||||
public typealias DenseStore = ContiguousArray<Entry>
|
||||
|
||||
public struct Entry {
|
||||
public let key: Key
|
||||
public let element: Element
|
||||
}
|
||||
|
||||
@usableFromInline var dense: ContiguousArray<Entry>
|
||||
@usableFromInline var sparse: [Index: Key]
|
||||
@usableFromInline var dense: DenseStore
|
||||
@usableFromInline var sparse: SparseStore
|
||||
|
||||
public init() {
|
||||
self.init(sparse: [:], dense: [])
|
||||
}
|
||||
|
||||
init(sparse: [Index: Key], dense: ContiguousArray<Entry>) {
|
||||
init(sparse: SparseStore, dense: DenseStore) {
|
||||
self.sparse = sparse
|
||||
self.dense = dense
|
||||
}
|
||||
|
|
@ -120,8 +133,18 @@ public struct UnorderedSparseSet<Element> {
|
|||
return (denseIndex, entry.element)
|
||||
}
|
||||
|
||||
@inlinable public var first: Element? {
|
||||
dense.first?.element
|
||||
}
|
||||
|
||||
@inlinable public var last: Element? {
|
||||
dense.last?.element
|
||||
}
|
||||
}
|
||||
|
||||
extension UnorderedSparseSet where Key == Int {
|
||||
@inlinable
|
||||
public subscript(position: Index) -> Element {
|
||||
public subscript(position: DenseIndex) -> Element {
|
||||
get {
|
||||
get(unsafeAt: position)
|
||||
}
|
||||
|
|
@ -130,14 +153,6 @@ public struct UnorderedSparseSet<Element> {
|
|||
insert(newValue, at: position)
|
||||
}
|
||||
}
|
||||
|
||||
@inlinable public var first: Element? {
|
||||
dense.first?.element
|
||||
}
|
||||
|
||||
@inlinable public var last: Element? {
|
||||
dense.last?.element
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Sequence
|
||||
|
|
@ -148,9 +163,9 @@ extension UnorderedSparseSet: Sequence {
|
|||
|
||||
// MARK: - UnorderedSparseSetIterator
|
||||
public struct ElementIterator: IteratorProtocol {
|
||||
public private(set) var iterator: IndexingIterator<ContiguousArray<UnorderedSparseSet<Element>.Entry>>
|
||||
public private(set) var iterator: IndexingIterator<ContiguousArray<UnorderedSparseSet<Element, Key>.Entry>>
|
||||
|
||||
public init(_ sparseSet: UnorderedSparseSet<Element>) {
|
||||
public init(_ sparseSet: UnorderedSparseSet<Element, Key>) {
|
||||
iterator = sparseSet.dense.makeIterator()
|
||||
}
|
||||
|
||||
|
|
@ -163,7 +178,7 @@ extension UnorderedSparseSet: Sequence {
|
|||
// MARK: - Equatable
|
||||
extension UnorderedSparseSet.Entry: Equatable where Element: Equatable { }
|
||||
extension UnorderedSparseSet: Equatable where Element: Equatable {
|
||||
public static func == (lhs: UnorderedSparseSet<Element>, rhs: UnorderedSparseSet<Element>) -> Bool {
|
||||
public static func == (lhs: UnorderedSparseSet<Element, Key>, rhs: UnorderedSparseSet<Element, Key>) -> Bool {
|
||||
lhs.dense == rhs.dense && lhs.sparse == rhs.sparse
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,11 +9,11 @@
|
|||
import XCTest
|
||||
|
||||
class SparseSetTests: XCTestCase {
|
||||
var set: UnorderedSparseSet<Position>!
|
||||
var set: UnorderedSparseSet<Position, Int>!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
set = UnorderedSparseSet<Position>()
|
||||
set = UnorderedSparseSet<Position, Int>()
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
|
|
@ -387,7 +387,7 @@ class SparseSetTests: XCTestCase {
|
|||
|
||||
func testSparseSetDoubleRemove() {
|
||||
class AClass { }
|
||||
var set = UnorderedSparseSet<AClass>()
|
||||
var set = UnorderedSparseSet<AClass, Int>()
|
||||
let a = AClass()
|
||||
let b = AClass()
|
||||
set.insert(a, at: 0)
|
||||
|
|
@ -471,7 +471,7 @@ class SparseSetTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testSparseSetReduce() {
|
||||
var characters = UnorderedSparseSet<Character>()
|
||||
var characters = UnorderedSparseSet<Character, Int>()
|
||||
|
||||
characters.insert("H", at: 4)
|
||||
characters.insert("e", at: 13)
|
||||
|
|
@ -497,7 +497,7 @@ class SparseSetTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testSubscript() {
|
||||
var characters = UnorderedSparseSet<Character>()
|
||||
var characters = UnorderedSparseSet<Character, Int>()
|
||||
|
||||
characters[4] = "H"
|
||||
characters[13] = "e"
|
||||
|
|
@ -528,7 +528,7 @@ class SparseSetTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testStartEndIndex() {
|
||||
var set = UnorderedSparseSet<Character>()
|
||||
var set = UnorderedSparseSet<Character, Int>()
|
||||
|
||||
set.insert("C", at: 33)
|
||||
set.insert("A", at: 11)
|
||||
|
|
@ -538,4 +538,22 @@ class SparseSetTests: XCTestCase {
|
|||
|
||||
XCTAssertEqual(mapped, ["C", "A", "B"])
|
||||
}
|
||||
|
||||
func testAlternativeKey() {
|
||||
|
||||
var set = UnorderedSparseSet<Character, String>()
|
||||
|
||||
set.insert("A", at: "a")
|
||||
set.insert("C", at: "c")
|
||||
set.insert("B", at: "b")
|
||||
|
||||
let mapped = set.dense.map { $0.element }
|
||||
XCTAssertEqual(mapped, ["A", "C", "B"])
|
||||
let keyValues = set.sparse.sorted(by: { $0.value < $1.value }).map { ($0.key, $0.value) }
|
||||
for (a, b) in zip(keyValues, [("a", 0), ("c", 1), ("b", 2)]) {
|
||||
XCTAssertEqual(a.0, b.0)
|
||||
XCTAssertEqual(a.1, b.1)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ extension SparseSetTests {
|
|||
// `swift test --generate-linuxmain`
|
||||
// to regenerate.
|
||||
static let __allTests__SparseSetTests = [
|
||||
("testAlternativeKey", testAlternativeKey),
|
||||
("testSparseSetAdd", testSparseSetAdd),
|
||||
("testSparseSetAddAndReplace", testSparseSetAddAndReplace),
|
||||
("testSparseSetClear", testSparseSetClear),
|
||||
|
|
|
|||
Loading…
Reference in New Issue