88
99/// A uniquely identifying token for removing a value that was inserted into a
1010/// Bag.
11- public final class RemovalToken {
12- fileprivate var identifier : UInt ?
13-
14- fileprivate init ( identifier: UInt ) {
15- self . identifier = identifier
16- }
17- }
11+ public final class RemovalToken { }
1812
1913/// An unordered, non-unique collection of values of type `Element`.
2014public struct Bag < Element> {
21- fileprivate var elements : [ BagElement < Element > ] = [ ]
22- private var currentIdentifier : UInt = 0
15+ fileprivate var elements : ContiguousArray < BagElement < Element > > = [ ]
2316
24- public init ( ) {
25- }
17+ public init ( ) { }
2618
2719 /// Insert the given value into `self`, and return a token that can
28- /// later be passed to `removeValueForToken( )`.
20+ /// later be passed to `remove(using: )`.
2921 ///
3022 /// - parameters:
3123 /// - value: A value that will be inserted.
3224 @discardableResult
3325 public mutating func insert( _ value: Element ) -> RemovalToken {
34- let ( nextIdentifier, overflow) = UInt . addWithOverflow ( currentIdentifier, 1 )
35- if overflow {
36- reindex ( )
37- }
38-
39- let token = RemovalToken ( identifier: currentIdentifier)
40- let element = BagElement ( value: value, identifier: currentIdentifier, token: token)
26+ let token = RemovalToken ( )
27+ let element = BagElement ( value: value, token: token)
4128
4229 elements. append ( element)
43- currentIdentifier = nextIdentifier
44-
4530 return token
4631 }
4732
@@ -52,29 +37,15 @@ public struct Bag<Element> {
5237 /// - parameters:
5338 /// - token: A token returned from a call to `insert()`.
5439 public mutating func remove( using token: RemovalToken ) {
55- if let identifier = token. identifier {
56- // Removal is more likely for recent objects than old ones.
57- for i in elements. indices. reversed ( ) {
58- if elements [ i] . identifier == identifier {
59- elements. remove ( at: i)
60- token. identifier = nil
61- break
62- }
40+ let tokenIdentifier = ObjectIdentifier ( token)
41+ // Removal is more likely for recent objects than old ones.
42+ for i in elements. indices. reversed ( ) {
43+ if ObjectIdentifier ( elements [ i] . token) == tokenIdentifier {
44+ elements. remove ( at: i)
45+ break
6346 }
6447 }
6548 }
66-
67- /// In the event of an identifier overflow (highly, highly unlikely), reset
68- /// all current identifiers to reclaim a contiguous set of available
69- /// identifiers for the future.
70- private mutating func reindex( ) {
71- for i in elements. indices {
72- currentIdentifier = UInt ( i)
73-
74- elements [ i] . identifier = currentIdentifier
75- elements [ i] . token. identifier = currentIdentifier
76- }
77- }
7849}
7950
8051extension Bag : Collection {
@@ -95,11 +66,14 @@ extension Bag: Collection {
9566 public func index( after i: Index ) -> Index {
9667 return i + 1
9768 }
69+
70+ public func makeIterator( ) -> BagIterator < Element > {
71+ return BagIterator ( elements)
72+ }
9873}
9974
10075private struct BagElement < Value> {
10176 let value : Value
102- var identifier : UInt
10377 let token : RemovalToken
10478}
10579
@@ -108,3 +82,26 @@ extension BagElement: CustomStringConvertible {
10882 return " BagElement( \( value) ) "
10983 }
11084}
85+
86+ public struct BagIterator < Element> : IteratorProtocol {
87+ private let base : ContiguousArray < BagElement < Element > >
88+ private var nextIndex : Int
89+ private let endIndex : Int
90+
91+ fileprivate init ( _ base: ContiguousArray < BagElement < Element > > ) {
92+ self . base = base
93+ nextIndex = base. startIndex
94+ endIndex = base. endIndex
95+ }
96+
97+ public mutating func next( ) -> Element ? {
98+ let currentIndex = nextIndex
99+
100+ if currentIndex < endIndex {
101+ nextIndex = currentIndex + 1
102+ return base [ currentIndex] . value
103+ }
104+
105+ return nil
106+ }
107+ }
0 commit comments