Indeed, it is possible to implement cycle(_:) using what's already in the standard library. What would be interesting to see is the performance difference between a custom type vs. the sequence-joined combination.
It would be an interesting micro-benchmark regardless, actually. Would you like to give it a shot?
This will hit the same problem of a potentially trapping count (although in this case it will only be trapping in some cases, when constructed with count: nil). Besides, as @benrimmington posted previously, sequence(element) { $0 } will achieve the same result. Admittedly a little more cryptic, but not too hard to write.
That's annoying indeed, I don't think that many will hit the trapping count, but it's unfortunate that that is allowed at all. It would be great to come up with a way for Repeated to be possibly infinite, while not sacrificing much efficiency. The easiest way right now would be to make Repeated.count optional, but that would involve a few more checks against nil on every access. Alternatively, Repeated could be a type-erased thing that fed accessors from FiniteRepeated and InfiniteRepeated. These will still all have the constraint of having Int.max - 1 be the last possible index, trapping on Int.max, but that's because of the way Collection works, which I assume is not up for debate at this point
Back to cycled: if we are going to consider the ?? .max trick here, I'd still argue for it being placed in repeatElement. The optional count argument is the API that I expected the function to have anyway, and I reckon that the benefits outweigh the costs.
Using Xcode, you can create a cross-platform "Empty" project; add a macOS "Unit Testing Bundle" target; and paste the code into the target's source file.
Ok, well if the results are so close, then we better choose the solution for other reasons. I'd go for the custom type, it lets us mutate the implementation if there's ever a reason, and swift's type system plays better with custom types than typealiases in general.
public struct SequenceCycle, as originally proposed
public func cycledRepeated, as in my updated gist
public func cycledUnfoldFirst, using sequence(first, next)
I chose to keep these all as sequence and not collection, which requires testing whether you have to see if a first Element is available. This ruled out the unfoldFirst solution.
I ran Ben's benchmarks on an optimized build:
Test Case '-[Test2Tests.CycleBenchmark testCycledRepeated]' passed (3.526 seconds).
Test Case '-[Test2Tests.CycleBenchmark testSequenceCycle]' passed (2.360 seconds).
And I ran my own pressure tests:
Starting Test: Using cycledSequenceCycle()
Ending Test : Using cycledSequenceCycle()
Elapsed time: 0.496450918028131
Starting Test: Using cycledRepeated()
Ending Test : Using cycledRepeated()
Elapsed time: 0.509369512787089
All things being equal, I'm leaning towards reverting to my original implementation, which follows how SE-0094 was implemented.
As for my different tests yesterday, they seem to be due to a typo, where I was feeding an array as the first argument to one test and the original sequence to the other.
Sorry I am late to this party. I just wanted to add one thing you might find interesting: it may be useful to differentiate between cycling over the sequence forever, and for some number of times through the entire sequence, as in:
[1,2,3].cycled() == [1,2,3].cycled(.forever /* or what have you */) // [1,2,3,1,2,3...]
[1,2,3].cycled(.times(2)) // [1,2,3,1,2,3]
Sorry, I meant something along the lines of repeatElement([1, 2, 3], count: .forever).lazy.joined()
Thinking about it now, though, I realize that I am thinking in a lazily evaluated context. This is all to say, I wanted the infinite and finite versions to share a name for discoverability and, maybe, that is what bitjammer was after, as well.
maybe repeatElements(of: [1,2, 3], count: .cycled) and repeatElements(of: [1,2, 3], count: 3) where 3 is achieved by ExpressibleByIntegerLiteral and, basically, becomes .finite(3) under the covers.
Hm, FWIW doesn't read super well to me in comparison. I look at repeatElement and I imagine someone could get confused as to whether [1,2,3] is repeated or its elements are.