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 answers

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.