| // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| part of dart.core; |
| |
| /// The base class for all Dart objects except `null`. |
| /// |
| /// Because `Object` is a root of the non-nullable Dart class hierarchy, |
| /// every other non-`Null` Dart class is a subclass of `Object`. |
| /// |
| /// When you define a class, you should consider overriding [toString] |
| /// to return a string describing an instance of that class. |
| /// You might also need to define [hashCode] and [operator ==], as described in the |
| /// [Implementing map keys](https://dart.dev/guides/libraries/library-tour#implementing-map-keys) |
| /// section of the [library tour](https://dart.dev/guides/libraries/library-tour). |
| @pragma("vm:entry-point") |
| class Object { |
| /// Creates a new [Object] instance. |
| /// |
| /// [Object] instances have no meaningful state, and are only useful |
| /// through their identity. An [Object] instance is equal to itself |
| /// only. |
| @pragma("vm:recognized", "other") |
| const Object(); |
| |
| /// The equality operator. |
| /// |
| /// The default behavior for all [Object]s is to return true if and |
| /// only if this object and [other] are the same object. |
| /// |
| /// Override this method to specify a different equality relation on |
| /// a class. The overriding method must still be an equivalence relation. |
| /// That is, it must be: |
| /// |
| /// * Total: It must return a boolean for all arguments. It should never throw. |
| /// |
| /// * Reflexive: For all objects `o`, `o == o` must be true. |
| /// |
| /// * Symmetric: For all objects `o1` and `o2`, `o1 == o2` and `o2 == o1` must |
| /// either both be true, or both be false. |
| /// |
| /// * Transitive: For all objects `o1`, `o2`, and `o3`, if `o1 == o2` and |
| /// `o2 == o3` are true, then `o1 == o3` must be true. |
| /// |
| /// The method should also be consistent over time, |
| /// so whether two objects are equal should only change |
| /// if at least one of the objects was modified. |
| /// |
| /// If a subclass overrides the equality operator, it should override |
| /// the [hashCode] method as well to maintain consistency. |
| external bool operator ==(Object other); |
| |
| /// The hash code for this object. |
| /// |
| /// A hash code is a single integer which represents the state of the object |
| /// that affects [operator ==] comparisons. |
| /// |
| /// All objects have hash codes. |
| /// The default hash code implemented by [Object] |
| /// represents only the identity of the object, |
| /// the same way as the default [operator ==] implementation only considers objects |
| /// equal if they are identical (see [identityHashCode]). |
| /// |
| /// If [operator ==] is overridden to use the object state instead, |
| /// the hash code must also be changed to represent that state, |
| /// otherwise the object cannot be used in hash based data structures |
| /// like the default [Set] and [Map] implementations. |
| /// |
| /// Hash codes must be the same for objects that are equal to each other |
| /// according to [operator ==]. |
| /// The hash code of an object should only change if the object changes |
| /// in a way that affects equality. |
| /// There are no further requirements for the hash codes. |
| /// They need not be consistent between executions of the same program |
| /// and there are no distribution guarantees. |
| /// |
| /// Objects that are not equal are allowed to have the same hash code. |
| /// It is even technically allowed that all instances have the same hash code, |
| /// but if clashes happen too often, |
| /// it may reduce the efficiency of hash-based data structures |
| /// like [HashSet] or [HashMap]. |
| /// |
| /// If a subclass overrides [hashCode], it should override the |
| /// [operator ==] operator as well to maintain consistency. |
| external int get hashCode; |
| |
| /// A string representation of this object. |
| /// |
| /// Some classes have a default textual representation, |
| /// often paired with a static `parse` function (like [int.parse]). |
| /// These classes will provide the textual representation as |
| /// their string represetion. |
| /// |
| /// Other classes have no meaningful textual representation |
| /// that a program will care about. |
| /// Such classes will typically override `toString` to provide |
| /// useful information when inspecting the object, |
| /// mainly for debugging or logging. |
| external String toString(); |
| |
| /// Invoked when a non-existent method or property is accessed. |
| /// |
| /// A dynamic member invocation can attempt to call a member which |
| /// doesn't exist on the receiving object. Example: |
| /// ```dart |
| /// dynamic object = 1; |
| /// object.add(42); // Statically allowed, run-time error |
| /// ``` |
| /// This invalid code will invoke the `noSuchMethod` method |
| /// of the integer `1` with an [Invocation] representing the |
| /// `.add(42)` call and arguments (which then throws). |
| /// |
| /// Classes can override [noSuchMethod] to provide custom behavior |
| /// for such invalid dynamic invocations. |
| /// |
| /// A class with a non-default [noSuchMethod] invocation can also |
| /// omit implementations for members of its interface. |
| /// Example: |
| /// ```dart |
| /// class MockList<T> implements List<T> { |
| /// noSuchMethod(Invocation invocation) { |
| /// log(invocation); |
| /// super.noSuchMethod(invocation); // Will throw. |
| /// } |
| /// } |
| /// void main() { |
| /// MockList().add(42); |
| /// } |
| /// ``` |
| /// This code has no compile-time warnings or errors even though |
| /// the `MockList` class has no concrete implementation of |
| /// any of the `List` interface methods. |
| /// Calls to `List` methods are forwarded to `noSuchMethod`, |
| /// so this code will `log` an invocation similar to |
| /// `Invocation.method(#add, [42])` and then throw. |
| /// |
| /// If a value is returned from `noSuchMethod`, |
| /// it becomes the result of the original invocation. |
| /// If the value is not of a type that can be returned by the original |
| /// invocation, a type error occurs at the invocation. |
| /// |
| /// The default behavior is to throw a [NoSuchMethodError]. |
| @pragma("vm:entry-point") |
| external dynamic noSuchMethod(Invocation invocation); |
| |
| /// A representation of the runtime type of the object. |
| external Type get runtimeType; |
| |
| /// Creates a combined hash code for a number of objects. |
| /// |
| /// The hash code is computed for all arguments that are actually |
| /// supplied, even if they are `null`, by numerically combining the |
| /// [Object.hashCode] of each argument. |
| /// |
| /// Example: |
| /// ```dart |
| /// class SomeObject { |
| /// final Object a, b, c; |
| /// SomeObject(this.a, this.b, this.c); |
| /// bool operator=(Object other) => |
| /// other is SomeObject && a == other.a && b == other.b && c == other.c; |
| /// int get hashCode => Object.hash(a, b, c); |
| /// } |
| /// ``` |
| /// |
| /// The computed value will be consistent when the function is called |
| /// with the same arguments multiple times |
| /// during the execution of a single program. |
| /// |
| /// The hash value generated by this function is *not* guaranteed to be stable |
| /// over different runs of the same program, |
| /// or between code run in different isolates of the same program. |
| /// The exact algorithm used may differ between different platforms, |
| /// or between different versions of the platform libraries, |
| /// and it may depend on values that change on each program execution. |
| /// |
| /// The [hashAll] function gives the same result as this function when |
| /// called with a collection containing the actual arguments |
| /// to this function in the same order. |
| @Since("2.14") |
| static int hash(Object? object1, Object? object2, |
| [Object? object3 = sentinelValue, |
| Object? object4 = sentinelValue, |
| Object? object5 = sentinelValue, |
| Object? object6 = sentinelValue, |
| Object? object7 = sentinelValue, |
| Object? object8 = sentinelValue, |
| Object? object9 = sentinelValue, |
| Object? object10 = sentinelValue, |
| Object? object11 = sentinelValue, |
| Object? object12 = sentinelValue, |
| Object? object13 = sentinelValue, |
| Object? object14 = sentinelValue, |
| Object? object15 = sentinelValue, |
| Object? object16 = sentinelValue, |
| Object? object17 = sentinelValue, |
| Object? object18 = sentinelValue, |
| Object? object19 = sentinelValue, |
| Object? object20 = sentinelValue]) { |
| if (sentinelValue == object3) { |
| return SystemHash.hash2(object1.hashCode, object2.hashCode, _hashSeed); |
| } |
| if (sentinelValue == object4) { |
| return SystemHash.hash3( |
| object1.hashCode, object2.hashCode, object3.hashCode, _hashSeed); |
| } |
| if (sentinelValue == object5) { |
| return SystemHash.hash4(object1.hashCode, object2.hashCode, |
| object3.hashCode, object4.hashCode, _hashSeed); |
| } |
| if (sentinelValue == object6) { |
| return SystemHash.hash5(object1.hashCode, object2.hashCode, |
| object3.hashCode, object4.hashCode, object5.hashCode, _hashSeed); |
| } |
| if (sentinelValue == object7) { |
| return SystemHash.hash6( |
| object1.hashCode, |
| object2.hashCode, |
| object3.hashCode, |
| object4.hashCode, |
| object5.hashCode, |
| object6.hashCode, |
| _hashSeed); |
| } |
| if (sentinelValue == object8) { |
| return SystemHash.hash7( |
| object1.hashCode, |
| object2.hashCode, |
| object3.hashCode, |
| object4.hashCode, |
| object5.hashCode, |
| object6.hashCode, |
| object7.hashCode, |
| _hashSeed); |
| } |
| if (sentinelValue == object9) { |
| return SystemHash.hash8( |
| object1.hashCode, |
| object2.hashCode, |
| object3.hashCode, |
| object4.hashCode, |
| object5.hashCode, |
| object6.hashCode, |
| object7.hashCode, |
| object8.hashCode, |
| _hashSeed); |
| } |
| if (sentinelValue == object10) { |
| return SystemHash.hash9( |
| object1.hashCode, |
| object2.hashCode, |
| object3.hashCode, |
| object4.hashCode, |
| object5.hashCode, |
| object6.hashCode, |
| object7.hashCode, |
| object8.hashCode, |
| object9.hashCode, |
| _hashSeed); |
| } |
| if (sentinelValue == object11) { |
| return SystemHash.hash10( |
| object1.hashCode, |
| object2.hashCode, |
| object3.hashCode, |
| object4.hashCode, |
| object5.hashCode, |
| object6.hashCode, |
| object7.hashCode, |
| object8.hashCode, |
| object9.hashCode, |
| object10.hashCode, |
| _hashSeed); |
| } |
| if (sentinelValue == object12) { |
| return SystemHash.hash11( |
| object1.hashCode, |
| object2.hashCode, |
| object3.hashCode, |
| object4.hashCode, |
| object5.hashCode, |
| object6.hashCode, |
| object7.hashCode, |
| object8.hashCode, |
| object9.hashCode, |
| object10.hashCode, |
| object11.hashCode, |
| _hashSeed); |
| } |
| if (sentinelValue == object13) { |
| return SystemHash.hash12( |
| object1.hashCode, |
| object2.hashCode, |
| object3.hashCode, |
| object4.hashCode, |
| object5.hashCode, |
| object6.hashCode, |
| object7.hashCode, |
| object8.hashCode, |
| object9.hashCode, |
| object10.hashCode, |
| object11.hashCode, |
| object12.hashCode, |
| _hashSeed); |
| } |
| if (sentinelValue == object14) { |
| return SystemHash.hash13( |
| object1.hashCode, |
| object2.hashCode, |
| object3.hashCode, |
| object4.hashCode, |
| object5.hashCode, |
| object6.hashCode, |
| object7.hashCode, |
| object8.hashCode, |
| object9.hashCode, |
| object10.hashCode, |
| object11.hashCode, |
| object12.hashCode, |
| object13.hashCode, |
| _hashSeed); |
| } |
| if (sentinelValue == object15) { |
| return SystemHash.hash14( |
| object1.hashCode, |
| object2.hashCode, |
| object3.hashCode, |
| object4.hashCode, |
| object5.hashCode, |
| object6.hashCode, |
| object7.hashCode, |
| object8.hashCode, |
| object9.hashCode, |
| object10.hashCode, |
| object11.hashCode, |
| object12.hashCode, |
| object13.hashCode, |
| object14.hashCode, |
| _hashSeed); |
| } |
| if (sentinelValue == object16) { |
| return SystemHash.hash15( |
| object1.hashCode, |
| object2.hashCode, |
| object3.hashCode, |
| object4.hashCode, |
| object5.hashCode, |
| object6.hashCode, |
| object7.hashCode, |
| object8.hashCode, |
| object9.hashCode, |
| object10.hashCode, |
| object11.hashCode, |
| object12.hashCode, |
| object13.hashCode, |
| object14.hashCode, |
| object15.hashCode, |
| _hashSeed); |
| } |
| if (sentinelValue == object17) { |
| return SystemHash.hash16( |
| object1.hashCode, |
| object2.hashCode, |
| object3.hashCode, |
| object4.hashCode, |
| object5.hashCode, |
| object6.hashCode, |
| object7.hashCode, |
| object8.hashCode, |
| object9.hashCode, |
| object10.hashCode, |
| object11.hashCode, |
| object12.hashCode, |
| object13.hashCode, |
| object14.hashCode, |
| object15.hashCode, |
| object16.hashCode, |
| _hashSeed); |
| } |
| if (sentinelValue == object18) { |
| return SystemHash.hash17( |
| object1.hashCode, |
| object2.hashCode, |
| object3.hashCode, |
| object4.hashCode, |
| object5.hashCode, |
| object6.hashCode, |
| object7.hashCode, |
| object8.hashCode, |
| object9.hashCode, |
| object10.hashCode, |
| object11.hashCode, |
| object12.hashCode, |
| object13.hashCode, |
| object14.hashCode, |
| object15.hashCode, |
| object16.hashCode, |
| object17.hashCode, |
| _hashSeed); |
| } |
| if (sentinelValue == object19) { |
| return SystemHash.hash18( |
| object1.hashCode, |
| object2.hashCode, |
| object3.hashCode, |
| object4.hashCode, |
| object5.hashCode, |
| object6.hashCode, |
| object7.hashCode, |
| object8.hashCode, |
| object9.hashCode, |
| object10.hashCode, |
| object11.hashCode, |
| object12.hashCode, |
| object13.hashCode, |
| object14.hashCode, |
| object15.hashCode, |
| object16.hashCode, |
| object17.hashCode, |
| object18.hashCode, |
| _hashSeed); |
| } |
| if (sentinelValue == object20) { |
| return SystemHash.hash19( |
| object1.hashCode, |
| object2.hashCode, |
| object3.hashCode, |
| object4.hashCode, |
| object5.hashCode, |
| object6.hashCode, |
| object7.hashCode, |
| object8.hashCode, |
| object9.hashCode, |
| object10.hashCode, |
| object11.hashCode, |
| object12.hashCode, |
| object13.hashCode, |
| object14.hashCode, |
| object15.hashCode, |
| object16.hashCode, |
| object17.hashCode, |
| object18.hashCode, |
| object19.hashCode, |
| _hashSeed); |
| } |
| return SystemHash.hash20( |
| object1.hashCode, |
| object2.hashCode, |
| object3.hashCode, |
| object4.hashCode, |
| object5.hashCode, |
| object6.hashCode, |
| object7.hashCode, |
| object8.hashCode, |
| object9.hashCode, |
| object10.hashCode, |
| object11.hashCode, |
| object12.hashCode, |
| object13.hashCode, |
| object14.hashCode, |
| object15.hashCode, |
| object16.hashCode, |
| object17.hashCode, |
| object18.hashCode, |
| object19.hashCode, |
| object20.hashCode, |
| _hashSeed); |
| } |
| |
| /// Creates a combined hash code for a sequence of objects. |
| /// |
| /// The hash code is computed for elements in [objects], |
| /// even if they are `null`, |
| /// by numerically combining the [Object.hashCode] of each element |
| /// in iteration order. |
| /// |
| /// The result of `hashAll([o])` is not `o.hashCode`. |
| /// |
| /// Example: |
| /// ```dart |
| /// class SomeObject { |
| /// final List<String> path; |
| /// SomeObject(this.path); |
| /// bool operator=(Object other) { |
| /// if (other is SomeObject) { |
| /// if (path.length != other.path.length) return false; |
| /// for (int i = 0; i < path.length; i++) { |
| /// if (path[i] != other.path[i]) return false; |
| /// } |
| /// return true; |
| /// } |
| /// return false; |
| /// } |
| /// |
| /// int get hashCode => Object.hashAll(path); |
| /// } |
| /// ``` |
| /// |
| /// The computed value will be be consistent when the function is called |
| /// again with objects that have the same hash codes in the same order |
| /// during an execution of a single program. |
| /// |
| /// The hash value generated by this function is *not* guranteed to be stable |
| /// over different runs of the same program, |
| /// or between code run in different isolates of the same program. |
| /// The exact algorithm used may differ between different platforms, |
| /// or between different versions of the platform libraries, |
| /// and it may depend on values that change on each program execution. |
| @Since("2.14") |
| static int hashAll(Iterable<Object?> objects) { |
| int hash = _hashSeed; |
| for (var object in objects) { |
| hash = SystemHash.combine(hash, object.hashCode); |
| } |
| return SystemHash.finish(hash); |
| } |
| |
| /// Creates a combined hash code for a collection of objects. |
| /// |
| /// The hash code is computed for elements in [objects], |
| /// even if they are `null`, |
| /// by numerically combining the [Object.hashCode] of each element |
| /// in an order independent way. |
| /// |
| /// The result of `unorderedHashAll({o})` is not `o.hashCode`. |
| /// |
| /// Example: |
| /// ```dart |
| /// bool setEquals<T>(Set<T> set1, Set<T> set2) { |
| /// var hashCode1 = Object.unorderedHashAll(set1); |
| /// var hashCode2 = Object.unorderedHashAll(set2); |
| /// if (hashCode1 != hashCode2) return false; |
| /// // Compare elements ... |
| /// } |
| /// ``` |
| /// |
| /// The computed value will be be consistent when the function is called |
| /// again with objects that have the same hash codes |
| /// during an execution of a single program, |
| /// even if the objects are not necessarily in the same order, |
| /// |
| /// The hash value generated by this function is *not* guranteed to be stable |
| /// over different runs of the same program. |
| /// The exact algorithm used may differ between different platforms, |
| /// or between different versions of the platform libraries, |
| /// and it may depend on values that change per program run |
| @Since("2.14") |
| static int hashAllUnordered(Iterable<Object?> objects) { |
| int sum = 0; |
| int count = 0; |
| const int mask = 0x3FFFFFFF; |
| for (var object in objects) { |
| int objectHash = SystemHash.smear(object.hashCode); |
| sum = (sum + objectHash) & mask; |
| count += 1; |
| } |
| return SystemHash.hash2(sum, count); |
| } |
| } |
| |
| // A per-isolate seed for hash code computations. |
| final int _hashSeed = identityHashCode(Object); |