Game Lua Kernel: simplify a horrendous loop

This can't be done in a simple loop over all_children_range since splice_children modifies
the source config. This adds a new getter method for a view over all tag names.
This commit is contained in:
Charles Dang 2024-09-15 17:27:11 -04:00
parent 39729290df
commit a52c5e133a
3 changed files with 30 additions and 13 deletions

View File

@ -583,7 +583,7 @@ void config::clear_children_impl(config_key_type key)
children_.erase(i);
}
void config::splice_children(config& src, const std::string& key)
void config::splice_children(config& src, config_key_type key)
{
child_map::iterator i_src = src.children_.find(key);
if(i_src == src.children_.end()) {

View File

@ -33,6 +33,12 @@
#include "utils/const_clone.hpp"
#include "utils/optional_reference.hpp"
#ifdef __cpp_lib_ranges
#include <ranges>
#else
#include <boost/range/adaptor/map.hpp>
#endif
#include <functional>
#include <iosfwd>
#include <map>
@ -609,7 +615,7 @@ public:
/**
* Moves all the children with tag @a key from @a src to this.
*/
void splice_children(config &src, const std::string &key);
void splice_children(config& src, config_key_type key);
void remove_child(config_key_type key, std::size_t index);
/**
@ -875,6 +881,16 @@ public:
*/
bool validate_wml() const;
/** A non-owning view over all child tag names. */
auto child_name_view() const
{
#ifdef __cpp_lib_ranges
return children_ | std::views::keys;
#else
return children_ | boost::adaptors::map_keys;
#endif
}
private:
/**
* Removes the child at position @a pos of @a l.

View File

@ -5708,11 +5708,11 @@ void game_lua_kernel::set_game_display(game_display * gd) {
* elsewhere (in the C++ code).
* Any child tags not in this list will be passed to Lua's on_load event.
*/
static bool is_handled_file_tag(const std::string& s)
static bool is_handled_file_tag(std::string_view s)
{
// Make sure this is sorted, since we binary_search!
using namespace std::literals::string_view_literals;
static const std::array handled_file_tags {
static constexpr std::array handled_file_tags {
"color_palette"sv,
"color_range"sv,
"display"sv,
@ -5787,23 +5787,24 @@ void game_lua_kernel::save_game(config &cfg)
luaW_toconfig(L, -1, v);
lua_pop(L, 1);
for (;;)
{
config::all_children_iterator i = v.ordered_begin();
if (i == v.ordered_end()) break;
if (is_handled_file_tag(i->key))
{
// Make a copy of the source tag names. Since splice is a destructive operation,
// we can't guarantee that the view will remain valid during iteration.
const auto temp = v.child_name_view();
const std::vector<std::string> src_tags(temp.begin(), temp.end());
for(const auto& key : src_tags) {
if(is_handled_file_tag(key)) {
/*
* It seems the only tags appearing in the config v variable here
* are the core-lua-handled (currently [item] and [objectives])
* and the extra UMC ones.
*/
const std::string m = "Tag is already used: [" + i->key + "]";
const std::string m = "Tag is already used: [" + key + "]";
log_error(m.c_str());
v.erase(i);
continue;
} else {
cfg.splice_children(v, key);
}
cfg.splice_children(v, i->key);
}
}