Files
swift-mirror/stdlib/public/core/HeapBuffer.swift
Andrew Trick 0b75ee975e Remove "illegal" UnsafePointer casts from the stdlib.
Update for SE-0107: UnsafeRawPointer

This adds a "mutating" initialize to UnsafePointer to make
Immutable -> Mutable conversions explicit.

These are quick fixes to stdlib, overlays, and test cases that are necessary
in order to remove arbitrary UnsafePointer conversions.

Many cases can be expressed better up by reworking the surrounding
code, but we first need a working starting point.
2016-07-28 20:42:23 -07:00

229 lines
6.6 KiB
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 http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
import SwiftShims
typealias _HeapObject = SwiftShims.HeapObject
@_silgen_name("swift_bufferAllocate")
internal func _swift_bufferAllocate(
bufferType type: AnyClass,
size: Int,
alignmentMask: Int
) -> AnyObject
/// A class containing an ivar "value" of type Value, and
/// containing storage for an array of Element whose size is
/// determined at create time.
///
/// The analogous C++-ish class template would be:
///
/// template <class Value, class Element>
/// struct _HeapBuffer {
/// Value value;
/// Element baseAddress[]; // length determined at creation time
///
/// _HeapBuffer() = delete
/// static shared_ptr<_HeapBuffer> create(Value init, int capacity);
/// }
///
/// Note that the Element array is RAW MEMORY. You are expected to
/// construct and---if necessary---destroy Elements there yourself,
/// either in a derived class, or it can be in some manager object
/// that owns the _HeapBuffer.
public // @testable (test/Prototypes/MutableIndexableDict.swift)
class _HeapBufferStorage<Value, Element> {
public init() {}
/// The type used to actually manage instances of
/// `_HeapBufferStorage<Value, Element>`.
typealias Buffer = _HeapBuffer<Value, Element>
deinit {
Buffer(self)._value.deinitialize()
}
final func __getInstanceSizeAndAlignMask() -> (Int, Int) {
return Buffer(self)._allocatedSizeAndAlignMask()
}
}
/// Management API for `_HeapBufferStorage<Value, Element>`
public // @testable
struct _HeapBuffer<Value, Element> : Equatable {
/// A default type to use as a backing store.
typealias Storage = _HeapBufferStorage<Value, Element>
// _storage is passed inout to _isUnique. Although its value
// is unchanged, it must appear mutable to the optimizer.
internal var _storage: Builtin.NativeObject?
public // @testable
var storage: AnyObject? {
return _storage.map { Builtin.castFromNativeObject($0) }
}
internal static func _valueOffset() -> Int {
return _roundUp(
sizeof(_HeapObject.self),
toAlignment: alignof(Value.self))
}
internal static func _elementOffset() -> Int {
return _roundUp(
_valueOffset() + sizeof(Value.self),
toAlignment: alignof(Element.self))
}
internal static func _requiredAlignMask() -> Int {
// We can't use max here because it can allocate an array.
let heapAlign = alignof(_HeapObject.self) &- 1
let valueAlign = alignof(Value.self) &- 1
let elementAlign = alignof(Element.self) &- 1
return (heapAlign < valueAlign
? (valueAlign < elementAlign ? elementAlign : valueAlign)
: (heapAlign < elementAlign ? elementAlign : heapAlign))
}
internal var _address: UnsafeMutableRawPointer {
return UnsafeMutableRawPointer(
Builtin.bridgeToRawPointer(self._nativeObject))
}
internal var _value: UnsafeMutablePointer<Value> {
return (_HeapBuffer._valueOffset() + _address).assumingMemoryBound(
to: Value.self)
}
public // @testable
var baseAddress: UnsafeMutablePointer<Element> {
return (_HeapBuffer._elementOffset() + _address).assumingMemoryBound(
to: Element.self)
}
internal func _allocatedSize() -> Int {
return _swift_stdlib_malloc_size(_address)
}
internal func _allocatedAlignMask() -> Int {
return _HeapBuffer._requiredAlignMask()
}
internal func _allocatedSizeAndAlignMask() -> (Int, Int) {
return (_allocatedSize(), _allocatedAlignMask())
}
/// Returns the actual number of `Elements` we can possibly store.
internal func _capacity() -> Int {
return (_allocatedSize() - _HeapBuffer._elementOffset())
/ strideof(Element.self)
}
internal init() {
self._storage = nil
}
public // @testable
init(_ storage: _HeapBufferStorage<Value, Element>) {
self._storage = Builtin.castToNativeObject(storage)
}
internal init(_ storage: AnyObject) {
_sanityCheck(
_usesNativeSwiftReferenceCounting(storage.dynamicType),
"HeapBuffer manages only native objects"
)
self._storage = Builtin.castToNativeObject(storage)
}
internal init<T : AnyObject>(_ storage: T?) {
self = storage.map { _HeapBuffer($0) } ?? _HeapBuffer()
}
internal init(nativeStorage: Builtin.NativeObject?) {
self._storage = nativeStorage
}
/// Create a `_HeapBuffer` with `self.value = initializer` and
/// `self._capacity() >= capacity`.
public // @testable
init(
_ storageClass: AnyClass,
_ initializer: Value, _ capacity: Int
) {
_sanityCheck(capacity >= 0, "creating a _HeapBuffer with negative capacity")
_sanityCheck(
_usesNativeSwiftReferenceCounting(storageClass),
"HeapBuffer can only create native objects"
)
let totalSize = _HeapBuffer._elementOffset() +
capacity * strideof(Element.self)
let alignMask = _HeapBuffer._requiredAlignMask()
let object: AnyObject = _swift_bufferAllocate(
bufferType: storageClass,
size: totalSize,
alignmentMask: alignMask)
self._storage = Builtin.castToNativeObject(object)
self._value.initialize(to: initializer)
}
public // @testable
var value: Value {
unsafeAddress {
return UnsafePointer(_value)
}
nonmutating unsafeMutableAddress {
return _value
}
}
/// `true` if storage is non-`nil`.
internal var hasStorage: Bool {
return _storage != nil
}
internal subscript(i: Int) -> Element {
unsafeAddress {
return UnsafePointer(baseAddress + i)
}
nonmutating unsafeMutableAddress {
return baseAddress + i
}
}
internal var _nativeObject: Builtin.NativeObject {
return _storage!
}
internal static func fromNativeObject(_ x: Builtin.NativeObject) -> _HeapBuffer {
return _HeapBuffer(nativeStorage: x)
}
public // @testable
mutating func isUniquelyReferenced() -> Bool {
return _isUnique(&_storage)
}
public // @testable
mutating func isUniquelyReferencedOrPinned() -> Bool {
return _isUniqueOrPinned(&_storage)
}
}
// HeapBuffers are equal when they reference the same buffer
public // @testable
func == <Value, Element>(
lhs: _HeapBuffer<Value, Element>,
rhs: _HeapBuffer<Value, Element>) -> Bool {
return lhs._nativeObject == rhs._nativeObject
}