62 lines
1.9 KiB
Swift
62 lines
1.9 KiB
Swift
//
|
|
// SemiCaseSensitiveComparator.swift
|
|
// Tusker
|
|
//
|
|
// Created by Shadowfacts on 11/30/22.
|
|
// Copyright © 2022 Shadowfacts. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
/// A comparator that sorts objects with a string key path case insensitively unless they're the same, in which case uppercase comes after lowercase.
|
|
struct SemiCaseSensitiveComparator: SortComparator {
|
|
var order: SortOrder = .forward
|
|
|
|
typealias Compared = String
|
|
|
|
static func keyPath<Object>(_ keyPath: KeyPath<Object, String>) -> KeyPathComparator<Object> {
|
|
return KeyPathComparator(keyPath, comparator: SemiCaseSensitiveComparator())
|
|
}
|
|
|
|
func compare(_ lhs: String, _ rhs: String) -> ComparisonResult {
|
|
let result = doCompare(lhs, rhs)
|
|
if case .reverse = order {
|
|
switch result {
|
|
case .orderedDescending:
|
|
return .orderedAscending
|
|
case .orderedAscending:
|
|
return .orderedDescending
|
|
case .orderedSame:
|
|
return .orderedSame
|
|
}
|
|
} else {
|
|
return result
|
|
}
|
|
}
|
|
|
|
private func doCompare(_ lhs: String, _ rhs: String) -> ComparisonResult {
|
|
for (l, r) in zip(lhs, rhs) {
|
|
let lLower = l.lowercased()
|
|
let rLower = r.lowercased()
|
|
if lLower < rLower {
|
|
return .orderedAscending
|
|
} else if lLower > rLower {
|
|
return .orderedDescending
|
|
} else {
|
|
if l < r {
|
|
return .orderedDescending
|
|
} else if l > r {
|
|
return .orderedAscending
|
|
}
|
|
}
|
|
}
|
|
if lhs.count > rhs.count {
|
|
return .orderedDescending
|
|
} else if lhs.count < rhs.count {
|
|
return .orderedAscending
|
|
} else {
|
|
return .orderedSame
|
|
}
|
|
}
|
|
}
|