// Contains experimental implementations of FixedArray and BufferView @frozen public struct FixedArray : ~Copyable { @usableFromInline let buffer: UnsafeMutablePointer public let capacity: Int @usableFromInline internal var _count: Int // Workaround until FixedArray itself can conform to ExpressibleByArrayLiteral @frozen public struct _Literal: ExpressibleByArrayLiteral { @usableFromInline let array: [T] @_transparent @_alwaysEmitIntoClient public init(arrayLiteral elements: T...) { self.array = elements } } @_transparent @_alwaysEmitIntoClient public init(capacity: Int) { self.capacity = capacity self.buffer = _allocateVector(elementType: T.self, capacity: capacity) self._count = 0 } @_transparent @_alwaysEmitIntoClient public init(elements: [T]) { let count = elements.count self._count = count self.capacity = count self.buffer = elements.createVector() } @_transparent @_alwaysEmitIntoClient public init(repeating repeatedValue: T, count: Int) { self.capacity = count self.buffer = _allocateVector(elementType: T.self, capacity: capacity) self._count = count for i in 0.. BufferView { BufferView(baseAddress: buffer, count: count) } public subscript(position: Int) -> T { @_alwaysEmitIntoClient get { precondition(position >= 0 && position < count) return buffer[position] } @_alwaysEmitIntoClient set { precondition(position >= 0 && position < count) buffer[position] = newValue } } // Will be used once it's possible to let FixedArray conform to Collection. public var startIndex: Int { 0 } public var endIndex: Int { count } public func index(after i: Int) -> Int { return i + 1 } @_alwaysEmitIntoClient public mutating func append(_ element: T) { precondition(count < capacity, "capacity overflow") (buffer + count).initialize(to: element) _count &+= 1 } @_alwaysEmitIntoClient deinit { buffer.deinitialize(count: count) } } // Syntatic sugar for creating a FixedArray literal prefix operator ^ @_transparent @_alwaysEmitIntoClient public prefix func ^(_ literal: FixedArray._Literal) -> FixedArray { return FixedArray(elements: literal.array) } // Syntatic sugar for getting a BufferView to a FixedArray prefix operator * @_transparent @_alwaysEmitIntoClient public prefix func *(array: borrowing FixedArray) -> BufferView { return array.view() } extension Array { @_transparent @_alwaysEmitIntoClient public func createVector() -> UnsafeMutablePointer { let count = self.count let vector = _allocateVector(elementType: Element.self, capacity: count) copyInto(vectorBuffer: vector) return vector } @_alwaysEmitIntoClient @_semantics("array.copy_into_vector") internal func copyInto(vectorBuffer: UnsafeMutablePointer) { withUnsafeBufferPointer { vectorBuffer.initialize(from: $0.baseAddress!, count: $0.count) } } } @frozen public struct BufferViewIndex : Equatable { public typealias Pointer = UnsafePointer @usableFromInline let _pointer: Pointer @_alwaysEmitIntoClient public init(pointer: Pointer) { _pointer = pointer } } extension BufferViewIndex : Strideable { public typealias Stride = Int @_alwaysEmitIntoClient public func distance(to other: BufferViewIndex) -> Int { _pointer.distance(to: other._pointer) } @_alwaysEmitIntoClient public func advanced(by n: Int) -> BufferViewIndex { .init(pointer: _pointer.advanced(by: n)) } } extension BufferViewIndex : Comparable { @_alwaysEmitIntoClient public static func < (lhs: BufferViewIndex, rhs: BufferViewIndex) -> Bool { lhs._pointer < rhs._pointer } } @frozen public struct BufferView: Collection { // BufferView is self-slicing. The implementation is omitted for our purpose. public typealias SubSequence = BufferView public typealias Index = BufferViewIndex public typealias Pointer = Index.Pointer @usableFromInline let start: Index public let count: Int // Initialization is internal because a user-specified count is unsafe. @_alwaysEmitIntoClient init(start index: Index, count: Int) { precondition(count >= 0, "Count must not be negative") self.start = index self.count = count } @_alwaysEmitIntoClient init(baseAddress: Pointer, count: Int) { self.init(start: .init(pointer: baseAddress), count: count) } // An unsafe public API serves as the low-level entry point for // BufferView creation. @_alwaysEmitIntoClient public static func withTemporaryView( unsafeBaseAddress: Pointer, unsafeCount: Int, _ body: (borrowing BufferView) throws -> ResultType ) rethrows -> ResultType { try body(BufferView(baseAddress: unsafeBaseAddress, count: unsafeCount)) } @_alwaysEmitIntoClient public var startIndex: Index { start } @_alwaysEmitIntoClient public var endIndex: Index { start.advanced(by: count) } @_alwaysEmitIntoClient func _checkBounds(_ position: Index) { precondition(startIndex <= position && position < endIndex, "Index out of bounds") } public subscript(position: Index) -> Element { @_alwaysEmitIntoClient get { _checkBounds(position) return self[unchecked: position] } } public subscript(unchecked position: Index) -> Element { @_alwaysEmitIntoClient get { return position._pointer.pointee } } @_alwaysEmitIntoClient public subscript(bounds: Range) -> BufferView { precondition(startIndex <= bounds.lowerBound && bounds.upperBound <= endIndex, "range out of bounds") return BufferView(start: bounds.lowerBound, count: bounds.lowerBound.distance(to: bounds.upperBound)) } @_alwaysEmitIntoClient public func index(after i: Index) -> Index { return i.advanced(by: 1) } }