File: SortComparator.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (286 lines) | stat: -rw-r--r-- 10,502 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 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
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

/// A comparison algorithm for a given type.
@preconcurrency
@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
public protocol SortComparator<Compared>: Hashable, Sendable {
    /// The type that the `SortComparator` provides a comparison for.
    associatedtype Compared

    /// The relative ordering of lhs, and rhs.
    ///
    /// The result of comparisons should be flipped if the current `order`
    /// is `reverse`.
    ///
    /// If `compare(lhs, rhs)` is `.orderedAscending`, then `compare(rhs, lhs)`
    /// must be `.orderedDescending`. If `compare(lhs, rhs)` is
    /// `.orderedDescending`, then `compare(rhs, lhs)` must be
    /// `.orderedAscending`.
    ///
    /// - Parameters:
    ///     - lhs: A value to compare.
    ///     - rhs: A value to compare.
    func compare(_ lhs: Compared, _ rhs: Compared) -> ComparisonResult

    /// If the `SortComparator`s resulting order is forward or reverse.
    var order: SortOrder { get set }
}

/// The orderings that sorts can be performed with.
@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
@frozen
public enum SortOrder: Hashable, Codable, Sendable {
    /// The ordering where if compare(a, b) == .orderedAscending,
    /// a is placed before b.
    case forward
    /// The ordering where if compare(a, b) == .orderedAscending,
    /// a is placed after b.
    case reverse

    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        let isForward = try container.decode(Bool.self)
        if isForward {
            self = .forward
        } else {
            self = .reverse
        }
    }

    public func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .forward: try container.encode(true)
        case .reverse: try container.encode(false)
        }
    }
}

@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
extension ComparisonResult {
    package func withOrder(_ order: SortOrder) -> ComparisonResult {
        if order == .reverse {
            if self == .orderedAscending { return .orderedDescending }
            if self == .orderedDescending { return .orderedAscending }
        }
        return self
    }
}

@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
package struct AnySortComparator: SortComparator, Sendable {
    var _base: any Hashable & Sendable // internal for testing

    /// Takes `base` and two values to be compared and compares the two values
    /// using `base`.
    private let _compare: @Sendable (Any, Any, Any) -> ComparisonResult

    /// Takes `base` inout, and a new `SortOrder` and changes `base`s `order`
    /// to match the new `SortOrder`.
    private let setOrder: @Sendable (inout any Hashable & Sendable, SortOrder) -> any Hashable & Sendable

    /// Gets the current `order` property of `base`.
    private let getOrder: @Sendable (Any) -> SortOrder

    package init<Comparator: SortComparator>(_ comparator: Comparator) where Comparator : Sendable {
        self._base = comparator
        self._compare = { (base: Any, lhs: Any, rhs: Any) -> ComparisonResult in
            (base as! Comparator).compare(lhs as! Comparator.Compared, rhs as! Comparator.Compared)
        }
        self.setOrder = { (base: inout any Hashable & Sendable, newOrder: SortOrder) -> AnyHashable in
            var typedBase = base as! Comparator
            typedBase.order = newOrder
            base = typedBase
            return AnyHashable(typedBase)
        }
        self.getOrder = { (base: Any) -> SortOrder in
            (base as! Comparator).order
        }
    }

    package var order: SortOrder {
        get {
            return getOrder(_base)
        }
        set {
            _base = setOrder(&_base, newValue)
        }
    }

    package func compare(_ lhs: Any, _ rhs: Any) -> ComparisonResult {
        return _compare(_base, lhs, rhs)
    }

    package func hash(into hasher: inout Hasher) {
        hasher.combine(_base)
    }

    package static func == (lhs: Self, rhs: Self) -> Bool {
        func compare<L : Equatable, R : Equatable>(_ l : L, _ r : R) -> Bool {
            guard let rr = r as? L else {
                return false
            }
            return l == rr
        }
        
        return compare(lhs._base, rhs._base)
    }
}

/// Compares `Comparable` types using their comparable implementation.
@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
public struct ComparableComparator<Compared: Comparable>: SortComparator, Sendable {
    public var order: SortOrder
    
#if FOUNDATION_FRAMEWORK
    @available(FoundationPreview 0.1, *)
    public init(order: SortOrder = .forward) {
        self.order = order
    }
#else
    // No need for availability on this initializer in the package.
    public init(order: SortOrder = .forward) {
        self.order = order
    }
#endif

    private func unorderedCompare(_ lhs: Compared, _ rhs: Compared) -> ComparisonResult {
        if lhs < rhs { return .orderedAscending }
        if lhs > rhs { return .orderedDescending }
        return .orderedSame
    }

    public func compare(_ lhs: Compared, _ rhs: Compared) -> ComparisonResult {
        return unorderedCompare(lhs, rhs).withOrder(order)
    }
}

/// A comparator which orders optional values using a comparator which
/// compares the optional's `Wrapped` type. `nil` values are ordered before
/// non-nil values when `order` is `forward`.
package struct OptionalComparator<Base: SortComparator>: SortComparator {
    private var base: Base

    package init(_ base: Base) {
        self.base = base
    }

    package var order: SortOrder {
        get { base.order }
        set { base.order = newValue }
    }

    package func compare(_ lhs: Base.Compared?, _ rhs: Base.Compared?) -> ComparisonResult {
        guard let lhs else {
            if rhs == nil { return .orderedSame }
            return .orderedAscending.withOrder(order)
        }
        guard let rhs else { return .orderedDescending.withOrder(order) }
        return base.compare(lhs, rhs)
    }
}

extension OptionalComparator : Sendable where Base : Sendable { }

@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
extension Never: SortComparator {
    public typealias Compared = Never

    public func compare(_ lhs: Never, _ rhs: Never) -> ComparisonResult {}

    public var order: SortOrder {
        get {
            switch self {}
        }
        set {
            switch self {}
        }
    }
}

@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
extension Sequence {
    /// Returns the elements of the sequence, sorted using the given comparator
    /// to compare elements.
    ///
    /// - Parameters:
    ///   - comparator: the comparator to use in ordering elements
    /// - Returns: an array of the elements sorted using `comparator`.
    public func sorted<Comparator: SortComparator>(using comparator: Comparator) -> [Element] where Comparator.Compared == Element {
        return self.sorted {
            comparator.compare($0, $1) == .orderedAscending
        }
    }

    /// Returns the elements of the sequence, sorted using the given array of
    /// `SortComparator`s to compare elements.
    ///
    /// - Parameters:
    ///   - comparators: an array of comparators used to compare elements. The
    ///   first comparator specifies the primary comparator to be used in
    ///   sorting the sequence's elements. Any subsequent comparators are used
    ///   to further refine the order of elements with equal values.
    /// - Returns: an array of the elements sorted using `comparators`.
    public func sorted<S: Sequence, Comparator: SortComparator>(using comparators: S) -> [Element] where
        S.Element == Comparator,
        Element == Comparator.Compared
    {
        return self.sorted {
            comparators.compare($0, $1) == .orderedAscending
        }
    }
}

@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
extension Sequence {
    /// If `lhs` is ordered before `rhs` in the ordering described by the given
    /// sequence of `SortComparator`s
    ///
    /// The first element of the sequence of comparators specifies the primary
    /// comparator to be used in sorting the sequence's elements. Any subsequent
    /// comparators are used to further refine the order of elements with equal
    /// values.
    public func compare<Comparator: SortComparator>(_ lhs: Comparator.Compared, _ rhs: Comparator.Compared) -> ComparisonResult where Element == Comparator {
        for comparator in self {
            let result = comparator.compare(lhs, rhs)
            if result != .orderedSame { return result }
        }
        return .orderedSame
    }
}

@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
extension MutableCollection where Self: RandomAccessCollection {
    /// Sorts the collection using the given comparator to compare elements.
    /// - Parameters:
    ///     - comparator: the sort comparator used to compare elements.
    public mutating func sort<Comparator: SortComparator>(using comparator: Comparator) where Comparator.Compared == Element {
        self.sort {
            comparator.compare($0, $1) == .orderedAscending
        }
    }

    /// Sorts the collection using the given array of `SortComparator`s to
    /// compare elements.
    ///
    /// - Parameters:
    ///   - comparators: an array of comparators used to compare elements. The
    ///   first comparator specifies the primary comparator to be used in
    ///   sorting the sequence's elements. Any subsequent comparators are used
    ///   to further refine the order of elements with equal values.
    public mutating func sort<S: Sequence, Comparator: SortComparator>(using comparators: S) where S.Element == Comparator, Element == Comparator.Compared {
        self.sort {
            comparators.compare($0, $1) == .orderedAscending
        }
    }
}