//===--- UnsafeRawBufferPointer.swift.gyb ---------------------*- swift -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2016 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 // //===----------------------------------------------------------------------===// %import gyb % for mutable in (True, False): % Self = 'UnsafeMutableRawBufferPointer' if mutable else 'UnsafeRawBufferPointer' % Mutable = 'Mutable' if mutable else '' /// A non-owning view over a region of memory as a Collection of bytes. /// /// Each 8-bit byte in memory is viewed as a `UInt8` value independent of the /// type of values held in that memory. /// /// Reads and writes on memory via `UnsafeRawBufferPointer` are untyped /// operations. Accessing this Collection's bytes does not bind the /// underlying memory to `UInt8`. The underlying memory must be bound /// to some trivial type whenever it is accessed via a typed operation. /// /// - Note: A trivial type can be copied with just a bit-for-bit copy without /// any indirection or reference-counting operations. Generally, native Swift /// types that do not contain strong or weak references or other forms of /// indirection are trivial, as are imported C structs and enums. Copying /// memory that contains values of nontrivial type can only be done safely /// with a typed pointer. Copying bytes directly from nontrivial in-memory /// values does not produce valid copies and can only be done by calling a C /// API such as memmove. /// /// In addition to the `Collection` interface, the following subset of /// `Unsafe${Mutable}RawPointer`'s interface to raw memory is /// provided with debug mode bounds checks: /// - `load(fromByteOffset:as:)`, % if mutable: /// - `storeBytes(of:toByteOffset:as:)` /// - `copyBytes(from:count:)` % end /// /// This is only a view into memory and does not own the memory. Copying a value /// of type `Unsafe${Mutable}Bytes` does not copy the underlying /// memory. However, initializing another collection, such as `[UInt8]`, with an /// `Unsafe${Mutable}Bytes` into copies bytes out of memory. /// /// Example: /// ```swift /// // View a slice of memory at someBytes. Nothing is copied. /// var destBytes = someBytes[0.. UInt8? { if _position == _end { return nil } let result = _position!.load(as: UInt8.self) _position! += 1 return result } internal var _position, _end: UnsafeRawPointer? } % if mutable: /// Allocate memory for `size` bytes with word alignment. /// /// - Postcondition: The memory is allocated, but not initialized. public static func allocate(count size: Int ) -> UnsafeMutableRawBufferPointer { return UnsafeMutableRawBufferPointer( start: UnsafeMutableRawPointer.allocate( bytes: size, alignedTo: MemoryLayout.alignment), count: size) } % end # mutable /// Deallocate this memory allocated for `bytes` number of bytes. /// /// - Precondition: The memory is not initialized. /// /// - Postcondition: The memory has been deallocated. public func deallocate() { _position?.deallocate( bytes: count, alignedTo: MemoryLayout.alignment) } /// Reads raw bytes from memory at `self + offset` and constructs a /// value of type `T`. /// /// - Precondition: `offset + MemoryLayout.size < self.count` /// /// - Precondition: The underlying pointer plus `offset` is properly /// aligned for accessing `T`. /// /// - Precondition: The memory is initialized to a value of some type `U` /// such that `T` is layout compatible with `U`. public func load(fromByteOffset offset: Int = 0, as type: T.Type) -> T { _debugPrecondition(offset >= 0, "${Self}.load with negative offset") _debugPrecondition(offset + MemoryLayout.size <= self.count, "${Self}.load out of bounds") return baseAddress!.load(fromByteOffset: offset, as: T.self) } % if mutable: /// Stores a value's bytes into raw memory at `self + offset`. /// /// - Precondition: `offset + MemoryLayout.size < self.count` /// /// - Precondition: The underlying pointer plus `offset` is properly /// aligned for storing type `T`. /// /// - Precondition: `T` is a trivial type. /// /// - Precondition: The memory is uninitialized, or initialized to /// some trivial type `U` such that `T` and `U` are mutually layout /// compatible. /// /// - Postcondition: The memory is initialized to raw bytes. If the /// memory is bound to type `U`, then it now contains a value of /// type `U`. /// /// - Note: A trivial type can be copied with just a bit-for-bit /// copy without any indirection or reference-counting operations. /// Generally, native Swift types that do not contain strong or /// weak references or other forms of indirection are trivial, as /// are imported C structs and enums. public func storeBytes( of value: T, toByteOffset offset: Int = 0, as: T.Type ) { _debugPrecondition(offset >= 0, "${Self}.storeBytes with negative offset") _debugPrecondition(offset + MemoryLayout.size <= self.count, "${Self}.storeBytes out of bounds") baseAddress!.storeBytes(of: value, toByteOffset: offset, as: T.self) } /// Copies `count` bytes from `source` into memory at `self`. /// /// - Precondition: `count` is non-negative. /// /// - Precondition: The memory at `source...stride`. /// /// - Postcondition: The memory at `self...stride`. /// /// - Postcondition: The memory at `self..(from source: C ) where C.Iterator.Element == UInt8 { _debugPrecondition(numericCast(source.count) <= self.count, "${Self}.copyBytes source has too many elements") guard let position = _position else { return } for (index, byteValue) in source.enumerated() { position.storeBytes( of: byteValue, toByteOffset: index, as: UInt8.self) } } % end # mutable /// Creates an `${Self}` over `count` contiguous bytes beginning at `start`. /// /// If `start` is nil, `count` must be 0. However, `count` may be 0 even for /// a nonzero `start`. public init(start: Unsafe${Mutable}RawPointer?, count: Int) { _precondition(count >= 0, "${Self} with negative count") _precondition(count == 0 || start != nil, "${Self} has a nil start and nonzero count") _position = start _end = start.map { $0 + count } } /// Converts UnsafeMutableRawBufferPointer to UnsafeRawBufferPointer. public init(_ bytes: UnsafeMutableRawBufferPointer) { self.init(start: bytes.baseAddress, count: bytes.count) } % if mutable: /// Converts UnsafeRawBufferPointer to UnsafeMutableRawBufferPointer. public init(mutating bytes: UnsafeRawBufferPointer) { self.init(start: UnsafeMutableRawPointer(mutating: bytes.baseAddress), count: bytes.count) } % else: /// Converts UnsafeRawBufferPointer to UnsafeMutableRawBufferPointer. public init(_ bytes: UnsafeRawBufferPointer) { self.init(start: bytes.baseAddress, count: bytes.count) } % end # !mutable /// Creates an `${Self}` over the contiguous bytes in `buffer`. /// /// - Precondition: `T` is a trivial type. public init(_ buffer: UnsafeMutableBufferPointer) { self.init(start: buffer.baseAddress!, count: buffer.count * MemoryLayout.stride) } % if not mutable: /// Creates an `${Self}` view over the contiguous memory in `buffer`. /// /// - Precondition: `T` is a trivial type. public init(_ buffer: UnsafeBufferPointer) { self.init(start: buffer.baseAddress!, count: buffer.count * MemoryLayout.stride) } % end # !mutable /// Always zero, which is the index of the first byte in a /// non-empty buffer. 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}RawBufferPointer` /// instance is always identical to `count`. public var endIndex: Int { return count } public typealias Indices = CountableRange public var indices: Indices { return startIndex.. UInt8 { get { _debugPrecondition(i >= 0) _debugPrecondition(i < endIndex) return _position!.load(fromByteOffset: i, as: UInt8.self) } % if mutable: nonmutating set { _debugPrecondition(i >= 0) _debugPrecondition(i < endIndex) _position!.storeBytes(of: newValue, toByteOffset: i, as: UInt8.self) } % end # mutable } /// Accesses the bytes in the memory region within `bounds` as a `UInt8` /// values. public subscript(bounds: Range) -> Unsafe${Mutable}RawBufferPointer { get { _debugPrecondition(bounds.lowerBound >= startIndex) _debugPrecondition(bounds.upperBound <= endIndex) return Unsafe${Mutable}RawBufferPointer( start: baseAddress.map { $0 + bounds.lowerBound }, count: bounds.count) } % if mutable: nonmutating set { _debugPrecondition(bounds.lowerBound >= startIndex) _debugPrecondition(bounds.upperBound <= endIndex) _debugPrecondition(bounds.count == newValue.count) if newValue.count > 0 { (baseAddress! + bounds.lowerBound).copyBytes( from: newValue.baseAddress!, count: newValue.count) } } % end # mutable } /// Returns an iterator over the bytes of this sequence. /// /// - Complexity: O(1). public func makeIterator() -> Iterator { return Iterator(_position: _position, _end: _end) } /// A pointer to the first byte of the buffer. public var baseAddress: Unsafe${Mutable}RawPointer? { return _position } /// The number of bytes in the buffer. public var count: Int { if let pos = _position { return _end! - pos } return 0 } let _position, _end: Unsafe${Mutable}RawPointer? } extension Unsafe${Mutable}RawBufferPointer : CustomDebugStringConvertible { /// A textual representation of `self`, suitable for debugging. public var debugDescription: String { return "${Self}" + "(start: \(_position.map(String.init(describing:)) ?? "nil"), count: \(count))" } } /// Invokes `body` with an `${Self}` argument and returns the /// result. % if mutable: public func withUnsafeMutableBytes( of arg: inout T, _ body: (UnsafeMutableRawBufferPointer) throws -> Result ) rethrows -> Result { return try withUnsafeMutablePointer(to: &arg) { return try body(UnsafeMutableRawBufferPointer( start: $0, count: MemoryLayout.size)) } } % else: public func withUnsafeBytes( of arg: inout T, _ body: (UnsafeRawBufferPointer) throws -> Result ) rethrows -> Result { return try withUnsafePointer(to: &arg) { try body(UnsafeRawBufferPointer(start: $0, count: MemoryLayout.size)) } } % end # mutable % end # for mutable