An improved version of ArgParser: You don't need to give an explicit storage
authoralpar
Mon, 12 Mar 2007 13:26:56 +0000
changeset 2402da8eb8f4ea41
parent 2401 7f20ec638bc2
child 2403 b8f65d8528e1
An improved version of ArgParser: You don't need to give an explicit storage
for each option.
TODO: Documentation must be updated
demo/arg_parser_demo.cc
lemon/arg_parser.cc
lemon/arg_parser.h
tools/lgf-gen.cc
     1.1 --- a/demo/arg_parser_demo.cc	Wed Mar 07 13:32:12 2007 +0000
     1.2 +++ b/demo/arg_parser_demo.cc	Mon Mar 12 13:26:56 2007 +0000
     1.3 @@ -27,15 +27,15 @@
     1.4    double d;
     1.5    bool b,sil;
     1.6    bool g1,g2,g3;
     1.7 -  ap.option("n", "an integer input", i, true)
     1.8 -    .option("val", "a double input", d)
     1.9 +  ap.refOption("n", "an integer input", i, true)
    1.10 +    .refOption("val", "a double input", d)
    1.11      .synonym("vals","val")
    1.12 -    .option("name", "a string input", s)
    1.13 -    .option("f", "a switch", b)
    1.14 -    .option("nohelp", "", sil)
    1.15 -    .option("gra","Choise A",g1)
    1.16 -    .option("grb","Choise B",g2)
    1.17 -    .option("grc","Choise C",g3)
    1.18 +    .refOption("name", "a string input", s)
    1.19 +    .refOption("f", "a switch", b)
    1.20 +    .refOption("nohelp", "", sil)
    1.21 +    .refOption("gra","Choise A",g1)
    1.22 +    .refOption("grb","Choise B",g2)
    1.23 +    .refOption("grc","Choise C",g3)
    1.24      .optionGroup("gr","gra")
    1.25      .optionGroup("gr","grb")
    1.26      .optionGroup("gr","grc")
     2.1 --- a/lemon/arg_parser.cc	Wed Mar 07 13:32:12 2007 +0000
     2.2 +++ b/lemon/arg_parser.cc	Mon Mar 12 13:26:56 2007 +0000
     2.3 @@ -28,31 +28,59 @@
     2.4  
     2.5    ArgParser::ArgParser(int argc, char **argv) :_argc(argc), _argv(argv),
     2.6  					       _command_name(argv[0]) {
     2.7 -    option("-help","Print a short help message",_showHelp,this);
     2.8 +    refOption("-help","Print a short help message",_showHelp,this);
     2.9      synonym("help","-help");
    2.10      synonym("h","-help");
    2.11  
    2.12    }
    2.13  
    2.14 -  ArgParser &ArgParser::option(const std::string &name,
    2.15 +  ArgParser::~ArgParser()
    2.16 +  {
    2.17 +    for(Opts::iterator i=_opts.begin();i!=_opts.end();++i)
    2.18 +      if(i->second.self_delete)
    2.19 +	switch(i->second.type) {
    2.20 +	case BOOL:
    2.21 +	  delete i->second.bool_p;
    2.22 +	  break;
    2.23 +	case STRING:
    2.24 +	  delete i->second.string_p;
    2.25 +	  break;
    2.26 +	case DOUBLE:
    2.27 +	  delete i->second.double_p;
    2.28 +	  break;
    2.29 +	case INTEGER:
    2.30 +	  delete i->second.int_p;
    2.31 +	  break;
    2.32 +	case UNKNOWN:
    2.33 +	  break;
    2.34 +	case FUNC:
    2.35 +	  break;
    2.36 +	}
    2.37 +  }
    2.38 +  
    2.39 +
    2.40 +  ArgParser &ArgParser::intOption(const std::string &name,
    2.41  			       const std::string &help,
    2.42 -			       int &value, bool obl)
    2.43 +			       int value, bool obl)
    2.44    {
    2.45      ParData p;
    2.46 -    p.int_p=&value;
    2.47 +    p.int_p=new int(value);
    2.48 +    p.self_delete=true;
    2.49      p.help=help;
    2.50      p.type=INTEGER;
    2.51      p.mandatory=obl;
    2.52 +    p.self_delete=true;
    2.53      _opts[name]=p;
    2.54      return *this;
    2.55    }
    2.56  
    2.57 -  ArgParser &ArgParser::option(const std::string &name,
    2.58 +  ArgParser &ArgParser::doubleOption(const std::string &name,
    2.59  			       const std::string &help,
    2.60 -			       double &value, bool obl)
    2.61 +			       double value, bool obl)
    2.62    {
    2.63      ParData p;
    2.64 -    p.double_p=&value;
    2.65 +    p.double_p=new double(value);
    2.66 +    p.self_delete=true;
    2.67      p.help=help;
    2.68      p.type=DOUBLE;
    2.69      p.mandatory=obl;
    2.70 @@ -60,12 +88,13 @@
    2.71      return *this;
    2.72    }
    2.73  
    2.74 -  ArgParser &ArgParser::option(const std::string &name,
    2.75 +  ArgParser &ArgParser::boolOption(const std::string &name,
    2.76  			       const std::string &help,
    2.77 -			       bool &value, bool obl)
    2.78 +			       bool value, bool obl)
    2.79    {
    2.80      ParData p;
    2.81 -    p.bool_p=&value;
    2.82 +    p.bool_p=new bool(value);
    2.83 +    p.self_delete=true;
    2.84      p.help=help;
    2.85      p.type=BOOL;
    2.86      p.mandatory=obl;
    2.87 @@ -76,12 +105,13 @@
    2.88      return *this;
    2.89    }
    2.90  
    2.91 -  ArgParser &ArgParser::option(const std::string &name,
    2.92 +  ArgParser &ArgParser::stringOption(const std::string &name,
    2.93  			       const std::string &help,
    2.94 -			       std::string &value, bool obl)
    2.95 +			       std::string value, bool obl)
    2.96    {
    2.97      ParData p;
    2.98 -    p.string_p=&value;
    2.99 +    p.string_p=new std::string(value);
   2.100 +    p.self_delete=true;
   2.101      p.help=help;
   2.102      p.type=STRING;
   2.103      p.mandatory=obl;
   2.104 @@ -89,19 +119,80 @@
   2.105      return *this;
   2.106    }
   2.107  
   2.108 -  ArgParser &ArgParser::option(const std::string &name,
   2.109 +  ArgParser &ArgParser::refOption(const std::string &name,
   2.110 +			       const std::string &help,
   2.111 +			       int &value, bool obl)
   2.112 +  {
   2.113 +    ParData p;
   2.114 +    p.int_p=&value;
   2.115 +    p.self_delete=false;
   2.116 +    p.help=help;
   2.117 +    p.type=INTEGER;
   2.118 +    p.mandatory=obl;
   2.119 +    _opts[name]=p;
   2.120 +    return *this;
   2.121 +  }
   2.122 +
   2.123 +  ArgParser &ArgParser::refOption(const std::string &name,
   2.124 +			       const std::string &help,
   2.125 +			       double &value, bool obl)
   2.126 +  {
   2.127 +    ParData p;
   2.128 +    p.double_p=&value;
   2.129 +    p.self_delete=false;
   2.130 +    p.help=help;
   2.131 +    p.type=DOUBLE;
   2.132 +    p.mandatory=obl;
   2.133 +    _opts[name]=p;
   2.134 +    return *this;
   2.135 +  }
   2.136 +
   2.137 +  ArgParser &ArgParser::refOption(const std::string &name,
   2.138 +			       const std::string &help,
   2.139 +			       bool &value, bool obl)
   2.140 +  {
   2.141 +    ParData p;
   2.142 +    p.bool_p=&value;
   2.143 +    p.self_delete=false;
   2.144 +    p.help=help;
   2.145 +    p.type=BOOL;
   2.146 +    p.mandatory=obl;
   2.147 +    _opts[name]=p;
   2.148 +
   2.149 +    value = false;
   2.150 +
   2.151 +    return *this;
   2.152 +  }
   2.153 +
   2.154 +  ArgParser &ArgParser::refOption(const std::string &name,
   2.155 +			       const std::string &help,
   2.156 +			       std::string &value, bool obl)
   2.157 +  {
   2.158 +    ParData p;
   2.159 +    p.string_p=&value;
   2.160 +    p.self_delete=false;
   2.161 +    p.help=help;
   2.162 +    p.type=STRING;
   2.163 +    p.mandatory=obl;
   2.164 +    _opts[name]=p;
   2.165 +    return *this;
   2.166 +  }
   2.167 +
   2.168 +  ArgParser &ArgParser::refOption(const std::string &name,
   2.169  			       const std::string &help,
   2.170  			       void (*func)(void *),void *data)
   2.171    {
   2.172      ParData p;
   2.173      p.func_p.p=func;
   2.174      p.func_p.data=data;
   2.175 +    p.self_delete=false;
   2.176      p.help=help;
   2.177      p.type=FUNC;
   2.178      p.mandatory=false;
   2.179      _opts[name]=p;
   2.180      return *this;
   2.181    }
   2.182 +
   2.183    ArgParser &ArgParser::optionGroup(const std::string &group,
   2.184  				    const std::string &opt)
   2.185    {
   2.186 @@ -377,5 +468,5 @@
   2.187  
   2.188      return *this;
   2.189    }  
   2.190 -    
   2.191 +
   2.192  }
     3.1 --- a/lemon/arg_parser.h	Wed Mar 07 13:32:12 2007 +0000
     3.2 +++ b/lemon/arg_parser.h	Mon Mar 12 13:26:56 2007 +0000
     3.3 @@ -70,9 +70,9 @@
     3.4        bool ingroup;
     3.5        bool has_syn;
     3.6        bool syn;
     3.7 -	     
     3.8 +      bool self_delete;
     3.9        ParData() : mandatory(false), type(UNKNOWN), set(false), ingroup(false),
    3.10 -		  has_syn(false), syn(false) {}
    3.11 +		  has_syn(false), syn(false), self_delete(false) {}
    3.12      };
    3.13  
    3.14      typedef std::map<std::string,ParData> Opts;
    3.15 @@ -108,13 +108,59 @@
    3.16      ///\e
    3.17      ArgParser(int argc, char **argv);
    3.18  
    3.19 +    ~ArgParser();
    3.20 +
    3.21      ///Add a new integer type option
    3.22  
    3.23      ///\param name The name of the option. The leading '-' must be omitted.
    3.24      ///\param help A help string.
    3.25      ///\retval value The value of the argument will be written to this variable.
    3.26      ///\param obl Indicate if the option is mandatory.
    3.27 -    ArgParser &option(const std::string &name,
    3.28 +    ArgParser &intOption(const std::string &name,
    3.29 +		    const std::string &help,
    3.30 +		    int value=0, bool obl=false);
    3.31 +
    3.32 +    ///Add a new floating type option
    3.33 +
    3.34 +    ///\param name The name of the option. The leading '-' must be omitted.
    3.35 +    ///\param help A help string.
    3.36 +    ///\retval value The value of the argument will be written to this variable.
    3.37 +    ///\param obl Indicate if the option is mandatory.
    3.38 +    ArgParser &doubleOption(const std::string &name,
    3.39 +		      const std::string &help,
    3.40 +		      double value=0, bool obl=false);
    3.41 +
    3.42 +    ///Add a new bool type option
    3.43 +
    3.44 +    ///\param name The name of the option. The leading '-' must be omitted.
    3.45 +    ///\param help A help string.
    3.46 +    ///\retval value The value of the argument will be written to this variable.
    3.47 +    ///\param obl Indicate if the option is mandatory.
    3.48 +    ////\note A mandatory bool obtion is of very little use.)
    3.49 +    ArgParser &boolOption(const std::string &name,
    3.50 +		      const std::string &help,
    3.51 +		      bool value=false, bool obl=false);
    3.52 +
    3.53 +    ///Add a new string type option
    3.54 +
    3.55 +    ///\param name The name of the option. The leading '-' must be omitted.
    3.56 +    ///\param help A help string.
    3.57 +    ///\retval value The value of the argument will be written to this variable.
    3.58 +    ///\param obl Indicate if the option is mandatory.
    3.59 +    ArgParser &stringOption(const std::string &name,
    3.60 +		      const std::string &help,
    3.61 +		      std::string value="", bool obl=false);
    3.62 +    
    3.63 +
    3.64 +
    3.65 +
    3.66 +    ///Add a new integer type option
    3.67 +
    3.68 +    ///\param name The name of the option. The leading '-' must be omitted.
    3.69 +    ///\param help A help string.
    3.70 +    ///\retval value The value of the argument will be written to this variable.
    3.71 +    ///\param obl Indicate if the option is mandatory.
    3.72 +    ArgParser &refOption(const std::string &name,
    3.73  		    const std::string &help,
    3.74  		    int &value, bool obl=false);
    3.75  
    3.76 @@ -124,7 +170,7 @@
    3.77      ///\param help A help string.
    3.78      ///\retval value The value of the argument will be written to this variable.
    3.79      ///\param obl Indicate if the option is mandatory.
    3.80 -    ArgParser &option(const std::string &name,
    3.81 +    ArgParser &refOption(const std::string &name,
    3.82  		      const std::string &help,
    3.83  		      double &value, bool obl=false);
    3.84  
    3.85 @@ -135,7 +181,7 @@
    3.86      ///\retval value The value of the argument will be written to this variable.
    3.87      ///\param obl Indicate if the option is mandatory.
    3.88      ////\note A mandatory bool obtion is of very little use.)
    3.89 -    ArgParser &option(const std::string &name,
    3.90 +    ArgParser &refOption(const std::string &name,
    3.91  		      const std::string &help,
    3.92  		      bool &value, bool obl=false);
    3.93  
    3.94 @@ -145,7 +191,7 @@
    3.95      ///\param help A help string.
    3.96      ///\retval value The value of the argument will be written to this variable.
    3.97      ///\param obl Indicate if the option is mandatory.
    3.98 -    ArgParser &option(const std::string &name,
    3.99 +    ArgParser &refOption(const std::string &name,
   3.100  		      const std::string &help,
   3.101  		      std::string &value, bool obl=false);
   3.102      
   3.103 @@ -156,7 +202,7 @@
   3.104      ///\retval func The function to be called when the option is given. It
   3.105      ///  must be of type "void f(void *)"
   3.106      ///\param data Data to be passed to \c func
   3.107 -    ArgParser &option(const std::string &name,
   3.108 +    ArgParser &refOption(const std::string &name,
   3.109  		    const std::string &help,
   3.110  		    void (*func)(void *),void *data);
   3.111  
   3.112 @@ -232,7 +278,51 @@
   3.113        Opts::iterator i = _opts.find(op);
   3.114        return i!=_opts.end()?i->second.set:false;
   3.115      }
   3.116 +
   3.117 +
   3.118 +    class RefType 
   3.119 +    {
   3.120 +      ArgParser &_parser;
   3.121 +      std::string _name;
   3.122 +    public:
   3.123 +      RefType(ArgParser &p,const std::string &n) :_parser(p),_name(n) {}
   3.124 +      operator bool() 
   3.125 +      {
   3.126 +	Opts::iterator i = _parser._opts.find(_name);
   3.127 +	if(i==_parser._opts.end()) exit(3); ///\todo throw exception instead
   3.128 +	else if(i->second.type!=ArgParser::BOOL) exit(3);
   3.129 +	else return *(i->second.bool_p);
   3.130 +      }
   3.131 +      operator std::string()
   3.132 +      {
   3.133 +	Opts::iterator i = _parser._opts.find(_name);
   3.134 +	if(i==_parser._opts.end()) exit(3); ///\todo throw exception instead
   3.135 +	else if(i->second.type!=ArgParser::STRING) exit(3);
   3.136 +	else return *(i->second.string_p);
   3.137 +      }
   3.138 +      operator double() 
   3.139 +      {
   3.140 +	Opts::iterator i = _parser._opts.find(_name);
   3.141 +	if(i==_parser._opts.end()) exit(3); ///\todo throw exception instead
   3.142 +	else if(i->second.type!=ArgParser::DOUBLE) exit(3);
   3.143 +	else return *(i->second.double_p);
   3.144 +      }
   3.145 +      operator int() 
   3.146 +      {
   3.147 +	Opts::iterator i = _parser._opts.find(_name);
   3.148 +	if(i==_parser._opts.end()) exit(3); ///\todo throw exception instead
   3.149 +	else if(i->second.type!=ArgParser::INTEGER) exit(3);
   3.150 +	else return *(i->second.int_p);
   3.151 +      }
   3.152 +
   3.153 +    };
   3.154 +
   3.155 +    RefType operator[](const std::string &n)
   3.156 +    {
   3.157 +      return RefType(*this, n);
   3.158 +    }
   3.159      
   3.160 +      
   3.161    };
   3.162  }
   3.163  
     4.1 --- a/tools/lgf-gen.cc	Wed Mar 07 13:32:12 2007 +0000
     4.2 +++ b/tools/lgf-gen.cc	Mon Mar 12 13:26:56 2007 +0000
     4.3 @@ -29,6 +29,7 @@
     4.4  #include <cmath>
     4.5  #include <algorithm>
     4.6  #include <lemon/unionfind.h>
     4.7 +#include <lemon/time_measure.h>
     4.8  
     4.9  using namespace lemon;
    4.10  
    4.11 @@ -36,8 +37,10 @@
    4.12  
    4.13  UGRAPH_TYPEDEFS(ListUGraph);
    4.14  
    4.15 +bool progress=true;
    4.16 +
    4.17  int N;
    4.18 -int girth;
    4.19 +// int girth;
    4.20  
    4.21  ListUGraph g;
    4.22  
    4.23 @@ -234,31 +237,44 @@
    4.24  }
    4.25  
    4.26  void minTree() {
    4.27 +  int en=0;
    4.28 +  int pr=0;
    4.29    std::vector<Pedge> pedges;
    4.30 +  Timer T;
    4.31 +  std::cout << T.realTime() << "s: Setting up the edges...\n";
    4.32    for(NodeIt n(g);n!=INVALID;++n) 
    4.33 -    for(NodeIt m=++(NodeIt(n));m!=INVALID;++m)
    4.34 -      {
    4.35 -	Pedge p;
    4.36 -	p.a=n;
    4.37 -	p.b=m;
    4.38 -	p.len=(coords[m]-coords[n]).normSquare();
    4.39 -	pedges.push_back(p);
    4.40 -      }
    4.41 +    {
    4.42 +      for(NodeIt m=++(NodeIt(n));m!=INVALID;++m)
    4.43 +	{
    4.44 +	  Pedge p;
    4.45 +	  p.a=n;
    4.46 +	  p.b=m;
    4.47 +	  p.len=(coords[m]-coords[n]).normSquare();
    4.48 +	  pedges.push_back(p);
    4.49 +	}
    4.50 +      en++;
    4.51 +      if(progress && en>=pr*double(N)/100) 
    4.52 +	{
    4.53 +	  std::cout << pr << "%  \r" << std::flush;
    4.54 +	  pr++;
    4.55 +	}
    4.56 +    }
    4.57 +  std::cout << T.realTime() << "s: Sorting the edges...\n";
    4.58    std::sort(pedges.begin(),pedges.end(),pedgeLess);
    4.59 +  std::cout << T.realTime() << "s: Creating the tree...\n";
    4.60    ListUGraph::NodeMap<int> comp(g);
    4.61    UnionFind<ListUGraph::NodeMap<int> > uf(comp);
    4.62    for (NodeIt it(g); it != INVALID; ++it)
    4.63 -    uf.insert(it);
    4.64 -
    4.65 -  int en=0;
    4.66 +    uf.insert(it);  
    4.67    for(std::vector<Pedge>::iterator pi=pedges.begin();pi!=pedges.end();++pi)
    4.68      {
    4.69        if ( uf.join(pi->a,pi->b) ) {
    4.70  	g.addEdge(pi->a,pi->b);
    4.71 -	en++;
    4.72 -	if(en>=N-1) return;
    4.73 +	if(en>=N-1)
    4.74 +	  break;
    4.75        }
    4.76      }
    4.77 +  std::cout << T.realTime() << "s: Done\n";
    4.78  }
    4.79  
    4.80  
    4.81 @@ -267,34 +283,34 @@
    4.82  {
    4.83    ArgParser ap(argc,argv);
    4.84  
    4.85 -  bool eps;
    4.86 +//   bool eps;
    4.87    bool disc_d, square_d, gauss_d;
    4.88 -  bool tsp_a,two_a,tree_a;
    4.89 +//   bool tsp_a,two_a,tree_a;
    4.90    int num_of_cities=1;
    4.91    double area=1;
    4.92    N=100;
    4.93 -  girth=10;
    4.94 +//   girth=10;
    4.95    std::string ndist("disc");
    4.96 -  ap.option("n", "Number of nodes (default is 100)", N)
    4.97 -    .option("g", "Girth parameter (default is 10)", girth)
    4.98 -    .option("cities", "Number of cities (default is 1)", num_of_cities)
    4.99 -    .option("area", "Full relative area of the cities (default is 1)", area)
   4.100 -    .option("disc", "Nodes are evenly distributed on a unit disc (default)",disc_d)
   4.101 +  ap.refOption("n", "Number of nodes (default is 100)", N)
   4.102 +    .intOption("g", "Girth parameter (default is 10)", 10)
   4.103 +    .refOption("cities", "Number of cities (default is 1)", num_of_cities)
   4.104 +    .refOption("area", "Full relative area of the cities (default is 1)", area)
   4.105 +    .refOption("disc", "Nodes are evenly distributed on a unit disc (default)",disc_d)
   4.106      .optionGroup("dist", "disc")
   4.107 -    .option("square", "Nodes are evenly distributed on a unit square", square_d)
   4.108 +    .refOption("square", "Nodes are evenly distributed on a unit square", square_d)
   4.109      .optionGroup("dist", "square")
   4.110 -    .option("gauss",
   4.111 +    .refOption("gauss",
   4.112  	    "Nodes are located according to a two-dim gauss distribution",
   4.113  	    gauss_d)
   4.114      .optionGroup("dist", "gauss")
   4.115  //     .mandatoryGroup("dist")
   4.116      .onlyOneGroup("dist")
   4.117 -    .option("eps", "Also generate .eps output (prefix.eps)",eps)
   4.118 -    .option("2con", "Create a two connected planar graph",two_a)
   4.119 +    .boolOption("eps", "Also generate .eps output (prefix.eps)")
   4.120 +    .boolOption("2con", "Create a two connected planar graph")
   4.121      .optionGroup("alg","2con")
   4.122 -    .option("tree", "Create a min. cost spanning tree",tree_a)
   4.123 +    .boolOption("tree", "Create a min. cost spanning tree")
   4.124      .optionGroup("alg","tree")
   4.125 -    .option("tsp", "Create a TSP tour",tsp_a)
   4.126 +    .boolOption("tsp", "Create a TSP tour")
   4.127      .optionGroup("alg","tsp")
   4.128      .onlyOneGroup("alg")
   4.129      .other("[prefix]","Prefix of the output files. Default is 'lgf-gen-out'")
   4.130 @@ -352,18 +368,18 @@
   4.131  	}
   4.132      }
   4.133    
   4.134 -  if(tsp_a) {
   4.135 +  if(ap["tsp"]) {
   4.136      tsp();
   4.137      std::cout << "#2-opt improvements: " << tsp_impr_num << std::endl;
   4.138    }
   4.139 -  else if(two_a) {
   4.140 +  else if(ap["2con"]) {
   4.141      std::cout << "Make triangles\n";
   4.142      //   triangle();
   4.143 -    sparseTriangle(girth);
   4.144 +    sparseTriangle(ap["g"]);
   4.145      std::cout << "Make it sparser\n";
   4.146 -    sparse2(girth);
   4.147 +    sparse2(ap["g"]);
   4.148    }
   4.149 -  else if(tree_a) {
   4.150 +  else if(ap["tree"]) {
   4.151      minTree();
   4.152    }
   4.153    
   4.154 @@ -374,7 +390,7 @@
   4.155    for(UEdgeIt e(g);e!=INVALID;++e)
   4.156      tlen+=sqrt((coords[g.source(e)]-coords[g.target(e)]).normSquare());
   4.157    std::cout << "Total edge length  : " << tlen << std::endl;
   4.158 -  if(eps)
   4.159 +  if(ap["eps"])
   4.160      graphToEps(g,prefix+".eps").
   4.161        scale(600).nodeScale(.2).edgeWidthScale(.001).preScale(false).
   4.162        coords(coords).run();