@@ -3,20 +3,17 @@ import ReactiveSwift
33import Result
44
55public final class ReactiveArray < Element> {
6-
76 public typealias Snapshot = ContiguousArray < Element >
87 public typealias Change = Delta < Snapshot , IndexSet >
98
10- public let signal : Signal < Change , NoError >
11-
12- fileprivate var elements : ContiguousArray < Element >
9+ fileprivate let storage : Storage < ContiguousArray < Element > >
1310
11+ public let signal : Signal < Change , NoError >
1412 fileprivate let innerObserver : Observer < Change , NoError >
1513
1614 public init ( _ elements: [ Element ] ) {
17- self . elements = ContiguousArray ( elements)
18-
1915 ( signal, innerObserver) = Signal < Change , NoError > . pipe ( )
16+ storage = Storage ( ContiguousArray ( elements) )
2017 }
2118
2219 public convenience init ( ) {
@@ -32,21 +29,22 @@ public final class ReactiveArray<Element> {
3229extension ReactiveArray {
3330
3431 public var producer : SignalProducer < Change , NoError > {
35- return SignalProducer < Change , NSError > . attempt { [ weak self] in
36- guard let `self` = self
37- else { return . failure( NSError ( domain: " org.RACCommunity.ReactiveCollections " , code: 0 , userInfo: nil ) ) }
38-
39- return . success(
40- Delta (
41- previous: [ ] ,
42- current: self . elements,
43- inserts: IndexSet ( integersIn: self . indices) ,
44- deletes: . empty,
45- updates: . empty
46- )
47- ) }
48- . flatMapError { _ in . empty }
49- . concat ( SignalProducer ( signal) )
32+ return SignalProducer { [ weak self, storage] observer, disposable in
33+ storage. modify { elements in
34+ let delta = Delta ( previous: [ ] ,
35+ current: elements,
36+ inserts: IndexSet ( integersIn: elements. indices) ,
37+ deletes: . empty,
38+ updates: . empty)
39+ observer. send ( value: delta)
40+
41+ if let strongSelf = self {
42+ disposable += strongSelf. signal. observe ( observer)
43+ } else {
44+ observer. sendCompleted ( )
45+ }
46+ }
47+ }
5048 }
5149}
5250
@@ -64,16 +62,16 @@ extension ReactiveArray: ExpressibleByArrayLiteral {
6462extension ReactiveArray : MutableCollection {
6563
6664 public var startIndex : Int {
67- return elements. startIndex
65+ return storage . elements. startIndex
6866 }
6967
7068 public var endIndex : Int {
71- return elements. endIndex
69+ return storage . elements. endIndex
7270 }
7371
7472 public subscript( position: Int ) -> Element {
7573 get {
76- return elements [ position]
74+ return storage . elements [ position]
7775 }
7876 set {
7977 replaceSubrange ( position..< index ( after: position) , with: CollectionOfOne ( newValue) )
@@ -82,7 +80,7 @@ extension ReactiveArray: MutableCollection {
8280
8381 public subscript( bounds: Range < Int > ) -> ArraySlice < Element > {
8482 get {
85- return elements [ bounds]
83+ return storage . elements [ bounds]
8684 }
8785 set {
8886 replaceSubrange ( bounds, with: newValue)
@@ -124,29 +122,29 @@ extension ReactiveArray: RangeReplaceableCollection {
124122
125123 public func remove( at position: Int ) -> Element {
126124 precondition ( !isEmpty, " can't remove from an empty array " )
127- let result = self [ position]
128- removeSubrange ( position..< index ( after: position) )
129- return result
125+
126+ return storage. modify { elements in
127+ let value = elements [ position]
128+ elements. remove ( at: position)
129+ return value
130+ }
130131 }
131132
132133 public func removeAll( keepingCapacity keepCapacity: Bool = false ) {
133134 if keepCapacity {
134135 removeSubrange ( indices)
135136 } else {
136-
137- let previous = elements
138-
139- elements. removeAll ( )
140-
141- innerObserver. send ( value:
142- Delta (
143- previous: previous,
144- current: elements,
145- inserts: . empty,
146- deletes: IndexSet ( integersIn: previous. indices) ,
147- updates: . empty
148- )
149- )
137+ storage. modify { elements in
138+ let previous = storage. elements
139+ elements. removeAll ( )
140+
141+ let delta = Delta ( previous: previous,
142+ current: elements,
143+ inserts: . empty,
144+ deletes: IndexSet ( integersIn: previous. indices) ,
145+ updates: . empty)
146+ innerObserver. send ( value: delta)
147+ }
150148 }
151149 }
152150
@@ -201,27 +199,59 @@ extension ReactiveArray: RangeReplaceableCollection {
201199 }
202200
203201 public func replaceSubrange< C> ( _ subrange: Range < Int > , with newElements: C ) where C: Collection , C. Iterator. Element == Element {
202+ storage. modify { elements in
203+ let previous = elements
204204
205- let previous = elements
206-
207- elements. replaceSubrange ( subrange, with: newElements)
205+ elements. replaceSubrange ( subrange, with: newElements)
208206
209- let inserts = IndexSet ( integersIn: subrange. lowerBound..< subrange. lowerBound. advanced ( by: newElements. underestimatedCount) )
210- let deletes = IndexSet ( integersIn: subrange)
211- let updates = inserts. intersection ( deletes)
207+ let insertsUpperBound = subrange. lowerBound. advanced ( by: Int ( newElements. distance ( from: newElements. startIndex, to: newElements. endIndex) . toIntMax ( ) ) )
208+ let inserts = IndexSet ( integersIn: subrange. lowerBound ..< insertsUpperBound)
209+ let deletes = IndexSet ( integersIn: subrange)
210+ let updates = inserts. intersection ( deletes)
212211
213- innerObserver. send ( value:
214- Delta (
215- previous: previous,
216- current: elements,
217- inserts: inserts. subtracting ( updates) ,
218- deletes: deletes. subtracting ( updates) ,
219- updates: updates
220- )
221- )
212+ let delta = Delta ( previous: previous,
213+ current: storage. elements,
214+ inserts: inserts. subtracting ( updates) ,
215+ deletes: deletes. subtracting ( updates) ,
216+ updates: updates)
217+ innerObserver. send ( value: delta)
218+ }
222219 }
223220
224221 public func reserveCapacity( _ n: Int ) {
225- elements. reserveCapacity ( n)
222+ storage. modify { $0. reserveCapacity ( n) }
223+ }
224+ }
225+
226+ private final class Storage < Elements> {
227+ private var _elements : Elements
228+
229+ var elements : Elements {
230+ get { return _elements }
231+ set {
232+ writeLock. lock ( )
233+ _elements = newValue
234+ writeLock. unlock ( )
235+ }
236+ }
237+
238+ /// A lock to protect mutations and their subsequent event emission. Reads do
239+ /// not need to be protected, since the copy-on-write already guards reads.
240+ /// The producer, however, has to acquire the lock to block new mutations
241+ /// before it observes the delta signal.
242+ fileprivate let writeLock : NSLock
243+
244+ init ( _ elements: Elements ) {
245+ self . _elements = elements
246+
247+ writeLock = NSLock ( )
248+ writeLock. name = " org.RACCommunity.ReactiveCollections.ReactiveArray.writeLock "
249+ }
250+
251+ func modify< Result> ( _ action: ( inout Elements ) throws -> Result ) rethrows -> Result {
252+ writeLock. lock ( )
253+ let returnValue = try action ( & _elements)
254+ writeLock. unlock ( )
255+ return returnValue
226256 }
227257}
0 commit comments