-
-
Notifications
You must be signed in to change notification settings - Fork 78
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f5a04aa
commit 5e75c9e
Showing
2 changed files
with
155 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
// A `Sequence` that can contain at most two elements. However it does not heap allocate. | ||
@usableFromInline | ||
struct Max2Sequence<Element>: Sequence { | ||
@usableFromInline | ||
private(set) var first: Element? | ||
@usableFromInline | ||
private(set) var second: Element? | ||
|
||
@inlinable | ||
var count: Int { | ||
if self.first == nil { return 0 } | ||
if self.second == nil { return 1 } | ||
return 2 | ||
} | ||
|
||
@inlinable | ||
var isEmpty: Bool { | ||
self.first == nil | ||
} | ||
|
||
@inlinable | ||
init(_ first: Element?, _ second: Element? = nil) { | ||
if let first = first { | ||
self.first = first | ||
self.second = second | ||
} else { | ||
self.first = second | ||
self.second = nil | ||
} | ||
} | ||
|
||
@inlinable | ||
init() { | ||
self.first = nil | ||
self.second = nil | ||
} | ||
|
||
@inlinable | ||
func makeIterator() -> Iterator { | ||
Iterator(first: self.first, second: self.second) | ||
} | ||
|
||
@usableFromInline | ||
struct Iterator: IteratorProtocol { | ||
@usableFromInline | ||
let first: Element? | ||
@usableFromInline | ||
let second: Element? | ||
|
||
@usableFromInline | ||
private(set) var index: UInt8 = 0 | ||
|
||
@inlinable | ||
init(first: Element?, second: Element?) { | ||
self.first = first | ||
self.second = second | ||
self.index = 0 | ||
} | ||
|
||
@inlinable | ||
mutating func next() -> Element? { | ||
switch self.index { | ||
case 0: | ||
self.index += 1 | ||
return self.first | ||
case 1: | ||
self.index += 1 | ||
return self.second | ||
default: | ||
return nil | ||
} | ||
} | ||
} | ||
|
||
@inlinable | ||
mutating func append(_ element: Element) { | ||
precondition(self.second == nil) | ||
if self.first == nil { | ||
self.first = element | ||
} else if self.second == nil { | ||
self.second = element | ||
} else { | ||
fatalError("Max2Sequence can only hold two Elements.") | ||
} | ||
} | ||
|
||
@inlinable | ||
func map<NewElement>(_ transform: (Element) throws -> (NewElement)) rethrows -> Max2Sequence<NewElement> { | ||
try Max2Sequence<NewElement>(self.first.flatMap(transform), self.second.flatMap(transform)) | ||
} | ||
} | ||
|
||
extension Max2Sequence: Equatable where Element: Equatable {} | ||
extension Max2Sequence: Hashable where Element: Hashable {} | ||
extension Max2Sequence: Sendable where Element: Sendable {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
@testable import _ConnectionPoolModule | ||
import XCTest | ||
|
||
final class Max2SequenceTests: XCTestCase { | ||
func testCountAndIsEmpty() async { | ||
var sequence = Max2Sequence<Int>() | ||
XCTAssertEqual(sequence.count, 0) | ||
XCTAssertEqual(sequence.isEmpty, true) | ||
sequence.append(1) | ||
XCTAssertEqual(sequence.count, 1) | ||
XCTAssertEqual(sequence.isEmpty, false) | ||
sequence.append(2) | ||
XCTAssertEqual(sequence.count, 2) | ||
XCTAssertEqual(sequence.isEmpty, false) | ||
} | ||
|
||
func testOptionalInitializer() { | ||
let emptySequence = Max2Sequence<Int>(nil, nil) | ||
XCTAssertEqual(emptySequence.count, 0) | ||
XCTAssertEqual(emptySequence.isEmpty, true) | ||
var emptySequenceIterator = emptySequence.makeIterator() | ||
XCTAssertNil(emptySequenceIterator.next()) | ||
XCTAssertNil(emptySequenceIterator.next()) | ||
XCTAssertNil(emptySequenceIterator.next()) | ||
|
||
let oneElemSequence1 = Max2Sequence<Int>(1, nil) | ||
XCTAssertEqual(oneElemSequence1.count, 1) | ||
XCTAssertEqual(oneElemSequence1.isEmpty, false) | ||
var oneElemSequence1Iterator = oneElemSequence1.makeIterator() | ||
XCTAssertEqual(oneElemSequence1Iterator.next(), 1) | ||
XCTAssertNil(oneElemSequence1Iterator.next()) | ||
XCTAssertNil(oneElemSequence1Iterator.next()) | ||
|
||
let oneElemSequence2 = Max2Sequence<Int>(nil, 2) | ||
XCTAssertEqual(oneElemSequence2.count, 1) | ||
XCTAssertEqual(oneElemSequence2.isEmpty, false) | ||
var oneElemSequence2Iterator = oneElemSequence2.makeIterator() | ||
XCTAssertEqual(oneElemSequence2Iterator.next(), 2) | ||
XCTAssertNil(oneElemSequence2Iterator.next()) | ||
XCTAssertNil(oneElemSequence2Iterator.next()) | ||
|
||
let twoElemSequence = Max2Sequence<Int>(1, 2) | ||
XCTAssertEqual(twoElemSequence.count, 2) | ||
XCTAssertEqual(twoElemSequence.isEmpty, false) | ||
var twoElemSequenceIterator = twoElemSequence.makeIterator() | ||
XCTAssertEqual(twoElemSequenceIterator.next(), 1) | ||
XCTAssertEqual(twoElemSequenceIterator.next(), 2) | ||
XCTAssertNil(twoElemSequenceIterator.next()) | ||
} | ||
|
||
func testMap() { | ||
let twoElemSequence = Max2Sequence<Int>(1, 2).map({ "\($0)" }) | ||
XCTAssertEqual(twoElemSequence.count, 2) | ||
XCTAssertEqual(twoElemSequence.isEmpty, false) | ||
var twoElemSequenceIterator = twoElemSequence.makeIterator() | ||
XCTAssertEqual(twoElemSequenceIterator.next(), "1") | ||
XCTAssertEqual(twoElemSequenceIterator.next(), "2") | ||
XCTAssertNil(twoElemSequenceIterator.next()) | ||
} | ||
} |