Merge commit '7621e2f8dec938cf48181c8b10afc9b01f444e68' into beta

This commit is contained in:
Ilya Laktyushin
2025-12-06 02:17:48 +04:00
commit 8344b97e03
28070 changed files with 7995182 additions and 0 deletions
+15
View File
@@ -0,0 +1,15 @@
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
swift_library(
name = "RangeSet",
module_name = "RangeSet",
srcs = glob([
"Sources/**/*.swift",
]),
copts = [
"-warnings-as-errors",
],
visibility = [
"//visibility:public",
],
)
+27
View File
@@ -0,0 +1,27 @@
// swift-tools-version:5.5
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "RangeSet",
platforms: [.macOS(.v10_13)],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "RangeSet",
targets: ["RangeSet"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target(
name: "RangeSet",
dependencies: [],
path: "Sources")
]
)
@@ -0,0 +1,269 @@
//===----------------------------------------------------------*- swift -*-===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//
// MARK: Subscripts
extension Collection {
/// Accesses a view of this collection with the elements at the given
/// indices.
///
/// - Parameter subranges: The indices of the elements to retrieve from this
/// collection.
/// - Returns: A collection of the elements at the positions in `subranges`.
///
/// - Complexity: O(1)
public subscript(subranges: RangeSet<Index>) -> DiscontiguousSlice<Self> {
DiscontiguousSlice(base: self, subranges: subranges)
}
}
extension MutableCollection {
/// Accesses a mutable view of this collection with the elements at the
/// given indices.
///
/// - Parameter subranges: The ranges of the elements to retrieve from this
/// collection.
/// - Returns: A collection of the elements at the positions in `subranges`.
///
/// - Complexity: O(1) to access the elements, O(*m*) to mutate the
/// elements at the positions in `subranges`, where *m* is the number of
/// elements indicated by `subranges`.
public subscript(subranges: RangeSet<Index>) -> DiscontiguousSlice<Self> {
get {
DiscontiguousSlice(base: self, subranges: subranges)
}
set {
for i in newValue.indices where subranges.contains(i.base) {
self[i.base] = newValue[i]
}
}
}
}
// MARK: - moveSubranges(_:to:)
extension MutableCollection {
/// Moves the elements in the given subranges to just before the element at
/// the specified index.
///
/// This example finds all the uppercase letters in the array and then
/// moves them to between `"i"` and `"j"`.
///
/// var letters = Array("ABCdeFGhijkLMNOp")
/// let uppercaseRanges = letters.subranges(where: { $0.isUppercase })
/// let rangeOfUppercase = letters.moveSubranges(uppercaseRanges, to: 10)
/// // String(letters) == "dehiABCFGLMNOjkp"
/// // rangeOfUppercase == 4..<13
///
/// - Parameters:
/// - subranges: The subranges of the elements to move.
/// - insertionPoint: The index to use as the destination of the elements.
/// - Returns: The new bounds of the moved elements.
///
/// - Complexity: O(*n* log *n*) where *n* is the length of the collection.
@discardableResult
public mutating func moveSubranges(
_ subranges: RangeSet<Index>, to insertionPoint: Index
) -> Range<Index> {
let lowerCount = distance(from: startIndex, to: insertionPoint)
let upperCount = distance(from: insertionPoint, to: endIndex)
let start = _indexedStablePartition(
count: lowerCount,
range: startIndex..<insertionPoint,
by: { subranges.contains($0) })
let end = _indexedStablePartition(
count: upperCount,
range: insertionPoint..<endIndex,
by: { !subranges.contains($0) })
return start..<end
}
}
// MARK: - removeSubranges(_:) / removingSubranges(_:)
extension RangeReplaceableCollection {
/// Removes the elements at the given indices.
///
/// For example, this code sample finds the indices of all the vowel
/// characters in the string, and then removes those characters.
///
/// var str = "The rain in Spain stays mainly in the plain."
/// let vowels: Set<Character> = ["a", "e", "i", "o", "u"]
/// let vowelIndices = str.subranges(where: { vowels.contains($0) })
///
/// str.removeSubranges(vowelIndices)
/// // str == "Th rn n Spn stys mnly n th pln."
///
/// - Parameter subranges: The indices of the elements to remove.
///
/// - Complexity: O(*n*), where *n* is the length of the collection.
public mutating func removeSubranges(_ subranges: RangeSet<Index>) {
guard !subranges.isEmpty else {
return
}
let inversion = subranges._inverted(within: self)
var result = Self()
for range in inversion.ranges {
result.append(contentsOf: self[range])
}
self = result
}
}
extension MutableCollection where Self: RangeReplaceableCollection {
/// Removes the elements at the given indices.
///
/// For example, this code sample finds the indices of all the negative
/// numbers in the array, and then removes those values.
///
/// var numbers = [5, 7, -3, -8, 11, 2, -1, 6]
/// let negativeIndices = numbers.subranges(where: { $0 < 0 })
///
/// numbers.removeSubranges(negativeIndices)
/// // numbers == [5, 7, 11, 2, 6]
///
/// - Parameter subranges: The indices of the elements to remove.
///
/// - Complexity: O(*n*), where *n* is the length of the collection.
public mutating func removeSubranges(_ subranges: RangeSet<Index>) {
guard let firstRange = subranges.ranges.first else {
return
}
var endOfElementsToKeep = firstRange.lowerBound
var firstUnprocessed = firstRange.upperBound
// This performs a half-stable partition based on the ranges in
// `indices`. At all times, the collection is divided into three
// regions:
//
// - `self[..<endOfElementsToKeep]` contains only elements that will
// remain in the collection after this method call.
// - `self[endOfElementsToKeep..<firstUnprocessed]` contains only
// elements that will be removed.
// - `self[firstUnprocessed...]` contains a mix of elements to remain
// and elements to be removed.
//
// Each iteration of this loop moves the elements that are _between_
// two ranges to remove from the third region to the first region.
for range in subranges.ranges.dropFirst() {
let nextLow = range.lowerBound
while firstUnprocessed != nextLow {
swapAt(endOfElementsToKeep, firstUnprocessed)
formIndex(after: &endOfElementsToKeep)
formIndex(after: &firstUnprocessed)
}
firstUnprocessed = range.upperBound
}
// After dealing with all the ranges in `indices`, move the elements
// that are still in the third region down to the first.
while firstUnprocessed != endIndex {
swapAt(endOfElementsToKeep, firstUnprocessed)
formIndex(after: &endOfElementsToKeep)
formIndex(after: &firstUnprocessed)
}
removeSubrange(endOfElementsToKeep..<endIndex)
}
}
extension Collection {
/// Returns a collection of the elements in this collection that are not
/// represented by the given range set.
///
/// For example, this code sample finds the indices of all the vowel
/// characters in the string, and then retrieves a collection that omits
/// those characters.
///
/// let str = "The rain in Spain stays mainly in the plain."
/// let vowels: Set<Character> = ["a", "e", "i", "o", "u"]
/// let vowelIndices = str.subranges(where: { vowels.contains($0) })
///
/// let disemvoweled = str.removingSubranges(vowelIndices)
/// print(String(disemvoweled))
/// // Prints "Th rn n Spn stys mnly n th pln."
///
/// - Parameter subranges: A range set representing the indices of the
/// elements to remove.
/// - Returns: A collection of the elements that are not in `subranges`.
///
/// - Complexity: O(*n*), where *n* is the length of the collection.
public func removingSubranges(
_ subranges: RangeSet<Index>
) -> DiscontiguousSlice<Self> {
let inversion = subranges._inverted(within: self)
return self[inversion]
}
}
// MARK: - subranges(where:) / subranges(of:)
extension Collection {
/// Returns the indices of all the elements that match the given predicate.
///
/// For example, you can use this method to find all the places that a
/// vowel occurs in a string.
///
/// let str = "Fresh cheese in a breeze"
/// let vowels: Set<Character> = ["a", "e", "i", "o", "u"]
/// let allTheVowels = str.subranges(where: { vowels.contains($0) })
/// // str[allTheVowels].count == 9
///
/// - Parameter predicate: A closure that takes an element as its argument
/// and returns a Boolean value that indicates whether the passed element
/// represents a match.
/// - Returns: A set of the indices of the elements for which `predicate`
/// returns `true`.
///
/// - Complexity: O(*n*), where *n* is the length of the collection.
public func subranges(where predicate: (Element) throws -> Bool) rethrows
-> RangeSet<Index>
{
if isEmpty { return RangeSet() }
var result = RangeSet<Index>()
var i = startIndex
while i != endIndex {
let next = index(after: i)
if try predicate(self[i]) {
result._append(i..<next)
}
i = next
}
return result
}
}
extension Collection where Element: Equatable {
/// Returns the indices of all the elements that are equal to the given
/// element.
///
/// For example, you can use this method to find all the places that a
/// particular letter occurs in a string.
///
/// let str = "Fresh cheese in a breeze"
/// let allTheEs = str.subranges(of: "e")
/// // str[allTheEs].count == 7
///
/// - Parameter element: An element to look for in the collection.
/// - Returns: A set of the indices of the elements that are equal to
/// `element`.
///
/// - Complexity: O(*n*), where *n* is the length of the collection.
public func subranges(of element: Element) -> RangeSet<Index> {
subranges(where: { $0 == element })
}
}
@@ -0,0 +1,140 @@
//===----------------------------------------------------------*- swift -*-===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//
/// A collection wrapper that provides access to the elements of a collection,
/// indexed by a set of indices.
public struct DiscontiguousSlice<Base: Collection> {
/// The collection that the indexed collection wraps.
public var base: Base
/// The set of subranges that are available through this discontiguous slice.
public var subranges: RangeSet<Base.Index>
}
extension DiscontiguousSlice {
/// A position in an `DiscontiguousSlice`.
public struct Index: Comparable {
/// The index of the range that contains `base`.
internal var _rangeOffset: Int
/// The position of this index in the base collection.
public var base: Base.Index
public static func < (lhs: Index, rhs: Index) -> Bool {
lhs.base < rhs.base
}
}
}
extension DiscontiguousSlice.Index: Hashable where Base.Index: Hashable {}
extension DiscontiguousSlice: Collection {
public typealias SubSequence = Self
public var startIndex: Index {
subranges.isEmpty
? endIndex
: Index(_rangeOffset: 0, base: subranges._ranges[0].lowerBound)
}
public var endIndex: Index {
Index(_rangeOffset: subranges._ranges.endIndex, base: base.endIndex)
}
public func index(after i: Index) -> Index {
let nextIndex = base.index(after: i.base)
if subranges._ranges[i._rangeOffset].contains(nextIndex) {
return Index(_rangeOffset: i._rangeOffset, base: nextIndex)
}
let nextOffset = i._rangeOffset + 1
if nextOffset < subranges._ranges.endIndex {
return Index(
_rangeOffset: nextOffset,
base: subranges._ranges[nextOffset].lowerBound)
} else {
return endIndex
}
}
public subscript(i: Index) -> Base.Element {
base[i.base]
}
public subscript(bounds: Range<Index>) -> DiscontiguousSlice<Base> {
let baseBounds = bounds.lowerBound.base ..< bounds.upperBound.base
let subset = subranges.intersection(RangeSet(baseBounds))
return DiscontiguousSlice<Base>(base: base, subranges: subset)
}
}
extension DiscontiguousSlice {
public var count: Int {
var c = 0
for range in subranges._ranges {
c += base.distance(from: range.lowerBound, to: range.upperBound)
}
return c
}
public __consuming func _copyToContiguousArray() -> ContiguousArray<Base.Element> {
var result: ContiguousArray<Base.Element> = []
for range in subranges._ranges {
result.append(contentsOf: base[range])
}
return result
}
}
extension DiscontiguousSlice: BidirectionalCollection
where Base: BidirectionalCollection
{
public func index(before i: Index) -> Index {
precondition(i != startIndex, "Can't move index before startIndex")
if i == endIndex || i.base == subranges._ranges[i._rangeOffset].lowerBound {
let offset = i._rangeOffset - 1
return Index(
_rangeOffset: offset,
base: base.index(before: subranges._ranges[offset].upperBound))
}
return Index(
_rangeOffset: i._rangeOffset,
base: base.index(before: i.base))
}
}
extension DiscontiguousSlice: MutableCollection where Base: MutableCollection {
public subscript(i: Index) -> Base.Element {
get {
base[i.base]
}
set {
base[i.base] = newValue
}
}
public subscript(bounds: Range<Index>) -> DiscontiguousSlice<Base> {
get {
let baseBounds = bounds.lowerBound.base ..< bounds.upperBound.base
let subset = subranges.intersection(RangeSet(baseBounds))
return DiscontiguousSlice<Base>(base: base, subranges: subset)
}
set {
let baseBounds = bounds.lowerBound.base ..< bounds.upperBound.base
let subset = subranges.intersection(RangeSet(baseBounds))
for i in newValue.indices where subset.contains(i.base) {
base[i.base] = newValue[i]
}
}
}
}
@@ -0,0 +1,33 @@
//===----------------------------------------------------------*- swift -*-===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//
/// A collection of two elements, to avoid heap allocation when calling
/// `replaceSubrange` with just two elements.
internal struct Pair<Element>: RandomAccessCollection {
var pair: (first: Element, second: Element)
init(_ first: Element, _ second: Element) {
self.pair = (first, second)
}
var startIndex: Int { 0 }
var endIndex: Int { 2 }
subscript(position: Int) -> Element {
get {
switch position {
case 0: return pair.first
case 1: return pair.second
default: fatalError("Index '\(position)' is out of range")
}
}
}
}
@@ -0,0 +1,217 @@
//===----------------------------------------------------------*- swift -*-===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//
// MARK: _rotate(in:shiftingToStart:)
extension MutableCollection {
/// Rotates the elements of the collection so that the element at `middle`
/// ends up first.
///
/// - Returns: The new index of the element that was first pre-rotation.
///
/// - Complexity: O(*n*)
@discardableResult
internal mutating func _rotate(in subrange: Range<Index>, shiftingToStart middle: Index) -> Index {
var m = middle, s = subrange.lowerBound
let e = subrange.upperBound
// Handle the trivial cases
if s == m { return e }
if m == e { return s }
// We have two regions of possibly-unequal length that need to be
// exchanged. The return value of this method is going to be the
// position following that of the element that is currently last
// (element j).
//
// [a b c d e f g|h i j] or [a b c|d e f g h i j]
// ^ ^ ^ ^ ^ ^
// s m e s m e
//
var ret = e // start with a known incorrect result.
while true {
// Exchange the leading elements of each region (up to the
// length of the shorter region).
//
// [a b c d e f g|h i j] or [a b c|d e f g h i j]
// ^^^^^ ^^^^^ ^^^^^ ^^^^^
// [h i j d e f g|a b c] or [d e f|a b c g h i j]
// ^ ^ ^ ^ ^ ^ ^ ^
// s s1 m m1/e s s1/m m1 e
//
let (s1, m1) = _swapNonemptySubrangePrefixes(s..<m, m..<e)
if m1 == e {
// Left-hand case: we have moved element j into position. if
// we haven't already, we can capture the return value which
// is in s1.
//
// Note: the STL breaks the loop into two just to avoid this
// comparison once the return value is known. I'm not sure
// it's a worthwhile optimization, though.
if ret == e { ret = s1 }
// If both regions were the same size, we're done.
if s1 == m { break }
}
// Now we have a smaller problem that is also a rotation, so we
// can adjust our bounds and repeat.
//
// h i j[d e f g|a b c] or d e f[a b c|g h i j]
// ^ ^ ^ ^ ^ ^
// s m e s m e
s = s1
if s == m { m = m1 }
}
return ret
}
/// Swaps the elements of the two given subranges, up to the upper bound of
/// the smaller subrange. The returned indices are the ends of the two
/// ranges that were actually swapped.
///
/// Input:
/// [a b c d e f g h i j k l m n o p]
/// ^^^^^^^ ^^^^^^^^^^^^^
/// lhs rhs
///
/// Output:
/// [i j k l e f g h a b c d m n o p]
/// ^ ^
/// p q
///
/// - Precondition: !lhs.isEmpty && !rhs.isEmpty
/// - Postcondition: For returned indices `(p, q)`:
///
/// - distance(from: lhs.lowerBound, to: p) == distance(from:
/// rhs.lowerBound, to: q)
/// - p == lhs.upperBound || q == rhs.upperBound
mutating func _swapNonemptySubrangePrefixes(
_ lhs: Range<Index>, _ rhs: Range<Index>
) -> (Index, Index) {
assert(!lhs.isEmpty)
assert(!rhs.isEmpty)
var p = lhs.lowerBound
var q = rhs.lowerBound
repeat {
swapAt(p, q)
formIndex(after: &p)
formIndex(after: &q)
}
while p != lhs.upperBound && q != rhs.upperBound
return (p, q)
}
}
// MARK: - _stablePartition(count:range:by:)
extension MutableCollection {
/// Moves all elements satisfying `belongsInSecondPartition` into a suffix
/// of the collection, preserving their relative order, and returns the
/// start of the resulting suffix.
///
/// - Complexity: O(*n* log *n*) where *n* is the number of elements.
/// - Precondition:
/// `n == distance(from: range.lowerBound, to: range.upperBound)`
internal mutating func _stablePartition(
count n: Int,
range: Range<Index>,
by belongsInSecondPartition: (Element) throws-> Bool
) rethrows -> Index {
if n == 0 { return range.lowerBound }
if n == 1 {
return try belongsInSecondPartition(self[range.lowerBound])
? range.lowerBound
: range.upperBound
}
let h = n / 2, i = index(range.lowerBound, offsetBy: h)
let j = try _stablePartition(
count: h,
range: range.lowerBound..<i,
by: belongsInSecondPartition)
let k = try _stablePartition(
count: n - h,
range: i..<range.upperBound,
by: belongsInSecondPartition)
return _rotate(in: j..<k, shiftingToStart: i)
}
/// Moves all elements at the indices satisfying `belongsInSecondPartition`
/// into a suffix of the collection, preserving their relative order, and
/// returns the start of the resulting suffix.
///
/// - Complexity: O(*n* log *n*) where *n* is the number of elements.
/// - Precondition:
/// `n == distance(from: range.lowerBound, to: range.upperBound)`
internal mutating func _indexedStablePartition(
count n: Int,
range: Range<Index>,
by belongsInSecondPartition: (Index) throws-> Bool
) rethrows -> Index {
if n == 0 { return range.lowerBound }
if n == 1 {
return try belongsInSecondPartition(range.lowerBound)
? range.lowerBound
: range.upperBound
}
let h = n / 2, i = index(range.lowerBound, offsetBy: h)
let j = try _indexedStablePartition(
count: h,
range: range.lowerBound..<i,
by: belongsInSecondPartition)
let k = try _indexedStablePartition(
count: n - h,
range: i..<range.upperBound,
by: belongsInSecondPartition)
return _rotate(in: j..<k, shiftingToStart: i)
}
}
// MARK: - partitioningIndex(where:)
extension Collection {
/// Returns the index of the first element in the collection that matches
/// the predicate.
///
/// The collection must already be partitioned according to the predicate.
/// That is, there should be an index `i` where for every element in
/// `collection[..<i]` the predicate is `false`, and for every element
/// in `collection[i...]` the predicate is `true`.
///
/// - Parameter predicate: A predicate that partitions the collection.
/// - Returns: The index of the first element in the collection for which
/// `predicate` returns `true`.
///
/// - Complexity: O(log *n*), where *n* is the length of this collection if
/// the collection conforms to `RandomAccessCollection`, otherwise O(*n*).
internal func _partitioningIndex(
where predicate: (Element) throws -> Bool
) rethrows -> Index {
var n = count
var l = startIndex
while n > 0 {
let half = n / 2
let mid = index(l, offsetBy: half)
if try predicate(self[mid]) {
n = half
} else {
l = index(after: mid)
n -= half + 1
}
}
return l
}
}
@@ -0,0 +1,564 @@
//===----------------------------------------------------------*- swift -*-===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//
/// A set of values of any comparable type, represented by ranges.
///
/// You can use a range set to efficiently represent a set of `Comparable`
/// values that spans any number of discontiguous ranges. Range sets are
/// commonly used to represent multiple subranges of a collection, by storing
/// ranges of a collection's index type.
///
/// In this example, `negativeSubranges` is a range set representing the
/// locations of all the negative values in `numbers`:
///
/// var numbers = [10, 12, -5, 14, -3, -9, 15]
/// let negativeSubranges = numbers.subranges(where: { $0 < 0 })
/// // numbers[negativeSubranges].count == 3
///
/// numbers.moveSubranges(negativeSubranges, to: 0)
/// // numbers == [-5, -3, -9, 10, 12, 14, 15]
public struct RangeSet<Bound: Comparable> {
internal var _ranges = _RangeSetStorage<Bound>()
/// Creates an empty range set.
public init() {}
/// Creates a range set containing the given range.
///
/// - Parameter range: The range to use for the new range set.
public init(_ range: Range<Bound>) {
if !range.isEmpty {
self._ranges = _RangeSetStorage(range)
}
}
/// Creates a range set containing the values in the given ranges.
///
/// Any empty ranges in `ranges` are ignored, and non-empty ranges are merged
/// to eliminate any overlaps. As such, the `ranges` collection in the
/// resulting range set may not be equivalent to the sequence of ranges
/// passed to this initializer.
///
/// - Parameter ranges: The ranges to use for the new range set.
public init<S: Sequence>(_ ranges: S) where S.Element == Range<Bound> {
for range in ranges {
insert(contentsOf: range)
}
}
/// Checks the invariants of `_ranges`.
///
/// The ranges stored by a range set are never empty, never overlap,
/// and are always stored in ascending order when comparing their lower
/// or upper bounds. In addition to not overlapping, no two consecutive
/// ranges share an upper and lower bound `[0..<5, 5..<10]` is ill-formed,
/// and would instead be represented as `[0..<10]`.
internal func _checkInvariants() {
for (a, b) in zip(ranges, ranges.dropFirst()) {
precondition(!a.isEmpty && !b.isEmpty, "Empty range in range set")
precondition(
a.upperBound < b.lowerBound,
"Out of order/overlapping ranges in range set")
}
}
/// Creates a new range set from `ranges`, which satisfies the range set
/// invariants.
internal init(_orderedRanges ranges: [Range<Bound>]) {
self._ranges = _RangeSetStorage(ranges)
_checkInvariants()
}
/// A Boolean value indicating whether the range set is empty.
public var isEmpty: Bool {
_ranges.isEmpty
}
/// Returns a Boolean value indicating whether the given value is
/// contained by the ranges in the range set.
///
/// - Parameter value: The value to look for in the range set.
/// - Returns: `true` if `value` is contained by a range in the range set;
/// otherwise, `false`.
///
/// - Complexity: O(log *n*), where *n* is the number of ranges in the
/// range set.
public func contains(_ value: Bound) -> Bool {
let i = _ranges._partitioningIndex { $0.upperBound > value }
return i == _ranges.endIndex
? false
: _ranges[i].lowerBound <= value
}
public func intersects(_ range: Range<Bound>) -> Bool {
if _ranges.isEmpty {
return false
}
if range.isEmpty {
return false
}
if range.lowerBound > _ranges.last!.upperBound {
return false
}
if range.upperBound < _ranges.first!.lowerBound {
return false
}
return !_indicesOfRange(range).isEmpty
}
/// Returns a range indicating the existing ranges that `range` overlaps
/// with.
///
/// For example, if `self` is `[0..<5, 10..<15, 20..<25, 30..<35]`, then:
///
/// - `_indicesOfRange(12..<14) == 1..<2`
/// - `_indicesOfRange(12..<19) == 1..<2`
/// - `_indicesOfRange(17..<19) == 2..<2`
/// - `_indicesOfRange(12..<22) == 1..<3`
func _indicesOfRange(_ range: Range<Bound>) -> Range<Int> {
precondition(!range.isEmpty)
precondition(!_ranges.isEmpty)
precondition(range.lowerBound <= _ranges.last!.upperBound)
precondition(range.upperBound >= _ranges.first!.lowerBound)
// The beginning index for the position of `range` is the first range
// with an upper bound larger than `range`'s lower bound. The range
// at this position may or may not overlap `range`.
let beginningIndex = _ranges
._partitioningIndex { $0.upperBound >= range.lowerBound }
// The ending index for `range` is the first range with a lower bound
// greater than `range`'s upper bound. If this is the same as
// `beginningIndex`, than `range` doesn't overlap any of the existing
// ranges. If this is `ranges.endIndex`, then `range` overlaps the
// rest of the ranges. Otherwise, `range` overlaps one or
// more ranges in the set.
let endingIndex = _ranges[beginningIndex...]
._partitioningIndex { $0.lowerBound > range.upperBound }
return beginningIndex ..< endingIndex
}
/// Inserts a non-empty range that is known to be greater than all the
/// elements in the set so far.
///
/// - Precondition: The range set must be empty, or else
/// `ranges.last!.upperBound <= range.lowerBound`.
/// - Precondition: `range` must not be empty.
internal mutating func _append(_ range: Range<Bound>) {
precondition(_ranges.isEmpty
|| _ranges.last!.upperBound <= range.lowerBound)
precondition(!range.isEmpty)
if _ranges.isEmpty {
_ranges.append(range)
} else if _ranges.last!.upperBound == range.lowerBound {
_ranges[_ranges.count - 1] =
_ranges[_ranges.count - 1].lowerBound ..< range.upperBound
} else {
_ranges.append(range)
}
}
/// Inserts the given range into the range set.
///
/// - Parameter range: The range to insert into the set.
///
/// - Complexity: O(*n*), where *n* is the number of ranges in the range
/// set.
public mutating func insert(contentsOf range: Range<Bound>) {
// Shortcuts for the (literal) edge cases
if range.isEmpty { return }
guard !_ranges.isEmpty else {
_ranges.append(range)
return
}
guard range.lowerBound < _ranges.last!.upperBound else {
_append(range)
return
}
guard range.upperBound >= _ranges.first!.lowerBound else {
_ranges.insert(range, at: 0)
return
}
let indices = _indicesOfRange(range)
// Non-overlapping is a simple insertion.
guard !indices.isEmpty else {
_ranges.insert(range, at: indices.lowerBound)
return
}
// Find the lower and upper bounds of the overlapping ranges.
let newLowerBound = Swift.min(
_ranges[indices.lowerBound].lowerBound,
range.lowerBound)
let newUpperBound = Swift.max(
_ranges[indices.upperBound - 1].upperBound,
range.upperBound)
_ranges.replaceSubrange(
indices,
with: CollectionOfOne(newLowerBound..<newUpperBound))
}
/// Removes the given range from the range set.
///
/// - Parameter range: The range to remove from the set.
///
/// - Complexity: O(*n*), where *n* is the number of ranges in the range
/// set.
public mutating func remove(contentsOf range: Range<Bound>) {
// Shortcuts for the (literal) edge cases
if range.isEmpty
|| _ranges.isEmpty
|| range.lowerBound >= _ranges.last!.upperBound
|| range.upperBound < _ranges.first!.lowerBound
{ return }
let indices = _indicesOfRange(range)
// No actual overlap, nothing to remove.
if indices.isEmpty { return }
let overlapsLowerBound =
range.lowerBound > _ranges[indices.lowerBound].lowerBound
let overlapsUpperBound =
range.upperBound < _ranges[indices.upperBound - 1].upperBound
switch (overlapsLowerBound, overlapsUpperBound) {
case (false, false):
_ranges.removeSubrange(indices)
case (false, true):
let newRange =
range.upperBound..<_ranges[indices.upperBound - 1].upperBound
_ranges.replaceSubrange(indices, with: CollectionOfOne(newRange))
case (true, false):
let newRange = _ranges[indices.lowerBound].lowerBound..<range.lowerBound
_ranges.replaceSubrange(indices, with: CollectionOfOne(newRange))
case (true, true):
_ranges.replaceSubrange(indices, with: Pair(
_ranges[indices.lowerBound].lowerBound..<range.lowerBound,
range.upperBound..<_ranges[indices.upperBound - 1].upperBound
))
}
}
}
extension RangeSet: Equatable {}
extension RangeSet: Hashable where Bound: Hashable {}
// MARK: - Range Collection
extension RangeSet {
/// A collection of the ranges that make up a range set.
public struct Ranges: RandomAccessCollection {
var _ranges: _RangeSetStorage<Bound>
public var startIndex: Int { _ranges.startIndex }
public var endIndex: Int { _ranges.endIndex }
public subscript(i: Int) -> Range<Bound> {
_ranges[i]
}
}
/// A collection of the ranges that make up the range set.
///
/// The ranges that you access by using `ranges` never overlap, are never
/// empty, and are always in increasing order.
public var ranges: Ranges {
Ranges(_ranges: _ranges)
}
}
// MARK: - Collection APIs
extension RangeSet {
/// Creates a new range set containing ranges that contain only the
/// specified indices in the given collection.
///
/// - Parameters:
/// - index: The index to include in the range set. `index` must be a
/// valid index of `collection` that isn't the collection's `endIndex`.
/// - collection: The collection that contains `index`.
public init<S, C>(_ indices: S, within collection: C)
where S: Sequence, C: Collection, S.Element == C.Index, C.Index == Bound
{
for i in indices {
self.insert(i, within: collection)
}
}
/// Inserts a range that contains only the specified index into the range
/// set.
///
/// - Parameters:
/// - index: The index to insert into the range set. `index` must be a
/// valid index of `collection` that isn't the collection's `endIndex`.
/// - collection: The collection that contains `index`.
///
/// - Complexity: O(*n*), where *n* is the number of ranges in the range
/// set.
public mutating func insert<C>(_ index: Bound, within collection: C)
where C: Collection, C.Index == Bound
{
insert(contentsOf: index ..< collection.index(after: index))
}
/// Removes the range that contains only the specified index from the range
/// set.
///
/// - Parameters:
/// - index: The index to remove from the range set. `index` must be a
/// valid index of `collection` that isn't the collection's `endIndex`.
/// - collection: The collection that contains `index`.
///
/// - Complexity: O(*n*), where *n* is the number of ranges in the range
/// set.
public mutating func remove<C>(_ index: Bound, within collection: C)
where C: Collection, C.Index == Bound
{
remove(contentsOf: index ..< collection.index(after: index))
}
/// Returns a range set that represents all the elements in the given
/// collection that aren't represented by this range set.
///
/// - Parameter collection: The collection that the range set is relative
/// to.
/// - Returns: A new range set that represents the elements in `collection`
/// that aren't represented by this range set.
///
/// - Complexity: O(*n*), where *n* is the number of ranges in the range
/// set.
internal func _inverted<C>(within collection: C) -> RangeSet
where C: Collection, C.Index == Bound
{
return _gaps(
boundedBy: collection.startIndex..<collection.endIndex)
}
/// Returns a range set that represents the ranges of values within the
/// given bounds that aren't represented by this range set.
internal func _gaps(boundedBy bounds: Range<Bound>) -> RangeSet {
guard !_ranges.isEmpty else { return RangeSet(bounds) }
guard let start = _ranges.firstIndex(where: { $0.lowerBound >= bounds.lowerBound })
else { return RangeSet() }
guard let end = _ranges.lastIndex(where: { $0.upperBound <= bounds.upperBound })
else { return RangeSet() }
var result = RangeSet()
var low = bounds.lowerBound
for range in _ranges[start...end] {
result.insert(contentsOf: low..<range.lowerBound)
low = range.upperBound
}
result.insert(contentsOf: low..<bounds.upperBound)
return result
}
}
// MARK: - SetAlgebra
// These methods only depend on the ranges that comprise the range set, so
// we can provide them even when we can't provide `SetAlgebra` conformance.
extension RangeSet {
/// Adds the contents of the given range set to this range set.
///
/// - Parameter other: A range set to merge with this one.
public mutating func formUnion(_ other: __owned RangeSet<Bound>) {
for range in other._ranges {
insert(contentsOf: range)
}
}
/// Removes the contents of this range set that aren't also in the given
/// range set.
///
/// - Parameter other: A range set to intersect with.
public mutating func formIntersection(_ other: RangeSet<Bound>) {
self = self.intersection(other)
}
/// Removes the contents of this range set that are also in the given set
/// and adds the contents of the given set that are not already in this
/// range set.
///
/// - Parameter other: A range set to perform a symmetric difference against.
public mutating func formSymmetricDifference(
_ other: __owned RangeSet<Bound>
) {
self = self.symmetricDifference(other)
}
/// Removes the contents of the given range set from this range set.
///
/// - Parameter other: A range set to subtract from this one.
public mutating func subtract(_ other: RangeSet<Bound>) {
for range in other._ranges {
remove(contentsOf: range)
}
}
/// Returns a new range set containing the contents of both this set and the
/// given set.
///
/// - Parameter other: The range set to merge with this one.
/// - Returns: A new range set.
public __consuming func union(
_ other: __owned RangeSet<Bound>
) -> RangeSet<Bound> {
var result = self
result.formUnion(other)
return result
}
/// Returns a new range set containing the contents of both this set and the
/// given set.
///
/// - Parameter other: The range set to merge with this one.
/// - Returns: A new range set.
public __consuming func intersection(
_ other: RangeSet<Bound>
) -> RangeSet<Bound> {
var otherRangeIndex = 0
var result: [Range<Bound>] = []
// Considering these two range sets:
//
// self = [0..<5, 9..<14]
// other = [1..<3, 4..<6, 8..<12]
//
// `self.intersection(other)` looks like this, where x's cover the
// ranges in `self`, y's cover the ranges in `other`, and z's cover the
// resulting ranges:
//
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// xxxxxxxxxxxxxxxxxxx__ xxxxxxxxxxxxxxxxxxx__
// yyyyyyy__ yyyyyyy__ yyyyyyyyyyyyyyy__
// zzzzzzz__ zzz__ zzzzzzzzzzz__
//
// The same, but for `other.intersection(self)`:
//
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// xxxxxxx__ xxxxxxx__ xxxxxxxxxxxxxxx__
// yyyyyyyyyyyyyyyyyyy__ yyyyyyyyyyyyyyyyyyy__
// zzzzzzz__ zzz__ zzzzzzzzzzz__
for currentRange in _ranges {
// Search forward in `other` until finding either an overlapping
// range or one that is strictly higher than this range.
while otherRangeIndex < other._ranges.endIndex &&
other._ranges[otherRangeIndex].upperBound <= currentRange.lowerBound
{
otherRangeIndex += 1
}
// For each range in `other` that overlaps with the current range
// in `self`, append the intersection to the result.
while otherRangeIndex < other._ranges.endIndex &&
other._ranges[otherRangeIndex].lowerBound < currentRange.upperBound
{
let lower = Swift.max(
other._ranges[otherRangeIndex].lowerBound,
currentRange.lowerBound)
let upper = Swift.min(
other._ranges[otherRangeIndex].upperBound,
currentRange.upperBound)
result.append(lower..<upper)
// If the range in `other` continues past the current range in
// `self`, it could overlap the next range in `self`, so break
// out of examining the current range.
guard
currentRange.upperBound > other._ranges[otherRangeIndex].upperBound
else {
break
}
otherRangeIndex += 1
}
}
return RangeSet(_orderedRanges: result)
}
/// Returns a new range set representing the values in this range set or the
/// given range set, but not both.
///
/// - Parameter other: The range set to find a symmetric difference with.
/// - Returns: A new range set.
public __consuming func symmetricDifference(
_ other: __owned RangeSet<Bound>
) -> RangeSet<Bound> {
return union(other).subtracting(intersection(other))
}
/// Returns a new set containing the contents of this range set that are not
/// also in the given range set.
///
/// - Parameter other: The range set to subtract.
/// - Returns: A new range set.
public func subtracting(_ other: RangeSet<Bound>) -> RangeSet<Bound> {
var result = self
result.subtract(other)
return result
}
/// Returns a Boolean value that indicates whether this range set is a
/// subset of the given set.
///
/// - Parameter other: A range set to compare against.
/// - Returns: `true` if this range set is a subset of `other`;
/// otherwise, `false`.
public func isSubset(of other: RangeSet<Bound>) -> Bool {
self.intersection(other) == self
}
/// Returns a Boolean value that indicates whether this range set is a
/// superset of the given set.
///
/// - Parameter other: A range set to compare against.
/// - Returns: `true` if this range set is a superset of `other`;
/// otherwise, `false`.
public func isSuperset(of other: RangeSet<Bound>) -> Bool {
other.isSubset(of: self)
}
/// Returns a Boolean value that indicates whether this range set is a
/// strict subset of the given set.
///
/// - Parameter other: A range set to compare against.
/// - Returns: `true` if this range set is a strict subset of `other`;
/// otherwise, `false`.
public func isStrictSubset(of other: RangeSet<Bound>) -> Bool {
self != other && isSubset(of: other)
}
/// Returns a Boolean value that indicates whether this range set is a
/// strict superset of the given set.
///
/// - Parameter other: A range set to compare against.
/// - Returns: `true` if this range set is a strict superset of `other`;
/// otherwise, `false`.
public func isStrictSuperset(of other: RangeSet<Bound>) -> Bool {
other.isStrictSubset(of: self)
}
}
extension RangeSet: CustomStringConvertible {
public var description: String {
let rangesDescription = _ranges
.map { r in "\(r.lowerBound)..<\(r.upperBound)" }
.joined(separator: ", ")
return "RangeSet(\(rangesDescription))"
}
}
@@ -0,0 +1,181 @@
//===----------------------------------------------------------*- swift -*-===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//
struct _RangeSetStorage<T: Comparable> {
fileprivate enum _Storage {
case empty
case singleRange(high: Int, low: Int32)
case variadic([Range<T>])
}
fileprivate var _storage: _Storage
init() {
_storage = .empty
}
init(_ range: Range<T>) {
if let intRange = range as? Range<Int>,
let lowerBound = Int32(exactly: intRange.lowerBound)
{
_storage = .singleRange(high: intRange.upperBound, low: lowerBound)
} else {
_storage = .variadic([range])
}
}
init(_ ranges: [Range<T>]) {
_storage = .variadic(ranges)
}
func unsafeRange(low: Int32, high: Int) -> Range<T> {
unsafeBitCast(Int(low)..<high, to: Range<T>.self)
}
}
// _RangeSetStorage has custom Equatable (and therefore Hashable)
// conformance, since the same "value" can be represented by different
// storage structures. For example, `.empty` and `.variadic([])` are
// equivalent, but the synthesized conformance treats them as distinct.
// The same holds with the `singleRange` representation and `variadic`
// with a single-element array.
extension _RangeSetStorage: Equatable {
static func == (lhs: _RangeSetStorage, rhs: _RangeSetStorage) -> Bool {
switch (lhs._storage, rhs._storage) {
case (.empty, .empty):
return true
case (.empty, .singleRange), (.singleRange, .empty):
return false
case let (.empty, .variadic(ranges)),
let (.variadic(ranges), .empty):
return ranges.isEmpty
case let (.singleRange(lhsHigh, lhsLow), .singleRange(rhsHigh, rhsLow)):
return (lhsLow, lhsHigh) == (rhsLow, rhsHigh)
case let (.singleRange(high, low), .variadic(ranges)),
let (.variadic(ranges), .singleRange(high, low)):
return ranges.count == 1 &&
(ranges[0] as! Range<Int>) == Int(low)..<high
case let (.variadic(lhsRanges), .variadic(rhsRanges)):
return lhsRanges == rhsRanges
}
}
}
extension _RangeSetStorage: Hashable where T: Hashable {
func hash(into hasher: inout Hasher) {
for range in self {
hasher.combine(range)
}
}
}
extension _RangeSetStorage: RandomAccessCollection, MutableCollection {
var startIndex: Int { 0 }
var endIndex: Int {
switch _storage {
case .empty: return 0
case .singleRange: return 1
case let .variadic(ranges): return ranges.count
}
}
subscript(i: Int) -> Range<T> {
get {
switch _storage {
case .empty: fatalError("Can't access elements of empty storage")
case let .singleRange(high, low):
assert(T.self == Int.self)
return unsafeRange(low: low, high: high)
case let .variadic(ranges):
return ranges[i]
}
}
set {
switch _storage {
case .empty: fatalError("Can't access elements of empty storage")
case .singleRange:
assert(T.self == Int.self)
let intRange = newValue as! Range<Int>
if let lowerBound = Int32(exactly: intRange.lowerBound) {
_storage = .singleRange(high: intRange.upperBound, low: lowerBound)
} else {
_storage = .variadic([newValue])
}
case .variadic(var ranges):
// Temporarily set `_storage` to empty so that `ranges`
// remains uniquely referenced while mutating.
_storage = .empty
ranges[i] = newValue
_storage = .variadic(ranges)
}
}
}
var count: Int {
switch _storage {
case .empty: return 0
case .singleRange: return 1
case let .variadic(ranges): return ranges.count
}
}
}
extension _RangeSetStorage: RangeReplaceableCollection {
mutating func replaceSubrange<C>(_ subrange: Range<Int>, with newElements: C) where C : Collection, C.Element == Element {
switch _storage {
case .empty:
if !newElements.isEmpty {
_storage = .variadic(Array(newElements))
}
case .singleRange(high: let high, low: let low):
switch (subrange.isEmpty, newElements.isEmpty) {
case (false, true):
// Replacing the single range with an empty collection.
_storage = .empty
case (false, false):
// Replacing the single range with a non-empty collection;
// promote to a variadic container.
_storage = .variadic(Array(newElements))
case (true, true):
// Inserting an empty collection; no-op.
break
case (true, false):
// Inserting a non-empty collection either before or after
// the existing single element.
var ranges: [Range<T>]
if subrange.lowerBound == 0 {
ranges = Array(newElements)
ranges.append(unsafeRange(low: low, high: high))
} else {
ranges = [unsafeRange(low: low, high: high)]
ranges.append(contentsOf: newElements)
}
_storage = .variadic(ranges)
}
case .variadic(var ranges):
// Temporarily set `_storage` to empty so that `ranges`
// remains uniquely referenced while mutating.
_storage = .empty
ranges.replaceSubrange(subrange, with: newElements)
_storage = .variadic(ranges)
}
}
}