mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
1202 lines
37 KiB
Swift
1202 lines
37 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`'),
|
|
('_UnitTestArray', 'a `_UnitTestArray`')
|
|
]
|
|
}%
|
|
|
|
% for (Self, a_Self) in arrayTypes:
|
|
|
|
%{
|
|
if True:
|
|
O1 = ("O(1) unless `self`'s storage is"
|
|
+ ' shared with another live array; O(`count`) '
|
|
+ ('if `self` does not wrap a bridged `NSArray`; '
|
|
+ 'otherwise the efficiency is unspecified.'
|
|
if Self == 'Array' else 'otherwise.'))
|
|
|
|
contiguousCaveat = (
|
|
' If no such storage exists, it is first created.' if Self == 'Array'
|
|
else '')
|
|
|
|
if Self == 'ContiguousArray':
|
|
SelfDocComment = """\
|
|
/// A fast, contiguously-stored array of `T`.
|
|
///
|
|
/// Efficiency is equivalent to that of `Array`, unless `T` is a
|
|
/// `class` or `@objc` `protocol` type, in which case using
|
|
/// `ContiguousArray` may be more efficient. Note, however, that
|
|
/// `ContiguousArray` does not bridge to Objective-C. See `Array`,
|
|
/// with which `ContiguousArray` shares most properties, for more
|
|
/// detail."""
|
|
elif Self == 'Slice':
|
|
SelfDocComment = """\
|
|
/// The `Array`-like type that represents a sub-sequence of any
|
|
/// `Array`, `ContiguousArray`, or other `Slice`.
|
|
///
|
|
/// `Slice` always uses contiguous storage and does not bridge to
|
|
/// Objective-C.
|
|
///
|
|
/// .. Warning:: Long-term storage of `Slice` instances is discouraged
|
|
///
|
|
/// Because a `Slice` presents a *view* onto the storage of some
|
|
/// larger array even after the original array's lifetime ends,
|
|
/// storing the slice may prolong the lifetime of elements that are
|
|
/// no longer accessible, which can manifest as apparent memory and
|
|
/// object leakage. To prevent this effect, use `Slice` only for
|
|
/// transient computation."""
|
|
elif Self == 'Array':
|
|
SelfDocComment = '''\
|
|
/// Conceptually_, `Array` is an efficient, tail-growable random-access
|
|
/// collection of arbitrary elements.
|
|
///
|
|
/// Common Properties of Array Types
|
|
/// ================================
|
|
///
|
|
/// The information in this section applies to all three of Swift's
|
|
/// array types, `Array<T>`, `ContiguousArray<T>`, and `Slice<T>`.
|
|
/// When you read the word "array" here in a normal typeface, it
|
|
/// applies to all three of them.
|
|
///
|
|
/// Value Semantics
|
|
/// ---------------
|
|
///
|
|
/// Each array variable, `let` binding, or stored property has an
|
|
/// independent value that includes the values of all of its elements.
|
|
/// Therefore, mutations to the array are not observable through its
|
|
/// copies::
|
|
///
|
|
/// var a = [1, 2, 3]
|
|
/// var b = a
|
|
/// b[0] = 4
|
|
/// println("a=\(a), b=\(b)") // a=[1, 2, 3], b=[4, 2, 3]
|
|
///
|
|
/// (Of course, if the array stores `class` references, the objects
|
|
/// are shared; only the values of the references are independent)
|
|
///
|
|
/// Arrays use Copy-on-Write so that their storage and elements are
|
|
/// only copied lazily, upon mutation, when more than one array
|
|
/// instance is using the same buffer. Therefore, the first in any
|
|
/// sequence of mutating operations may cost `O(N)` time and space,
|
|
/// where `N` is the length of the array.
|
|
///
|
|
/// Growth and Capacity
|
|
/// -------------------
|
|
///
|
|
/// When an array's contiguous storage fills up, new storage must be
|
|
/// allocated and elements must be moved to the new storage. `Array`,
|
|
/// `ContiguousArray`, and `Slice` share an exponential growth
|
|
/// strategy that makes `append` a constant time operation *when
|
|
/// amortized over many invocations*. In addition to a `count`
|
|
/// property, these array types have a `capacity` that reflects their
|
|
/// potential to store elements without reallocation, and when you
|
|
/// know how many elements you'll store, you can call
|
|
/// `reserveCapacity` to pre-emptively reallocate and prevent
|
|
/// intermediate reallocations.
|
|
///
|
|
/// .. _Conceptually:
|
|
///
|
|
/// Objective-C Bridge
|
|
/// ==================
|
|
///
|
|
/// The main distinction between `Array` and the other array types is
|
|
/// that it interoperates seamlessly and efficiently with Objective-C.
|
|
///
|
|
/// `Array<T>` is considered bridged to Objective-C iff `T` is bridged
|
|
/// to Objective-C.
|
|
///
|
|
/// When `T` is a `class` or `@objc` protocol type, `Array` may store
|
|
/// its elements in an `NSArray`. Since any arbitrary subclass of
|
|
/// `NSArray` can become an `Array`, there are no guarantees about
|
|
/// representation or efficiency in this case (see also
|
|
/// `ContiguousArray`). Since `NSArray` is immutable, it is just as
|
|
/// though the storage was shared by some copy: the first in any
|
|
/// sequence of mutating operations causes elements to be copied into
|
|
/// unique, contiguous storage which may cost `O(N)` time and space,
|
|
/// where `N` is the length of the array (or more, if the underlying
|
|
/// `NSArray` is has unusual performance characteristics).
|
|
///
|
|
/// Bridging to Objective-C
|
|
/// -----------------------
|
|
///
|
|
/// Any bridged `Array` can be implicitly converted to an `NSArray`.
|
|
/// When `T` is a `class` or `@objc` protocol, bridging takes O(1)
|
|
/// time and O(1) space. Other `Array`\ s must be bridged
|
|
/// element-by-element, allocating a new object for each element, at a
|
|
/// cost of at least O(`count`) time and space.
|
|
///
|
|
/// Bridging from Objective-C
|
|
/// -------------------------
|
|
///
|
|
/// An `NSArray` can be implicitly or explicitly converted to any
|
|
/// bridged `Array<T>`. This conversion calls `copyWithZone` on the
|
|
/// `NSArray`, to ensure it won't be modified, and stores the result
|
|
/// in the `Array`. Type-checking, to ensure the `NSArray`\ 's
|
|
/// elements match or can be bridged to `T`, is deferred until the
|
|
/// first element access.'''
|
|
# FIXME: Write about Array up/down-casting.
|
|
elif Self == '_UnitTestArray':
|
|
SelfDocComment = "\n/// Temporary"
|
|
else:
|
|
raise AssertionError('Unhandled case: ' + Self)
|
|
}%
|
|
|
|
${SelfDocComment}
|
|
public struct ${Self}<T> : MutableCollectionType, Sliceable, _DestructorSafeContainer {
|
|
/// The type of element stored by this `${Self}`
|
|
public typealias Element = T
|
|
|
|
/// Always zero, which is the index of the first element when non-empty.
|
|
public var startIndex: Int {
|
|
return 0
|
|
}
|
|
|
|
/// A "past-the-end" element index; the successor of the last valid
|
|
/// subscript argument.
|
|
public var endIndex: Int {
|
|
return _getCount()
|
|
}
|
|
|
|
/// Access the `index`\ th element. Reading is O(1). Writing is
|
|
/// ${O1}.
|
|
public subscript(index: Int) -> Element {
|
|
%if Self == 'Array':
|
|
get {
|
|
_checkSubscript(index)
|
|
return _getElement(index)
|
|
}
|
|
%else:
|
|
address {
|
|
_checkSubscript(index)
|
|
return UnsafePointer(_buffer.baseAddress + index)
|
|
}
|
|
%end
|
|
mutableAddress {
|
|
_makeMutableAndUnique()
|
|
_checkSubscript(index)
|
|
return _getElementAddress(index)
|
|
}
|
|
}
|
|
|
|
/// Return a *generator* over the elements.
|
|
///
|
|
/// Complexity: O(1)
|
|
public func generate() -> IndexingGenerator<${Self}> {
|
|
return IndexingGenerator(self)
|
|
}
|
|
|
|
/// A type that can represent a sub-range of ${a_Self}
|
|
public typealias SubSlice = Slice<T>
|
|
|
|
/// Access the elements indicated by the given half-open
|
|
/// `subRange`. O(1)
|
|
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
|
|
}
|
|
|
|
// Don't inline copyBuffer - this would inline the copy loop into the current
|
|
// path preventing retains/releases to be matched accross that region.
|
|
@inline(never)
|
|
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.get_element_address")
|
|
func _getElementAddress(index: Int) -> UnsafeMutablePointer<Element> {
|
|
return _buffer.baseAddress + index
|
|
}
|
|
|
|
public
|
|
%if Self == 'Array':
|
|
#if _runtime(_ObjC)
|
|
typealias _Buffer = _ArrayBuffer<T>
|
|
#else
|
|
typealias _Buffer = _ContiguousArrayBuffer<T>
|
|
#endif
|
|
%else:
|
|
typealias _Buffer = _${Self.strip('_')}Buffer<T>
|
|
%end
|
|
|
|
/// 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} : __ArrayType {
|
|
public func _doCopyToNativeArrayBuffer() -> _ContiguousArrayBuffer<T> {
|
|
return _extractOrCopyToNativeArrayBuffer(self._buffer)
|
|
}
|
|
}
|
|
|
|
extension ${Self} : ArrayLiteralConvertible {
|
|
%if Self == 'Array':
|
|
// Optimized implementation for Array
|
|
/// Create an instance containing `elements`.
|
|
public init(arrayLiteral elements: Element...) {
|
|
self = elements
|
|
}
|
|
%else:
|
|
/// Create an instance containing `elements`.
|
|
public init(arrayLiteral elements: Element...) {
|
|
self.init(_extractOrCopyToNativeArrayBuffer(elements._buffer))
|
|
}
|
|
%end
|
|
}
|
|
|
|
// Referenced by the compiler to allocate array literals.
|
|
@semantics("array.uninitialized")
|
|
public func _allocateUninitialized${Self}<T>(count: Builtin.Word)
|
|
-> (${Self}<T>, Builtin.RawPointer) {
|
|
let (array, ptr) = ${Self}<T>._allocateUninitialized(Int(count))
|
|
return (array, ptr._rawValue)
|
|
}
|
|
|
|
extension ${Self} : _ArrayType {
|
|
/// Construct an empty ${Self}
|
|
@semantics("array.init")
|
|
public init() {
|
|
_buffer = _Buffer()
|
|
}
|
|
|
|
/// Construct from an arbitrary sequence with elements of type `T`
|
|
public init<
|
|
S: SequenceType where S.Generator.Element == _Buffer.Element
|
|
>(_ s: S) {
|
|
self = ${Self}(_Buffer(s~>_copyToNativeArrayBuffer()))
|
|
}
|
|
|
|
/// Construct a ${Self} of `count` elements, each initialized to
|
|
/// `repeatedValue`.
|
|
@semantics("array.init")
|
|
public init(count: Int, repeatedValue: T) {
|
|
var p: UnsafeMutablePointer<T>
|
|
(self, p) = ${Self}._allocateUninitialized(count)
|
|
for _ in 0..<count {
|
|
p.initialize(repeatedValue)
|
|
++p
|
|
}
|
|
}
|
|
|
|
/// Construct a ${Self} of `count` uninitialized elements
|
|
internal init(_uninitializedCount count: Int) {
|
|
_precondition(count >= 0, "Can't construct ${Self} with count < 0")
|
|
_buffer = _Buffer()
|
|
|
|
// Performance optimization: avoid reserveCapacity call if not needed.
|
|
if count > 0 {
|
|
reserveCapacity(count)
|
|
}
|
|
_buffer.count = count
|
|
}
|
|
|
|
/// Entry point for `Array` literal construction; builds and returns
|
|
/// a ${Self} of `count` uninitialized elements
|
|
internal static func _allocateUninitialized(
|
|
count: Int
|
|
) -> (${Self}, UnsafeMutablePointer<T>) {
|
|
var result = ${Self}(_uninitializedCount: count)
|
|
return (result, result._buffer.baseAddress)
|
|
}
|
|
|
|
/// 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 ------------------------------------------------===//
|
|
|
|
|
|
/// Reserve enough space to store minimumCapacity elements.
|
|
///
|
|
/// PostCondition: `capacity >= minimumCapacity` and the array has
|
|
/// mutable contiguous storage.
|
|
///
|
|
/// Complexity: O(`count`)
|
|
@semantics("array.mutate_unknown")
|
|
public mutating func reserveCapacity(minimumCapacity: Int) {
|
|
if _buffer.requestUniqueMutableBackingBuffer(minimumCapacity) == nil {
|
|
|
|
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}
|
|
///
|
|
/// Complexity: amortized ${O1}
|
|
@semantics("array.mutate_unknown")
|
|
public mutating func append(newElement: T) {
|
|
_arrayAppend(&_buffer, newElement)
|
|
}
|
|
|
|
/// Append the elements of `newElements` to `self`.
|
|
///
|
|
/// Complexity: O(*length of result*)
|
|
///
|
|
public mutating func extend<
|
|
S : SequenceType
|
|
where S.Generator.Element == T
|
|
>(newElements: 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, newElements)
|
|
}
|
|
|
|
/// 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 `newElement` at index `i`.
|
|
///
|
|
/// Requires: `i <= count`
|
|
///
|
|
/// Complexity: O(\ `count`\ ).
|
|
public mutating func insert(newElement: T, atIndex i: Int) {
|
|
_checkIndex(i)
|
|
self.replaceRange(i..<i, with: CollectionOfOne(newElement))
|
|
}
|
|
|
|
/// Remove and return the element at index `i`
|
|
///
|
|
/// Invalidates all indices with respect to `self`.
|
|
///
|
|
/// Complexity: O(\ `count`\ ).
|
|
public mutating func removeAtIndex(index: Int) -> T {
|
|
let result = self[index]
|
|
self.replaceRange(index..<(index + 1), with: EmptyCollection())
|
|
return result
|
|
}
|
|
|
|
/// Remove all elements.
|
|
///
|
|
/// Postcondition: `capacity == 0` iff `keepCapacity` is `false`.
|
|
///
|
|
/// Complexity: O(\ `count(self)`\ ).
|
|
public mutating func removeAll(keepCapacity: Bool = false) {
|
|
if !keepCapacity {
|
|
_buffer = _Buffer()
|
|
}
|
|
else {
|
|
self.replaceRange(indices(self), with: EmptyCollection())
|
|
}
|
|
}
|
|
|
|
//===--- algorithms -----------------------------------------------------===//
|
|
|
|
/// Interpose `self` between each consecutive pair of `elements`,
|
|
/// and concatenate the elements of the resulting sequence. For
|
|
/// example, `[-1, -2].join([[1, 2, 3], [4, 5, 6], [7, 8, 9]])`
|
|
/// yields `[1, 2, 3, -1, -2, 4, 5, 6, -1, -2, 7, 8, 9]`
|
|
public func join<
|
|
S : SequenceType where S.Generator.Element == ${Self}<T>
|
|
>(elements: S) -> ${Self}<T> {
|
|
return Swift.join(self, elements)
|
|
}
|
|
|
|
/// Return the result of repeatedly calling `combine` with an
|
|
/// accumulated value initialized to `initial` and each element of
|
|
/// `self`, in turn, i.e. return
|
|
/// `combine(combine(...combine(combine(initial, self[0]),
|
|
/// self[1]),...self[count-2]), self[count-1])`.
|
|
public func reduce<U>(initial: U, combine: (U, T)->U) -> U {
|
|
return Swift.reduce(self, initial, combine)
|
|
}
|
|
|
|
/// Sort `self` in-place according to `isOrderedBefore`. Requires:
|
|
/// `isOrderedBefore` induces a `strict weak ordering
|
|
/// <http://en.wikipedia.org/wiki/Strict_weak_order#Strict_weak_orderings>`__
|
|
/// over the elements.
|
|
public mutating func sort(isOrderedBefore: (T, T)->Bool) {
|
|
return withUnsafeMutableBufferPointer {
|
|
me in Swift.sort(&me, isOrderedBefore)
|
|
return
|
|
}
|
|
}
|
|
|
|
/// Return a copy of `self` that has been sorted according to
|
|
/// `isOrderedBefore`. Requires: `isOrderedBefore` induces a
|
|
/// `strict weak ordering
|
|
/// <http://en.wikipedia.org/wiki/Strict_weak_order#Strict_weak_orderings>`__
|
|
/// over the elements.
|
|
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 {
|
|
/// Returns a mirror that reflects `self`.
|
|
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
|
|
}
|
|
|
|
/// A textual representation of `self`.
|
|
public var description: String {
|
|
return _makeDescription(isDebug: false)
|
|
}
|
|
|
|
/// A textual representation of `self`, suitable for debugging.
|
|
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._rawValue)
|
|
}
|
|
let n = _extractOrCopyToNativeArrayBuffer(self._buffer)
|
|
return (n.owner, n.baseAddress._rawValue)
|
|
}
|
|
|
|
}
|
|
|
|
extension ${Self} {
|
|
/// Call `body(p)`, where `p` is a pointer to the `${Self}`\ 's
|
|
/// contiguous storage.${contiguousCaveat}
|
|
///
|
|
/// Often, the optimizer can eliminate bounds checks within an
|
|
/// array algorithm, but when that fails, invoking the
|
|
/// same algorithm on `body`\ 's argument lets you trade safety for
|
|
/// speed.
|
|
public func withUnsafeBufferPointer<R>(
|
|
body: (UnsafeBufferPointer<T>) -> R
|
|
) -> R {
|
|
return _buffer.withUnsafeBufferPointer(body)
|
|
}
|
|
|
|
/// Call `body(p)`, where `p` is a pointer to the `${Self}`\ 's
|
|
/// mutable contiguous storage.${contiguousCaveat}
|
|
///
|
|
/// Often, the optimizer can eliminate bounds- and uniqueness-checks
|
|
/// within an array algorithm, but when that fails, invoking the
|
|
/// same algorithm on `body`\ 's argument lets you trade safety for
|
|
/// speed.
|
|
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, count: work.count)
|
|
|
|
// Invoke the body
|
|
let ret = body(&a)
|
|
|
|
// Put the working array back before returning.
|
|
swap(&work, &self)
|
|
return ret
|
|
}
|
|
}
|
|
%end
|
|
|
|
struct _InitializeMemoryFromCollection<
|
|
C: CollectionType
|
|
> : _PointerFunctionType {
|
|
func call(rawMemory: UnsafeMutablePointer<C.Generator.Element>, count: Int) {
|
|
var p = rawMemory
|
|
var q = newValues.startIndex
|
|
for _ in 0..<count {
|
|
p++.initialize(newValues[q++])
|
|
}
|
|
_expectEnd(q, newValues)
|
|
}
|
|
|
|
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 - count(subRange)
|
|
let newCount = source.count + growth
|
|
var newBuffer = Optional(
|
|
_forceCreateUniqueMutableBuffer(&source, newCount, newCount))
|
|
|
|
_arrayOutOfPlaceUpdate(
|
|
&source, &newBuffer,
|
|
subRange.startIndex, insertCount,
|
|
_InitializeMemoryFromCollection(newValues)
|
|
)
|
|
}
|
|
|
|
/// A _debugPrecondition check that `i` has exactly reached the end of
|
|
/// `s`. This test is never used to ensure memory safety; that is
|
|
/// always guaranteed by measuring `s` once and re-using that value.
|
|
internal func _expectEnd<C: _CollectionType>(
|
|
i: C.Index, s: C
|
|
) {
|
|
_debugPrecondition(
|
|
i == s.endIndex,
|
|
"invalid CollectionType: count differed in successive traversals"
|
|
)
|
|
}
|
|
|
|
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 = count(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++])
|
|
}
|
|
_expectEnd(i, newValues)
|
|
}
|
|
else { // We're not growing the buffer
|
|
// Assign all the new elements into the start of the subRange
|
|
var i = subRange.startIndex
|
|
var j = newValues.startIndex
|
|
for _ in 0..<insertCount {
|
|
elements[i++] = newValues[j++]
|
|
}
|
|
_expectEnd(j, newValues)
|
|
|
|
// 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 _growArrayCapacity(capacity: Int) -> Int {
|
|
return capacity * 2
|
|
}
|
|
|
|
% for (Self, a_Self) in arrayTypes:
|
|
extension ${Self} {
|
|
/// Replace the given `subRange` of elements with `newElements`.
|
|
///
|
|
/// Complexity: O(\ `count(subRange)`\ ) if `subRange.endIndex
|
|
/// == self.endIndex` and `isEmpty(newElements)`\ , O(N) otherwise.
|
|
@semantics("array.mutate_unknown")
|
|
public mutating func replaceRange<
|
|
C: CollectionType where C.Generator.Element == _Buffer.Element
|
|
>(
|
|
subRange: Range<Int>, with newElements: C
|
|
) {
|
|
_precondition(subRange.startIndex >= 0,
|
|
"${Self} replace: subRange start is negative")
|
|
|
|
_precondition(subRange.endIndex <= self._buffer.endIndex,
|
|
"${Self} replace: subRange extends past the end")
|
|
|
|
let oldCount = self._buffer.count
|
|
let eraseCount = Swift.count(subRange)
|
|
let insertCount = numericCast(Swift.count(newElements)) as Int
|
|
let growth = insertCount - eraseCount
|
|
|
|
if self._buffer.requestUniqueMutableBackingBuffer(oldCount + growth) != nil {
|
|
self._buffer.replace(subRange: subRange, with: insertCount, elementsOf: newElements)
|
|
} else {
|
|
_arrayOutOfPlaceReplace(&self._buffer, subRange, newElements, insertCount)
|
|
}
|
|
}
|
|
|
|
/// Insert `newElements` at index `i`
|
|
///
|
|
/// Invalidates all indices with respect to `self`.
|
|
///
|
|
/// Complexity: O(\ `count + count(newElements)`\ ).
|
|
public mutating func splice<
|
|
S: CollectionType where S.Generator.Element == T
|
|
>(newElements: S, atIndex i: Int) {
|
|
// FIXME: <rdar://problem/17866066>
|
|
// Swift.splice(&self, newElements, atIndex: i)
|
|
self.replaceRange(i..<i, with: newElements)
|
|
}
|
|
|
|
/// Remove the indicated `subRange` of elements
|
|
///
|
|
/// Complexity: O(\ `count`\ ).
|
|
public mutating func removeRange(subRange: Range<Int>) {
|
|
Swift.removeRange(&self, subRange)
|
|
}
|
|
}
|
|
|
|
/// Extend `lhs` with the elements of `rhs`
|
|
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)
|
|
}
|
|
|
|
/// Extend `lhs` with the elements of `rhs`
|
|
public
|
|
func += <
|
|
T, C: CollectionType
|
|
where C.Generator.Element == T
|
|
>(inout lhs: ${Self}<T>, rhs: C) {
|
|
let rhsCount = numericCast(count(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>, count: Int)
|
|
}
|
|
|
|
/// 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, count: newCount)
|
|
|
|
// 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, count: newCount)
|
|
source._uninitializedCopy(headCount + oldCount..<sourceCount,
|
|
target: newEnd)
|
|
}
|
|
source = _Buffer(dest!)
|
|
}
|
|
|
|
struct _InitializePointer<T> : _PointerFunctionType {
|
|
func call(rawMemory: UnsafeMutablePointer<T>, count: Int) {
|
|
_sanityCheck(count == 1)
|
|
// FIXME: it would be better if we could find a way to move, here
|
|
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 == nil) {
|
|
(buffer.baseAddress + oldCount).initialize(newValue)
|
|
}
|
|
else {
|
|
_arrayOutOfPlaceUpdate(
|
|
&buffer, &newBuffer, oldCount, 1, _InitializePointer(newValue))
|
|
}
|
|
}
|
|
|
|
struct _IgnorePointer<T> : _PointerFunctionType {
|
|
func call(_:UnsafeMutablePointer<T>, count: Int) {
|
|
_sanityCheck(count == 0)
|
|
}
|
|
}
|
|
|
|
func _arrayReserve<_Buffer: _ArrayBufferType>(
|
|
inout buffer: _Buffer, minimumCapacity: Int
|
|
) {
|
|
let oldCount = buffer.count
|
|
var newBuffer = _createUniqueMutableBuffer(
|
|
&buffer, oldCount, minimumCapacity: minimumCapacity)
|
|
if _slowPath(newBuffer != nil){
|
|
_arrayOutOfPlaceUpdate(&buffer, &newBuffer, oldCount, 0, _IgnorePointer())
|
|
}
|
|
}
|
|
|
|
public func _extractOrCopyToNativeArrayBuffer<
|
|
_Buffer: _ArrayBufferType
|
|
where _Buffer.Generator.Element == _Buffer.Element,
|
|
_Buffer.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 == nil {
|
|
return
|
|
}
|
|
|
|
// This will force uniqueness
|
|
_arrayAppend(&buffer, nextItem!)
|
|
var count = buffer.count
|
|
nextItem = stream.next()
|
|
while nextItem != nil {
|
|
let capacity = buffer.capacity
|
|
let base = buffer.baseAddress
|
|
|
|
while (nextItem != nil) && count < capacity {
|
|
(base + count++).initialize(nextItem!)
|
|
nextItem = stream.next()
|
|
}
|
|
buffer.count = count
|
|
if nextItem != nil {
|
|
_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 != nil {
|
|
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
|
|
|
|
#if _runtime(_ObjC)
|
|
/// 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.
|
|
/// FIXME: Dynamic casting is currently not possible without the objc runtime:
|
|
/// rdar://problem/18801510
|
|
public func _arrayUpCast<Derived, Base>(a: Array<Derived>) -> Array<Base> {
|
|
return Array(a._buffer.castToBufferOf(Base.self))
|
|
}
|
|
#endif
|
|
|
|
#if _runtime(_ObjC)
|
|
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 deferred = source as? _SwiftDeferredNSArray {
|
|
if let nativeStorage =
|
|
deferred._nativeStorage as? _ContiguousArrayStorage<T> {
|
|
return Array(_ContiguousArrayBuffer(nativeStorage))
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
/// Construct from the given `_NSArrayCoreType`.
|
|
///
|
|
/// If `noCopy` is `true`, either `source` must be known to be immutable,
|
|
/// or the resulting `Array` must not survive across code that could mutate
|
|
/// `source`.
|
|
public init(
|
|
_fromCocoaArray source: _NSArrayCoreType,
|
|
noCopy: Bool = false) {
|
|
var selectedSource: _NSArrayCoreType =
|
|
noCopy ?
|
|
source :
|
|
unsafeBitCast(
|
|
source.copyWithZone(nil),
|
|
_NSArrayCoreType.self)
|
|
self = Array(_ArrayBuffer(nsArray: selectedSource))
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// ${'Local Variables'}:
|
|
// eval: (read-only-mode 1)
|
|
// End:
|