Files
swift-mirror/stdlib/public/core/HeapBuffer.swift
Andrew Trick 5bc23acf75 Add wrappers around Builtin.isUnique.
Currently they do nothing but allow stdlib code to use regular (Bool)
types.  However, soon the wrappers for the _native variants will
provide point-of-use sanity checking.

These need to be fully generic to support class protocols and
single-payload enums (not just for optional). It also avoids a massive
amount of overloading for all the reference type variations
(AnyObject, Native, Unknown, Bridge) x 2 for optional versions of
each.

Because the wrapper is generic, type checking had to be deferred until
IRGen. Generating code for the wrapper itself will result in an
IRGen-time type error. They need to be transparent anyway for proper
diagnostics, but also must be internal.

Note that the similar external API type checks ok because it
forces conformance to AnyObject.

The sanity checks are disabled because our current facilities for
unsafe type casting are incomplete and unsound. SILCombine can
remove UnsafeMutablePointer and RawPointer casts by assuming layout
compatibility. IRGen will later discover layout incompatibility and
generate a trap.

I'll send out a proposal for improving the casting situation so we can
get the sanity checks back.

Swift SVN r28057
2015-05-01 23:45:44 +00:00

209 lines
6.2 KiB
Swift

//===----------------------------------------------------------------------===//
//
// 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
typealias _HeapObject = SwiftShims.HeapObject
@asmname("swift_bufferAllocate")
func _swift_bufferAllocate(
bufferType: AnyClass, _ size: Int, _ alignMask: 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> : NonObjectiveCBase {
public override init() {}
/// The type used to actually manage instances of
/// `_HeapBufferStorage<Value,Element>`
typealias Buffer = _HeapBuffer<Value, Element>
deinit {
Buffer(self)._value.destroy()
}
final func __getInstanceSizeAndAlignMask() -> (Int,Int) {
return Buffer(self)._allocatedSizeAndAlignMask()
}
}
/// Management API for `_HeapBufferStorage<Value, Element>`
internal 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.
var _storage: Builtin.NativeObject?
var storage: AnyObject? {
return _storage.map { Builtin.castFromNativeObject($0) }
}
static func _valueOffset() -> Int {
return _roundUpToAlignment(sizeof(_HeapObject.self), alignof(Value.self))
}
static func _elementOffset() -> Int {
return _roundUpToAlignment(_valueOffset() + sizeof(Value.self),
alignof(Element.self))
}
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))
}
var _address: UnsafeMutablePointer<Int8> {
return UnsafeMutablePointer(
Builtin.bridgeToRawPointer(self._nativeObject))
}
var _value: UnsafeMutablePointer<Value> {
return UnsafeMutablePointer(
_HeapBuffer._valueOffset() + _address)
}
var baseAddress: UnsafeMutablePointer<Element> {
return UnsafeMutablePointer(_HeapBuffer._elementOffset() + _address)
}
func _allocatedSize() -> Int {
return swift_malloc_size(_address)
}
func _allocatedAlignMask() -> Int {
return _HeapBuffer._requiredAlignMask()
}
func _allocatedSizeAndAlignMask() -> (Int, Int) {
return (_allocatedSize(), _allocatedAlignMask())
}
/// Return the actual number of `Elements` we can possibly store.
func _capacity() -> Int {
return (_allocatedSize() - _HeapBuffer._elementOffset())
/ strideof(Element.self)
}
init() {
self._storage = .None
}
init(_ storage: _HeapBufferStorage<Value,Element>) {
self._storage = Builtin.castToNativeObject(storage)
}
init(_ storage: AnyObject) {
_sanityCheck(
_usesNativeSwiftReferenceCounting(storage.dynamicType),
"HeapBuffer manages only native objects"
)
self._storage = Builtin.castToNativeObject(storage)
}
init<T : AnyObject>(_ storage: T?) {
self = storage.map { _HeapBuffer($0) } ?? _HeapBuffer()
}
init(nativeStorage: Builtin.NativeObject?) {
self._storage = nativeStorage
}
/// Create a `_HeapBuffer` with `self.value = initializer` and
/// `self._capacity() >= capacity`.
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(
storageClass, totalSize, alignMask)
self._storage = Builtin.castToNativeObject(object)
self._value.initialize(initializer)
}
var value : Value {
unsafeAddress {
return UnsafePointer(_value)
}
nonmutating unsafeMutableAddress {
return _value
}
}
/// True if storage is non-`nil`
var hasStorage: Bool {
return _storage != nil
}
subscript(i: Int) -> Element {
unsafeAddress {
return UnsafePointer(baseAddress + i)
}
nonmutating unsafeMutableAddress {
return baseAddress + i
}
}
var _nativeObject: Builtin.NativeObject {
return _storage!
}
static func fromNativeObject(x: Builtin.NativeObject) -> _HeapBuffer {
return _HeapBuffer(nativeStorage: x)
}
mutating func isUniquelyReferenced() -> Bool {
return _isUnique(&_storage)
}
mutating func isUniquelyReferencedOrPinned() -> Bool {
return _isUniqueOrPinned(&_storage)
}
}
// HeapBuffers are equal when they reference the same buffer
func == <Value, Element> (
lhs: _HeapBuffer<Value, Element>,
rhs: _HeapBuffer<Value, Element>) -> Bool {
return lhs._nativeObject == rhs._nativeObject
}