@@ -35,8 +35,19 @@ struct Stack<Element> : CollectionLikeSequence {
3535 BridgedPassContext . Slab. getCapacity ( ) / MemoryLayout< Element> . stride
3636 }
3737
38- private static func bind( _ slab: BridgedPassContext . Slab ) -> UnsafeMutablePointer < Element > {
39- return UnsafeMutableRawPointer ( slab. data!) . bindMemory ( to: Element . self, capacity: Stack . slabCapacity)
38+ private func allocate( after lastSlab: BridgedPassContext . Slab ? = nil ) -> BridgedPassContext . Slab {
39+ let lastSlab = lastSlab ?? BridgedPassContext . Slab ( nil )
40+ let newSlab = bridgedContext. allocSlab ( lastSlab)
41+ UnsafeMutableRawPointer ( newSlab. data!) . bindMemory ( to: Element . self, capacity: Stack . slabCapacity)
42+ return newSlab
43+ }
44+
45+ private static func element( in slab: BridgedPassContext . Slab , at index: Int ) -> Element {
46+ return pointer ( in: slab, at: index) . pointee
47+ }
48+
49+ private static func pointer( in slab: BridgedPassContext . Slab , at index: Int ) -> UnsafeMutablePointer < Element > {
50+ return UnsafeMutableRawPointer ( slab. data!) . assumingMemoryBound ( to: Element . self) + index
4051 }
4152
4253 struct Iterator : IteratorProtocol {
@@ -50,7 +61,7 @@ struct Stack<Element> : CollectionLikeSequence {
5061
5162 guard index < end else { return nil }
5263
53- let elem = Stack . bind ( slab) [ index]
64+ let elem = Stack . element ( in : slab, at : index)
5465 index += 1
5566
5667 if index >= end && slab. data != lastSlab. data {
@@ -68,23 +79,23 @@ struct Stack<Element> : CollectionLikeSequence {
6879 }
6980
7081 var first : Element ? {
71- isEmpty ? nil : Stack . bind ( firstSlab) [ 0 ]
82+ isEmpty ? nil : Stack . element ( in : firstSlab, at : 0 )
7283 }
7384
7485 var last : Element ? {
75- isEmpty ? nil : Stack . bind ( lastSlab) [ endIndex &- 1 ]
86+ isEmpty ? nil : Stack . element ( in : lastSlab, at : endIndex &- 1 )
7687 }
7788
7889 mutating func push( _ element: Element ) {
7990 if endIndex >= Stack . slabCapacity {
80- lastSlab = bridgedContext . allocSlab ( lastSlab)
91+ lastSlab = allocate ( after : lastSlab)
8192 endIndex = 0
8293 } else if firstSlab. data == nil {
8394 assert ( endIndex == 0 )
84- firstSlab = bridgedContext . allocSlab ( lastSlab )
95+ firstSlab = allocate ( )
8596 lastSlab = firstSlab
8697 }
87- ( Stack . bind ( lastSlab) + endIndex) . initialize ( to: element)
98+ Stack . pointer ( in : lastSlab, at : endIndex) . initialize ( to: element)
8899 endIndex += 1
89100 }
90101
@@ -105,7 +116,7 @@ struct Stack<Element> : CollectionLikeSequence {
105116 }
106117 assert ( endIndex > 0 )
107118 endIndex -= 1
108- let elem = ( Stack . bind ( lastSlab) + endIndex) . move ( )
119+ let elem = Stack . pointer ( in : lastSlab, at : endIndex) . move ( )
109120
110121 if endIndex == 0 {
111122 if lastSlab. data == firstSlab. data {
@@ -129,3 +140,83 @@ struct Stack<Element> : CollectionLikeSequence {
129140 /// TODO: once we have move-only types, make this a real deinit.
130141 mutating func deinitialize( ) { removeAll ( ) }
131142}
143+
144+ extension Stack {
145+ /// Mark a stack location for future iteration.
146+ ///
147+ /// TODO: Marker should be ~Escapable.
148+ struct Marker {
149+ let slab : BridgedPassContext . Slab
150+ let index : Int
151+ }
152+
153+ var top : Marker { Marker ( slab: lastSlab, index: endIndex) }
154+
155+ struct Segment : CollectionLikeSequence {
156+ let low : Marker
157+ let high : Marker
158+
159+ init ( in stack: Stack , low: Marker , high: Marker ) {
160+ if low. slab. data == nil {
161+ assert ( low. index == 0 , " invalid empty stack marker " )
162+ // `low == nil` and `high == nil` is a valid empty segment,
163+ // even though `assertValid(marker:)` would return false.
164+ if high. slab. data != nil {
165+ stack. assertValid ( marker: high)
166+ }
167+ self . low = Marker ( slab: stack. firstSlab, index: 0 )
168+ self . high = high
169+ return
170+ }
171+ stack. assertValid ( marker: low)
172+ stack. assertValid ( marker: high)
173+ self . low = low
174+ self . high = high
175+ }
176+
177+ func makeIterator( ) -> Stack . Iterator {
178+ return Iterator ( slab: low. slab, index: low. index,
179+ lastSlab: high. slab, endIndex: high. index)
180+ }
181+ }
182+
183+ /// Assert that `marker` is valid based on the current `top`.
184+ ///
185+ /// This is an assert rather than a query because slabs can reuse
186+ /// memory leading to a stale marker that appears valid.
187+ func assertValid( marker: Marker ) {
188+ var currentSlab = lastSlab
189+ var currentIndex = endIndex
190+ while currentSlab. data != marker. slab. data {
191+ assert ( currentSlab. data != firstSlab. data, " Invalid stack marker " )
192+ currentSlab = currentSlab. getPrevious ( )
193+ currentIndex = Stack . slabCapacity
194+ }
195+ assert ( marker. index <= currentIndex, " Invalid stack marker " )
196+ }
197+
198+ /// Execute the `body` closure, passing it `self` for further
199+ /// mutation of the stack and passing `marker` to mark the stack
200+ /// position prior to executing `body`. `marker` must not escape the
201+ /// `body` closure.
202+ mutating func withMarker< R> (
203+ _ body: ( inout Stack < Element > , Marker ) throws -> R ) rethrows -> R {
204+ return try body ( & self , top)
205+ }
206+
207+ /// Record a stack marker, execute a `body` closure, then execute a
208+ /// `handleNewElements` closure with the Segment that contains all
209+ /// elements that remain on the stack after being pushed on the
210+ /// stack while executing `body`. `body` must push more elements
211+ /// than it pops.
212+ mutating func withMarker< R> (
213+ pushElements body: ( inout Stack ) throws -> R ,
214+ withNewElements handleNewElements: ( ( Segment ) -> ( ) )
215+ ) rethrows -> R {
216+ return try withMarker { ( stack: inout Stack < Element > , marker: Marker ) in
217+ let result = try body ( & stack)
218+ handleNewElements ( Segment ( in: stack, low: marker, high: stack. top) )
219+ return result
220+ }
221+ }
222+ }
0 commit comments