mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
This reverts r22541. It turns out that because of the type-punning we need in order to handle the canonical empty array buffer in Array<Int> and Array<SomeClass>, calls through methods that could be dynamically-dispatched (i.e. methods of classes) can't be used to access an array buffer. So, for arrays, we need to keep the HeapBuffer strategy wherein a struct manager object does all the address calculations. ManagedBuffer is still a useful tool for users though, and it fills the role that HeapBuffer was intended to serve for them better than HeapBuffer itself does, because it is simpler and more type-safe. Swift SVN r22573
175 lines
6.1 KiB
Swift
175 lines
6.1 KiB
Swift
//===--- ManagedBuffer.swift - variable-sized buffer of aligned memory ---===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
import SwiftShims
|
|
|
|
/// A base class of `ManagedBuffer<Value,Element>`, used during
|
|
/// instance creation.
|
|
///
|
|
/// During instance creation, in particular during
|
|
/// `ManagedBuffer.create`\ 's call to initialize, `ManagedBuffer`\ 's
|
|
/// `value` property is as-yet uninitialized, and therefore
|
|
///
|
|
/// `ManagedProtoBuffer` does not offer
|
|
/// access to the as-yet uninitialized `value` property of
|
|
/// `ManagedBuffer`,
|
|
public class ManagedProtoBuffer<Value, Element> {
|
|
/// 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 "value" area when
|
|
/// an instance is created.
|
|
public final var allocatedElementCount : Int {
|
|
return (
|
|
_allocatedByteCount &- ManagedProtoBuffer._elementOffset &+ sizeof(Element) &- 1
|
|
) &/ sizeof(Element)
|
|
}
|
|
|
|
/// Call `body` with an `UnsafeMutablePointer` to the stored `Value`
|
|
public final func withUnsafeMutablePointerToValue<R>(
|
|
body: (UnsafeMutablePointer<Value>)->R
|
|
) -> R {
|
|
return withUnsafeMutablePointers { (v, e) in return body(v) }
|
|
}
|
|
|
|
/// Call body with an `UnsafeMutablePointer` to the `Element` storage
|
|
public final func withUnsafeMutablePointerToElements<R>(
|
|
body: (UnsafeMutablePointer<Element>)->R
|
|
) -> R {
|
|
return withUnsafeMutablePointers { return body($0.1) }
|
|
}
|
|
|
|
/// Call body with `UnsafeMutablePointer`\ s to the stored `Value`
|
|
/// and raw `Element` storage
|
|
public final func withUnsafeMutablePointers<R>(
|
|
body: (_: UnsafeMutablePointer<Value>, _: UnsafeMutablePointer<Element>)->R
|
|
) -> R {
|
|
let result = body(
|
|
UnsafeMutablePointer(_address + ManagedProtoBuffer._valueOffset),
|
|
UnsafeMutablePointer(_address + ManagedProtoBuffer._elementOffset)
|
|
)
|
|
_fixLifetime(self)
|
|
return result
|
|
}
|
|
|
|
//===--- internal/private API -------------------------------------------===//
|
|
|
|
/// Make ordinary initialization unavailable
|
|
internal init(_doNotCallMe: ()) {
|
|
_sanityCheckFailure("Only initialize these by calling create")
|
|
}
|
|
|
|
/// The required alignment for allocations of this type, minus 1
|
|
internal final class var _alignmentMask : Int {
|
|
return max(
|
|
alignof(_HeapObject.self),
|
|
max(alignof(Value.self), alignof(Element.self))) &- 1
|
|
}
|
|
|
|
/// The actual number of bytes allocated for this object.
|
|
internal final var _allocatedByteCount : Int {
|
|
return Int(bitPattern: malloc_size(unsafeAddressOf(self)))
|
|
}
|
|
|
|
/// The address of this instance in a convenient pointer-to-bytes form
|
|
internal final var _address : UnsafePointer<UInt8> {
|
|
return UnsafePointer(unsafeAddressOf(self))
|
|
}
|
|
|
|
/// Offset from the allocated storage for `self` to the stored `Value`
|
|
internal final class var _valueOffset : Int {
|
|
return _roundUpToAlignment(sizeof(_HeapObject.self), alignof(Value.self))
|
|
}
|
|
|
|
/// Offset from the allocated storage for `self` to the `Element` storage
|
|
internal final class var _elementOffset : Int {
|
|
return _roundUpToAlignment(
|
|
_valueOffset + sizeof(Value.self), alignof(Element.self))
|
|
}
|
|
|
|
/// A hack that gives the deallocator information about our
|
|
/// allocated size. Probably completely unused per
|
|
/// <rdar://problem/18156440>
|
|
internal final func __getInstanceSizeAndAlignMask() -> (Int,Int) {
|
|
return (_allocatedByteCount, ManagedProtoBuffer._alignmentMask)
|
|
}
|
|
}
|
|
|
|
/// A class whose instances contain a property of type `Value` 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 `Value` 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 `Value`.
|
|
public class ManagedBuffer<Value, Element>
|
|
: ManagedProtoBuffer<Value, Element> {
|
|
|
|
/// Create a new instance of the most-derived class, calling
|
|
/// `initialize` on the partially-constructed object to generate an
|
|
/// initial `Value`.
|
|
///
|
|
/// Note, in particular, accessing `value` inside the `initialize`
|
|
/// function is undefined.
|
|
public final class func create(
|
|
minimumCapacity: Int, initialize: (ManagedProtoBuffer<Value,Element>)->Value
|
|
) -> ManagedBuffer {
|
|
_precondition(
|
|
minimumCapacity >= 0,
|
|
"ManagedBuffer must have non-negative capacity")
|
|
|
|
let totalSize = ManagedBuffer._elementOffset
|
|
+ minimumCapacity * strideof(Element.self)
|
|
|
|
let alignMask = ManagedBuffer._alignmentMask
|
|
|
|
let result: ManagedBuffer = unsafeDowncast(
|
|
_swift_bufferAllocate(self, totalSize, alignMask)
|
|
)
|
|
|
|
result.withUnsafeMutablePointerToValue {
|
|
$0.initialize(initialize(result))
|
|
}
|
|
return result
|
|
}
|
|
|
|
/// Destroy the stored Value
|
|
deinit {
|
|
// FIXME: doing the work in a helper is a workaround for
|
|
// <rdar://problem/18158010>
|
|
_deinit()
|
|
}
|
|
|
|
// FIXME: separating this from the real deinit is a workaround for
|
|
// <rdar://problem/18158010>
|
|
/// The guts of deinit(); do not call
|
|
internal final func _deinit() {
|
|
withUnsafeMutablePointerToValue { $0.destroy() }
|
|
}
|
|
|
|
/// The stored `Value` instance.
|
|
///
|
|
/// Note: this value must not be accessed during instance creation.
|
|
public final var value: Value {
|
|
address {
|
|
return withUnsafeMutablePointerToValue { UnsafePointer($0) }
|
|
}
|
|
mutableAddress {
|
|
return withUnsafeMutablePointerToValue { $0 }
|
|
}
|
|
}
|
|
}
|