mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
As proposed in SE-0107: UnsafeRawPointer: Rename 'init(allocatingCapacity:)' to 'UnsafeMutablePointer.allocate(capacity:)' Rename 'deallocateCapacity' to 'deallocate(capacity:)' `allocate` should not be an initializer. It's primary function is to allocate memory, not initialize a pointer.
478 lines
15 KiB
Plaintext
478 lines
15 KiB
Plaintext
// RUN: %target-run-simple-swiftgyb
|
|
// REQUIRES: executable_test
|
|
|
|
import StdlibUnittest
|
|
import StdlibCollectionUnittest
|
|
|
|
// Tests
|
|
|
|
struct SubscriptGetTest {
|
|
// SubscriptGetTest operates on a `(end - start)` sized buffer containing
|
|
// monotonically increasing integers from `start` to `end - 1`.
|
|
static let start = 0
|
|
static let end = 20
|
|
let rangeSelection: RangeSelection
|
|
/// The values that should be expected by slicing the UBP, or `nil` if the
|
|
/// test is expected to crash.
|
|
let expectedValues: [Int]?
|
|
/// Same as `expectedValues`, but for closed ranges. `nil` if no difference.
|
|
let expectedClosedValues: [Int]?
|
|
let loc: SourceLoc
|
|
|
|
static var elementCount = (end - start)
|
|
|
|
% for SelfType in ['UnsafeBufferPointer', 'UnsafeMutableBufferPointer']:
|
|
/// Create and populate an `${SelfType}` for use with unit tests.
|
|
/// PRECONDITION: `memory` must be allocated with space for
|
|
/// `SubscriptGetTest.elementCount` elements.
|
|
func create${SelfType}(from memory: UnsafeMutablePointer<OpaqueValue<Int>>)
|
|
-> ${SelfType}<OpaqueValue<Int>>
|
|
{
|
|
for i in SubscriptGetTest.start..<SubscriptGetTest.end {
|
|
memory[i] = OpaqueValue(i)
|
|
}
|
|
return ${SelfType}(start: memory, count: SubscriptGetTest.elementCount)
|
|
}
|
|
% end
|
|
|
|
init(
|
|
rangeSelection: RangeSelection, expectedValues: [Int]? = nil,
|
|
expectedClosedValues: [Int]? = nil,
|
|
file: String = #file, line: UInt = #line
|
|
) {
|
|
self.rangeSelection = rangeSelection
|
|
self.expectedValues = expectedValues
|
|
self.expectedClosedValues = expectedClosedValues ?? expectedValues
|
|
self.loc = SourceLoc(file, line, comment: "test data")
|
|
}
|
|
}
|
|
|
|
let subscriptGetTests : [SubscriptGetTest] = [
|
|
// Valid, empty.
|
|
SubscriptGetTest(rangeSelection: .emptyRange, expectedValues: []),
|
|
|
|
// Valid, edges.
|
|
SubscriptGetTest(rangeSelection: .leftEdge,
|
|
expectedValues: [],
|
|
expectedClosedValues: [0]),
|
|
SubscriptGetTest(rangeSelection: .rightEdge,
|
|
expectedValues: [],
|
|
expectedClosedValues: [19]),
|
|
|
|
// Valid, internal.
|
|
SubscriptGetTest(rangeSelection: .leftHalf,
|
|
expectedValues: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
|
|
SubscriptGetTest(rangeSelection: .rightHalf,
|
|
expectedValues: [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]),
|
|
SubscriptGetTest(rangeSelection: .middle,
|
|
expectedValues: [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]),
|
|
SubscriptGetTest(rangeSelection: .full,
|
|
expectedValues: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]),
|
|
SubscriptGetTest(rangeSelection: .offsets(2, 4),
|
|
expectedValues: [2, 3],
|
|
expectedClosedValues: [2, 3, 4]),
|
|
SubscriptGetTest(rangeSelection: .offsets(16, 19),
|
|
expectedValues: [16, 17, 18],
|
|
expectedClosedValues: [16, 17, 18, 19]),
|
|
|
|
// Invalid, bottom out of bounds.
|
|
SubscriptGetTest(rangeSelection: .offsets(-1, -1)),
|
|
SubscriptGetTest(rangeSelection: .offsets(-1, 0)),
|
|
SubscriptGetTest(rangeSelection: .offsets(-100, 5)),
|
|
|
|
// Invalid, top out of bounds.
|
|
SubscriptGetTest(rangeSelection: .offsets(20, 20)),
|
|
SubscriptGetTest(rangeSelection: .offsets(19, 20)),
|
|
SubscriptGetTest(rangeSelection: .offsets(5, 100)),
|
|
|
|
// Invalid, both out of bounds.
|
|
SubscriptGetTest(rangeSelection: .offsets(-1, 20)),
|
|
SubscriptGetTest(rangeSelection: .offsets(-100, 100)),
|
|
]
|
|
|
|
struct SubscriptSetTest {
|
|
// SubscriptSetTest operates on a `(end - start)` sized buffer containing
|
|
// monotonically increasing integers from `start` to `end - 1`.
|
|
static let start = 0
|
|
static let end = 10
|
|
|
|
let rangeSelection: RangeSelection
|
|
|
|
let replacementValues: [OpaqueValue<Int>]
|
|
let replacementValuesClosed: [OpaqueValue<Int>]
|
|
|
|
/// The values that should be expected by slicing the UBP, or `nil` if the
|
|
/// test is expected to crash.
|
|
let expectedValues: [Int]?
|
|
let expectedValuesClosed: [Int]?
|
|
|
|
let loc: SourceLoc
|
|
|
|
static var elementCount = (end - start)
|
|
|
|
/// Create and populate an `UnsafeMutableBufferPointer` for use with unit
|
|
/// tests.
|
|
/// PRECONDITION: `memory` must be allocated with space for
|
|
/// `SubscriptSetTest.elementCount` elements.
|
|
func createUnsafeMutableBufferPointer(
|
|
from memory: UnsafeMutablePointer<OpaqueValue<Int>>
|
|
) -> UnsafeMutableBufferPointer<OpaqueValue<Int>>
|
|
{
|
|
for i in SubscriptSetTest.start..<SubscriptSetTest.end {
|
|
memory[i] = OpaqueValue(i)
|
|
}
|
|
return UnsafeMutableBufferPointer(
|
|
start: memory,
|
|
count: SubscriptSetTest.elementCount)
|
|
}
|
|
|
|
/// Create and populate a mutable buffer pointer slice for use with unit
|
|
/// tests.
|
|
/// PRECONDITION: `memory` must be allocated with space for
|
|
/// `replacementValues.count` elements.
|
|
func replacementValuesSlice(
|
|
from memory: UnsafeMutablePointer<OpaqueValue<Int>>,
|
|
replacementValues: [OpaqueValue<Int>]
|
|
) -> MutableRandomAccessSlice<UnsafeMutableBufferPointer<OpaqueValue<Int>>>
|
|
{
|
|
for (i, value) in replacementValues.enumerated() {
|
|
memory[i] = value
|
|
}
|
|
let buffer = UnsafeMutableBufferPointer(
|
|
start: memory,
|
|
count: replacementValues.count)
|
|
let fullRange = RangeSelection.full.range(in: buffer)
|
|
return buffer[fullRange]
|
|
}
|
|
|
|
init(
|
|
rangeSelection: RangeSelection,
|
|
replacementValues: [Int],
|
|
replacementValuesClosed: [Int]? = nil,
|
|
expectedValues: [Int]? = nil,
|
|
expectedValuesClosed: [Int]? = nil,
|
|
file: String = #file, line: UInt = #line
|
|
) {
|
|
self.rangeSelection = rangeSelection
|
|
self.replacementValues = replacementValues.map { OpaqueValue($0) }
|
|
if let replacements = replacementValuesClosed {
|
|
self.replacementValuesClosed = replacements.map { OpaqueValue($0) }
|
|
} else {
|
|
self.replacementValuesClosed = self.replacementValues
|
|
}
|
|
self.expectedValues = expectedValues
|
|
self.expectedValuesClosed = expectedValuesClosed ?? expectedValues
|
|
self.loc = SourceLoc(file, line, comment: "test data")
|
|
}
|
|
}
|
|
|
|
let subscriptSetTests : [SubscriptSetTest] = [
|
|
// Valid, empty.
|
|
SubscriptSetTest(
|
|
rangeSelection: .emptyRange,
|
|
replacementValues: [],
|
|
expectedValues: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
|
|
|
|
// Valid, edges.
|
|
SubscriptSetTest(
|
|
rangeSelection: .leftEdge,
|
|
replacementValues: [],
|
|
replacementValuesClosed: [9001],
|
|
expectedValues: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
|
expectedValuesClosed: [9001, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
|
|
SubscriptSetTest(
|
|
rangeSelection: .rightEdge,
|
|
replacementValues: [],
|
|
replacementValuesClosed: [9001],
|
|
expectedValues: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
|
expectedValuesClosed: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9001]),
|
|
|
|
// Valid, internal.
|
|
SubscriptSetTest(
|
|
rangeSelection: .leftHalf,
|
|
replacementValues: [10, 11, 12, 13, 14],
|
|
expectedValues: [10, 11, 12, 13, 14, 5, 6, 7, 8, 9]),
|
|
SubscriptSetTest(
|
|
rangeSelection: .rightHalf,
|
|
replacementValues: [10, 11, 12, 13, 14],
|
|
expectedValues: [0, 1, 2, 3, 4, 10, 11, 12, 13, 14]),
|
|
SubscriptSetTest(
|
|
rangeSelection: .middle,
|
|
replacementValues: [10, 11, 12, 13, 14, 15],
|
|
expectedValues: [0, 1, 10, 11, 12, 13, 14, 15, 8, 9]),
|
|
SubscriptSetTest(
|
|
rangeSelection: .full,
|
|
replacementValues: [10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
|
|
expectedValues: [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]),
|
|
|
|
// Invalid, range and replacement count mismatch.
|
|
SubscriptSetTest(
|
|
rangeSelection: .leftEdge,
|
|
replacementValues: [],
|
|
replacementValuesClosed: [9]),
|
|
SubscriptSetTest(
|
|
rangeSelection: .leftEdge,
|
|
replacementValues: [9, 9],
|
|
replacementValuesClosed: [9, 9, 9]),
|
|
SubscriptSetTest(
|
|
rangeSelection: .offsets(1, 2),
|
|
replacementValues: [],
|
|
replacementValuesClosed: [9]),
|
|
SubscriptSetTest(
|
|
rangeSelection: .offsets(1, 2),
|
|
replacementValues: [9, 9],
|
|
replacementValuesClosed: [9, 9, 9]),
|
|
SubscriptSetTest(
|
|
rangeSelection: .offsets(2, 5),
|
|
replacementValues: [9, 9],
|
|
replacementValuesClosed: [9, 9, 9]),
|
|
SubscriptSetTest(
|
|
rangeSelection: .offsets(2, 5),
|
|
replacementValues: [9, 9, 9, 9],
|
|
replacementValuesClosed: [9, 9, 9, 9, 9]),
|
|
|
|
// Invalid, bottom out of bounds.
|
|
SubscriptSetTest(
|
|
rangeSelection: .offsets(-1, -1),
|
|
replacementValues: []),
|
|
SubscriptSetTest(
|
|
rangeSelection: .offsets(-1, 0),
|
|
replacementValues: [9]),
|
|
SubscriptSetTest(
|
|
rangeSelection: .offsets(-3, 5),
|
|
replacementValues: [9, 9, 9, 9, 9, 9, 9, 9]),
|
|
|
|
// Invalid, top out of bounds.
|
|
SubscriptSetTest(
|
|
rangeSelection: .offsets(10, 10),
|
|
replacementValues: []),
|
|
SubscriptSetTest(
|
|
rangeSelection: .offsets(9, 10),
|
|
replacementValues: [9]),
|
|
SubscriptSetTest(
|
|
rangeSelection: .offsets(8, 15),
|
|
replacementValues: [9, 9, 9, 9, 9, 9, 9]),
|
|
|
|
// Invalid, both out of bounds.
|
|
SubscriptSetTest(
|
|
rangeSelection: .offsets(-1, 10),
|
|
replacementValues: [9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9]),
|
|
SubscriptSetTest(
|
|
rangeSelection: .offsets(-2, 11),
|
|
replacementValues: [9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9]),
|
|
]
|
|
|
|
|
|
// Test Suites
|
|
|
|
var UnsafeBufferPointerTestSuite = TestSuite("UnsafeBufferPointer")
|
|
var UnsafeMutableBufferPointerTestSuite = TestSuite("UnsafeMutableBufferPointer")
|
|
|
|
% for (SelfName, IsMutable, SelfType, PointerType) in [
|
|
% ('UnsafeBufferPointer', False, 'UnsafeBufferPointer<Float>', 'UnsafePointer<Float>'),
|
|
% ('UnsafeMutableBufferPointer', True, 'UnsafeMutableBufferPointer<Float>', 'UnsafeMutablePointer<Float>')
|
|
% ]:
|
|
|
|
${SelfName}TestSuite.test("AssociatedTypes") {
|
|
typealias Subject = ${SelfName}<OpaqueValue<Int>>
|
|
expectRandomAccessCollectionAssociatedTypes(
|
|
collectionType: Subject.self,
|
|
iteratorType: IndexingIterator<Subject>.self,
|
|
subSequenceType: ${'Mutable' if IsMutable else ''}RandomAccessSlice<Subject>.self,
|
|
indexType: Int.self,
|
|
indexDistanceType: Int.self,
|
|
indicesType: CountableRange<Int>.self)
|
|
|
|
expect${'Mutable' if IsMutable else ''}CollectionType(Subject.self)
|
|
}
|
|
|
|
${SelfName}TestSuite.test("nilBaseAddress") {
|
|
let emptyBuffer = ${SelfType}(start: nil, count: 0)
|
|
expectEmpty(emptyBuffer.baseAddress)
|
|
expectEqual(0, emptyBuffer.count)
|
|
expectTrue(emptyBuffer.startIndex == emptyBuffer.endIndex)
|
|
|
|
var iter = emptyBuffer.makeIterator()
|
|
expectEmpty(iter.next())
|
|
|
|
expectEqualSequence([], emptyBuffer)
|
|
}
|
|
|
|
${SelfName}TestSuite.test("nonNilButEmpty") {
|
|
let emptyAllocated = UnsafeMutablePointer<Float>.allocate(capacity: 0)
|
|
defer { emptyAllocated.deallocate(capacity: 0) }
|
|
|
|
let emptyBuffer = ${SelfType}(start: ${PointerType}(emptyAllocated), count: 0)
|
|
expectEqual(emptyAllocated, emptyBuffer.baseAddress)
|
|
expectEqual(0, emptyBuffer.count)
|
|
expectTrue(emptyBuffer.startIndex == emptyBuffer.endIndex)
|
|
|
|
var iter = emptyBuffer.makeIterator()
|
|
expectEmpty(iter.next())
|
|
|
|
expectEqualSequence([], emptyBuffer)
|
|
}
|
|
|
|
${SelfName}TestSuite.test("nonNilNonEmpty") {
|
|
let count = 4
|
|
let allocated = UnsafeMutablePointer<Float>.allocate(capacity: count)
|
|
defer { allocated.deallocate(capacity: count) }
|
|
allocated.initialize(to: 1.0, count: count)
|
|
allocated[count - 1] = 2.0
|
|
|
|
let buffer = ${SelfType}(start: ${PointerType}(allocated), count: count - 1)
|
|
expectEqual(allocated, buffer.baseAddress)
|
|
expectEqual(count - 1, buffer.count)
|
|
expectEqual(count - 1, buffer.endIndex - buffer.startIndex)
|
|
|
|
allocated[1] = 0.0
|
|
expectEqual(1.0, buffer[0])
|
|
expectEqual(0.0, buffer[1])
|
|
expectEqual(1.0, buffer[2])
|
|
|
|
var iter = buffer.makeIterator()
|
|
expectEqual(1.0, iter.next())
|
|
expectEqual(0.0, iter.next())
|
|
expectEqual(1.0, iter.next())
|
|
expectEmpty(iter.next())
|
|
|
|
expectEqualSequence([1.0, 0.0, 1.0], buffer)
|
|
|
|
expectEqual(2.0, allocated[count-1])
|
|
}
|
|
|
|
${SelfName}TestSuite.test("badCount")
|
|
.skip(.custom(
|
|
{ _isFastAssertConfiguration() },
|
|
reason: "this trap is not guaranteed to happen in -Ounchecked"))
|
|
.code {
|
|
expectCrashLater()
|
|
|
|
let emptyAllocated = UnsafeMutablePointer<Float>.allocate(capacity: 0)
|
|
defer { emptyAllocated.deallocate(capacity: 0) }
|
|
|
|
let buffer = ${SelfType}(start: ${PointerType}(emptyAllocated), count: -1)
|
|
_ = buffer
|
|
}
|
|
|
|
${SelfName}TestSuite.test("badNilCount")
|
|
.skip(.custom(
|
|
{ _isFastAssertConfiguration() },
|
|
reason: "this trap is not guaranteed to happen in -Ounchecked"))
|
|
.code {
|
|
expectCrashLater()
|
|
|
|
let buffer = ${SelfType}(start: nil, count: 1)
|
|
_ = buffer
|
|
}
|
|
|
|
% for RangeName in ['range', 'countableRange', 'closedRange', 'countableClosedRange']:
|
|
${SelfName}TestSuite.test("subscript/${RangeName}/get").forEach(in: subscriptGetTests) {
|
|
(test) in
|
|
|
|
let expectedValues: [Int]?
|
|
% if 'closed' in RangeName.lower():
|
|
if test.rangeSelection.isEmpty {
|
|
return
|
|
}
|
|
expectedValues = test.expectedClosedValues
|
|
% else:
|
|
expectedValues = test.expectedValues
|
|
% end
|
|
|
|
let elementCount = SubscriptGetTest.elementCount
|
|
|
|
var memory = UnsafeMutablePointer<OpaqueValue<Int>>.allocate(capacity: elementCount)
|
|
let buffer = test.create${SelfName}(from: memory)
|
|
defer { memory.deallocate(capacity: elementCount) }
|
|
|
|
let range = test.rangeSelection.${RangeName}(in: buffer)
|
|
|
|
if expectedValues == nil { expectCrashLater() }
|
|
let slice = buffer[range]
|
|
expectEqual(
|
|
expectedValues!,
|
|
slice.map { $0.value },
|
|
stackTrace: SourceLocStack().with(test.loc)
|
|
)
|
|
}
|
|
% end
|
|
|
|
% end
|
|
|
|
% for RangeName in ['range', 'countableRange', 'closedRange', 'countableClosedRange']:
|
|
UnsafeMutableBufferPointerTestSuite.test("subscript/${RangeName}/set")
|
|
.forEach(in: subscriptSetTests) { (test) in
|
|
|
|
let expectedValues: [Int]?
|
|
let replacementValues: [OpaqueValue<Int>]
|
|
% if 'closed' in RangeName.lower():
|
|
if test.rangeSelection.isEmpty {
|
|
return
|
|
}
|
|
expectedValues = test.expectedValuesClosed
|
|
replacementValues = test.replacementValuesClosed
|
|
% else:
|
|
expectedValues = test.expectedValues
|
|
replacementValues = test.replacementValues
|
|
% end
|
|
|
|
let elementCount = SubscriptSetTest.elementCount
|
|
|
|
var memory = UnsafeMutablePointer<OpaqueValue<Int>>.allocate(
|
|
capacity: elementCount)
|
|
var sliceMemory = UnsafeMutablePointer<OpaqueValue<Int>>.allocate(
|
|
capacity: replacementValues.count)
|
|
var buffer = test.createUnsafeMutableBufferPointer(from: memory)
|
|
defer {
|
|
memory.deallocate(capacity: elementCount)
|
|
sliceMemory.deallocate(capacity: replacementValues.count)
|
|
}
|
|
|
|
let range = test.rangeSelection.${RangeName}(in: buffer)
|
|
let replacementSlice = test.replacementValuesSlice(
|
|
from: sliceMemory,
|
|
replacementValues: replacementValues)
|
|
|
|
if expectedValues == nil { expectCrashLater() }
|
|
buffer[range] = replacementSlice
|
|
expectEqual(
|
|
expectedValues!,
|
|
buffer.map { $0.value },
|
|
stackTrace: SourceLocStack().with(test.loc)
|
|
)
|
|
}
|
|
% end
|
|
|
|
UnsafeMutableBufferPointerTestSuite.test("changeElementViaBuffer") {
|
|
let count = 4
|
|
let allocated = UnsafeMutablePointer<Float>.allocate(capacity: count)
|
|
defer { allocated.deallocate(capacity: count) }
|
|
allocated.initialize(to: 1.0, count: count)
|
|
allocated[count-1] = -1.0
|
|
|
|
var buffer = UnsafeMutableBufferPointer(start: allocated, count: count - 1)
|
|
|
|
buffer[1] = 0.0
|
|
expectEqual(1.0, buffer[0])
|
|
expectEqual(0.0, buffer[1])
|
|
expectEqual(1.0, buffer[2])
|
|
|
|
expectEqual(1.0, allocated[0])
|
|
expectEqual(0.0, allocated[1])
|
|
expectEqual(1.0, allocated[2])
|
|
expectEqual(-1.0, allocated[count-1])
|
|
|
|
buffer.sort()
|
|
expectEqual(0.0, buffer[0])
|
|
expectEqual(1.0, buffer[1])
|
|
expectEqual(1.0, buffer[2])
|
|
|
|
expectEqual(0.0, allocated[0])
|
|
expectEqual(1.0, allocated[1])
|
|
expectEqual(1.0, allocated[2])
|
|
expectEqual(-1.0, allocated[count-1])
|
|
}
|
|
|
|
runAllTests()
|