config.h
#pragma once

#include <any>
#include <fstream>
#include <iostream>
#include <map>
#include <mutex>
#include <string_view>

#include "comm_func.h"
#include "logger.h"

namespace flower {
class config final {
public:
    static config &instance() {
        static config ins{};
        return ins;
    }

    ~config() = default;

    config(const config &) = delete;

    config &operator=(const config &) = delete;

private:
    config() = default;

public:
    bool start(std::string_view file_name);

    template <typename T>
    T get(std::string_view key) {
        if (!running_) {
            LOG_ERROR("config::get not init please call start function.", key);
            return {};
        }

        std::lock_guard<std::mutex> lock(mutex_);
        auto &any_value = config_map_[key.data()];
        if (!any_value.has_value()) {
            return {};
        }

        auto value = std::any_cast<std::string>(any_value);
        if (value.empty()) {
            return {};
        }

        if constexpr (std::is_integral_v<T>) {
            return static_cast<T>(comm_func::string_to_uint64(value));
        } else if constexpr (std::is_same_v<T, bool>) {
            return value == "true";
        } else if constexpr (std::is_same_v<T, float>) {
            return comm_func::string_to_float(value);
        } else if constexpr (std::is_same_v<T, double>) {
            return comm_func::string_to_double(value);
        } else if constexpr (std::is_same_v<T, time_t>) {
            return comm_func::string_to_time(value);
        } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, std::string_view> ||
                             std::is_same_v<T, const char *>) {
            return value;
        } else {
            LOG_ERROR("config::get not found type field:{}", key);
            return {};
        }
    }

private:
    bool running_{};
    std::mutex mutex_{};
    std::map<std::string, std::any> config_map_{};
};
}  // namespace flower
config.cpp
#include "config.h"

#include "logger.h"

namespace flower {
bool config::start(std::string_view file_name) {
    std::string path = comm_func::get_current_exe_dir().append("/").append(file_name.data());
    std::ifstream file_handle(path);

    if (file_handle.fail()) {
        LOG_ERROR("config::start cfg open failed");
        return false;
    }

    std::string key, value, data;
    std::string::size_type ignore, pos;
    while (getline(file_handle, data)) {
        ignore = data.find('#');
        if (ignore != std::string::npos) {
            continue;
        }

        pos = data.find('=');
        if (pos == std::string::npos) {
            continue;
        }

        key = data.substr(0, pos);
        value = data.substr(pos + 1);
        comm_func::trim(key);
        comm_func::trim(value);
        std::lock_guard<std::mutex> lock(mutex_);
        config_map_.insert({key, value});
    }

    running_ = true;
    file_handle.close();
    return true;
}
}  // namespace flower