-
Notifications
You must be signed in to change notification settings - Fork 440
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
82ee335
commit 375eb1f
Showing
3 changed files
with
167 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# EndsWith | ||
|
||
[[Source](https://github.com/apple/swift-algorithms/blob/main/Sources/Algorithms/EndsWith.swift) | | ||
[Tests](https://github.com/apple/swift-algorithms/blob/main/Tests/SwiftAlgorithmsTests/EndsWithTests.swift)] | ||
|
||
This function checks whether the final elements of the one collection are the same as the elements in another collection. | ||
``` | ||
## Detailed Design | ||
The `ends(with:)` and `ends(with:by:)` functions are added as methods on an extension of | ||
`BidirectionalCollection`. | ||
```swift | ||
extension BidirectionalCollection { | ||
public func ends<PossibleSuffix: BidirectionalCollection>( | ||
with possibleSuffix: PossibleSuffix | ||
) -> Bool where PossibleSuffix.Element == Element | ||
public func ends<PossibleSuffix: BidirectionalCollection>( | ||
with possibleSuffix: PossibleSuffix, | ||
by areEquivalent: (Element, PossibleSuffix.Element) throws -> Bool | ||
) rethrows -> Bool | ||
} | ||
``` | ||
|
||
This method requires `BidirectionalCollection` for being able to traverse back from the end of the collection. It also requires the `possibleSuffix` to be `BidirectionalCollection`, because it too needs to be traverse backwards, to compare its elements against `self` from back to front. | ||
|
||
### Complexity | ||
|
||
O(*m*), where *m* is the lesser of the length of the collection and the length of `possibleSuffix`. | ||
|
||
### Naming | ||
|
||
The function's name resembles that of an existing Swift function | ||
`starts(with:)`, which performs same operation however in the forward direction | ||
of the collection. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This source file is part of the Swift Algorithms open source project | ||
// | ||
// Copyright (c) 2021 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
//===----------------------------------------------------------------------===// | ||
// EndsWith | ||
//===----------------------------------------------------------------------===// | ||
|
||
extension BidirectionalCollection where Element: Equatable { | ||
|
||
|
||
/// Returns a Boolean value indicating whether the final elements of the | ||
/// collection are the same as the elements in another collection. | ||
/// | ||
/// This example tests whether one countable range ends with the elements | ||
/// of another countable range. | ||
/// | ||
/// let a = 8...10 | ||
/// let b = 1...10 | ||
/// | ||
/// print(b.ends(with: a)) | ||
/// // Prints "true" | ||
/// | ||
/// Passing a collection with no elements or an empty collection as | ||
/// `possibleSuffix` always results in `true`. | ||
/// | ||
/// print(b.ends(with: [])) | ||
/// // Prints "true" | ||
/// | ||
/// - Parameter possibleSuffix: A collection to compare to this collection. | ||
/// - Returns: `true` if the initial elements of the collection are the same as | ||
/// the elements of `possibleSuffix`; otherwise, `false`. If | ||
/// `possibleSuffix` has no elements, the return value is `true`. | ||
/// | ||
/// - Complexity: O(*m*), where *m* is the lesser of the length of the | ||
/// collection and the length of `possibleSuffix`. | ||
@inlinable | ||
public func ends<PossibleSuffix: BidirectionalCollection>( | ||
with possibleSuffix: PossibleSuffix | ||
) -> Bool where PossibleSuffix.Element == Element { | ||
return self.ends(with: possibleSuffix, by: ==) | ||
} | ||
|
||
/// Returns a Boolean value indicating whether the final elements of the | ||
/// collection are equivalent to the elements in another collection, using | ||
/// the given predicate as the equivalence test. | ||
/// | ||
/// The predicate must be a *equivalence relation* over the elements. That | ||
/// is, for any elements `a`, `b`, and `c`, the following conditions must | ||
/// hold: | ||
/// | ||
/// - `areEquivalent(a, a)` is always `true`. (Reflexivity) | ||
/// - `areEquivalent(a, b)` implies `areEquivalent(b, a)`. (Symmetry) | ||
/// - If `areEquivalent(a, b)` and `areEquivalent(b, c)` are both `true`, then | ||
/// `areEquivalent(a, c)` is also `true`. (Transitivity) | ||
/// | ||
/// - Parameters: | ||
/// - possibleSuffix: A collection to compare to this collection. | ||
/// - areEquivalent: A predicate that returns `true` if its two arguments | ||
/// are equivalent; otherwise, `false`. | ||
/// - Returns: `true` if the initial elements of the collection are equivalent | ||
/// to the elements of `possibleSuffix`; otherwise, `false`. If | ||
/// `possibleSuffix` has no elements, the return value is `true`. | ||
/// | ||
/// - Complexity: O(*m*), where *m* is the lesser of the length of the | ||
/// collection and the length of `possibleSuffix`. | ||
@inlinable | ||
public func ends<PossibleSuffix: BidirectionalCollection>( | ||
with possibleSuffix: PossibleSuffix, | ||
by areEquivalent: (Element, PossibleSuffix.Element) throws -> Bool | ||
) rethrows -> Bool { | ||
try self.reversed().starts(with: possibleSuffix.reversed(), by: areEquivalent) | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This source file is part of the Swift Algorithms open source project | ||
// | ||
// Copyright (c) 2021 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
import XCTest | ||
import Algorithms | ||
|
||
final class EndsWithTests: XCTestCase { | ||
func testEndsWithCorrectSuffix() { | ||
let a = 8...10 | ||
let b = 1...10 | ||
|
||
XCTAssertTrue(b.ends(with: a)) | ||
} | ||
|
||
func testDoesntEndWithWrongSuffix() { | ||
let a = 8...9 | ||
let b = 1...10 | ||
|
||
XCTAssertFalse(b.ends(with: a)) | ||
} | ||
|
||
func testDoesntEndWithTooLongSuffix() { | ||
XCTAssertFalse((2...5).ends(with: (1...10))) | ||
} | ||
|
||
func testEndsWithEmpty() { | ||
let a = 8...10 | ||
let empty = [Int]() | ||
XCTAssertTrue(a.ends(with: empty)) | ||
} | ||
|
||
func testEmptyEndsWithEmpty() { | ||
let empty = [Int]() | ||
XCTAssertTrue(empty.ends(with: empty)) | ||
} | ||
|
||
func testEmptyDoesNotEndWithNonempty() { | ||
XCTAssertFalse([].ends(with: 1...10)) | ||
} | ||
} |