mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
168 lines
6.9 KiB
Swift
168 lines
6.9 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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 type that can be hashed into a `Hasher` to produce an integer hash value.
|
|
///
|
|
/// You can use any type that conforms to the `Hashable` protocol in a set or as
|
|
/// a dictionary key. Many types in the standard library conform to `Hashable`:
|
|
/// Strings, integers, floating-point and Boolean values, and even sets are
|
|
/// hashable by default. Some other types, such as optionals, arrays and ranges
|
|
/// automatically become hashable when their type arguments implement the same.
|
|
///
|
|
/// Your own custom types can be hashable as well. When you define an
|
|
/// enumeration without associated values, it gains `Hashable` conformance
|
|
/// automatically, and you can add `Hashable` conformance to your other custom
|
|
/// types by implementing the `hash(into:)` method. For structs whose stored
|
|
/// properties are all `Hashable`, and for enum types that have all-`Hashable`
|
|
/// associated values, the compiler is able to provide an implementation of
|
|
/// `hash(into:)` automatically.
|
|
///
|
|
/// Hashing a value means feeding its essential components into a hash function,
|
|
/// represented by the `Hasher` type. Essential components are those that
|
|
/// contribute to the type's implementation of `Equatable`. Two instances that
|
|
/// are equal must feed the same values to `Hasher` in `hash(into:)`, in the
|
|
/// same order.
|
|
///
|
|
/// Conforming to the Hashable Protocol
|
|
/// ===================================
|
|
///
|
|
/// To use your own custom type in a set or as the key type of a dictionary,
|
|
/// add `Hashable` conformance to your type. The `Hashable` protocol inherits
|
|
/// from the `Equatable` protocol, so you must also satisfy that protocol's
|
|
/// requirements.
|
|
///
|
|
/// The compiler automatically synthesizes your custom type's `Hashable` and
|
|
/// requirements when you declare `Hashable` conformance in the type's original
|
|
/// declaration and your type meets these criteria:
|
|
///
|
|
/// - For a `struct`, all its stored properties must conform to `Hashable`.
|
|
/// - For an `enum`, all its associated values must conform to `Hashable`. (An
|
|
/// `enum` without associated values has `Hashable` conformance even without
|
|
/// the declaration.)
|
|
///
|
|
/// To customize your type's `Hashable` conformance, to adopt `Hashable` in a
|
|
/// type that doesn't meet the criteria listed above, or to extend an existing
|
|
/// type to conform to `Hashable`, implement the `hash(into:)` method in your
|
|
/// custom type.
|
|
///
|
|
/// In your `hash(into:)` implementation, call `combine(_:)` on the provided
|
|
/// `Hasher` instance with the essential components of your type. To ensure
|
|
/// that your type meets the semantic requirements of the `Hashable` and
|
|
/// `Equatable` protocols, it's a good idea to also customize your type's
|
|
/// `Equatable` conformance to match.
|
|
///
|
|
/// As an example, consider a `GridPoint` type that describes a location in a
|
|
/// grid of buttons. Here's the initial declaration of the `GridPoint` type:
|
|
///
|
|
/// /// A point in an x-y coordinate system.
|
|
/// struct GridPoint {
|
|
/// var x: Int
|
|
/// var y: Int
|
|
/// }
|
|
///
|
|
/// You'd like to create a set of the grid points where a user has already
|
|
/// tapped. Because the `GridPoint` type is not hashable yet, it can't be used
|
|
/// in a set. To add `Hashable` conformance, provide an `==` operator function
|
|
/// and implement the `hash(into:)` method.
|
|
///
|
|
/// extension GridPoint: Hashable {
|
|
/// static func == (lhs: GridPoint, rhs: GridPoint) -> Bool {
|
|
/// return lhs.x == rhs.x && lhs.y == rhs.y
|
|
/// }
|
|
///
|
|
/// func hash(into hasher: inout Hasher) {
|
|
/// hasher.combine(x)
|
|
/// hasher.combine(y)
|
|
/// }
|
|
/// }
|
|
///
|
|
/// The `hash(into:)` method in this example feeds the grid point's `x` and `y`
|
|
/// properties into the provided hasher. These properties are the same ones
|
|
/// used to test for equality in the `==` operator function.
|
|
///
|
|
/// Now that `GridPoint` conforms to the `Hashable` protocol, you can create a
|
|
/// set of previously tapped grid points.
|
|
///
|
|
/// var tappedPoints: Set = [GridPoint(x: 2, y: 3), GridPoint(x: 4, y: 1)]
|
|
/// let nextTap = GridPoint(x: 0, y: 1)
|
|
/// if tappedPoints.contains(nextTap) {
|
|
/// print("Already tapped at (\(nextTap.x), \(nextTap.y)).")
|
|
/// } else {
|
|
/// tappedPoints.insert(nextTap)
|
|
/// print("New tap detected at (\(nextTap.x), \(nextTap.y)).")
|
|
/// }
|
|
/// // Prints "New tap detected at (0, 1).")
|
|
public protocol Hashable: Equatable {
|
|
/// The hash value.
|
|
///
|
|
/// Hash values are not guaranteed to be equal across different executions of
|
|
/// your program. Do not save hash values to use during a future execution.
|
|
///
|
|
/// - Important: `hashValue` is deprecated as a `Hashable` requirement. To
|
|
/// conform to `Hashable`, implement the `hash(into:)` requirement instead.
|
|
var hashValue: Int { get }
|
|
|
|
/// Hashes the essential components of this value by feeding them into the
|
|
/// given hasher.
|
|
///
|
|
/// Implement this method to conform to the `Hashable` protocol. The
|
|
/// components used for hashing must be the same as the components compared
|
|
/// in your type's `==` operator implementation. Call `hasher.combine(_:)`
|
|
/// with each of these components.
|
|
///
|
|
/// - Important: Never call `finalize()` on `hasher`. Doing so may become a
|
|
/// compile-time error in the future.
|
|
///
|
|
/// - Parameter hasher: The hasher to use when combining the components
|
|
/// of this instance.
|
|
func hash(into hasher: inout Hasher)
|
|
|
|
// Raw top-level hashing interface. Some standard library types (mostly
|
|
// primitives) specialize this to eliminate small resiliency overheads. (This
|
|
// only matters for tiny keys.)
|
|
func _rawHashValue(seed: Int) -> Int
|
|
}
|
|
|
|
extension Hashable {
|
|
@inlinable
|
|
@inline(__always)
|
|
public func _rawHashValue(seed: Int) -> Int {
|
|
var hasher = Hasher(_seed: seed)
|
|
hasher.combine(self)
|
|
return hasher._finalize()
|
|
}
|
|
}
|
|
|
|
// Called by synthesized `hashValue` implementations.
|
|
@inlinable
|
|
@inline(__always)
|
|
public func _hashValue<H: Hashable>(for value: H) -> Int {
|
|
return value._rawHashValue(seed: 0)
|
|
}
|
|
|
|
// Called by the SwiftValue implementation.
|
|
@_silgen_name("_swift_stdlib_Hashable_isEqual_indirect")
|
|
internal func Hashable_isEqual_indirect<T: Hashable>(
|
|
_ lhs: UnsafePointer<T>,
|
|
_ rhs: UnsafePointer<T>
|
|
) -> Bool {
|
|
return lhs.pointee == rhs.pointee
|
|
}
|
|
|
|
// Called by the SwiftValue implementation.
|
|
@_silgen_name("_swift_stdlib_Hashable_hashValue_indirect")
|
|
internal func Hashable_hashValue_indirect<T: Hashable>(
|
|
_ value: UnsafePointer<T>
|
|
) -> Int {
|
|
return value.pointee.hashValue
|
|
}
|