mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
193 lines
5.5 KiB
Swift
193 lines
5.5 KiB
Swift
//===--- Join.swift - Protocol and Algorithm for concatenation ------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
internal enum _JoinGeneratorState {
|
|
case Start
|
|
case GeneratingElements
|
|
case GeneratingSeparator
|
|
case End
|
|
}
|
|
|
|
/// A generator that presents the elements of the sequences generated
|
|
/// by `Base`, concatenated using a given separator.
|
|
public struct JoinGenerator<
|
|
Base : GeneratorType where Base.Element : SequenceType
|
|
> : GeneratorType {
|
|
|
|
/// Creates a generator that presents the elements of the sequences
|
|
/// generated by `base`, concatenated using `separator`.
|
|
///
|
|
/// - Complexity: O(`separator.count`).
|
|
public init<
|
|
Separator : SequenceType
|
|
where
|
|
Separator.Generator.Element == Base.Element.Generator.Element
|
|
>(base: Base, separator: Separator) {
|
|
self._base = base
|
|
self._separatorData = ContiguousArray(separator)
|
|
}
|
|
|
|
/// Advance to the next element and return it, or `nil` if no next
|
|
/// element exists.
|
|
public mutating func next() -> Base.Element.Generator.Element? {
|
|
repeat {
|
|
switch _state {
|
|
case .Start:
|
|
if let nextSubSequence = _base.next() {
|
|
_inner = nextSubSequence.generate()
|
|
_state = .GeneratingElements
|
|
} else {
|
|
_state = .End
|
|
return nil
|
|
}
|
|
|
|
case .GeneratingElements:
|
|
let result = _inner!.next()
|
|
if _fastPath(result != nil) {
|
|
return result
|
|
}
|
|
if _separatorData.isEmpty {
|
|
_inner = _base.next()?.generate()
|
|
if _inner == nil {
|
|
_state = .End
|
|
return nil
|
|
}
|
|
} else {
|
|
_inner = _base.next()?.generate()
|
|
if _inner == nil {
|
|
_state = .End
|
|
return nil
|
|
}
|
|
_separator = _separatorData.generate()
|
|
_state = .GeneratingSeparator
|
|
}
|
|
|
|
case .GeneratingSeparator:
|
|
let result = _separator!.next()
|
|
if _fastPath(result != nil) {
|
|
return result
|
|
}
|
|
_state = .GeneratingElements
|
|
|
|
case .End:
|
|
return nil
|
|
|
|
}
|
|
}
|
|
while true
|
|
}
|
|
|
|
internal var _base: Base
|
|
internal var _inner: Base.Element.Generator? = nil
|
|
internal var _separatorData: ContiguousArray<Base.Element.Generator.Element>
|
|
internal var _separator: ContiguousArray<Base.Element.Generator.Element>.Generator?
|
|
internal var _state: _JoinGeneratorState = .Start
|
|
}
|
|
|
|
/// A sequence that presents the elements of the `Base` sequences
|
|
/// concatenated using a given separator.
|
|
public struct JoinSequence<
|
|
Base : SequenceType where Base.Generator.Element : SequenceType
|
|
> : SequenceType {
|
|
|
|
/// Creates a sequence that presents the elements of `base` sequences
|
|
/// concatenated using `separator`.
|
|
///
|
|
/// - Complexity: O(`separator.count`).
|
|
public init<
|
|
Separator : SequenceType
|
|
where
|
|
Separator.Generator.Element ==
|
|
Base.Generator.Element.Generator.Element
|
|
>(base: Base, separator: Separator) {
|
|
self._base = base
|
|
self._separator = ContiguousArray(separator)
|
|
}
|
|
|
|
/// Returns a generator over the elements of this sequence.
|
|
///
|
|
/// - Complexity: O(1).
|
|
public func generate() -> JoinGenerator<Base.Generator> {
|
|
return JoinGenerator(
|
|
base: _base.generate(),
|
|
separator: _separator)
|
|
}
|
|
|
|
public func _copyToNativeArrayBuffer()
|
|
-> _ContiguousArrayBuffer<Base.Generator.Element.Generator.Element> {
|
|
var result = ContiguousArray<Generator.Element>()
|
|
let separatorSize: Int = numericCast(_separator.count)
|
|
|
|
let reservation = _base._preprocessingPass {
|
|
() -> Int in
|
|
var r = 0
|
|
for chunk in _base {
|
|
r += separatorSize + chunk.underestimateCount()
|
|
}
|
|
return r - separatorSize
|
|
}
|
|
|
|
if let n = reservation {
|
|
result.reserveCapacity(numericCast(n))
|
|
}
|
|
|
|
if separatorSize != 0 {
|
|
var gen = _base.generate()
|
|
if let first = gen.next() {
|
|
result.appendContentsOf(first)
|
|
while let next = gen.next() {
|
|
result.appendContentsOf(_separator)
|
|
result.appendContentsOf(next)
|
|
}
|
|
}
|
|
} else {
|
|
for x in _base {
|
|
result.appendContentsOf(x)
|
|
}
|
|
}
|
|
|
|
return result._buffer
|
|
}
|
|
|
|
internal var _base: Base
|
|
internal var _separator:
|
|
ContiguousArray<Base.Generator.Element.Generator.Element>
|
|
}
|
|
|
|
extension SequenceType where Generator.Element : SequenceType {
|
|
/// Returns a view, whose elements are the result of interposing a given
|
|
/// `separator` between the elements of the sequence `self`.
|
|
///
|
|
/// For example,
|
|
/// `[[1, 2, 3], [4, 5, 6], [7, 8, 9]].joinWithSeparator([-1, -2])`
|
|
/// yields `[1, 2, 3, -1, -2, 4, 5, 6, -1, -2, 7, 8, 9]`.
|
|
@warn_unused_result
|
|
public func joinWithSeparator<
|
|
Separator : SequenceType
|
|
where
|
|
Separator.Generator.Element == Generator.Element.Generator.Element
|
|
>(separator: Separator) -> JoinSequence<Self> {
|
|
return JoinSequence(base: self, separator: separator)
|
|
}
|
|
}
|
|
|
|
@available(*, unavailable, message="call the 'joinWithSeparator()' method on the sequence of elements")
|
|
public func join<
|
|
C : RangeReplaceableCollectionType, S : SequenceType
|
|
where S.Generator.Element == C
|
|
>(
|
|
separator: C, _ elements: S
|
|
) -> C {
|
|
fatalError("unavailable function can't be called")
|
|
}
|
|
|