Skip to content

Instantly share code, notes, and snippets.

@dennisvennink
Last active November 20, 2017 09:22
Show Gist options
  • Save dennisvennink/1c0aac76dc7a145f64787ed23246b4e4 to your computer and use it in GitHub Desktop.
Save dennisvennink/1c0aac76dc7a145f64787ed23246b4e4 to your computer and use it in GitHub Desktop.
/// The iterator for `LazyAppendSequence`.
public struct LazyAppendIterator <BaseIterator1: IteratorProtocol, BaseIterator2: IteratorProtocol>: IteratorProtocol
where BaseIterator1.Element == BaseIterator2.Element {
public typealias Element = BaseIterator1.Element
private var baseIterator1: BaseIterator1
private var baseIterator2: BaseIterator2
private var reachedEndOfBaseIterator1 = false
private var reachedEnd = false
internal init (_ baseIterator1: BaseIterator1, _ baseIterator2: BaseIterator2) {
self.baseIterator1 = baseIterator1
self.baseIterator2 = baseIterator2
}
public mutating func next () -> Element? {
if self.reachedEnd {
return nil
}
var next: Element?
if !self.reachedEndOfBaseIterator1 {
next = self.baseIterator1.next()
if next == nil {
self.reachedEndOfBaseIterator1 = true
}
}
if next == nil {
next = self.baseIterator2.next()
if next == nil {
self.reachedEnd = true
}
}
return next
}
}
/// A lazily evaluated `Sequence` containing the elements of the right-hand base `Sequence` appended to the elements
/// of the left-hand base `Sequence`.
///
/// - Attention: To create an instance of `LazyAppendSequence`, use the `++(_:_:)` operator.
public struct LazyAppendSequence <BaseSequence1: Sequence, BaseSequence2: Sequence>: LazySequenceProtocol
where BaseSequence1.Iterator.Element == BaseSequence2.Iterator.Element {
public typealias Iterator = LazyAppendIterator<BaseSequence1.Iterator, BaseSequence2.Iterator>
public typealias Element = Iterator.Element
internal let baseSequence1: BaseSequence1
internal let baseSequence2: BaseSequence2
internal init (_ baseSequence1: BaseSequence1, _ baseSequence2: BaseSequence2) {
self.baseSequence1 = baseSequence1
self.baseSequence2 = baseSequence2
}
public func makeIterator () -> Iterator {
return Iterator(self.baseSequence1.makeIterator(), self.baseSequence2.makeIterator())
}
}
infix operator ++
/// Creates a lazily evaluated `Sequence` that appends the right-hand base `Sequence` to the left-hand base `Sequence`.
///
/// print(Array([1, 2] ++ [3, 4]))
/// // Prints "[1, 2, 3, 4]".
///
/// - Attention:
/// - If the left-hand base `Sequence` is infinite, the result is the left-hand base `Sequence`.
/// - Unlike `+(_:_:)`, `++(_:_:)` guarantees to return a lazy `Sequence`.
/// - Parameters:
/// - lhs: The left-hand base `Sequence`.
/// - rhs: The right-hand base `Sequence`.
/// - Returns: A lazily evaluated `Sequence` containing the elements from the right-hand base `Sequence` appended to
/// the elements of the left-hand base `Sequence`.
public func ++ <BaseSequence1: Sequence, BaseSequence2: Sequence> (lhs: BaseSequence1, rhs: BaseSequence2) ->
LazyAppendSequence<BaseSequence1, BaseSequence2> {
return LazyAppendSequence(lhs, rhs)
}
import XCTest
@testable import SequenceExtensions
/// - Note: Since `++(_:_:)` is a newly defined operator without any overloads we only check the type and value for the
/// base `Sequence`.
class AppendTests: XCTestCase {
let baseSequence = sequence(first: 0, next: {
if $0 < 2 {
return $0 + 1
}
return nil
})
typealias BaseSequence = UnfoldSequence<Int, (Int?, Bool)>
func testShouldReturnCorrectType () {
XCTAssertTrue(type(of: self.baseSequence ++ self.baseSequence) == LazyAppendSequence<BaseSequence, BaseSequence>
.self)
}
func testShouldReturnCorrectValue () {
XCTAssertEqual(Array(self.baseSequence ++ self.baseSequence), [0, 1, 2, 0, 1, 2])
XCTAssertEqual(Array(self.baseSequence ++ [Int]()), [0, 1, 2])
XCTAssertEqual(Array([Int]() ++ self.baseSequence), [0, 1, 2])
XCTAssertEqual(Array([Int]() ++ [Int]()), [])
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment