|
10 | 10 | //
|
11 | 11 | //===----------------------------------------------------------------------===//
|
12 | 12 |
|
| 13 | +/// A type which can be used to slice a collection. A `RangeExpression` can |
| 14 | +/// convert itself to a `Range<Bound>` of indices within a given collection; |
| 15 | +/// the collection can then slice itself with that `Range`. |
| 16 | +public protocol RangeExpression { |
| 17 | + associatedtype Bound: Comparable |
| 18 | + /// Returns `self` expressed as a range of indices within `collection`. |
| 19 | + /// |
| 20 | + /// -Parameter collection: The collection `self` should be |
| 21 | + /// relative to. |
| 22 | + /// |
| 23 | + /// -Returns: A `Range<Bound>` suitable for slicing `collection`. |
| 24 | + /// The return value is *not* guaranteed to be inside |
| 25 | + /// its bounds. Callers should apply the same preconditions |
| 26 | + /// to the return value as they would to a range provided |
| 27 | + /// directly by the user. |
| 28 | + func relative<C: _Indexable>(to collection: C) -> Range<Bound> where C.Index == Bound |
| 29 | + |
| 30 | + func contains(_ element: Bound) -> Bool |
| 31 | +} |
| 32 | + |
| 33 | +extension RangeExpression { |
| 34 | + @_inlineable |
| 35 | + public static func ~= (pattern: Self, value: Bound) -> Bool { |
| 36 | + return pattern.contains(value) |
| 37 | + } |
| 38 | +} |
| 39 | + |
13 | 40 | // FIXME(ABI)#55 (Statically Unavailable/Dynamically Available): remove this type, it creates an ABI burden
|
14 | 41 | // on the library.
|
15 | 42 | //
|
@@ -513,6 +540,18 @@ extension ${Self} {
|
513 | 540 | }
|
514 | 541 | }
|
515 | 542 |
|
| 543 | +extension ${Self}: RangeExpression { |
| 544 | + public func relative<C: _Indexable>(to collection: C) -> Range<Bound> where C.Index == Bound { |
| 545 | + % if 'Closed' in Self: |
| 546 | + return Range(uncheckedBounds: |
| 547 | + (lower: lowerBound, upper: collection.index(after: self.upperBound)) |
| 548 | + % else: |
| 549 | + return Range(uncheckedBounds: (lower: lowerBound, upper: upperBound) |
| 550 | + % end |
| 551 | + ) |
| 552 | + } |
| 553 | +} |
| 554 | + |
516 | 555 | extension ${Self} : CustomStringConvertible {
|
517 | 556 | /// A textual representation of the range.
|
518 | 557 | public var description: String {
|
@@ -697,6 +736,201 @@ public func ..< <Bound>(
|
697 | 736 | return CountableRange(uncheckedBounds: (lower: minimum, upper: maximum))
|
698 | 737 | }
|
699 | 738 |
|
| 739 | +@_fixed_layout |
| 740 | +public struct PartialRangeUpTo<Bound: Comparable>: RangeExpression { |
| 741 | + public init(_ upperBound: Bound) { self.upperBound = upperBound } |
| 742 | + public let upperBound: Bound |
| 743 | + @_transparent |
| 744 | + public func relative<C: _Indexable>(to collection: C) -> Range<Bound> where C.Index == Bound { |
| 745 | + return collection.startIndex..<self.upperBound |
| 746 | + } |
| 747 | + @_transparent |
| 748 | + public func contains(_ element: Bound) -> Bool { |
| 749 | + return element < upperBound |
| 750 | + } |
| 751 | +} |
| 752 | + |
| 753 | +@_fixed_layout |
| 754 | +public struct PartialRangeThrough<Bound: Comparable>: RangeExpression { |
| 755 | + public init(_ upperBound: Bound) { self.upperBound = upperBound } |
| 756 | + public let upperBound: Bound |
| 757 | + @_transparent |
| 758 | + public func relative<C: _Indexable>(to collection: C) -> Range<Bound> where C.Index == Bound { |
| 759 | + return collection.startIndex..<collection.index(after: self.upperBound) |
| 760 | + } |
| 761 | + @_transparent |
| 762 | + public func contains(_ element: Bound) -> Bool { |
| 763 | + return element <= upperBound |
| 764 | + } |
| 765 | +} |
| 766 | + |
| 767 | +@_fixed_layout |
| 768 | +public struct PartialRangeFrom<Bound: Comparable>: RangeExpression { |
| 769 | + public init(_ lowerBound: Bound) { self.lowerBound = lowerBound } |
| 770 | + public let lowerBound: Bound |
| 771 | + @_transparent |
| 772 | + public func relative<C: _Indexable>(to collection: C) -> Range<Bound> where C.Index == Bound { |
| 773 | + return self.lowerBound..<collection.endIndex |
| 774 | + } |
| 775 | + @_transparent |
| 776 | + public func contains(_ element: Bound) -> Bool { |
| 777 | + return lowerBound <= element |
| 778 | + } |
| 779 | +} |
| 780 | + |
| 781 | +@_fixed_layout |
| 782 | +public struct CountablePartialRangeFrom< |
| 783 | + Bound: Strideable |
| 784 | +>: RangeExpression where Bound.Stride : SignedInteger { |
| 785 | + public init(_ lowerBound: Bound) { self.lowerBound = lowerBound } |
| 786 | + public let lowerBound: Bound |
| 787 | + @_transparent |
| 788 | + public func relative<C: _Indexable>( |
| 789 | + to collection: C |
| 790 | + ) -> Range<Bound> where C.Index == Bound { |
| 791 | + return self.lowerBound..<collection.endIndex |
| 792 | + } |
| 793 | + public func contains(_ element: Bound) -> Bool { |
| 794 | + return lowerBound <= element |
| 795 | + } |
| 796 | +} |
| 797 | + |
| 798 | +extension CountablePartialRangeFrom: Sequence { |
| 799 | + @_fixed_layout |
| 800 | + public struct Iterator: IteratorProtocol { |
| 801 | + @_inlineable |
| 802 | + public init(_current: Bound) { self._current = _current } |
| 803 | + @_inlineable |
| 804 | + public mutating func next() -> Bound? { |
| 805 | + defer { _current = _current.advanced(by: 1) } |
| 806 | + return _current |
| 807 | + } |
| 808 | + @_versioned |
| 809 | + var _current: Bound |
| 810 | + } |
| 811 | + @_inlineable |
| 812 | + public func makeIterator() -> Iterator { |
| 813 | + return Iterator(_current: lowerBound) |
| 814 | + } |
| 815 | +} |
| 816 | + |
| 817 | +extension Comparable { |
| 818 | + /// Returns a partial range up to but not including its maximum. |
| 819 | + /// |
| 820 | + /// Use the partial range up to operator (`..<`) to create a partial range of |
| 821 | + /// any type that conforms to the `Comparable` protocol. This example creates |
| 822 | + /// a `PartialRangeUpTo<Double>` up to, but not including, 5.0. |
| 823 | + /// |
| 824 | + /// let lessThanFive = ..<5.0 |
| 825 | + /// print(lessThanFive.contains(3.14)) // Prints "true" |
| 826 | + /// print(lessThanFive.contains(5.0)) // Prints "false" |
| 827 | + /// |
| 828 | + /// Partial ranges can be used to slice types conforming to `Collection` |
| 829 | + /// from the start of the collection up to, but not including, the maximum. |
| 830 | + /// |
| 831 | + /// let array = Array(0..<5) |
| 832 | + /// print(array[..<3]) // prints [0, 1, 2] |
| 833 | + /// |
| 834 | + /// - Parameters: |
| 835 | + /// - maximum: The upper bound for the range. |
| 836 | + @_transparent |
| 837 | + public static prefix func ..<(maximum: Self) -> PartialRangeUpTo<Self> { |
| 838 | + return PartialRangeUpTo(maximum) |
| 839 | + } |
| 840 | + |
| 841 | + /// Returns a partial range up to and including its maximum. |
| 842 | + /// |
| 843 | + /// Use the partial range up to operator (`...`) to create a partial range of |
| 844 | + /// any type that conforms to the `Comparable` protocol. This example creates |
| 845 | + /// a `PartialRangeThrough<Double>` up to 5. |
| 846 | + /// |
| 847 | + /// let upToFive = ..<5.0 |
| 848 | + /// print(upToFive.contains(4)) // Prints "true" |
| 849 | + /// print(upToFive.contains(5)) // Prints "true" |
| 850 | + /// print(upToFive.contains(6)) // Prints "false" |
| 851 | + /// |
| 852 | + /// Partial ranges can be used to slice types conforming to `Collection` |
| 853 | + /// from the start of the collection up to the maximum. |
| 854 | + /// |
| 855 | + /// let array = Array(0..<5) |
| 856 | + /// print(array[...3]) // prints [0, 1, 2, 3] |
| 857 | + /// |
| 858 | + /// - Parameters: |
| 859 | + /// - maximum: The upper bound for the range. |
| 860 | + @_transparent |
| 861 | + public static prefix func ...(maximum: Self) -> PartialRangeThrough<Self> { |
| 862 | + return PartialRangeThrough(maximum) |
| 863 | + } |
| 864 | + |
| 865 | + /// Returns a countable partial range from a lower bound. |
| 866 | + /// |
| 867 | + /// Use the partial range up to operator (`...`) to create a range of any type |
| 868 | + /// that conforms to the `Strideable` protocol with an associated integer |
| 869 | + /// `Stride` type, such as any of the standard library's integer types. This |
| 870 | + /// example creates a `CountablePartialRangeFrom<Int>` from 5 up. |
| 871 | + /// |
| 872 | + /// let fiveOrMore = 5... |
| 873 | + /// print(fiveOrMore.contains(3)) // Prints "false" |
| 874 | + /// print(fiveOrMore.contains(5)) // Prints "true" |
| 875 | + /// |
| 876 | + /// - Parameters: |
| 877 | + /// - minimum: The lower bound for the range. |
| 878 | + @_transparent |
| 879 | + public static postfix func ...(minimum: Self) -> PartialRangeFrom<Self> { |
| 880 | + return PartialRangeFrom(minimum) |
| 881 | + } |
| 882 | +} |
| 883 | + |
| 884 | +extension Strideable where Stride: SignedInteger { |
| 885 | + /// Returns a countable partial range from a lower bound. |
| 886 | + /// |
| 887 | + /// Use the partial range up to operator (`...`) to create a range of any type |
| 888 | + /// that conforms to the `Strideable` protocol with an associated integer |
| 889 | + /// `Stride` type, such as any of the standard library's integer types. This |
| 890 | + /// example creates a `CountablePartialRangeFrom<Int>` from 5 up. |
| 891 | + /// |
| 892 | + /// let fiveOrMore = 5... |
| 893 | + /// print(fiveOrMore.contains(3)) // Prints "false" |
| 894 | + /// print(fiveOrMore.contains(5)) // Prints "true" |
| 895 | + /// |
| 896 | + /// You can use sequence methods on these partial ranges. |
| 897 | + /// |
| 898 | + /// let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
| 899 | + /// let asciiTable = zip(0x41..., alphabet) |
| 900 | + /// for (code, letter) in asciiTable { print(code, letter) } |
| 901 | + /// |
| 902 | + /// Note that these sequences count up indefinitely. You should not use them |
| 903 | + /// with algorithms such as `map` or `filter` that will try to read the entire |
| 904 | + /// sequence eagerly. The upper limit for the sequence is determined by the |
| 905 | + /// type of `Bound`. For example, `CountablePartialRangeFrom<Int>` will trap |
| 906 | + /// when the sequences' next value would be above `Int.max`. |
| 907 | + /// |
| 908 | + /// - Parameters: |
| 909 | + /// - minimum: The lower bound for the range. |
| 910 | + @_transparent |
| 911 | + public static postfix func ...(minimum: Self) -> CountablePartialRangeFrom<Self> { |
| 912 | + return CountablePartialRangeFrom(minimum) |
| 913 | + } |
| 914 | +} |
| 915 | + |
| 916 | +extension _Indexable { |
| 917 | + @_inlineable |
| 918 | + public subscript<R: RangeExpression>(r: R) -> SubSequence where R.Bound == Index { |
| 919 | + return self[r.relative(to: self)] |
| 920 | + } |
| 921 | +} |
| 922 | +extension _MutableIndexable { |
| 923 | + @_inlineable |
| 924 | + public subscript<R: RangeExpression>(r: R) -> SubSequence where R.Bound == Index { |
| 925 | + get { |
| 926 | + return self[r.relative(to: self)] |
| 927 | + } |
| 928 | + set { |
| 929 | + self[r.relative(to: self)] = newValue |
| 930 | + } |
| 931 | + } |
| 932 | +} |
| 933 | + |
700 | 934 | // swift-3-indexing-model: this is not really a proper rename
|
701 | 935 | @available(*, unavailable, renamed: "IndexingIterator")
|
702 | 936 | public struct RangeGenerator<Bound> {}
|
|
0 commit comments