Files
noggit-red/src/noggit/AsyncLoader.cpp
2020-10-20 22:46:14 +03:00

158 lines
3.3 KiB
C++

// This file is part of Noggit3, licensed under GNU General Public License (version 3).
#include <noggit/AsyncLoader.h>
#include <noggit/errorHandling.h>
#include <QtCore/QSettings>
#include <algorithm>
#include <list>
bool AsyncLoader::is_loading()
{
std::lock_guard<std::mutex> const lock (_guard);
if (_currently_loading.empty())
{
return false;
}
else
{
for (auto async_obj : _currently_loading)
{
if (!async_obj->loading_failed() && async_obj->filename.length()) // the filename check is a hack
{
return true;
}
}
}
return false;
}
void AsyncLoader::process()
{
AsyncObject* object = nullptr;
QSettings settings;
bool additional_log = settings.value("additional_file_loading_log", false).toBool();
while (!_stop)
{
{
std::unique_lock<std::mutex> lock (_guard);
_state_changed.wait
( lock
, [&]
{
return !!_stop || std::any_of ( _to_load.begin(), _to_load.end()
, [](auto const& to_load) { return !to_load.empty(); }
);
}
);
if (_stop)
{
return;
}
for (auto& to_load : _to_load)
{
if (to_load.empty())
{
continue;
}
object = to_load.front();
_currently_loading.emplace_back (object);
to_load.pop_front();
break;
}
}
try
{
if (additional_log)
{
std::lock_guard<std::mutex> const lock(_guard);
LogDebug << "Loading '" << object->filename << "'" << std::endl;
}
object->finishLoading();
if (additional_log)
{
std::lock_guard<std::mutex> const lock(_guard);
LogDebug << "Loaded '" << object->filename << "'" << std::endl;
}
{
std::lock_guard<std::mutex> const lock (_guard);
_currently_loading.remove (object);
_state_changed.notify_all();
}
}
catch (...)
{
std::lock_guard<std::mutex> const lock(_guard);
object->error_on_loading();
if (object->is_required_when_saving())
{
_important_object_failed_loading = true;
}
}
}
}
void AsyncLoader::queue_for_load (AsyncObject* object)
{
std::lock_guard<std::mutex> const lock (_guard);
_to_load[(size_t)object->loading_priority()].push_back (object);
_state_changed.notify_one();
}
void AsyncLoader::ensure_deletable (AsyncObject* object)
{
std::unique_lock<std::mutex> lock (_guard);
_state_changed.wait
( lock
, [&]
{
auto& to_load = _to_load[(size_t)object->loading_priority()];
auto const& it = std::find (to_load.begin(), to_load.end(), object);
// don't load it if it's just to delete it afterward
if (it != to_load.end())
{
to_load.erase(it);
return true;
}
else
{
return std::find (_currently_loading.begin(), _currently_loading.end(), object) == _currently_loading.end();
}
}
);
}
AsyncLoader::AsyncLoader(int numThreads)
: _stop (false)
{
for (int i = 0; i < numThreads; ++i)
{
_threads.emplace_back (&AsyncLoader::process, this);
}
}
AsyncLoader::~AsyncLoader()
{
_stop = true;
_state_changed.notify_all();
for (auto& thread : _threads)
{
thread.join();
}
}