//===--- 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 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 // //===----------------------------------------------------------------------===// % arrayTypes = ['ContiguousArray', 'Slice', 'Array'] % for Self in arrayTypes: @public struct ${Self} : MutableCollection, Sliceable { @public typealias Element = T @public var startIndex: Int { return 0 } @public var endIndex: Int { return _buffer.count } @public subscript(index: Int) -> Element { get { _precondition(index < count, "${Self} index out of range") _precondition(index >= 0, "Negative ${Self} index is out of range") return _buffer[index] } set { _precondition(index < count, "${Self} index out of range") _precondition(index >= 0, "Negative array index is out of range") if _buffer.isMutableAndUniquelyReferenced() { _buffer[index] = newValue } else { _subscriptSetSlowPath(&_buffer, e: newValue, index: index) } } } @public func generate() -> IndexingGenerator<${Self}> { return IndexingGenerator(self) } @public typealias SliceType = Slice @public subscript(subRange: Range) -> SliceType { get { return Slice(_buffer[subRange]) } set(rhs) { if self[subRange] !== rhs { self.replaceRange(subRange, with: rhs) } } } //===--- private --------------------------------------------------------===// @inline(never) func _subscriptSetSlowPath(inout buffer: _Buffer, e: Element, index : Int) { var newBuffer = ContiguousArrayBuffer( count: buffer.count, minimumCapacity: buffer.count) let target = buffer._uninitializedCopy( 0.. @public init(_ buffer: _Buffer) { self._buffer = buffer } @public var _buffer: _Buffer } extension ${Self} : ArrayLiteralConvertible { @public static func convertFromArrayLiteral(elements: Element...) -> ${Self} { return ${Self}(_extractOrCopyToNativeArrayBuffer(elements._buffer)) } } extension ${Self} { @public func _asCocoaArray() -> _CocoaArray { return _buffer._asCocoaArray() } } extension ${Self} : ArrayType { /// Construct an empty ${Self} @public init() { _buffer = _Buffer() } @public init< S: Sequence where S.GeneratorType.Element == _Buffer.Element >(_ s: S) { self = ${Self}(_Buffer(s~>_copyToNativeArrayBuffer())) } /// Construct an array of `count` elements, each initialized to /// `repeatedValue`. @public init(count: Int, repeatedValue: T) { _precondition(count >= 0, "Can't construct ${Self} with count < 0") _buffer = _Buffer() reserveCapacity(count) var p = _buffer.elementStorage for _ in 0.. { return _buffer.elementStorage } %if Self != 'Array': # // Array does not necessarily have contiguous storage var _elementStorage: UnsafePointer { return _buffer.elementStorage } %end //===--- basic mutations ------------------------------------------------===// /// Ensure the array has enough mutable contiguous storage to store /// minimumCapacity elements in. Note: does not affect count. /// Complexity: O(N) @public mutating func reserveCapacity(minimumCapacity: Int) { if !_buffer.requestUniqueMutableBackingBuffer(minimumCapacity) { var newBuffer = ContiguousArrayBuffer( count: count, minimumCapacity: minimumCapacity) _buffer._uninitializedCopy(0..= minimumCapacity) } /// Append newElement to the ${Self} in O(1) (amortized) @public mutating func append(newElement: T) { _arrayAppend(&_buffer, newElement) } /// Append elements from `sequence` to the Array @public mutating func extend< S : Sequence where S.GeneratorType.Element == T >(sequence: S) { // Calling a helper free function instead of writing the code inline // because of: // // 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).. 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 : Sequence where S.GeneratorType.Element == ${Self} >(elements: S) -> ${Self} { return Swift.join(self, elements) } @public func reduce(initial: U, combine: (U, T)->U) -> U { return Swift.reduce(self, initial, combine) } @public mutating func sort(isOrderedBefore: (T, T)->Bool) { return withUnsafeMutableStorage { 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(transform: (T)->U) -> ${Self} { return ${Self}(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 : Sequence where S.GeneratorType.Element == T >(inout a: ${Self}, sequence: S) { a += sequence } extension ${Self} : Reflectable { @public 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 } @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 = _elementStorageIfContiguous if _fastPath(p != nil || count == 0) { return (_owner, p.value) } let n = _extractOrCopyToNativeArrayBuffer(self._buffer) return (n.owner, n.elementStorage.value) } } extension ${Self} { /// Call body(p), where p is a pointer to the ${Self}'s contiguous storage %if Self != 'Array': /// Requires: the Array's storage is not provided by an opaque NSArray %end @public func withUnsafePointerToElements( body: (UnsafePointer) -> R ) -> R { return _buffer.withUnsafePointerToElements(body) } } extension ${Self} { @public mutating func withUnsafeMutableStorage( body: (inout UnsafeMutableArray)->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 UnsafeArray over work that we can pass to body var a = UnsafeMutableArray( start: work._buffer.elementStorage, 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 @public 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 } @inline(never) func _arrayOutOfPlaceReplace< B: ArrayBufferType, C: Collection where C.GeneratorType.Element == B.Element, B.IndexType == Int >( inout source: B, subRange: Range, 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: Collection where C.GeneratorType.Element == B.Element, B.IndexType == Int >(inout target: B, subRange: Range, insertCount: Int, newValues: C) { let oldCount = target.count let eraseCount = countElements(subRange) let growth = insertCount - eraseCount target.count = oldCount + growth let elements = target.elementStorage _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.. 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: Collection where C.GeneratorType.Element == B.Element, B.IndexType == Int >( inout target: B, subRange: Range, 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 in arrayTypes: extension ${Self} { @public mutating func replaceRange< C: Collection where C.GeneratorType.Element == _Buffer.Element >( subRange: Range, with newValues: C ) { _arrayReplace(&self._buffer, subRange, newValues) } } @assignment @public func += < T, S: Sequence where S.GeneratorType.Element == T >(inout lhs: ${Self}, 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) } @assignment @public func += < T, C: Collection where C.GeneratorType.Element == T >(inout lhs: ${Self}, 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.elementStorage + oldCount for x in rhs { (p++).initialize(x) } lhs._buffer.count = newCount } @assignment @public func += (inout lhs: ${Self}, rhs: T) { _arrayAppend(&lhs._buffer, rhs) } % 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 _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<_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!.elementStorage 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.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(backingEnd - sourceEnd) backing.count = 0 } else { let newStart = source._uninitializedCopy(0.. : _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<_Buffer: ArrayBufferType>( inout buffer: _Buffer, newValue: _Buffer.Element ) { let oldCount = buffer.count var newBuffer = _createUniqueMutableBuffer(&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<_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.GeneratorType.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: 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, _growArrayCapacity(capacity)) } } } /// 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 arrayTypes: // 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. @public 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. @public 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. @public 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`. @public func _arrayDownCast(a: Array) -> [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 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( 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 { // FIXME: reinterpretCast works around 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( source: Array ) -> Array { _sanityCheck(isBridgedVerbatimToObjectiveC(Base.self)) _sanityCheck(!isBridgedVerbatimToObjectiveC(BridgesToDerived.self)) 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)) } /// 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( source: Array ) -> Array { let result: Array? = _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( source: Array ) -> Array? { _sanityCheck(isBridgedVerbatimToObjectiveC(Base.self)) _sanityCheck(!isBridgedVerbatimToObjectiveC(BridgesToDerived.self)) var buf = ContiguousArrayBuffer(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: