Files
swift-mirror/stdlib/core/Arrays.swift.gyb
Andrew Trick f36ff584cf Add array.init semantics.
This way, array optimization can see initialization as a copy of the
whole array value into a local variable, regardless of whether it's
from a factory method or Array initializer.

I'm making an assumption that when we return an Array by value, we
can't have an alias of the array buffer without retaining it.

Swift SVN r20444
2014-07-23 23:25:17 +00:00

1038 lines
30 KiB
Swift

//===--- Arrays.swift.gyb - ContiguousArray, Array, and Slice -*- 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
//
//===----------------------------------------------------------------------===//
//
// Three generic, mutable array-like types with value semantics.
//
// - ContiguousArray<T> is a fast, contiguous array of T with a known
// backing store.
//
// - Slice<T> presents an arbitrary subsequence of some contiguous sequence
// of Ts.
//
// - Array<T> is like ContiguousArray<T> when T is not an ObjC type.
// Otherwise, it may use an NSArray bridged from Cocoa for storage
//
//===----------------------------------------------------------------------===//
% arrayTypes = [
% ('ContiguousArray', 'a ContiguousArray'),
% ('Slice', 'a Slice'),
% ('Array', 'an Array')
% ]
% for (Self, a_Self) in arrayTypes:
public struct ${Self}<T> : MutableCollectionType, Sliceable {
public typealias Element = T
public var startIndex: Int {
return 0
}
public var endIndex: Int {
return _getCount()
}
public subscript(index: Int) -> Element {
get {
_checkSubscript(index)
return _getElement(index)
}
set {
_makeMutableAndUnique()
_checkSubscript(index)
_setElement(index, newValue: newValue)
}
}
public func generate() -> IndexingGenerator<${Self}> {
return IndexingGenerator(self)
}
public typealias SubSlice = Slice<T>
public subscript(subRange: Range<Int>) -> SubSlice {
get {
_checkIndex(subRange.startIndex)
_checkIndex(subRange.endIndex)
return Slice(_buffer[subRange])
}
set(rhs) {
_checkIndex(subRange.startIndex)
_checkIndex(subRange.endIndex)
if self[subRange]._buffer.identity != rhs._buffer.identity {
self.replaceRange(subRange, with: rhs)
}
}
}
//===--- private --------------------------------------------------------===//
@semantics("array.get_count")
func _getCount() -> Int {
return _buffer.count
}
@semantics("array.get_capacity")
func _getCapacity() -> Int {
return _buffer.capacity
}
func _copyBuffer(inout buffer: _Buffer) {
var newBuffer = _ContiguousArrayBuffer<T>(
count: buffer.count, minimumCapacity: buffer.count)
let target = buffer._uninitializedCopy(
0..<count, target: newBuffer.baseAddress)
buffer = _Buffer(newBuffer)
}
@semantics("array.make_mutable")
mutating func _makeMutableAndUnique() {
if _slowPath(!_buffer.isMutableAndUniquelyReferenced()) {
_copyBuffer(&_buffer)
}
}
/// Check that the given `index` is valid for subscripting, i.e. `0
/// index < count`
@semantics("array.check_subscript")
func _checkSubscript(index: Int) {
_precondition(_buffer._isValidSubscript(index), "${Self} index out of range")
}
/// Check that the given `index` is valid, i.e. `0 index count`
@semantics("array.check_index")
func _checkIndex(index: Int) {
_precondition(index <= count, "${Self} index out of range")
_precondition(index >= 0, "Negative ${Self} index is out of range")
}
@semantics("array.get_element")
func _getElement(index: Int) -> Element {
return _buffer[index]
}
@semantics("array.set_element")
mutating func _setElement(
index: Int, newValue: Element
) {
_buffer[index] = newValue
}
public
typealias _Buffer = _${Self}Buffer<T>
/// Initialization from an existing buffer does not have "array.init"
/// semantics because the caller may retain an alias to buffer.
public
init(_ buffer: _Buffer) {
self._buffer = buffer
}
public var _buffer: _Buffer
}
extension ${Self} : ArrayLiteralConvertible {
@semantics("readonly")
public static func convertFromArrayLiteral(elements: Element...) -> ${Self} {
return ${Self}(_extractOrCopyToNativeArrayBuffer(elements._buffer))
}
}
extension ${Self} {
public func _asCocoaArray() -> _CocoaArrayType {
return _buffer._asCocoaArray()
}
}
extension ${Self} : ArrayType {
/// Construct an empty ${Self}
@semantics("array.init")
public init() {
_buffer = _Buffer()
}
public init<
S: SequenceType where S.Generator.Element == _Buffer.Element
>(_ s: S) {
self = ${Self}(_Buffer(s~>_copyToNativeArrayBuffer()))
}
/// Construct an array of `count` elements, each initialized to
/// `repeatedValue`.
@semantics("array.init")
public init(count: Int, repeatedValue: T) {
_precondition(count >= 0, "Can't construct ${Self} with count < 0")
_buffer = _Buffer()
reserveCapacity(count)
var p = _buffer.baseAddress
for _ in 0..<count {
p++.initialize(repeatedValue)
}
_buffer.count = count
}
/// How many elements the ${Self} stores
public var count: Int {
return _getCount()
}
/// How many elements the `${Self}` can store without reallocation
public var capacity: Int {
return _getCapacity()
}
/// `true` if and only if the `${Self}` is empty
public var isEmpty: Bool {
return count == 0
}
/// The first element, or `nil` if the array is empty
public var first: Element? {
return Swift.first(self)
}
/// The last element, or `nil` if the array is empty
public var last: Element? {
return Swift.last(self)
}
/// An object that guarantees the lifetime of this array's elements
public
var _owner: AnyObject? {
return _buffer.owner
}
/// If the elements are stored contiguously, a pointer to the first
/// element. Otherwise, nil.
public var _baseAddressIfContiguous: UnsafeMutablePointer<Element> {
return _buffer.baseAddress
}
%if Self != 'Array': # // Array does not necessarily have contiguous storage
var _baseAddress: UnsafeMutablePointer<Element> {
return _buffer.baseAddress
}
%end
//===--- basic mutations ------------------------------------------------===//
/// Ensure the array has enough mutable contiguous storage to store
/// minimumCapacity elements in. Note: does not affect count.
/// Complexity: O(N)
@semantics("array.mutate_unknown")
public mutating func reserveCapacity(minimumCapacity: Int) {
if !_buffer.requestUniqueMutableBackingBuffer(minimumCapacity) {
var newBuffer = _ContiguousArrayBuffer<T>(
count: count, minimumCapacity: minimumCapacity)
_buffer._uninitializedCopy(0..<count, target: newBuffer.baseAddress)
_buffer = _Buffer(newBuffer)
}
_sanityCheck(capacity >= minimumCapacity)
}
/// Append newElement to the ${Self} in O(1) (amortized)
@semantics("array.mutate_unknown")
public mutating func append(newElement: T) {
_arrayAppend(&_buffer, newElement)
}
/// Append elements from `sequence` to the Array
public mutating func extend<
S : SequenceType
where S.Generator.Element == T
>(sequence: S) {
// Calling a helper free function instead of writing the code inline
// because of:
//
// <rdar://problem/16954386> Type checker assertion: Unable to solve for
// call to witness?
_${Self}Extend(&self, sequence)
}
/// Remove an element from the end of the ${Self} in O(1).
/// Requires: count > 0
public mutating func removeLast() -> T {
_precondition(count > 0, "can't removeLast from an empty ${Self}")
let c = count
let result = self[c - 1]
self.replaceRange((c - 1)..<c, with: EmptyCollection())
return result
}
/// Insert an element at index `i` in O(N). Requires: `i` <=
/// `count`
public mutating func insert(newElement: T, atIndex i: Int) {
_checkIndex(i)
self.replaceRange(i..<i, with: CollectionOfOne(newElement))
}
/// Remove the element at the given index. Worst case complexity:
/// O(N). Requires: `index` < `count`
public mutating func removeAtIndex(index: Int) -> T {
let result = self[index]
self.replaceRange(index..<(index + 1), with: EmptyCollection())
return result
}
/// Erase all the elements. If `keepCapacity` is `true`, `capacity`
/// will not change
public mutating func removeAll(keepCapacity: Bool = false) {
if !keepCapacity {
_buffer = _Buffer()
}
else {
self.replaceRange(indices(self), with: EmptyCollection())
}
}
//===--- algorithms -----------------------------------------------------===//
public func join<
S : SequenceType where S.Generator.Element == ${Self}<T>
>(elements: S) -> ${Self}<T> {
return Swift.join(self, elements)
}
public func reduce<U>(initial: U, combine: (U, T)->U) -> U {
return Swift.reduce(self, initial, combine)
}
public mutating func sort(isOrderedBefore: (T, T)->Bool) {
return withUnsafeMutableBufferPointer {
me in Swift.sort(&me, isOrderedBefore)
return
}
}
public func sorted(isOrderedBefore: (T, T)->Bool) -> ${Self} {
var result = self
result.sort(isOrderedBefore)
return result
}
/// Return ${a_Self} containing the results of calling
/// `transform(x)` on each element `x` of `self`
public func map<U>(transform: (T)->U) -> ${Self}<U> {
return ${Self}<U>(lazy(self).map(transform))
}
/// A ${Self} containing the elements of `self` in reverse order
public func reverse() -> ${Self} {
return ${Self}(lazy(self).reverse())
}
/// Return ${a_Self} containing the elements `x` of `self` for which
/// `includeElement(x)` is `true`
public func filter(includeElement: (T)->Bool) -> ${Self} {
return ${Self}(lazy(self).filter(includeElement))
}
}
func _${Self}Extend<
T, S : SequenceType
where S.Generator.Element == T
>(inout a: ${Self}<T>, sequence: S) {
a += sequence
}
extension ${Self} : Reflectable {
public func getMirror() -> MirrorType {
return _ArrayTypeMirror(self)
}
}
extension ${Self} : Printable, DebugPrintable {
func _makeDescription(#isDebug: Bool) -> String {
var result = "["
var first = true
for item in self {
if first {
first = false
} else {
result += ", "
}
if isDebug {
debugPrint(item, &result)
} else {
print(item, &result)
}
}
result += "]"
return result
}
public var description: String {
return _makeDescription(isDebug: false)
}
public var debugDescription: String {
return _makeDescription(isDebug: true)
}
}
extension ${Self} {
@transparent
func _cPointerArgs() -> (AnyObject?, Builtin.RawPointer) {
let p = _baseAddressIfContiguous
if _fastPath(p != nil || count == 0) {
return (_owner, p.value)
}
let n = _extractOrCopyToNativeArrayBuffer(self._buffer)
return (n.owner, n.baseAddress.value)
}
}
extension ${Self} {
/// Call body(p), where p is a pointer to the ${Self}'s contiguous storage
public func withUnsafeBufferPointer<R>(
body: (UnsafeBufferPointer<T>) -> R
) -> R {
return _buffer.withUnsafeBufferPointer(body)
}
public mutating func withUnsafeMutableBufferPointer<R>(
body: (inout UnsafeMutableBufferPointer<T>)->R
) -> R {
// Ensure unique storage
_arrayReserve(&_buffer, 0)
// Ensure that body can't invalidate the storage or its bounds by
// moving self into a temporary working array.
var work = ${Self}()
swap(&work, &self)
// Create an UnsafeBufferPointer over work that we can pass to body
var a = UnsafeMutableBufferPointer(
start: work._buffer.baseAddress, length: work.count)
// Invoke the body
let ret = body(&a)
// Put the working array back before returning.
swap(&work, &self)
return ret
}
}
%end
extension Array {
/// This function "seeds" the ArrayLiteralConvertible protocol
@semantics("readonly")
public static func convertFromHeapArray(
base: Builtin.RawPointer,
owner: Builtin.NativeObject,
count: Builtin.Word
) -> Array {
let elements = UnsafeBufferPointer(
start: reinterpretCast(base) as UnsafeMutablePointer<T>,
length: reinterpretCast(count) as Int
)
let r = Array(elements)
_fixLifetime(owner)
return r
}
}
struct _InitializeMemoryFromCollection<
C: CollectionType
> : _PointerFunctionType {
func call(rawMemory: UnsafeMutablePointer<C.Generator.Element>) {
var p = rawMemory
for x in newValues {
p++.initialize(x)
}
}
init(_ newValues: C) {
self.newValues = newValues
}
var newValues: C
}
@inline(never)
func _arrayOutOfPlaceReplace<
B: _ArrayBufferType, C: CollectionType
where C.Generator.Element == B.Element, B.Index == Int
>(
inout source: B, subRange: Range<Int>, newValues: C, insertCount: Int
) {
let growth = insertCount - countElements(subRange)
let newCount = source.count + growth
var newBuffer = Optional(
_forceCreateUniqueMutableBuffer(&source, newCount, newCount))
_arrayOutOfPlaceUpdate(
&source, &newBuffer,
subRange.startIndex, insertCount,
_InitializeMemoryFromCollection(newValues)
)
}
func _arrayNonSliceInPlaceReplace<
B: _ArrayBufferType, C: CollectionType
where C.Generator.Element == B.Element, B.Index == Int
>(inout target: B, subRange: Range<Int>, insertCount: Int, newValues: C) {
let oldCount = target.count
let eraseCount = countElements(subRange)
let growth = insertCount - eraseCount
target.count = oldCount + growth
let elements = target.baseAddress
_sanityCheck(elements != nil)
let oldTailIndex = subRange.endIndex
let oldTailStart = elements + oldTailIndex
let newTailIndex = oldTailIndex + growth
let newTailStart = oldTailStart + growth
let tailCount = oldCount - subRange.endIndex
if growth > 0 {
// Slide the tail part of the buffer forwards, in reverse order
// so as not to self-clobber.
newTailStart.moveInitializeBackwardFrom(oldTailStart, count: tailCount)
// Assign over the original subRange
var i = newValues.startIndex
for j in subRange {
elements[j] = newValues[i++]
}
// Initialize the hole left by sliding the tail forward
for j in oldTailIndex..<newTailIndex {
(elements + j).initialize(newValues[i++])
}
}
else { // We're not growing the buffer
// Assign all the new elements into the start of the subRange
var i = subRange.startIndex
for j in indices(newValues) {
elements[i++] = newValues[j]
}
// If the size didn't change, we're done.
if growth == 0 {
return
}
// Move the tail backward to cover the shrinkage.
let shrinkage = -growth
if tailCount > shrinkage { // If the tail length exceeds the shrinkage
// Assign over the rest of the replaced range with the first
// part of the tail.
newTailStart.moveAssignFrom(oldTailStart, count: shrinkage)
// slide the rest of the tail back
oldTailStart.moveInitializeFrom(
oldTailStart + shrinkage, count: tailCount - shrinkage)
}
else { // tail fits within erased elements
// Assign over the start of the replaced range with the tail
newTailStart.moveAssignFrom(oldTailStart, count: tailCount)
// destroy elements remaining after the tail in subRange
(newTailStart + tailCount).destroy(shrinkage - tailCount)
}
}
}
func _arrayReplace<
B: _ArrayBufferType, C: CollectionType
where C.Generator.Element == B.Element, B.Index == Int
>(
inout target: B, subRange: Range<Int>, newValues: C
) {
_precondition(
subRange.startIndex >= 0,
"${Self} replace: subRange start is negative")
_precondition(
subRange.endIndex >= subRange.startIndex,
"${Self} replace: subRange is inside-out")
_precondition(
subRange.endIndex <= target.endIndex,
"${Self} replace: subRange extends past the end")
let oldCount = target.count
let eraseCount = countElements(subRange)
let insertCount = numericCast(countElements(newValues)) as Int
let growth = insertCount - eraseCount
if target.requestUniqueMutableBackingBuffer(oldCount + growth) {
target.replace(subRange: subRange, with: insertCount, elementsOf: newValues)
}
else {
_arrayOutOfPlaceReplace(&target, subRange, newValues, insertCount)
}
}
func _growArrayCapacity(capacity: Int) -> Int {
return capacity * 2
}
% for (Self, a_Self) in arrayTypes:
extension ${Self} {
@semantics("array.mutate_unknown")
public mutating func replaceRange<
C: CollectionType where C.Generator.Element == _Buffer.Element
>(
subRange: Range<Int>, with newValues: C
) {
_arrayReplace(&self._buffer, subRange, newValues)
}
}
public
func += <
T, S: SequenceType
where S.Generator.Element == T
>(inout lhs: ${Self}<T>, rhs: S) {
let oldCount = lhs.count
let capacity = lhs.capacity
let newCount = oldCount + underestimateCount(rhs)
if newCount > capacity {
lhs.reserveCapacity(
max(newCount, _growArrayCapacity(capacity)))
}
_arrayAppendSequence(&lhs._buffer, rhs)
}
public
func += <
T, C: CollectionType
where C.Generator.Element == T
>(inout lhs: ${Self}<T>, rhs: C) {
let rhsCount = numericCast(countElements(rhs)) as Int
let oldCount = lhs.count
let capacity = lhs.capacity
let newCount = oldCount + rhsCount
// Ensure uniqueness, mutability, and sufficient storage. Note that
// for consistency, we need unique lhs even if rhs is empty.
lhs.reserveCapacity(
newCount > capacity ?
max(newCount, _growArrayCapacity(capacity))
: newCount)
var p = lhs._buffer.baseAddress + oldCount
for x in rhs {
(p++).initialize(x)
}
lhs._buffer.count = newCount
}
% end
//===--- generic helpers --------------------------------------------------===//
/// Ensure there's a _ContiguousArrayBuffer capable of storing
/// max(newCount, minimumCapacity) elements, with count set to
/// newCount.
///
/// If source has sufficient capacity, returns nil. Otherwise,
/// returns a new buffer.
///
/// NOTE: does not initialize or destroy any elements. In general,
/// the buffer that satisfies the capacity request now has a count
/// that does not match its number of initialized elements, and that
/// needs to be corrected before the buffer can go back into circulation.
func _createUniqueMutableBuffer<_Buffer: _ArrayBufferType>(
inout source: _Buffer, newCount: Int, minimumCapacity: Int = 0)
-> _ContiguousArrayBuffer<_Buffer.Element>? {
_sanityCheck(newCount >= 0)
let requiredCapacity = max(newCount, minimumCapacity)
if let b = source.requestUniqueMutableBackingBuffer(requiredCapacity) {
source.count = newCount
return nil
}
return _forceCreateUniqueMutableBuffer(&source, newCount, requiredCapacity)
}
func _forceCreateUniqueMutableBuffer<_Buffer: _ArrayBufferType>(
inout source: _Buffer, newCount: Int, requiredCapacity: Int
) -> _ContiguousArrayBuffer<_Buffer.Element> {
_sanityCheck(newCount >= 0)
_sanityCheck(requiredCapacity >= newCount)
let minimumCapacity = max(
requiredCapacity,
newCount > source.capacity
? _growArrayCapacity(source.capacity) : source.capacity)
return _ContiguousArrayBuffer(
count: newCount, minimumCapacity: minimumCapacity)
}
protocol _PointerFunctionType {
typealias Element
func call(UnsafeMutablePointer<Element>)
}
/// initialize the elements of dest by copying the first headCount
/// items from source, calling initializeNewElements on the next
/// uninitialized element, and finally by copying the last N items
/// from source into the N remaining uninitialized elements of dest.
///
/// As an optimization, may move elements out of source rather than
/// copying when it isUniquelyReferenced.
func _arrayOutOfPlaceUpdate<
_Buffer: _ArrayBufferType, Initializer: _PointerFunctionType
where Initializer.Element == _Buffer.Element
>(
inout source: _Buffer,
inout dest: _ContiguousArrayBuffer<_Buffer.Element>?,
headCount: Int, // Count of initial source elements to copy/move
newCount: Int, // Count of new elements to insert
initializeNewElements: Initializer
) {
_sanityCheck(headCount >= 0)
_sanityCheck(newCount >= 0)
// Count of trailing source elements to copy/move
let tailCount = dest!.count - headCount - newCount
_sanityCheck(headCount + tailCount <= source.count)
let sourceCount = source.count
let oldCount = sourceCount - headCount - tailCount
let destStart = dest!.baseAddress
let newStart = destStart + headCount
let newEnd = newStart + newCount
// Check to see if we have storage we can move from
if let backing = source.requestUniqueMutableBackingBuffer(sourceCount) {
let sourceStart = source.baseAddress
let oldStart = sourceStart + headCount
// Destroy any items that may be lurking in a _SliceBuffer before
// its real first element
let backingStart = backing.baseAddress
let sourceOffset = sourceStart - backingStart
backingStart.destroy(sourceOffset)
// Move the head items
destStart.moveInitializeFrom(sourceStart, count: headCount)
// Destroy unused source items
oldStart.destroy(oldCount)
initializeNewElements.call(newStart)
// Move the tail items
newEnd.moveInitializeFrom(oldStart + oldCount, count: tailCount)
// Destroy any items that may be lurking in a _SliceBuffer after
// its real last element
let backingEnd = backingStart + backing.count
let sourceEnd = sourceStart + sourceCount
sourceEnd.destroy(backingEnd - sourceEnd)
backing.count = 0
}
else {
let newStart = source._uninitializedCopy(0..<headCount, target: destStart)
initializeNewElements.call(newStart)
source._uninitializedCopy(headCount + oldCount..<sourceCount,
target: newEnd)
}
source = _Buffer(dest!)
}
struct _InitializePointer<T> : _PointerFunctionType {
func call(rawMemory: UnsafeMutablePointer<T>) {
// FIXME: maybe we should move here instead of copying?
rawMemory.initialize(newValue)
}
@transparent
init(_ newValue: T) {
self.newValue = newValue
}
var newValue: T
}
func _arrayAppend<_Buffer: _ArrayBufferType>(
inout buffer: _Buffer, newValue: _Buffer.Element
) {
let oldCount = buffer.count
var newBuffer = _createUniqueMutableBuffer(&buffer, oldCount + 1)
if _fastPath(!newBuffer) {
(buffer.baseAddress + oldCount).initialize(newValue)
}
else {
_arrayOutOfPlaceUpdate(
&buffer, &newBuffer, oldCount, 1, _InitializePointer(newValue))
}
}
struct _IgnorePointer<T> : _PointerFunctionType {
func call(_:UnsafeMutablePointer<T>) {}
}
func _arrayReserve<_Buffer: _ArrayBufferType>(
inout buffer: _Buffer, minimumCapacity: Int
) {
let oldCount = buffer.count
var newBuffer = _createUniqueMutableBuffer(
&buffer, oldCount, minimumCapacity: minimumCapacity)
if _slowPath(newBuffer) {
_arrayOutOfPlaceUpdate(&buffer, &newBuffer, oldCount, 0, _IgnorePointer())
}
}
public func _extractOrCopyToNativeArrayBuffer<
_Buffer: _ArrayBufferType
where _Buffer.Generator.Element == _Buffer.Element
>(source: _Buffer)
-> _ContiguousArrayBuffer<_Buffer.Element>
{
if let n = source.requestNativeBuffer() {
return n
}
return _copyCollectionToNativeArrayBuffer(source)
}
/// Append items from newItems to buffer
func _arrayAppendSequence<
_Buffer: _ArrayBufferType,
S: SequenceType where S.Generator.Element == _Buffer.Element
>(
inout buffer: _Buffer, newItems: S
) {
var stream = newItems.generate()
var nextItem = stream.next()
if !nextItem {
return
}
// This will force uniqueness
_arrayAppend(&buffer, nextItem!)
var count = buffer.count
nextItem = stream.next()
while nextItem {
let capacity = buffer.capacity
let base = buffer.baseAddress
while nextItem && count < capacity {
(base + count++).initialize(nextItem!)
nextItem = stream.next()
}
buffer.count = count
if nextItem {
_arrayReserve(&buffer, _growArrayCapacity(capacity))
}
}
}
% for (Self, a_Self) in arrayTypes:
// NOTE: The '==' and '!=' below only handles array types
// that are the same, e.g. Array<Int> and Array<Int>, not
// Slice<Int> and Array<Int>.
/// Returns true if these arrays contain the same elements.
public func ==<T: Equatable>(lhs: ${Self}<T>, rhs: ${Self}<T>) -> Bool {
let lhsCount = lhs.count
if lhsCount != rhs.count {
return false
}
// Test referential equality.
if lhsCount == 0 || lhs._buffer.identity == rhs._buffer.identity {
return true
}
var streamLHS = lhs.generate()
var streamRHS = rhs.generate()
var nextLHS = streamLHS.next()
while nextLHS {
let nextRHS = streamRHS.next()
if nextLHS != nextRHS {
return false
}
nextLHS = streamLHS.next()
}
return true
}
/// Returns true if the arrays do not contain the same elements.
public func !=<T: Equatable>(lhs: ${Self}<T>, rhs: ${Self}<T>) -> Bool {
return !(lhs == rhs)
}
%end
/// Returns an Array<Base> containing the same elements as a in
/// O(1). Requires: Base is a base class or base @objc protocol (such
/// as AnyObject) of Derived.
public func _arrayUpCast<Derived, Base>(a: Array<Derived>) -> Array<Base> {
return Array(a._buffer.castToBufferOf(Base.self))
}
extension Array {
/// Try to downcast the source `NSArray` as our native buffer type.
/// If it succeeds, create a new `Array` around it and return that.
/// Return `nil` otherwise.
// Note: this function exists here so that Foundation doesn't have
// to know Array's implementation details.
public static func _bridgeFromObjectiveCAdoptingNativeStorage(
source: AnyObject
) -> Array? {
if let nativeStorage = source as? _ContiguousArrayStorage<T> {
return Array(_ContiguousArrayBuffer(nativeStorage))
}
return nil
}
}
/// Implements the semantics of `x as [Derived]` where `x` has type
/// `[Base]` and `Derived` is a verbatim-bridged trivial subtype of
/// `Base`.
public func _arrayDownCast<Base, Derived>(a: Array<Base>) -> [Derived] {
_sanityCheck(_isBridgedVerbatimToObjectiveC(Base.self))
_sanityCheck(_isBridgedVerbatimToObjectiveC(Derived.self))
let native = a._buffer.requestNativeBuffer()
// Fast path: a native buffer that already stores elements of the
// Derived type.
if _fastPath(native) {
if _fastPath(native!.storesOnlyElementsOfType(Derived.self)) {
return Array(a._buffer.castToBufferOf(Derived.self))
}
}
// FIXME: Make these checks deferred.
let result: [Derived]? = _arrayDownCastConditional(a)
_precondition(result, "array cannot be downcast to array of derived")
return result!
}
/// Implements the semantics of `x as? [Derived]` where `x` has type
/// `[Base]` and `Derived` is a verbatim-bridged trivial subtype of
/// `Base`.
///
/// Returns an Array<Derived> containing the same elements as a in
/// O(1) iff a's buffer elements are dynamically known to have
/// type Derived or a type derived from Derived.
public func _arrayDownCastConditional<Base, Derived>(
a: Array<Base>
) -> [Derived]? {
_sanityCheck(_isBridgedVerbatimToObjectiveC(Base.self))
_sanityCheck(_isBridgedVerbatimToObjectiveC(Derived.self))
if _fastPath(!a.isEmpty) {
let native = a._buffer.requestNativeBuffer()
if _fastPath(native) {
if native!.storesOnlyElementsOfType(Derived.self) {
return Array(a._buffer.castToBufferOf(Derived.self))
}
return nil
}
// slow path: we store an NSArray
// We can skip the check if Derived happens to be AnyObject
if !(AnyObject.self is Derived.Type) {
for element in a {
// FIXME: reinterpretCast works around <rdar://problem/16953026>
if !(reinterpretCast(element) as AnyObject is Derived) {
return nil
}
}
}
return Array(a._buffer.castToBufferOf(Derived.self))
}
return []
}
/// Convert a to its corresponding bridged array type.
/// Precondition: T is bridged non-verbatim to objective C
/// O(N), because each element must be bridged separately.
public func _arrayBridgeToObjectiveC<BridgesToDerived, Base>(
source: Array<BridgesToDerived>
) -> Array<Base> {
_sanityCheck(_isBridgedVerbatimToObjectiveC(Base.self))
_sanityCheck(!_isBridgedVerbatimToObjectiveC(BridgesToDerived.self))
var buf = _ContiguousArrayBuffer<Base>(count: source.count, minimumCapacity: 0)
var p = buf._unsafeElementStorage
for value in source {
let bridged: AnyObject? = _bridgeToObjectiveC(value)
_precondition(bridged, "array element cannot be bridged to Objective-C")
p++.initialize(reinterpretCast(bridged!))
}
return Array(_ArrayBuffer(buf))
}
/// Try to convert the source array of objects to an array of values
/// produced by bridging the objects from Objective-C to \c
/// BridgesToDerived.
///
/// Precondition: Base is a class type.
/// Precondition: BridgesToDerived is bridged non-verbatim to Objective-C.
/// O(n), because each element must be bridged separately.
public func _arrayBridgeFromObjectiveC<Base, BridgesToDerived>(
source: Array<Base>
) -> Array<BridgesToDerived> {
let result: Array<BridgesToDerived>?
= _arrayBridgeFromObjectiveCConditional(source);
_precondition(result, "array cannot be bridged from Objective-C")
return result!
}
/// Try to convert the source array of objects to an array of values
/// produced by bridging the objects from Objective-C to \c
/// BridgesToDerived.
///
/// Precondition: Base is a class type.
/// Precondition: BridgesToDerived is bridged non-verbatim to Objective-C.
/// O(n), because each element must be bridged separately.
public func _arrayBridgeFromObjectiveCConditional<Base, BridgesToDerived>(
source: Array<Base>
) -> Array<BridgesToDerived>? {
_sanityCheck(_isBridgedVerbatimToObjectiveC(Base.self))
_sanityCheck(!_isBridgedVerbatimToObjectiveC(BridgesToDerived.self))
var buf = _ContiguousArrayBuffer<BridgesToDerived>(count: source.count,
minimumCapacity: 0)
var p = buf._unsafeElementStorage
ElementwiseBridging:
do {
for object: Base in source {
let value = Swift._bridgeFromObjectiveCConditional(
reinterpretCast(object), BridgesToDerived.self)
if _slowPath(!value) {
break ElementwiseBridging
}
p++.initialize(value!)
}
return Array(_ArrayBuffer(buf))
}
while false
// Don't destroy anything we never created.
buf.count = p - buf._unsafeElementStorage
// Report failure
return nil
}
// ${'Local Variables'}:
// eval: (read-only-mode 1)
// End: