Cycle.swift 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. //===----------------------------------------------------------------------===//
  2. //
  3. // This source file is part of the Swift Algorithms open source project
  4. //
  5. // Copyright (c) 2020 Apple Inc. and the Swift project authors
  6. // Licensed under Apache License v2.0 with Runtime Library Exception
  7. //
  8. // See https://swift.org/LICENSE.txt for license information
  9. //
  10. //===----------------------------------------------------------------------===//
  11. /// A collection wrapper that repeats the elements of a base collection.
  12. public struct CycledSequence<Base: Collection> {
  13. /// The collection to repeat.
  14. @usableFromInline
  15. internal let base: Base
  16. @inlinable
  17. internal init(base: Base) {
  18. self.base = base
  19. }
  20. }
  21. extension CycledSequence: Sequence {
  22. /// The iterator for a `CycledSequence` instance.
  23. public struct Iterator: IteratorProtocol {
  24. @usableFromInline
  25. internal let base: Base
  26. @usableFromInline
  27. internal var current: Base.Index
  28. @inlinable
  29. internal init(base: Base) {
  30. self.base = base
  31. self.current = base.startIndex
  32. }
  33. @inlinable
  34. public mutating func next() -> Base.Element? {
  35. guard !base.isEmpty else { return nil }
  36. if current == base.endIndex {
  37. current = base.startIndex
  38. }
  39. defer { base.formIndex(after: &current) }
  40. return base[current]
  41. }
  42. }
  43. @inlinable
  44. public func makeIterator() -> Iterator {
  45. Iterator(base: base)
  46. }
  47. }
  48. extension CycledSequence: LazySequenceProtocol
  49. where Base: LazySequenceProtocol {}
  50. /// A collection wrapper that repeats the elements of a base collection for a
  51. /// finite number of times.
  52. public struct CycledTimesCollection<Base: Collection> {
  53. /// A `Product2Sequence` instance for iterating the base collection.
  54. @usableFromInline
  55. internal let product: Product2Sequence<Range<Int>, Base>
  56. @inlinable
  57. internal init(base: Base, times: Int) {
  58. self.product = Product2Sequence(0..<times, base)
  59. }
  60. }
  61. extension CycledTimesCollection: Collection {
  62. public typealias Element = Base.Element
  63. public struct Index: Comparable {
  64. /// The index corresponding to the `Product2Sequence` index at this
  65. /// position.
  66. @usableFromInline
  67. internal let productIndex: Product2Sequence<Range<Int>, Base>.Index
  68. @inlinable
  69. internal init(_ productIndex: Product2Sequence<Range<Int>, Base>.Index) {
  70. self.productIndex = productIndex
  71. }
  72. @inlinable
  73. public static func == (lhs: Index, rhs: Index) -> Bool {
  74. lhs.productIndex == rhs.productIndex
  75. }
  76. @inlinable
  77. public static func < (lhs: Index, rhs: Index) -> Bool {
  78. lhs.productIndex < rhs.productIndex
  79. }
  80. }
  81. @inlinable
  82. public var startIndex: Index {
  83. Index(product.startIndex)
  84. }
  85. @inlinable
  86. public var endIndex: Index {
  87. Index(product.endIndex)
  88. }
  89. @inlinable
  90. public subscript(_ index: Index) -> Element {
  91. product[index.productIndex].1
  92. }
  93. @inlinable
  94. public func index(after i: Index) -> Index {
  95. let productIndex = product.index(after: i.productIndex)
  96. return Index(productIndex)
  97. }
  98. @inlinable
  99. public func distance(from start: Index, to end: Index) -> Int {
  100. product.distance(from: start.productIndex, to: end.productIndex)
  101. }
  102. @inlinable
  103. public func index(_ i: Index, offsetBy distance: Int) -> Index {
  104. let productIndex = product.index(i.productIndex, offsetBy: distance)
  105. return Index(productIndex)
  106. }
  107. @inlinable
  108. public func index(
  109. _ i: Index,
  110. offsetBy distance: Int,
  111. limitedBy limit: Index
  112. ) -> Index? {
  113. guard let productIndex = product.index(
  114. i.productIndex,
  115. offsetBy: distance,
  116. limitedBy: limit.productIndex)
  117. else { return nil }
  118. return Index(productIndex)
  119. }
  120. @inlinable
  121. public var count: Int {
  122. product.count
  123. }
  124. }
  125. extension CycledTimesCollection: BidirectionalCollection
  126. where Base: BidirectionalCollection {
  127. @inlinable
  128. public func index(before i: Index) -> Index {
  129. let productIndex = product.index(before: i.productIndex)
  130. return Index(productIndex)
  131. }
  132. }
  133. extension CycledTimesCollection: RandomAccessCollection
  134. where Base: RandomAccessCollection {}
  135. extension CycledTimesCollection: LazySequenceProtocol, LazyCollectionProtocol
  136. where Base: LazySequenceProtocol {}
  137. //===----------------------------------------------------------------------===//
  138. // cycled()
  139. //===----------------------------------------------------------------------===//
  140. extension Collection {
  141. /// Returns a sequence that repeats the elements of this collection forever.
  142. ///
  143. /// Use the `cycled()` method to repeat the elements of a sequence or
  144. /// collection forever. You can combine `cycled()` with another, finite
  145. /// sequence to iterate over the two together.
  146. ///
  147. /// for (evenOrOdd, number) in zip(["even", "odd"].cycled(), 0..<10) {
  148. /// print("\(number) is \(evenOrOdd)")
  149. /// }
  150. /// // 0 is even
  151. /// // 1 is odd
  152. /// // 2 is even
  153. /// // 3 is odd
  154. /// // ...
  155. /// // 9 is odd
  156. ///
  157. /// - Important: When called on a non-empty collection, the resulting sequence
  158. /// is infinite. Do not directly call methods that require a finite
  159. /// sequence, like `map` or `filter`, without first constraining the length
  160. /// of the cycling sequence.
  161. ///
  162. /// - Returns: A sequence that repeats the elements of this collection
  163. /// forever.
  164. ///
  165. /// - Complexity: O(1)
  166. @inlinable
  167. public func cycled() -> CycledSequence<Self> {
  168. CycledSequence(base: self)
  169. }
  170. /// Returns a sequence that repeats the elements of this collection the
  171. /// specified number of times.
  172. ///
  173. /// Passing `1` as `times` results in this collection's elements being
  174. /// provided a single time; passing `0` results in an empty sequence. The
  175. /// `print(_:)` function in this example is never called:
  176. ///
  177. /// for x in [1, 2, 3].cycled(times: 0) {
  178. /// print(x)
  179. /// }
  180. ///
  181. /// - Parameter times: The number of times to repeat this sequence. `times`
  182. /// must be zero or greater.
  183. /// - Returns: A sequence that repeats the elements of this sequence `times`
  184. /// times.
  185. ///
  186. /// - Complexity: O(1)
  187. @inlinable
  188. public func cycled(times: Int) -> CycledTimesCollection<Self> {
  189. CycledTimesCollection(base: self, times: times)
  190. }
  191. }