//===----------------------------------------------------------------------===// // // 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 @availability(*, unavailable, message="Please use ManagedBuffer instead.") public class HeapBufferStorage {} @availability(*, unavailable, message="Please use class ManagedBuffer instead.") public struct HeapBuffer {} /// 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 /// 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. internal class _HeapBufferStorage : NonObjectiveCBase { /// The type used to actually manage instances of /// `_HeapBufferStorage` typealias Buffer = _HeapBuffer deinit { Buffer(self)._value.destroy() } final func __getInstanceSizeAndAlignMask() -> (Int,Int) { return Buffer(self)._allocatedSizeAndAlignMask() } } // Return true if x is the only (strong) reference to the given RawBuffer // // This is an inout function for two reasons: // // 1. You should only call it when about to mutate the object. // Doing so otherwise implies a race condition if the buffer is // shared across threads. // // 2. When it is not an inout function, self is passed by // value... thus bumping the reference count and disturbing the // result we are trying to observe, Dr. Heisenberg! // // NOTE: this is not as safe as it could be; class types that come // from Cocoa don't have a reference count stored inline where we're // checking for it. However, we have no way to restrict T to being a // native Swift class, and in fact we have no reasonable way of // getting a class pointer out of some other types, such as an enum // whose first case is a native Swift object and is statically known // to be in that case, without affecting its reference count. Instead // we accept everything; unsafeBitCast will at least catch // inappropriately-sized things at runtime. internal func _isUniquelyReferenced_native( inout x: Builtin.NativeObject? ) -> Bool { let p: UnsafePointer<_HeapObject> = Builtin.reinterpretCast(x) let result = _swift_isUniquelyReferenced_native(p) != 0 Builtin.fixLifetime(x) return result } /// Management API for `_HeapBufferStorage` internal struct _HeapBuffer : Equatable { /// A default type to use as a backing store typealias Storage = _HeapBufferStorage let _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 { return UnsafeMutablePointer( Builtin.bridgeToRawPointer(self._nativeObject)) } var _value: UnsafeMutablePointer { return UnsafeMutablePointer( _HeapBuffer._valueOffset() + _address) } var baseAddress: UnsafeMutablePointer { return UnsafeMutablePointer(_HeapBuffer._elementOffset() + _address) } func _allocatedSize() -> Int { return Int(bitPattern: malloc_size(UnsafeMutablePointer(_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) { self._storage = Builtin.castToNativeObject(storage) } init(_ storage: AnyObject) { _sanityCheck( _usesNativeSwiftReferenceCounting(storage.dynamicType), "HeapBuffer manages only native objects" ) self._storage = Builtin.castToNativeObject(storage) } init(_ 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 { address { return UnsafePointer(_value) } nonmutating mutableAddress { return _value } } /// True if storage is non-\ `nil` var hasStorage: Bool { return _storage != nil } subscript(i: Int) -> Element { address { return UnsafePointer(baseAddress + i) } nonmutating mutableAddress { return baseAddress + i } } var _nativeObject: Builtin.NativeObject { return _storage! } static func fromNativeObject(x: Builtin.NativeObject) -> _HeapBuffer { return _HeapBuffer(nativeStorage: x) } mutating func isUniquelyReferenced() -> Bool { let o: UnsafePointer = Builtin.reinterpretCast(_storage) let result = _swift_isUniquelyReferenced_native(o) Builtin.fixLifetime(_storage) return result != 0 } } // HeapBuffers are equal when they reference the same buffer func == ( lhs: _HeapBuffer, rhs: _HeapBuffer) -> Bool { return lhs._nativeObject == rhs._nativeObject } @availability(*, unavailable, message="Please use ManagedBuffer instead") public struct OnHeap {}