db/simple/DirectorySave: optimize duplicate checks with std::set
This reduces the CPU usage for loading a large database by more than 50%.
This commit is contained in:
parent
2c4ef4460f
commit
c96e8ab47c
|
@ -17,6 +17,9 @@
|
|||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <set>
|
||||
#include <string_view>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define DIRECTORY_DIR "directory: "
|
||||
|
@ -109,9 +112,6 @@ ParseLine(Directory &directory, const char *line)
|
|||
static Directory *
|
||||
directory_load_subdir(LineReader &file, Directory &parent, std::string_view name)
|
||||
{
|
||||
if (parent.FindChild(name) != nullptr)
|
||||
throw FmtRuntimeError("Duplicate subdirectory '{}'", name);
|
||||
|
||||
Directory *directory = parent.CreateChild(name);
|
||||
|
||||
try {
|
||||
|
@ -139,20 +139,24 @@ directory_load_subdir(LineReader &file, Directory &parent, std::string_view name
|
|||
void
|
||||
directory_load(LineReader &file, Directory &directory)
|
||||
{
|
||||
/* these sets are used to quickly check for duplicates,
|
||||
avoiding linear lookups */
|
||||
std::set<std::string_view> children, songs;
|
||||
|
||||
const char *line;
|
||||
|
||||
while ((line = file.ReadLine()) != nullptr &&
|
||||
!StringStartsWith(line, DIRECTORY_END)) {
|
||||
const char *p;
|
||||
if ((p = StringAfterPrefix(line, DIRECTORY_DIR))) {
|
||||
directory_load_subdir(file, directory, p);
|
||||
auto *child = directory_load_subdir(file, directory, p);
|
||||
|
||||
const std::string_view name = child->GetName();
|
||||
if (!children.emplace(name).second)
|
||||
throw FmtRuntimeError("Duplicate subdirectory '{}'", name);
|
||||
} else if ((p = StringAfterPrefix(line, SONG_BEGIN))) {
|
||||
const char *name = p;
|
||||
|
||||
if (directory.FindSong(name) != nullptr)
|
||||
throw FmtRuntimeError("Duplicate song '{}'",
|
||||
name);
|
||||
|
||||
std::string target;
|
||||
bool in_playlist = false;
|
||||
auto detached_song = song_load(file, name,
|
||||
|
@ -163,6 +167,10 @@ directory_load(LineReader &file, Directory &directory)
|
|||
song->target = std::move(target);
|
||||
song->in_playlist = in_playlist;
|
||||
|
||||
if (!songs.emplace(song->filename).second)
|
||||
throw FmtRuntimeError("Duplicate song '{}'",
|
||||
name);
|
||||
|
||||
directory.AddSong(std::move(song));
|
||||
} else if ((p = StringAfterPrefix(line, PLAYLIST_META_BEGIN))) {
|
||||
const char *name = p;
|
||||
|
|
Loading…
Reference in New Issue