|
2 | 2 | //
|
3 | 3 | // This source file is part of the Swift.org open source project
|
4 | 4 | //
|
5 |
| -// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors |
| 5 | +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors |
6 | 6 | // Licensed under Apache License v2.0 with Runtime Library Exception
|
7 | 7 | //
|
8 | 8 | // See https://swift.org/LICENSE.txt for license information
|
@@ -209,6 +209,70 @@ extension BidirectionalCollection where Element: Equatable {
|
209 | 209 | }
|
210 | 210 | }
|
211 | 211 |
|
| 212 | +//===----------------------------------------------------------------------===// |
| 213 | +// subranges(where:) / subranges(of:) |
| 214 | +//===----------------------------------------------------------------------===// |
| 215 | + |
| 216 | +extension Collection { |
| 217 | + /// Returns the indices of all the elements that match the given predicate. |
| 218 | + /// |
| 219 | + /// For example, you can use this method to find all the places that a |
| 220 | + /// vowel occurs in a string. |
| 221 | + /// |
| 222 | + /// let str = "Fresh cheese in a breeze" |
| 223 | + /// let vowels: Set<Character> = ["a", "e", "i", "o", "u"] |
| 224 | + /// let allTheVowels = str.subranges(where: { vowels.contains($0) }) |
| 225 | + /// // str[allTheVowels].count == 9 |
| 226 | + /// |
| 227 | + /// - Parameter predicate: A closure that takes an element as its argument |
| 228 | + /// and returns a Boolean value that indicates whether the passed element |
| 229 | + /// represents a match. |
| 230 | + /// - Returns: A set of the indices of the elements for which `predicate` |
| 231 | + /// returns `true`. |
| 232 | + /// |
| 233 | + /// - Complexity: O(*n*), where *n* is the length of the collection. |
| 234 | + @available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *) |
| 235 | + public func subranges(where predicate: (Element) throws -> Bool) rethrows |
| 236 | + -> RangeSet<Index> |
| 237 | + { |
| 238 | + if isEmpty { return RangeSet() } |
| 239 | + |
| 240 | + var result = RangeSet<Index>() |
| 241 | + var i = startIndex |
| 242 | + while i != endIndex { |
| 243 | + let next = index(after: i) |
| 244 | + if try predicate(self[i]) { |
| 245 | + result._append(i..<next) |
| 246 | + } |
| 247 | + i = next |
| 248 | + } |
| 249 | + |
| 250 | + return result |
| 251 | + } |
| 252 | +} |
| 253 | + |
| 254 | +extension Collection where Element: Equatable { |
| 255 | + /// Returns the indices of all the elements that are equal to the given |
| 256 | + /// element. |
| 257 | + /// |
| 258 | + /// For example, you can use this method to find all the places that a |
| 259 | + /// particular letter occurs in a string. |
| 260 | + /// |
| 261 | + /// let str = "Fresh cheese in a breeze" |
| 262 | + /// let allTheEs = str.subranges(of: "e") |
| 263 | + /// // str[allTheEs].count == 7 |
| 264 | + /// |
| 265 | + /// - Parameter element: An element to look for in the collection. |
| 266 | + /// - Returns: A set of the indices of the elements that are equal to |
| 267 | + /// `element`. |
| 268 | + /// |
| 269 | + /// - Complexity: O(*n*), where *n* is the length of the collection. |
| 270 | + @available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *) |
| 271 | + public func subranges(of element: Element) -> RangeSet<Index> { |
| 272 | + subranges(where: { $0 == element }) |
| 273 | + } |
| 274 | +} |
| 275 | + |
212 | 276 | //===----------------------------------------------------------------------===//
|
213 | 277 | // partition(by:)
|
214 | 278 | //===----------------------------------------------------------------------===//
|
@@ -369,6 +433,81 @@ extension MutableCollection where Self: BidirectionalCollection {
|
369 | 433 | }
|
370 | 434 | }
|
371 | 435 |
|
| 436 | +//===----------------------------------------------------------------------===// |
| 437 | +// _indexedStablePartition / _partitioningIndex |
| 438 | +//===----------------------------------------------------------------------===// |
| 439 | + |
| 440 | +extension MutableCollection { |
| 441 | + /// Moves all elements at the indices satisfying `belongsInSecondPartition` |
| 442 | + /// into a suffix of the collection, preserving their relative order, and |
| 443 | + /// returns the start of the resulting suffix. |
| 444 | + /// |
| 445 | + /// - Complexity: O(*n* log *n*) where *n* is the number of elements. |
| 446 | + /// - Precondition: |
| 447 | + /// `n == distance(from: range.lowerBound, to: range.upperBound)` |
| 448 | + internal mutating func _indexedStablePartition( |
| 449 | + count n: Int, |
| 450 | + range: Range<Index>, |
| 451 | + by belongsInSecondPartition: (Index) throws-> Bool |
| 452 | + ) rethrows -> Index { |
| 453 | + if n == 0 { return range.lowerBound } |
| 454 | + if n == 1 { |
| 455 | + return try belongsInSecondPartition(range.lowerBound) |
| 456 | + ? range.lowerBound |
| 457 | + : range.upperBound |
| 458 | + } |
| 459 | + let h = n / 2, i = index(range.lowerBound, offsetBy: h) |
| 460 | + let j = try _indexedStablePartition( |
| 461 | + count: h, |
| 462 | + range: range.lowerBound..<i, |
| 463 | + by: belongsInSecondPartition) |
| 464 | + let k = try _indexedStablePartition( |
| 465 | + count: n - h, |
| 466 | + range: i..<range.upperBound, |
| 467 | + by: belongsInSecondPartition) |
| 468 | + return _rotate(in: j..<k, shiftingToStart: i) |
| 469 | + } |
| 470 | +} |
| 471 | + |
| 472 | +//===----------------------------------------------------------------------===// |
| 473 | +// _partitioningIndex(where:) |
| 474 | +//===----------------------------------------------------------------------===// |
| 475 | + |
| 476 | +extension Collection { |
| 477 | + /// Returns the index of the first element in the collection that matches |
| 478 | + /// the predicate. |
| 479 | + /// |
| 480 | + /// The collection must already be partitioned according to the predicate. |
| 481 | + /// That is, there should be an index `i` where for every element in |
| 482 | + /// `collection[..<i]` the predicate is `false`, and for every element |
| 483 | + /// in `collection[i...]` the predicate is `true`. |
| 484 | + /// |
| 485 | + /// - Parameter predicate: A predicate that partitions the collection. |
| 486 | + /// - Returns: The index of the first element in the collection for which |
| 487 | + /// `predicate` returns `true`. |
| 488 | + /// |
| 489 | + /// - Complexity: O(log *n*), where *n* is the length of this collection if |
| 490 | + /// the collection conforms to `RandomAccessCollection`, otherwise O(*n*). |
| 491 | + internal func _partitioningIndex( |
| 492 | + where predicate: (Element) throws -> Bool |
| 493 | + ) rethrows -> Index { |
| 494 | + var n = count |
| 495 | + var l = startIndex |
| 496 | + |
| 497 | + while n > 0 { |
| 498 | + let half = n / 2 |
| 499 | + let mid = index(l, offsetBy: half) |
| 500 | + if try predicate(self[mid]) { |
| 501 | + n = half |
| 502 | + } else { |
| 503 | + l = index(after: mid) |
| 504 | + n -= half + 1 |
| 505 | + } |
| 506 | + } |
| 507 | + return l |
| 508 | + } |
| 509 | +} |
| 510 | + |
372 | 511 | //===----------------------------------------------------------------------===//
|
373 | 512 | // shuffled()/shuffle()
|
374 | 513 | //===----------------------------------------------------------------------===//
|
|
0 commit comments