/* * 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 */ #pragma once #include "log/log.hpp" #include "introspection/name.hpp" #include #include namespace cruft { template 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 () ); return cookie { key }; } { LOG_ERROR ( "Unable to register {} for {}", key, cruft::introspection::name::full () ); 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 s_factory; return s_factory; } }; }