Boost_option to parse a configuration file

671 Views Asked by At

I am trying to parse a neural network configuration file similar to the following lines. Actual file will have many more lines but similar format.

Resnet50 {
    Layer CONV1 {
        Type: CONV
        Stride { X: 2, Y: 2 }       
        Dimensions { K: 64, C: 3, R: 7, S: 7, Y:224, X:224 }
    }


    Layer CONV2_1_1 {
        Type: CONV
        Stride { X: 1, Y: 1 }       
        Dimensions { K: 64, C: 64, R: 1, S: 1, Y: 56, X: 56 }
    }

I use this Boost argument parsing code:

void to_cout(const std::vector<std::string> &v)
{
   std::copy(v.begin(), v.end(), std::ostream_iterator<std::string>{std::cout, "\n"});
}

int main(int argc, char* argv[]) {
   namespace po = boost::program_options;
   po::options_description conf("Config file options");
   conf.add_options()("confg_file", po::value<std::string>(&file_name), "HW configuration file");
   po::options_description all_options;
   all_options.add(conf);
   po::variables_map vm;
   po::store(po::parse_command_line(argc, argv, all_options), vm);
   po::notify(vm);

   return 0;
}

Seeming a regular parsing routine. But the configuration file wasn't parsed correctly because there was no output in the to_cout of vm. How does parse_command_line get into the hierarchy of the example configuration file?

1

There are 1 best solutions below

15
sehe On

That's not what Program Options is about. You can use it to read ini files, but not with the code shown. You are literally invoking parse_command_line (not parse_config_file).

The code you show allows you to parse the name of a config file from the command line. This is also why the value is std::string file_name.

Maybe we're missing (quite a lot of) code, because there's also nothing invoking to_cout in your code, nevermind that it wouldn't work with vm because the argument type doesn't directly match. I know you can loop over matched names in the variable map, and this is likely what you did, but that's all not very relevant.

Even if you did call parse_config_file would not know how to read that file format, as the documented format is an INI-file flavour.

The Good News

The good news is that your config file does have a format that closely resembles INFO files as supported by Boost Property Tree. Which gives me the first opportunity in 10 years¹ to actually suggest using that library: It seems to be more or less precisely what you are after:

Live On Coliru

#include <boost/property_tree/info_parser.hpp>
#include <iostream>

extern std::string config;

int main() {
    boost::property_tree::ptree pt;
    std::istringstream iss(config);
    read_info(iss, pt);

    write_info(std::cout, pt);
}

std::string config = R"(
Resnet50 {
    Layer CONV1 {
        Type: CONV
        Stride { X: 2, Y: 2 }       
        Dimensions { K: 64, C: 3, R: 7, S: 7, Y:224, X:224 }
    }


    Layer CONV2_1_1 {
        Type: CONV
        Stride { X: 1, Y: 1 }       
        Dimensions { K: 64, C: 64, R: 1, S: 1, Y: 56, X: 56 }
    }
}
)";

Prints

Resnet50
{
    Layer CONV1
    {
        Type: CONV
        Stride
        {
            X: 2,
            Y: 2
        }
        Dimensions
        {
            K: 64,
            C: 3,
            R: 7,
            S: 7,
            Y:224, X:224
        }
    }
    Layer CONV2_1_1
    {
        Type: CONV
        Stride
        {
            X: 1,
            Y: 1
        }
        Dimensions
        {
            K: 64,
            C: 64,
            R: 1,
            S: 1,
            Y: 56,
            X: 56
        }
    }
}

Tieing It Together

You may tie it together with a CLI argument for the filename:

Live On Coliru

#include <boost/property_tree/info_parser.hpp>
#include <boost/program_options.hpp>
#include <iostream>
using boost::property_tree::ptree;

int main(int argc, char* argv[]) {
    std::string file_name;
    {
        namespace po = boost::program_options;
        po::options_description cliopts("options");
        cliopts.add_options() //
            ("config_file", po::value<std::string>(&file_name),
             "HW configuration file");

        po::variables_map vm;
        po::store(po::parse_command_line(argc, argv, cliopts), vm);

        if (!vm.contains("config_file")) {
            std::cerr << cliopts << '\n';
            return 255;
        }

        po::notify(vm); // sets file_name
    }

    boost::property_tree::ptree pt;
    {
        std::ifstream ifs(file_name);
        read_info(ifs, pt);
    } // closes file

    for (auto const& [key, sub] : pt.get_child("Resnet50")) {
        std::cout << key << " " << sub.get_value("") << "\n";
    }
}

Then for running ./test.exe --config_file config.cfg it may print e.g.

Layer CONV1
Layer CONV2_1_1

¹ 10 years (and more) of admonishing people not to abuse Property Tree as an XML, INI, or JSON parser, because it is none of these things. It's ... a property tree library.