%# -*- mode: swift -*- //===--- Arrays.swift.gyb - ContiguousArray, Array, and Slice -----------------===// // // 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 is a fast, contiguous array of T with a known // backing store. // // - Slice presents an arbitrary subsequence of some contiguous sequence // of Ts. // // - Array is like ContiguousArray when T is not an ObjC type. // Otherwise, it may use an NSArray bridged from Cocoa for storage // //===----------------------------------------------------------------------===// % for Self in ['ContiguousArray', 'Slice', 'Array']: struct ${Self} : MutableCollection, Sliceable { typealias Element = T var startIndex: Int { return 0 } var endIndex: Int { return buffer.count } subscript(index: Int) -> Element { get { assert(index < count, "Array index out of range") return buffer[index] } nonmutating set { assert(index < count, "Array index out of range") buffer[index] = newValue } } func generate() -> IndexingGenerator<${Self}> { return IndexingGenerator(self) } typealias SliceType = Slice subscript(subRange: Range) -> SliceType { get { return Slice(buffer[subRange]) } set { if self[subRange] !== newValue { replace(&self, subRange, newValue) } } } //===--- private --------------------------------------------------------===// typealias Buffer = ${'Array' if Self.startswith('New') else Self}Buffer init(_ buffer: Buffer) { self.buffer = buffer } var buffer: Buffer } extension ${Self} : ArrayLiteralConvertible { static func convertFromArrayLiteral(elements: Element...) -> ${Self} { return ${Self}(_extractOrCopyToNativeArrayBuffer(elements.buffer)) } } extension ${Self} { func _asCocoaArray() -> _CocoaArray { return buffer._asCocoaArray() } } extension ${Self} : ArrayType { /// Construct an empty ${Self} init() { buffer = Buffer() } init(_ s: S) { self = ${Self}(Buffer(s~>_copyToNativeArrayBuffer())) } /// Construct an array of count elements, each initialized to value init(count: Int, value: T) { assert(count >= 0) buffer = Buffer() reserveCapacity(count) var p = buffer.elementStorage for _ in 0..count { p++.initialize(value) } buffer.count = count } /// How many elements the ${Self} stores var count: Int { return buffer.count } /// How many elements the ${Self} can store without reallocation var capacity: Int { return buffer.capacity } /// true if and only if the ${Self} is empty var isEmpty: Bool { return count == 0 } /// An object that guarantees the lifetime of this array's elements var owner: AnyObject? { return buffer.owner } /// If the elements are stored contiguously, a pointer to the first /// element. Otherwise, nil. var elementStorage: UnsafePointer { return buffer.elementStorage } //===--- basic mutations ------------------------------------------------===// /// Returns a new array that does not share the underlying storage with this /// array. /// Complexity: O(N) func copy() -> ${Self} { var result = self result.reserveCapacity(0) return result } /// Ensure the uniqueness of the array. /// Complexity: O(N) mutating func unshare() { reserveCapacity(0) } /// Ensure the array has enough mutable contiguous storage to store /// newCapacity elements in. Note: does not affect count. /// Complexity: O(N) mutating func reserveCapacity(newCapacity: Int) { if !buffer.requestUniqueMutableBuffer(newCapacity) { var newBuffer = ContiguousArrayBuffer(count: count, minimumCapacity: newCapacity) buffer._uninitializedCopy(0..count, target: newBuffer.elementStorage) buffer = Buffer(newBuffer) } assert(capacity >= newCapacity) } /// Append newElement to the ${Self} in O(1) (amortized) mutating func append(newElement: T) { _arrayAppend(&buffer, newElement) } /// Remove an element from the end of the ${Self} in O(1). /// Requires: count > 0 mutating func popLast() -> T { assert(count > 0, "can't pop from an empty ${Self}") let c = count let result = self[c - 1] replace(&self, (c - 1)..c, EmptyCollection()) return result } /// Insert an element at the given index in O(N). Requires: atIndex /// <= count mutating func insert(atIndex: Int, newElement: T) { replace(&self, atIndex..atIndex, CollectionOfOne(newElement)) } /// Remove the element at the given index. Worst case complexity: /// O(N). Requires: index < count mutating func removeAt(index: Int) -> T { let result = self[index] replace(&self, index..(index + 1), EmptyCollection()) return result } /// Erase all the elements and release the storage mutating func clear() { buffer = Buffer() } /// Erase all the elements. If keepStorage is true, capacity will not change mutating func clear(keepStorage: Bool) { if !keepStorage { clear() } else { replace(&self, indices(self), EmptyCollection()) } } //===--- algorithms -----------------------------------------------------===// func reduce(initial: U, combine: (U, T)->U) -> U { return Swift.reduce(self, initial, combine) } mutating func sort(isOrderedBefore: (T, T)->Bool) { quickSort(&self, indices(self), isOrderedBefore) } func map(transform: (T)->U) -> ${Self} { var result = ${Self}() let count = self.count result.reserveCapacity(count) var p = result.buffer.elementStorage for i in 0..count { p++.initialize( transform(self[i]) ) } result.buffer.count = count return result } } extension ${Self} : Reflectable { func getMirror() -> Mirror { 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 } var description: String { return _makeDescription(isDebug: false) } var debugDescription: String { return _makeDescription(isDebug: true) } } extension ${Self} { @transparent func _cPointerArgs() -> (AnyObject?, Builtin.RawPointer) { let p = elementStorage if _fastPath(p != nil || count == 0) { return (owner, p.value) } let n = _extractOrCopyToNativeArrayBuffer(self.buffer) return (n.owner, n.elementStorage.value) } // Conversion to C pointer arguments @transparent @conversion func __conversion() -> CConstPointer { return CConstPointer(_cPointerArgs()) } @transparent @conversion func __conversion() -> CConstVoidPointer { return CConstVoidPointer(_cPointerArgs()) } } %if Self != 'Array': # // Array does not necessarily have contiguous storage extension ${Self} { func withUnsafePointerToElements(body: (UnsafePointer)->R) -> R { return buffer.withUnsafePointerToElements(body) } } %end %end extension Array { /// This function "seeds" the ArrayLiteralConvertible protocol static func convertFromHeapArray( base: Builtin.RawPointer, owner: Builtin.NativeObject, count: Builtin.Word ) -> Array { let elements = UnsafeArray( start: reinterpretCast(base) as UnsafePointer, length: reinterpretCast(count) as Int ) let r = Array(elements) _fixLifetime(owner) return r } } struct _InitializeMemoryFromCollection : PointerFunction { func call(rawMemory: UnsafePointer) { var p = rawMemory for x in newValues { p++.initialize(x) } } init(_ newValues: C) { self.newValues = newValues } var newValues: C } func replace< A: ArrayType, C: Collection where C.GeneratorType.Element == A.Buffer.Element, A.IndexType == Int >( inout target: A, subRange: Range, newValues: C ) { assert(subRange.startIndex >= 0) assert(subRange.endIndex >= subRange.startIndex) assert(subRange.endIndex <= target.endIndex) let oldCount = target.count let eraseCount = countElements(subRange) let insertCount = numericCast(countElements(newValues)) as Int var newBuffer = _demandUniqueMutableBuffer( &target.buffer, oldCount + insertCount - eraseCount) if _fastPath(!newBuffer) { let growth = insertCount - eraseCount let elements = target.buffer.elementStorage assert(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) } } } else { _arrayOutOfPlaceUpdate( &target.buffer, &newBuffer, subRange.startIndex, insertCount, _InitializeMemoryFromCollection(newValues) ) } } @assignment func += < A: ArrayType, S: Sequence where S.GeneratorType.Element == A.Buffer.Element >(inout lhs: A, rhs: S) { _arrayAppendSequence(&lhs.buffer, rhs) } @assignment func += < A: ArrayType, C: Collection where C.GeneratorType.Element == A.Buffer.Element >(inout lhs: A, 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, capacity * 2) : newCount) var p = lhs.buffer.elementStorage + oldCount for x in rhs { (p++).initialize(x) } lhs.buffer.count = newCount } @assignment func += < A: ArrayType >(inout lhs: A, rhs: A.Buffer.Element) { lhs += CollectionOfOne(rhs) } //===--- 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 _demandUniqueMutableBuffer( inout source: Buffer, newCount: Int, minimumCapacity: Int = 0) -> ContiguousArrayBuffer? { assert(newCount >= 0) let requiredCapacity = max(newCount, minimumCapacity) if let b = source.requestUniqueMutableBuffer(requiredCapacity) { source.count = newCount return nil } let newCapacity = max( requiredCapacity, newCount > source.capacity ? source.capacity * 2 : source.capacity) return ContiguousArrayBuffer(count: newCount, minimumCapacity: newCapacity) } protocol PointerFunction { typealias Element func call(UnsafePointer) } /// 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: PointerFunction where Initializer.Element == Buffer.Element >( inout source: Buffer, inout dest: ContiguousArrayBuffer?, headCount: Int, // Count of initial source elements to copy/move newCount: Int, // Count of new elements to insert initializeNewElements: Initializer ) { assert(headCount >= 0) assert(newCount >= 0) // Count of trailing source elements to copy/move let tailCount = dest!.count - headCount - newCount assert(headCount + tailCount <= source.count) let sourceCount = source.count let oldCount = sourceCount - headCount - tailCount let destStart = dest!.elementStorage let newStart = destStart + headCount let newEnd = newStart + newCount // Check to see if we have storage we can move from if let backing = source.requestUniqueMutableBuffer(sourceCount) { let sourceStart = source.elementStorage let oldStart = sourceStart + headCount // Destroy any items that may be lurking in a SliceBuffer before // its real first element let backingStart = backing.elementStorage 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(sourceEnd - backingEnd) 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 : PointerFunction { func call(rawMemory: UnsafePointer) { // FIXME: maybe we should move here instead of copying? rawMemory.initialize(newValue) } @transparent init(_ newValue: T) { self.newValue = newValue } var newValue: T } func _arrayAppend( inout buffer: Buffer, newValue: Buffer.Element ) { let oldCount = buffer.count var newBuffer = _demandUniqueMutableBuffer(&buffer, oldCount + 1) if _fastPath(!newBuffer) { (buffer.elementStorage + oldCount).initialize(newValue) } else { _arrayOutOfPlaceUpdate( &buffer, &newBuffer, oldCount, 1, InitializePointer(newValue)) } } struct IgnorePointer : PointerFunction { func call(_:UnsafePointer) {} } func _arrayReserve( inout buffer: Buffer, newCapacity: Int ) { let oldCount = buffer.count var newBuffer = _demandUniqueMutableBuffer(&buffer, oldCount, minimumCapacity: newCapacity) if _slowPath(newBuffer) { _arrayOutOfPlaceUpdate(&buffer, &newBuffer, oldCount, 1, IgnorePointer()) } } func _extractOrCopyToNativeArrayBuffer< Buffer: ArrayBufferType where Buffer.GeneratorType.Element == Buffer.Element >(source: Buffer) -> ContiguousArrayBuffer { if let n = source.requestNativeBuffer() { return n } return _copyCollectionToNativeArrayBuffer(source) } /// Append items from newItems to buffer func _arrayAppendSequence< Buffer: ArrayBufferType, S: Sequence where S.GeneratorType.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.elementStorage while nextItem && count < capacity { (base + count++).initialize(nextItem!) nextItem = stream.next() } buffer.count = count if nextItem { _arrayReserve(&buffer, capacity * 2) } } } /// Returns true iff these arrays reference exactly the same elements. func ===(lhs: T, rhs: U) -> Bool { let lhsCount = lhs.count if lhsCount != rhs.count { return false } return lhsCount == 0 || lhs.buffer.identity == rhs.buffer.identity } /// Returns false iff these arrays reference exactly the same /// elements. func !==(lhs: T, rhs: U) -> Bool { return !(lhs === rhs) } % for Self in ['ContiguousArray', 'Slice', 'Array']: // NOTE: The '==' and '!=' below only handles array types // that are the same, e.g. Array and Array, not // Slice and Array. /// Returns true if these arrays contain the same elements. func ==(lhs: ${Self}, rhs: ${Self}) -> 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. func !=(lhs: ${Self}, rhs: ${Self}) -> Bool { return !(lhs == rhs) } %end /// Returns an Array containing the same elements as a in /// O(1). Requires: Base is a base class or base @objc protocol (such /// as AnyObject) of Derived. func _arrayUpCast(a: Array) -> Array { return Array(a.buffer.castToBufferOf(Base.self)) } /// 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 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. func _arrayCheckedDownCast(a: Array) -> 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 { if !(element is Derived) { return nil } } } return Array(a.buffer.castToBufferOf(Derived.self)) } return [] } /// Convert a to its corresponding bridged array type. /// Precondition: T is bridged to objective C /// O(1) if T is bridged verbatim, O(N) otherwise func _arrayBridgeToObjectiveC( source: Array ) -> Array { var buf = ContiguousArrayBuffer(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)) } // ${'Local Variables'}: // eval: (read-only-mode 1) // End: