1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-15 13:51:40 +00:00

Modify Dictionary::operator== to do real key/value comparison with recursive support (and add unittests)

This commit is contained in:
Emmanuel Leblond
2020-02-01 07:04:14 +01:00
parent 78f86ff515
commit f9ba2efe1e
15 changed files with 1031 additions and 100 deletions

View File

@@ -784,16 +784,11 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type
}
bool Variant::operator==(const Variant &p_variant) const {
if (type != p_variant.type) { //evaluation of operator== needs to be more strict
return false;
}
bool v;
Variant r;
evaluate(OP_EQUAL, *this, p_variant, r, v);
return r;
return hash_compare(p_variant);
}
bool Variant::operator!=(const Variant &p_variant) const {
// Don't use `!hash_compare(p_variant)` given it makes use of OP_EQUAL
if (type != p_variant.type) { //evaluation of operator== needs to be more strict
return true;
}
@@ -1617,25 +1612,23 @@ struct _VariantStrPair {
};
Variant::operator String() const {
List<const void *> stack;
return stringify(stack);
return stringify(0);
}
template <class T>
String stringify_vector(const T &vec, List<const void *> &stack) {
String stringify_vector(const T &vec, int recursion_count) {
String str("[");
for (int i = 0; i < vec.size(); i++) {
if (i > 0) {
str += ", ";
}
str = str + Variant(vec[i]).stringify(stack);
str = str + Variant(vec[i]).stringify(recursion_count);
}
str += "]";
return str;
}
String Variant::stringify(List<const void *> &stack) const {
String Variant::stringify(int recursion_count) const {
switch (type) {
case NIL:
return "null";
@@ -1679,23 +1672,22 @@ String Variant::stringify(List<const void *> &stack) const {
return operator Color();
case DICTIONARY: {
const Dictionary &d = *reinterpret_cast<const Dictionary *>(_data._mem);
if (stack.find(d.id())) {
if (recursion_count > MAX_RECURSION) {
ERR_PRINT("Max recursion reached");
return "{...}";
}
stack.push_back(d.id());
//const String *K=nullptr;
String str("{");
List<Variant> keys;
d.get_key_list(&keys);
Vector<_VariantStrPair> pairs;
for (const Variant &E : keys) {
recursion_count++;
for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
_VariantStrPair sp;
sp.key = E.stringify(stack);
sp.value = d[E].stringify(stack);
sp.key = E->get().stringify(recursion_count);
sp.value = d[E->get()].stringify(recursion_count);
pairs.push_back(sp);
}
@@ -1710,46 +1702,43 @@ String Variant::stringify(List<const void *> &stack) const {
}
str += "}";
stack.erase(d.id());
return str;
} break;
case PACKED_VECTOR2_ARRAY: {
return stringify_vector(operator Vector<Vector2>(), stack);
return stringify_vector(operator Vector<Vector2>(), recursion_count);
} break;
case PACKED_VECTOR3_ARRAY: {
return stringify_vector(operator Vector<Vector3>(), stack);
return stringify_vector(operator Vector<Vector3>(), recursion_count);
} break;
case PACKED_COLOR_ARRAY: {
return stringify_vector(operator Vector<Color>(), stack);
return stringify_vector(operator Vector<Color>(), recursion_count);
} break;
case PACKED_STRING_ARRAY: {
return stringify_vector(operator Vector<String>(), stack);
return stringify_vector(operator Vector<String>(), recursion_count);
} break;
case PACKED_BYTE_ARRAY: {
return stringify_vector(operator Vector<uint8_t>(), stack);
return stringify_vector(operator Vector<uint8_t>(), recursion_count);
} break;
case PACKED_INT32_ARRAY: {
return stringify_vector(operator Vector<int32_t>(), stack);
return stringify_vector(operator Vector<int32_t>(), recursion_count);
} break;
case PACKED_INT64_ARRAY: {
return stringify_vector(operator Vector<int64_t>(), stack);
return stringify_vector(operator Vector<int64_t>(), recursion_count);
} break;
case PACKED_FLOAT32_ARRAY: {
return stringify_vector(operator Vector<float>(), stack);
return stringify_vector(operator Vector<float>(), recursion_count);
} break;
case PACKED_FLOAT64_ARRAY: {
return stringify_vector(operator Vector<double>(), stack);
return stringify_vector(operator Vector<double>(), recursion_count);
} break;
case ARRAY: {
Array arr = operator Array();
if (stack.find(arr.id())) {
if (recursion_count > MAX_RECURSION) {
ERR_PRINT("Max recursion reached");
return "[...]";
}
stack.push_back(arr.id());
String str = stringify_vector(arr, stack);
stack.erase(arr.id());
String str = stringify_vector(arr, recursion_count);
return str;
} break;
@@ -2768,6 +2757,10 @@ Variant::Variant(const Variant &p_variant) {
}
uint32_t Variant::hash() const {
return recursive_hash(0);
}
uint32_t Variant::recursive_hash(int recursion_count) const {
switch (type) {
case NIL: {
return 0;
@@ -2895,7 +2888,7 @@ uint32_t Variant::hash() const {
return reinterpret_cast<const NodePath *>(_data._mem)->hash();
} break;
case DICTIONARY: {
return reinterpret_cast<const Dictionary *>(_data._mem)->hash();
return reinterpret_cast<const Dictionary *>(_data._mem)->recursive_hash(recursion_count);
} break;
case CALLABLE: {
@@ -2909,7 +2902,7 @@ uint32_t Variant::hash() const {
} break;
case ARRAY: {
const Array &arr = *reinterpret_cast<const Array *>(_data._mem);
return arr.hash();
return arr.recursive_hash(recursion_count);
} break;
case PACKED_BYTE_ARRAY: {
@@ -3083,7 +3076,7 @@ uint32_t Variant::hash() const {
\
return true
bool Variant::hash_compare(const Variant &p_variant) const {
bool Variant::hash_compare(const Variant &p_variant, int recursion_count) const {
if (type != p_variant.type) {
return false;
}
@@ -3214,14 +3207,19 @@ bool Variant::hash_compare(const Variant &p_variant) const {
const Array &l = *(reinterpret_cast<const Array *>(_data._mem));
const Array &r = *(reinterpret_cast<const Array *>(p_variant._data._mem));
if (l.size() != r.size()) {
if (!l.recursive_equal(r, recursion_count + 1)) {
return false;
}
for (int i = 0; i < l.size(); ++i) {
if (!l[i].hash_compare(r[i])) {
return false;
}
return true;
} break;
case DICTIONARY: {
const Dictionary &l = *(reinterpret_cast<const Dictionary *>(_data._mem));
const Dictionary &r = *(reinterpret_cast<const Dictionary *>(p_variant._data._mem));
if (!l.recursive_equal(r, recursion_count + 1)) {
return false;
}
return true;