Made load dialog faster when there are many saved games.

1. Added a child_range_index member function to config to generate an index

2. Changed the load dialog from the O(N^2) search for saved games to a
O(N) listing.
This commit is contained in:
Thonsew 2011-09-08 19:17:20 +00:00
parent 81c2162d93
commit 82e7d2c6f8
6 changed files with 63 additions and 12 deletions

BIN
perf.data Normal file

Binary file not shown.

View File

@ -422,8 +422,7 @@ void config::merge_children_by_attribute(const t_token& key, const t_token& attr
void config::merge_children_by_attribute(const std::string& key, const std::string& attribute){
merge_children_by_attribute(t_token(key), t_token(attribute));}
config::child_itors config::child_range(const t_token& key)
{
config::child_itors config::child_range(const t_token& key) {
check_valid();
child_map::iterator i = children.find(key);
@ -437,8 +436,7 @@ config::child_itors config::child_range(const t_token& key)
}
config::child_itors config::child_range(const std::string& key){ return child_range( t_token(key) );}
config::const_child_itors config::child_range(const t_token& key) const
{
config::const_child_itors config::child_range(const t_token& key) const {
check_valid();
child_map::const_iterator i = children.find(key);
@ -452,8 +450,7 @@ config::const_child_itors config::child_range(const t_token& key) const
}
config::const_child_itors config::child_range(const std::string& key) const { return child_range(t_token(key));}
unsigned config::child_count(const t_token &key) const
{
unsigned config::child_count(const t_token &key) const {
check_valid();
child_map::const_iterator i = children.find(key);
@ -463,6 +460,25 @@ unsigned config::child_count(const t_token &key) const
return 0;
}
config::t_child_range_index config::child_range_index(config::t_token const & key, config::t_token const & name) {
t_child_range_index index;
child_map::iterator irange = children.find(key);
if (irange != children.end()) {
foreach(config * c, irange->second) {
index.insert(std::make_pair((*c)[name].token(), c)); } }
return index; }
config::t_const_child_range_index config::const_child_range_index(config::t_token const & key, config::t_token const & name) const {
t_const_child_range_index index;
child_map::const_iterator irange = children.find(key);
if (irange != children.end()) {
foreach(config const * c, irange->second){
index.insert(std::make_pair((*c)[name].token(), c)); } }
return index; }
unsigned config::child_count(const std::string &key) const { return child_count(t_token(key)); }
config &config::child(const t_token& key, int n)
{

View File

@ -117,6 +117,9 @@ public:
//typedef std::map<t_token,child_list> child_map;
typedef boost::unordered_map<t_token,child_list> child_map;
typedef boost::unordered_map<config::t_token, config *> t_child_range_index;
typedef boost::unordered_map<config::t_token, config const *> t_const_child_range_index;
struct const_child_iterator;
struct child_iterator
@ -298,6 +301,19 @@ public:
typedef std::pair<const_attribute_iterator,const_attribute_iterator> const_attr_itors;
child_itors child_range(const t_token& key);
const_child_itors child_range(const t_token& key) const;
/** Creates an index into the child range to allow for quick searches.
key is the key for the child range and name is the column to index.
i.e. if the list of save games is stored in a child called save with titles
then to create a container indexed by titles do
child_range_index(z_save, z_title);
@Note the index is not stored in the config and is intended for
repeated searches of large child ranges.
*/
t_child_range_index child_range_index(const t_token& key, config::t_token const & name);
t_const_child_range_index const_child_range_index(const t_token& key, config::t_token const & name) const;
unsigned child_count(const t_token &key) const;
child_itors child_range(const std::string& key);

View File

@ -578,14 +578,20 @@ std::string load_game_dialog(display& disp, const config& game_config, bool* sho
return "";
}
config::t_child_range_index index = savegame::save_index::indexed_summaries();
std::vector<config*> summaries;
std::vector<savegame::save_info>::const_iterator i;
//FIXME: parent_to_child is not used yet
std::map<std::string,std::string> parent_to_child;
for(i = games.begin(); i != games.end(); ++i) {
config& cfg = savegame::save_index::save_summary(i->name);
parent_to_child[cfg["parent"]] = i->name;
summaries.push_back(&cfg);
config::t_token iname(i->name);
config::t_child_range_index::iterator xcfgi = index.find( iname);
if(xcfgi != index.end()){
config& cfg = *xcfgi->second;
parent_to_child[cfg["parent"]] = iname;
summaries.push_back(&cfg);
}
}
const events::event_context context;

View File

@ -126,6 +126,13 @@ static lg::log_domain log_engine("engine");
}
#endif /* _WIN32 */
namespace {
//Static tokens are replacements for string literals in code
//They allow for fast comparison, copying and hashing operations.
static const config::t_token z_save("save", false);
}
namespace savegame {
const std::string save_info::format_time_local() const{
@ -374,14 +381,18 @@ config& save_index::save_summary(std::string save)
}
config& cfg = load();
if (config &sv = cfg.find_child("save", "save", save))
if (config &sv = cfg.find_child(z_save, z_save, save))
return sv;
config &res = cfg.add_child("save");
res["save"] = save;
config &res = cfg.add_child(z_save);
res[z_save] = save;
return res;
}
config::t_child_range_index save_index::indexed_summaries(){
return load().child_range_index(z_save, z_save);
}
void save_index::write_save_index()
{
log_scope("write_save_index()");

View File

@ -80,6 +80,8 @@ public:
static config& save_summary(std::string save);
/** Update the save_index file with changed savegame information. */
static void write_save_index();
/** Create an index to the save summaries. */
static config::t_child_range_index indexed_summaries();
private:
/** Default-Constructor (don't instantiate this class) */