diff --git a/stdlib/public/core/UnsafeBufferPointer.swift.gyb b/stdlib/public/core/UnsafeBufferPointer.swift.gyb index 76526fee27fd0..bf185b4877317 100644 --- a/stdlib/public/core/UnsafeBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeBufferPointer.swift.gyb @@ -275,6 +275,43 @@ extension Unsafe${Mutable}BufferPointer: ${Mutable}Collection, RandomAccessColle %end } + /// Accesses a contiguous subrange of the buffer's elements. + /// + /// The accessed slice uses the same indices for the same elements as the + /// original buffer uses. Always use the slice's `startIndex` property + /// instead of assuming that its indices start at a particular value. + /// + /// This example demonstrates getting a slice from a buffer of strings, finding + /// the index of one of the strings in the slice, and then using that index + /// in the original buffer. + /// +%if Mutable: + /// var streets = ["Adams", "Bryant", "Channing", "Douglas", "Evarts"] + /// streets.withUnsafeMutableBufferPointer { buffer in + /// let streetSlice = buffer[2..) -> Slice> @@ -286,11 +323,17 @@ extension Unsafe${Mutable}BufferPointer: ${Mutable}Collection, RandomAccessColle base: self, bounds: bounds) } % if Mutable: - set { + nonmutating set { _debugPrecondition(bounds.lowerBound >= startIndex) _debugPrecondition(bounds.upperBound <= endIndex) + _debugPrecondition(bounds.count == newValue.count) + // FIXME: swift-3-indexing-model: tests. - _writeBackMutableSlice(&self, bounds: bounds, slice: newValue) + if !newValue.isEmpty { + (_position! + bounds.lowerBound).assign( + from: newValue.base._position! + newValue.startIndex, + count: newValue.count) + } } % end } diff --git a/stdlib/public/core/UnsafePointer.swift.gyb b/stdlib/public/core/UnsafePointer.swift.gyb index 05ae11e627913..288b484b1a5e8 100644 --- a/stdlib/public/core/UnsafePointer.swift.gyb +++ b/stdlib/public/core/UnsafePointer.swift.gyb @@ -577,6 +577,8 @@ public struct ${Self}: _Pointer { /// `Pointee` must be a trivial type. After calling /// `assign(from:count:)`, the region is initialized. /// + /// - Note: Returns without performing work if `self` and `source` are equal. + /// /// - Parameters: /// - source: A pointer to at least `count` initialized instances of type /// `Pointee`. The memory regions referenced by `source` and this @@ -596,7 +598,7 @@ public struct ${Self}: _Pointer { // self[i] = source[i] // } } - else { + else if UnsafePointer(self) != source { // assign backward from a non-following overlapping range. Builtin.assignCopyArrayBackToFront( Pointee.self, self._rawValue, source._rawValue, count._builtinWordValue) diff --git a/validation-test/stdlib/CollectionType.swift.gyb b/validation-test/stdlib/CollectionType.swift.gyb index 5ae631ca8efc9..7ecf241f15205 100644 --- a/validation-test/stdlib/CollectionType.swift.gyb +++ b/validation-test/stdlib/CollectionType.swift.gyb @@ -580,21 +580,17 @@ CollectionTypeTests.test("subscript(_: Range)/writeback") { CollectionTypeTests.test("subscript(_: Range)/defaultImplementation/sliceTooLarge") .crashOutputMatches("Cannot replace a slice of a MutableCollection with a slice of a larger size") .code { - var x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + var x = Slice(base: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], bounds: 0..<10) expectCrashLater() - x.withUnsafeMutableBufferPointer { buffer in - buffer[2..<4] = buffer[4..<8] - } + x[2..<4] = x[4..<8] } CollectionTypeTests.test("subscript(_: Range)/defaultImplementation/sliceTooSmall") .crashOutputMatches("Cannot replace a slice of a MutableCollection with a slice of a smaller size") .code { - var x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + var x = Slice(base: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], bounds: 0..<10) expectCrashLater() - x.withUnsafeMutableBufferPointer { buffer in - buffer[2..<6] = buffer[6..<8] - } + x[2..<6] = x[6..<8] } //===----------------------------------------------------------------------===// diff --git a/validation-test/stdlib/UnsafeBufferPointer.swift.gyb b/validation-test/stdlib/UnsafeBufferPointer.swift.gyb index 94571b91a87bb..42aff03042b5a 100644 --- a/validation-test/stdlib/UnsafeBufferPointer.swift.gyb +++ b/validation-test/stdlib/UnsafeBufferPointer.swift.gyb @@ -756,8 +756,11 @@ UnsafeMutable${'Raw' if IsRaw else ''}BufferPointerTestSuite.test("subscript/${R defer { deallocateFor${Raw}Buffer( sliceMemory, count: replacementValues.count) } - // This produces a spurious compiler warning, someone take a look lol? +% if RangeName == 'range': + let buffer = SubscriptSetTest.create${SelfName}(from: memory) +% else: var buffer = SubscriptSetTest.create${SelfName}(from: memory) +% end % if IsRaw: // A raw buffer pointer has debug bounds checks on indices, and @@ -793,6 +796,39 @@ UnsafeMutable${'Raw' if IsRaw else ''}BufferPointerTestSuite.test("subscript/${R % end # RangeName +UnsafeMutable${'Raw' if IsRaw else ''}BufferPointerTestSuite.test("subscript/set/overlaps") { +% if IsRaw: + let buffer = UnsafeMutableRawBufferPointer.allocate(count: 4) +% else: + let buffer = UnsafeMutableBufferPointer.allocate(capacity: 4) +% end + defer { buffer.deallocate() } + + // Right Overlap + buffer[0] = 1 + buffer[1] = 2 + buffer[1..<3] = buffer[0..<2] + expectEqual(1, buffer[1]) + expectEqual(2, buffer[2]) + // Left Overlap + buffer[1] = 2 + buffer[2] = 3 + buffer[0..<2] = buffer[1..<3] + expectEqual(2, buffer[0]) + expectEqual(3, buffer[1]) + // Disjoint + buffer[2] = 2 + buffer[3] = 3 + buffer[0..<2] = buffer[2..<4] + expectEqual(2, buffer[0]) + expectEqual(3, buffer[1]) + buffer[0] = 0 + buffer[1] = 1 + buffer[2..<4] = buffer[0..<2] + expectEqual(0, buffer[2]) + expectEqual(1, buffer[3]) +} + % end # SelfName runAllTests()