Files
UUVPN/iOS-SwiftUI-Code/GRDB.swift-6.29.3/GRDB/Core/DatabaseCollation.swift
T
2025-01-22 14:09:10 +08:00

79 lines
2.8 KiB
Swift

import Foundation
/// `DatabaseCollation` is a custom string comparison function used by SQLite.
///
/// See also ``Database/CollationName``.
///
/// Related SQLite documentation: <https://www.sqlite.org/datatype3.html#collating_sequences>
///
/// ## Topics
///
/// ### Creating a Custom Collation
///
/// - ``init(_:function:)``
/// - ``name``
///
/// ### Built-in Collations
///
/// - ``caseInsensitiveCompare``
/// - ``localizedCaseInsensitiveCompare``
/// - ``localizedCompare``
/// - ``localizedStandardCompare``
/// - ``unicodeCompare``
public final class DatabaseCollation {
/// The name of the collation.
public let name: String
let function: (CInt, UnsafeRawPointer?, CInt, UnsafeRawPointer?) -> ComparisonResult
/// Creates a collation.
///
/// For example:
///
/// ```swift
/// let collation = DatabaseCollation("localized_standard") { (string1, string2) in
/// return (string1 as NSString).localizedStandardCompare(string2)
/// }
/// db.add(collation: collation)
/// try db.execute(sql: "CREATE TABLE file (name TEXT COLLATE localized_standard")
/// ```
///
/// - parameters:
/// - name: The collation name.
/// - function: A function that compares two strings.
public init(_ name: String, function: @escaping (String, String) -> ComparisonResult) {
self.name = name
self.function = { (length1, buffer1, length2, buffer2) in
// Buffers are not C strings: they do not end with \0.
let string1 = String(
bytesNoCopy: UnsafeMutableRawPointer(mutating: buffer1.unsafelyUnwrapped),
length: Int(length1),
encoding: .utf8,
freeWhenDone: false)!
let string2 = String(
bytesNoCopy: UnsafeMutableRawPointer(mutating: buffer2.unsafelyUnwrapped),
length: Int(length2),
encoding: .utf8,
freeWhenDone: false)!
return function(string1, string2)
}
}
}
extension DatabaseCollation: Hashable {
// Collation equality is based on the sqlite3_strnicmp SQLite function.
// (see https://www.sqlite.org/c3ref/create_collation.html). Computing
// a hash value that honors the Swift Hashable contract (value equality
// implies hash equality) is thus non trivial. But it's not that
// important, since this hashValue is only used when one adds
// or removes a collation from a database connection.
public func hash(into hasher: inout Hasher) {
hasher.combine(0)
}
/// Two collations are equal if they share the same name (case insensitive)
public static func == (lhs: DatabaseCollation, rhs: DatabaseCollation) -> Bool {
// See <https://www.sqlite.org/c3ref/create_collation.html>
return sqlite3_stricmp(lhs.name, rhs.name) == 0
}
}