//===--- ClosedRange.swift ------------------------------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2016 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 // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // FIXME: swift-3-indexing-model: Generalize all tests to check both // [Closed]Range and [Closed]CountableRange. internal enum _ClosedRangeIndexRepresentation where // WORKAROUND rdar://25214598 - should be Bound : Strideable Bound : _Strideable & Comparable, Bound.Stride : Integer { case pastEnd case inRange(Bound) } // FIXME(ABI)#23 (Nesting types in generics): should be a nested type in // `ClosedRange`. /// A position in a `CountableClosedRange` instance. public struct ClosedRangeIndex where // WORKAROUND rdar://25214598 - should be Bound : Strideable // swift-3-indexing-model: should conform to _Strideable, otherwise // CountableClosedRange is not interchangeable with CountableRange in all // contexts. Bound : _Strideable & Comparable, Bound.Stride : SignedInteger { /// Creates the "past the end" position. internal init() { _value = .pastEnd } /// Creates a position `p` for which `r[p] == x`. internal init(_ x: Bound) { _value = .inRange(x) } internal var _value: _ClosedRangeIndexRepresentation internal var _dereferenced: Bound { switch _value { case .inRange(let x): return x case .pastEnd: _preconditionFailure("Index out of range") } } } extension ClosedRangeIndex : Comparable { public static func == ( lhs: ClosedRangeIndex, rhs: ClosedRangeIndex ) -> Bool { switch (lhs._value, rhs._value) { case (.inRange(let l), .inRange(let r)): return l == r case (.pastEnd, .pastEnd): return true default: return false } } public static func < ( lhs: ClosedRangeIndex, rhs: ClosedRangeIndex ) -> Bool { switch (lhs._value, rhs._value) { case (.inRange(let l), .inRange(let r)): return l < r case (.inRange(_), .pastEnd): return true default: return false } } } // WORKAROUND: needed because of rdar://25584401 /// An iterator over the elements of a `CountableClosedRange` instance. public struct ClosedRangeIterator : IteratorProtocol, Sequence where // WORKAROUND rdar://25214598 - should be just Bound : Strideable Bound : _Strideable & Comparable, Bound.Stride : SignedInteger { internal init(_range r: CountableClosedRange) { _nextResult = r.lowerBound _upperBound = r.upperBound } public func makeIterator() -> ClosedRangeIterator { return self } public mutating func next() -> Bound? { let r = _nextResult if let x = r { _nextResult = x == _upperBound ? nil : x.advanced(by: 1) } return r } internal var _nextResult: Bound? internal let _upperBound: Bound } /// A closed range that forms a collection of consecutive values. /// /// You create a `CountableClosedRange` instance by using the closed range /// operator (`...`). /// /// let throughFive = 0...5 /// /// A `CountableClosedRange` instance contains both its lower bound and its /// upper bound. /// /// print(throughFive.contains(3)) // Prints "true" /// print(throughFive.contains(10)) // Prints "false" /// print(throughFive.contains(5)) // Prints "true" /// /// Because a closed range includes its upper bound, a closed range whose lower /// bound is equal to the upper bound contains one element. Therefore, a /// `CountableClosedRange` instance cannot represent an empty range. /// /// let zeroInclusive = 0...0 /// print(zeroInclusive.isEmpty) /// // Prints "false" /// print(zeroInclusive.count) /// // Prints "1" /// /// You can use a `for`-`in` loop or any sequence or collection method with a /// countable range. The elements of the range are the consecutive values from /// its lower bound up to, and including, its upper bound. /// /// for n in throughFive.suffix(3) { /// print(n) /// } /// // Prints "3" /// // Prints "4" /// // Prints "5" /// /// You can create a countable range over any type that conforms to the /// `Strideable` protocol and uses an integer as its associated `Stride` type. /// By default, Swift's integer and pointer types are usable as the bounds of /// a countable range. /// /// Because floating-point types such as `Float` and `Double` are their own /// `Stride` types, they cannot be used as the bounds of a countable range. If /// you need to test whether values are contained within a closed interval /// bound by floating-point values, see the `ClosedRange` type. If you need to /// iterate over consecutive floating-point values, see the /// `stride(from:through:by:)` function. /// /// - SeeAlso: `CountableRange`, `ClosedRange`, `Range` public struct CountableClosedRange : RandomAccessCollection where // WORKAROUND rdar://25214598 - should be just Bound : Strideable Bound : _Strideable & Comparable, Bound.Stride : SignedInteger { /// The range's lower bound. public let lowerBound: Bound /// The range's upper bound. /// /// `upperBound` is always reachable from `lowerBound` by zero or /// more applications of `index(after:)`. public let upperBound: Bound /// The element type of the range; the same type as the range's bounds. public typealias Element = Bound /// A type that represents a position in the range. public typealias Index = ClosedRangeIndex public typealias IndexDistance = Bound.Stride // WORKAROUND: needed because of rdar://25584401 public typealias Iterator = ClosedRangeIterator // WORKAROUND: needed because of rdar://25584401 public func makeIterator() -> ClosedRangeIterator { return ClosedRangeIterator(_range: self) } /// The position of the first element in the range. public var startIndex: ClosedRangeIndex { return ClosedRangeIndex(lowerBound) } /// The range's "past the end" position---that is, the position one greater /// than the last valid subscript argument. public var endIndex: ClosedRangeIndex { return ClosedRangeIndex() } public func index(after i: Index) -> Index { switch i._value { case .inRange(let x): return x == upperBound ? ClosedRangeIndex() : ClosedRangeIndex(x.advanced(by: 1)) case .pastEnd: _preconditionFailure("Incrementing past end index") } } public func index(before i: Index) -> Index { switch i._value { case .inRange(let x): _precondition(x > lowerBound, "Incrementing past start index") return ClosedRangeIndex(x.advanced(by: -1)) case .pastEnd: _precondition(upperBound >= lowerBound, "Incrementing past start index") return ClosedRangeIndex(upperBound) } } public func index(_ i: Index, offsetBy n: IndexDistance) -> Index { switch i._value { case .inRange(let x): let d = x.distance(to: upperBound) if n <= d { let newPosition = x.advanced(by: n) _precondition(newPosition >= lowerBound, "Advancing past start index") return ClosedRangeIndex(newPosition) } if d - -1 == n { return ClosedRangeIndex() } _preconditionFailure("Advancing past end index") case .pastEnd: if n == 0 { return i } if n < 0 { return index(ClosedRangeIndex(upperBound), offsetBy: (n + 1)) } _preconditionFailure("Advancing past end index") } } public func distance(from start: Index, to end: Index) -> IndexDistance { switch (start._value, end._value) { case let (.inRange(left), .inRange(right)): // in range <--> in range return left.distance(to: right) case let (.inRange(left), .pastEnd): // in range --> end return 1 + left.distance(to: upperBound) case let (.pastEnd, .inRange(right)): // in range <-- end return upperBound.distance(to: right) - 1 case (.pastEnd, .pastEnd): // end <--> end return 0 } } /// Accesses the element at specified position. /// /// You can subscript a collection with any valid index other than the /// collection's end index. The end index refers to the position one past /// the last element of a collection, so it doesn't correspond with an /// element. /// /// - Parameter position: The position of the element to access. `position` /// must be a valid index of the range, and must not equal the range's end /// index. public subscript(position: ClosedRangeIndex) -> Bound { // FIXME: swift-3-indexing-model: range checks and tests. return position._dereferenced } public subscript(bounds: Range) -> RandomAccessSlice> { return RandomAccessSlice(base: self, bounds: bounds) } public // WORKAROUND: needed because of rdar://25584401 var indices: DefaultRandomAccessIndices> { return DefaultRandomAccessIndices( _elements: self, startIndex: self.startIndex, endIndex: self.endIndex) } /// Creates an instance with the given bounds. /// /// Because this initializer does not perform any checks, it should be used /// as an optimization only when you are absolutely certain that `lower` is /// less than or equal to `upper`. Using the closed range operator (`...`) /// to form `CountableClosedRange` instances is preferred. /// /// - Parameter bounds: A tuple of the lower and upper bounds of the range. public init(uncheckedBounds bounds: (lower: Bound, upper: Bound)) { self.lowerBound = bounds.lower self.upperBound = bounds.upper } public func _customContainsEquatableElement(_ element: Bound) -> Bool? { return element >= self.lowerBound && element <= self.upperBound } /// A Boolean value indicating whether the range contains no elements. /// /// Because a closed range cannot represent an empty range, this property is /// always `false`. public var isEmpty: Bool { return false } } /// An interval over a comparable type, from a lower bound up to, and /// including, an upper bound. /// /// You create instances of `ClosedRange` by using the closed range operator /// (`...`). /// /// let lowercase = "a"..."z" /// /// You can use a `ClosedRange` instance to quickly check if a value is /// contained in a particular range of values. For example: /// /// print(lowercase.contains("c")) // Prints "true" /// print(lowercase.contains("5")) // Prints "false" /// print(lowercase.contains("z")) // Prints "true" /// /// Unlike `Range`, instances of `ClosedRange` cannot represent an empty /// interval. /// /// let lowercaseA = "a"..."a" /// print(lowercaseA.isEmpty) /// // Prints "false" /// /// - SeeAlso: `CountableRange`, `Range`, `CountableClosedRange` @_fixed_layout public struct ClosedRange< Bound : Comparable > { /// Creates an instance with the given bounds. /// /// Because this initializer does not perform any checks, it should be used /// as an optimization only when you are absolutely certain that `lower` is /// less than or equal to `upper`. Using the closed range operator (`...`) /// to form `ClosedRange` instances is preferred. /// /// - Parameter bounds: A tuple of the lower and upper bounds of the range. @inline(__always) public init(uncheckedBounds bounds: (lower: Bound, upper: Bound)) { self.lowerBound = bounds.lower self.upperBound = bounds.upper } /// The range's lower bound. public let lowerBound: Bound /// The range's upper bound. public let upperBound: Bound /// Returns a Boolean value indicating whether the given element is contained /// within the range. /// /// A `ClosedRange` instance contains both its lower and upper bound. /// `element` is contained in the range if it is between the two bounds or /// equal to either bound. /// /// - Parameter element: The element to check for containment. /// - Returns: `true` if `element` is contained in the range; otherwise, /// `false`. public func contains(_ element: Bound) -> Bool { return element >= self.lowerBound && element <= self.upperBound } /// A Boolean value indicating whether the range contains no elements. /// /// Because a closed range cannot represent an empty range, this property is /// always `false`. public var isEmpty: Bool { return false } } /// Returns a closed range that contains both of its bounds. /// /// Use the closed range operator (`...`) to create a closed range of any type /// that conforms to the `Comparable` protocol. This example creates a /// `ClosedRange` from "a" up to, and including, "z". /// /// let lowercase = "a"..."z" /// print(lowercase.contains("z")) /// // Prints "true" /// /// - Parameters: /// - minimum: The lower bound for the range. /// - maximum: The upper bound for the range. @_transparent public func ... (minimum: Bound, maximum: Bound) -> ClosedRange { _precondition( minimum <= maximum, "Can't form Range with upperBound < lowerBound") return ClosedRange(uncheckedBounds: (lower: minimum, upper: maximum)) } /// Returns a countable closed range that contains both of its bounds. /// /// Use the closed range operator (`...`) to create a closed range of any type /// that conforms to the `Strideable` protocol with an associated signed /// integer `Stride` type, such as any of the standard library's integer /// types. This example creates a `CountableClosedRange` from zero up to, /// and including, nine. /// /// let singleDigits = 0...9 /// print(singleDigits.contains(9)) /// // Prints "true" /// /// You can use sequence or collection methods on the `singleDigits` range. /// /// print(singleDigits.count) /// // Prints "10" /// print(singleDigits.last) /// // Prints "9" /// /// - Parameters: /// - minimum: The lower bound for the range. /// - maximum: The upper bound for the range. @_transparent public func ... ( minimum: Bound, maximum: Bound ) -> CountableClosedRange where // WORKAROUND rdar://25214598 - should be just Bound : Strideable Bound : _Strideable & Comparable, Bound.Stride : SignedInteger { // FIXME: swift-3-indexing-model: tests for traps. _precondition( minimum <= maximum, "Can't form Range with upperBound < lowerBound") return CountableClosedRange(uncheckedBounds: (lower: minimum, upper: maximum)) } extension ClosedRange { @available(*, unavailable, renamed: "lowerBound") public var startIndex: Bound { Builtin.unreachable() } @available(*, unavailable, renamed: "upperBound") public var endIndex: Bound { Builtin.unreachable() } }