Skip to content

[stdlib] Underscore usable-from-inline types #19686

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
287 changes: 143 additions & 144 deletions stdlib/public/core/Array.swift
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,144 @@ public struct Array<Element>: _DestructorSafeContainer {
internal init(_buffer: _Buffer) {
self._buffer = _buffer
}
}

//===--- private helpers---------------------------------------------------===//
extension Array {
/// Returns `true` if the array is native and does not need a deferred
/// type check. May be hoisted by the optimizer, which means its
/// results may be stale by the time they are used if there is an
/// inout violation in user code.
@inlinable
@_semantics("array.props.isNativeTypeChecked")
public // @testable
func _hoistableIsNativeTypeChecked() -> Bool {
return _buffer.arrayPropertyIsNativeTypeChecked
}

@inlinable
@_semantics("array.get_count")
internal func _getCount() -> Int {
return _buffer.count
}

@inlinable
@_semantics("array.get_capacity")
internal func _getCapacity() -> Int {
return _buffer.capacity
}

@inlinable
@_semantics("array.make_mutable")
internal mutating func _makeMutableAndUnique() {
if _slowPath(!_buffer.isMutableAndUniquelyReferenced()) {
_buffer = _Buffer(copying: _buffer)
}
}

/// Check that the given `index` is valid for subscripting, i.e.
/// `0 ≤ index < count`.
@inlinable
@inline(__always)
internal func _checkSubscript_native(_ index: Int) {
_ = _checkSubscript(index, wasNativeTypeChecked: true)
}

/// Check that the given `index` is valid for subscripting, i.e.
/// `0 ≤ index < count`.
@inlinable
@_semantics("array.check_subscript")
public // @testable
func _checkSubscript(
_ index: Int, wasNativeTypeChecked: Bool
) -> _DependenceToken {
#if _runtime(_ObjC)
_buffer._checkInoutAndNativeTypeCheckedBounds(
index, wasNativeTypeChecked: wasNativeTypeChecked)
#else
_buffer._checkValidSubscript(index)
#endif
return _DependenceToken()
}

/// Check that the specified `index` is valid, i.e. `0 ≤ index ≤ count`.
@inlinable
@_semantics("array.check_index")
internal func _checkIndex(_ index: Int) {
_precondition(index <= endIndex, "Array index is out of range")
_precondition(index >= startIndex, "Negative Array index is out of range")
}

@_semantics("array.get_element")
@inline(__always)
public // @testable
func _getElement(
_ index: Int,
wasNativeTypeChecked: Bool,
matchingSubscriptCheck: _DependenceToken
) -> Element {
#if _runtime(_ObjC)
return _buffer.getElement(index, wasNativeTypeChecked: wasNativeTypeChecked)
#else
return _buffer.getElement(index)
#endif
}

@inlinable
@_semantics("array.get_element_address")
internal func _getElementAddress(_ index: Int) -> UnsafeMutablePointer<Element> {
return _buffer.subscriptBaseAddress + index
}
}

extension Array: _ArrayProtocol {
/// The total number of elements that the array can contain without
/// allocating new storage.
///
/// Every array reserves a specific amount of memory to hold its contents.
/// When you add elements to an array and that array begins to exceed its
/// reserved capacity, the array allocates a larger region of memory and
/// copies its elements into the new storage. The new storage is a multiple
/// of the old storage's size. This exponential growth strategy means that
/// appending an element happens in constant time, averaging the performance
/// of many append operations. Append operations that trigger reallocation
/// have a performance cost, but they occur less and less often as the array
/// grows larger.
///
/// The following example creates an array of integers from an array literal,
/// then appends the elements of another collection. Before appending, the
/// array allocates new storage that is large enough store the resulting
/// elements.
///
/// var numbers = [10, 20, 30, 40, 50]
/// // numbers.count == 5
/// // numbers.capacity == 5
///
/// numbers.append(contentsOf: stride(from: 60, through: 100, by: 10))
/// // numbers.count == 10
/// // numbers.capacity == 12
@inlinable
public var capacity: Int {
return _getCapacity()
}

/// An object that guarantees the lifetime of this array's elements.
@inlinable
public // @testable
var _owner: AnyObject? {
@inline(__always)
get {
return _buffer.owner
}
}

/// If the elements are stored contiguously, a pointer to the first
/// element. Otherwise, `nil`.
@inlinable
public var _baseAddressIfContiguous: UnsafeMutablePointer<Element>? {
@inline(__always) // FIXME(TODO: JIRA): Hack around test failure
get { return _buffer.firstElementAddressIfContiguous }
}
}

extension Array: RandomAccessCollection, MutableCollection {
Expand Down Expand Up @@ -620,93 +757,11 @@ extension Array: RandomAccessCollection, MutableCollection {
}
}
}
}

//===--- private helpers---------------------------------------------------===//
extension Array {
/// Returns `true` if the array is native and does not need a deferred
/// type check. May be hoisted by the optimizer, which means its
/// results may be stale by the time they are used if there is an
/// inout violation in user code.
@inlinable
@_semantics("array.props.isNativeTypeChecked")
public // @testable
func _hoistableIsNativeTypeChecked() -> Bool {
return _buffer.arrayPropertyIsNativeTypeChecked
}

@inlinable
@_semantics("array.get_count")
internal func _getCount() -> Int {
return _buffer.count
}

@inlinable
@_semantics("array.get_capacity")
internal func _getCapacity() -> Int {
return _buffer.capacity
}

@inlinable
@_semantics("array.make_mutable")
internal mutating func _makeMutableAndUnique() {
if _slowPath(!_buffer.isMutableAndUniquelyReferenced()) {
_buffer = _Buffer(copying: _buffer)
}
}

/// Check that the given `index` is valid for subscripting, i.e.
/// `0 ≤ index < count`.
@inlinable
@inline(__always)
internal func _checkSubscript_native(_ index: Int) {
_ = _checkSubscript(index, wasNativeTypeChecked: true)
}

/// Check that the given `index` is valid for subscripting, i.e.
/// `0 ≤ index < count`.
@inlinable
@_semantics("array.check_subscript")
public // @testable
func _checkSubscript(
_ index: Int, wasNativeTypeChecked: Bool
) -> _DependenceToken {
#if _runtime(_ObjC)
_buffer._checkInoutAndNativeTypeCheckedBounds(
index, wasNativeTypeChecked: wasNativeTypeChecked)
#else
_buffer._checkValidSubscript(index)
#endif
return _DependenceToken()
}

/// Check that the specified `index` is valid, i.e. `0 ≤ index ≤ count`.
@inlinable
@_semantics("array.check_index")
internal func _checkIndex(_ index: Int) {
_precondition(index <= endIndex, "Array index is out of range")
_precondition(index >= startIndex, "Negative Array index is out of range")
}

@_semantics("array.get_element")
@inline(__always)
public // @testable
func _getElement(
_ index: Int,
wasNativeTypeChecked: Bool,
matchingSubscriptCheck: _DependenceToken
) -> Element {
#if _runtime(_ObjC)
return _buffer.getElement(index, wasNativeTypeChecked: wasNativeTypeChecked)
#else
return _buffer.getElement(index)
#endif
}


/// The number of elements in the array.
@inlinable
@_semantics("array.get_element_address")
internal func _getElementAddress(_ index: Int) -> UnsafeMutablePointer<Element> {
return _buffer.subscriptBaseAddress + index
public var count: Int {
return _getCount()
}
}

Expand All @@ -731,7 +786,7 @@ extension Array: ExpressibleByArrayLiteral {
}
}

extension Array: RangeReplaceableCollection, ArrayProtocol {
extension Array: RangeReplaceableCollection {
/// Creates a new, empty array.
///
/// This is equivalent to initializing with an empty array literal.
Expand Down Expand Up @@ -785,9 +840,7 @@ extension Array: RangeReplaceableCollection, ArrayProtocol {
///
/// - Parameter s: The sequence of elements to turn into an array.
@inlinable
public init<S: Sequence>(_ s: S)
where S.Element == Element {

public init<S: Sequence>(_ s: S) where S.Element == Element {
self = Array(
_buffer: _Buffer(
_buffer: s._copyToContiguousArray()._buffer,
Expand Down Expand Up @@ -889,60 +942,6 @@ extension Array: RangeReplaceableCollection, ArrayProtocol {
_buffer.count = 0
}

/// The number of elements in the array.
@inlinable
public var count: Int {
return _getCount()
}

/// The total number of elements that the array can contain without
/// allocating new storage.
///
/// Every array reserves a specific amount of memory to hold its contents.
/// When you add elements to an array and that array begins to exceed its
/// reserved capacity, the array allocates a larger region of memory and
/// copies its elements into the new storage. The new storage is a multiple
/// of the old storage's size. This exponential growth strategy means that
/// appending an element happens in constant time, averaging the performance
/// of many append operations. Append operations that trigger reallocation
/// have a performance cost, but they occur less and less often as the array
/// grows larger.
///
/// The following example creates an array of integers from an array literal,
/// then appends the elements of another collection. Before appending, the
/// array allocates new storage that is large enough store the resulting
/// elements.
///
/// var numbers = [10, 20, 30, 40, 50]
/// // numbers.count == 5
/// // numbers.capacity == 5
///
/// numbers.append(contentsOf: stride(from: 60, through: 100, by: 10))
/// // numbers.count == 10
/// // numbers.capacity == 12
@inlinable
public var capacity: Int {
return _getCapacity()
}

/// An object that guarantees the lifetime of this array's elements.
@inlinable
public // @testable
var _owner: AnyObject? {
@inline(__always)
get {
return _buffer.owner
}
}

/// If the elements are stored contiguously, a pointer to the first
/// element. Otherwise, `nil`.
@inlinable
public var _baseAddressIfContiguous: UnsafeMutablePointer<Element>? {
@inline(__always) // FIXME(TODO: JIRA): Hack around test failure
get { return _buffer.firstElementAddressIfContiguous }
}

//===--- basic mutations ------------------------------------------------===//


Expand Down
11 changes: 2 additions & 9 deletions stdlib/public/core/ArrayBufferProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@
/// `_ArrayBufferProtocol`. This buffer does not provide value semantics.
@usableFromInline
internal protocol _ArrayBufferProtocol
: MutableCollection, RandomAccessCollection {

associatedtype Indices = Range<Int>
: MutableCollection, RandomAccessCollection
where Indices == Range<Int> {

/// Create an empty buffer.
init()
Expand All @@ -35,9 +34,6 @@ internal protocol _ArrayBufferProtocol
initializing target: UnsafeMutablePointer<Element>
) -> UnsafeMutablePointer<Element>

/// Get or set the index'th element.
subscript(index: Int) -> Element { get nonmutating set }

/// If this buffer is backed by a uniquely-referenced mutable
/// `_ContiguousArrayBuffer` that can be grown in-place to allow the `self`
/// buffer store `minimumCapacity` elements, returns that buffer.
Expand Down Expand Up @@ -121,9 +117,6 @@ internal protocol _ArrayBufferProtocol
/// buffers address the same elements when they have the same
/// identity and count.
var identity: UnsafeRawPointer { get }

var startIndex: Int { get }
var endIndex: Int { get }
}

extension _ArrayBufferProtocol where Indices == Range<Int>{
Expand Down
6 changes: 3 additions & 3 deletions stdlib/public/core/ArrayCast.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@ public func _arrayForceCast<SourceElement, TargetElement>(
return source.map { $0 as! TargetElement }
}

@_fixed_layout // FIXME(sil-serialize-all)
@usableFromInline // FIXME(sil-serialize-all)
@_fixed_layout
@usableFromInline
internal struct _UnwrappingFailed : Error {
@inlinable // FIXME(sil-serialize-all)
@inlinable
internal init() {}
}

Expand Down
Loading