mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
424 lines
12 KiB
Swift
424 lines
12 KiB
Swift
//===--- SequenceAlgorithms.swift.gyb -------------------------*- 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 http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
%{
|
|
|
|
# We know we will eventually get a SequenceType.Element type. Define
|
|
# a shorthand that we can use today.
|
|
GElement = "Generator.Element"
|
|
|
|
}%
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// enumerate()
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
extension SequenceType {
|
|
/// Returns a lazy `SequenceType` containing pairs (*n*, *x*), where
|
|
/// *n*s are consecutive `Int`s starting at zero, and *x*s are
|
|
/// the elements of `base`:
|
|
///
|
|
/// > for (n, c) in "Swift".characters.enumerate() {
|
|
/// print("\(n): '\(c)'")
|
|
/// }
|
|
/// 0: 'S'
|
|
/// 1: 'w'
|
|
/// 2: 'i'
|
|
/// 3: 'f'
|
|
/// 4: 't'
|
|
@warn_unused_result
|
|
public func enumerate() -> EnumerateSequence<Self> {
|
|
return EnumerateSequence(self)
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// minElement(), maxElement()
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
% # Generate two versions: with explicit predicates and with
|
|
% # a Comparable requirement.
|
|
% for preds in [ True, False ]:
|
|
|
|
%{
|
|
if preds:
|
|
orderingRequirement = """
|
|
/// - Requires: `isOrderedBefore` is a
|
|
/// [strict weak ordering](http://en.wikipedia.org/wiki/Strict_weak_order#Strict_weak_orderings)
|
|
/// over `self`."""
|
|
rethrows_ = "rethrows "
|
|
else:
|
|
orderingRequirement = ""
|
|
rethrows_ = ""
|
|
}%
|
|
|
|
extension SequenceType ${"" if preds else "where Generator.Element : Comparable"} {
|
|
|
|
/// Returns the minimum element in `self` or `nil` if the sequence is empty.
|
|
///
|
|
/// - Complexity: O(`elements.count`).
|
|
///
|
|
/// ${orderingRequirement}
|
|
@warn_unused_result
|
|
public func minElement(
|
|
% if preds:
|
|
@noescape isOrderedBefore: (${GElement}, ${GElement}) throws -> Bool
|
|
% end
|
|
) ${rethrows_}-> ${GElement}? {
|
|
var g = generate()
|
|
guard var result = g.next() else { return nil }
|
|
for e in GeneratorSequence(g) {
|
|
% if preds:
|
|
if try isOrderedBefore(e, result) { result = e }
|
|
% else:
|
|
if e < result { result = e }
|
|
% end
|
|
}
|
|
return result
|
|
}
|
|
|
|
/// Returns the maximum element in `self` or `nil` if the sequence is empty.
|
|
///
|
|
/// - Complexity: O(`elements.count`).
|
|
/// ${orderingRequirement}
|
|
@warn_unused_result
|
|
public func maxElement(
|
|
% if preds:
|
|
@noescape isOrderedBefore: (${GElement}, ${GElement}) throws -> Bool
|
|
% end
|
|
) ${rethrows_}-> ${GElement}? {
|
|
var g = generate()
|
|
guard var result = g.next() else { return nil }
|
|
for e in GeneratorSequence(g) {
|
|
% if preds:
|
|
if try isOrderedBefore(result, e) { result = e }
|
|
% else:
|
|
if e > result { result = e }
|
|
% end
|
|
}
|
|
return result
|
|
}
|
|
}
|
|
|
|
% end
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// startsWith()
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
% # Generate two versions: with explicit predicates and with
|
|
% # an Equatable requirement.
|
|
% for preds in [ True, False ]:
|
|
|
|
extension SequenceType ${"" if preds else "where Generator.Element : Equatable"} {
|
|
|
|
%{
|
|
if preds:
|
|
comment = """
|
|
/// Returns `true` iff `self` begins with elements equivalent to those of
|
|
/// `other`, using `isEquivalent` as the equivalence test. Returns `true` if
|
|
/// `other` is empty.
|
|
///
|
|
/// - Requires: `isEquivalent` is an
|
|
/// [equivalence relation](http://en.wikipedia.org/wiki/Equivalence_relation)."""
|
|
|
|
rethrows_ = "rethrows "
|
|
else:
|
|
comment = """
|
|
/// Returns `true` iff the initial elements of `self` are equal to `prefix`.
|
|
/// Returns `true` if `other` is empty."""
|
|
rethrows_ = ""
|
|
}%
|
|
${comment}
|
|
@warn_unused_result
|
|
public func startsWith<
|
|
OtherSequence : SequenceType where OtherSequence.${GElement} == ${GElement}
|
|
>(
|
|
other: OtherSequence${"," if preds else ""}
|
|
% if preds:
|
|
@noescape isEquivalent: (${GElement}, ${GElement}) throws -> Bool
|
|
% end
|
|
) ${rethrows_}-> Bool {
|
|
var otherGenerator = other.generate()
|
|
for e0 in self {
|
|
if let e1 = otherGenerator.next() {
|
|
if ${"try !isEquivalent(e0, e1)" if preds else "e0 != e1"} {
|
|
return false
|
|
}
|
|
}
|
|
else {
|
|
return true
|
|
}
|
|
}
|
|
return otherGenerator.next() == nil
|
|
}
|
|
}
|
|
|
|
% end
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// elementsEqual()
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
% # Generate two versions: with explicit predicates and with
|
|
% # an Equatable requirement.
|
|
% for preds in [ True, False ]:
|
|
|
|
extension SequenceType ${"" if preds else "where Generator.Element : Equatable"} {
|
|
|
|
%{
|
|
if preds:
|
|
comment = """
|
|
/// Returns `true` iff `self` and `other` contain equivalent elements, using
|
|
/// `isEquivalent` as the equivalence test.
|
|
///
|
|
/// - Requires: `isEquivalent` is an
|
|
/// [equivalence relation](http://en.wikipedia.org/wiki/Equivalence_relation)."""
|
|
rethrows_ = "rethrows "
|
|
else:
|
|
comment = """
|
|
/// Returns `true` iff `self` and `other` contain the same elements in the
|
|
/// same order."""
|
|
rethrows_ = ""
|
|
}%
|
|
|
|
${comment}
|
|
@warn_unused_result
|
|
public func elementsEqual<
|
|
OtherSequence : SequenceType where OtherSequence.${GElement} == ${GElement}
|
|
>(
|
|
other: OtherSequence${"," if preds else ""}
|
|
% if preds:
|
|
@noescape isEquivalent: (${GElement}, ${GElement}) throws -> Bool
|
|
% end
|
|
) ${rethrows_}-> Bool {
|
|
var g1 = self.generate()
|
|
var g2 = other.generate()
|
|
while true {
|
|
switch (g1.next(), g2.next()) {
|
|
case let (e1?, e2?):
|
|
if ${'try !isEquivalent(e1, e2)' if preds else 'e1 != e2'} {
|
|
return false
|
|
}
|
|
case (_?, nil),
|
|
(nil, _?):
|
|
return false
|
|
case (nil, nil):
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
% end
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// lexicographicalCompare()
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
% # Generate two versions: with explicit predicates and with
|
|
% # Comparable requirement.
|
|
% for preds in [ True, False ]:
|
|
|
|
extension SequenceType ${"" if preds else "where Generator.Element : Comparable"} {
|
|
|
|
%{
|
|
if preds:
|
|
comment = """
|
|
/// Returns `true` iff `self` precedes `other` in a lexicographical
|
|
/// ("dictionary") ordering, using `isOrderedBefore` as the comparison
|
|
/// between elements.
|
|
///
|
|
/// - Note: This method implements the mathematical notion of lexicographical
|
|
/// ordering, which has no connection to Unicode. If you are sorting strings
|
|
/// to present to the end-user, you should use `String` APIs that perform
|
|
/// localized comparison.
|
|
///
|
|
/// - Requires: `isOrderedBefore` is a
|
|
/// [strict weak ordering](http://en.wikipedia.org/wiki/Strict_weak_order#Strict_weak_orderings)
|
|
/// over the elements of `self` and `other`."""
|
|
rethrows_ = "rethrows "
|
|
else:
|
|
comment = """
|
|
/// Returns `true` iff `self` precedes `other` in a lexicographical
|
|
/// ("dictionary") ordering, using "<" as the comparison between elements.
|
|
///
|
|
/// - Note: This method implements the mathematical notion of lexicographical
|
|
/// ordering, which has no connection to Unicode. If you are sorting strings
|
|
/// to present to the end-user, you should use `String` APIs that perform
|
|
/// localized comparison."""
|
|
rethrows_ = ""
|
|
}%
|
|
|
|
${comment}
|
|
@warn_unused_result
|
|
public func lexicographicalCompare<
|
|
OtherSequence : SequenceType where OtherSequence.${GElement} == ${GElement}
|
|
>(
|
|
other: OtherSequence${"," if preds else ""}
|
|
% if preds:
|
|
@noescape isOrderedBefore: (${GElement}, ${GElement}) throws -> Bool
|
|
% end
|
|
) ${rethrows_}-> Bool {
|
|
var g1 = self.generate()
|
|
var g2 = other.generate()
|
|
while true {
|
|
if let e1 = g1.next() {
|
|
if let e2 = g2.next() {
|
|
if ${"try isOrderedBefore(e1, e2)" if preds else "e1 < e2"} {
|
|
return true
|
|
}
|
|
if ${"try isOrderedBefore(e2, e1)" if preds else "e2 < e1"} {
|
|
return false
|
|
}
|
|
continue // Equivalent
|
|
}
|
|
return false
|
|
}
|
|
|
|
return g2.next() != nil
|
|
}
|
|
}
|
|
}
|
|
|
|
% end
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// contains()
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
extension SequenceType where Generator.Element : Equatable {
|
|
/// Returns `true` iff `element` is in `self`.
|
|
@warn_unused_result
|
|
public func contains(element: ${GElement}) -> Bool {
|
|
if let result = _customContainsEquatableElement(element) {
|
|
return result
|
|
}
|
|
|
|
for e in self {
|
|
if e == element {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
}
|
|
|
|
extension SequenceType {
|
|
/// Returns `true` iff an element in `self` satisfies `predicate`.
|
|
@warn_unused_result
|
|
public func contains(
|
|
@noescape predicate: (${GElement}) throws -> Bool
|
|
) rethrows -> Bool {
|
|
for e in self {
|
|
if try predicate(e) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// reduce()
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
extension SequenceType {
|
|
/// Returns the result of repeatedly calling `combine` with an
|
|
/// accumulated value initialized to `initial` and each element of
|
|
/// `self`, in turn, i.e. return
|
|
/// `combine(combine(...combine(combine(initial, self[0]),
|
|
/// self[1]),...self[count-2]), self[count-1])`.
|
|
@warn_unused_result
|
|
public func reduce<T>(
|
|
initial: T, @noescape combine: (T, ${GElement}) throws -> T
|
|
) rethrows -> T {
|
|
var result = initial
|
|
for element in self {
|
|
result = try combine(result, element)
|
|
}
|
|
return result
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// reverse()
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
extension SequenceType {
|
|
/// Returns an `Array` containing the elements of `self` in reverse
|
|
/// order.
|
|
///
|
|
/// Complexity: O(N), where N is the length of `self`.
|
|
@warn_unused_result
|
|
public func reverse() -> [${GElement}] {
|
|
// FIXME(performance): optimize to 1 pass? But Array(self) can be
|
|
// optimized to a memcpy() sometimes. Those cases are usually collections,
|
|
// though.
|
|
var result = Array(self)
|
|
let count = result.count
|
|
for i in 0..<count/2 {
|
|
swap(&result[i], &result[count - i - 1])
|
|
}
|
|
return result
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// flatMap()
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
extension SequenceType {
|
|
/// Returns an `Array` containing the concatenated results of mapping
|
|
/// `transform` over `self`.
|
|
///
|
|
/// s.flatMap(transform)
|
|
///
|
|
/// is equivalent to
|
|
///
|
|
/// Array(s.map(transform).flatten())
|
|
///
|
|
/// - Complexity: O(*M* + *N*), where *M* is the length of `self`
|
|
/// and *N* is the length of the result.
|
|
@warn_unused_result
|
|
public func flatMap<S : SequenceType>(
|
|
@noescape transform: (${GElement}) throws -> S
|
|
) rethrows -> [S.${GElement}] {
|
|
var result: [S.${GElement}] = []
|
|
for element in self {
|
|
result.appendContentsOf(try transform(element))
|
|
}
|
|
return result
|
|
}
|
|
}
|
|
|
|
extension SequenceType {
|
|
/// Returns an `Array` containing the non-nil results of mapping
|
|
/// `transform` over `self`.
|
|
///
|
|
/// - Complexity: O(*M* + *N*), where *M* is the length of `self`
|
|
/// and *N* is the length of the result.
|
|
@warn_unused_result
|
|
public func flatMap<T>(
|
|
@noescape transform: (${GElement}) throws -> T?
|
|
) rethrows -> [T] {
|
|
var result: [T] = []
|
|
for element in self {
|
|
if let newElement = try transform(element) {
|
|
result.append(newElement)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
}
|
|
|