lemon/arg_parser.h
author Peter Kovacs <kpeter@inf.elte.hu>
Tue, 15 Mar 2011 19:32:21 +0100
changeset 936 ddd3c0d3d9bf
parent 877 141f9c0db4a3
child 1123 18c89646185e
permissions -rw-r--r--
Implement the scaling Price Refinement heuristic in CostScaling (#417)
instead of Early Termination.

These two heuristics are similar, but the newer one is faster
and not only makes it possible to skip some epsilon phases, but
it can improve the performance of the other phases, as well.
     1 /* -*- mode: C++; indent-tabs-mode: nil; -*-
     2  *
     3  * This file is a part of LEMON, a generic C++ optimization library.
     4  *
     5  * Copyright (C) 2003-2010
     6  * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
     7  * (Egervary Research Group on Combinatorial Optimization, EGRES).
     8  *
     9  * Permission to use, modify and distribute this software is granted
    10  * provided that this copyright notice appears in all copies. For
    11  * precise terms see the accompanying LICENSE file.
    12  *
    13  * This software is provided "AS IS" with no warranty of any kind,
    14  * express or implied, and with no claim as to its suitability for any
    15  * purpose.
    16  *
    17  */
    18 
    19 #ifndef LEMON_ARG_PARSER_H
    20 #define LEMON_ARG_PARSER_H
    21 
    22 #include <vector>
    23 #include <map>
    24 #include <list>
    25 #include <string>
    26 #include <iostream>
    27 #include <sstream>
    28 #include <algorithm>
    29 #include <lemon/assert.h>
    30 
    31 ///\ingroup misc
    32 ///\file
    33 ///\brief A tool to parse command line arguments.
    34 
    35 namespace lemon {
    36 
    37   ///Exception used by ArgParser
    38 
    39   ///Exception used by ArgParser.
    40   ///
    41   class ArgParserException : public Exception {
    42   public:
    43     /// Reasons for failure
    44 
    45     /// Reasons for failure.
    46     ///
    47     enum Reason {
    48       HELP,         ///< <tt>--help</tt> option was given.
    49       UNKNOWN_OPT,  ///< Unknown option was given.
    50       INVALID_OPT   ///< Invalid combination of options.
    51     };
    52 
    53   private:
    54     Reason _reason;
    55 
    56   public:
    57     ///Constructor
    58     ArgParserException(Reason r) throw() : _reason(r) {}
    59     ///Virtual destructor
    60     virtual ~ArgParserException() throw() {}
    61     ///A short description of the exception
    62     virtual const char* what() const throw() {
    63       switch(_reason)
    64         {
    65         case HELP:
    66           return "lemon::ArgParseException: ask for help";
    67           break;
    68         case UNKNOWN_OPT:
    69           return "lemon::ArgParseException: unknown option";
    70           break;
    71         case INVALID_OPT:
    72           return "lemon::ArgParseException: invalid combination of options";
    73           break;
    74         }
    75       return "";
    76     }
    77     ///Return the reason for the failure
    78     Reason reason() const {return _reason; }
    79   };
    80 
    81 
    82   ///Command line arguments parser
    83 
    84   ///\ingroup misc
    85   ///Command line arguments parser.
    86   ///
    87   ///For a complete example see the \ref arg_parser_demo.cc demo file.
    88   class ArgParser {
    89 
    90     static void _showHelp(void *p);
    91   protected:
    92 
    93     int _argc;
    94     const char * const *_argv;
    95 
    96     enum OptType { UNKNOWN=0, BOOL=1, STRING=2, DOUBLE=3, INTEGER=4, FUNC=5 };
    97 
    98     class ParData {
    99     public:
   100       union {
   101         bool *bool_p;
   102         int *int_p;
   103         double *double_p;
   104         std::string *string_p;
   105         struct {
   106           void (*p)(void *);
   107           void *data;
   108         } func_p;
   109 
   110       };
   111       std::string help;
   112       bool mandatory;
   113       OptType type;
   114       bool set;
   115       bool ingroup;
   116       bool has_syn;
   117       bool syn;
   118       bool self_delete;
   119       ParData() : mandatory(false), type(UNKNOWN), set(false), ingroup(false),
   120                   has_syn(false), syn(false), self_delete(false) {}
   121     };
   122 
   123     typedef std::map<std::string,ParData> Opts;
   124     Opts _opts;
   125 
   126     class GroupData
   127     {
   128     public:
   129       typedef std::list<std::string> Opts;
   130       Opts opts;
   131       bool only_one;
   132       bool mandatory;
   133       GroupData() :only_one(false), mandatory(false) {}
   134     };
   135 
   136     typedef std::map<std::string,GroupData> Groups;
   137     Groups _groups;
   138 
   139     struct OtherArg
   140     {
   141       std::string name;
   142       std::string help;
   143       OtherArg(std::string n, std::string h) :name(n), help(h) {}
   144 
   145     };
   146 
   147     std::vector<OtherArg> _others_help;
   148     std::vector<std::string> _file_args;
   149     std::string _command_name;
   150 
   151 
   152   private:
   153     //Bind a function to an option.
   154 
   155     //\param name The name of the option. The leading '-' must be omitted.
   156     //\param help A help string.
   157     //\retval func The function to be called when the option is given. It
   158     //  must be of type "void f(void *)"
   159     //\param data Data to be passed to \c func
   160     ArgParser &funcOption(const std::string &name,
   161                     const std::string &help,
   162                     void (*func)(void *),void *data);
   163 
   164     bool _exit_on_problems;
   165 
   166     void _terminate(ArgParserException::Reason reason) const;
   167 
   168   public:
   169 
   170     ///Constructor
   171     ArgParser(int argc, const char * const *argv);
   172 
   173     ~ArgParser();
   174 
   175     ///\name Options
   176     ///
   177 
   178     ///@{
   179 
   180     ///Add a new integer type option
   181 
   182     ///Add a new integer type option.
   183     ///\param name The name of the option. The leading '-' must be omitted.
   184     ///\param help A help string.
   185     ///\param value A default value for the option.
   186     ///\param obl Indicate if the option is mandatory.
   187     ArgParser &intOption(const std::string &name,
   188                     const std::string &help,
   189                     int value=0, bool obl=false);
   190 
   191     ///Add a new floating point type option
   192 
   193     ///Add a new floating point type option.
   194     ///\param name The name of the option. The leading '-' must be omitted.
   195     ///\param help A help string.
   196     ///\param value A default value for the option.
   197     ///\param obl Indicate if the option is mandatory.
   198     ArgParser &doubleOption(const std::string &name,
   199                       const std::string &help,
   200                       double value=0, bool obl=false);
   201 
   202     ///Add a new bool type option
   203 
   204     ///Add a new bool type option.
   205     ///\param name The name of the option. The leading '-' must be omitted.
   206     ///\param help A help string.
   207     ///\param value A default value for the option.
   208     ///\param obl Indicate if the option is mandatory.
   209     ///\note A mandatory bool obtion is of very little use.
   210     ArgParser &boolOption(const std::string &name,
   211                       const std::string &help,
   212                       bool value=false, bool obl=false);
   213 
   214     ///Add a new string type option
   215 
   216     ///Add a new string type option.
   217     ///\param name The name of the option. The leading '-' must be omitted.
   218     ///\param help A help string.
   219     ///\param value A default value for the option.
   220     ///\param obl Indicate if the option is mandatory.
   221     ArgParser &stringOption(const std::string &name,
   222                       const std::string &help,
   223                       std::string value="", bool obl=false);
   224 
   225     ///Give help string for non-parsed arguments.
   226 
   227     ///With this function you can give help string for non-parsed arguments.
   228     ///The parameter \c name will be printed in the short usage line, while
   229     ///\c help gives a more detailed description.
   230     ArgParser &other(const std::string &name,
   231                      const std::string &help="");
   232 
   233     ///@}
   234 
   235     ///\name Options with External Storage
   236     ///Using this functions, the value of the option will be directly written
   237     ///into a variable once the option appears in the command line.
   238 
   239     ///@{
   240 
   241     ///Add a new integer type option with a storage reference
   242 
   243     ///Add a new integer type option with a storage reference.
   244     ///\param name The name of the option. The leading '-' must be omitted.
   245     ///\param help A help string.
   246     ///\param obl Indicate if the option is mandatory.
   247     ///\retval ref The value of the argument will be written to this variable.
   248     ArgParser &refOption(const std::string &name,
   249                     const std::string &help,
   250                     int &ref, bool obl=false);
   251 
   252     ///Add a new floating type option with a storage reference
   253 
   254     ///Add a new floating type option with a storage reference.
   255     ///\param name The name of the option. The leading '-' must be omitted.
   256     ///\param help A help string.
   257     ///\param obl Indicate if the option is mandatory.
   258     ///\retval ref The value of the argument will be written to this variable.
   259     ArgParser &refOption(const std::string &name,
   260                       const std::string &help,
   261                       double &ref, bool obl=false);
   262 
   263     ///Add a new bool type option with a storage reference
   264 
   265     ///Add a new bool type option with a storage reference.
   266     ///\param name The name of the option. The leading '-' must be omitted.
   267     ///\param help A help string.
   268     ///\param obl Indicate if the option is mandatory.
   269     ///\retval ref The value of the argument will be written to this variable.
   270     ///\note A mandatory bool obtion is of very little use.
   271     ArgParser &refOption(const std::string &name,
   272                       const std::string &help,
   273                       bool &ref, bool obl=false);
   274 
   275     ///Add a new string type option with a storage reference
   276 
   277     ///Add a new string type option with a storage reference.
   278     ///\param name The name of the option. The leading '-' must be omitted.
   279     ///\param help A help string.
   280     ///\param obl Indicate if the option is mandatory.
   281     ///\retval ref The value of the argument will be written to this variable.
   282     ArgParser &refOption(const std::string &name,
   283                       const std::string &help,
   284                       std::string &ref, bool obl=false);
   285 
   286     ///@}
   287 
   288     ///\name Option Groups and Synonyms
   289     ///
   290 
   291     ///@{
   292 
   293     ///Bundle some options into a group
   294 
   295     /// You can group some option by calling this function repeatedly for each
   296     /// option to be grouped with the same groupname.
   297     ///\param group The group name.
   298     ///\param opt The option name.
   299     ArgParser &optionGroup(const std::string &group,
   300                            const std::string &opt);
   301 
   302     ///Make the members of a group exclusive
   303 
   304     ///If you call this function for a group, than at most one of them can be
   305     ///given at the same time.
   306     ArgParser &onlyOneGroup(const std::string &group);
   307 
   308     ///Make a group mandatory
   309 
   310     ///Using this function, at least one of the members of \c group
   311     ///must be given.
   312     ArgParser &mandatoryGroup(const std::string &group);
   313 
   314     ///Create synonym to an option
   315 
   316     ///With this function you can create a synonym \c syn of the
   317     ///option \c opt.
   318     ArgParser &synonym(const std::string &syn,
   319                            const std::string &opt);
   320 
   321     ///@}
   322 
   323   private:
   324     void show(std::ostream &os,Opts::const_iterator i) const;
   325     void show(std::ostream &os,Groups::const_iterator i) const;
   326     void showHelp(Opts::const_iterator i) const;
   327     void showHelp(std::vector<OtherArg>::const_iterator i) const;
   328 
   329     void unknownOpt(std::string arg) const;
   330 
   331     void requiresValue(std::string arg, OptType t) const;
   332     void checkMandatories() const;
   333 
   334     void shortHelp() const;
   335     void showHelp() const;
   336   public:
   337 
   338     ///Start the parsing process
   339     ArgParser &parse();
   340 
   341     /// Synonym for parse()
   342     ArgParser &run()
   343     {
   344       return parse();
   345     }
   346 
   347     ///Give back the command name (the 0th argument)
   348     const std::string &commandName() const { return _command_name; }
   349 
   350     ///Check if an opion has been given to the command.
   351     bool given(std::string op) const
   352     {
   353       Opts::const_iterator i = _opts.find(op);
   354       return i!=_opts.end()?i->second.set:false;
   355     }
   356 
   357 
   358     ///Magic type for operator[]
   359 
   360     ///This is the type of the return value of ArgParser::operator[]().
   361     ///It automatically converts to \c int, \c double, \c bool or
   362     ///\c std::string if the type of the option matches, which is checked
   363     ///with an \ref LEMON_ASSERT "assertion" (i.e. it performs runtime
   364     ///type checking).
   365     class RefType
   366     {
   367       const ArgParser &_parser;
   368       std::string _name;
   369     public:
   370       ///\e
   371       RefType(const ArgParser &p,const std::string &n) :_parser(p),_name(n) {}
   372       ///\e
   373       operator bool()
   374       {
   375         Opts::const_iterator i = _parser._opts.find(_name);
   376         LEMON_ASSERT(i!=_parser._opts.end(),
   377                      std::string()+"Unkown option: '"+_name+"'");
   378         LEMON_ASSERT(i->second.type==ArgParser::BOOL,
   379                      std::string()+"'"+_name+"' is a bool option");
   380         return *(i->second.bool_p);
   381       }
   382       ///\e
   383       operator std::string()
   384       {
   385         Opts::const_iterator i = _parser._opts.find(_name);
   386         LEMON_ASSERT(i!=_parser._opts.end(),
   387                      std::string()+"Unkown option: '"+_name+"'");
   388         LEMON_ASSERT(i->second.type==ArgParser::STRING,
   389                      std::string()+"'"+_name+"' is a string option");
   390         return *(i->second.string_p);
   391       }
   392       ///\e
   393       operator double()
   394       {
   395         Opts::const_iterator i = _parser._opts.find(_name);
   396         LEMON_ASSERT(i!=_parser._opts.end(),
   397                      std::string()+"Unkown option: '"+_name+"'");
   398         LEMON_ASSERT(i->second.type==ArgParser::DOUBLE ||
   399                      i->second.type==ArgParser::INTEGER,
   400                      std::string()+"'"+_name+"' is a floating point option");
   401         return i->second.type==ArgParser::DOUBLE ?
   402           *(i->second.double_p) : *(i->second.int_p);
   403       }
   404       ///\e
   405       operator int()
   406       {
   407         Opts::const_iterator i = _parser._opts.find(_name);
   408         LEMON_ASSERT(i!=_parser._opts.end(),
   409                      std::string()+"Unkown option: '"+_name+"'");
   410         LEMON_ASSERT(i->second.type==ArgParser::INTEGER,
   411                      std::string()+"'"+_name+"' is an integer option");
   412         return *(i->second.int_p);
   413       }
   414 
   415     };
   416 
   417     ///Give back the value of an option
   418 
   419     ///Give back the value of an option.
   420     ///\sa RefType
   421     RefType operator[](const std::string &n) const
   422     {
   423       return RefType(*this, n);
   424     }
   425 
   426     ///Give back the non-option type arguments.
   427 
   428     ///Give back a reference to a vector consisting of the program arguments
   429     ///not starting with a '-' character.
   430     const std::vector<std::string> &files() const { return _file_args; }
   431 
   432     ///Throw instead of exit in case of problems
   433     void throwOnProblems()
   434     {
   435       _exit_on_problems=false;
   436     }
   437   };
   438 }
   439 
   440 #endif // LEMON_ARG_PARSER_H