-
Notifications
You must be signed in to change notification settings - Fork 10.4k
/
Copy pathHashable.swift
167 lines (160 loc) · 6.91 KB
/
Hashable.swift
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
//===----------------------------------------------------------------------===//
//
// 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
}