@@ -41,16 +41,16 @@ public struct IdentifiedArray<ID, Element>: MutableCollection, RandomAccessColle
41
41
where ID: Hashable {
42
42
/// A key path to a value that identifies an element.
43
43
public let id : KeyPath < Element , ID >
44
-
44
+
45
45
/// A raw array of each element's identifier.
46
46
public private( set) var ids : [ ID ]
47
-
47
+
48
48
/// A raw array of the underlying elements.
49
49
public var elements : [ Element ] { Array ( self ) }
50
-
50
+
51
51
// TODO: Support multiple elements with the same identifier but different data.
52
52
private var dictionary : [ ID : Element ]
53
-
53
+
54
54
/// Initializes an identified array with a sequence of elements and a key
55
55
/// path to an element's identifier.
56
56
///
@@ -60,92 +60,92 @@ where ID: Hashable {
60
60
public init < S> ( _ elements: S , id: KeyPath < Element , ID > )
61
61
where S: Sequence , S. Element == Element {
62
62
self . id = id
63
-
63
+
64
64
let idsAndElements = elements. map { ( id: $0 [ keyPath: id] , element: $0) }
65
65
self . ids = idsAndElements. map { $0. id }
66
66
self . dictionary = Dictionary ( idsAndElements, uniquingKeysWith: { $1 } )
67
67
}
68
-
68
+
69
69
/// Initializes an empty identified array with a key path to an element's
70
70
/// identifier.
71
71
///
72
72
/// - Parameter id: A key path to a value that identifies an element.
73
73
public init ( id: KeyPath < Element , ID > ) {
74
74
self . init ( [ ] , id: id)
75
75
}
76
-
76
+
77
77
public var startIndex : Int { self . ids. startIndex }
78
78
public var endIndex : Int { self . ids. endIndex }
79
-
79
+
80
80
public func index( after i: Int ) -> Int {
81
81
self . ids. index ( after: i)
82
82
}
83
-
83
+
84
84
public func index( before i: Int ) -> Int {
85
85
self . ids. index ( before: i)
86
86
}
87
-
87
+
88
88
public subscript( position: Int ) -> Element {
89
89
// NB: `_read` crashes Xcode Preview compilation.
90
90
get { self . dictionary [ self . ids [ position] ] ! }
91
91
_modify { yield & self . dictionary [ self . ids [ position] ] ! }
92
92
}
93
-
93
+
94
94
#if DEBUG
95
- /// Direct access to an element by its identifier.
96
- ///
97
- /// - Parameter id: The identifier of element to access. Must be a valid identifier for an
98
- /// element of the array and will _not_ insert elements that are not already in the array, or
99
- /// remove elements when passed `nil`. Use `append` or `insert(_:at:)` to insert elements. Use
100
- /// `remove(id:)` to remove an element by its identifier.
101
- /// - Returns: The element.
102
- public subscript( id id: ID ) -> Element ? {
103
- get { self . dictionary [ id] }
104
- set {
105
- if newValue != nil && self . dictionary [ id] == nil {
106
- fatalError (
107
- """
108
- Can't update element with identifier \( id) because no such element exists in the array.
109
-
110
- If you are trying to insert an element into the array, use the " append " or " insert " \
111
- methods.
112
- """
113
- )
114
- }
115
- if newValue == nil {
116
- fatalError (
117
- """
118
- Can't update element with identifier \( id) with nil.
119
-
120
- If you are trying to remove an element from the array, use the " remove(id:) method. "
121
- """
122
- )
95
+ /// Direct access to an element by its identifier.
96
+ ///
97
+ /// - Parameter id: The identifier of element to access. Must be a valid identifier for an
98
+ /// element of the array and will _not_ insert elements that are not already in the array, or
99
+ /// remove elements when passed `nil`. Use `append` or `insert(_:at:)` to insert elements. Use
100
+ /// `remove(id:)` to remove an element by its identifier.
101
+ /// - Returns: The element.
102
+ public subscript( id id: ID ) -> Element ? {
103
+ get { self . dictionary [ id] }
104
+ set {
105
+ if newValue != nil && self . dictionary [ id] == nil {
106
+ fatalError (
107
+ """
108
+ Can't update element with identifier \( id) because no such element exists in the array.
109
+
110
+ If you are trying to insert an element into the array, use the " append " or " insert " \
111
+ methods.
112
+ """
113
+ )
114
+ }
115
+ if newValue == nil {
116
+ fatalError (
117
+ """
118
+ Can't update element with identifier \( id) with nil.
119
+
120
+ If you are trying to remove an element from the array, use the " remove(id:) method. "
121
+ """
122
+ )
123
+ }
124
+ self . dictionary [ id] = newValue
123
125
}
124
- self . dictionary [ id] = newValue
125
126
}
126
- }
127
127
#else
128
- public subscript( id id: ID ) -> Element ? {
129
- // NB: `_read` crashes Xcode Preview compilation.
130
- get { self . dictionary [ id] }
131
- _modify { yield & self . dictionary [ id] }
132
- }
128
+ public subscript( id id: ID ) -> Element ? {
129
+ // NB: `_read` crashes Xcode Preview compilation.
130
+ get { self . dictionary [ id] }
131
+ _modify { yield & self . dictionary [ id] }
132
+ }
133
133
#endif
134
-
134
+
135
135
public mutating func insert( _ newElement: Element , at i: Int ) {
136
136
let id = newElement [ keyPath: self . id]
137
137
self . dictionary [ id] = newElement
138
138
self . ids. insert ( id, at: i)
139
139
}
140
-
140
+
141
141
public mutating func insert< C> (
142
142
contentsOf newElements: C , at i: Int
143
143
) where C: Collection , Element == C . Element {
144
144
for newElement in newElements. reversed ( ) {
145
145
self . insert ( newElement, at: i)
146
146
}
147
147
}
148
-
148
+
149
149
/// Removes and returns the element with the specified identifier.
150
150
///
151
151
/// - Parameter id: The identifier of the element to remove.
@@ -158,12 +158,12 @@ where ID: Hashable {
158
158
self . ids. removeAll ( where: { $0 == id } )
159
159
return element!
160
160
}
161
-
161
+
162
162
@discardableResult
163
163
public mutating func remove( at position: Int ) -> Element {
164
164
self . remove ( id: self . ids. remove ( at: position) )
165
165
}
166
-
166
+
167
167
public mutating func removeAll( where shouldBeRemoved: ( Element ) throws -> Bool ) rethrows {
168
168
var ids : [ ID ] = [ ]
169
169
for (index, id) in zip ( self . ids. indices, self . ids) . reversed ( ) {
@@ -176,34 +176,34 @@ where ID: Hashable {
176
176
self . dictionary [ id] = nil
177
177
}
178
178
}
179
-
179
+
180
180
public mutating func remove( atOffsets offsets: IndexSet ) {
181
181
for offset in offsets. reversed ( ) {
182
182
_ = self . remove ( at: offset)
183
183
}
184
184
}
185
-
185
+
186
186
#if canImport(SwiftUI)
187
- public mutating func move( fromOffsets source: IndexSet , toOffset destination: Int ) {
188
- self . ids. move ( fromOffsets: source, toOffset: destination)
189
- }
187
+ public mutating func move( fromOffsets source: IndexSet , toOffset destination: Int ) {
188
+ self . ids. move ( fromOffsets: source, toOffset: destination)
189
+ }
190
190
#endif
191
-
191
+
192
192
public mutating func sort( by areInIncreasingOrder: ( Element , Element ) throws -> Bool ) rethrows {
193
193
try self . ids. sort {
194
194
try areInIncreasingOrder ( self . dictionary [ $0] !, self . dictionary [ $1] !)
195
195
}
196
196
}
197
-
197
+
198
198
public mutating func shuffle< T> ( using generator: inout T ) where T: RandomNumberGenerator {
199
199
ids. shuffle ( using: & generator)
200
200
}
201
-
201
+
202
202
public mutating func shuffle( ) {
203
203
var rng = SystemRandomNumberGenerator ( )
204
204
self . shuffle ( using: & rng)
205
205
}
206
-
206
+
207
207
public mutating func reverse( ) {
208
208
ids. reverse ( )
209
209
}
@@ -278,17 +278,17 @@ where Element: Identifiable, ID == Element.ID {
278
278
public init ( ) {
279
279
self . init ( [ ] , id: \. id)
280
280
}
281
-
281
+
282
282
public mutating func replaceSubrange< C, R> ( _ subrange: R , with newElements: C )
283
283
where C: Collection , R: RangeExpression , Element == C . Element , Index == R . Bound {
284
284
let replacingIds = self . ids [ subrange]
285
285
let newIds = newElements. map { $0. id }
286
286
ids. replaceSubrange ( subrange, with: newIds)
287
-
287
+
288
288
for element in newElements {
289
289
self . dictionary [ element. id] = element
290
290
}
291
-
291
+
292
292
for id in replacingIds where !self . ids. contains ( id) {
293
293
self . dictionary [ id] = nil
294
294
}
0 commit comments