[consider merging] tl::Variant now considers byte arrays and strings equivalent for sloppy compare. This is important for Ruby string property keys as they are often kept as byte arrays when not UTF-8 encoded.

This commit is contained in:
Matthias Koefferlein 2025-07-27 22:15:52 +02:00
parent ede15ffcc0
commit 5b3ce9ff30
4 changed files with 98 additions and 41 deletions

View File

View File

@ -1078,6 +1078,18 @@ is_integer_type (Variant::type type)
}
}
inline bool
is_string_type (Variant::type type)
{
switch (type) {
case Variant::t_stdstring:
case Variant::t_string:
return true;
default:
return false;
}
}
/**
* @brief normalized_type
*/
@ -1126,25 +1138,26 @@ normalized_type (Variant::type type)
}
}
inline std::pair<bool, Variant::type>
normalized_type (Variant::type type1, Variant::type type2)
inline std::pair<Variant::type, Variant::type>
normalized_types (Variant::type type1, Variant::type type2)
{
type1 = normalized_type (type1);
type2 = normalized_type (type2);
if (type1 == type2) {
return std::make_pair (true, type1);
if (is_integer_type (type1)) {
type1 = Variant::t_double;
}
if (is_integer_type (type2)) {
type2 = Variant::t_double;
}
if (type1 == Variant::t_double && is_integer_type (type2)) {
// use double as common representation
return std::make_pair (true, Variant::t_double);
} else if (type2 == Variant::t_double && is_integer_type (type1)) {
// use double as common representation
return std::make_pair (true, Variant::t_double);
} else {
return std::make_pair (type1 == type2, type1);
if (is_string_type (type1) && type2 == Variant::t_bytearray) {
type1 = Variant::t_bytearray;
} else if (is_string_type (type2) && type1 == Variant::t_bytearray) {
type2 = Variant::t_bytearray;
}
return std::make_pair (type1, type2);
}
/**
@ -1226,8 +1239,11 @@ Variant::equal_core (const tl::Variant &d, type t) const
} else if (t == t_string) {
return strcmp (to_string (), d.to_string ()) == 0;
} else if (t == t_bytearray) {
// TODO: can't compare std::vector<char> with QByteArray currently
return *m_var.m_bytearray == *d.m_var.m_bytearray;
if (m_type == t_bytearray && d.m_type == t_bytearray) {
return *m_var.m_bytearray == *d.m_var.m_bytearray;
} else {
return to_bytearray () == d.to_bytearray ();
}
#if defined(HAVE_QT)
} else if (t == t_qstring) {
return *m_var.m_qstring == *d.m_var.m_qstring;
@ -1275,8 +1291,11 @@ Variant::less_core (const tl::Variant &d, type t) const
} else if (t == t_string) {
return strcmp (to_string (), d.to_string ()) < 0;
} else if (t == t_bytearray) {
// TODO: can't compare std::vector<char> with QByteArray currently
return *m_var.m_bytearray < *d.m_var.m_bytearray;
if (m_type == t_bytearray && d.m_type == t_bytearray) {
return *m_var.m_bytearray < *d.m_var.m_bytearray;
} else {
return to_bytearray () < d.to_bytearray ();
}
#if defined(HAVE_QT)
} else if (t == t_qstring) {
return *m_var.m_qstring < *d.m_var.m_qstring;
@ -1309,40 +1328,22 @@ Variant::less_core (const tl::Variant &d, type t) const
bool
Variant::operator== (const tl::Variant &d) const
{
type type1 = normalized_type (m_type);
type type2 = normalized_type (d.m_type);
if (is_integer_type (type1)) {
type1 = Variant::t_double;
}
if (is_integer_type (type2)) {
type2 = Variant::t_double;
}
if (type1 != type2) {
auto tt = normalized_types (m_type, d.m_type);
if (tt.first != tt.second) {
return false;
} else {
return equal_core (d, type1);
return equal_core (d, tt.first);
}
}
bool
Variant::operator< (const tl::Variant &d) const
{
type type1 = normalized_type (m_type);
type type2 = normalized_type (d.m_type);
if (is_integer_type (type1)) {
type1 = Variant::t_double;
}
if (is_integer_type (type2)) {
type2 = Variant::t_double;
}
if (type1 != type2) {
return type1 < type2;
auto tt = normalized_types (m_type, d.m_type);
if (tt.first != tt.second) {
return tt.first < tt.second;
} else {
return less_core (d, type1);
return less_core (d, tt.first);
}
}

View File

@ -1435,4 +1435,60 @@ TEST(13)
EXPECT_EQ (vm[tl::Variant ("2")], 4);
}
// tl::Variant byte arrays vs. strings
TEST(14)
{
std::vector<char> ba1;
const char ba1_str[] = { 'A', 'B', 0, 'D' };
ba1.insert (ba1.end (), ba1_str, ba1_str + sizeof (ba1_str) / sizeof (ba1_str [0]));
std::vector<char> ba2;
const char ba2_str[] = { 'A', 'B', 'C', 'D' };
ba2.insert (ba2.end (), ba2_str, ba2_str + sizeof (ba2_str) / sizeof (ba2_str [0]));
tl::Variant ba1_var (ba1), ba2_var (ba2);
EXPECT_EQ (ba1_var.is_a_bytearray (), true);
EXPECT_EQ (ba1_var.to_string (), std::string ("AB"));
EXPECT_EQ (ba1_var.to_bytearray ().size (), size_t (4));
EXPECT_EQ (ba2_var.is_a_bytearray (), true);
EXPECT_EQ (ba2_var.to_string (), std::string ("ABCD"));
EXPECT_EQ (ba2_var.to_bytearray ().size (), size_t (4));
EXPECT_EQ (ba1_var == ba2_var, false);
EXPECT_EQ (ba1_var == ba1_var, true);
EXPECT_EQ (ba1_var < ba2_var, true);
EXPECT_EQ (ba2_var < ba1_var, false);
EXPECT_EQ (ba1_var != ba2_var, true);
EXPECT_EQ (ba1_var != ba1_var, false);
EXPECT_EQ (ba1_var == tl::Variant ("AB"), false);
EXPECT_EQ (ba1_var < tl::Variant ("AB"), false);
EXPECT_EQ (ba1_var < tl::Variant ("ABCD"), true);
EXPECT_EQ (tl::Variant ("AB") == ba1_var, false);
EXPECT_EQ (tl::Variant ("AB") < ba1_var, true);
EXPECT_EQ (tl::Variant ("ABCD") < ba1_var, false);
EXPECT_EQ (ba2_var == tl::Variant ("ABCD"), true);
EXPECT_EQ (ba2_var < tl::Variant ("ABCD"), false);
EXPECT_EQ (tl::Variant ("ABCD") == ba2_var, true);
EXPECT_EQ (tl::Variant ("ABCD") < ba2_var, false);
EXPECT_EQ (ba1_var.equal (ba2_var), false);
EXPECT_EQ (ba1_var.equal (ba1_var), true);
EXPECT_EQ (ba1_var.less (ba2_var), true);
EXPECT_EQ (ba2_var.less (ba1_var), false);
EXPECT_EQ (ba1_var.equal (tl::Variant ("AB")), false);
EXPECT_EQ (ba1_var.less (tl::Variant ("AB")), false);
EXPECT_EQ (ba1_var.less (tl::Variant ("ABCD")), false);
EXPECT_EQ (tl::Variant ("AB").equal (ba1_var), false);
EXPECT_EQ (tl::Variant ("AB").less (ba1_var), true);
EXPECT_EQ (tl::Variant ("ABCD").less (ba1_var), true);
EXPECT_EQ (ba2_var.equal (tl::Variant ("ABCD")), false);
EXPECT_EQ (ba2_var.less (tl::Variant ("ABCD")), false);
EXPECT_EQ (tl::Variant ("ABCD").equal (ba2_var), false);
EXPECT_EQ (tl::Variant ("ABCD").less (ba2_var), true);
}
}