Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Guides/Chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ public func chain<S1, S2>(_ s1: S1, _ s2: S2) -> Chain2Sequence<S1, S2>
```

The resulting `Chain2Sequence` type is a sequence, with conditional conformance
to `Collection`, `BidirectionalCollection`, and `RandomAccessCollection` when
both the first and second arguments conform.
to `Collection`, `BidirectionalCollection`, `RandomAccessCollection`, and
`MutableCollection` when both the first and second arguments conform.

### Naming

Expand Down
35 changes: 33 additions & 2 deletions Sources/Algorithms/Chain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ public struct Chain2Sequence<Base1: Sequence, Base2: Sequence>
where Base1.Element == Base2.Element {
/// The first sequence in this chain.
@usableFromInline
internal let base1: Base1
internal var base1: Base1

/// The second sequence in this chain.
@usableFromInline
internal let base2: Base2
internal var base2: Base2

@inlinable
internal init(base1: Base1, base2: Base2) {
Expand Down Expand Up @@ -292,6 +292,37 @@ where Base1: BidirectionalCollection, Base2: BidirectionalCollection {
extension Chain2Sequence: RandomAccessCollection
where Base1: RandomAccessCollection, Base2: RandomAccessCollection {}

extension Chain2Sequence: MutableCollection
where Base1: MutableCollection, Base2: MutableCollection {
@inlinable
public subscript(i: Index) -> Base1.Element {
get {
switch i.position {
case .first(let i):
return base1[i]
case .second(let i):
return base2[i]
}
}
set {
switch i.position {
case .first(let i):
base1[i] = newValue
case .second(let i):
base2[i] = newValue
}
}
_modify {
switch i.position {
case .first(let i):
yield &base1[i]
case .second(let i):
yield &base2[i]
}
}
}
}

//===----------------------------------------------------------------------===//
// chain(_:_:)
//===----------------------------------------------------------------------===//
Expand Down
17 changes: 17 additions & 0 deletions Tests/SwiftAlgorithmsTests/ChainTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,21 @@ final class ChainTests: XCTestCase {
XCTAssertNil(j)
}
}

func testChainMutableCollection() {
let a = [1, 2, 3]
let b = [4, 5, 6]
var c = chain(a, b)

c[c.startIndex] = 10
let secondStart = c.index(c.startIndex, offsetBy: 3)
c[secondStart] = 40

expectEqualSequences(c, [10, 2, 3, 40, 5, 6])

for i in c.indices {
c[i] *= 2
}
expectEqualSequences(c, [20, 4, 6, 80, 10, 12])
}
}