17 #include <boost/optional.hpp> 41 boost::optional<alps::hdf5::archive> try_open_ar(
const std::string& fname,
const char* mode)
46 std::ifstream f(fname.c_str(),std::ios::binary);
47 if(!f.good())
return boost::none;
48 static const char hdf5_checksum[]={char(137),72,68,70,13,10,26,10};
49 char firstbytes[
sizeof(hdf5_checksum)];
50 f.read(firstbytes,
sizeof(firstbytes));
51 if(!f.good() || memcmp(hdf5_checksum, firstbytes,
sizeof(firstbytes))!=0)
return boost::none;
61 template <
typename MAP_T>
62 void ini_file_to_map(
const std::string& ini_name, MAP_T& map)
64 detail::iniparser parser(ini_name);
65 for(
const detail::iniparser::kv_pair& kv: parser()) {
67 std::string key=kv.first;
68 if (!key.empty() && key[0]==
'.') key.erase(0,1);
76 const std::string& strparam_val_;
79 typedef bool result_type;
82 strparam_val_(strparam_val), dictval_(dval)
85 template <
typename BOUND_T>
86 result_type operator()(
const BOUND_T& bound_val)
const 88 boost::optional<BOUND_T> maybe_val=detail::parse_string<BOUND_T>::apply(strparam_val_);
89 if (!maybe_val)
return false;
102 static const char Default_help_description[]=
"Print help message";
106 :
dictionary(), raw_kv_content_(), td_map_(), err_status_(), origins_(), help_header_()
108 read_ini_file_(inifile);
109 if (!
defined(
"help"))
define(
"help", Default_help_description);
122 initialize_(argc, argv, hdf5_path);
123 if (!
defined(
"help"))
define(
"help", Default_help_description);
129 return origins_.data().size()-origins_type::INIFILES;
135 return origins_.data()[origins_type::INIFILES+n];
140 return origins_.data()[origins_type::ARGV0];
145 if (!this->
is_restored())
throw std::runtime_error(
"The parameters object is not restored from an archive");
146 return origins_.data()[origins_type::ARCHNAME];
151 help_header_=message;
152 if (!
defined(
"help"))
define(
"help", Default_help_description);
156 bool params::has_unused_(std::ostream& out,
const std::string* prefix_ptr)
const 159 for(
const strmap::value_type& kv: raw_kv_content_) {
160 bool relevant = !prefix_ptr
161 || (prefix_ptr->empty() ? kv.first.find(
'.')==std::string::npos
162 : kv.first.find(*prefix_ptr+
".")==0);
163 if (relevant && !this->
exists(kv.first)) {
164 unused.push_back(kv.first+
" = "+kv.second);
167 if (!unused.empty()) {
168 out <<
"The following arguments are supplied, but never referenced:\n";
169 std::copy(unused.begin(), unused.end(), std::ostream_iterator<std::string>(out,
"\n"));
171 return !unused.empty();
176 return has_unused_(out, &subsection);
181 return has_unused_(out, 0);
186 out << help_header_ <<
"\nAvailable options:\n";
188 typedef std::pair<std::string, std::string> nd_pair;
189 typedef std::vector<nd_pair> nd_vector;
190 nd_vector name_and_description;
191 name_and_description.resize(td_map_.size());
192 std::string::size_type names_column_width=0;
195 for(
const td_map_type::value_type& tdp: td_map_) {
196 const std::string name_and_type=tdp.first +
" (" + tdp.second.typestr() +
"):";
197 if (names_column_width<name_and_type.size()) names_column_width=name_and_type.size();
199 std::ostringstream ostr;
201 ostr << tdp.second.descr();
202 if (this->
exists(tdp.first) && tdp.first!=
"help") {
203 ostr <<
" (default value: ";
204 print(ostr, (*
this)[tdp.first],
true) <<
")";
207 int defnum=tdp.second.defnumber();
208 if (defnum<0 || static_cast<unsigned int>(defnum)>=name_and_description.size()) {
209 std::ostringstream errmsg;
210 errmsg <<
"Invalid entry in parameters object.\n" 211 <<
"name='" << tdp.first
212 <<
"' defnumber=" << defnum;
213 throw std::logic_error(errmsg.str());
215 name_and_description[defnum]=std::make_pair(name_and_type, ostr.str());
219 std::ostream::fmtflags oldfmt=out.flags();
221 names_column_width += 4;
222 for(
const nd_pair& ndp: name_and_description) {
223 out << std::left << std::setw(names_column_width) << ndp.first << ndp.second <<
"\n";
232 return this->exists<bool>(
"help") && (*
this)[
"help"].as<
bool>();
244 if (this->
ok())
return false;
245 std::copy(err_status_.begin(), err_status_.end(), std::ostream_iterator<std::string>(out,
"\n"));
249 void params::initialize_(
int argc,
const char*
const * argv,
const char* hdf5_path)
252 typedef std::string::size_type size_type;
253 const size_type& npos=std::string::npos;
255 using boost::optional;
258 origins_.data()[origins_type::ARGV0].assign(argv[0]);
261 std::vector<string> all_args(argv+1,argv+argc);
262 std::stringstream cmd_options;
263 std::vector<string> ini_files;
264 optional<string> restored_from_archive;
265 bool file_args_mode=
false;
266 for(
const string& arg: all_args) {
267 if (file_args_mode) {
268 ini_files.push_back(arg);
271 size_type key_end=arg.find(
'=');
272 size_type key_begin=0;
273 if (arg.substr(0,2)==
"--") {
279 }
else if (arg.substr(0,1)==
"-") {
282 if (0==key_begin && npos==key_end) {
284 optional<alps::hdf5::archive> maybe_ar=try_open_ar(arg,
"r");
286 if (restored_from_archive) {
287 throw archive_conflict(
"More than one archive is specified in command line",
288 *restored_from_archive, arg);
290 maybe_ar->set_context(hdf5_path);
291 this->
load(*maybe_ar);
292 origins_.data()[origins_type::ARCHNAME]=arg;
293 restored_from_archive=arg;
298 ini_files.push_back(arg);
302 cmd_options << arg.substr(key_begin) <<
"=true\n";
304 cmd_options << arg.substr(key_begin) <<
"\n";
307 for (
auto fname: ini_files) {
308 read_ini_file_(fname);
314 std::ofstream tmpstream(tmpfile_name.c_str());
315 tmpstream << cmd_options.rdbuf();
317 ini_file_to_map(tmpfile_name, raw_kv_content_);
319 if (restored_from_archive) {
329 for (
auto& kv: *
this) {
330 const auto& key=kv.first;
331 auto raw_kv_it=raw_kv_content_.find(key);
332 if (raw_kv_it != raw_kv_content_.end()) {
333 bool ok=
apply_visitor(parse_visitor(raw_kv_it->second, const_cast<dictionary::value_type&>(kv.second)), kv.second);
335 const auto typestr=td_map_[key].typestr();
343 void params::read_ini_file_(
const std::string& inifile)
345 ini_file_to_map(inifile, raw_kv_content_);
346 origins_.data().push_back(inifile);
351 td_map_type::const_iterator it=td_map_.find(name);
352 return (td_map_.end()==it)? std::string() : it->second.descr();
361 (lhs.raw_kv_content_ == rhs.raw_kv_content_) &&
362 (lhs.td_map_ == rhs.td_map_) &&
363 (lhs.err_status_ == rhs.err_status_) &&
364 (lhs.help_header_ == rhs.help_header_) &&
365 (lhs_dict==rhs_dict);
374 std::vector<std::string> raw_keys, raw_vals;
375 raw_keys.reserve(raw_kv_content_.size());
376 raw_vals.reserve(raw_kv_content_.size());
377 for(
const strmap::value_type& kv: raw_kv_content_) {
378 raw_keys.push_back(kv.first);
379 raw_vals.push_back(kv.second);
381 ar[context+
"@ini_keys"] << raw_keys;
382 ar[context+
"@ini_values"] << raw_vals;
383 ar[context+
"@status"] << err_status_;
384 ar[context+
"@origins"] << origins_.data();
385 ar[context+
"@help_header"] << help_header_;
388 for(
const std::string& key: keys) {
389 td_map_type::const_iterator it=td_map_.find(key);
391 if (it!=td_map_.end()) {
392 ar[key+
"@description"] << it->second.descr();
393 ar[key+
"@defnumber"] << it->second.defnumber();
400 newpar.dictionary::load(ar);
404 ar[context+
"@status"] >> newpar.err_status_;
405 ar[context+
"@origins"] >> newpar.origins_.data();
406 newpar.origins_.check();
407 ar[context+
"@help_header"] >> newpar.help_header_;
411 typedef std::vector<std::string> stringvec;
412 stringvec raw_keys, raw_vals;
413 ar[context+
"@ini_keys"] >> raw_keys;
414 ar[context+
"@ini_values"] >> raw_vals;
415 if (raw_keys.size()!=raw_vals.size()) {
416 throw std::invalid_argument(
"params::load(): invalid ini-file data in HDF5 (size mismatch)");
418 stringvec::const_iterator key_it=raw_keys.begin();
419 stringvec::const_iterator val_it=raw_vals.begin();
420 for (; key_it!=raw_keys.end(); ++key_it, ++val_it) {
421 strmap::const_iterator insloc=newpar.raw_kv_content_.insert(newpar.raw_kv_content_.end(), std::make_pair(*key_it, *val_it));
422 if (insloc->second!=*val_it) {
423 throw std::invalid_argument(
"params::load(): invalid ini-file data in HDF5 (repeated key '"+insloc->first+
"')");
428 for(
const std::string& key: keys) {
429 const std::string d_attr=key+
"@description";
430 const std::string num_attr=key+
"@defnumber";
440 throw std::runtime_error(
"Invalid HDF5 format: missing attribute "+ num_attr);
444 if (newpar.
end()==it) {
445 throw std::logic_error(
"params::load(): loading the dictionary" 446 " missed key '"+key+
"'??");
448 std::string typestr=
apply_visitor(detail::make_typestr(), it);
449 newpar.td_map_.insert(std::make_pair(key, detail::td_type(typestr, descr, dn)));
460 template <
typename T>
461 inline std::ostream& operator<<(std::ostream& strm, const std::vector<T>& vec)
463 typedef std::vector<T> vtype;
464 typedef typename vtype::const_iterator itype;
467 itype it=vec.begin();
468 const itype
end=vec.end();
472 for (++it; end!=it; ++it) {
483 s <<
"[alps::params]" 484 <<
" origins=" << p.origins_.data() <<
" status=" << p.err_status_
487 s << kv.first <<
"=" << kv.second <<
"\n";
489 s <<
"[alps::params] Dictionary:\n";
491 const std::string& key=it->first;
493 s << key <<
" = " << val;
495 if (tdit!=p.td_map_.end()) {
496 s <<
" descr='" << tdit->second.descr()
497 <<
"' typestring='" << tdit->second.typestr() <<
"'" 498 <<
"' defnum=" << tdit->second.defnumber();
bool ok() const
No-errors status.
bool has_unused(std::ostream &out) const
True if there are parameters supplied but not defined; prints them out.
bool operator==(const params &rhs) const
Returns true if the objects are identical.
Parse sectioned INI file or HDF5 or command line, provide the results as dictionary.
friend std::ostream & operator<<(std::ostream &, const params &)
Prints parameters to a stream in an unspecified format.
void save(alps::hdf5::archive &) const
Saves parameter object to an archive.
bool defined(const std::string &name) const
Check whether a parameter was ever defined.
bool is_attribute(std::string path) const
params & define(const std::string &name, const std::string &descr)
Defines a parameter; returns false on error, and records the error in the object. ...
const_iterator begin() const
Const-iterator to the beginning of the contained map.
std::ostream & print_help(std::ostream &) const
Print help to the given stream.
void broadcast(C const &c, P &p, int r=0)
void swap(params &p1, params &p2)
std::string get_ini_name(int n) const
Access to ini file names (if any); returns empty string if out of range.
Encapsulation of an MPI communicator and some communicator-related operations.
void load(alps::hdf5::archive &)
Loads parameter object form an archive.
F::result_type apply_visitor(F &visitor, dictionary::const_iterator it)
Const-access visitor to a value by an iterator.
int get_ini_name_count() const
Returns the number of ini file names.
params()
Default ctor: creates an empty parameters object.
const std::string get_descr(const std::string &name) const
Returns a string describing the parameter (or an empty string)
std::string origin_name(const params &p)
Convenience function to obtain the "origin" filename associated with the parameters object...
std::string get_archive_name() const
Convenience method: returns the archive name the object has been restored from, or throws...
Exception type: attempt to restore from 2 archives.
bool has_missing() const
True if there are missing or wrong-type parameters.
params & description(const std::string &message)
Sets a description for the help message and introduces "--help" flag (if not already defined) ...
void save(alps::hdf5::archive &ar) const
Save the dictionary to an archive.
std::string get_basename(const std::string &path)
Returns the base name of the file (removing leading directories)
bool is_restored() const
Conveninece method: true if the object was restored from an archive.
std::ostream & print(std::ostream &s, const dict_value &dv, bool terse)
std::string get_context() const
Header for object-oriented interface to MPI for std::pair.
std::vector< std::string > list_children(std::string path) const
std::string temporary_filename(const std::string &prefix)
Generate a reasonably unique file name with a given prefix.
Exception for value mismatch.
const_iterator end() const
Const-iterator to the end of the contained map.
void broadcast(const communicator &comm, T *vals, std::size_t count, int root)
Broadcasts array vals of a primitive type T, length count on communicator comm with root root ...
bool exists(const std::string &key) const
Check if a key exists and has a value (without creating the key)
std::string get_argv0() const
Access to argv[0] (returns empty string if unknown)
friend void swap(params &p1, params &p2)
const_iterator find(const std::string &key) const
Obtain read-only iterator to a name.
detail::None None
"Empty value" type
map_type::const_iterator const_iterator
Header for object-oriented interface to MPI for std::map.
bool help_requested() const
True if user requested help.