[stdlib] Implement Equatable/Comparable sequence algos in terms predicate ones (#14758)

* Implement Equatable/Comparable sequence algos in terms predicate ones

* Remove IteratorSequence use

* de-gyb SequenceAlgorithms.swift
diff --git a/stdlib/public/core/CMakeLists.txt b/stdlib/public/core/CMakeLists.txt
index 5dc52eea..754c241 100644
--- a/stdlib/public/core/CMakeLists.txt
+++ b/stdlib/public/core/CMakeLists.txt
@@ -110,7 +110,7 @@
   SipHash.swift.gyb
   SentinelCollection.swift
   Sequence.swift
-  SequenceAlgorithms.swift.gyb
+  SequenceAlgorithms.swift
   SequenceWrapper.swift
   SetAlgebra.swift
   ShadowProtocols.swift
diff --git a/stdlib/public/core/SequenceAlgorithms.swift.gyb b/stdlib/public/core/SequenceAlgorithms.swift
similarity index 86%
rename from stdlib/public/core/SequenceAlgorithms.swift.gyb
rename to stdlib/public/core/SequenceAlgorithms.swift
index fb2a7fd..960ef8d 100644
--- a/stdlib/public/core/SequenceAlgorithms.swift.gyb
+++ b/stdlib/public/core/SequenceAlgorithms.swift
@@ -1,4 +1,4 @@
-//===--- SequenceAlgorithms.swift.gyb -------------------------*- swift -*-===//
+//===--- SequenceAlgorithms.swift -----------------------------*- swift -*-===//
 //
 // This source file is part of the Swift.org open source project
 //
@@ -10,36 +10,6 @@
 //
 //===----------------------------------------------------------------------===//
 
-%{
-
-orderingExplanation = """\
-  /// The predicate must be a *strict weak ordering* over the elements. That
-  /// is, for any elements `a`, `b`, and `c`, the following conditions must
-  /// hold:
-  ///
-  /// - `areInIncreasingOrder(a, a)` is always `false`. (Irreflexivity)
-  /// - If `areInIncreasingOrder(a, b)` and `areInIncreasingOrder(b, c)` are
-  ///   both `true`, then `areInIncreasingOrder(a, c)` is also
-  ///   `true`. (Transitive comparability)
-  /// - Two elements are *incomparable* if neither is ordered before the other
-  ///   according to the predicate. If `a` and `b` are incomparable, and `b`
-  ///   and `c` are incomparable, then `a` and `c` are also incomparable.
-  ///   (Transitive incomparability)
-  ///"""
-
-equivalenceExplanation = """\
-  /// 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)
-  ///"""
-
-}%
-
 //===----------------------------------------------------------------------===//
 // enumerated()
 //===----------------------------------------------------------------------===//
@@ -101,18 +71,23 @@
 // min(), max()
 //===----------------------------------------------------------------------===//
 
-% # Generate two versions: with explicit predicates and with
-% # a Comparable requirement.
-% for preds in [True, False]:
-%   rethrows_ = "rethrows " if preds else ""
-
-extension Sequence ${"" if preds else "where Element : Comparable"} {
-
-%   if preds:
+extension Sequence {
   /// Returns the minimum element in the sequence, using the given predicate as
   /// the comparison between elements.
   ///
-${orderingExplanation}
+  /// The predicate must be a *strict weak ordering* over the elements. That
+  /// is, for any elements `a`, `b`, and `c`, the following conditions must
+  /// hold:
+  ///
+  /// - `areInIncreasingOrder(a, a)` is always `false`. (Irreflexivity)
+  /// - If `areInIncreasingOrder(a, b)` and `areInIncreasingOrder(b, c)` are
+  ///   both `true`, then `areInIncreasingOrder(a, c)` is also
+  ///   `true`. (Transitive comparability)
+  /// - Two elements are *incomparable* if neither is ordered before the other
+  ///   according to the predicate. If `a` and `b` are incomparable, and `b`
+  ///   and `c` are incomparable, then `a` and `c` are also incomparable.
+  ///   (Transitive incomparability)
+  ///
   /// This example shows how to use the `min(by:)` method on a
   /// dictionary to find the key-value pair with the lowest value.
   ///
@@ -127,43 +102,35 @@
   /// - Returns: The sequence's minimum element, according to
   ///   `areInIncreasingOrder`. If the sequence has no elements, returns
   ///   `nil`.
-%   else:
-  /// Returns the minimum element in the sequence.
-  ///
-  /// This example finds the smallest value in an array of height measurements.
-  ///
-  ///     let heights = [67.5, 65.7, 64.3, 61.1, 58.5, 60.3, 64.9]
-  ///     let lowestHeight = heights.min()
-  ///     print(lowestHeight)
-  ///     // Prints "Optional(58.5)"
-  ///
-  /// - Returns: The sequence's minimum element. If the sequence has no
-  ///   elements, returns `nil`.
-%   end
   @_inlineable
   @warn_unqualified_access
   public func min(
-%   if preds:
     by areInIncreasingOrder: (Element, Element) throws -> Bool
-%   end
-  ) ${rethrows_}-> Element? {
+  ) rethrows -> Element? {
     var it = makeIterator()
     guard var result = it.next() else { return nil }
-    for e in IteratorSequence(it) {
-%   if preds:
+    while let e = it.next() {
       if try areInIncreasingOrder(e, result) { result = e }
-%   else:
-      if e < result { result = e }
-%   end
     }
     return result
   }
 
-%   if preds:
   /// Returns the maximum element in the sequence, using the given predicate
   /// as the comparison between elements.
   ///
-${orderingExplanation}
+  /// The predicate must be a *strict weak ordering* over the elements. That
+  /// is, for any elements `a`, `b`, and `c`, the following conditions must
+  /// hold:
+  ///
+  /// - `areInIncreasingOrder(a, a)` is always `false`. (Irreflexivity)
+  /// - If `areInIncreasingOrder(a, b)` and `areInIncreasingOrder(b, c)` are
+  ///   both `true`, then `areInIncreasingOrder(a, c)` is also
+  ///   `true`. (Transitive comparability)
+  /// - Two elements are *incomparable* if neither is ordered before the other
+  ///   according to the predicate. If `a` and `b` are incomparable, and `b`
+  ///   and `c` are incomparable, then `a` and `c` are also incomparable.
+  ///   (Transitive incomparability)
+  ///
   /// This example shows how to use the `max(by:)` method on a
   /// dictionary to find the key-value pair with the highest value.
   ///
@@ -177,7 +144,38 @@
   ///   otherwise, `false`.
   /// - Returns: The sequence's maximum element if the sequence is not empty;
   ///   otherwise, `nil`.
-%   else:
+  @_inlineable
+  @warn_unqualified_access
+  public func max(
+    by areInIncreasingOrder: (Element, Element) throws -> Bool
+  ) rethrows -> Element? {
+    var it = makeIterator()
+    guard var result = it.next() else { return nil }
+    while let e = it.next() {
+      if try areInIncreasingOrder(result, e) { result = e }
+    }
+    return result
+  }
+}
+
+extension Sequence where Element: Comparable {
+  /// Returns the minimum element in the sequence.
+  ///
+  /// This example finds the smallest value in an array of height measurements.
+  ///
+  ///     let heights = [67.5, 65.7, 64.3, 61.1, 58.5, 60.3, 64.9]
+  ///     let lowestHeight = heights.min()
+  ///     print(lowestHeight)
+  ///     // Prints "Optional(58.5)"
+  ///
+  /// - Returns: The sequence's minimum element. If the sequence has no
+  ///   elements, returns `nil`.
+  @_inlineable
+  @warn_unqualified_access
+  public func min() -> Element? {
+    return self.min(by: <)
+  }
+
   /// Returns the maximum element in the sequence.
   ///
   /// This example finds the largest value in an array of height measurements.
@@ -189,46 +187,31 @@
   ///
   /// - Returns: The sequence's maximum element. If the sequence has no
   ///   elements, returns `nil`.
-%   end
   @_inlineable
   @warn_unqualified_access
-  public func max(
-%   if preds:
-    by areInIncreasingOrder: (Element, Element) throws -> Bool
-%   end
-  ) ${rethrows_}-> Element? {
-    var it = makeIterator()
-    guard var result = it.next() else { return nil }
-    for e in IteratorSequence(it) {
-%   if preds:
-      if try areInIncreasingOrder(result, e) { result = e }
-%   else:
-      if e > result { result = e }
-%   end
-    }
-    return result
+  public func max() -> Element? {
+    return self.max(by: <)
   }
 }
 
-% end
-
 //===----------------------------------------------------------------------===//
 // starts(with:)
 //===----------------------------------------------------------------------===//
 
-% # Generate two versions: with explicit predicates and with
-% # an Equatable requirement.
-% for preds in [True, False]:
-%   rethrows_ = "rethrows " if preds else ""
-
-extension Sequence ${"" if preds else "where Element : Equatable"} {
-
-%   if preds:
+extension Sequence  {
   /// Returns a Boolean value indicating whether the initial elements of the
   /// sequence are equivalent to the elements in another sequence, using
   /// the given predicate as the equivalence test.
   ///
-${equivalenceExplanation}
+  /// 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:
   ///   - possiblePrefix: A sequence to compare to this sequence.
   ///   - areEquivalent: A predicate that returns `true` if its two arguments
@@ -236,7 +219,27 @@
   /// - Returns: `true` if the initial elements of the sequence are equivalent
   ///   to the elements of `possiblePrefix`; otherwise, `false`. If
   ///   `possiblePrefix` has no elements, the return value is `true`.
-%   else:
+  @_inlineable
+  public func starts<PossiblePrefix: Sequence>(
+    with possiblePrefix: PossiblePrefix,
+    by areEquivalent: (Element, PossiblePrefix.Element) throws -> Bool
+  ) rethrows -> Bool {
+    var possiblePrefixIterator = possiblePrefix.makeIterator()
+    for e0 in self {
+      if let e1 = possiblePrefixIterator.next() {
+        if try !areEquivalent(e0, e1) {
+          return false
+        }
+      }
+      else {
+        return true
+      }
+    }
+    return possiblePrefixIterator.next() == nil
+  }
+}
+
+extension Sequence where Element: Equatable {
   /// Returns a Boolean value indicating whether the initial elements of the
   /// sequence are the same as the elements in another sequence.
   ///
@@ -259,61 +262,61 @@
   /// - Returns: `true` if the initial elements of the sequence are the same as
   ///   the elements of `possiblePrefix`; otherwise, `false`. If
   ///   `possiblePrefix` has no elements, the return value is `true`.
-%   end
   @_inlineable
-  public func starts<PossiblePrefix>(
-    with possiblePrefix: PossiblePrefix${"," if preds else ""}
-%   if preds:
-    by areEquivalent: (Element, Element) throws -> Bool
-%   end
-  ) ${rethrows_}-> Bool
-    where
-    PossiblePrefix : Sequence,
-    PossiblePrefix.Element == Element {
-
-    var possiblePrefixIterator = possiblePrefix.makeIterator()
-    for e0 in self {
-      if let e1 = possiblePrefixIterator.next() {
-        if ${"try !areEquivalent(e0, e1)" if preds else "e0 != e1"} {
-          return false
-        }
-      }
-      else {
-        return true
-      }
-    }
-    return possiblePrefixIterator.next() == nil
+  public func starts<PossiblePrefix: Sequence>(
+    with possiblePrefix: PossiblePrefix
+  ) -> Bool where PossiblePrefix.Element == Element {
+    return self.starts(with: possiblePrefix, by: ==)
   }
 }
 
-% end
-
 //===----------------------------------------------------------------------===//
 // elementsEqual()
 //===----------------------------------------------------------------------===//
 
-% # Generate two versions: with explicit predicates and with
-% # an Equatable requirement.
-% for preds in [True, False]:
-%   rethrows_ = "rethrows " if preds else ""
-
-extension Sequence ${"" if preds else "where Element : Equatable"} {
-
-%   if preds:
+extension Sequence {
   /// Returns a Boolean value indicating whether this sequence and another
   /// sequence contain equivalent elements in the same order, using the given
   /// predicate as the equivalence test.
   ///
   /// At least one of the sequences must be finite.
   ///
-${equivalenceExplanation}
+  /// 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:
   ///   - other: A sequence to compare to this sequence.
   ///   - areEquivalent: A predicate that returns `true` if its two arguments
   ///     are equivalent; otherwise, `false`.
   /// - Returns: `true` if this sequence and `other` contain equivalent items,
   ///   using `areEquivalent` as the equivalence test; otherwise, `false.`
-%   else:
+  @_inlineable
+  public func elementsEqual<OtherSequence: Sequence>(
+    _ other: OtherSequence,
+    by areEquivalent: (Element, OtherSequence.Element) throws -> Bool
+  ) rethrows -> Bool {
+    var iter1 = self.makeIterator()
+    var iter2 = other.makeIterator()
+    while true {
+      switch (iter1.next(), iter2.next()) {
+      case let (e1?, e2?):
+        if try !areEquivalent(e1, e2) {
+          return false
+        }
+      case (_?, nil), (nil, _?): return false
+      case (nil, nil):           return true
+      }
+    }
+  }
+}
+
+extension Sequence where Element : Equatable {
   /// Returns a Boolean value indicating whether this sequence and another
   /// sequence contain the same elements in the same order.
   ///
@@ -333,57 +336,36 @@
   /// - Parameter other: A sequence to compare to this sequence.
   /// - Returns: `true` if this sequence and `other` contain the same elements
   ///   in the same order.
-%   end
   @_inlineable
-  public func elementsEqual<OtherSequence>(
-    _ other: OtherSequence${"," if preds else ""}
-%   if preds:
-    by areEquivalent: (Element, OtherSequence.Element) throws -> Bool
-%   end
-  ) ${rethrows_}-> Bool
-    where
-    OtherSequence: Sequence${" {" if preds else ","}
-%   if not preds:
-    OtherSequence.Element == Element {
-%   end
-
-    var iter1 = self.makeIterator()
-    var iter2 = other.makeIterator()
-    while true {
-      switch (iter1.next(), iter2.next()) {
-      case let (e1?, e2?):
-        if ${'try !areEquivalent(e1, e2)' if preds else 'e1 != e2'} {
-          return false
-        }
-      case (_?, nil),
-           (nil, _?):
-        return false
-      case (nil, nil):
-        return true
-      }
-    }
+  public func elementsEqual<OtherSequence: Sequence>(
+    _ other: OtherSequence
+  ) -> Bool where OtherSequence.Element == Element {
+    return self.elementsEqual(other, by: ==)
   }
 }
 
-% end
-
 //===----------------------------------------------------------------------===//
 // lexicographicallyPrecedes()
 //===----------------------------------------------------------------------===//
 
-% # Generate two versions: with explicit predicates and with
-% # Comparable requirement.
-% for preds in [True, False]:
-%   rethrows_ = "rethrows " if preds else ""
-
-extension Sequence ${"" if preds else "where Element : Comparable"} {
-
-%   if preds:
+extension Sequence {
   /// Returns a Boolean value indicating whether the sequence precedes another
   /// sequence in a lexicographical (dictionary) ordering, using the given
   /// predicate to compare elements.
   ///
-${orderingExplanation}
+  /// The predicate must be a *strict weak ordering* over the elements. That
+  /// is, for any elements `a`, `b`, and `c`, the following conditions must
+  /// hold:
+  ///
+  /// - `areInIncreasingOrder(a, a)` is always `false`. (Irreflexivity)
+  /// - If `areInIncreasingOrder(a, b)` and `areInIncreasingOrder(b, c)` are
+  ///   both `true`, then `areInIncreasingOrder(a, c)` is also
+  ///   `true`. (Transitive comparability)
+  /// - Two elements are *incomparable* if neither is ordered before the other
+  ///   according to the predicate. If `a` and `b` are incomparable, and `b`
+  ///   and `c` are incomparable, then `a` and `c` are also incomparable.
+  ///   (Transitive incomparability)
+  ///
   /// - Parameters:
   ///   - other: A sequence to compare to this sequence.
   ///   - areInIncreasingOrder:  A predicate that returns `true` if its first
@@ -396,7 +378,34 @@
   ///   ordering, which has no connection to Unicode.  If you are sorting
   ///   strings to present to the end user, use `String` APIs that perform
   ///   localized comparison instead.
-%   else:
+  @_inlineable
+  public func lexicographicallyPrecedes<OtherSequence: Sequence>(
+    _ other: OtherSequence,
+    by areInIncreasingOrder: (Element, Element) throws -> Bool
+  ) rethrows -> Bool 
+  where OtherSequence.Element == Element {
+    var iter1 = self.makeIterator()
+    var iter2 = other.makeIterator()
+    while true {
+      if let e1 = iter1.next() {
+        if let e2 = iter2.next() {
+          if try areInIncreasingOrder(e1, e2) {
+            return true
+          }
+          if try areInIncreasingOrder(e2, e1) {
+            return false
+          }
+          continue // Equivalent
+        }
+        return false
+      }
+
+      return iter2.next() != nil
+    }
+  }
+}
+
+extension Sequence where Element : Comparable {
   /// Returns a Boolean value indicating whether the sequence precedes another
   /// sequence in a lexicographical (dictionary) ordering, using the
   /// less-than operator (`<`) to compare elements.
@@ -420,77 +429,18 @@
   ///   ordering, which has no connection to Unicode.  If you are sorting
   ///   strings to present to the end user, use `String` APIs that
   ///   perform localized comparison.
-%   end
   @_inlineable
-  public func lexicographicallyPrecedes<OtherSequence>(
-    _ other: OtherSequence${"," if preds else ""}
-%   if preds:
-    by areInIncreasingOrder:
-      (Element, Element) throws -> Bool
-%   end
-  ) ${rethrows_}-> Bool
-    where
-    OtherSequence : Sequence,
-    OtherSequence.Element == Element {
-
-    var iter1 = self.makeIterator()
-    var iter2 = other.makeIterator()
-    while true {
-      if let e1 = iter1.next() {
-        if let e2 = iter2.next() {
-          if ${"try areInIncreasingOrder(e1, e2)" if preds else "e1 < e2"} {
-            return true
-          }
-          if ${"try areInIncreasingOrder(e2, e1)" if preds else "e2 < e1"} {
-            return false
-          }
-          continue // Equivalent
-        }
-        return false
-      }
-
-      return iter2.next() != nil
-    }
+  public func lexicographicallyPrecedes<OtherSequence: Sequence>(
+    _ other: OtherSequence
+  ) -> Bool where OtherSequence.Element == Element {
+    return self.lexicographicallyPrecedes(other, by: <)
   }
 }
 
-% end
-
 //===----------------------------------------------------------------------===//
 // contains()
 //===----------------------------------------------------------------------===//
 
-extension Sequence where Element : Equatable {
-  /// Returns a Boolean value indicating whether the sequence contains the
-  /// given element.
-  ///
-  /// This example checks to see whether a favorite actor is in an array
-  /// storing a movie's cast.
-  ///
-  ///     let cast = ["Vivien", "Marlon", "Kim", "Karl"]
-  ///     print(cast.contains("Marlon"))
-  ///     // Prints "true"
-  ///     print(cast.contains("James"))
-  ///     // Prints "false"
-  ///
-  /// - Parameter element: The element to find in the sequence.
-  /// - Returns: `true` if the element was found in the sequence; otherwise,
-  ///   `false`.
-  @_inlineable
-  public func contains(_ element: Element) -> Bool {
-    if let result = _customContainsEquatableElement(element) {
-      return result
-    }
-
-    for e in self {
-      if e == element {
-        return true
-      }
-    }
-    return false
-  }
-}
-
 extension Sequence {
   /// Returns a Boolean value indicating whether the sequence contains an
   /// element that satisfies the given predicate.
@@ -540,6 +490,32 @@
   }
 }
 
+extension Sequence where Element : Equatable {
+  /// Returns a Boolean value indicating whether the sequence contains the
+  /// given element.
+  ///
+  /// This example checks to see whether a favorite actor is in an array
+  /// storing a movie's cast.
+  ///
+  ///     let cast = ["Vivien", "Marlon", "Kim", "Karl"]
+  ///     print(cast.contains("Marlon"))
+  ///     // Prints "true"
+  ///     print(cast.contains("James"))
+  ///     // Prints "false"
+  ///
+  /// - Parameter element: The element to find in the sequence.
+  /// - Returns: `true` if the element was found in the sequence; otherwise,
+  ///   `false`.
+  @_inlineable
+  public func contains(_ element: Element) -> Bool {
+    if let result = _customContainsEquatableElement(element) {
+      return result
+    } else {
+      return self.contains { $0 == element }
+    }
+  }
+}
+
 //===----------------------------------------------------------------------===//
 // reduce()
 //===----------------------------------------------------------------------===//