2
0
mirror of https://github.com/godotengine/godot.git synced 2025-04-25 01:48:08 +08:00

Merge pull request from YYF233333/dict_iter

Add const iteration support to `Dictionary`
This commit is contained in:
Thaddeus Crews 2025-03-13 08:57:23 -05:00
commit 22a7079afd
No known key found for this signature in database
GPG Key ID: 62181B86FE9E5D84
34 changed files with 131 additions and 179 deletions

@ -1555,11 +1555,8 @@ static void gdextension_placeholder_script_instance_update(GDExtensionScriptInst
properties_list.push_back(PropertyInfo::from_dict(d));
}
List<Variant> keys;
values.get_key_list(&keys);
for (const Variant &E : keys) {
values_map.insert(E, values[E]);
for (const KeyValue<Variant, Variant> &kv : values) {
values_map.insert(kv.key, kv.value);
}
placeholder->update(properties_list, values_map);

@ -922,12 +922,9 @@ Variant JSON::_from_native(const Variant &p_variant, bool p_full_objects, int p_
ERR_FAIL_COND_V_MSG(p_depth > Variant::MAX_RECURSION_DEPTH, ret, "Variant is too deep. Bailing.");
List<Variant> keys;
dict.get_key_list(&keys);
for (const Variant &key : keys) {
args.push_back(_from_native(key, p_full_objects, p_depth + 1));
args.push_back(_from_native(dict[key], p_full_objects, p_depth + 1));
for (const KeyValue<Variant, Variant> &kv : dict) {
args.push_back(_from_native(kv.key, p_full_objects, p_depth + 1));
args.push_back(_from_native(kv.value, p_full_objects, p_depth + 1));
}
return ret;

@ -1849,19 +1849,16 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
}
r_len += 4;
List<Variant> keys;
dict.get_key_list(&keys);
for (const Variant &key : keys) {
for (const KeyValue<Variant, Variant> &kv : dict) {
int len;
Error err = encode_variant(key, buf, len, p_full_objects, p_depth + 1);
Error err = encode_variant(kv.key, buf, len, p_full_objects, p_depth + 1);
ERR_FAIL_COND_V(err, err);
ERR_FAIL_COND_V(len % 4, ERR_BUG);
r_len += len;
if (buf) {
buf += len;
}
const Variant *value = dict.getptr(key);
const Variant *value = dict.getptr(kv.key);
ERR_FAIL_NULL_V(value, ERR_BUG);
err = encode_variant(*value, buf, len, p_full_objects, p_depth + 1);
ERR_FAIL_COND_V(err, err);

@ -268,14 +268,12 @@ uint32_t PackedDataContainer::_pack(const Variant &p_data, Vector<uint8_t> &tmpd
encode_uint32(TYPE_DICT, &tmpdata.write[pos + 0]);
encode_uint32(len, &tmpdata.write[pos + 4]);
List<Variant> keys;
d.get_key_list(&keys);
List<DictKey> sortk;
for (const Variant &key : keys) {
for (const KeyValue<Variant, Variant> &kv : d) {
DictKey dk;
dk.hash = key.hash();
dk.key = key;
dk.hash = kv.key.hash();
dk.key = kv.key;
sortk.push_back(dk);
}

@ -322,11 +322,9 @@ void Resource::_find_sub_resources(const Variant &p_variant, HashSet<Ref<Resourc
} break;
case Variant::DICTIONARY: {
Dictionary d = p_variant;
List<Variant> keys;
d.get_key_list(&keys);
for (const Variant &k : keys) {
_find_sub_resources(k, p_resources_found);
_find_sub_resources(d[k], p_resources_found);
for (const KeyValue<Variant, Variant> &kv : d) {
_find_sub_resources(kv.key, p_resources_found);
_find_sub_resources(kv.value, p_resources_found);
}
} break;
case Variant::OBJECT: {

@ -1876,12 +1876,9 @@ void ResourceFormatSaverBinaryInstance::write_variant(Ref<FileAccess> f, const V
Dictionary d = p_property;
f->store_32(uint32_t(d.size()));
List<Variant> keys;
d.get_key_list(&keys);
for (const Variant &E : keys) {
write_variant(f, E, resource_map, external_resources, string_map);
write_variant(f, d[E], resource_map, external_resources, string_map);
for (const KeyValue<Variant, Variant> &kv : d) {
write_variant(f, kv.key, resource_map, external_resources, string_map);
write_variant(f, kv.value, resource_map, external_resources, string_map);
}
} break;
@ -2086,12 +2083,9 @@ void ResourceFormatSaverBinaryInstance::_find_resources(const Variant &p_variant
Dictionary d = p_variant;
_find_resources(d.get_typed_key_script());
_find_resources(d.get_typed_value_script());
List<Variant> keys;
d.get_key_list(&keys);
for (const Variant &E : keys) {
_find_resources(E);
Variant v = d[E];
_find_resources(v);
for (const KeyValue<Variant, Variant> &kv : d) {
_find_resources(kv.key);
_find_resources(kv.value);
}
} break;
case Variant::NODE_PATH: {

@ -1339,10 +1339,8 @@ void ResourceLoader::load_translation_remaps() {
}
Dictionary remaps = GLOBAL_GET("internationalization/locale/translation_remaps");
List<Variant> keys;
remaps.get_key_list(&keys);
for (const Variant &E : keys) {
Array langs = remaps[E];
for (const KeyValue<Variant, Variant> &kv : remaps) {
Array langs = kv.value;
Vector<String> lang_remaps;
lang_remaps.resize(langs.size());
String *lang_remaps_ptrw = lang_remaps.ptrw();
@ -1350,7 +1348,7 @@ void ResourceLoader::load_translation_remaps() {
*lang_remaps_ptrw++ = lang;
}
translation_remaps[String(E)] = lang_remaps;
translation_remaps[String(kv.key)] = lang_remaps;
}
}

@ -1640,12 +1640,10 @@ void Object::_clear_internal_resource_paths(const Variant &p_var) {
} break;
case Variant::DICTIONARY: {
Dictionary d = p_var;
List<Variant> keys;
d.get_key_list(&keys);
for (const Variant &E : keys) {
_clear_internal_resource_paths(E);
_clear_internal_resource_paths(d[E]);
for (const KeyValue<Variant, Variant> &kv : d) {
_clear_internal_resource_paths(kv.key);
_clear_internal_resource_paths(kv.value);
}
} break;
default: {

@ -192,10 +192,8 @@ public:
virtual void get_constants(HashMap<StringName, Variant> *p_constants) override {
Dictionary constants;
GDVIRTUAL_CALL(_get_constants, constants);
List<Variant> keys;
constants.get_key_list(&keys);
for (const Variant &K : keys) {
p_constants->insert(K, constants[K]);
for (const KeyValue<Variant, Variant> &kv : constants) {
p_constants->insert(kv.key, kv.value);
}
}
GDVIRTUAL0RC_REQUIRED(TypedArray<StringName>, _get_members)

@ -67,10 +67,8 @@ Vector<String> Translation::get_translated_message_list() const {
}
void Translation::_set_messages(const Dictionary &p_messages) {
List<Variant> keys;
p_messages.get_key_list(&keys);
for (const Variant &E : keys) {
translation_map[E] = p_messages[E];
for (const KeyValue<Variant, Variant> &kv : p_messages) {
translation_map[kv.key] = kv.value;
}
}

@ -86,20 +86,16 @@ Dictionary TranslationPO::_get_messages() const {
void TranslationPO::_set_messages(const Dictionary &p_messages) {
// Construct translation_map from a Dictionary.
List<Variant> context_l;
p_messages.get_key_list(&context_l);
for (const Variant &ctx : context_l) {
const Dictionary &id_str_map = p_messages[ctx];
for (const KeyValue<Variant, Variant> &kv : p_messages) {
const Dictionary &id_str_map = kv.value;
HashMap<StringName, Vector<StringName>> temp_map;
List<Variant> id_l;
id_str_map.get_key_list(&id_l);
for (List<Variant>::Element *E2 = id_l.front(); E2; E2 = E2->next()) {
StringName id = E2->get();
temp_map[id] = id_str_map[id];
for (const KeyValue<Variant, Variant> &kv_id : id_str_map) {
StringName id = kv_id.key;
temp_map[id] = kv_id.value;
}
translation_map[ctx] = temp_map;
translation_map[kv.key] = temp_map;
}
}

@ -4024,11 +4024,9 @@ String String::format(const Variant &values, const String &placeholder) const {
}
} else if (values.get_type() == Variant::DICTIONARY) {
Dictionary d = values;
List<Variant> keys;
d.get_key_list(&keys);
for (const Variant &key : keys) {
new_string = new_string.replace(placeholder.replace("_", key), d[key]);
for (const KeyValue<Variant, Variant> &kv : d) {
new_string = new_string.replace(placeholder.replace("_", kv.key), kv.value);
}
} else if (values.get_type() == Variant::OBJECT) {
Object *obj = values.get_validated_object();

@ -49,6 +49,14 @@ struct DictionaryPrivate {
Variant *typed_fallback = nullptr; // Allows a typed dictionary to return dummy values when attempting an invalid access.
};
Dictionary::ConstIterator Dictionary::begin() const {
return _p->variant_map.begin();
}
Dictionary::ConstIterator Dictionary::end() const {
return _p->variant_map.end();
}
void Dictionary::get_key_list(List<Variant> *p_keys) const {
if (_p->variant_map.is_empty()) {
return;

@ -31,6 +31,7 @@
#pragma once
#include "core/string/ustring.h"
#include "core/templates/hash_map.h"
#include "core/templates/list.h"
#include "core/templates/pair.h"
#include "core/variant/array.h"
@ -39,6 +40,8 @@ class Variant;
struct ContainerType;
struct DictionaryPrivate;
struct StringLikeVariantComparator;
struct VariantHasher;
class Dictionary {
mutable DictionaryPrivate *_p;
@ -47,6 +50,11 @@ class Dictionary {
void _unref() const;
public:
using ConstIterator = HashMap<Variant, Variant, VariantHasher, StringLikeVariantComparator>::ConstIterator;
ConstIterator begin() const;
ConstIterator end() const;
void get_key_list(List<Variant> *p_keys) const;
Variant get_key_at_index(int p_index) const;
Variant get_value_at_index(int p_index) const;

@ -1654,15 +1654,13 @@ String Variant::stringify(int recursion_count) const {
// Add leading and trailing space to Dictionary printing. This distinguishes it
// from array printing on fonts that have similar-looking {} and [] characters.
String str("{ ");
List<Variant> keys;
d.get_key_list(&keys);
Vector<_VariantStrPair> pairs;
for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
for (const KeyValue<Variant, Variant> &kv : d) {
_VariantStrPair sp;
sp.key = stringify_variant_clean(E->get(), recursion_count);
sp.value = stringify_variant_clean(d[E->get()], recursion_count);
sp.key = stringify_variant_clean(kv.key, recursion_count);
sp.value = stringify_variant_clean(kv.value, recursion_count);
pairs.push_back(sp);
}

@ -1286,11 +1286,9 @@ Variant Variant::get(const Variant &p_index, bool *r_valid, VariantGetError *err
void Variant::get_property_list(List<PropertyInfo> *p_list) const {
if (type == DICTIONARY) {
const Dictionary *dic = reinterpret_cast<const Dictionary *>(_data._mem);
List<Variant> keys;
dic->get_key_list(&keys);
for (const Variant &E : keys) {
if (E.is_string()) {
p_list->push_back(PropertyInfo(dic->get_valid(E).get_type(), E));
for (const KeyValue<Variant, Variant> &kv : *dic) {
if (kv.key.is_string()) {
p_list->push_back(PropertyInfo(dic->get_valid(kv.key).get_type(), kv.key));
}
}
} else if (type == OBJECT) {

@ -297,11 +297,9 @@ Error EditorBuildProfile::load_from_file(const String &p_path) {
if (data.has("disabled_build_options")) {
Dictionary disabled_build_options_arr = data["disabled_build_options"];
List<Variant> keys;
disabled_build_options_arr.get_key_list(&keys);
for (const Variant &K : keys) {
String key = K;
for (const KeyValue<Variant, Variant> &kv : disabled_build_options_arr) {
String key = kv.key;
for (int i = 0; i < BUILD_OPTION_MAX; i++) {
String f = build_option_identifiers[i];

@ -336,12 +336,8 @@ void EditorData::set_editor_plugin_states(const Dictionary &p_states) {
return;
}
List<Variant> keys;
p_states.get_key_list(&keys);
List<Variant>::Element *E = keys.front();
for (; E; E = E->next()) {
String name = E->get();
for (const KeyValue<Variant, Variant> &kv : p_states) {
String name = kv.key;
int idx = -1;
for (int i = 0; i < editor_plugins.size(); i++) {
if (editor_plugins[i]->get_plugin_name() == name) {
@ -353,7 +349,7 @@ void EditorData::set_editor_plugin_states(const Dictionary &p_states) {
if (idx == -1) {
continue;
}
editor_plugins[idx]->set_state(p_states[name]);
editor_plugins[idx]->set_state(kv.value);
}
}
@ -1071,12 +1067,10 @@ void EditorData::script_class_load_icon_paths() {
#ifndef DISABLE_DEPRECATED
if (ProjectSettings::get_singleton()->has_setting("_global_script_class_icons")) {
Dictionary d = GLOBAL_GET("_global_script_class_icons");
List<Variant> keys;
d.get_key_list(&keys);
for (const Variant &E : keys) {
String name = E.operator String();
_script_class_icon_paths[name] = d[name];
for (const KeyValue<Variant, Variant> &kv : d) {
String name = kv.key.operator String();
_script_class_icon_paths[name] = kv.value;
String path = ScriptServer::get_global_class_path(name);
script_class_set_name(path, name);

@ -2824,11 +2824,9 @@ Error EditorFileSystem::_reimport_file(const String &p_file, const HashMap<Strin
if (load_default && ProjectSettings::get_singleton()->has_setting("importer_defaults/" + importer->get_importer_name())) {
//use defaults if exist
Dictionary d = GLOBAL_GET("importer_defaults/" + importer->get_importer_name());
List<Variant> v;
d.get_key_list(&v);
for (const Variant &E : v) {
params[E] = d[E];
for (const KeyValue<Variant, Variant> &kv : d) {
params[kv.key] = kv.value;
}
}

@ -1593,10 +1593,8 @@ void EditorNode::_save_editor_states(const String &p_file, int p_idx) {
md = editor_data.get_scene_editor_states(p_idx);
}
List<Variant> keys;
md.get_key_list(&keys);
for (const Variant &E : keys) {
cf->set_value("editor_states", E, md[E]);
for (const KeyValue<Variant, Variant> &kv : md) {
cf->set_value("editor_states", kv.key, kv.value);
}
// Save the currently selected nodes.
@ -1670,11 +1668,8 @@ bool EditorNode::_find_and_save_edited_subresources(Object *obj, HashMap<Ref<Res
} break;
case Variant::DICTIONARY: {
Dictionary d = obj->get(E.name);
List<Variant> keys;
d.get_key_list(&keys);
for (const Variant &F : keys) {
Variant v = d[F];
Ref<Resource> res = v;
for (const KeyValue<Variant, Variant> &kv : d) {
Ref<Resource> res = kv.value;
if (_find_and_save_resource(res, processed, flags)) {
ret_changed = true;
}

@ -3036,15 +3036,14 @@ static bool _find_recursive_resources(const Variant &v, HashSet<Resource *> &res
} break;
case Variant::DICTIONARY: {
Dictionary d = v;
List<Variant> keys;
d.get_key_list(&keys);
for (const Variant &k : keys) {
for (const KeyValue<Variant, Variant> &kv : d) {
const Variant &k = kv.key;
const Variant &v2 = kv.value;
if (k.get_type() == Variant::ARRAY || k.get_type() == Variant::DICTIONARY || k.get_type() == Variant::OBJECT) {
if (_find_recursive_resources(k, resources_found)) {
return true;
}
}
Variant v2 = d[k];
if (v2.get_type() == Variant::ARRAY || v2.get_type() == Variant::DICTIONARY || v2.get_type() == Variant::OBJECT) {
if (_find_recursive_resources(v2, resources_found)) {
return true;

@ -205,10 +205,8 @@ bool EditorImportPlugin::can_import_threaded() const {
Error EditorImportPlugin::_append_import_external_resource(const String &p_file, const Dictionary &p_custom_options, const String &p_custom_importer, Variant p_generator_parameters) {
HashMap<StringName, Variant> options;
List<Variant> keys;
p_custom_options.get_key_list(&keys);
for (const Variant &K : keys) {
options.insert(K, p_custom_options[K]);
for (const KeyValue<Variant, Variant> &kv : p_custom_options) {
options.insert(kv.key, kv.value);
}
return append_import_external_resource(p_file, options, p_custom_importer, p_generator_parameters);
}

@ -297,13 +297,11 @@ void ImportDock::set_edit_multiple_paths(const Vector<String> &p_paths) {
if (value_frequency.has(E.option.name)) {
Dictionary d = value_frequency[E.option.name];
int freq = 0;
List<Variant> v;
d.get_key_list(&v);
Variant value;
for (const Variant &F : v) {
int f = d[F];
for (const KeyValue<Variant, Variant> &kv : d) {
int f = kv.value;
if (f > freq) {
value = F;
value = kv.key;
}
}
@ -456,16 +454,14 @@ void ImportDock::_preset_selected(int p_idx) {
ERR_FAIL_COND(!ProjectSettings::get_singleton()->has_setting(setting_name));
Dictionary import_settings = GLOBAL_GET(setting_name);
List<Variant> keys;
import_settings.get_key_list(&keys);
if (params->checking) {
params->checked.clear();
}
for (const Variant &E : keys) {
params->values[E] = import_settings[E];
for (const KeyValue<Variant, Variant> &kv : import_settings) {
params->values[kv.key] = kv.value;
if (params->checking) {
params->checked.insert(E);
params->checked.insert(kv.key);
}
}
params->update();

@ -539,11 +539,9 @@ void LocalizationEditor::update_translations() {
if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/translation_remaps")) {
Dictionary remaps = GLOBAL_GET("internationalization/locale/translation_remaps");
List<Variant> rk;
remaps.get_key_list(&rk);
Vector<String> keys;
for (const Variant &E : rk) {
keys.push_back(E);
for (const KeyValue<Variant, Variant> &kv : remaps) {
keys.push_back(kv.key);
}
keys.sort();

@ -6619,17 +6619,15 @@ void Node3DEditor::set_state(const Dictionary &p_state) {
if (d.has("gizmos_status")) {
Dictionary gizmos_status = d["gizmos_status"];
List<Variant> keys;
gizmos_status.get_key_list(&keys);
for (int j = 0; j < gizmo_plugins_by_name.size(); ++j) {
if (!gizmo_plugins_by_name[j]->can_be_hidden()) {
continue;
}
int state = EditorNode3DGizmoPlugin::VISIBLE;
for (const Variant &key : keys) {
if (gizmo_plugins_by_name.write[j]->get_gizmo_name() == String(key)) {
state = gizmos_status[key];
for (const KeyValue<Variant, Variant> &kv : gizmos_status) {
if (gizmo_plugins_by_name.write[j]->get_gizmo_name() == String(kv.key)) {
state = kv.value;
break;
}
}

@ -173,11 +173,9 @@ int AudioStreamInteractive::get_clip_auto_advance_next_clip(int p_clip) const {
// TRANSITIONS
void AudioStreamInteractive::_set_transitions(const Dictionary &p_transitions) {
List<Variant> keys;
p_transitions.get_key_list(&keys);
for (const Variant &K : keys) {
Vector2i k = K;
Dictionary data = p_transitions[K];
for (const KeyValue<Variant, Variant> &kv : p_transitions) {
Vector2i k = kv.key;
Dictionary data = kv.value;
ERR_CONTINUE(!data.has("from_time"));
ERR_CONTINUE(!data.has("to_time"));
ERR_CONTINUE(!data.has("fade_mode"));

@ -77,11 +77,9 @@ bool AnimationMixer::_set(const StringName &p_name, const Variant &p_value) {
while (animation_libraries.size()) {
remove_animation_library(animation_libraries[0].name);
}
List<Variant> keys;
d.get_key_list(&keys);
for (const Variant &K : keys) {
Ref<AnimationLibrary> lib = d[K];
add_animation_library(K, lib);
for (const KeyValue<Variant, Variant> &kv : d) {
Ref<AnimationLibrary> lib = kv.value;
add_animation_library(kv.key, lib);
}
emit_signal(SNAME("animation_libraries_updated"));

@ -121,12 +121,10 @@ AnimationNode::NodeTimeInfo AnimationNode::get_node_time_info() const {
void AnimationNode::get_child_nodes(List<ChildNode> *r_child_nodes) {
Dictionary cn;
if (GDVIRTUAL_CALL(_get_child_nodes, cn)) {
List<Variant> keys;
cn.get_key_list(&keys);
for (const Variant &E : keys) {
for (const KeyValue<Variant, Variant> &kv : cn) {
ChildNode child;
child.name = E;
child.node = cn[E];
child.name = kv.key;
child.node = kv.value;
r_child_nodes->push_back(child);
}
}

@ -91,13 +91,11 @@ void ImporterMesh::add_surface(Mesh::PrimitiveType p_primitive, const Array &p_a
s.blend_shape_data.push_back(bs);
}
List<Variant> lods;
p_lods.get_key_list(&lods);
for (const Variant &E : lods) {
ERR_CONTINUE(!E.is_num());
for (const KeyValue<Variant, Variant> &kv : p_lods) {
ERR_CONTINUE(!kv.key.is_num());
Surface::LOD lod;
lod.distance = E;
lod.indices = p_lods[E];
lod.distance = kv.key;
lod.indices = kv.value;
ERR_CONTINUE(lod.indices.is_empty());
s.lods.push_back(lod);
}

@ -134,10 +134,8 @@ void AnimationLibrary::_set_data(const Dictionary &p_data) {
K.value->disconnect_changed(callable_mp(this, &AnimationLibrary::_animation_changed));
}
animations.clear();
List<Variant> keys;
p_data.get_key_list(&keys);
for (const Variant &K : keys) {
add_animation(K, p_data[K]);
for (const KeyValue<Variant, Variant> &kv : p_data) {
add_animation(kv.key, kv.value);
}
}

@ -1674,14 +1674,11 @@ void ResourceFormatSaverTextInstance::_find_resources(const Variant &p_variant,
Dictionary d = p_variant;
_find_resources(d.get_typed_key_script());
_find_resources(d.get_typed_value_script());
List<Variant> keys;
d.get_key_list(&keys);
for (const Variant &E : keys) {
for (const KeyValue<Variant, Variant> &kv : d) {
// Of course keys should also be cached, after all we can't prevent users from using resources as keys, right?
// See also ResourceFormatSaverBinaryInstance::_find_resources (when p_variant is of type Variant::DICTIONARY)
_find_resources(E);
Variant v = d[E];
_find_resources(v);
_find_resources(kv.key);
_find_resources(kv.value);
}
} break;
case Variant::PACKED_BYTE_ARRAY: {

@ -537,16 +537,13 @@ bool CodeHighlighter::has_color_region(const String &p_start_key) const {
void CodeHighlighter::set_color_regions(const Dictionary &p_color_regions) {
color_regions.clear();
List<Variant> keys;
p_color_regions.get_key_list(&keys);
for (const Variant &E : keys) {
String key = E;
for (const KeyValue<Variant, Variant> &kv : p_color_regions) {
String key = kv.key;
String start_key = key.get_slicec(' ', 0);
String end_key = key.get_slice_count(" ") > 1 ? key.get_slicec(' ', 1) : String();
add_color_region(start_key, end_key, p_color_regions[key], end_key.is_empty());
add_color_region(start_key, end_key, kv.value, end_key.is_empty());
}
clear_highlighting_cache();
}

@ -425,11 +425,9 @@ protected:
}
void _set_versions(const Dictionary &p_versions) {
versions.clear();
List<Variant> keys;
p_versions.get_key_list(&keys);
for (const Variant &E : keys) {
StringName vname = E;
Ref<RDShaderSPIRV> bc = p_versions[E];
for (const KeyValue<Variant, Variant> &kv : p_versions) {
StringName vname = kv.key;
Ref<RDShaderSPIRV> bc = kv.value;
ERR_CONTINUE(bc.is_null());
versions[vname] = bc;
}

@ -593,4 +593,21 @@ TEST_CASE("[Dictionary] Typed copying") {
d6.clear();
}
TEST_CASE("[Dictionary] Iteration") {
Dictionary a1 = build_dictionary(1, 2, 3, 4, 5, 6);
Dictionary a2 = build_dictionary(1, 2, 3, 4, 5, 6);
int idx = 0;
for (const KeyValue<Variant, Variant> &kv : (const Dictionary &)a1) {
CHECK_EQ(int(a2[kv.key]), int(kv.value));
idx++;
}
CHECK_EQ(idx, a1.size());
a1.clear();
a2.clear();
}
} // namespace TestDictionary