//===--- SequenceAlgorithms.swift.gyb -------------------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2015 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 Sequence.Element type. Define # a shorthand that we can use today. GElement = "Iterator.Element" }% //===----------------------------------------------------------------------===// // enumerated //===----------------------------------------------------------------------===// extension Sequence { /// Return a lazy `Sequence` containing pairs (*n*, *x*), where /// *n*s are consecutive `Int`s starting at zero, and *x*s are /// the elements of `self`: /// /// > for (n, c) in "Swift".characters.enumerated { /// print("\(n): '\(c)'") /// } /// 0: 'S' /// 1: 'w' /// 2: 'i' /// 3: 'f' /// 4: 't' public var enumerated: EnumeratedSequence { return EnumeratedSequence(_base: 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 Sequence ${"" if preds else "where Iterator.Element : Comparable"} { /// Returns the minimum element in `self` or `nil` if the sequence is empty. /// /// - Complexity: O(`self.length`). /// /// ${orderingRequirement} @warn_unused_result public func minElement( % if preds: @noescape isOrderedBefore: (${GElement}, ${GElement}) throws -> Bool % end ) ${rethrows_}-> ${GElement}? { var minResult: ${GElement}? = nil for e in IteratorSequence(iterator()) { if let currentMinResult = minResult { % if preds: if try isOrderedBefore(e, currentMinResult) { minResult = e } % else: if e < currentMinResult { minResult = e } % end } else { minResult = e } } return minResult } /// Returns the maximum element in `self` or `nil` if the sequence is empty. /// /// - Complexity: O(`self.length`). /// ${orderingRequirement} @warn_unused_result public func maxElement( % if preds: @noescape isOrderedBefore: (${GElement}, ${GElement}) throws -> Bool % end ) ${rethrows_}-> ${GElement}? { var maxResult: ${GElement}? = nil for e in IteratorSequence(iterator()) { if let currentMaxResult = maxResult { % if preds: if try isOrderedBefore(currentMaxResult, e) { maxResult = e } % else: if e > currentMaxResult { maxResult = e } % end } else { maxResult = e } } return maxResult } } % end //===----------------------------------------------------------------------===// // startsWith() //===----------------------------------------------------------------------===// % # Generate two versions: with explicit predicates and with % # an Equatable requirement. % for preds in [ True, False ]: extension Sequence ${"" if preds else "where Iterator.Element : Equatable"} { %{ if preds: comment = """ /// Return true iff `self` begins with elements equivalent to those of /// `other`, using `isEquivalent` as the equivalence test. Return true if /// `other` is empty. /// /// - Requires: `isEquivalent` is an /// [equivalence relation](http://en.wikipedia.org/wiki/Equivalence_relation).""" rethrows_ = "rethrows " else: comment = """ /// Return true iff the initial elements of `self` are equal to `prefix`. /// Return true if `other` is empty.""" rethrows_ = "" }% ${comment} @warn_unused_result public func startsWith< OtherSequence : Sequence where OtherSequence.${GElement} == ${GElement} >( other: OtherSequence${"," if preds else ""} % if preds: @noescape isEquivalent: (${GElement}, ${GElement}) throws -> Bool % end ) ${rethrows_}-> Bool { var otherIterator = other.iterator() for e0 in self { if let e1 = otherIterator.next() { if ${"try !isEquivalent(e0, e1)" if preds else "e0 != e1"} { return false } } else { return true } } return otherIterator.next() == nil } } % end //===----------------------------------------------------------------------===// // elementsEqual() //===----------------------------------------------------------------------===// % # Generate two versions: with explicit predicates and with % # an Equatable requirement. % for preds in [ True, False ]: extension Sequence ${"" if preds else "where Iterator.Element : Equatable"} { %{ if preds: comment = """ /// Return 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 = """ /// Return `true` iff `self` and `other` contain the same elements in the /// same order.""" rethrows_ = "" }% ${comment} @warn_unused_result public func elementsEqual< OtherSequence : Sequence where OtherSequence.${GElement} == ${GElement} >( other: OtherSequence${"," if preds else ""} % if preds: @noescape isEquivalent: (${GElement}, ${GElement}) throws -> Bool % end ) ${rethrows_}-> Bool { var iter1 = self.iterator() var iter2 = other.iterator() while true { switch (iter1.next(), iter2.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 Sequence ${"" if preds else "where Iterator.Element : Comparable"} { %{ if preds: comment = """ /// Return 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 = """ /// Return 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 : Sequence where OtherSequence.${GElement} == ${GElement} >( other: OtherSequence${"," if preds else ""} % if preds: @noescape isOrderedBefore: (${GElement}, ${GElement}) throws -> Bool % end ) ${rethrows_}-> Bool { var iter1 = self.iterator() var iter2 = other.iterator() while true { if let e1 = iter1.next() { if let e2 = iter2.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 iter2.next() != nil } } } % end //===----------------------------------------------------------------------===// // contains() //===----------------------------------------------------------------------===// extension Sequence where Iterator.Element : Equatable { /// Return `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 Sequence { /// Return `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 Sequence { /// Return 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[length-2]), self[length-1])`. @warn_unused_result public func reduce( 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 Sequence { /// Return an `Array` containing the elements of `self` in reverse /// order. /// /// Complexity: O(`self.length`). @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 length = result.length for i in 0..( transform: (${GElement}) throws -> S ) rethrows -> [S.${GElement}] { var result: [S.${GElement}] = [] for element in self { result.appendContentsOf(try transform(element)) } return result } } extension Sequence { /// Return 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( @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 } }