Merge pull request #97542 from AThousandShips/dict_sort_fix

[Core] Fix sorting of `Dictionary` keys
This commit is contained in:
Thaddeus Crews 2024-10-21 16:39:05 -05:00
commit 5fb22327ee
No known key found for this signature in database
GPG Key ID: 62181B86FE9E5D84
6 changed files with 28 additions and 8 deletions

View File

@ -121,7 +121,7 @@ String JSON::_stringify(const Variant &p_var, const String &p_indent, int p_cur_
d.get_key_list(&keys); d.get_key_list(&keys);
if (p_sort_keys) { if (p_sort_keys) {
keys.sort(); keys.sort_custom<StringLikeVariantOrder>();
} }
bool first_key = true; bool first_key = true;

View File

@ -854,6 +854,19 @@ struct StringLikeVariantComparator {
static bool compare(const Variant &p_lhs, const Variant &p_rhs); static bool compare(const Variant &p_lhs, const Variant &p_rhs);
}; };
struct StringLikeVariantOrder {
static _ALWAYS_INLINE_ bool compare(const Variant &p_lhs, const Variant &p_rhs) {
if (p_lhs.is_string() && p_rhs.is_string()) {
return p_lhs.operator String() < p_rhs.operator String();
}
return p_lhs < p_rhs;
}
_ALWAYS_INLINE_ bool operator()(const Variant &p_lhs, const Variant &p_rhs) const {
return compare(p_lhs, p_rhs);
}
};
Variant::ObjData &Variant::_get_obj() { Variant::ObjData &Variant::_get_obj() {
return *reinterpret_cast<ObjData *>(&_data._mem[0]); return *reinterpret_cast<ObjData *>(&_data._mem[0]);
} }

View File

@ -2245,7 +2245,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
} else { } else {
List<Variant> keys; List<Variant> keys;
dict.get_key_list(&keys); dict.get_key_list(&keys);
keys.sort(); keys.sort_custom<StringLikeVariantOrder>();
if (keys.is_empty()) { if (keys.is_empty()) {
// Avoid unnecessary line break. // Avoid unnecessary line break.

View File

@ -2128,12 +2128,11 @@ void VisualShaderEditor::_update_nodes() {
} }
} }
Array keys = added.keys(); List<Variant> keys;
keys.sort(); added.get_key_list(&keys);
keys.sort_custom<StringLikeVariantOrder>();
for (int i = 0; i < keys.size(); i++) {
const Variant &key = keys.get(i);
for (const Variant &key : keys) {
const Dictionary &value = (Dictionary)added[key]; const Dictionary &value = (Dictionary)added[key];
add_custom_type(value["name"], value["type"], value["script"], value["description"], value["return_icon_type"], value["category"], value["highend"]); add_custom_type(value["name"], value["type"], value["script"], value["description"], value["return_icon_type"], value["category"], value["highend"]);

View File

@ -217,7 +217,7 @@ String GDScriptDocGen::_docvalue_from_variant(const Variant &p_variant, int p_re
List<Variant> keys; List<Variant> keys;
dict.get_key_list(&keys); dict.get_key_list(&keys);
keys.sort(); keys.sort_custom<StringLikeVariantOrder>();
for (List<Variant>::Element *E = keys.front(); E; E = E->next()) { for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
if (E->prev()) { if (E->prev()) {

View File

@ -1806,6 +1806,14 @@ TEST_CASE("[Variant] Writer and parser dictionary") {
CHECK_MESSAGE(d_parsed == Variant(d), "Should parse back."); CHECK_MESSAGE(d_parsed == Variant(d), "Should parse back.");
} }
TEST_CASE("[Variant] Writer key sorting") {
Dictionary d = build_dictionary(StringName("C"), 3, "A", 1, StringName("B"), 2, "D", 4);
String d_str;
VariantWriter::write_to_string(d, d_str);
CHECK_EQ(d_str, "{\n\"A\": 1,\n&\"B\": 2,\n&\"C\": 3,\n\"D\": 4\n}");
}
TEST_CASE("[Variant] Writer recursive dictionary") { TEST_CASE("[Variant] Writer recursive dictionary") {
// There is no way to accurately represent a recursive dictionary, // There is no way to accurately represent a recursive dictionary,
// the only thing we can do is make sure the writer doesn't blow up // the only thing we can do is make sure the writer doesn't blow up