FlattenCollection.swift 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. //===----------------------------------------------------------------------===//
  2. //
  3. // This source file is part of the Swift Algorithms open source project
  4. //
  5. // Copyright (c) 2021 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 consisting of all the elements contained in a collection of
  12. /// collections.
  13. @usableFromInline
  14. internal struct FlattenCollection<Base: Collection>
  15. where Base.Element: Collection
  16. {
  17. @usableFromInline
  18. internal let base: Base
  19. @usableFromInline
  20. internal let indexOfFirstNonEmptyElement: Base.Index
  21. @inlinable
  22. internal init(base: Base) {
  23. self.base = base
  24. self.indexOfFirstNonEmptyElement = base.endOfPrefix(while: { $0.isEmpty })
  25. }
  26. }
  27. extension FlattenCollection: Collection {
  28. @usableFromInline
  29. internal struct Index: Comparable {
  30. @usableFromInline
  31. internal let outer: Base.Index
  32. @usableFromInline
  33. internal let inner: Base.Element.Index?
  34. @inlinable
  35. init(outer: Base.Index, inner: Base.Element.Index?) {
  36. self.outer = outer
  37. self.inner = inner
  38. }
  39. @inlinable
  40. internal static func < (lhs: Self, rhs: Self) -> Bool {
  41. guard lhs.outer == rhs.outer else { return lhs.outer < rhs.outer }
  42. return lhs.inner == nil ? false : lhs.inner! < rhs.inner!
  43. }
  44. }
  45. @inlinable
  46. internal var startIndex: Index {
  47. let outer = indexOfFirstNonEmptyElement
  48. let inner = outer == base.endIndex ? nil : base[outer].startIndex
  49. return Index(outer: outer, inner: inner)
  50. }
  51. @inlinable
  52. internal var endIndex: Index {
  53. Index(outer: base.endIndex, inner: nil)
  54. }
  55. /// Forms an index from a pair of base indices, normalizing
  56. /// `(i, base2.endIndex)` to `(base1.index(after: i), base2.startIndex)` if
  57. /// necessary.
  58. @inlinable
  59. internal func normalizeIndex(
  60. outer: Base.Index,
  61. inner: Base.Element.Index
  62. ) -> Index {
  63. if inner == base[outer].endIndex {
  64. let outer = base[base.index(after: outer)...]
  65. .endOfPrefix(while: { $0.isEmpty })
  66. let inner = outer == base.endIndex ? nil : base[outer].startIndex
  67. return Index(outer: outer, inner: inner)
  68. } else {
  69. return Index(outer: outer, inner: inner)
  70. }
  71. }
  72. @inlinable
  73. internal func index(after index: Index) -> Index {
  74. let element = base[index.outer]
  75. let nextInner = element.index(after: index.inner!)
  76. return normalizeIndex(outer: index.outer, inner: nextInner)
  77. }
  78. @inlinable
  79. internal subscript(position: Index) -> Base.Element.Element {
  80. base[position.outer][position.inner!]
  81. }
  82. @inlinable
  83. internal func distance(from start: Index, to end: Index) -> Int {
  84. guard start.outer <= end.outer
  85. else { return -distance(from: end, to: start) }
  86. guard let startInner = start.inner
  87. else { return 0 }
  88. guard start.outer != end.outer
  89. else {
  90. return base[start.outer].distance(from: startInner, to: end.inner!)
  91. }
  92. let firstPart = base[start.outer][startInner...].count
  93. let middlePart = base[start.outer..<end.outer].dropFirst()
  94. .reduce(0, { $0 + $1.count })
  95. let lastPart = end.inner.map { base[end.outer][..<$0].count } ?? 0
  96. return firstPart + middlePart + lastPart
  97. }
  98. @inlinable
  99. internal func index(_ index: Index, offsetBy distance: Int) -> Index {
  100. guard distance != 0 else { return index }
  101. return distance > 0
  102. ? offsetForward(index, by: distance)
  103. : offsetBackward(index, by: -distance)
  104. }
  105. @inlinable
  106. internal func index(
  107. _ index: Index,
  108. offsetBy distance: Int,
  109. limitedBy limit: Index
  110. ) -> Index? {
  111. guard distance != 0 else { return index }
  112. if distance > 0 {
  113. return limit >= index
  114. ? offsetForward(index, by: distance, limitedBy: limit)
  115. : offsetForward(index, by: distance)
  116. } else {
  117. return limit <= index
  118. ? offsetBackward(index, by: -distance, limitedBy: limit)
  119. : offsetBackward(index, by: -distance)
  120. }
  121. }
  122. @inlinable
  123. internal func offsetForward(_ i: Index, by distance: Int) -> Index {
  124. guard let index = offsetForward(i, by: distance, limitedBy: endIndex)
  125. else { fatalError("Index is out of bounds") }
  126. return index
  127. }
  128. @inlinable
  129. internal func offsetBackward(_ i: Index, by distance: Int) -> Index {
  130. guard let index = offsetBackward(i, by: distance, limitedBy: startIndex)
  131. else { fatalError("Index is out of bounds") }
  132. return index
  133. }
  134. @inlinable
  135. internal func offsetForward(
  136. _ index: Index, by distance: Int, limitedBy limit: Index
  137. ) -> Index? {
  138. assert(distance > 0)
  139. assert(limit >= index)
  140. if index.outer == limit.outer {
  141. if let indexInner = index.inner, let limitInner = limit.inner {
  142. return base[index.outer]
  143. .index(indexInner, offsetBy: distance, limitedBy: limitInner)
  144. .map { inner in Index(outer: index.outer, inner: inner) }
  145. } else {
  146. // `index` and `limit` are both `endIndex`
  147. return nil
  148. }
  149. }
  150. // `index <= limit` and `index.outer != limit.outer`, so `index != endIndex`
  151. let indexInner = index.inner!
  152. let element = base[index.outer]
  153. if let inner = element.index(
  154. indexInner,
  155. offsetBy: distance,
  156. limitedBy: element.endIndex
  157. ) {
  158. return normalizeIndex(outer: index.outer, inner: inner)
  159. }
  160. var remainder = distance - element[indexInner...].count
  161. var outer = base.index(after: index.outer)
  162. while outer != limit.outer {
  163. let element = base[outer]
  164. if let inner = element.index(
  165. element.startIndex,
  166. offsetBy: remainder,
  167. limitedBy: element.endIndex
  168. ) {
  169. return normalizeIndex(outer: outer, inner: inner)
  170. }
  171. remainder -= element.count
  172. base.formIndex(after: &outer)
  173. }
  174. if let limitInner = limit.inner {
  175. let element = base[outer]
  176. return element.index(
  177. element.startIndex,
  178. offsetBy: remainder,
  179. limitedBy: limitInner)
  180. .map { inner in Index(outer: outer, inner: inner) }
  181. } else {
  182. return nil
  183. }
  184. }
  185. @inlinable
  186. internal func offsetBackward(
  187. _ index: Index, by distance: Int, limitedBy limit: Index
  188. ) -> Index? {
  189. assert(distance > 0)
  190. assert(limit <= index)
  191. if index.outer == limit.outer {
  192. if let indexInner = index.inner, let limitInner = limit.inner {
  193. return base[index.outer]
  194. .index(indexInner, offsetBy: -distance, limitedBy: limitInner)
  195. .map { inner in Index(outer: index.outer, inner: inner) }
  196. } else {
  197. // `index` and `limit` are both `endIndex`
  198. return nil
  199. }
  200. }
  201. var remainder = distance
  202. if let indexInner = index.inner {
  203. let element = base[index.outer]
  204. if let inner = element.index(
  205. indexInner,
  206. offsetBy: -remainder,
  207. limitedBy: element.startIndex
  208. ) {
  209. return Index(outer: index.outer, inner: inner)
  210. }
  211. remainder -= element[..<indexInner].count
  212. }
  213. var outer = base.index(index.outer, offsetBy: -1)
  214. while outer != limit.outer {
  215. let element = base[outer]
  216. if let inner = element.index(
  217. element.endIndex,
  218. offsetBy: -remainder,
  219. limitedBy: element.startIndex
  220. ) {
  221. return Index(outer: outer, inner: inner)
  222. }
  223. remainder -= element.count
  224. base.formIndex(&outer, offsetBy: -1)
  225. }
  226. let element = base[outer]
  227. return element.index(
  228. element.endIndex,
  229. offsetBy: -remainder,
  230. limitedBy: limit.inner!
  231. ).map { inner in Index(outer: outer, inner: inner) }
  232. }
  233. }
  234. extension FlattenCollection: BidirectionalCollection
  235. where Base: BidirectionalCollection, Base.Element: BidirectionalCollection
  236. {
  237. @inlinable
  238. internal func index(before index: Index) -> Index {
  239. if let inner = index.inner {
  240. let element = base[index.outer]
  241. if inner != element.startIndex {
  242. let previousInner = element.index(before: inner)
  243. return Index(outer: index.outer, inner: previousInner)
  244. }
  245. }
  246. let previousOuter = base[..<index.outer].lastIndex(where: { !$0.isEmpty })!
  247. let element = base[previousOuter]
  248. let previousInner = element.index(before: element.endIndex)
  249. return Index(outer: previousOuter, inner: previousInner)
  250. }
  251. }
  252. extension FlattenCollection: LazySequenceProtocol, LazyCollectionProtocol
  253. where Base: LazySequenceProtocol, Base.Element: LazySequenceProtocol {}
  254. //===----------------------------------------------------------------------===//
  255. // joined()
  256. //===----------------------------------------------------------------------===//
  257. extension Collection where Element: Collection {
  258. /// Returns the concatenation of the elements in this collection of
  259. /// collections.
  260. @inlinable
  261. internal func joined() -> FlattenCollection<Self> {
  262. FlattenCollection(base: self)
  263. }
  264. }