mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
- index(_:stepsFrom:limitedBy:) returns Index? - formIndex(_:stepsFrom:limitedBy) returns Bool
391 lines
14 KiB
Plaintext
391 lines
14 KiB
Plaintext
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2016 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
%{
|
|
|
|
from gyb_stdlib_support import (
|
|
TRAVERSALS,
|
|
collectionForTraversal,
|
|
sliceTypeName,
|
|
protocolsForCollectionFeatures
|
|
)
|
|
|
|
def get_slice_doc_comment(Self):
|
|
return """\
|
|
/// A view into a sub-sequence of elements of another collection.
|
|
///
|
|
/// A `%s` instance stores the base collection, the start and end indices of
|
|
/// the view. It does not copy the elements from the collection into separate
|
|
/// storage. Thus, creating a slice has `O(1)` complexity.
|
|
///
|
|
/// A `%s` instance inherits the value or reference semantics of the base
|
|
/// collection. That is, if a `%s` instance is wrapped around a mutable
|
|
/// collection that has value semantics (for example, `Array`), mutating the
|
|
/// original collection would not affect the copy stored inside of the slice.
|
|
///
|
|
/// An element of a slice is located under the same index in the slice and in
|
|
/// the base collection, as long as neither the collection or the slice were
|
|
/// mutated. Thus, indices of a slice can be used interchangeably with indices
|
|
/// of the base collection.
|
|
///
|
|
/// - Warning: Long-term storage of `%s` instances is discouraged.
|
|
///
|
|
/// Because a `%s` presents a *view* onto the storage of some larger
|
|
/// collection even after the original collection goes out of scope, 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 slices only for transient computation.\
|
|
""" % (Self, Self, Self, Self, Self)
|
|
}%
|
|
|
|
// FIXME(ABI)(compiler limitation): There should be just one slice type
|
|
// that has conditional conformances to `BidirectionalCollection`,
|
|
// `RandomAccessCollection`, `RangeReplaceableCollection`, and
|
|
// `MutableCollection`.
|
|
|
|
% for Traversal in TRAVERSALS:
|
|
% for Mutable in [ False, True ]:
|
|
% for RangeReplaceable in [ False, True ]:
|
|
% Self = sliceTypeName(traversal=Traversal, mutable=Mutable, rangeReplaceable=RangeReplaceable)
|
|
% BaseRequirements = [collectionForTraversal(Traversal).replace('Collection', 'Indexable')]
|
|
% if Mutable:
|
|
% BaseRequirements.append('MutableIndexable')
|
|
% if RangeReplaceable:
|
|
% BaseRequirements.append('RangeReplaceableIndexable')
|
|
% BaseRequirements = 'protocol<' + ', '.join(BaseRequirements) + '>'
|
|
% SelfProtocols = ', '.join(protocolsForCollectionFeatures(traversal=Traversal, mutable=Mutable, rangeReplaceable=RangeReplaceable))
|
|
|
|
${get_slice_doc_comment(Self)}
|
|
% if Mutable:
|
|
///
|
|
/// - Warning: `${Self}` requires the setter of `Base.subscript(_: Index)`
|
|
/// to not invalidate indices. If you are writing a collection and mutations
|
|
/// need to invalidate indices, don't use `${Self}`, use `Slice` or
|
|
/// define your own `Base.SubSequence` type that takes that into account.
|
|
% end
|
|
public struct ${Self}<Base : ${BaseRequirements}>
|
|
: ${SelfProtocols} {
|
|
|
|
public typealias Index = Base.Index
|
|
public typealias IndexDistance = Base.IndexDistance
|
|
|
|
public var _startIndex: Index
|
|
public var _endIndex: Index
|
|
|
|
public var startIndex: Index {
|
|
return _startIndex
|
|
}
|
|
|
|
public var endIndex: Index {
|
|
return _endIndex
|
|
}
|
|
|
|
public subscript(index: Index) -> Base._Element {
|
|
get {
|
|
_failEarlyRangeCheck(index, bounds: startIndex..<endIndex)
|
|
return _base[index]
|
|
}
|
|
% if Mutable:
|
|
set {
|
|
_failEarlyRangeCheck(index, bounds: startIndex..<endIndex)
|
|
_base[index] = newValue
|
|
// MutableSlice requires that the underlying collection's subscript
|
|
// setter does not invalidate indices, so our `startIndex` and `endIndex`
|
|
// continue to be valid.
|
|
}
|
|
% end
|
|
}
|
|
|
|
public typealias SubSequence = ${Self}<Base>
|
|
|
|
public subscript(bounds: Range<Index>) -> ${Self}<Base> {
|
|
get {
|
|
_failEarlyRangeCheck(bounds, bounds: startIndex..<endIndex)
|
|
return ${Self}(base: _base, bounds: bounds)
|
|
}
|
|
% if Mutable:
|
|
set {
|
|
_writeBackMutableSlice(&self, bounds: bounds, slice: newValue)
|
|
}
|
|
% end
|
|
}
|
|
|
|
// FIXME(ABI)(compiler limitation):
|
|
//
|
|
// public typealias Indices = Base.Indices
|
|
// public var indices: Indices { ... }
|
|
//
|
|
// We can't do it right now because we don't have enough
|
|
// constraints on the Base.Indices type in this context.
|
|
|
|
@warn_unused_result
|
|
public func successor(of i: Index) -> Index {
|
|
// FIXME: swift-3-indexing-model: range check.
|
|
return _base.successor(of: i)
|
|
}
|
|
|
|
public func formSuccessor(i: inout Index) {
|
|
// FIXME: swift-3-indexing-model: range check.
|
|
_base.formSuccessor(&i)
|
|
}
|
|
|
|
% if Traversal in ['Bidirectional', 'RandomAccess']:
|
|
@warn_unused_result
|
|
public func predecessor(of i: Index) -> Index {
|
|
// FIXME: swift-3-indexing-model: range check.
|
|
return _base.predecessor(of: i)
|
|
}
|
|
|
|
public func formPredecessor(i: inout Index) {
|
|
// FIXME: swift-3-indexing-model: range check.
|
|
_base.formPredecessor(&i)
|
|
}
|
|
% end
|
|
|
|
@warn_unused_result
|
|
public func index(n: IndexDistance, stepsFrom i: Index) -> Index {
|
|
// FIXME: swift-3-indexing-model: range check.
|
|
return _base.index(n, stepsFrom: i)
|
|
}
|
|
|
|
@warn_unused_result
|
|
public func index(
|
|
n: IndexDistance, stepsFrom i: Index, limitedBy limit: Index
|
|
) -> Index? {
|
|
// FIXME: swift-3-indexing-model: range check.
|
|
return _base.index(n, stepsFrom: i, limitedBy: limit)
|
|
}
|
|
|
|
@warn_unused_result
|
|
public func distance(from start: Index, to end: Index) -> IndexDistance {
|
|
// FIXME: swift-3-indexing-model: range check.
|
|
return _base.distance(from: start, to: end)
|
|
}
|
|
|
|
public func _failEarlyRangeCheck(index: Index, bounds: Range<Index>) {
|
|
_base._failEarlyRangeCheck(index, bounds: bounds)
|
|
}
|
|
|
|
public func _failEarlyRangeCheck(range: Range<Index>, bounds: Range<Index>) {
|
|
_base._failEarlyRangeCheck(range, bounds: bounds)
|
|
}
|
|
|
|
% if RangeReplaceable:
|
|
public init() {
|
|
self._base = Base()
|
|
self._startIndex = _base.startIndex
|
|
self._endIndex = _base.endIndex
|
|
}
|
|
|
|
public init(repeating repeatedValue: Base._Element, count: Int) {
|
|
self._base = Base(repeating: repeatedValue, count: count)
|
|
self._startIndex = _base.startIndex
|
|
self._endIndex = _base.endIndex
|
|
}
|
|
|
|
public init<
|
|
S : Sequence where S.Iterator.Element == Base._Element
|
|
>(_ elements: S) {
|
|
self._base = Base(elements)
|
|
self._startIndex = _base.startIndex
|
|
self._endIndex = _base.endIndex
|
|
}
|
|
|
|
public mutating func replaceSubrange<
|
|
C : Collection where C.Iterator.Element == Base._Element
|
|
>(
|
|
subRange: Range<Index>, with newElements: C
|
|
) {
|
|
// FIXME: swift-3-indexing-model: range check.
|
|
% if Traversal == 'Forward':
|
|
let sliceOffset: IndexDistance =
|
|
_base.distance(from: _base.startIndex, to: _startIndex)
|
|
let newSliceCount: IndexDistance =
|
|
_base.distance(from: _startIndex, to: subRange.lowerBound)
|
|
+ _base.distance(from: subRange.upperBound, to: _endIndex)
|
|
+ numericCast(newElements.count)
|
|
_base.replaceSubrange(subRange, with: newElements)
|
|
_startIndex = _base.index(sliceOffset, stepsFrom: _base.startIndex)
|
|
_endIndex = _base.index(newSliceCount, stepsFrom: _startIndex)
|
|
% else:
|
|
if subRange.lowerBound == _base.startIndex {
|
|
let newSliceCount: IndexDistance =
|
|
_base.distance(from: _startIndex, to: subRange.lowerBound)
|
|
+ _base.distance(from: subRange.upperBound, to: _endIndex)
|
|
+ numericCast(newElements.count)
|
|
_base.replaceSubrange(subRange, with: newElements)
|
|
_startIndex = _base.startIndex
|
|
_endIndex = _base.index(newSliceCount, stepsFrom: _startIndex)
|
|
} else {
|
|
let shouldUpdateStartIndex = subRange.lowerBound == _startIndex
|
|
let lastValidIndex = _base.predecessor(of: subRange.lowerBound)
|
|
let newEndIndexOffset =
|
|
_base.distance(from: subRange.upperBound, to: _endIndex)
|
|
+ numericCast(newElements.count) + 1
|
|
_base.replaceSubrange(subRange, with: newElements)
|
|
if shouldUpdateStartIndex {
|
|
_startIndex = _base.successor(of: lastValidIndex)
|
|
}
|
|
_endIndex = _base.index(newEndIndexOffset, stepsFrom: lastValidIndex)
|
|
}
|
|
% end
|
|
}
|
|
|
|
public mutating func insert(newElement: Base._Element, at i: Index) {
|
|
// FIXME: swift-3-indexing-model: range check.
|
|
% if Traversal == 'Forward':
|
|
let sliceOffset: IndexDistance =
|
|
_base.distance(from: _base.startIndex, to: _startIndex)
|
|
let newSliceCount: IndexDistance = count + 1
|
|
_base.insert(newElement, at: i)
|
|
_startIndex = _base.index(sliceOffset, stepsFrom: _base.startIndex)
|
|
_endIndex = _base.index(newSliceCount, stepsFrom: _startIndex)
|
|
% else:
|
|
if i == _base.startIndex {
|
|
let newSliceCount: IndexDistance = count + 1
|
|
_base.insert(newElement, at: i)
|
|
_startIndex = _base.startIndex
|
|
_endIndex = _base.index(newSliceCount, stepsFrom: _startIndex)
|
|
} else {
|
|
let shouldUpdateStartIndex = i == _startIndex
|
|
let lastValidIndex = _base.predecessor(of: i)
|
|
let newEndIndexOffset = _base.distance(from: i, to: _endIndex) + 2
|
|
_base.insert(newElement, at: i)
|
|
if shouldUpdateStartIndex {
|
|
_startIndex = _base.successor(of: lastValidIndex)
|
|
}
|
|
_endIndex = _base.index(newEndIndexOffset, stepsFrom: lastValidIndex)
|
|
}
|
|
% end
|
|
}
|
|
|
|
public mutating func insert<
|
|
S : Collection where S.Iterator.Element == Base._Element
|
|
>(contentsOf newElements: S, at i: Index) {
|
|
// FIXME: swift-3-indexing-model: range check.
|
|
% if Traversal == 'Forward':
|
|
let sliceOffset: IndexDistance =
|
|
_base.distance(from: _base.startIndex, to: _startIndex)
|
|
let newSliceCount: IndexDistance =
|
|
count + numericCast(newElements.count)
|
|
_base.insert(contentsOf: newElements, at: i)
|
|
_startIndex = _base.index(sliceOffset, stepsFrom: _base.startIndex)
|
|
_endIndex = _base.index(newSliceCount, stepsFrom: _startIndex)
|
|
% else:
|
|
if i == _base.startIndex {
|
|
let newSliceCount: IndexDistance =
|
|
count + numericCast(newElements.count)
|
|
_base.insert(contentsOf: newElements, at: i)
|
|
_startIndex = _base.startIndex
|
|
_endIndex = _base.index(newSliceCount, stepsFrom: _startIndex)
|
|
} else {
|
|
let shouldUpdateStartIndex = i == _startIndex
|
|
let lastValidIndex = _base.predecessor(of: i)
|
|
let newEndIndexOffset =
|
|
_base.distance(from: i, to: _endIndex)
|
|
+ numericCast(newElements.count) + 1
|
|
_base.insert(contentsOf: newElements, at: i)
|
|
if shouldUpdateStartIndex {
|
|
_startIndex = _base.successor(of: lastValidIndex)
|
|
}
|
|
_endIndex = _base.index(newEndIndexOffset, stepsFrom: lastValidIndex)
|
|
}
|
|
% end
|
|
}
|
|
|
|
public mutating func remove(at i: Index) -> Base._Element {
|
|
// FIXME: swift-3-indexing-model: range check.
|
|
% if Traversal == 'Forward':
|
|
let sliceOffset: IndexDistance =
|
|
_base.distance(from: _base.startIndex, to: _startIndex)
|
|
let newSliceCount: IndexDistance = count - 1
|
|
let result = _base.remove(at: i)
|
|
_startIndex = _base.index(sliceOffset, stepsFrom: _base.startIndex)
|
|
_endIndex = _base.index(newSliceCount, stepsFrom: _startIndex)
|
|
return result
|
|
% else:
|
|
if i == _base.startIndex {
|
|
let newSliceCount: IndexDistance = count - 1
|
|
let result = _base.remove(at: i)
|
|
_startIndex = _base.startIndex
|
|
_endIndex = _base.index(newSliceCount, stepsFrom: _startIndex)
|
|
return result
|
|
} else {
|
|
let shouldUpdateStartIndex = i == _startIndex
|
|
let lastValidIndex = _base.predecessor(of: i)
|
|
let newEndIndexOffset = _base.distance(from: i, to: _endIndex)
|
|
let result = _base.remove(at: i)
|
|
if shouldUpdateStartIndex {
|
|
_startIndex = _base.successor(of: lastValidIndex)
|
|
}
|
|
_endIndex = _base.index(newEndIndexOffset, stepsFrom: lastValidIndex)
|
|
return result
|
|
}
|
|
% end
|
|
}
|
|
|
|
public mutating func removeSubrange(bounds: Range<Index>) {
|
|
// FIXME: swift-3-indexing-model: range check.
|
|
% if Traversal == 'Forward':
|
|
let sliceOffset: IndexDistance =
|
|
_base.distance(from: _base.startIndex, to: _startIndex)
|
|
let newSliceCount: IndexDistance =
|
|
count - distance(from: bounds.lowerBound, to: bounds.upperBound)
|
|
_base.removeSubrange(bounds)
|
|
_startIndex = _base.index(sliceOffset, stepsFrom: _base.startIndex)
|
|
_endIndex = _base.index(newSliceCount, stepsFrom: _startIndex)
|
|
% else:
|
|
if bounds.lowerBound == _base.startIndex {
|
|
let newSliceCount: IndexDistance =
|
|
count
|
|
- _base.distance(from: bounds.lowerBound, to: bounds.upperBound)
|
|
_base.removeSubrange(bounds)
|
|
_startIndex = _base.startIndex
|
|
_endIndex = _base.index(newSliceCount, stepsFrom: _startIndex)
|
|
} else {
|
|
let shouldUpdateStartIndex = bounds.lowerBound == _startIndex
|
|
let lastValidIndex = _base.predecessor(of: bounds.lowerBound)
|
|
let newEndIndexOffset =
|
|
_base.distance(from: bounds.lowerBound, to: _endIndex)
|
|
- _base.distance(from: bounds.lowerBound, to: bounds.upperBound)
|
|
+ 1
|
|
_base.removeSubrange(bounds)
|
|
if shouldUpdateStartIndex {
|
|
_startIndex = _base.successor(of: lastValidIndex)
|
|
}
|
|
_endIndex = _base.index(newEndIndexOffset, stepsFrom: lastValidIndex)
|
|
}
|
|
% end
|
|
}
|
|
% end
|
|
|
|
/// Create a view into collection `base` that allows access within `bounds`.
|
|
///
|
|
/// - Complexity: O(1).
|
|
public init(base: Base, bounds: Range<Index>) {
|
|
self._base = base
|
|
self._startIndex = bounds.lowerBound
|
|
self._endIndex = bounds.upperBound
|
|
}
|
|
|
|
% if Mutable or RangeReplaceable:
|
|
internal var _base: Base
|
|
% else:
|
|
internal let _base: Base
|
|
% end
|
|
}
|
|
|
|
% end
|
|
% end
|
|
% end
|
|
|