psemek/libs/rs/source/registry.cpp

106 lines
2 KiB
C++

#include <psemek/rs/registry.hpp>
#include <psemek/util/to_string.hpp>
#include <map>
#include <unordered_map>
#include <mutex>
#include <atomic>
#include <optional>
namespace psemek::rs
{
namespace
{
auto & resources_mutex()
{
static std::mutex instance;
return instance;
}
auto & resources()
{
static std::map<id, resource> instance;
return instance;
}
auto & name_map_mutex()
{
static std::mutex instance;
return instance;
}
auto & name_map()
{
static std::unordered_map<std::string_view, id> instance;
return instance;
}
std::atomic<id> next_id{0};
}
unknown_id_error::unknown_id_error(rs::id id, boost::stacktrace::stacktrace stacktrace)
: util::exception(util::to_string("unknown resource id: ", id), std::move(stacktrace))
, id_(id)
{}
unknown_name_error::unknown_name_error(std::string_view name, boost::stacktrace::stacktrace stacktrace)
: util::exception(util::to_string("unknown resource name: ", name), std::move(stacktrace))
{}
resource const * find(id id)
{
std::lock_guard lock{resources_mutex()};
auto it = resources().find(id);
if (it == resources().end())
return nullptr;
return &(it->second);
}
resource const * find(std::string_view name)
{
rs::id id;
{
std::lock_guard lock{name_map_mutex()};
auto it = name_map().find(name);
if (it == name_map().end())
return nullptr;
id = it->second;
}
return find(id);
}
resource const & get(id id)
{
auto result = find(id);
if (!result)
throw unknown_id_error{id};
return *result;
}
resource const & get(std::string_view name)
{
auto result = find(name);
if (!result)
throw unknown_name_error{name};
return *result;
}
id add(std::string_view name, std::string_view data)
{
auto id = next_id.fetch_add(1);
{
std::lock_guard lock{name_map_mutex()};
name_map()[name] = id;
}
{
std::lock_guard lock{resources_mutex()};
resources()[id] = {id, name, data};
}
return id;
}
}