//===--- 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 internal var _separator: ContiguousArray.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 { return JoinGenerator( base: _base.generate(), separator: _separator) } public func _copyToNativeArrayBuffer() -> _ContiguousArrayBuffer { var result = ContiguousArray() 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 } 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 { 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") }