Skip to content

Commit abbaa47

Browse files
authored
Merge pull request #12504 from glessard/umbp-nonmutating-setter
2 parents 9bd1ac9 + 0fb0d51 commit abbaa47

File tree

4 files changed

+89
-12
lines changed

4 files changed

+89
-12
lines changed

stdlib/public/core/UnsafeBufferPointer.swift.gyb

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,43 @@ extension Unsafe${Mutable}BufferPointer: ${Mutable}Collection, RandomAccessColle
275275
%end
276276
}
277277

278+
/// Accesses a contiguous subrange of the buffer's elements.
279+
///
280+
/// The accessed slice uses the same indices for the same elements as the
281+
/// original buffer uses. Always use the slice's `startIndex` property
282+
/// instead of assuming that its indices start at a particular value.
283+
///
284+
/// This example demonstrates getting a slice from a buffer of strings, finding
285+
/// the index of one of the strings in the slice, and then using that index
286+
/// in the original buffer.
287+
///
288+
%if Mutable:
289+
/// var streets = ["Adams", "Bryant", "Channing", "Douglas", "Evarts"]
290+
/// streets.withUnsafeMutableBufferPointer { buffer in
291+
/// let streetSlice = buffer[2..<buffer.endIndex]
292+
/// print(Array(streetSlice))
293+
/// // Prints "["Channing", "Douglas", "Evarts"]"
294+
/// let index = streetSlice.index(of: "Evarts") // 4
295+
/// buffer[index!] = "Eustace"
296+
/// }
297+
/// print(streets.last!)
298+
/// // Prints "Eustace"
299+
%else:
300+
/// let streets = ["Adams", "Bryant", "Channing", "Douglas", "Evarts"]
301+
/// streets.withUnsafeBufferPointer { buffer in
302+
/// let streetSlice = buffer[2..<buffer.endIndex]
303+
/// print(Array(streetSlice))
304+
/// // Prints "["Channing", "Douglas", "Evarts"]"
305+
/// let index = streetSlice.index(of: "Evarts") // 4
306+
/// print(buffer[index!])
307+
/// // Prints "Evarts"
308+
/// }
309+
%end
310+
///
311+
/// - Note: Bounds checks for `bounds` are performed only in debug mode.
312+
///
313+
/// - Parameter bounds: A range of the buffer's indices. The bounds of
314+
/// the range must be valid indices of the buffer.
278315
@_inlineable
279316
public subscript(bounds: Range<Int>)
280317
-> Slice<Unsafe${Mutable}BufferPointer<Element>>
@@ -286,11 +323,17 @@ extension Unsafe${Mutable}BufferPointer: ${Mutable}Collection, RandomAccessColle
286323
base: self, bounds: bounds)
287324
}
288325
% if Mutable:
289-
set {
326+
nonmutating set {
290327
_debugPrecondition(bounds.lowerBound >= startIndex)
291328
_debugPrecondition(bounds.upperBound <= endIndex)
329+
_debugPrecondition(bounds.count == newValue.count)
330+
292331
// FIXME: swift-3-indexing-model: tests.
293-
_writeBackMutableSlice(&self, bounds: bounds, slice: newValue)
332+
if !newValue.isEmpty {
333+
(_position! + bounds.lowerBound).assign(
334+
from: newValue.base._position! + newValue.startIndex,
335+
count: newValue.count)
336+
}
294337
}
295338
% end
296339
}

stdlib/public/core/UnsafePointer.swift.gyb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,8 @@ public struct ${Self}<Pointee>: _Pointer {
577577
/// `Pointee` must be a trivial type. After calling
578578
/// `assign(from:count:)`, the region is initialized.
579579
///
580+
/// - Note: Returns without performing work if `self` and `source` are equal.
581+
///
580582
/// - Parameters:
581583
/// - source: A pointer to at least `count` initialized instances of type
582584
/// `Pointee`. The memory regions referenced by `source` and this
@@ -596,7 +598,7 @@ public struct ${Self}<Pointee>: _Pointer {
596598
// self[i] = source[i]
597599
// }
598600
}
599-
else {
601+
else if UnsafePointer(self) != source {
600602
// assign backward from a non-following overlapping range.
601603
Builtin.assignCopyArrayBackToFront(
602604
Pointee.self, self._rawValue, source._rawValue, count._builtinWordValue)

validation-test/stdlib/CollectionType.swift.gyb

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -580,21 +580,17 @@ CollectionTypeTests.test("subscript(_: Range<Index>)/writeback") {
580580
CollectionTypeTests.test("subscript(_: Range<Index>)/defaultImplementation/sliceTooLarge")
581581
.crashOutputMatches("Cannot replace a slice of a MutableCollection with a slice of a larger size")
582582
.code {
583-
var x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
583+
var x = Slice(base: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], bounds: 0..<10)
584584
expectCrashLater()
585-
x.withUnsafeMutableBufferPointer { buffer in
586-
buffer[2..<4] = buffer[4..<8]
587-
}
585+
x[2..<4] = x[4..<8]
588586
}
589587

590588
CollectionTypeTests.test("subscript(_: Range<Index>)/defaultImplementation/sliceTooSmall")
591589
.crashOutputMatches("Cannot replace a slice of a MutableCollection with a slice of a smaller size")
592590
.code {
593-
var x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
591+
var x = Slice(base: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], bounds: 0..<10)
594592
expectCrashLater()
595-
x.withUnsafeMutableBufferPointer { buffer in
596-
buffer[2..<6] = buffer[6..<8]
597-
}
593+
x[2..<6] = x[6..<8]
598594
}
599595

600596
//===----------------------------------------------------------------------===//

validation-test/stdlib/UnsafeBufferPointer.swift.gyb

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -756,8 +756,11 @@ UnsafeMutable${'Raw' if IsRaw else ''}BufferPointerTestSuite.test("subscript/${R
756756
defer { deallocateFor${Raw}Buffer(
757757
sliceMemory, count: replacementValues.count) }
758758

759-
// This produces a spurious compiler warning, someone take a look lol?
759+
% if RangeName == 'range':
760+
let buffer = SubscriptSetTest.create${SelfName}(from: memory)
761+
% else:
760762
var buffer = SubscriptSetTest.create${SelfName}(from: memory)
763+
% end
761764

762765
% if IsRaw:
763766
// A raw buffer pointer has debug bounds checks on indices, and
@@ -793,6 +796,39 @@ UnsafeMutable${'Raw' if IsRaw else ''}BufferPointerTestSuite.test("subscript/${R
793796

794797
% end # RangeName
795798

799+
UnsafeMutable${'Raw' if IsRaw else ''}BufferPointerTestSuite.test("subscript/set/overlaps") {
800+
% if IsRaw:
801+
let buffer = UnsafeMutableRawBufferPointer.allocate(count: 4)
802+
% else:
803+
let buffer = UnsafeMutableBufferPointer<Int>.allocate(capacity: 4)
804+
% end
805+
defer { buffer.deallocate() }
806+
807+
// Right Overlap
808+
buffer[0] = 1
809+
buffer[1] = 2
810+
buffer[1..<3] = buffer[0..<2]
811+
expectEqual(1, buffer[1])
812+
expectEqual(2, buffer[2])
813+
// Left Overlap
814+
buffer[1] = 2
815+
buffer[2] = 3
816+
buffer[0..<2] = buffer[1..<3]
817+
expectEqual(2, buffer[0])
818+
expectEqual(3, buffer[1])
819+
// Disjoint
820+
buffer[2] = 2
821+
buffer[3] = 3
822+
buffer[0..<2] = buffer[2..<4]
823+
expectEqual(2, buffer[0])
824+
expectEqual(3, buffer[1])
825+
buffer[0] = 0
826+
buffer[1] = 1
827+
buffer[2..<4] = buffer[0..<2]
828+
expectEqual(0, buffer[2])
829+
expectEqual(1, buffer[3])
830+
}
831+
796832
% end # SelfName
797833

798834
runAllTests()

0 commit comments

Comments
 (0)