From f6b55a786461d80afeb4ec0505770420fad45bc2 Mon Sep 17 00:00:00 2001 From: Anders Date: Sat, 26 Nov 2016 04:03:24 +0100 Subject: [PATCH 1/3] Optimized `Bag`. --- Sources/Bag.swift | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/Sources/Bag.swift b/Sources/Bag.swift index 657f74639..c1ad78850 100644 --- a/Sources/Bag.swift +++ b/Sources/Bag.swift @@ -18,7 +18,7 @@ public final class RemovalToken { /// An unordered, non-unique collection of values of type `Element`. public struct Bag { - fileprivate var elements: [BagElement] = [] + fileprivate var elements: ContiguousArray> = [] private var currentIdentifier: UInt = 0 public init() { @@ -95,6 +95,10 @@ extension Bag: Collection { public func index(after i: Index) -> Index { return i + 1 } + + public func makeIterator() -> BagIterator { + return BagIterator(elements) + } } private struct BagElement { @@ -108,3 +112,26 @@ extension BagElement: CustomStringConvertible { return "BagElement(\(value))" } } + +public struct BagIterator: IteratorProtocol { + private let base: ContiguousArray> + private var nextIndex: Int + private let endIndex: Int + + fileprivate init(_ base: ContiguousArray>) { + self.base = base + nextIndex = base.startIndex + endIndex = base.endIndex + } + + public mutating func next() -> Element? { + let currentIndex = nextIndex + nextIndex = currentIndex + 1 + + if currentIndex < endIndex { + return base[currentIndex].value + } + + return nil + } +} From 30abe6ff8cc53ade0d39a4666a1e23908c288528 Mon Sep 17 00:00:00 2001 From: Anders Date: Sat, 26 Nov 2016 04:37:26 +0100 Subject: [PATCH 2/3] Replace the monotonic ID in `Bag` with `ObjectIdentifier`. --- Sources/Bag.swift | 52 ++++++++++------------------------------------- 1 file changed, 11 insertions(+), 41 deletions(-) diff --git a/Sources/Bag.swift b/Sources/Bag.swift index c1ad78850..63d7f6ea1 100644 --- a/Sources/Bag.swift +++ b/Sources/Bag.swift @@ -8,40 +8,25 @@ /// A uniquely identifying token for removing a value that was inserted into a /// Bag. -public final class RemovalToken { - fileprivate var identifier: UInt? - - fileprivate init(identifier: UInt) { - self.identifier = identifier - } -} +public final class RemovalToken {} /// An unordered, non-unique collection of values of type `Element`. public struct Bag { fileprivate var elements: ContiguousArray> = [] - private var currentIdentifier: UInt = 0 - public init() { - } + public init() {} /// Insert the given value into `self`, and return a token that can - /// later be passed to `removeValueForToken()`. + /// later be passed to `remove(using:)`. /// /// - parameters: /// - value: A value that will be inserted. @discardableResult public mutating func insert(_ value: Element) -> RemovalToken { - let (nextIdentifier, overflow) = UInt.addWithOverflow(currentIdentifier, 1) - if overflow { - reindex() - } - - let token = RemovalToken(identifier: currentIdentifier) - let element = BagElement(value: value, identifier: currentIdentifier, token: token) + let token = RemovalToken() + let element = BagElement(value: value, token: token) elements.append(element) - currentIdentifier = nextIdentifier - return token } @@ -52,29 +37,15 @@ public struct Bag { /// - parameters: /// - token: A token returned from a call to `insert()`. public mutating func remove(using token: RemovalToken) { - if let identifier = token.identifier { - // Removal is more likely for recent objects than old ones. - for i in elements.indices.reversed() { - if elements[i].identifier == identifier { - elements.remove(at: i) - token.identifier = nil - break - } + let tokenIdentifier = ObjectIdentifier(token) + // Removal is more likely for recent objects than old ones. + for i in elements.indices.reversed() { + if ObjectIdentifier(elements[i].token) == tokenIdentifier { + elements.remove(at: i) + break } } } - - /// In the event of an identifier overflow (highly, highly unlikely), reset - /// all current identifiers to reclaim a contiguous set of available - /// identifiers for the future. - private mutating func reindex() { - for i in elements.indices { - currentIdentifier = UInt(i) - - elements[i].identifier = currentIdentifier - elements[i].token.identifier = currentIdentifier - } - } } extension Bag: Collection { @@ -103,7 +74,6 @@ extension Bag: Collection { private struct BagElement { let value: Value - var identifier: UInt let token: RemovalToken } From 439f535825efc88442aae347c534723dd5faca06 Mon Sep 17 00:00:00 2001 From: Anders Date: Sun, 27 Nov 2016 19:58:36 +0100 Subject: [PATCH 3/3] Stop increasing the `nextIndex` beyond `endIndex` in `BagIterator`. --- Sources/Bag.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Bag.swift b/Sources/Bag.swift index 63d7f6ea1..3434f5152 100644 --- a/Sources/Bag.swift +++ b/Sources/Bag.swift @@ -96,9 +96,9 @@ public struct BagIterator: IteratorProtocol { public mutating func next() -> Element? { let currentIndex = nextIndex - nextIndex = currentIndex + 1 if currentIndex < endIndex { + nextIndex = currentIndex + 1 return base[currentIndex].value }