mirror of
https://github.com/apple/swift.git
synced 2026-06-20 15:42:51 +02:00
70360f3888
This reverts commit dcd214065f.
228 lines
8.0 KiB
Swift
228 lines
8.0 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2026 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// A dynamically self-resizing, heap allocated, noncopyable array of
|
|
/// potentially noncopyable elements.
|
|
///
|
|
/// `UniqueArray` instances automatically resize their underlying storage as
|
|
/// needed to accommodate newly inserted items, using a geometric growth curve.
|
|
/// This lets code using `UniqueArray` avoid having to allocate enough
|
|
/// capacity in advance; on the other hand, it makes it difficult to tell
|
|
/// when and where such reallocations may happen.
|
|
///
|
|
/// For example, appending an element to a `UniqueArray` has highly variable
|
|
/// complexity; often, it runs at a constant cost, but if the operation has to
|
|
/// resize storage, then the cost of an individual append suddenly becomes
|
|
/// proportional to the size of the whole array.
|
|
///
|
|
/// The geometric growth curve allows the cost of such latency spikes to
|
|
/// get amortized across repeated invocations, bringing the average cost back
|
|
/// to O(1); but the spikes make this construct less suitable for use cases that
|
|
/// expect predictable, consistent performance on every operation.
|
|
///
|
|
/// Implicit growth also makes it more difficult to predict/analyze the amount
|
|
/// of memory an algorithm would need. Developers targeting environments with
|
|
/// stringent limits on heap allocations may prefer to avoid using dynamically
|
|
/// resizing container types as a matter of policy. The type `RigidArray` provides
|
|
/// a fixed-capacity array variant that caters specifically for these use cases,
|
|
/// trading ease-of-use for more consistent/predictable execution.
|
|
/// For copyable elements, the copy-on-write `Array` type is an
|
|
/// even more convenient and expressive choice.
|
|
@available(SwiftStdlib 6.4, *)
|
|
@frozen
|
|
public struct UniqueArray<Element: ~Copyable>: ~Copyable {
|
|
@usableFromInline
|
|
internal var _storage: _RigidArray<Element>
|
|
|
|
@_alwaysEmitIntoClient
|
|
internal init(_storage: consuming _RigidArray<Element>) {
|
|
self._storage = _storage
|
|
}
|
|
}
|
|
|
|
@available(SwiftStdlib 6.4, *)
|
|
extension UniqueArray: Sendable where Element: Sendable & ~Copyable {}
|
|
|
|
@available(SwiftStdlib 6.4, *)
|
|
extension UniqueArray where Element: ~Copyable {
|
|
/// The maximum number of elements this array can hold without having to
|
|
/// reallocate its storage.
|
|
///
|
|
/// - Complexity: O(1)
|
|
@available(SwiftStdlib 6.4, *)
|
|
@_alwaysEmitIntoClient
|
|
@_transparent
|
|
public var capacity: Int {
|
|
_assumeNonNegative(_storage.capacity)
|
|
}
|
|
|
|
/// The number of additional elements that can be added to this array without
|
|
/// reallocating its storage.
|
|
///
|
|
/// - Complexity: O(1)
|
|
@available(SwiftStdlib 6.4, *)
|
|
@_alwaysEmitIntoClient
|
|
@_transparent
|
|
public var freeCapacity: Int {
|
|
_assumeNonNegative(_storage.capacity &- _storage.count)
|
|
}
|
|
}
|
|
|
|
@available(SwiftStdlib 6.4, *)
|
|
extension UniqueArray where Element: ~Copyable {
|
|
/// A span over the elements of this array, providing direct read-only access.
|
|
///
|
|
/// - Complexity: O(1)
|
|
@available(SwiftStdlib 6.4, *)
|
|
@_alwaysEmitIntoClient
|
|
public var span: Span<Element> {
|
|
@_lifetime(borrow self)
|
|
@_transparent
|
|
get {
|
|
_storage.span
|
|
}
|
|
}
|
|
|
|
/// A mutable span over the elements of this array, providing direct
|
|
/// mutating access.
|
|
///
|
|
/// - Complexity: O(1)
|
|
@available(SwiftStdlib 6.4, *)
|
|
@_alwaysEmitIntoClient
|
|
public var mutableSpan: MutableSpan<Element> {
|
|
@_lifetime(&self)
|
|
@_transparent
|
|
mutating get {
|
|
_storage.mutableSpan
|
|
}
|
|
}
|
|
}
|
|
|
|
@available(SwiftStdlib 6.4, *)
|
|
extension UniqueArray where Element: ~Copyable {
|
|
/// Arbitrarily edit the storage underlying this array by invoking a
|
|
/// user-supplied closure with a mutable `OutputSpan` view over it.
|
|
/// This method calls its function argument at most once, allowing it to
|
|
/// arbitrarily modify the contents of the output span it is given.
|
|
/// The argument is free to add, remove or reorder any items; however,
|
|
/// it is not allowed to replace the span or change its capacity.
|
|
///
|
|
/// When the function argument finishes (whether by returning or throwing an
|
|
/// error) the rigid array instance is updated to match the final contents of
|
|
/// the output span.
|
|
///
|
|
/// - Parameter body: A function that edits the contents of this array through
|
|
/// an `OutputSpan` argument. This method invokes this function
|
|
/// at most once.
|
|
/// - Returns: This method returns the result of its function argument.
|
|
/// - Complexity: Adds O(1) overhead to the complexity of the function
|
|
/// argument.
|
|
@available(SwiftStdlib 6.4, *)
|
|
@_alwaysEmitIntoClient
|
|
@_transparent
|
|
public mutating func edit<E: Error, R: ~Copyable>(
|
|
_ body: (inout OutputSpan<Element>) throws(E) -> R
|
|
) throws(E) -> R {
|
|
try _storage.edit(body)
|
|
}
|
|
}
|
|
|
|
@_alwaysEmitIntoClient
|
|
@_transparent
|
|
internal func _growUniqueArrayCapacity(_ capacity: Int) -> Int {
|
|
// A growth factor of 1.5 seems like a reasonable compromise between
|
|
// over-allocating memory and wasting cycles on repeatedly resizing storage.
|
|
let c = (3 &* UInt(bitPattern: capacity) &+ 1) / 2
|
|
return Int(bitPattern: c)
|
|
}
|
|
|
|
@available(SwiftStdlib 6.4, *)
|
|
extension UniqueArray where Element: ~Copyable {
|
|
/// Grow or shrink the capacity of a unique array instance without discarding
|
|
/// its contents.
|
|
///
|
|
/// This operation replaces the array's storage buffer with a newly allocated
|
|
/// buffer of the specified capacity, moving all existing elements
|
|
/// to its new storage. The old storage is then deallocated.
|
|
///
|
|
/// - Parameter newCapacity: The desired new capacity. `newCapacity` must be
|
|
/// greater than or equal to the current count.
|
|
///
|
|
/// - Complexity: O(`count`)
|
|
@available(SwiftStdlib 6.4, *)
|
|
@_alwaysEmitIntoClient
|
|
public mutating func reallocate(capacity: Int) {
|
|
_storage.reallocate(capacity: capacity)
|
|
}
|
|
|
|
/// Ensure that the array has capacity to store the specified number of
|
|
/// elements, by growing its storage buffer if necessary.
|
|
///
|
|
/// If `capacity < n`, then this operation reallocates the unique array's
|
|
/// storage to grow it; on return, the array's capacity becomes `n`.
|
|
/// Otherwise the array is left as is.
|
|
///
|
|
/// - Complexity: O(`count`)
|
|
@available(SwiftStdlib 6.4, *)
|
|
@_alwaysEmitIntoClient
|
|
public mutating func reserveCapacity(_ n: Int) {
|
|
_storage.reserveCapacity(n)
|
|
}
|
|
|
|
@_alwaysEmitIntoClient
|
|
@_transparent
|
|
internal mutating func _ensureFreeCapacity(_ freeCapacity: Int) {
|
|
guard _storage.freeCapacity < freeCapacity else { return }
|
|
_ensureFreeCapacitySlow(freeCapacity)
|
|
}
|
|
|
|
@_alwaysEmitIntoClient
|
|
@_transparent
|
|
internal func _grow(freeCapacity: Int) -> Int {
|
|
Swift.max(
|
|
count &+ freeCapacity,
|
|
_growUniqueArrayCapacity(capacity))
|
|
}
|
|
|
|
@_alwaysEmitIntoClient
|
|
internal mutating func _ensureFreeCapacitySlow(_ freeCapacity: Int) {
|
|
let newCapacity = _grow(freeCapacity: freeCapacity)
|
|
reallocate(capacity: newCapacity)
|
|
}
|
|
}
|
|
|
|
@available(SwiftStdlib 6.4, *)
|
|
extension UniqueArray {
|
|
/// Copy the contents of this array into a newly allocated unique array
|
|
/// instance with just enough capacity to hold all its elements.
|
|
///
|
|
/// - Complexity: O(`count`)
|
|
@available(SwiftStdlib 6.4, *)
|
|
@_alwaysEmitIntoClient
|
|
public func clone() -> Self {
|
|
UniqueArray(consuming: _storage.clone())
|
|
}
|
|
|
|
/// Copy the contents of this array into a newly allocated unique array
|
|
/// instance with the specified capacity.
|
|
///
|
|
/// - Parameter capacity: The desired capacity of the resulting unique array.
|
|
/// `capacity` must be greater than or equal to `count`.
|
|
///
|
|
/// - Complexity: O(`count`)
|
|
@available(SwiftStdlib 6.4, *)
|
|
@_alwaysEmitIntoClient
|
|
public func clone(capacity: Int) -> Self {
|
|
UniqueArray(consuming: _storage.clone(capacity: capacity))
|
|
}
|
|
}
|