| //===--- FixedArray.swift.gyb ---------------------------------*- swift -*-===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // A helper struct to provide fixed-sized array like functionality |
| // |
| //===----------------------------------------------------------------------===// |
| |
| %{ |
| # The sizes to generate code for. |
| sizes = [2, 4, 8, 16] |
| }% |
| |
| % for N in sizes: |
| |
| internal struct _FixedArray${N}<T> { |
| // ABI TODO: This makes assumptions about tuple layout in the ABI, namely that |
| // they are laid out contiguously and individually addressable (i.e. strided). |
| // |
| internal var storage: ( |
| // A ${N}-wide tuple of type T |
| % for i in range(0, N-1): |
| T, |
| % end |
| T |
| ) |
| |
| var _count: Int8 |
| } |
| |
| extension _FixedArray${N} { |
| internal static var capacity: Int { |
| @inline(__always) get { return ${N} } |
| } |
| |
| internal var capacity: Int { |
| @inline(__always) get { return ${N} } |
| } |
| |
| internal var count: Int { |
| @inline(__always) get { return Int(truncatingIfNeeded: _count) } |
| @inline(__always) set { _count = Int8(newValue) } |
| } |
| } |
| |
| extension _FixedArray${N} : RandomAccessCollection, MutableCollection { |
| internal typealias Index = Int |
| |
| internal var startIndex : Index { |
| return 0 |
| } |
| |
| internal var endIndex : Index { |
| return count |
| } |
| |
| internal subscript(i: Index) -> T { |
| @inline(__always) |
| get { |
| let count = self.count // for exclusive access |
| _internalInvariant(i >= 0 && i < count) |
| let res: T = withUnsafeBytes(of: storage) { |
| (rawPtr : UnsafeRawBufferPointer) -> T in |
| let stride = MemoryLayout<T>.stride |
| _internalInvariant(rawPtr.count == ${N}*stride, "layout mismatch?") |
| let bufPtr = UnsafeBufferPointer( |
| start: rawPtr.baseAddress!.assumingMemoryBound(to: T.self), |
| count: count) |
| return bufPtr[_unchecked: i] |
| } |
| return res |
| } |
| @inline(__always) |
| set { |
| _internalInvariant(i >= 0 && i < count) |
| self.withUnsafeMutableBufferPointer { buffer in |
| buffer[_unchecked: i] = newValue |
| } |
| } |
| } |
| |
| @inline(__always) |
| internal func index(after i: Index) -> Index { |
| return i+1 |
| } |
| |
| @inline(__always) |
| internal func index(before i: Index) -> Index { |
| return i-1 |
| } |
| } |
| |
| extension _FixedArray${N} { |
| internal mutating func append(_ newElement: T) { |
| _internalInvariant(count < capacity) |
| _count += 1 |
| self[count-1] = newElement |
| } |
| } |
| |
| extension _FixedArray${N} where T : ExpressibleByIntegerLiteral { |
| @inline(__always) |
| internal init(count: Int) { |
| _internalInvariant(count >= 0 && count <= _FixedArray${N}.capacity) |
| self.storage = ( |
| % for i in range(0, N-1): |
| 0, |
| % end |
| 0 |
| ) |
| self._count = Int8(truncatingIfNeeded: count) |
| } |
| |
| @inline(__always) |
| internal init() { |
| self.init(count: 0) |
| } |
| |
| @inline(__always) |
| internal init(allZeros: ()) { |
| self.init(count: ${N}) |
| } |
| } |
| |
| extension _FixedArray${N} { |
| internal mutating func withUnsafeMutableBufferPointer<R>( |
| _ body: (UnsafeMutableBufferPointer<Element>) throws -> R |
| ) rethrows -> R { |
| let count = self.count // for exclusive access |
| return try withUnsafeMutableBytes(of: &storage) { rawBuffer in |
| _internalInvariant(rawBuffer.count == ${N}*MemoryLayout<T>.stride, |
| "layout mismatch?") |
| let buffer = UnsafeMutableBufferPointer<Element>( |
| start: rawBuffer.baseAddress._unsafelyUnwrappedUnchecked |
| .assumingMemoryBound(to: Element.self), |
| count: count) |
| return try body(buffer) |
| } |
| } |
| |
| internal mutating func withUnsafeBufferPointer<R>( |
| _ body: (UnsafeBufferPointer<Element>) throws -> R |
| ) rethrows -> R { |
| let count = self.count // for exclusive access |
| return try withUnsafeBytes(of: &storage) { rawBuffer in |
| _internalInvariant(rawBuffer.count == ${N}*MemoryLayout<T>.stride, |
| "layout mismatch?") |
| let buffer = UnsafeBufferPointer<Element>( |
| start: rawBuffer.baseAddress._unsafelyUnwrappedUnchecked |
| .assumingMemoryBound(to: Element.self), |
| count: count) |
| return try body(buffer) |
| } |
| } |
| } |
| |
| % end |
| |
| // ${'Local Variables'}: |
| // eval: (read-only-mode 1) |
| // End: |