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 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
|
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Equatable
//===----------------------------------------------------------------------===//
/// A type that can be compared for value equality.
///
/// Types that conform to the `Equatable` protocol can be compared for equality
/// using the equal-to operator (`==`) or inequality using the not-equal-to
/// operator (`!=`). Most basic types in the Swift standard library conform to
/// `Equatable`.
///
/// Some sequence and collection operations can be used more simply when the
/// elements conform to `Equatable`. For example, to check whether an array
/// contains a particular value, you can pass the value itself to the
/// `contains(_:)` method when the array's element conforms to `Equatable`
/// instead of providing a closure that determines equivalence. The following
/// example shows how the `contains(_:)` method can be used with an array of
/// strings.
///
/// let students = ["Kofi", "Abena", "Efua", "Kweku", "Akosua"]
///
/// let nameToCheck = "Kofi"
/// if students.contains(nameToCheck) {
/// print("\(nameToCheck) is signed up!")
/// } else {
/// print("No record of \(nameToCheck).")
/// }
/// // Prints "Kofi is signed up!"
///
/// Conforming to the Equatable Protocol
/// ====================================
///
/// Adding `Equatable` conformance to your custom types means that you can use
/// more convenient APIs when searching for particular instances in a
/// collection. `Equatable` is also the base protocol for the `Hashable` and
/// `Comparable` protocols, which allow more uses of your custom type, such as
/// constructing sets or sorting the elements of a collection.
///
/// You can rely on automatic synthesis of the `Equatable` protocol's
/// requirements for a custom type when you declare `Equatable` conformance in
/// the type's original declaration and your type meets these criteria:
///
/// - For a `struct`, all its stored properties must conform to `Equatable`.
/// - For an `enum`, all its associated values must conform to `Equatable`. (An
/// `enum` without associated values has `Equatable` conformance even
/// without the declaration.)
///
/// To customize your type's `Equatable` conformance, to adopt `Equatable` in a
/// type that doesn't meet the criteria listed above, or to extend an existing
/// type to conform to `Equatable`, implement the equal-to operator (`==`) as
/// a static method of your type. The standard library provides an
/// implementation for the not-equal-to operator (`!=`) for any `Equatable`
/// type, which calls the custom `==` function and negates its result.
///
/// As an example, consider a `StreetAddress` class that holds the parts of a
/// street address: a house or building number, the street name, and an
/// optional unit number. Here's the initial declaration of the
/// `StreetAddress` type:
///
/// class StreetAddress {
/// let number: String
/// let street: String
/// let unit: String?
///
/// init(_ number: String, _ street: String, unit: String? = nil) {
/// self.number = number
/// self.street = street
/// self.unit = unit
/// }
/// }
///
/// Now suppose you have an array of addresses that you need to check for a
/// particular address. To use the `contains(_:)` method without including a
/// closure in each call, extend the `StreetAddress` type to conform to
/// `Equatable`.
///
/// extension StreetAddress: Equatable {
/// static func == (lhs: StreetAddress, rhs: StreetAddress) -> Bool {
/// return
/// lhs.number == rhs.number &&
/// lhs.street == rhs.street &&
/// lhs.unit == rhs.unit
/// }
/// }
///
/// The `StreetAddress` type now conforms to `Equatable`. You can use `==` to
/// check for equality between any two instances or call the
/// `Equatable`-constrained `contains(_:)` method.
///
/// let addresses = [StreetAddress("1490", "Grove Street"),
/// StreetAddress("2119", "Maple Avenue"),
/// StreetAddress("1400", "16th Street")]
/// let home = StreetAddress("1400", "16th Street")
///
/// print(addresses[0] == home)
/// // Prints "false"
/// print(addresses.contains(home))
/// // Prints "true"
///
/// Equality implies substitutability---any two instances that compare equally
/// can be used interchangeably in any code that depends on their values. To
/// maintain substitutability, the `==` operator should take into account all
/// visible aspects of an `Equatable` type. Exposing nonvalue aspects of
/// `Equatable` types other than class identity is discouraged, and any that
/// *are* exposed should be explicitly pointed out in documentation.
///
/// Since equality between instances of `Equatable` types is an equivalence
/// relation, any of your custom types that conform to `Equatable` must
/// satisfy three conditions, for any values `a`, `b`, and `c`:
///
/// - `a == a` is always `true` (Reflexivity)
/// - `a == b` implies `b == a` (Symmetry)
/// - `a == b` and `b == c` implies `a == c` (Transitivity)
///
/// Moreover, inequality is the inverse of equality, so any custom
/// implementation of the `!=` operator must guarantee that `a != b` implies
/// `!(a == b)`. The default implementation of the `!=` operator function
/// satisfies this requirement.
///
/// Equality is Separate From Identity
/// ----------------------------------
///
/// The identity of a class instance is not part of an instance's value.
/// Consider a class called `IntegerRef` that wraps an integer value. Here's
/// the definition for `IntegerRef` and the `==` function that makes it
/// conform to `Equatable`:
///
/// class IntegerRef: Equatable {
/// let value: Int
/// init(_ value: Int) {
/// self.value = value
/// }
///
/// static func == (lhs: IntegerRef, rhs: IntegerRef) -> Bool {
/// return lhs.value == rhs.value
/// }
/// }
///
/// The implementation of the `==` function returns the same value whether its
/// two arguments are the same instance or are two different instances with
/// the same integer stored in their `value` properties. For example:
///
/// let a = IntegerRef(100)
/// let b = IntegerRef(100)
///
/// print(a == a, a == b, separator: ", ")
/// // Prints "true, true"
///
/// Class instance identity, on the other hand, is compared using the
/// triple-equals identical-to operator (`===`). For example:
///
/// let c = a
/// print(c === a, c === b, separator: ", ")
/// // Prints "true, false"
public protocol Equatable {
/// Returns a Boolean value indicating whether two values are equal.
///
/// Equality is the inverse of inequality. For any values `a` and `b`,
/// `a == b` implies that `a != b` is `false`.
///
/// - Parameters:
/// - lhs: A value to compare.
/// - rhs: Another value to compare.
static func == (lhs: Self, rhs: Self) -> Bool
}
extension Equatable {
/// Returns a Boolean value indicating whether two values are not equal.
///
/// Inequality is the inverse of equality. For any values `a` and `b`, `a != b`
/// implies that `a == b` is `false`.
///
/// This is the default implementation of the not-equal-to operator (`!=`)
/// for any type that conforms to `Equatable`.
///
/// - Parameters:
/// - lhs: A value to compare.
/// - rhs: Another value to compare.
// transparent because sometimes types that use this generate compile-time
// warnings, e.g. that an expression always evaluates to true
@_transparent
public static func != (lhs: Self, rhs: Self) -> Bool {
return !(lhs == rhs)
}
}
// Called by the SwiftValue implementation.
@_silgen_name("_swift_stdlib_Equatable_isEqual_indirect")
internal func Equatable_isEqual_indirect<T: Equatable>(
_ lhs: UnsafePointer<T>,
_ rhs: UnsafePointer<T>
) -> Bool {
return lhs.pointee == rhs.pointee
}
//===----------------------------------------------------------------------===//
// Reference comparison
//===----------------------------------------------------------------------===//
/// Returns a Boolean value indicating whether two references point to the same
/// object instance.
///
/// This operator tests whether two instances have the same identity, not the
/// same value. For value equality, see the equal-to operator (`==`) and the
/// `Equatable` protocol.
///
/// The following example defines an `IntegerRef` type, an integer type with
/// reference semantics.
///
/// class IntegerRef: Equatable {
/// let value: Int
/// init(_ value: Int) {
/// self.value = value
/// }
/// }
///
/// func == (lhs: IntegerRef, rhs: IntegerRef) -> Bool {
/// return lhs.value == rhs.value
/// }
///
/// Because `IntegerRef` is a class, its instances can be compared using the
/// identical-to operator (`===`). In addition, because `IntegerRef` conforms
/// to the `Equatable` protocol, instances can also be compared using the
/// equal-to operator (`==`).
///
/// let a = IntegerRef(10)
/// let b = a
/// print(a == b)
/// // Prints "true"
/// print(a === b)
/// // Prints "true"
///
/// The identical-to operator (`===`) returns `false` when comparing two
/// references to different object instances, even if the two instances have
/// the same value.
///
/// let c = IntegerRef(10)
/// print(a == c)
/// // Prints "true"
/// print(a === c)
/// // Prints "false"
///
/// - Parameters:
/// - lhs: A reference to compare.
/// - rhs: Another reference to compare.
#if !$Embedded
@inlinable // trivial-implementation
public func === (lhs: AnyObject?, rhs: AnyObject?) -> Bool {
switch (lhs, rhs) {
case let (l?, r?):
return ObjectIdentifier(l) == ObjectIdentifier(r)
case (nil, nil):
return true
default:
return false
}
}
#else
@inlinable // trivial-implementation
public func ===<T: AnyObject, U: AnyObject>(lhs: T?, rhs: U?) -> Bool {
switch (lhs, rhs) {
case let (l?, r?):
return Builtin.bridgeToRawPointer(l) == Builtin.bridgeToRawPointer(r)
case (nil, nil):
return true
default:
return false
}
}
#endif
/// Returns a Boolean value indicating whether two references point to
/// different object instances.
///
/// This operator tests whether two instances have different identities, not
/// different values. For value inequality, see the not-equal-to operator
/// (`!=`) and the `Equatable` protocol.
///
/// - Parameters:
/// - lhs: A reference to compare.
/// - rhs: Another reference to compare.
#if !$Embedded
@inlinable // trivial-implementation
public func !== (lhs: AnyObject?, rhs: AnyObject?) -> Bool {
return !(lhs === rhs)
}
#else
@inlinable // trivial-implementation
public func !==<T: AnyObject, U: AnyObject>(lhs: T, rhs: U) -> Bool {
return !(lhs === rhs)
}
#endif
|