From f1797ae707d6f27f04ae5199a01490f477352d7e Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Wed, 30 Nov 2022 21:24:06 -0600 Subject: [PATCH 1/3] Remove `RegexConsumer` and fix its dependencies This eliminates the RegexConsumer type and rewrites its users to call through to other, existing functionality on Regex or in the Algorithms implementations. RegexConsumer doesn't take account of the dual subranges required for matching, so it can produce results that are inconsistent with matches(of:) and ranges(of:), which were rewritten earlier. rdar://102841216 --- .../Algorithms/Algorithms/FirstRange.swift | 8 +- .../Algorithms/Algorithms/Ranges.swift | 7 -- .../Algorithms/Algorithms/Split.swift | 48 +++++---- .../Algorithms/Algorithms/StartsWith.swift | 7 +- .../Algorithms/Algorithms/Trim.swift | 52 ++-------- .../Algorithms/Consumers/RegexConsumer.swift | 98 ------------------- .../Algorithms/Matching/FirstMatch.swift | 15 --- .../Algorithms/Matching/MatchReplace.swift | 39 -------- .../Algorithms/Matching/Matches.swift | 7 -- .../RegexTests/AlgorithmsInternalsTests.swift | 8 -- 10 files changed, 43 insertions(+), 246 deletions(-) delete mode 100644 Sources/_StringProcessing/Algorithms/Consumers/RegexConsumer.swift diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift b/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift index 696f36eca..31759aa4a 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift @@ -78,11 +78,7 @@ extension BidirectionalCollection where SubSequence == Substring { @_disfavoredOverload @available(SwiftStdlib 5.7, *) public func firstRange(of regex: some RegexComponent) -> Range? { - _firstRange(of: RegexConsumer(regex)) - } - - @available(SwiftStdlib 5.7, *) - func _lastRange(of regex: R) -> Range? { - _lastRange(of: RegexConsumer(regex)) + let s = self[...] + return try? regex.regex.firstMatch(in: s)?.range } } diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Ranges.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Ranges.swift index fc6b23af2..d4f7b5a22 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Ranges.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Ranges.swift @@ -299,13 +299,6 @@ extension Collection where SubSequence == Substring { } extension BidirectionalCollection where SubSequence == Substring { - @available(SwiftStdlib 5.7, *) - func _rangesFromBack( - of regex: R - ) -> ReversedRangesCollection> { - _rangesFromBack(of: RegexConsumer(regex)) - } - // FIXME: Return `some Collection>` for SE-0346 /// Finds and returns the ranges of the all occurrences of a given sequence /// within the collection. diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift index 44364df71..bfee59832 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift @@ -399,21 +399,6 @@ extension StringProtocol where SubSequence == Substring { @available(SwiftStdlib 5.7, *) extension BidirectionalCollection where SubSequence == Substring { - @_disfavoredOverload - func split( - by separator: R, - maxSplits: Int, - omittingEmptySubsequences: Bool - ) -> SplitCollection> { - split(by: RegexConsumer(separator), maxSplits: maxSplits, omittingEmptySubsequences: omittingEmptySubsequences) - } - - func splitFromBack( - by separator: R - ) -> ReversedSplitCollection> { - splitFromBack(by: RegexConsumer(separator)) - } - // TODO: Is this @_disfavoredOverload necessary? // It prevents split(separator: String) from choosing this overload instead // of the collection-based version when String has RegexComponent conformance @@ -431,9 +416,34 @@ extension BidirectionalCollection where SubSequence == Substring { maxSplits: Int = .max, omittingEmptySubsequences: Bool = true ) -> [SubSequence] { - Array(split( - by: RegexConsumer(separator), - maxSplits: maxSplits, - omittingEmptySubsequences: omittingEmptySubsequences)) + var result: [SubSequence] = [] + var subSequenceStart = startIndex + + func appendSubsequence(end: Index) -> Bool { + if subSequenceStart == end && omittingEmptySubsequences { + return false + } + result.append(self[subSequenceStart.. 0 && !isEmpty else { + _ = appendSubsequence(end: endIndex) + return result + } + + for match in _matches(of: separator) { + defer { subSequenceStart = match.range.upperBound } + let didAppend = appendSubsequence(end: match.range.lowerBound) + if didAppend && result.count == maxSplits { + break + } + } + + if subSequenceStart != endIndex || !omittingEmptySubsequences { + result.append(self[subSequenceStart.. Bool { - _starts(with: RegexConsumer(regex)) - } - - func _ends(with regex: R) -> Bool { - _ends(with: RegexConsumer(regex)) + let s = self[...] + return (try? regex.regex.prefixMatch(in: s)) != nil } } diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift index 37f7513db..e5ebad2bc 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift @@ -292,17 +292,11 @@ extension BidirectionalCollection where SubSequence == Substring { @_disfavoredOverload @available(SwiftStdlib 5.7, *) public func trimmingPrefix(_ regex: some RegexComponent) -> SubSequence { - _trimmingPrefix(RegexConsumer(regex)) - } - - @available(SwiftStdlib 5.7, *) - func _trimmingSuffix(_ regex: R) -> SubSequence { - _trimmingSuffix(RegexConsumer(regex)) - } - - @available(SwiftStdlib 5.7, *) - func _trimming(_ regex: R) -> SubSequence { - _trimming(RegexConsumer(regex)) + let s = self[...] + guard let prefix = try? regex.regex.prefixMatch(in: s) else { + return s + } + return s[prefix.range.upperBound...] } } @@ -314,37 +308,11 @@ extension RangeReplaceableCollection @_disfavoredOverload @available(SwiftStdlib 5.7, *) public mutating func trimPrefix(_ regex: some RegexComponent) { - _trimPrefix(RegexConsumer(regex)) - } - - @available(SwiftStdlib 5.7, *) - mutating func _trimSuffix(_ regex: R) { - _trimSuffix(RegexConsumer(regex)) - } - - @available(SwiftStdlib 5.7, *) - mutating func _trim(_ regex: R) { - let consumer = RegexConsumer(regex) - _trimPrefix(consumer) - _trimSuffix(consumer) + let s = self[...] + guard let prefix = try? regex.regex.prefixMatch(in: s) else { + return + } + self.removeSubrange(prefix.range) } } -extension Substring { - @available(SwiftStdlib 5.7, *) - mutating func _trimPrefix(_ regex: R) { - _trimPrefix(RegexConsumer(regex)) - } - - @available(SwiftStdlib 5.7, *) - mutating func _trimSuffix(_ regex: R) { - _trimSuffix(RegexConsumer(regex)) - } - - @available(SwiftStdlib 5.7, *) - mutating func _trim(_ regex: R) { - let consumer = RegexConsumer(regex) - _trimPrefix(consumer) - _trimSuffix(consumer) - } -} diff --git a/Sources/_StringProcessing/Algorithms/Consumers/RegexConsumer.swift b/Sources/_StringProcessing/Algorithms/Consumers/RegexConsumer.swift deleted file mode 100644 index 4956406da..000000000 --- a/Sources/_StringProcessing/Algorithms/Consumers/RegexConsumer.swift +++ /dev/null @@ -1,98 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2021-2022 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 -// -//===----------------------------------------------------------------------===// - -// FIXME: What even is this? Can we delete this whole thing? -@available(SwiftStdlib 5.7, *) -struct RegexConsumer< - R: RegexComponent, Consumed: BidirectionalCollection -> where Consumed.SubSequence == Substring { - // TODO: Should `Regex` itself implement these protocols? - let regex: R - - init(_ regex: R) { - self.regex = regex - } -} - -@available(SwiftStdlib 5.7, *) -extension RegexConsumer { - func _matchingConsuming( - _ consumed: Substring, in range: Range - ) -> (upperBound: String.Index, match: Match)? { - guard let result = try! regex.regex._match( - consumed.base, - in: range, mode: .partialFromFront - ) else { return nil } - return (result.range.upperBound, result.output) - } -} - -// TODO: Explicitly implement the non-matching consumer/searcher protocols as -// well, taking advantage of the fact that the captures can be ignored - -@available(SwiftStdlib 5.7, *) -extension RegexConsumer: MatchingCollectionConsumer { - typealias Match = R.RegexOutput - - func matchingConsuming( - _ consumed: Consumed, in range: Range - ) -> (upperBound: String.Index, match: Match)? { - _matchingConsuming(consumed[...], in: range) - } -} - -// TODO: We'll want to bake backwards into the engine -@available(SwiftStdlib 5.7, *) -extension RegexConsumer: BidirectionalMatchingCollectionConsumer { - func matchingConsumingBack( - _ consumed: Consumed, in range: Range - ) -> (lowerBound: String.Index, match: Match)? { - var i = range.lowerBound - while true { - if let (end, capture) = _matchingConsuming( - consumed[...], - in: i.. - ) -> (range: Range, match: Match)? { - ConsumerSearcher(consumer: self).matchingSearch(searched, in: range) - } -} - -// TODO: Bake in search-back to engine too -@available(SwiftStdlib 5.7, *) -extension RegexConsumer: BackwardMatchingStatelessCollectionSearcher { - typealias BackwardSearched = Consumed - - func matchingSearchBack( - _ searched: BackwardSearched, in range: Range - ) -> (range: Range, match: Match)? { - ConsumerSearcher(consumer: self).matchingSearchBack(searched, in: range) - } -} diff --git a/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift b/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift index c8c6867f4..3ee74f258 100644 --- a/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift +++ b/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift @@ -38,21 +38,6 @@ extension BidirectionalCollection { // MARK: Regex algorithms extension BidirectionalCollection where SubSequence == Substring { - @available(SwiftStdlib 5.7, *) - @_disfavoredOverload - func firstMatch( - of regex: R - ) -> _MatchResult>? { - _firstMatch(of: RegexConsumer(regex)) - } - - @available(SwiftStdlib 5.7, *) - func lastMatch( - of regex: R - ) -> _BackwardMatchResult>? { - lastMatch(of: RegexConsumer(regex)) - } - /// Returns the first match of the specified regex within the collection. /// - Parameter regex: The regex to search for. /// - Returns: The first match of `regex` in the collection, or `nil` if diff --git a/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift b/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift index 6bc9b4d77..0f23280ce 100644 --- a/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift +++ b/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift @@ -75,45 +75,6 @@ extension RangeReplaceableCollection { // MARK: Regex algorithms extension RangeReplaceableCollection where SubSequence == Substring { - @available(SwiftStdlib 5.7, *) - func _replacing( - _ regex: R, - with replacement: (_MatchResult>) throws -> Replacement, - subrange: Range, - maxReplacements: Int = .max - ) rethrows -> Self where Replacement.Element == Element { - try _replacing( - RegexConsumer(regex), - with: replacement, - subrange: subrange, - maxReplacements: maxReplacements) - } - - @available(SwiftStdlib 5.7, *) - func _replacing( - _ regex: R, - with replacement: (_MatchResult>) throws -> Replacement, - maxReplacements: Int = .max - ) rethrows -> Self where Replacement.Element == Element { - try _replacing( - regex, - with: replacement, - subrange: startIndex..( - _ regex: R, - with replacement: (_MatchResult>) throws -> Replacement, - maxReplacements: Int = .max - ) rethrows where Replacement.Element == Element { - self = try _replacing( - regex, - with: replacement, - maxReplacements: maxReplacements) - } - /// Returns a new collection in which all occurrences of a sequence matching /// the given regex are replaced by another regex match. /// - Parameters: diff --git a/Sources/_StringProcessing/Algorithms/Matching/Matches.swift b/Sources/_StringProcessing/Algorithms/Matching/Matches.swift index f5c645105..12846bf0f 100644 --- a/Sources/_StringProcessing/Algorithms/Matching/Matches.swift +++ b/Sources/_StringProcessing/Algorithms/Matching/Matches.swift @@ -357,13 +357,6 @@ extension BidirectionalCollection where SubSequence == Substring { regex: regex.regex) } - @available(SwiftStdlib 5.7, *) - func _matchesFromBack( - of regex: R - ) -> ReversedMatchesCollection> { - _matchesFromBack(of: RegexConsumer(regex)) - } - // FIXME: Return `some Collection.Match> for SE-0346 /// Returns a collection containing all matches of the specified regex. /// - Parameter regex: The regex to search for. diff --git a/Tests/RegexTests/AlgorithmsInternalsTests.swift b/Tests/RegexTests/AlgorithmsInternalsTests.swift index 96cd12076..af0007bbe 100644 --- a/Tests/RegexTests/AlgorithmsInternalsTests.swift +++ b/Tests/RegexTests/AlgorithmsInternalsTests.swift @@ -24,25 +24,17 @@ extension AlgorithmTests { let str = "a string with the letter b in it" let first = str.firstRange(of: r) - let last = str._lastRange(of: r) let (expectFirst, expectLast) = ( str.index(atOffset: 0).. Date: Fri, 2 Dec 2022 16:18:27 -0600 Subject: [PATCH 2/3] Remove remaining from-end algorithm methods This removes methods that are left over from when we were considering from-end algorithms. These aren't tested and may not have the correct semantics, so it's safer to remove them entirely. --- .../Algorithms/Algorithms/FirstRange.swift | 9 - .../Algorithms/Algorithms/Ranges.swift | 76 --------- .../Algorithms/Algorithms/Split.swift | 141 ---------------- .../Algorithms/Algorithms/StartsWith.swift | 36 ---- .../Algorithms/Algorithms/Trim.swift | 157 ------------------ Tests/RegexTests/RenderDSLTests.swift | 13 +- 6 files changed, 12 insertions(+), 420 deletions(-) diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift b/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift index 31759aa4a..484ff4648 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift @@ -20,15 +20,6 @@ extension Collection { } } -extension BidirectionalCollection { - func _lastRange( - of searcher: S - ) -> Range? where S.BackwardSearched == Self { - var state = searcher.backwardState(for: self, in: startIndex.. { - typealias Base = Searcher.BackwardSearched - - let base: Base - let searcher: Searcher - - init(base: Base, searcher: Searcher) { - self.base = base - self.searcher = searcher - } -} - -extension ReversedRangesCollection: Sequence { - public struct Iterator: IteratorProtocol { - let base: Base - let searcher: Searcher - var state: Searcher.BackwardState - - init(base: Base, searcher: Searcher) { - self.base = base - self.searcher = searcher - self.state = searcher.backwardState( - for: base, in: base.startIndex.. Range? { - searcher.searchBack(base, &state) - } - } - - public func makeIterator() -> Iterator { - Iterator(base: base, searcher: searcher) - } -} - // TODO: `Collection` conformance // MARK: `CollectionSearcher` algorithms @@ -164,14 +127,6 @@ extension Collection { } } -extension BidirectionalCollection { - func _rangesFromBack( - of searcher: S - ) -> ReversedRangesCollection where S.BackwardSearched == Self { - ReversedRangesCollection(base: self, searcher: searcher) - } -} - // MARK: Fixed pattern algorithms extension Collection where Element: Equatable { @@ -195,37 +150,6 @@ extension Collection where Element: Equatable { } } -extension BidirectionalCollection where Element: Equatable { - // FIXME -// public func rangesFromBack( -// of other: S -// ) -> ReversedRangesCollection> -// where S.Element == Element -// { -// fatalError() -// } -} - -extension BidirectionalCollection where Element: Comparable { - func _ranges( - of other: C - ) -> RangesCollection>> - where C.Element == Element - { - _ranges(of: PatternOrEmpty(searcher: TwoWaySearcher(pattern: Array(other)))) - } - - // FIXME -// public func rangesFromBack( -// of other: S -// ) -> ReversedRangesCollection>> -// where S.Element == Element -// { -// rangesFromBack( -// of: PatternOrEmpty(searcher: TwoWaySearcher(pattern: Array(other)))) -// } -} - @available(SwiftStdlib 5.7, *) struct RegexRangesCollection { let base: RegexMatchesCollection diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift index bfee59832..6634d2945 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift @@ -106,121 +106,6 @@ extension SplitCollection: Sequence { } } -//extension SplitCollection: Collection { -// public struct Index { -// var start: Base.Index -// var base: RangesCollection.Index -// var isEndIndex: Bool -// } -// -// public var startIndex: Index { -// let base = ranges.startIndex -// return Index(start: ranges.base.startIndex, base: base, isEndIndex: false) -// } -// -// public var endIndex: Index { -// Index(start: ranges.base.endIndex, base: ranges.endIndex, isEndIndex: true) -// } -// -// public func formIndex(after index: inout Index) { -// guard !index.isEndIndex else { fatalError("Cannot advance past endIndex") } -// -// if let range = index.base.range { -// let newStart = range.upperBound -// ranges.formIndex(after: &index.base) -// index.start = newStart -// } else { -// index.isEndIndex = true -// } -// } -// -// public func index(after index: Index) -> Index { -// var index = index -// formIndex(after: &index) -// return index -// } -// -// public subscript(index: Index) -> Base.SubSequence { -// guard !index.isEndIndex else { -// fatalError("Cannot subscript using endIndex") -// } -// let end = index.base.range?.lowerBound ?? ranges.base.endIndex -// return ranges.base[index.start.. Bool { -// switch (lhs.isEndIndex, rhs.isEndIndex) { -// case (false, false): -// return lhs.start == rhs.start -// case (let lhs, let rhs): -// return lhs == rhs -// } -// } -// -// static func < (lhs: Self, rhs: Self) -> Bool { -// switch (lhs.isEndIndex, rhs.isEndIndex) { -// case (true, _): -// return false -// case (_, true): -// return true -// case (false, false): -// return lhs.start < rhs.start -// } -// } -//} - -// MARK: `ReversedSplitCollection` - -struct ReversedSplitCollection { - public typealias Base = Searcher.BackwardSearched - - let ranges: ReversedRangesCollection - - init(ranges: ReversedRangesCollection) { - self.ranges = ranges - } - - init(base: Base, searcher: Searcher) { - self.ranges = base._rangesFromBack(of: searcher) - } -} - -extension ReversedSplitCollection: Sequence { - public struct Iterator: IteratorProtocol { - let base: Base - var index: Base.Index - var ranges: ReversedRangesCollection.Iterator - var isDone: Bool - - init(ranges: ReversedRangesCollection) { - self.base = ranges.base - self.index = base.endIndex - self.ranges = ranges.makeIterator() - self.isDone = false - } - - public mutating func next() -> Base.SubSequence? { - guard !isDone else { return nil } - - guard let range = ranges.next() else { - isDone = true - return base[.. Iterator { - Iterator(ranges: ranges) - } -} - -// TODO: `Collection` conformance - // MARK: `CollectionSearcher` algorithms extension Collection { @@ -237,16 +122,6 @@ extension Collection { } } -extension BidirectionalCollection { - func splitFromBack( - by separator: Searcher - ) -> ReversedSplitCollection - where Searcher.BackwardSearched == Self - { - ReversedSplitCollection(base: self, searcher: separator) - } -} - // MARK: Predicate algorithms extension Collection { @@ -260,14 +135,6 @@ extension Collection { } } -extension BidirectionalCollection where Element: Equatable { - func splitFromBack( - whereSeparator predicate: @escaping (Element) -> Bool - ) -> ReversedSplitCollection> { - splitFromBack(by: PredicateConsumer(predicate: predicate)) - } -} - // MARK: Single element algorithms extension Collection where Element: Equatable { @@ -280,14 +147,6 @@ extension Collection where Element: Equatable { } } -extension BidirectionalCollection where Element: Equatable { - func splitFromBack( - by separator: Element - ) -> ReversedSplitCollection> { - splitFromBack(whereSeparator: { $0 == separator }) - } -} - // MARK: Fixed pattern algorithms extension Collection where Element: Equatable { diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift b/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift index 736139b5b..6f3a25809 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift @@ -9,42 +9,6 @@ // //===----------------------------------------------------------------------===// -// MARK: `CollectionConsumer` algorithms - -extension Collection { - func _starts(with consumer: C) -> Bool - where C.Consumed == SubSequence - { - consumer.consuming(self[...]) != nil - } -} - -extension BidirectionalCollection { - func _ends(with consumer: C) -> Bool - where C.Consumed == SubSequence - { - consumer.consumingBack(self[...]) != nil - } -} - -// MARK: Fixed pattern algorithms - -extension Collection where Element: Equatable { - func _starts(with prefix: C) -> Bool - where C.Element == Element - { - _starts(with: FixedPatternConsumer(pattern: prefix)) - } -} - -extension BidirectionalCollection where Element: Equatable { - func _ends(with suffix: C) -> Bool - where C.Element == Element - { - _ends(with: FixedPatternConsumer(pattern: suffix)) - } -} - // MARK: Regex algorithms @available(SwiftStdlib 5.7, *) diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift index e5ebad2bc..2908c4dc5 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift @@ -41,64 +41,6 @@ extension RangeReplaceableCollection { } } -extension BidirectionalCollection { - func _trimmingSuffix( - _ consumer: Consumer - ) -> SubSequence - where Consumer.Consumed == Self - { - let end = consumer.consumingBack(self) ?? endIndex - return self[..( - _ consumer: Consumer - ) -> SubSequence where Consumer.Consumed == Self { - // NOTE: Might give different results than trimming the suffix before - // trimming the prefix - let start = consumer.consuming(self) ?? startIndex - let end = consumer.consumingBack(self) ?? endIndex - let actualEnd = end < start ? start : end - return self[start..( - _ consumer: Consumer - ) where Consumer.Consumed == SubSequence - { - _ = consumer.consumeBack(&self) - } - - mutating func _trim( - _ consumer: Consumer - ) where Consumer.Consumed == Self { - _trimPrefix(consumer) - _trimSuffix(consumer) - } -} - -extension RangeReplaceableCollection where Self: BidirectionalCollection { - @_disfavoredOverload - mutating func _trimSuffix( - _ consumer: Consumer - ) where Consumer.Consumed == Self - { - if let end = consumer.consumingBack(self) { - removeSubrange(end...) - } - } - - @_disfavoredOverload - mutating func _trim( - _ consumer: Consumer - ) where Consumer.Consumed == Self { - _trimSuffix(consumer) - _trimPrefix(consumer) - } -} - // MARK: Predicate algorithms extension Collection { @@ -136,53 +78,6 @@ extension RangeReplaceableCollection { } } -extension BidirectionalCollection { - func _trimmingSuffix( - while predicate: @escaping (Element) -> Bool - ) -> SubSequence { - _trimmingSuffix(ManyConsumer(base: PredicateConsumer(predicate: predicate))) - } - - func _trimming( - while predicate: @escaping (Element) -> Bool - ) -> SubSequence { - _trimming(ManyConsumer(base: PredicateConsumer(predicate: predicate))) - } -} - -extension BidirectionalCollection where SubSequence == Self { - mutating func _trimSuffix( - while predicate: @escaping (Element) -> Bool - ) { - _trimSuffix(ManyConsumer( - base: PredicateConsumer(predicate: predicate))) - } - - mutating func _trim(while predicate: @escaping (Element) -> Bool) { - let consumer = ManyConsumer( - base: PredicateConsumer(predicate: predicate)) - _trimPrefix(consumer) - _trimSuffix(consumer) - } -} - -extension RangeReplaceableCollection where Self: BidirectionalCollection { - @_disfavoredOverload - mutating func _trimSuffix( - while predicate: @escaping (Element) -> Bool - ) { - _trimSuffix(ManyConsumer(base: PredicateConsumer(predicate: predicate))) - } - - @_disfavoredOverload - mutating func _trim(while predicate: @escaping (Element) -> Bool) { - let consumer = ManyConsumer( - base: PredicateConsumer(predicate: predicate)) - _trimPrefix(consumer) - _trimSuffix(consumer) - } -} - // MARK: Fixed pattern algorithms extension Collection where Element: Equatable { @@ -229,58 +124,6 @@ extension RangeReplaceableCollection where Element: Equatable { } } -extension BidirectionalCollection where Element: Equatable { - func _trimmingSuffix( - _ suffix: Suffix - ) -> SubSequence where Suffix.Element == Element { - _trimmingSuffix(FixedPatternConsumer(pattern: suffix)) - } - - func _trimming( - _ pattern: Pattern - ) -> SubSequence where Pattern.Element == Element { - _trimming(FixedPatternConsumer(pattern: pattern)) - } -} - -extension BidirectionalCollection - where SubSequence == Self, Element: Equatable -{ - mutating func _trimSuffix( - _ suffix: Suffix - ) where Suffix.Element == Element { - _trimSuffix(FixedPatternConsumer(pattern: suffix)) - } - - mutating func _trim( - _ pattern: Pattern - ) where Pattern.Element == Element { - let consumer = FixedPatternConsumer(pattern: pattern) - _trimPrefix(consumer) - _trimSuffix(consumer) - } -} - -extension RangeReplaceableCollection - where Self: BidirectionalCollection, Element: Equatable -{ - @_disfavoredOverload - mutating func _trimSuffix( - _ prefix: Suffix - ) where Suffix.Element == Element { - _trimSuffix(FixedPatternConsumer(pattern: prefix)) - } - - @_disfavoredOverload - mutating func _trim( - _ pattern: Pattern - ) where Pattern.Element == Element { - let consumer = FixedPatternConsumer(pattern: pattern) - _trimPrefix(consumer) - _trimSuffix(consumer) - } -} - // MARK: Regex algorithms extension BidirectionalCollection where SubSequence == Substring { diff --git a/Tests/RegexTests/RenderDSLTests.swift b/Tests/RegexTests/RenderDSLTests.swift index 31d59cb66..c38ff0663 100644 --- a/Tests/RegexTests/RenderDSLTests.swift +++ b/Tests/RegexTests/RenderDSLTests.swift @@ -16,13 +16,24 @@ import _StringProcessing class RenderDSLTests: XCTestCase {} +extension BidirectionalCollection { + func trimmingSuffix(while predicate: (Element) -> Bool) -> SubSequence { + var i = endIndex + while i > startIndex { + formIndex(before: &i) + if !predicate(self[i]) { return self[...i] } + } + return self[.. Date: Thu, 8 Dec 2022 10:32:49 -0600 Subject: [PATCH 3/3] Add back an _ends(with:) for TwoWaySearcher --- .../Algorithms/Searchers/TwoWaySearcher.swift | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Sources/_StringProcessing/Algorithms/Searchers/TwoWaySearcher.swift b/Sources/_StringProcessing/Algorithms/Searchers/TwoWaySearcher.swift index 837493a30..c3537d415 100644 --- a/Sources/_StringProcessing/Algorithms/Searchers/TwoWaySearcher.swift +++ b/Sources/_StringProcessing/Algorithms/Searchers/TwoWaySearcher.swift @@ -9,6 +9,14 @@ // //===----------------------------------------------------------------------===// +extension BidirectionalCollection where Element: Equatable { + fileprivate func _ends(with suffix: C) -> Bool + where C.Element == Element + { + FixedPatternConsumer(pattern: suffix).consumingBack(self[...]) != nil + } + } + struct TwoWaySearcher where Searched.Element: Comparable {