Skip to content

File phonebook.hpp

File List > illixr > phonebook.hpp

Go to the documentation of this file

#pragma once

#include "export.hpp"

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#if defined(_WIN32) || defined(_WIN64)
#    include 
#    include 
#endif

#ifndef NDEBUG
#    include 
// #  include "spdlog/sinks/stdout_color_sinks.h"
#endif

namespace ILLIXR {

#if defined(_WIN32) || defined(_WIN64)
static void setenv(const std::string& var, const std::string& val, int) {
    std::string env_stmt = var + "=" + val;
    putenv(env_stmt.c_str());
}
#endif

class MY_EXPORT_API phonebook {
    /*
      Proof of thread-safety:
      - Since all instance members are private, acquiring a lock in each method implies the class is datarace-free.
      - Since there is only one lock and this does not call any code containing locks, this is deadlock-free.
      - Both of these methods are only used during initialization, so the locks are not contended in steady-state.

      However, to write a correct program, one must also check the thread-safety of the elements
      inserted into this class by the caller.
    */

public:
    class service {
    public:
        // auto spdlogger(const char* log_level) {
        //     if (!log_level) {
        // #ifdef NDEBUG
        //         log_level = "warn";
        // #else
        //         log_level = "debug";
        // #endif
        //     }
        //     std::vector sinks;
        //     // auto                          file_sink = std::make_shared("logs/" +
        //     type_index.name() + ".log"); auto                          console_sink =
        //     std::make_shared();
        //     // sinks.push_back(file_sink);
        //     sinks.push_back(console_sink);
        //     plugin_logger = std::make_shared(type_index.name(), begin(sinks), end(sinks));
        //     plugin_logger->set_level(spdlog::level::from_str(log_level));
        //     spdlog::register_logger(plugin_logger);
        //     return plugin_logger;
        // }

        // void spd_add_file_sink(const std::string& file_name, const std::string& extension, const std::string& log_level) {
        //     if (!plugin_logger) {
        //         throw std::runtime_error("Logger not found");
        //     }

        // auto file_sink = std::make_shared("logs/" + file_name + "." + extension, true);
        // file_sink->set_level(spdlog::level::from_str(log_level));
        // plugin_logger->sinks().push_back(file_sink);
        // size_t sink_count = plugin_logger->sinks().size();
        // plugin_logger->sinks()[sink_count-1]->set_pattern("%v");
        // }

        virtual ~service() = default;

        // std::shared_ptr      plugin_logger;
    };

    template<typename Specific_service>
    void register_impl(std::shared_ptr<Specific_service> impl) {
        const std::unique_lock<std::shared_mutex> lock{mutex_};

        const std::type_index type_index = std::type_index(typeid(Specific_service));
#ifndef NDEBUG
        spdlog::get("illixr")->debug("[phonebook] Register {}", type_index.name());
#endif
        assert(registry_.count(type_index.name()) == 0);
        registry_.try_emplace(type_index.name(), impl);
    }

    template<typename Specific_service>
    std::shared_ptr<Specific_service> lookup_impl() const {
        const std::shared_lock<std::shared_mutex> lock{mutex_};

        const std::type_index type_index = std::type_index(typeid(Specific_service));

#ifndef NDEBUG
        // if this fails, and there are no duplicate base classes, ensure the hash_code's are unique.
        if (registry_.count(type_index.name()) != 1) {
            throw std::runtime_error{"Attempted to lookup an unregistered implementation " + std::string{type_index.name()}};
        }
#endif

        std::shared_ptr<service> this_service = registry_.at(type_index.name());
        if (!static_cast<bool>(this_service))
            throw std::runtime_error{"Could not find " + std::string{type_index.name()}};

        std::shared_ptr<Specific_service> this_specific_service = std::dynamic_pointer_cast<Specific_service>(this_service);
        if (!static_cast<bool>(this_service) || this_specific_service == nullptr)
            throw std::runtime_error{"Could not find specific " + std::string{type_index.name()}};

        return this_specific_service;
    }

    template<typename specific_service>
    [[maybe_unused]] bool has_impl() const {
        const std::shared_lock<std::shared_mutex> lock{mutex_};

        const std::type_index type_index = std::type_index(typeid(specific_service));

        return registry_.count(type_index.name()) == 1;
    }

    size_t get_next_id() {
        size_t val = current_id_;
        current_id_++;
        return val;
    }

private:
    std::unordered_map<std::string, const std::shared_ptr<service>> registry_;
    mutable std::shared_mutex                                       mutex_;
    size_t                                                          current_id_ = 0;
};
} // namespace ILLIXR