Skip to content
Snippets Groups Projects
json_tools.hpp 3.59 KiB
Newer Older
  • Learn to ignore specific revisions
  • #include "nlohmann/json.hpp"
    
    
    Ian Bell's avatar
    Ian Bell committed
    #include <set>
    
    #include <filesystem>
    #include <fstream>
    
    #include "teqp/exceptions.hpp"
    
    Ian Bell's avatar
    Ian Bell committed
    
    
        
        /// Load a JSON file from a specified file
        inline nlohmann::json load_a_JSON_file(const std::string& path) {
            if (!std::filesystem::is_regular_file(path)) {
                throw std::invalid_argument("Path to be loaded does not exist: " + path);
            }
            auto stream = std::ifstream(path);
            if (!stream) {
                throw std::invalid_argument("File stream cannot be opened from: " + path);
            }
            try {
                return nlohmann::json::parse(stream);
            }
            catch (...) {
                throw std::invalid_argument("File at " + path + " is not valid JSON");
            }
        }
    
    
        inline auto all_same_length(const nlohmann::json& j, const std::vector<std::string>& ks) {
            std::set<decltype(j[0].size())> lengths;
            for (auto k : ks) { lengths.insert(j.at(k).size()); }
            return lengths.size() == 1;
        }
    
    Ian Bell's avatar
    Ian Bell committed
        inline auto build_square_matrix = [](const nlohmann::json& j){
    
            if (j.is_null() || (j.is_array() && j.size() == 0)){
                return Eigen::ArrayXXd(0, 0);
            }
            try{
                const std::valarray<std::valarray<double>> m = j;
                // First assume that the matrix is square, resize
                Eigen::ArrayXXd mat(m.size(), m.size());
                if (m.size() == 0){
                    return mat;
                }
                // Then copy elements over
                for (auto i = 0; i < m.size(); ++i){
                    auto row = m[i];
                    if (row.size() != mat.rows()){
                        throw std::invalid_argument("provided matrix is not square");
                    }
                    for (auto j = 0; j < row.size(); ++j){
                        mat(i, j) = row[j];
                    }
                }
                return mat;
            }
            catch(const nlohmann::json::exception&){
                throw teqp::InvalidArgument("Unable to convert this kmat to a 2x2 matrix of doubles:" + j.dump(2));
            }
        };
    
    
        /**
        A method for loading something from a nlohmann::json node. Thing to be operated on can be:
        
         0. empty, in which case the file at the default_path is loaded
         1. An object node, in which case it is returned
         2. A path as a string. If this file exists, it will be loaded
         3. A JSON-encoded string
         
         */
        inline auto multilevel_JSON_load(const nlohmann::json &j, const std::string& default_path){
            
            auto is_valid_path = [](const std::string & s){
                try{
                    std::filesystem::is_regular_file(s);
                    return true;
                }
                catch(...){
                    return false;
                }
            };
            
            // If not provided (NULL, empty array or empty string), load from the default path provided
            if (j.is_null() || (j.is_array() && j.empty()) || (j.is_string() && j.get<std::string>().empty())){
                return load_a_JSON_file(default_path);
            }
            else if (j.is_object()){
                // Assume we are already providing the thing
                return j;
            }
            else if (j.is_string()){
                // If a string, either data in JSON format, or a path-like thing
                std::string s = j.get<std::string>();
                
                // If path to existing file, use it
                if (is_valid_path(s) && std::filesystem::is_regular_file(s)){
                    return load_a_JSON_file(s);
                }
                // Or assume it is a string in JSON format
                else{
                    return nlohmann::json::parse(s);
                }
            }
        }