Skip to content

Commit 3890376

Browse files
Revert "Revert "[stdlib] One-sided ranges and RangeExpression (swiftlang#8710)""
1 parent f45196d commit 3890376

12 files changed

+380
-100
lines changed

stdlib/public/core/Policy.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,9 @@ infix operator ^ : AdditionPrecedence
660660
// FIXME: is this the right precedence level for "..." ?
661661
infix operator ... : RangeFormationPrecedence
662662
infix operator ..< : RangeFormationPrecedence
663+
postfix operator ...
664+
prefix operator ...
665+
prefix operator ..<
663666

664667
// The cast operators 'as' and 'is' are hardcoded as if they had the
665668
// following attributes:

stdlib/public/core/Range.swift.gyb

Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,33 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

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+
1340
// FIXME(ABI)#55 (Statically Unavailable/Dynamically Available): remove this type, it creates an ABI burden
1441
// on the library.
1542
//
@@ -513,6 +540,18 @@ extension ${Self} {
513540
}
514541
}
515542

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+
516555
extension ${Self} : CustomStringConvertible {
517556
/// A textual representation of the range.
518557
public var description: String {
@@ -697,6 +736,201 @@ public func ..< <Bound>(
697736
return CountableRange(uncheckedBounds: (lower: minimum, upper: maximum))
698737
}
699738

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+
700934
// swift-3-indexing-model: this is not really a proper rename
701935
@available(*, unavailable, renamed: "IndexingIterator")
702936
public struct RangeGenerator<Bound> {}

stdlib/public/core/RangeReplaceableCollection.swift.gyb

Lines changed: 9 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -890,28 +890,7 @@ extension RangeReplaceableCollection where SubSequence == Self {
890890
}
891891
}
892892

893-
% for Range in ['CountableRange', 'ClosedRange', 'CountableClosedRange']:
894-
extension RangeReplaceableCollection
895-
% if 'Countable' in Range:
896-
where
897-
Index : Strideable, Index.Stride : SignedInteger
898-
% end
899-
{
900-
/// Returns a half-open range denoting the same positions as `r`.
901-
@_versioned
902-
@_inlineable
903-
internal func _makeHalfOpen(_ r: ${Range}<Index>) -> Range<Index> {
904-
// The upperBound of the result depends on whether `r` is a closed
905-
// range.
906-
% if 'Closed' in Range:
907-
return Range(uncheckedBounds: (
908-
lower: r.lowerBound,
909-
upper: index(after: r.upperBound)))
910-
% else:
911-
return Range(r)
912-
% end
913-
}
914-
893+
extension RangeReplaceableCollection {
915894
/// Replaces the specified subrange of elements with the given collection.
916895
///
917896
/// This method has the effect of removing the specified range of elements
@@ -949,11 +928,11 @@ extension RangeReplaceableCollection
949928
/// contents of `newElements` to the collection, the complexity is O(*n*),
950929
/// where *n* is the length of `newElements`.
951930
@_inlineable
952-
public mutating func replaceSubrange<C>(
953-
_ subrange: ${Range}<Index>,
931+
public mutating func replaceSubrange<C: Collection, R: RangeExpression>(
932+
_ subrange: R,
954933
with newElements: C
955-
) where C : Collection, C.Iterator.Element == Iterator.Element {
956-
self.replaceSubrange(_makeHalfOpen(subrange), with: newElements)
934+
) where C.Iterator.Element == Iterator.Element, R.Bound == Index {
935+
self.replaceSubrange(subrange.relative(to: self), with: newElements)
957936
}
958937

959938
/// Removes the elements in the specified subrange from the collection.
@@ -975,11 +954,12 @@ extension RangeReplaceableCollection
975954
///
976955
/// - Complexity: O(*n*), where *n* is the length of the collection.
977956
@_inlineable
978-
public mutating func removeSubrange(_ bounds: ${Range}<Index>) {
979-
removeSubrange(_makeHalfOpen(bounds))
957+
public mutating func removeSubrange<R: RangeExpression>(
958+
_ bounds: R
959+
) where R.Bound == Index {
960+
removeSubrange(bounds.relative(to: self))
980961
}
981962
}
982-
% end
983963

984964
extension RangeReplaceableCollection {
985965
@_inlineable

stdlib/public/core/StringRangeReplaceableCollection.swift.gyb

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,6 @@ extension String {
247247
}
248248
}
249249

250-
% for Range in ['Range', 'ClosedRange']:
251250
/// Replaces the text within the specified bounds with the given characters.
252251
///
253252
/// Calling this method invalidates any existing indices for use with this
@@ -263,7 +262,7 @@ extension String {
263262
/// removes text at the end of the string, the complexity is O(*n*), where
264263
/// *n* is equal to `bounds.count`.
265264
public mutating func replaceSubrange<C>(
266-
_ bounds: ${Range}<Index>,
265+
_ bounds: Range<Index>,
267266
with newElements: C
268267
) where C : Collection, C.Iterator.Element == Character {
269268
withMutableCharacters {
@@ -272,27 +271,6 @@ extension String {
272271
}
273272
}
274273

275-
/// Replaces the text within the specified bounds with the given string.
276-
///
277-
/// Calling this method invalidates any existing indices for use with this
278-
/// string.
279-
///
280-
/// - Parameters:
281-
/// - bounds: The range of text to replace. The bounds of the range must be
282-
/// valid indices of the string.
283-
/// - newElements: The new text to add to the string.
284-
///
285-
/// - Complexity: O(*m*), where *m* is the combined length of the string and
286-
/// `newElements`. If the call to `replaceSubrange(_:with:)` simply
287-
/// removes text at the end of the string, the complexity is O(*n*), where
288-
/// *n* is equal to `bounds.count`.
289-
public mutating func replaceSubrange(
290-
_ bounds: ${Range}<Index>, with newElements: String
291-
) {
292-
replaceSubrange(bounds, with: newElements.characters)
293-
}
294-
% end
295-
296274
/// Inserts a new character at the specified position.
297275
///
298276
/// Calling this method invalidates any existing indices for use with this
@@ -357,26 +335,21 @@ extension String {
357335
}
358336
}
359337

360-
% for Range in ['Range', 'ClosedRange']:
361338
/// Removes the characters in the given range.
362339
///
363340
/// Calling this method invalidates any existing indices for use with this
364341
/// string.
365342
///
366-
% if Range == 'ClosedRange':
367343
/// - Parameter bounds: The range of the elements to remove. The upper and
368344
/// lower bounds of `bounds` must be valid indices of the string and not
369345
/// equal to the string's end index.
370-
% else:
371346
/// - Parameter bounds: The range of the elements to remove. The upper and
372347
/// lower bounds of `bounds` must be valid indices of the string.
373-
% end
374-
public mutating func removeSubrange(_ bounds: ${Range}<Index>) {
348+
public mutating func removeSubrange(_ bounds: Range<Index>) {
375349
withMutableCharacters {
376350
(v: inout CharacterView) in v.removeSubrange(bounds)
377351
}
378352
}
379-
% end
380353

381354
/// Replaces this string with the empty string.
382355
///

0 commit comments

Comments
 (0)