//===--- ArrayShared.swift ------------------------------------*- swift -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // /// This type is used as a result of the `_checkSubscript` call to associate the /// call with the array access call it guards. /// /// In order for the optimizer see that a call to `_checkSubscript` is semantically /// associated with an array access, a value of this type is returned and later passed /// to the accessing function. For example, a typical call to `_getElement` looks like /// let token = _checkSubscript(index, ...) /// return _getElement(index, ... , matchingSubscriptCheck: token) @frozen public struct _DependenceToken { @inlinable public init() { } } /// Returns an Array of `_count` uninitialized elements using the /// given `storage`, and a pointer to uninitialized memory for the /// first element. /// /// This function is referenced by the compiler to allocate array literals. /// /// - Precondition: `storage` is `_ContiguousArrayStorage`. @inlinable // FIXME(inline-always) @inline(__always) @_semantics("array.uninitialized_intrinsic") public // COMPILER_INTRINSIC func _allocateUninitializedArray(_ builtinCount: Builtin.Word) -> (Array, Builtin.RawPointer) { let count = Int(builtinCount) if count > 0 { // Doing the actual buffer allocation outside of the array.uninitialized // semantics function enables stack propagation of the buffer. #if !$Embedded let bufferObject = Builtin.allocWithTailElems_1( getContiguousArrayStorageType(for: Element.self), builtinCount, Element.self) #else let bufferObject = Builtin.allocWithTailElems_1( _ContiguousArrayStorage.self, builtinCount, Element.self) #endif let (array, ptr) = unsafe Array._adoptStorage(bufferObject, count: count) return (array, ptr._rawValue) } // For an empty array no buffer allocation is needed. let (array, ptr) = unsafe Array._allocateUninitialized(count) return (array, ptr._rawValue) } // Referenced by the compiler to deallocate array literals on the // error path. @inlinable @_semantics("array.dealloc_uninitialized") public // COMPILER_INTRINSIC func _deallocateUninitializedArray( _ array: __owned Array ) { var array = array array._deallocateUninitialized() } #if !INTERNAL_CHECKS_ENABLED @_alwaysEmitIntoClient @_semantics("array.finalize_intrinsic") @_effects(readnone) @_effects(escaping array.value** => return.value**) @_effects(escaping array.value**.class*.value** => return.value**.class*.value**) public // COMPILER_INTRINSIC func _finalizeUninitializedArray( _ array: __owned Array ) -> Array { var mutableArray = array mutableArray._endMutation() return mutableArray } #else // When asserts are enabled, _endCOWMutation writes to _native.isImmutable // So we cannot have @_effects(readnone) @_alwaysEmitIntoClient @_semantics("array.finalize_intrinsic") public // COMPILER_INTRINSIC func _finalizeUninitializedArray( _ array: __owned Array ) -> Array { var mutableArray = array mutableArray._endMutation() return mutableArray } #endif @_unavailableInEmbedded extension Collection { // Utility method for collections that wish to implement // CustomStringConvertible and CustomDebugStringConvertible using a bracketed // list of elements, like an array. internal func _makeCollectionDescription( withTypeName type: String? = nil ) -> String { #if !SWIFT_STDLIB_STATIC_PRINT var result = "" if let type = type { result += "\(type)([" } else { result += "[" } var first = true for item in self { if first { first = false } else { result += ", " } #if !$Embedded debugPrint(item, terminator: "", to: &result) #else "(cannot print value in embedded Swift)".write(to: &result) #endif } result += type != nil ? "])" : "]" return result #else return "(collection printing not available)" #endif } } extension _ArrayBufferProtocol { @inlinable // FIXME: @useableFromInline (https://github.com/apple/swift/issues/50130). @inline(never) internal mutating func _arrayOutOfPlaceReplace( _ bounds: Range, with newValues: __owned C, count insertCount: Int ) where C.Element == Element { let growth = insertCount - bounds.count let newCount = self.count + growth var newBuffer = _forceCreateUniqueMutableBuffer( newCount: newCount, requiredCapacity: newCount) unsafe _arrayOutOfPlaceUpdate( &newBuffer, bounds.lowerBound - startIndex, insertCount, { rawMemory, count in var p = unsafe rawMemory var q = newValues.startIndex for _ in 0..(of s: C, is i: C.Index) { _debugPrecondition( i == s.endIndex, "invalid Collection: count differed in successive traversals") } @inlinable internal func _growArrayCapacity(_ capacity: Int) -> Int { return capacity * 2 } @_alwaysEmitIntoClient internal func _growArrayCapacity( oldCapacity: Int, minimumCapacity: Int, growForAppend: Bool ) -> Int { if growForAppend { if oldCapacity < minimumCapacity { // When appending to an array, grow exponentially. return Swift.max(minimumCapacity, _growArrayCapacity(oldCapacity)) } return oldCapacity } // If not for append, just use the specified capacity, ignoring oldCapacity. // This means that we "shrink" the buffer in case minimumCapacity is less // than oldCapacity. return minimumCapacity } //===--- generic helpers --------------------------------------------------===// extension _ArrayBufferProtocol { /// Create a unique mutable buffer that has enough capacity to hold 'newCount' /// elements and at least 'requiredCapacity' elements. Set the count of the new /// buffer to 'newCount'. The content of the buffer is uninitialized. /// The formula used to compute the new buffers capacity is: /// max(requiredCapacity, source.capacity) if newCount <= source.capacity /// max(requiredCapacity, _growArrayCapacity(source.capacity)) otherwise @inline(never) @inlinable // @specializable internal func _forceCreateUniqueMutableBuffer( newCount: Int, requiredCapacity: Int ) -> _ContiguousArrayBuffer { return _forceCreateUniqueMutableBufferImpl( countForBuffer: newCount, minNewCapacity: newCount, requiredCapacity: requiredCapacity) } /// Create a unique mutable buffer that has enough capacity to hold /// 'minNewCapacity' elements and set the count of the new buffer to /// 'countForNewBuffer'. The content of the buffer uninitialized. /// The formula used to compute the new buffers capacity is: /// max(minNewCapacity, source.capacity) if minNewCapacity <= source.capacity /// max(minNewCapacity, _growArrayCapacity(source.capacity)) otherwise @inline(never) @inlinable // @specializable internal func _forceCreateUniqueMutableBuffer( countForNewBuffer: Int, minNewCapacity: Int ) -> _ContiguousArrayBuffer { return _forceCreateUniqueMutableBufferImpl( countForBuffer: countForNewBuffer, minNewCapacity: minNewCapacity, requiredCapacity: minNewCapacity) } /// Create a unique mutable buffer that has enough capacity to hold /// 'minNewCapacity' elements and at least 'requiredCapacity' elements and set /// the count of the new buffer to 'countForBuffer'. The content of the buffer /// uninitialized. /// The formula used to compute the new capacity is: /// max(requiredCapacity, source.capacity) if minNewCapacity <= source.capacity /// max(requiredCapacity, _growArrayCapacity(source.capacity)) otherwise @inlinable internal func _forceCreateUniqueMutableBufferImpl( countForBuffer: Int, minNewCapacity: Int, requiredCapacity: Int ) -> _ContiguousArrayBuffer { _internalInvariant(countForBuffer >= 0) _internalInvariant(requiredCapacity >= countForBuffer) _internalInvariant(minNewCapacity >= countForBuffer) let minimumCapacity = Swift.max(requiredCapacity, minNewCapacity > capacity ? _growArrayCapacity(capacity) : capacity) return _ContiguousArrayBuffer( _uninitializedCount: countForBuffer, minimumCapacity: minimumCapacity) } } extension _ArrayBufferProtocol { /// 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. @inline(never) @inlinable // @specializable internal mutating func _arrayOutOfPlaceUpdate( _ dest: inout _ContiguousArrayBuffer, _ headCount: Int, // Count of initial source elements to copy/move _ newCount: Int, // Number of new elements to insert _ initializeNewElements: ((UnsafeMutablePointer, _ count: Int) -> ()) = { ptr, count in _internalInvariant(count == 0) } ) { _internalInvariant(headCount >= 0) _internalInvariant(newCount >= 0) // Count of trailing source elements to copy/move let sourceCount = self.count let tailCount = dest.count - headCount - newCount _internalInvariant(headCount + tailCount <= sourceCount) let oldCount = sourceCount - headCount - tailCount let destStart = unsafe dest.firstElementAddress let newStart = unsafe destStart + headCount let newEnd = unsafe newStart + newCount // Check to see if we have storage we can move from if let backing = requestUniqueMutableBackingBuffer( minimumCapacity: sourceCount) { let sourceStart = unsafe firstElementAddress let oldStart = unsafe sourceStart + headCount // Destroy any items that may be lurking in a _SliceBuffer before // its real first element let backingStart = unsafe backing.firstElementAddress let sourceOffset = unsafe sourceStart - backingStart unsafe backingStart.deinitialize(count: sourceOffset) // Move the head items unsafe destStart.moveInitialize(from: sourceStart, count: headCount) // Destroy unused source items unsafe oldStart.deinitialize(count: oldCount) unsafe initializeNewElements(newStart, newCount) // Move the tail items unsafe newEnd.moveInitialize(from: oldStart + oldCount, count: tailCount) // Destroy any items that may be lurking in a _SliceBuffer after // its real last element let backingEnd = unsafe backingStart + backing.count let sourceEnd = unsafe sourceStart + sourceCount unsafe sourceEnd.deinitialize(count: backingEnd - sourceEnd) backing.count = 0 } else { let headStart = startIndex let headEnd = headStart + headCount let newStart = unsafe _copyContents( subRange: headStart..( _ newItems: __owned S ) where S.Element == Element { // this function is only ever called from append(contentsOf:) // which should always have exhausted its capacity before calling _internalInvariant(count == capacity) var newCount = self.count // there might not be any elements to append remaining, // so check for nil element first, then increase capacity, // then inner-loop to fill that capacity with elements var stream = newItems.makeIterator() var nextItem = stream.next() while nextItem != nil { // grow capacity, first time around and when filled var newBuffer = _forceCreateUniqueMutableBuffer( countForNewBuffer: newCount, // minNewCapacity handles the exponential growth, just // need to request 1 more than current count/capacity minNewCapacity: newCount + 1) unsafe _arrayOutOfPlaceUpdate(&newBuffer, newCount, 0) let currentCapacity = self.capacity let base = unsafe self.firstElementAddress // fill while there is another item and spare capacity while let next = nextItem, newCount < currentCapacity { unsafe (base + newCount).initialize(to: next) newCount += 1 nextItem = stream.next() } self.count = newCount } } }