* Rename misleading Instance::Equals to CanonicalizeEquals and document it.

* Keep 'Equals' alias for String and Integer.
* Add Instance::OperatorEquals that calls or mimics Object.operator==.

This is partly in preparation for internalizing HashMap/Set.

R=hausner@google.com, rmacnak@google.com

Review URL: https://codereview.chromium.org//274333002

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@36066 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
koda@google.com
2014-05-12 20:53:23 +00:00
parent a08555d604
commit da7bf22b7f
7 changed files with 118 additions and 35 deletions
+1 -1
View File
@@ -19,7 +19,7 @@ void FUNCTION_NAME(Unhandled_equals)(Dart_NativeArguments args) {
NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
const Instance& expected = Instance::CheckedHandle(arguments->NativeArgAt(0));
const Instance& actual = Instance::CheckedHandle(arguments->NativeArgAt(1));
if (!expected.Equals(actual)) {
if (!expected.CanonicalizeEquals(actual)) {
OS::Print("expected: '%s' actual: '%s'\n",
expected.ToCString(), actual.ToCString());
FATAL("Unhandled_equals fails.\n");
+31 -11
View File
@@ -12733,7 +12733,7 @@ RawObject* Instance::Evaluate(const String& expr,
bool Instance::Equals(const Instance& other) const {
bool Instance::CanonicalizeEquals(const Instance& other) const {
if (this->raw() == other.raw()) {
return true; // "===".
}
@@ -12844,7 +12844,7 @@ RawInstance* Instance::CheckAndCanonicalize(const char** error_str) const {
if (result.IsNull()) {
break;
}
if (this->Equals(result)) {
if (this->CanonicalizeEquals(result)) {
return result.raw();
}
index++;
@@ -12950,13 +12950,22 @@ bool Instance::IsInstanceOf(const AbstractType& other,
}
bool Instance::OperatorEquals(const Instance& other) const {
// TODO(koda): Optimize for all builtin classes and all classes
// that do not override operator==.
const Object& result =
Object::Handle(DartLibraryCalls::Equals(*this, other));
return result.raw() == Object::bool_true().raw();
}
bool Instance::IsIdenticalTo(const Instance& other) const {
if (raw() == other.raw()) return true;
if (IsInteger() && other.IsInteger()) {
return Equals(other);
return Integer::Cast(*this).Equals(other);
}
if (IsDouble() && other.IsDouble()) {
if (Equals(other)) return true;
if (Double::Cast(*this).CanonicalizeEquals(other)) return true;
// Check for NaN.
const Double& a_double = Double::Cast(*this);
const Double& b_double = Double::Cast(other);
@@ -15482,7 +15491,7 @@ void Double::set_value(double value) const {
}
bool Double::EqualsToDouble(double value) const {
bool Double::BitwiseEqualsToDouble(double value) const {
intptr_t value_offset = Double::value_offset();
void* this_addr = reinterpret_cast<void*>(
reinterpret_cast<uword>(this->raw_ptr()) + value_offset);
@@ -15491,14 +15500,25 @@ bool Double::EqualsToDouble(double value) const {
}
bool Double::Equals(const Instance& other) const {
bool Double::OperatorEquals(const Instance& other) const {
if (this->IsNull() || other.IsNull()) {
return (this->IsNull() && other.IsNull());
}
if (!other.IsDouble()) {
return false;
}
return this->value() == Double::Cast(other).value();
}
bool Double::CanonicalizeEquals(const Instance& other) const {
if (this->raw() == other.raw()) {
return true; // "===".
}
if (other.IsNull() || !other.IsDouble()) {
return false;
}
return EqualsToDouble(Double::Cast(other).value());
return BitwiseEqualsToDouble(Double::Cast(other).value());
}
@@ -15540,7 +15560,7 @@ RawDouble* Double::NewCanonical(double value) {
if (canonical_value.IsNull()) {
break;
}
if (canonical_value.EqualsToDouble(value)) {
if (canonical_value.BitwiseEqualsToDouble(value)) {
return canonical_value.raw();
}
index++;
@@ -17441,7 +17461,7 @@ void Bool::PrintJSONImpl(JSONStream* stream, bool ref) const {
}
bool Array::Equals(const Instance& other) const {
bool Array::CanonicalizeEquals(const Instance& other) const {
if (this->raw() == other.raw()) {
// Both handles point to the same raw instance.
return true;
@@ -17681,7 +17701,7 @@ RawObject* GrowableObjectArray::RemoveLast() const {
}
bool GrowableObjectArray::Equals(const Instance& other) const {
bool GrowableObjectArray::CanonicalizeEquals(const Instance& other) const {
// If both handles point to the same raw instance they are equal.
if (this->raw() == other.raw()) {
return true;
@@ -18591,7 +18611,7 @@ const char* JSRegExp::Flags() const {
}
bool JSRegExp::Equals(const Instance& other) const {
bool JSRegExp::CanonicalizeEquals(const Instance& other) const {
if (this->raw() == other.raw()) {
return true; // "===".
}
+37 -10
View File
@@ -4136,7 +4136,17 @@ class UnwindError : public Error {
// in Dart source code.
class Instance : public Object {
public:
virtual bool Equals(const Instance& other) const;
// Equality and identity testing.
// 1. OperatorEquals: true iff 'this == other' is true in Dart code.
// 2. IsIdenticalTo: true iff 'identical(this, other)' is true in Dart code.
// 3. CanonicalizeEquals: used to canonicalize compile-time constants, e.g.,
// using bitwise equality of fields and list elements.
// Subclasses where 1 and 3 coincide may also define a plain Equals, e.g.,
// String and Integer.
virtual bool OperatorEquals(const Instance& other) const;
bool IsIdenticalTo(const Instance& other) const;
virtual bool CanonicalizeEquals(const Instance& other) const;
// Returns Instance::null() if instance cannot be canonicalized.
// Any non-canonical number of string will be canonicalized here.
// An instance cannot be canonicalized if it still contains non-canonical
@@ -4166,10 +4176,6 @@ class Instance : public Object {
const TypeArguments& type_instantiator,
Error* bound_error) const;
// Check whether this instance is identical to the argument according to the
// specification of dare:core's identical().
bool IsIdenticalTo(const Instance& other) const;
bool IsValidNativeIndex(int index) const {
return ((index >= 0) && (index < clazz()->ptr()->num_native_fields_));
}
@@ -4314,6 +4320,9 @@ class AbstractType : public Instance {
virtual RawTypeArguments* arguments() const;
virtual intptr_t token_pos() const;
virtual bool IsInstantiated(GrowableObjectArray* trail = NULL) const;
virtual bool CanonicalizeEquals(const Instance& other) const {
return Equals(other);
}
virtual bool Equals(const Instance& other) const {
return IsEquivalent(other);
}
@@ -4880,6 +4889,17 @@ class Integer : public Number {
Heap::Space space = Heap::kNew,
const bool silent = false);
virtual bool OperatorEquals(const Instance& other) const {
return Equals(other);
}
virtual bool CanonicalizeEquals(const Instance& other) const {
return Equals(other);
}
virtual bool Equals(const Instance& other) const {
UNREACHABLE();
return false;
}
// Integer is an abstract class.
virtual bool IsZero() const {
UNREACHABLE();
@@ -5144,8 +5164,9 @@ class Double : public Number {
return raw_ptr()->value_;
}
bool EqualsToDouble(double value) const;
virtual bool Equals(const Instance& other) const;
bool BitwiseEqualsToDouble(double value) const;
virtual bool OperatorEquals(const Instance& other) const;
virtual bool CanonicalizeEquals(const Instance& other) const;
static RawDouble* New(double d, Heap::Space space = Heap::kNew);
@@ -5265,6 +5286,12 @@ class String : public Instance {
// Compares to an array of UTF-32 encoded characters.
bool Equals(const int32_t* characters, intptr_t len) const;
virtual bool OperatorEquals(const Instance& other) const {
return Equals(other);
}
virtual bool CanonicalizeEquals(const Instance& other) const {
return Equals(other);
}
virtual bool Equals(const Instance& other) const;
intptr_t CompareTo(const String& other) const;
@@ -5895,7 +5922,7 @@ class Array : public Instance {
StorePointer(&raw_ptr()->type_arguments_, value.raw());
}
virtual bool Equals(const Instance& other) const;
virtual bool CanonicalizeEquals(const Instance& other) const;
static const intptr_t kBytesPerElement = kWordSize;
static const intptr_t kMaxElements = kSmiMax / kBytesPerElement;
@@ -6055,7 +6082,7 @@ class GrowableObjectArray : public Instance {
StorePointer(&raw_ptr()->type_arguments_, value.raw());
}
virtual bool Equals(const Instance& other) const;
virtual bool CanonicalizeEquals(const Instance& other) const;
virtual RawInstance* CheckAndCanonicalize(const char** error_str) const {
UNREACHABLE();
@@ -6766,7 +6793,7 @@ class JSRegExp : public Instance {
static RawJSRegExp* FromDataStartAddress(void* data);
const char* Flags() const;
virtual bool Equals(const Instance& other) const;
virtual bool CanonicalizeEquals(const Instance& other) const;
static const intptr_t kBytesPerElement = 1;
static const intptr_t kMaxElements = kSmiMax / kBytesPerElement;
+44 -8
View File
@@ -516,11 +516,18 @@ TEST_CASE(Double) {
const double dbl_const = 2.0;
const Double& dbl1 = Double::Handle(Double::New(dbl_const));
const Double& dbl2 = Double::Handle(Double::New(dbl_const));
EXPECT(dbl1.Equals(dbl2));
EXPECT(dbl1.OperatorEquals(dbl2));
EXPECT(dbl1.IsIdenticalTo(dbl2));
EXPECT(dbl1.CanonicalizeEquals(dbl2));
const Double& dbl3 = Double::Handle(Double::New(3.3));
EXPECT(!dbl1.Equals(dbl3));
EXPECT(!dbl1.Equals(Smi::Handle(Smi::New(3))));
EXPECT(!dbl1.Equals(Double::Handle()));
EXPECT(!dbl1.OperatorEquals(dbl3));
EXPECT(!dbl1.OperatorEquals(Smi::Handle(Smi::New(3))));
EXPECT(!dbl1.OperatorEquals(Double::Handle()));
const Double& nan0 = Double::Handle(Double::New(NAN));
EXPECT(nan0.IsIdenticalTo(nan0));
EXPECT(nan0.CanonicalizeEquals(nan0));
EXPECT(!nan0.OperatorEquals(nan0));
// TODO(18738): Test bitwise different NaNs after agreement on spec.
}
{
const String& dbl_str0 = String::Handle(String::New("bla"));
@@ -1838,16 +1845,16 @@ TEST_CASE(Array) {
other_array.SetAt(0, array);
other_array.SetAt(2, array);
EXPECT(array.Equals(array));
EXPECT(array.Equals(other_array));
EXPECT(array.CanonicalizeEquals(array));
EXPECT(array.CanonicalizeEquals(other_array));
other_array.SetAt(1, other_array);
EXPECT(!array.Equals(other_array));
EXPECT(!array.CanonicalizeEquals(other_array));
other_array = Array::New(kArrayLen - 1);
other_array.SetAt(0, array);
other_array.SetAt(2, array);
EXPECT(!array.Equals(other_array));
EXPECT(!array.CanonicalizeEquals(other_array));
EXPECT_EQ(0, Object::empty_array().Length());
@@ -4014,4 +4021,33 @@ TEST_CASE(PrintJSON) {
heap->IterateObjects(&verifier);
}
TEST_CASE(InstanceEquality) {
// Test that Instance::OperatorEquals can call a user-defined operator==.
const char* kScript =
"class A {\n"
" bool operator==(A other) { return true; }\n"
"}\n"
"main() {\n"
" A a = new A();\n"
"}";
Dart_Handle h_lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(h_lib);
Library& lib = Library::Handle();
lib ^= Api::UnwrapHandle(h_lib);
EXPECT(!lib.IsNull());
Dart_Handle result = Dart_Invoke(h_lib, NewString("main"), 0, NULL);
EXPECT_VALID(result);
const Class& clazz = Class::Handle(GetClass(lib, "A"));
EXPECT(!clazz.IsNull());
const Instance& a0 = Instance::Handle(Instance::New(clazz));
const Instance& a1 = Instance::Handle(Instance::New(clazz));
EXPECT(a0.raw() != a1.raw());
EXPECT(a0.OperatorEquals(a0));
EXPECT(a0.OperatorEquals(a1));
EXPECT(a0.IsIdenticalTo(a0));
EXPECT(!a0.IsIdenticalTo(a1));
}
} // namespace dart
+2 -2
View File
@@ -572,7 +572,7 @@ TEST_CASE(SerializeArray) {
Snapshot::kMessage, Isolate::Current());
Array& serialized_array = Array::Handle();
serialized_array ^= reader.ReadObject();
EXPECT(array.Equals(serialized_array));
EXPECT(array.CanonicalizeEquals(serialized_array));
// Read object back from the snapshot into a C structure.
ApiNativeScope scope;
@@ -657,7 +657,7 @@ TEST_CASE(SerializeEmptyArray) {
Snapshot::kMessage, Isolate::Current());
Array& serialized_array = Array::Handle();
serialized_array ^= reader.ReadObject();
EXPECT(array.Equals(serialized_array));
EXPECT(array.CanonicalizeEquals(serialized_array));
// Read object back from the snapshot into a C structure.
ApiNativeScope scope;
+1 -1
View File
@@ -42,7 +42,7 @@ void FUNCTION_NAME(StackFrame_equals)(Dart_NativeArguments args) {
NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
const Instance& expected = Instance::CheckedHandle(arguments->NativeArgAt(0));
const Instance& actual = Instance::CheckedHandle(arguments->NativeArgAt(1));
if (!expected.Equals(actual)) {
if (!expected.OperatorEquals(actual)) {
OS::Print("expected: '%s' actual: '%s'\n",
expected.ToCString(), actual.ToCString());
FATAL("Expect_equals fails.\n");
+2 -2
View File
@@ -90,7 +90,7 @@
EXPECT(!result.IsError()); \
Instance& actual = Instance::Handle(); \
actual ^= result.raw(); \
EXPECT(actual.Equals(Instance::Handle(expected))); \
EXPECT(actual.CanonicalizeEquals(Instance::Handle(expected))); \
}
@@ -128,7 +128,7 @@
EXPECT(!result.IsError()); \
Instance& actual = Instance::Handle(); \
actual ^= result.raw(); \
EXPECT(actual.Equals(Instance::Handle(expected))); \
EXPECT(actual.CanonicalizeEquals(Instance::Handle(expected))); \
}