Skip to content

Commit 59b91a6

Browse files
authored
Merge pull request #483 from scratchcpp/rewrite_value_equality_operator
Fix #482: Rewrite Value::operator==()
2 parents 316efbe + 733c216 commit 59b91a6

File tree

2 files changed

+68
-51
lines changed

2 files changed

+68
-51
lines changed

include/scratchcpp/value.h

Lines changed: 63 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
#pragma once
44

55
#include <string>
6-
#include <variant>
76
#include <algorithm>
87
#include <limits>
98
#include <ctgmath>
9+
#include <cassert>
1010
#include <utf8.h>
1111

1212
#include "global.h"
@@ -548,63 +548,75 @@ class LIBSCRATCHCPP_EXPORT Value
548548
}
549549
}
550550

551+
double getNumber(bool *ok = nullptr) const
552+
{
553+
// Equivalent to JavaScript Number(), *ok == false means NaN
554+
if (ok)
555+
*ok = true;
556+
557+
switch (m_type) {
558+
case Type::Integer:
559+
return m_intValue;
560+
561+
case Type::Double:
562+
return m_doubleValue;
563+
564+
case Type::Bool:
565+
return m_boolValue;
566+
567+
case Type::String:
568+
return stringToDouble(m_stringValue, ok);
569+
570+
case Type::Infinity:
571+
return std::numeric_limits<double>::infinity();
572+
573+
case Type::NegativeInfinity:
574+
return -std::numeric_limits<double>::infinity();
575+
576+
case Type::NaN:
577+
if (ok)
578+
*ok = false;
579+
580+
return 0;
581+
582+
default:
583+
assert(false); // this should never happen
584+
if (ok)
585+
*ok = false;
586+
587+
return 0;
588+
}
589+
}
590+
551591
void initString(const char *str) { initString(std::string(str)); }
552592

553593
Type m_type;
554594

555595
friend bool operator==(const Value &v1, const Value &v2)
556596
{
557-
if (v1.m_type == v2.m_type) {
558-
auto type = v1.m_type;
559-
switch (type) {
560-
case Type::Integer:
561-
return v1.toLong() == v2.toLong();
562-
case Type::Double:
563-
return v1.toDouble() == v2.toDouble();
564-
case Type::Bool:
565-
return v1.toBool() == v2.toBool();
566-
case Type::String:
567-
return stringsEqual(v1.toUtf16(), v2.toUtf16());
568-
default:
569-
if ((static_cast<int>(v1.m_type) < 0) && (static_cast<int>(v2.m_type) < 0)) {
570-
return v1.m_type == v2.m_type;
571-
}
572-
}
573-
} else {
574-
if (v1.isString() || v2.isString()) {
575-
if (static_cast<int>(v1.m_type) < 0 || static_cast<int>(v2.m_type) < 0)
576-
return stringsEqual(v1.toUtf16(), v2.toUtf16());
577-
578-
long l1, l2;
579-
double d1, d2;
580-
int type1 = checkString(v1.toString(), &l1, &d1);
581-
int type2 = checkString(v2.toString(), &l2, &d2);
582-
583-
if (type1 == 1)
584-
d1 = l1;
585-
586-
if (type2 == 1)
587-
d2 = l2;
588-
589-
if (type1 > 0 && type2 > 0)
590-
return d1 == d2;
591-
else if (type2 > 0)
592-
return v1.toString() == doubleToString(d2);
593-
else if (type1 > 0)
594-
return doubleToString(d1) == v2.toString();
595-
else
596-
return stringsEqual(v1.toUtf16(), v2.toUtf16());
597-
} else if (v1.isNumber() || v2.isNumber()) {
598-
if (static_cast<int>(v1.m_type) < 0 || static_cast<int>(v2.m_type) < 0)
599-
return false;
600-
else
601-
return v1.toDouble() == v2.toDouble();
602-
} else if (v1.isBool() || v2.isBool())
603-
return ((v1.m_type != Type::NaN && v2.m_type != Type::NaN) && (v1.toBool() == v2.toBool()));
604-
else
605-
return false;
597+
// https://github.com/scratchfoundation/scratch-vm/blob/112989da0e7306eeb405a5c52616e41c2164af24/src/util/cast.js#L121-L150
598+
bool ok;
599+
double n1 = v1.getNumber(&ok);
600+
double n2;
601+
602+
if (ok)
603+
n2 = v2.getNumber(&ok);
604+
605+
if (!ok) {
606+
// At least one argument can't be converted to a number
607+
// Scratch compares strings as case insensitive
608+
return stringsEqual(v1.toUtf16(), v2.toUtf16());
606609
}
607-
return false;
610+
611+
// Handle the special case of Infinity
612+
if ((static_cast<int>(v1.m_type) < 0) && (static_cast<int>(v2.m_type) < 0)) {
613+
assert(v1.m_type != Type::NaN);
614+
assert(v2.m_type != Type::NaN);
615+
return v1.m_type == v2.m_type;
616+
}
617+
618+
// Compare as numbers
619+
return n1 == n2;
608620
}
609621

610622
friend bool operator!=(const Value &v1, const Value &v2) { return !(v1 == v2); }

test/scratch_classes/value_test.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1809,6 +1809,8 @@ TEST(ValueTest, EqualityOperators)
18091809
Value v5 = " 5.25 ";
18101810
Value v6 = " 5.25 ";
18111811
Value v7 = "5.26";
1812+
Value v8 = 5;
1813+
Value v9 = "5 ";
18121814

18131815
ASSERT_TRUE(v1 == v2);
18141816
ASSERT_FALSE(v1 != v2);
@@ -1842,6 +1844,9 @@ TEST(ValueTest, EqualityOperators)
18421844

18431845
ASSERT_FALSE(v6 == v7);
18441846
ASSERT_TRUE(v6 != v7);
1847+
1848+
ASSERT_TRUE(v8 == v9);
1849+
ASSERT_FALSE(v8 != v9);
18451850
}
18461851

18471852
{

0 commit comments

Comments
 (0)