Skip to content

Commit bbe2688

Browse files
[stdlib] Update InlineArray (2) (#79866)
* Amend doc comments. * Add `guard` for empty array. * Add tests for initialization errors. * Use `Self.` to call static method. * Use `_checkIndex` in `swapAt` method. * Wrap overlong lines.
1 parent b904e96 commit bbe2688

File tree

2 files changed

+98
-22
lines changed

2 files changed

+98
-22
lines changed

stdlib/public/core/InlineArray.swift

+36-22
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,10 @@ extension InlineArray where Element: ~Copyable {
9595
@_transparent
9696
internal var _mutableBuffer: UnsafeMutableBufferPointer<Element> {
9797
mutating get {
98-
unsafe UnsafeMutableBufferPointer<Element>(start: _mutableAddress, count: count)
98+
unsafe UnsafeMutableBufferPointer<Element>(
99+
start: _mutableAddress,
100+
count: count
101+
)
99102
}
100103
}
101104

@@ -121,14 +124,18 @@ extension InlineArray where Element: ~Copyable {
121124
@available(SwiftStdlib 6.2, *)
122125
extension InlineArray where Element: ~Copyable {
123126
/// Initializes every element in this array, by calling the given closure
124-
/// for each index.
127+
/// with each index.
125128
///
126129
/// This will call the closure `count` times, where `count` is the static
127130
/// count of the array, to initialize every element by passing the closure
128-
/// the index of the current element being initialized. The closure is allowed
129-
/// to throw an error at any point during initialization at which point the
130-
/// array will stop initialization, deinitialize every currently initialized
131-
/// element, and throw the given error back out to the caller.
131+
/// the index of the current element being initialized.
132+
///
133+
/// InlineArray<4, Int> { 1 << $0 } //-> [1, 2, 4, 8]
134+
///
135+
/// The closure is allowed to throw an error at any point during
136+
/// initialization at which point the array will stop initialization,
137+
/// deinitialize every currently initialized element, and throw the given
138+
/// error back out to the caller.
132139
///
133140
/// - Parameter body: A closure that returns an owned `Element` to emplace at
134141
/// the passed in index.
@@ -139,9 +146,7 @@ extension InlineArray where Element: ~Copyable {
139146
public init<E: Error>(_ body: (Index) throws(E) -> Element) throws(E) {
140147
#if $BuiltinEmplaceTypedThrows
141148
self = try Builtin.emplace { (rawPtr) throws(E) -> () in
142-
let buffer = InlineArray<count, Element>._initializationBuffer(
143-
start: rawPtr
144-
)
149+
let buffer = Self._initializationBuffer(start: rawPtr)
145150

146151
for i in 0 ..< count {
147152
do throws(E) {
@@ -164,19 +169,23 @@ extension InlineArray where Element: ~Copyable {
164169
}
165170

166171
/// Initializes every element in this array, by calling the given closure
167-
/// for each previously initialized element.
172+
/// with each preceding element.
168173
///
169174
/// This will call the closure `count - 1` times, where `count` is the static
170175
/// count of the array, to initialize every element by passing the closure an
171-
/// immutable borrow reference to the previous element. The closure is allowed
172-
/// to throw an error at any point during initialization at which point the
173-
/// array will stop initialization, deinitialize every currently initialized
174-
/// element, and throw the given error back out to the caller.
176+
/// immutable borrow reference to the preceding element.
177+
///
178+
/// InlineArray<4, Int>(first: 1) { $0 << 1 } //-> [1, 2, 4, 8]
179+
///
180+
/// The closure is allowed to throw an error at any point during
181+
/// initialization at which point the array will stop initialization,
182+
/// deinitialize every currently initialized element, and throw the given
183+
/// error back out to the caller.
175184
///
176185
/// - Parameters:
177186
/// - first: The first value to emplace into the array.
178187
/// - next: A closure that takes an immutable borrow reference to the
179-
/// previous element, and returns an owned `Element` instance to emplace
188+
/// preceding element, and returns an owned `Element` instance to emplace
180189
/// into the array.
181190
///
182191
/// - Complexity: O(*n*), where *n* is the number of elements in the array.
@@ -194,11 +203,16 @@ extension InlineArray where Element: ~Copyable {
194203
var o: Element? = first
195204

196205
self = try Builtin.emplace { (rawPtr) throws(E) -> () in
197-
let buffer = InlineArray<count, Element>._initializationBuffer(
198-
start: rawPtr
199-
)
206+
let buffer = Self._initializationBuffer(start: rawPtr)
200207

201-
unsafe buffer.initializeElement(at: 0, to: o.take()._consumingUncheckedUnwrapped())
208+
guard Self.count > 0 else {
209+
return
210+
}
211+
212+
unsafe buffer.initializeElement(
213+
at: 0,
214+
to: o.take()._consumingUncheckedUnwrapped()
215+
)
202216

203217
for i in 1 ..< count {
204218
do throws(E) {
@@ -232,7 +246,7 @@ extension InlineArray where Element: Copyable {
232246
@_alwaysEmitIntoClient
233247
public init(repeating value: Element) {
234248
self = Builtin.emplace {
235-
let buffer = InlineArray<count, Element>._initializationBuffer(start: $0)
249+
let buffer = Self._initializationBuffer(start: $0)
236250

237251
unsafe buffer.initialize(repeating: value)
238252
}
@@ -431,8 +445,8 @@ extension InlineArray where Element: ~Copyable {
431445
return
432446
}
433447

434-
_precondition(indices.contains(i), "Index out of bounds")
435-
_precondition(indices.contains(j), "Index out of bounds")
448+
_checkIndex(i)
449+
_checkIndex(j)
436450

437451
let ithElement = unsafe _mutableBuffer.moveElement(from: i)
438452
let jthElement = unsafe _mutableBuffer.moveElement(from: j)

test/stdlib/InlineArray.swift

+62
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ enum InlineArrayTests {
3636
testSuite.test("Copyable", testCopyable)
3737
testSuite.test("Noncopyable", testNoncopyable)
3838
testSuite.test("Uninhabited", testUninhabited)
39+
testSuite.test("Throws", testThrows)
3940
runAllTests()
4041
}
4142

@@ -82,8 +83,10 @@ enum InlineArrayTests {
8283
let b = InlineArray<4, Int>(first: 1) { $0 << 1 }
8384
var c = InlineArray<4, Int>(repeating: 9)
8485
var d = InlineArray<4, Int>(repeating: 9)
86+
let e = InlineArray<0, Int>(repeating: 9)
8587
_checkInlineArray(c, oracle: [9, 9, 9, 9])
8688
_checkInlineArray(d, oracle: [9, 9, 9, 9])
89+
_checkInlineArray(e, oracle: [])
8790
c[0] = 1
8891
c[1] = 2
8992
c[2] = 4
@@ -150,6 +153,47 @@ enum InlineArrayTests {
150153
_checkInlineArray(f, oracle: [])
151154
}
152155
}
156+
157+
/// The closure is allowed to throw an error at any point during
158+
/// initialization at which point the array will stop initialization,
159+
/// deinitialize every currently initialized element, and throw the given
160+
/// error back out to the caller.
161+
@available(SwiftStdlib 6.2, *)
162+
static func testThrows() {
163+
let error = CancellationError()
164+
do {
165+
expectDoesNotThrow {
166+
let a = try InlineArray<0, String> { _ in throw error }
167+
_checkInlineArray(a, oracle: [])
168+
}
169+
_expectThrows {
170+
let _ = try InlineArray<1, String> { _ in throw error }
171+
}
172+
_expectThrows {
173+
let _ = try InlineArray<2, String> { index in
174+
if index == 0 { "first" } else { throw error }
175+
}
176+
}
177+
}
178+
do {
179+
expectDoesNotThrow {
180+
let a = try InlineArray<0, String>(first: "first") { _ in throw error }
181+
_checkInlineArray(a, oracle: [])
182+
}
183+
expectDoesNotThrow {
184+
let a = try InlineArray<1, String>(first: "first") { _ in throw error }
185+
_checkInlineArray(a, oracle: ["first"])
186+
}
187+
_expectThrows {
188+
let _ = try InlineArray<2, String>(first: "first") { _ in throw error }
189+
}
190+
_expectThrows {
191+
let _ = try InlineArray<3, String>(first: "first") { element in
192+
if element == "first" { "second" } else { throw error }
193+
}
194+
}
195+
}
196+
}
153197
}
154198
155199
//===----------------------------------------------------------------------===//
@@ -179,6 +223,24 @@ extension InlineArray where Element: ~Copyable {
179223
// MARK: - StdlibUnittest Additions
180224
//===----------------------------------------------------------------------===//
181225
226+
/// Tests that the given closure always throws an error.
227+
func _expectThrows<Failure: Error>(
228+
stackTrace: SourceLocStack = SourceLocStack(),
229+
showFrame: Bool = true,
230+
file: String = #file,
231+
line: UInt = #line,
232+
_ body: () throws(Failure) -> Void
233+
) {
234+
do throws(Failure) {
235+
try body()
236+
expectUnreachable(
237+
stackTrace: stackTrace.pushIf(showFrame, file: file, line: line)
238+
)
239+
} catch {
240+
return
241+
}
242+
}
243+
182244
/// Tests the properties and subscripts of an `InlineArray` instance, by
183245
/// comparing them against an `Array` oracle with the expected elements.
184246
@available(SwiftStdlib 6.2, *)

0 commit comments

Comments
 (0)