//===--- UnsafeBufferPointer.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 // //===----------------------------------------------------------------------===// /// An iterator for the elements in the buffer referenced by an /// `UnsafeBufferPointer` or `UnsafeMutableBufferPointer` instance. @_fixed_layout public struct UnsafeBufferPointerIterator : IteratorProtocol, Sequence { /// Advances to the next element and returns it, or `nil` if no next element /// exists. /// /// Once `nil` has been returned, all subsequent calls return `nil`. @_inlineable public mutating func next() -> Element? { if _position == _end { return nil } let result = _position!.pointee _position! += 1 return result } @_versioned internal var _position, _end: UnsafePointer? @_inlineable public init(_position: UnsafePointer?, _end: UnsafePointer?) { self._position = _position self._end = _end } } % for mutable in (True, False): % Self = 'UnsafeMutableBufferPointer' if mutable else 'UnsafeBufferPointer' % Mutable = 'Mutable' if mutable else '' /// A non-owning collection interface to a buffer of ${Mutable.lower()} /// elements stored contiguously in memory. /// /// You can use an `${Self}` instance in low level operations to eliminate /// uniqueness checks and, in release mode, bounds checks. Bounds checks are /// always performed in debug mode. /// /// ${Self} Semantics /// ================= /// /// An `${Self}` instance is a view into memory and does not own the memory /// that it references. Copying a value of type `${Self}` does not copy the /// instances stored in the underlying memory. However, initializing another /// collection with an `${Self}` instance copies the instances out of the /// referenced memory and into the new collection. @_fixed_layout public struct Unsafe${Mutable}BufferPointer : _${Mutable}Indexable, ${Mutable}Collection, RandomAccessCollection { // FIXME: rdar://18157434 - until this is fixed, this has to be fixed layout // to avoid a hang in Foundation, which has the following setup: // struct A { struct B { let x: UnsafeMutableBufferPointer<...> } let b: B } public typealias Index = Int public typealias IndexDistance = Int public typealias Iterator = UnsafeBufferPointerIterator /// The index of the first element in a nonempty buffer. /// /// The `startIndex` property of an `Unsafe${Mutable}BufferPointer` instance /// is always zero. @_inlineable public var startIndex: Int { return 0 } /// The "past the end" position---that is, the position one greater than the /// last valid subscript argument. /// /// The `endIndex` property of an `Unsafe${Mutable}BufferPointer` instance is /// always identical to `count`. @_inlineable public var endIndex: Int { return count } @_inlineable public func index(after i: Int) -> Int { // NOTE: this is a manual specialization of index movement for a Strideable // index that is required for UnsafeBufferPointer performance. The // optimizer is not capable of creating partial specializations yet. // NOTE: Range checks are not performed here, because it is done later by // the subscript function. return i + 1 } @_inlineable public func formIndex(after i: inout Int) { // NOTE: this is a manual specialization of index movement for a Strideable // index that is required for UnsafeBufferPointer performance. The // optimizer is not capable of creating partial specializations yet. // NOTE: Range checks are not performed here, because it is done later by // the subscript function. i += 1 } @_inlineable public func index(before i: Int) -> Int { // NOTE: this is a manual specialization of index movement for a Strideable // index that is required for UnsafeBufferPointer performance. The // optimizer is not capable of creating partial specializations yet. // NOTE: Range checks are not performed here, because it is done later by // the subscript function. return i - 1 } @_inlineable public func formIndex(before i: inout Int) { // NOTE: this is a manual specialization of index movement for a Strideable // index that is required for UnsafeBufferPointer performance. The // optimizer is not capable of creating partial specializations yet. // NOTE: Range checks are not performed here, because it is done later by // the subscript function. i -= 1 } @_inlineable public func index(_ i: Int, offsetBy n: Int) -> Int { // NOTE: this is a manual specialization of index movement for a Strideable // index that is required for UnsafeBufferPointer performance. The // optimizer is not capable of creating partial specializations yet. // NOTE: Range checks are not performed here, because it is done later by // the subscript function. return i + n } @_inlineable public func index( _ i: Int, offsetBy n: Int, limitedBy limit: Int ) -> Int? { // NOTE: this is a manual specialization of index movement for a Strideable // index that is required for UnsafeBufferPointer performance. The // optimizer is not capable of creating partial specializations yet. // NOTE: Range checks are not performed here, because it is done later by // the subscript function. let l = limit - i if n > 0 ? l >= 0 && l < n : l <= 0 && n < l { return nil } return i + n } @_inlineable public func distance(from start: Int, to end: Int) -> Int { // NOTE: this is a manual specialization of index movement for a Strideable // index that is required for UnsafeBufferPointer performance. The // optimizer is not capable of creating partial specializations yet. // NOTE: Range checks are not performed here, because it is done later by // the subscript function. return end - start } @_inlineable public func _failEarlyRangeCheck(_ index: Int, bounds: Range) { // NOTE: This method is a no-op for performance reasons. } @_inlineable public func _failEarlyRangeCheck(_ range: Range, bounds: Range) { // NOTE: This method is a no-op for performance reasons. } public typealias Indices = CountableRange @_inlineable public var indices: Indices { return startIndex.. ) -> (Iterator, UnsafeMutableBufferPointer.Index) { guard !isEmpty && !destination.isEmpty else { return (makeIterator(), 0) } let s = self.baseAddress._unsafelyUnwrappedUnchecked let d = destination.baseAddress._unsafelyUnwrappedUnchecked let n = Swift.min(destination.count, self.count) d.initialize(from: s, count: n) return (Iterator(_position: s + n, _end: _end), n) } /// Accesses the element at the specified position. /// %if Mutable: /// The following example uses the buffer pointer's subscript to access and /// modifying the elements of a mutable buffer pointing to the contiguous /// contents of an array: /// /// var numbers = [1, 2, 3, 4, 5] /// numbers.withUnsafeMutableBufferPointer { buffer in /// for i in stride(from: buffer.startIndex, to: buffer.endIndex - 1, by: 2) { /// let x = buffer[i] /// buffer[i + 1] = buffer[i] /// buffer[i] = x /// } /// } /// print(numbers) /// // Prints "[2, 1, 4, 3, 5]" %else: /// The following example uses the buffer pointer's subscript to access every /// other element of the buffer: /// /// let numbers = [1, 2, 3, 4, 5] /// let sum = numbers.withUnsafeBufferPointer { buffer -> Int in /// var result = 0 /// for i in stride(from: buffer.startIndex, to: buffer.endIndex, by: 2) { /// result += buffer[i] /// } /// return result /// } /// // 'sum' == 9 %end /// /// - Note: Bounds checks for `i` are performed only in debug mode. /// /// - Parameter i: The position of the element to access. `i` must be in the /// range `0.. Element { get { _debugPrecondition(i >= 0) _debugPrecondition(i < endIndex) return _position![i] } %if Mutable: nonmutating set { _debugPrecondition(i >= 0) _debugPrecondition(i < endIndex) _position![i] = newValue } %end } @_inlineable public subscript(bounds: Range) -> ${Mutable}RandomAccessSlice> { get { _debugPrecondition(bounds.lowerBound >= startIndex) _debugPrecondition(bounds.upperBound <= endIndex) return ${Mutable}RandomAccessSlice( base: self, bounds: bounds) } % if Mutable: set { _debugPrecondition(bounds.lowerBound >= startIndex) _debugPrecondition(bounds.upperBound <= endIndex) // FIXME: swift-3-indexing-model: tests. _writeBackMutableSlice(&self, bounds: bounds, slice: newValue) } % end } /// Creates a new buffer pointer over the specified number of contiguous /// instances beginning at the given pointer. /// /// - Parameters: /// - start: A pointer to the start of the buffer, or `nil`. If `start` is /// `nil`, `count` must be zero. However, `count` may be zero even for a /// non-`nil` `start`. The pointer passed as `start` must be aligned to /// `MemoryLayout.alignment`. /// - count: The number of instances in the buffer. `count` must not be /// negative. @_inlineable public init(start: Unsafe${Mutable}Pointer?, count: Int) { _precondition( count >= 0, "Unsafe${Mutable}BufferPointer with negative count") _precondition( count == 0 || start != nil, "Unsafe${Mutable}BufferPointer has a nil start and nonzero count") _position = start _end = start.map { $0 + count } } /// Creates a buffer pointer starting at `start` and extending up to the last /// addressable pointer to `Element` in the memory space @_inlineable public init(_unboundedStartingAt start: Unsafe${Mutable}Pointer) { _position = start _end = type(of: start)._max } @_inlineable public init(_empty: ()) { _position = Unsafe${Mutable}Pointer._max _end = _position } % if not Mutable: /// Creates a buffer over the same memory as the given buffer slice. /// /// The new buffer represents the same region of memory as `slice`, but is /// indexed starting at zero instead of sharing indices with the original /// buffer. For example: /// /// let buffer = returnsABuffer() /// let n = 5 /// let slice = buffer[n...] /// let rebased = UnsafeBufferPointer(rebasing: slice) /// /// After rebasing `slice` as the `rebased` buffer, the following are true: /// /// - `rebased.startIndex == 0` /// - `rebased[0] == slice[n]` /// - `rebased[0] == buffer[n]` /// - `rebased.count == slice.count` /// /// - Parameter slice: The buffer slice to rebase. @_inlineable public init(rebasing slice: RandomAccessSlice>) { self.init(start: slice.base.baseAddress! + slice.startIndex, count: slice.count) } % end # !mutable /// Creates a buffer over the same memory as the given buffer slice. /// /// The new buffer represents the same region of memory as `slice`, but is /// indexed starting at zero instead of sharing indices with the original /// buffer. For example: /// /// let buffer = returnsABuffer() /// let n = 5 /// let slice = buffer[n...] /// let rebased = Unsafe${Mutable}BufferPointer(rebasing: slice) /// /// After rebasing `slice` as the `rebased` buffer, the following are true: /// /// - `rebased.startIndex == 0` /// - `rebased[0] == slice[n]` /// - `rebased[0] == buffer[n]` /// - `rebased.count == slice.count` /// /// - Parameter slice: The buffer slice to rebase. @_inlineable public init( rebasing slice: MutableRandomAccessSlice> ) { self.init(start: slice.base.baseAddress! + slice.startIndex, count: slice.count) } /// Returns an iterator over the elements of this buffer. /// /// - Returns: An iterator over the elements of this buffer. @_inlineable public func makeIterator() -> UnsafeBufferPointerIterator { return UnsafeBufferPointerIterator(_position: _position, _end: _end) } /// A pointer to the first element of the buffer. /// /// If the `baseAddress` of this buffer is `nil`, the count is zero. However, /// a buffer can have a `count` of zero even with a non-`nil` base address. @_inlineable public var baseAddress: Unsafe${Mutable}Pointer? { return _position } /// The number of elements in the buffer. /// /// If the `baseAddress` of this buffer is `nil`, the count is zero. However, /// a buffer can have a `count` of zero even with a non-`nil` base address. @_inlineable public var count: Int { switch(_position, _end) { case (.some(let pos), .some(let end)): return (end - pos) case _: return 0 } } @_versioned let _position, _end: Unsafe${Mutable}Pointer? } extension Unsafe${Mutable}BufferPointer : CustomDebugStringConvertible { /// A textual representation of the buffer, suitable for debugging. @_inlineable // FIXME(sil-serialize-all) public var debugDescription: String { return "Unsafe${Mutable}BufferPointer" + "(start: \(_position.map(String.init(describing:)) ?? "nil"), count: \(count))" } } %end extension UnsafeMutableBufferPointer { /// Initializes the buffer's memory with the given elements. /// /// When calling the `initialize(from:)` method on a buffer `b`, the memory /// referenced by `b` must be uninitialized or the `Element` type must be a /// trivial type. After the call, the memory referenced by this buffer up /// to, but not including, the returned index is initialized. The buffer /// must contain sufficient memory to accommodate /// `source.underestimatedCount`. /// /// The returned index is the position of the element in the buffer one past /// the last element written. If `source` contains no elements, the returned /// index is equal to the buffer's `startIndex`. If `source` contains an /// equal or greater number of elements than the buffer can hold, the /// returned index is equal to the buffer's `endIndex`. /// /// - Parameter source: A sequence of elements with which to initializer the /// buffer. /// - Returns: An iterator to any elements of `source` that didn't fit in the /// buffer, and an index to the point in the buffer one past the last /// element written. @_inlineable public func initialize(from source: S) -> (S.Iterator, Index) where S.Element == Element { return source._copyContents(initializing: self) } } // ${'Local Variables'}: // eval: (read-only-mode 1) // End: