//===--- 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 SequenceType.Element type. Define # a shorthand that we can use today. GElement = "Generator.Element" }% //===----------------------------------------------------------------------===// // enumerate() //===----------------------------------------------------------------------===// extension SequenceType { /// Return 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' public func enumerate() -> EnumerateSequence { 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`.""" else: orderingRequirement = "" }% 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} public func minElement( % if preds: @noescape isOrderedBefore: (${GElement}, ${GElement}) -> Bool % end ) -> ${GElement}? { var g = generate() guard var result = g.next() else { return nil } for e in GeneratorSequence(g) { % if preds: if 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} public func maxElement( % if preds: @noescape isOrderedBefore: (${GElement}, ${GElement}) -> Bool % end ) -> ${GElement}? { var g = generate() guard var result = g.next() else { return nil } for e in GeneratorSequence(g) { % if preds: if 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 = """ /// 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).""" else: comment = """ /// Return true iff the the initial elements of `self` are equal to `prefix`. /// Return true if `other` is empty.""" }% ${comment} public func startsWith< OtherSequence : SequenceType where OtherSequence.${GElement} == ${GElement} >( other: OtherSequence${"," if preds else ""} % if preds: @noescape isEquivalent: (${GElement}, ${GElement}) -> Bool % end ) -> Bool { var otherGenerator = other.generate() for e0 in self { if let e1 = otherGenerator.next() { if ${"!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 = """ /// 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).""" else: comment = """ /// Return `true` iff `self` and `other` contain the same elements in the /// same order.""" }% ${comment} public func elementsEqual< OtherSequence : SequenceType where OtherSequence.${GElement} == ${GElement} >( other: OtherSequence${"," if preds else ""} % if preds: @noescape isEquivalent: (${GElement}, ${GElement}) -> Bool % end ) -> Bool { var g1 = self.generate() var g2 = other.generate() while true { switch (g1.next(), g2.next()) { case let (e1?, e2?): if ${'!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 = """ /// 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`.""" 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.""" }% ${comment} public func lexicographicalCompare< OtherSequence : SequenceType where OtherSequence.${GElement} == ${GElement} >( other: OtherSequence${"," if preds else ""} % if preds: @noescape isOrderedBefore: (${GElement}, ${GElement}) -> Bool % end ) -> Bool { var g1 = self.generate() var g2 = other.generate() while true { if let e1 = g1.next() { if let e2 = g2.next() { if ${"isOrderedBefore(e1, e2)" if preds else "e1 < e2"} { return true } if ${"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 { /// Return `true` iff `x` is in `self`. 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 { /// Return `true` iff an element in `self` satisfies `predicate`. public func contains( @noescape predicate: (${GElement}) -> Bool ) -> Bool { for e in self { if predicate(e) { return true } } return false } } //===----------------------------------------------------------------------===// // reduce() //===----------------------------------------------------------------------===// extension SequenceType { /// 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[count-2]), self[count-1])`. public func reduce( initial: T, @noescape combine: (T, ${GElement}) -> T ) -> T { var result = initial for element in self { result = combine(result, element) } return result } } //===----------------------------------------------------------------------===// // reverse() //===----------------------------------------------------------------------===// extension SequenceType { /// Return an `Array` containing the elements of `self` in reverse /// order. 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.. ReverseCollection { return ReverseCollection(self) } } extension CollectionType where Index : RandomAccessIndexType { /// Return a lazy `CollectionType` containing the elements of `self` /// in reverse order. public func reverse() -> ReverseRandomAccessCollection { return ReverseRandomAccessCollection(self) } } //===----------------------------------------------------------------------===// // flatMap() //===----------------------------------------------------------------------===// extension SequenceType { /// Return an `Array` containing the concatenated results of mapping /// `transform` over `self`. /// /// s.flatMap(transform) /// /// is equivalent to /// /// Array(s.map(transform)._prext_flatten) /// /// - Complexity: O(*M* + *N*), where *M* is the length of `self` /// and *N* is the length of the result. public func flatMap( transform: (${GElement}) -> S ) -> [S.${GElement}] { var result: [S.${GElement}] = [] for element in self { result.appendContentsOf(transform(element)) } return result } } extension SequenceType { /// 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. public func flatMap( @noescape transform: (${GElement}) -> T? ) -> [T] { var result: [T] = [] for element in self { if let newElement = transform(element) { result.append(newElement) } } return result } }