[stdlib] in-place initializer for InlineArray

This commit is contained in:
Guillaume Lessard
2025-04-17 18:10:51 -07:00
parent 285f7250f6
commit 1d776a6b06
3 changed files with 117 additions and 3 deletions

View File

@@ -300,6 +300,25 @@ extension InlineArray where Element: ~Copyable {
}
#else
fatalError()
#endif
}
@available(SwiftStdlib 6.2, *)
@_alwaysEmitIntoClient
public init<E: Error>(
initializingWith initializer: (inout OutputSpan<Element>) throws(E) -> Void
) throws(E) {
#if $BuiltinEmplaceTypedThrows
_storage = try Builtin.emplace { (rawPtr) throws(E) -> () in
let buffer = unsafe Self._initializationBuffer(start: rawPtr)
_internalInvariant(Self.count == buffer.count)
var output = unsafe OutputSpan(buffer: buffer, initializedCount: 0)
try initializer(&output)
let initialized = unsafe output.finalize(for: buffer)
_precondition(count == initialized, "InlineArray initialization underflow")
}
#else
fatalError()
#endif
}
}

View File

@@ -168,14 +168,14 @@ enum InlineArrayTests {
let error = CancellationError()
do {
expectDoesNotThrow {
let a = try InlineArray<0, String> { _ in throw error }
let a = try InlineArray<0, String>({ _ in throw error })
_checkInlineArray(a, oracle: [])
}
_expectThrows {
let _ = try InlineArray<1, String> { _ in throw error }
let _ = try InlineArray<1, String>({ _ in throw error })
}
_expectThrows {
let _ = try InlineArray<1, any P> { _ in throw error }
let _ = try InlineArray<1, any P>({ _ in throw error })
}
_expectThrows {
let _ = try InlineArray<2, String> { index in

View File

@@ -325,3 +325,98 @@ suite.test("mutate with MutableSpan prefix")
expectTrue(b.elementsEqual((0..<10).map({2*(1+$0)})))
b.deinitialize()
}
suite.test("InlineArray initialization")
.require(.stdlib_6_2).code {
guard #available(SwiftStdlib 6.2, *) else { return }
var a: [Int] = []
let i = InlineArray<10, Int> {
(o: inout OutputSpan<Int>) in
for _ in 0..<o.capacity {
let r = Int.random(in: 10...99)
a.append(r)
o.append(r)
}
}
expectEqual(a.count, i.count)
for j in i.indices {
expectEqual(a[j], i[j])
}
}
suite.test("InlineArray initialization underflow")
.skip(.wasiAny(reason: "Trap tests aren't supported on WASI."))
.require(.stdlib_6_2).code {
guard #available(SwiftStdlib 6.2, *) else { return }
expectCrashLater()
_ = InlineArray<4, Int> {
$0.append(1)
}
}
#if false
suite.test("InlineArray initialization throws 0")
.require(.stdlib_6_2).code {
guard #available(SwiftStdlib 6.2, *) else { return }
enum LocalError: Error { case error }
class I {
static public var count = 0
init() { Self.count += 1 }
deinit { Self.count -= 1 }
}
let a: InlineArray<4, I>
do throws(LocalError) {
var c = 1
a = try InlineArray(first: I()) {
i throws(LocalError) in
c += 1
if c < 4 {
return I()
}
print(I.count)
throw LocalError.error
}
_ = a
} catch {
print(error, I.count)
expectEqual(I.count, 0)
}
}
suite.test("InlineArray initialization throws")
.require(.stdlib_6_2).code {
guard #available(SwiftStdlib 6.2, *) else { return }
enum LocalError: Error { case error }
class I {
static var count = 0
init() { Self.count += 1 }
deinit { Self.count -= 1 }
}
let a: InlineArray<4, I>
do throws(LocalError) {
a = try InlineArray {
o throws(LocalError) in
o.append(I())
o.append(I())
o.append(I())
o.append(I())
expectEqual(I.count, 4)
print(I.count)
throw LocalError.error
}
_ = a
} catch {
print(error, I.count)
expectEqual(I.count, 0)
}
}
#endif