libcruft-util/registrar.hpp

109 lines
2.7 KiB
C++

/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright 2019 Danny Robson <danny@nerdcruft.net>
*/
#pragma once
#include "log/log.hpp"
#include "introspection/name.hpp"
#include <map>
#include <stdexcept>
namespace cruft {
template <typename KeyT, typename FactoryT>
class registry {
public:
struct cookie {
explicit cookie (KeyT const &_key)
: m_key (_key)
{ ; }
explicit cookie (KeyT &&_key)
: m_key (std::move (_key))
{ ; }
cookie (cookie &&rhs) noexcept
: m_key (std::move (rhs.key))
{ ; }
cookie& operator= (cookie &&rhs) noexcept
{
std::swap (rhs.m_key, m_key);
return *this;
}
cookie (cookie const&) = delete;
cookie& operator= (cookie const&) = delete;
~cookie ()
{
try {
registry::remove (m_key);
} catch (std::exception const &err) {
LOG_ERROR ("Unable to remove registration for {}", m_key);
}
}
private:
KeyT m_key;
};
static cookie
add [[nodiscard]] (KeyT key, FactoryT &&factory)
{
auto const &[pos, success] = store ().insert (
{ key, std::move (factory) }
);
if (success) {
LOG_INFO (
"Registered {} for {}",
key,
cruft::introspection::name::full<FactoryT> ()
);
return cookie { key };
} {
LOG_ERROR (
"Unable to register {} for {}",
key,
cruft::introspection::name::full<FactoryT> ()
);
throw std::runtime_error ("Unable to register type");
}
}
static FactoryT remove (KeyT const &key)
{
auto &s_factory = store ();
auto pos = s_factory.find (key);
if (pos == s_factory.cend ())
throw std::invalid_argument ("Key not found");
auto val = s_factory.extract (pos);
return std::move (val.mapped ());
}
static FactoryT& at (KeyT const &key)
{
return store ().at (key);
}
private:
static auto&
store (void)
{
static std::map<KeyT,FactoryT> s_factory;
return s_factory;
}
};
}