blob: ab5b74c26cc45a5b1982b3673686028883cb7089 [file] [log] [blame]
//===--- ManagedBuffer.swift - variable-sized buffer of aligned memory ----===//
//
// 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
//
//===----------------------------------------------------------------------===//
import SwiftShims
@usableFromInline
internal typealias _HeapObject = SwiftShims.HeapObject
@usableFromInline
@_silgen_name("swift_bufferAllocate")
internal func _swift_bufferAllocate(
bufferType type: AnyClass,
size: Int,
alignmentMask: Int
) -> AnyObject
/// A class whose instances contain a property of type `Header` and raw
/// storage for an array of `Element`, whose size is determined at
/// instance creation.
///
/// Note that the `Element` array is suitably-aligned **raw memory**.
/// You are expected to construct and---if necessary---destroy objects
/// there yourself, using the APIs on `UnsafeMutablePointer<Element>`.
/// Typical usage stores a count and capacity in `Header` and destroys
/// any live elements in the `deinit` of a subclass.
/// - Note: Subclasses must not have any stored properties; any storage
/// needed should be included in `Header`.
@_fixed_layout
open class ManagedBuffer<Header, Element> {
/// The stored `Header` instance.
///
/// During instance creation, in particular during
/// `ManagedBuffer.create`'s call to initialize, `ManagedBuffer`'s
/// `header` property is as-yet uninitialized, and therefore
/// reading the `header` property during `ManagedBuffer.create` is undefined.
public final var header: Header
internal init(_doNotCallMe: ()) {
_internalInvariantFailure("Only initialize these by calling create")
}
}
extension ManagedBuffer {
/// Create a new instance of the most-derived class, calling
/// `factory` on the partially-constructed object to generate
/// an initial `Header`.
@inlinable
public final class func create(
minimumCapacity: Int,
makingHeaderWith factory: (
ManagedBuffer<Header, Element>) throws -> Header
) rethrows -> ManagedBuffer<Header, Element> {
let p = Builtin.allocWithTailElems_1(
self,
minimumCapacity._builtinWordValue, Element.self)
let initHeaderVal = try factory(p)
p.headerAddress.initialize(to: initHeaderVal)
// The _fixLifetime is not really needed, because p is used afterwards.
// But let's be conservative and fix the lifetime after we use the
// headerAddress.
_fixLifetime(p)
return p
}
/// The actual number of elements that can be stored in this object.
///
/// This header may be nontrivial to compute; it is usually a good
/// idea to store this information in the "header" area when
/// an instance is created.
@inlinable
public final var capacity: Int {
let storageAddr = UnsafeMutableRawPointer(Builtin.bridgeToRawPointer(self))
let endAddr = storageAddr + _swift_stdlib_malloc_size(storageAddr)
let realCapacity = endAddr.assumingMemoryBound(to: Element.self) -
firstElementAddress
return realCapacity
}
@inlinable
internal final var firstElementAddress: UnsafeMutablePointer<Element> {
return UnsafeMutablePointer(
Builtin.projectTailElems(self, Element.self))
}
@inlinable
internal final var headerAddress: UnsafeMutablePointer<Header> {
return UnsafeMutablePointer<Header>(Builtin.addressof(&header))
}
/// Call `body` with an `UnsafeMutablePointer` to the stored
/// `Header`.
///
/// - Note: This pointer is valid only for the duration of the
/// call to `body`.
@inlinable
public final func withUnsafeMutablePointerToHeader<R>(
_ body: (UnsafeMutablePointer<Header>) throws -> R
) rethrows -> R {
return try withUnsafeMutablePointers { (v, _) in return try body(v) }
}
/// Call `body` with an `UnsafeMutablePointer` to the `Element`
/// storage.
///
/// - Note: This pointer is valid only for the duration of the
/// call to `body`.
@inlinable
public final func withUnsafeMutablePointerToElements<R>(
_ body: (UnsafeMutablePointer<Element>) throws -> R
) rethrows -> R {
return try withUnsafeMutablePointers { return try body($1) }
}
/// Call `body` with `UnsafeMutablePointer`s to the stored `Header`
/// and raw `Element` storage.
///
/// - Note: These pointers are valid only for the duration of the
/// call to `body`.
@inlinable
public final func withUnsafeMutablePointers<R>(
_ body: (UnsafeMutablePointer<Header>, UnsafeMutablePointer<Element>) throws -> R
) rethrows -> R {
defer { _fixLifetime(self) }
return try body(headerAddress, firstElementAddress)
}
}
@inline(never)
public func tryReallocateUniquelyReferenced<Header, Element, Buffer: ManagedBuffer<Header, Element>>(
buffer: inout Buffer,
newMinimumCapacity: Int
) -> Bool {
precondition(_isBitwiseTakable(Header.self))
precondition(_isBitwiseTakable(Element.self))
precondition(isKnownUniquelyReferenced(&buffer))
let newSizeInBytes = MemoryLayout<Header>.stride
+ newMinimumCapacity * MemoryLayout<Element>.stride
return withUnsafeMutablePointer(to: &buffer) {
$0.withMemoryRebound(to: UnsafeMutableRawPointer.self, capacity: 1) {
if let reallocdObject = _reallocObject($0.pointee, newSizeInBytes) {
$0.pointee = reallocdObject
return true
} else {
return false
}
}
}
}
/// Contains a buffer object, and provides access to an instance of
/// `Header` and contiguous storage for an arbitrary number of
/// `Element` instances stored in that buffer.
///
/// For most purposes, the `ManagedBuffer` class works fine for this
/// purpose, and can simply be used on its own. However, in cases
/// where objects of various different classes must serve as storage,
/// `ManagedBufferPointer` is needed.
///
/// A valid buffer class is non-`@objc`, with no declared stored
/// properties. Its `deinit` must destroy its
/// stored `Header` and any constructed `Element`s.
///
/// Example Buffer Class
/// --------------------
///
/// class MyBuffer<Element> { // non-@objc
/// typealias Manager = ManagedBufferPointer<(Int, String), Element>
/// deinit {
/// Manager(unsafeBufferObject: self).withUnsafeMutablePointers {
/// (pointerToHeader, pointerToElements) -> Void in
/// pointerToElements.deinitialize(count: self.count)
/// pointerToHeader.deinitialize(count: 1)
/// }
/// }
///
/// // All properties are *computed* based on members of the Header
/// var count: Int {
/// return Manager(unsafeBufferObject: self).header.0
/// }
/// var name: String {
/// return Manager(unsafeBufferObject: self).header.1
/// }
/// }
///
@_fixed_layout
public struct ManagedBufferPointer<Header, Element> {
@usableFromInline
internal var _nativeBuffer: Builtin.NativeObject
/// Create with new storage containing an initial `Header` and space
/// for at least `minimumCapacity` `element`s.
///
/// - parameter bufferClass: The class of the object used for storage.
/// - parameter minimumCapacity: The minimum number of `Element`s that
/// must be able to be stored in the new buffer.
/// - parameter factory: A function that produces the initial
/// `Header` instance stored in the buffer, given the `buffer`
/// object and a function that can be called on it to get the actual
/// number of allocated elements.
///
/// - Precondition: `minimumCapacity >= 0`, and the type indicated by
/// `bufferClass` is a non-`@objc` class with no declared stored
/// properties. The `deinit` of `bufferClass` must destroy its
/// stored `Header` and any constructed `Element`s.
@inlinable
public init(
bufferClass: AnyClass,
minimumCapacity: Int,
makingHeaderWith factory:
(_ buffer: AnyObject, _ capacity: (AnyObject) -> Int) throws -> Header
) rethrows {
self = ManagedBufferPointer(
bufferClass: bufferClass, minimumCapacity: minimumCapacity)
// initialize the header field
try withUnsafeMutablePointerToHeader {
$0.initialize(to:
try factory(
self.buffer,
{
ManagedBufferPointer(unsafeBufferObject: $0).capacity
}))
}
// FIXME: workaround for <rdar://problem/18619176>. If we don't
// access header somewhere, its addressor gets linked away
_ = header
}
/// Manage the given `buffer`.
///
/// - Precondition: `buffer` is an instance of a non-`@objc` class whose
/// `deinit` destroys its stored `Header` and any constructed `Element`s.
@inlinable
public init(unsafeBufferObject buffer: AnyObject) {
ManagedBufferPointer._checkValidBufferClass(type(of: buffer))
self._nativeBuffer = Builtin.unsafeCastToNativeObject(buffer)
}
//===--- internal/private API -------------------------------------------===//
/// Internal version for use by _ContiguousArrayBuffer where we know that we
/// have a valid buffer class.
/// This version of the init function gets called from
/// _ContiguousArrayBuffer's deinit function. Since 'deinit' does not get
/// specialized with current versions of the compiler, we can't get rid of the
/// _debugPreconditions in _checkValidBufferClass for any array. Since we know
/// for the _ContiguousArrayBuffer that this check must always succeed we omit
/// it in this specialized constructor.
@inlinable
internal init(_uncheckedUnsafeBufferObject buffer: AnyObject) {
ManagedBufferPointer._internalInvariantValidBufferClass(type(of: buffer))
self._nativeBuffer = Builtin.unsafeCastToNativeObject(buffer)
}
/// Create with new storage containing space for an initial `Header`
/// and at least `minimumCapacity` `element`s.
///
/// - parameter bufferClass: The class of the object used for storage.
/// - parameter minimumCapacity: The minimum number of `Element`s that
/// must be able to be stored in the new buffer.
///
/// - Precondition: `minimumCapacity >= 0`, and the type indicated by
/// `bufferClass` is a non-`@objc` class with no declared stored
/// properties. The `deinit` of `bufferClass` must destroy its
/// stored `Header` and any constructed `Element`s.
@inlinable
internal init(
bufferClass: AnyClass,
minimumCapacity: Int
) {
ManagedBufferPointer._checkValidBufferClass(bufferClass, creating: true)
_precondition(
minimumCapacity >= 0,
"ManagedBufferPointer must have non-negative capacity")
self.init(
_uncheckedBufferClass: bufferClass, minimumCapacity: minimumCapacity)
}
/// Internal version for use by _ContiguousArrayBuffer.init where we know that
/// we have a valid buffer class and that the capacity is >= 0.
@inlinable
internal init(
_uncheckedBufferClass: AnyClass,
minimumCapacity: Int
) {
ManagedBufferPointer._internalInvariantValidBufferClass(_uncheckedBufferClass, creating: true)
_internalInvariant(
minimumCapacity >= 0,
"ManagedBufferPointer must have non-negative capacity")
let totalSize = ManagedBufferPointer._elementOffset
+ minimumCapacity * MemoryLayout<Element>.stride
let newBuffer: AnyObject = _swift_bufferAllocate(
bufferType: _uncheckedBufferClass,
size: totalSize,
alignmentMask: ManagedBufferPointer._alignmentMask)
self._nativeBuffer = Builtin.unsafeCastToNativeObject(newBuffer)
}
/// Manage the given `buffer`.
///
/// - Note: It is an error to use the `header` property of the resulting
/// instance unless it has been initialized.
@inlinable
internal init(_ buffer: ManagedBuffer<Header, Element>) {
_nativeBuffer = Builtin.unsafeCastToNativeObject(buffer)
}
}
extension ManagedBufferPointer {
/// The stored `Header` instance.
@inlinable
public var header: Header {
_read {
yield _headerPointer.pointee
}
_modify {
yield &_headerPointer.pointee
}
}
/// Returns the object instance being used for storage.
@inlinable
public var buffer: AnyObject {
return Builtin.castFromNativeObject(_nativeBuffer)
}
/// The actual number of elements that can be stored in this object.
///
/// This value may be nontrivial to compute; it is usually a good
/// idea to store this information in the "header" area when
/// an instance is created.
@inlinable
public var capacity: Int {
return (
_capacityInBytes &- ManagedBufferPointer._elementOffset
) / MemoryLayout<Element>.stride
}
/// Call `body` with an `UnsafeMutablePointer` to the stored
/// `Header`.
///
/// - Note: This pointer is valid only
/// for the duration of the call to `body`.
@inlinable
public func withUnsafeMutablePointerToHeader<R>(
_ body: (UnsafeMutablePointer<Header>) throws -> R
) rethrows -> R {
return try withUnsafeMutablePointers { (v, _) in return try body(v) }
}
/// Call `body` with an `UnsafeMutablePointer` to the `Element`
/// storage.
///
/// - Note: This pointer is valid only for the duration of the
/// call to `body`.
@inlinable
public func withUnsafeMutablePointerToElements<R>(
_ body: (UnsafeMutablePointer<Element>) throws -> R
) rethrows -> R {
return try withUnsafeMutablePointers { return try body($1) }
}
/// Call `body` with `UnsafeMutablePointer`s to the stored `Header`
/// and raw `Element` storage.
///
/// - Note: These pointers are valid only for the duration of the
/// call to `body`.
@inlinable
public func withUnsafeMutablePointers<R>(
_ body: (UnsafeMutablePointer<Header>, UnsafeMutablePointer<Element>) throws -> R
) rethrows -> R {
defer { _fixLifetime(_nativeBuffer) }
return try body(_headerPointer, _elementPointer)
}
/// Returns `true` iff `self` holds the only strong reference to its buffer.
///
/// See `isUniquelyReferenced` for details.
@inlinable
public mutating func isUniqueReference() -> Bool {
return _isUnique(&_nativeBuffer)
}
}
extension ManagedBufferPointer {
@inlinable
internal static func _checkValidBufferClass(
_ bufferClass: AnyClass, creating: Bool = false
) {
_debugPrecondition(
_class_getInstancePositiveExtentSize(bufferClass) == MemoryLayout<_HeapObject>.size
|| (
(!creating || bufferClass is ManagedBuffer<Header, Element>.Type)
&& _class_getInstancePositiveExtentSize(bufferClass)
== _headerOffset + MemoryLayout<Header>.size),
"ManagedBufferPointer buffer class has illegal stored properties"
)
_debugPrecondition(
_usesNativeSwiftReferenceCounting(bufferClass),
"ManagedBufferPointer buffer class must be non-@objc"
)
}
@inlinable
internal static func _internalInvariantValidBufferClass(
_ bufferClass: AnyClass, creating: Bool = false
) {
_internalInvariant(
_class_getInstancePositiveExtentSize(bufferClass) == MemoryLayout<_HeapObject>.size
|| (
(!creating || bufferClass is ManagedBuffer<Header, Element>.Type)
&& _class_getInstancePositiveExtentSize(bufferClass)
== _headerOffset + MemoryLayout<Header>.size),
"ManagedBufferPointer buffer class has illegal stored properties"
)
_internalInvariant(
_usesNativeSwiftReferenceCounting(bufferClass),
"ManagedBufferPointer buffer class must be non-@objc"
)
}
}
extension ManagedBufferPointer {
/// The required alignment for allocations of this type, minus 1
@inlinable
internal static var _alignmentMask: Int {
return max(
MemoryLayout<_HeapObject>.alignment,
max(MemoryLayout<Header>.alignment, MemoryLayout<Element>.alignment)) &- 1
}
/// The actual number of bytes allocated for this object.
@inlinable
internal var _capacityInBytes: Int {
return _swift_stdlib_malloc_size(_address)
}
/// The address of this instance in a convenient pointer-to-bytes form
@inlinable
internal var _address: UnsafeMutableRawPointer {
return UnsafeMutableRawPointer(Builtin.bridgeToRawPointer(_nativeBuffer))
}
/// Offset from the allocated storage for `self` to the stored `Header`
@inlinable
internal static var _headerOffset: Int {
_onFastPath()
return _roundUp(
MemoryLayout<_HeapObject>.size,
toAlignment: MemoryLayout<Header>.alignment)
}
/// An **unmanaged** pointer to the storage for the `Header`
/// instance. Not safe to use without _fixLifetime calls to
/// guarantee it doesn't dangle
@inlinable
internal var _headerPointer: UnsafeMutablePointer<Header> {
_onFastPath()
return (_address + ManagedBufferPointer._headerOffset).assumingMemoryBound(
to: Header.self)
}
/// An **unmanaged** pointer to the storage for `Element`s. Not
/// safe to use without _fixLifetime calls to guarantee it doesn't
/// dangle.
@inlinable
internal var _elementPointer: UnsafeMutablePointer<Element> {
_onFastPath()
return (_address + ManagedBufferPointer._elementOffset).assumingMemoryBound(
to: Element.self)
}
/// Offset from the allocated storage for `self` to the `Element` storage
@inlinable
internal static var _elementOffset: Int {
_onFastPath()
return _roundUp(
_headerOffset + MemoryLayout<Header>.size,
toAlignment: MemoryLayout<Element>.alignment)
}
}
extension ManagedBufferPointer: Equatable {
@inlinable
public static func == (
lhs: ManagedBufferPointer,
rhs: ManagedBufferPointer
) -> Bool {
return lhs._address == rhs._address
}
}
// FIXME: when our calling convention changes to pass self at +0,
// inout should be dropped from the arguments to these functions.
// FIXME(docs): isKnownUniquelyReferenced should check weak/unowned counts too,
// but currently does not. rdar://problem/29341361
/// Returns a Boolean value indicating whether the given object is known to
/// have a single strong reference.
///
/// The `isKnownUniquelyReferenced(_:)` function is useful for implementing the
/// copy-on-write optimization for the deep storage of value types:
///
/// mutating func update(withValue value: T) {
/// if !isKnownUniquelyReferenced(&myStorage) {
/// myStorage = self.copiedStorage()
/// }
/// myStorage.update(withValue: value)
/// }
///
/// Use care when calling `isKnownUniquelyReferenced(_:)` from within a Boolean
/// expression. In debug builds, an instance in the left-hand side of a `&&`
/// or `||` expression may still be referenced when evaluating the right-hand
/// side, inflating the instance's reference count. For example, this version
/// of the `update(withValue)` method will re-copy `myStorage` on every call:
///
/// // Copies too frequently:
/// mutating func badUpdate(withValue value: T) {
/// if myStorage.shouldCopy || !isKnownUniquelyReferenced(&myStorage) {
/// myStorage = self.copiedStorage()
/// }
/// myStorage.update(withValue: value)
/// }
///
/// To avoid this behavior, swap the call `isKnownUniquelyReferenced(_:)` to
/// the left-hand side or store the result of the first expression in a local
/// constant:
///
/// mutating func goodUpdate(withValue value: T) {
/// let shouldCopy = myStorage.shouldCopy
/// if shouldCopy || !isKnownUniquelyReferenced(&myStorage) {
/// myStorage = self.copiedStorage()
/// }
/// myStorage.update(withValue: value)
/// }
///
/// `isKnownUniquelyReferenced(_:)` checks only for strong references to the
/// given object---if `object` has additional weak or unowned references, the
/// result may still be `true`. Because weak and unowned references cannot be
/// the only reference to an object, passing a weak or unowned reference as
/// `object` always results in `false`.
///
/// If the instance passed as `object` is being accessed by multiple threads
/// simultaneously, this function may still return `true`. Therefore, you must
/// only call this function from mutating methods with appropriate thread
/// synchronization. That will ensure that `isKnownUniquelyReferenced(_:)`
/// only returns `true` when there is really one accessor, or when there is a
/// race condition, which is already undefined behavior.
///
/// - Parameter object: An instance of a class. This function does *not* modify
/// `object`; the use of `inout` is an implementation artifact.
/// - Returns: `true` if `object` is known to have a single strong reference;
/// otherwise, `false`.
@inlinable
public func isKnownUniquelyReferenced<T : AnyObject>(_ object: inout T) -> Bool
{
return _isUnique(&object)
}
/// Returns a Boolean value indicating whether the given object is known to
/// have a single strong reference.
///
/// The `isKnownUniquelyReferenced(_:)` function is useful for implementing the
/// copy-on-write optimization for the deep storage of value types:
///
/// mutating func update(withValue value: T) {
/// if !isKnownUniquelyReferenced(&myStorage) {
/// myStorage = self.copiedStorage()
/// }
/// myStorage.update(withValue: value)
/// }
///
/// `isKnownUniquelyReferenced(_:)` checks only for strong references to the
/// given object---if `object` has additional weak or unowned references, the
/// result may still be `true`. Because weak and unowned references cannot be
/// the only reference to an object, passing a weak or unowned reference as
/// `object` always results in `false`.
///
/// If the instance passed as `object` is being accessed by multiple threads
/// simultaneously, this function may still return `true`. Therefore, you must
/// only call this function from mutating methods with appropriate thread
/// synchronization. That will ensure that `isKnownUniquelyReferenced(_:)`
/// only returns `true` when there is really one accessor, or when there is a
/// race condition, which is already undefined behavior.
///
/// - Parameter object: An instance of a class. This function does *not* modify
/// `object`; the use of `inout` is an implementation artifact.
/// - Returns: `true` if `object` is known to have a single strong reference;
/// otherwise, `false`. If `object` is `nil`, the return value is `false`.
@inlinable
public func isKnownUniquelyReferenced<T : AnyObject>(
_ object: inout T?
) -> Bool {
return _isUnique(&object)
}