@@ -149,75 +149,44 @@ extension _ArrayBufferProtocol {
149149 elementsOf newValues: __owned C
150150 ) where C: Collection , C. Element == Element {
151151 _internalInvariant ( startIndex == 0 , " _SliceBuffer should override this function. " )
152- let oldCount = self . count
152+ let elements = self . firstElementAddress
153+
154+ // erase all the elements we're replacing to create a hole
155+ let holeStart = elements + subrange. lowerBound
156+ let holeEnd = holeStart + newCount
153157 let eraseCount = subrange. count
158+ holeStart. deinitialize ( count: eraseCount)
154159
155160 let growth = newCount - eraseCount
156- // This check will prevent storing a 0 count to the empty array singleton.
157- if growth != 0 {
158- self . count = oldCount + growth
159- }
160161
161- let elements = self . subscriptBaseAddress
162- let oldTailIndex = subrange. upperBound
163- let oldTailStart = elements + oldTailIndex
164- let newTailIndex = oldTailIndex + growth
165- let newTailStart = oldTailStart + growth
166- let tailCount = oldCount - subrange. upperBound
167-
168- if growth > 0 {
169- // Slide the tail part of the buffer forwards, in reverse order
170- // so as not to self-clobber.
171- newTailStart. moveInitialize ( from: oldTailStart, count: tailCount)
172-
173- // Update the original subrange
174- var i = newValues. startIndex
175- for j in subrange {
176- elements [ j] = newValues [ i]
177- newValues. formIndex ( after: & i)
178- }
179- // Initialize the hole left by sliding the tail forward
180- for j in oldTailIndex..< newTailIndex {
181- ( elements + j) . initialize ( to: newValues [ i] )
182- newValues. formIndex ( after: & i)
183- }
184- _expectEnd ( of: newValues, is: i)
162+ if growth != 0 {
163+ let tailStart = elements + subrange. upperBound
164+ let tailCount = self . count - subrange. upperBound
165+ holeEnd. moveInitialize ( from: tailStart, count: tailCount)
166+ self . count += growth
185167 }
186- else { // We're not growing the buffer
187- // Assign all the new elements into the start of the subrange
188- var i = subrange. lowerBound
189- var j = newValues. startIndex
190- for _ in 0 ..< newCount {
191- elements [ i] = newValues [ j]
192- i += 1
193- newValues. formIndex ( after: & j)
194- }
195- _expectEnd ( of: newValues, is: j)
196-
197- // If the size didn't change, we're done.
198- if growth == 0 {
199- return
200- }
201168
202- // Move the tail backward to cover the shrinkage.
203- let shrinkage = - growth
204- if tailCount > shrinkage { // If the tail length exceeds the shrinkage
205-
206- // Update the rest of the replaced range with the first
207- // part of the tail.
208- newTailStart . moveUpdate ( from : oldTailStart , count : shrinkage )
209-
210- // Slide the rest of the tail back
211- oldTailStart . moveInitialize (
212- from: oldTailStart + shrinkage , count: tailCount - shrinkage )
169+ // don't use UnsafeMutableBufferPointer.initialize(fromContentsOf:)
170+ // since it behaves differently on collections that misreport count,
171+ // and breaks validation tests for those usecases / potentially
172+ // breaks ABI guarantees.
173+ if newCount > 0 {
174+ let done : Void ? = newValues . withContiguousStorageIfAvailable {
175+ _precondition (
176+ $0 . count == newCount ,
177+ " invalid Collection: count differed in successive traversals "
178+ )
179+ holeStart . initialize ( from: $0 . baseAddress! , count: newCount )
213180 }
214- else { // Tail fits within erased elements
215- // Update the start of the replaced range with the tail
216- newTailStart. moveUpdate ( from: oldTailStart, count: tailCount)
217-
218- // Destroy elements remaining after the tail in subrange
219- ( newTailStart + tailCount) . deinitialize (
220- count: shrinkage - tailCount)
181+ if done == nil {
182+ var place = holeStart
183+ var i = newValues. startIndex
184+ while place < holeEnd {
185+ place. initialize ( to: newValues [ i] )
186+ place += 1
187+ newValues. formIndex ( after: & i)
188+ }
189+ _expectEnd ( of: newValues, is: i)
221190 }
222191 }
223192 }
0 commit comments