// RUN: %target-run-simple-swift(%S/Inputs/ExperimentalFixedArray.swift -enable-experimental-feature Embedded -enable-experimental-feature FixedArrays -parse-as-library -runtime-compatibility-version none -wmo -Xfrontend -disable-objc-interop) | %FileCheck %s // RUN: %target-run-simple-swift(-O %S/Inputs/ExperimentalFixedArray.swift -enable-experimental-feature Embedded -enable-experimental-feature FixedArrays -parse-as-library -runtime-compatibility-version none -wmo -Xfrontend -disable-objc-interop) | %FileCheck %s // Also test in non-embedded mode // RUN: %target-run-simple-swift(-target %target-cpu-apple-macosx10.13 %S/Inputs/ExperimentalFixedArray.swift -enable-experimental-feature FixedArrays -parse-as-library -wmo) | %FileCheck %s // RUN: %target-run-simple-swift(-target %target-cpu-apple-macosx10.13 -O %S/Inputs/ExperimentalFixedArray.swift -enable-experimental-feature FixedArrays -parse-as-library -wmo) | %FileCheck %s // REQUIRES: executable_test // REQUIRES: optimized_stdlib // REQUIRES: VENDOR=apple // REQUIRES: OS=macosx // REQUIRES: swift_feature_Embedded // REQUIRES: swift_feature_FixedArrays func simpleStackAllocated() { var a = FixedArray(capacity: 10) a.append(27) a.append(28) a.append(29) a.append(30) printit(a) } func testDestroyOfElements() { var a = FixedArray(capacity: 10) a.append(CheckLifetime(27)) a.append(CheckLifetime(28)) a.append(CheckLifetime(29)) a.append(CheckLifetime(30)) // The `*` is a prefix operator and serves as syntatic sugar for FixedArray.view. printit(*a) } struct IntByte: Printable { let i: Int32 let b: Int8 func print() { Swift.print(i, terminator: "") Swift.print(",", terminator: "") Swift.print(b, terminator: "") } } extension Optional: Printable where Wrapped == Int64 { func print() { if let x = self { Swift.print(x, terminator: "") } else { Swift.print("nil", terminator: "") } } } struct S { // Space for elements is reserved in the data section, but not initialized, yet static var a = FixedArray(capacity: 10) // Elements are initialized in the data section. // The `^` is a prefix operator and serves as syntatic sugar to create a FixedArray literal. static let b = ^[1, 2, 3] static let c: FixedArray = ^[10, 20, 30] static let d: FixedArray = ^[IntByte(i: 1, b: 2), IntByte(i: 3, b: 4), IntByte(i: 5, b: 6)] static var e = FixedArray(capacity: 3) static var f = FixedArray(capacity: 3) } func globalWithAppend() { S.a.append(27) S.a.append(28) S.a.append(29) S.a.append(30) printit(S.a) } // First method to pass a FixedArray to a function: as `borrowing` parameter func printit(_ a: borrowing FixedArray) { // Currently FixedArray cannot conform to Collection, yet. // For iteration, we need to take the detour through BufferView. for x in *a { x.print() print("") } } // Second method to pass a FixedArray to a function: pass a view to its elements func printit(_ a: BufferView) { for x in a { x.print() print("") } } extension FixedArray { // Functions _can_ return a FixedArray, but must be declared as `@_transparent`. @_transparent func map(_ c: (T) -> V) -> FixedArray { var newArray = FixedArray(capacity: self.count) for element in view() { newArray.append(c(element)) } return newArray } } func testMap() { let a = ^[1, 2, 3] printit(a.map { $0 + 100 }) } // A somehow more complex exmample, where FixedArray is used in another struct struct Matrix: ~Copyable { var elements: FixedArray let rows: Int let columns: Int @_transparent init(rows: Int, columns: Int, _ elements: [T]) { self.rows = rows self.columns = columns precondition(rows * columns == elements.count) self.elements = FixedArray(elements: elements) } @_transparent init(rows: Int, columns: Int, initialValue: T) { self.rows = rows self.columns = columns self.elements = FixedArray(repeating: initialValue, count: rows * columns) } subscript(row: Int, col: Int) -> T { get { return elements[row * columns + col] } set { elements[row * columns + col] = newValue } } func rowView(for row: Int) -> BufferView { let start = elements.view().startIndex.advanced(by: row * columns) let end = start.advanced(by: columns) return elements.view()[start.., rhs: borrowing Matrix) -> Matrix { var result = Matrix(rows: lhs.rows, columns: lhs.columns, initialValue: 0) for i in 0.. elements are allocated in the data section. static let c = Matrix(rows: 2, columns: 3, [ 10, 20, 30, 40, 50, 60 ]) } func testMatrixAdd() { let x = Matrix(rows: 2, columns: 3, [ 1, 2, 3, 4, 5, 6 ]) let y = x + MatricConsts.c y.print() } // Example of another type, using the basic non-allocating buffer utilities (allocateVector). // It's possible to implement such a type outside of the stdlib. struct RingBuffer: ~Copyable { private let buffer: UnsafeMutablePointer private let capacity: Int private var writeIndex: Int private var readIndex = 0 @_transparent public init(capacity: Int) { self.capacity = capacity self.buffer = _allocateVector(elementType: Element.self, capacity: capacity) self.writeIndex = 0 } @_transparent init(repeating repeatedValue: Element, count: Int) { self.capacity = count + 1 self.buffer = _allocateVector(elementType: Element.self, capacity: capacity) self.writeIndex = count for i in 0.. Bool { guard (writeIndex + 1) % capacity != readIndex else { return false } (buffer + writeIndex).initialize(to: element) writeIndex = (writeIndex + 1) % capacity return true } mutating func next() -> Element? { if isEmpty { return nil } let value = (buffer + readIndex).move() readIndex = (readIndex + 1) % capacity return value } deinit { var idx = readIndex while idx != writeIndex { _ = (buffer + idx).move() idx = (idx + 1) % capacity } } } func testRingBuffer() { var rb = RingBuffer(capacity: 3) print(rb.push(1)) print(rb.push(2)) print(rb.next()) print(rb.push(3)) print(rb.push(4)) print(rb.next()) print(rb.next()) print(rb.next()) } // Test utilities protocol Printable { func print() } extension Int: Printable { func print() { Swift.print(self, terminator: "") } } func print(_ i: Int?) { if let i = i { print(i) } else { print("nil") } } final class CheckLifetime: Printable { let x: Int init(_ x: Int) { self.x = x } deinit { Swift.print("deinit ", terminator: "") Swift.print(x) } func print() { Swift.print("CheckLifetime(", terminator: "") Swift.print(x, terminator: ")") } } // Check for correctness @main struct Main { static func main() { // CHECK-LABEL: ### simpleStackAllocated // CHECK-NEXT: 27 // CHECK-NEXT: 28 // CHECK-NEXT: 29 // CHECK-NEXT: 30 print("### simpleStackAllocated") simpleStackAllocated() // CHECK-LABEL: ### testDestroyOfElements // CHECK-NEXT: CheckLifetime(27) // CHECK-NEXT: CheckLifetime(28) // CHECK-NEXT: CheckLifetime(29) // CHECK-NEXT: CheckLifetime(30) // CHECK-NEXT: deinit 27 // CHECK-NEXT: deinit 28 // CHECK-NEXT: deinit 29 // CHECK-NEXT: deinit 30 print("### testDestroyOfElements") testDestroyOfElements() // CHECK-LABEL: ### globalWithAppend // CHECK-NEXT: 27 // CHECK-NEXT: 28 // CHECK-NEXT: 29 // CHECK-NEXT: 30 print("### globalWithAppend") globalWithAppend() // CHECK-LABEL: ### globalLiteral // CHECK-NEXT: 1 // CHECK-NEXT: 2 // CHECK-NEXT: 3 print("### globalLiteral") printit(S.b) // CHECK-LABEL: ### globalOptional // CHECK-NEXT: 10 // CHECK-NEXT: 20 // CHECK-NEXT: 30 print("### globalOptional") printit(S.c) // CHECK-LABEL: ### globalStruct // CHECK-NEXT: 1,2 // CHECK-NEXT: 3,4 // CHECK-NEXT: 5,6 print("### globalStruct") printit(S.d) // CHECK-LABEL: ### globalUninitOptional // CHECK-NEXT: 100 // CHECK-NEXT: 200 // CHECK-NEXT: 300 print("### globalUninitOptional") S.e.append(100) S.e.append(200) S.e.append(300) printit(S.e) // CHECK-LABEL: ### globalUninitStruct // CHECK-NEXT: 11,21 // CHECK-NEXT: 31,41 // CHECK-NEXT: 51,61 print("### globalUninitStruct") S.f.append(IntByte(i: 11, b: 21)) S.f.append(IntByte(i: 31, b: 41)) S.f.append(IntByte(i: 51, b: 61)) printit(S.f) // CHECK-LABEL: ### testMap // CHECK-NEXT: 101 // CHECK-NEXT: 102 // CHECK-NEXT: 103 print("### testMap") testMap() // CHECK-LABEL: ### testMatrixAdd // CHECK-NEXT: (11,22,33) // CHECK-NEXT: (44,55,66) print("### testMatrixAdd") testMatrixAdd() // CHECK-LABEL: ### testRingBuffer // CHECK-NEXT: true // CHECK-NEXT: true // CHECK-NEXT: 1 // CHECK-NEXT: true // CHECK-NEXT: false // CHECK-NEXT: 2 // CHECK-NEXT: 3 // CHECK-NEXT: nil print("### testRingBuffer") testRingBuffer() } }