Skip to content

File ConfigParser.cpp

File List > benchmark > ConfigParser.cpp

Go to the documentation of this file

// ConfigParser.cpp
//
// Lit un JSON et le met "en ligne" sous forme d'argv pour CLI11.
//
// Regles :
//   - cle "input" ou "output"           -> --key value(s)
//   - cle "parameters" (a tout niveau)  -> cle ignoree, chaque cle du premier
//                                          niveau devient --key, suivie des
//                                          valeurs feuilles de son sous-arbre
//                                          (cles internes ignorees)
//   - autre cle scalaire (hors mode parameters)  -> juste la valeur
//   - autre objet                        -> cle ignoree, on recurse
//
// Forward-declaration a coller dans main.cpp :
//
//     #include <string>
//     #include <vector>
//     std::vector<char*> getConfigJSON(const std::string& filepath);
//

#include <nlohmann/json.hpp>
#include <fstream>
#include <stdexcept>
#include <string>
#include <vector>

using json = nlohmann::ordered_json;

namespace {

// Storage statique : les char* retournes pointent ici.
static std::vector<std::string> g_argsStorage;

std::string toFlag(const std::string& key) {
    return key.size() == 1 ? "-" + key : "--" + key;
}

std::string toString(const json& v) {
    if (v.is_string()) return v.get<std::string>();
    return v.dump();  // nombres, booleens, etc.
}

void appendLeafValues(const json& v, std::vector<std::string>& out) {
    if (v.is_null()) return;

    if (v.is_array()) {
        for (const auto& item : v) appendLeafValues(item, out);
        return;
    }

    if (v.is_object()) {
        for (auto it = v.begin(); it != v.end(); ++it) {
            appendLeafValues(it.value(), out);
        }
        return;
    }

    out.push_back(toString(v));
}

// Aplatit recursivement le JSON dans `out`.
void flatten(const json& v, std::vector<std::string>& out) {
    if (!v.is_object()) return;

    for (auto it = v.begin(); it != v.end(); ++it) {
        const std::string& key = it.key();
        const json&        val = it.value();

        if (val.is_null()) continue;

        // Cas special : "input" / "output" -> toujours --key value(s)
        if (key == "input" || key == "output") {
            out.push_back(toFlag(key));
            if (val.is_array()) {
                for (const auto& x : val) out.push_back(toString(x));
            }
            else if (!val.is_object()) {
                out.push_back(toString(val));
            }
            continue;
        }

        // Cas special : "parameters" -> cle ignoree, mode parameters active
        if (key == "parameters") {
            if (val.is_object()) {
                for (auto paramIt = val.begin(); paramIt != val.end(); ++paramIt) {
                    out.push_back(toFlag(paramIt.key()));
                    appendLeafValues(paramIt.value(), out);
                }
            }
            else if (val.is_array()) {
                for (const auto& item : val) {
                    if (!item.is_object()) continue;

                    for (auto paramIt = item.begin(); paramIt != item.end(); ++paramIt) {
                        out.push_back(toFlag(paramIt.key()));
                        appendLeafValues(paramIt.value(), out);
                    }
                }
            }
            continue;
        }

        // Cas general
        if (val.is_object()) {
            // On saute la cle parente, on aplatit le contenu.
            flatten(val, out);
        }
        else if (val.is_array()) {
            if (!val.empty() && val.front().is_object()) {
                // Tableau d'objets : on aplatit chaque objet.
                for (const auto& item : val) flatten(item, out);
            }
            else {
                // Tableau de scalaires.
                for (const auto& x : val) out.push_back(toString(x));
            }
        }
        else {
            // Scalaire.
            out.push_back(toString(val));
        }
    }
}

}


std::vector<char*> getConfigJSON(const std::string& filepath) {
    std::ifstream file(filepath);
    if (!file.is_open()) {
        throw std::runtime_error("Cannot open config file: " + filepath);
    }

    json data;
    file >> data;

    g_argsStorage.clear();
    g_argsStorage.push_back("argos_benchmark"); // argv[0]
    flatten(data, g_argsStorage);

    std::vector<char*> argv;
    argv.reserve(g_argsStorage.size());
    for (auto& s : g_argsStorage) argv.push_back(s.data());

    return argv;
}