LSSTApplications  10.0-2-g4f67435,11.0.rc2+1,11.0.rc2+12,11.0.rc2+3,11.0.rc2+4,11.0.rc2+5,11.0.rc2+6,11.0.rc2+7,11.0.rc2+8
LSSTDataManagementBasePackage
ConfigFile.h
Go to the documentation of this file.
1 #ifndef MeasAlgoShapeletConfigFile_H
2 #define MeasAlgoShapeletConfigFile_H
3 
4 #include <string>
5 #include <map>
6 #include <iostream>
7 #include <fstream>
8 #include <sstream>
9 #include <typeinfo>
10 #include <vector>
11 #include <algorithm>
12 #include <stdexcept>
13 #include <limits>
14 
17 
18 namespace lsst {
19 namespace meas {
20 namespace algorithms {
21 namespace shapelet {
22 
23 namespace {
24  // Check whether T is a bool, so we can handle it differently
25  template<typename T>
26  struct is_bool {
27  enum { value = false };
28  };
29 
30  template<>
31  struct is_bool<bool> {
32  enum { value = true };
33  };
34 }
35 
36 #ifdef __INTEL_COMPILER
37 #pragma warning (disable : 444)
38  // Disable "destructor for base class ... is not virtual"
39  // Technically, it is bad form to inherit from a class that doesn't have
40  // a virtual destructor. The reason is that an object that is only
41  // known as a reference or pointer to the base class won't call the
42  // derived class's destructor when it is deleted.
43  // A) This isn't a problem here, since ConvertibleString has no
44  // data elements that need to be cleaned up by a destructor.
45  // B) I can't find a way to avoid inheriting from std::string. When I
46  // instead keep a string variable, then I can't find a way to
47  // make assignment from ConvertibleString to string work correctly.
48  // The operator T() technique that we use for all other types
49  // fails, since the compiler can't disambiguate which string
50  // assignment operator to use this with.
51  // Specializing an operator string() case doesn't help.
52  // So the easiest solution is to leave this as is and just disable the warning.
53 #endif
54  class ConvertibleString : public std::string
55  {
56 
57  public:
58  ConvertibleString() : std::string("") {};
59  ConvertibleString(const std::string s) : std::string(s) {}
60 
61  template <typename T>
62  explicit ConvertibleString(const T& x)
63  { *this = x; }
64 
65  template <typename T>
66  explicit ConvertibleString(const std::vector<T>& x)
67  { *this = x; }
68 
70 
71  ConvertibleString& operator=(const std::string& rhs)
72  {
73  std::string::operator=(rhs);
74  return *this;
75  }
76 
77  template <typename T>
79  {
80  std::stringstream oss;
81  oss << x;
82  *this = oss.str();
83  return *this;
84  }
85 
86  template <typename T>
87  ConvertibleString& operator=(const std::vector<T>& x)
88  {
89  std::stringstream oss;
90  const int n = x.size();
91  if (n > 0) oss << x[0];
92  for(int i=1;i<n;++i) oss << ' ' << x[i];
93  *this = oss.str();
94  return *this;
95  }
96 
97  template <typename T>
98  operator T() const
99  {
100  // Handle bool specially
101  if (is_bool<T>::value) {
102  return operator_bool();
103  }
104 
105  // OK, not bool
106 #ifdef Use_Zero_Default
107  if (*this == "") return T();
108 #endif
109 
110  std::string err="Could not convert ConvertibleString to input type ";
111  err += typeid(T).name();
112  err += std::string(": this = ") + *this;
113  T temp;
114  std::stringstream ss(*this);
115 
116  // This bit is needed to get the oct and hex to work:
117  // I haven't incorporated it into the below vector conversion,
118  // so those always need to be decimal.
119  if (std::numeric_limits<T>::is_integer) {
120  if ((*this)[0] == '0') {
121  if ((*this)[1] == 'x' || (*this)[1] == 'X') {
122  ss >> std::hex;
123  } else {
124  ss >> std::oct;
125  }
126  }
127  }
128  ss >> temp;
129  if (!ss) {
130 #ifndef NOTHROW
131  std::cerr<<err<<std::endl;
132  exit(1);
133 #else
134  throw ParameterException(err);
135 #endif
136  }
137  return temp;
138  }
139 
140  template <typename T>
141  operator std::vector<T>() const
142  {
143 #ifdef Use_Zero_Default
144  if (*this == "") return std::vector<T>();
145 #endif
146 
147  std::string err="Could not convert ConvertibleString to input type ";
148  err += std::string("std::vector<")+typeid(T).name()+">";
149  err += std::string(": this = ") + *this;
150 
151  // Two syntaxes: "{1.,2.,3.}" or "1. 2. 3."
152  if ((*this)[0] == '{') {
153  // Using "{1.,2.,3.}" syntax
154 
155  int i1 = this->find_first_not_of(" \t\n\r\f",1);
156  if (i1 == int(std::string::npos)) {
157 #ifdef NOTHROW
158  std::cerr<<err<<std::endl;
159  exit(1);
160  return std::vector<T>();
161 #else
162  throw ParameterException(err);
163 #endif
164  }
165  if ((*this)[i1] == '}') {
166  // string is empty: "{ }"
167  return std::vector<T>();
168  }
169 
170  int nComma = std::count(this->begin(),this->end(),',');
171  std::vector<T> ret(nComma+1);
172 
173  int i2 = this->find_first_of("},",i1);
174  int j = 0;
175 
176  while ((*this)[i2] != '}') {
177  std::string s = this->substr(i1,i2-i1);
178  std::stringstream ss(s);
179  ss >> ret[j++];
180  i1 = i2+1;
181  i2 = this->find_first_of("},",i1);
182  }
183  {
184  // Do last element
185  std::string s = this->substr(i1,i2-i1);
186  std::stringstream ss(s);
187  ss >> ret[j];
188  }
189  if (j != nComma) {
190  throw ParameterException(err);
191  }
192  return ret;
193  } else {
194  // Using "1. 2. 3." syntax
195  std::stringstream ss(*this);
196  std::vector<T> ret;
197  T x;
198  while (ss >> x) ret.push_back(x);
199  return ret;
200  }
201  }
202 #ifdef __INTEL_COMPILER
203 #pragma warning (default : 444)
204 #endif
205 
206  private:
207  bool operator_bool() const
208  {
209 #ifdef Use_Zero_Default
210  if (*this == "") return false;
211 #endif
212 
213  // make string all caps
214  std::string sup = *this;
215  for ( std::string::iterator p = sup.begin(); p != sup.end(); ++p )
216  *p = toupper(*p);
217 
218  if ( sup=="FALSE" || sup=="F" || sup=="NO" || sup=="N" ||
219  sup=="0" || sup=="NONE" ) {
220  return false;
221  } else if ( sup=="TRUE" || sup=="T" || sup=="YES" || sup=="Y" ||
222  sup=="1" ) {
223  return true;
224  } else {
225  std::string err=
226  "Could not convert ConvertibleString to input type bool"
227  ": this = " + *this;
228 #ifdef NOTHROW
229  std::cerr<<err<<std::endl;
230  exit(1);
231  return false;
232 #else
233  throw ParameterException(err);
234 #endif
235  }
236  }
237  };
238 
239  class ConfigFile
240  {
241 
242  public:
243  // Create a blank config file with default values of delimiter, etc.
244  ConfigFile();
245 
246  // Create and read from the specified file
247  ConfigFile( const std::string fileName,
248  const std::string delimiter = "=",
249  const std::string comment = "#",
250  const std::string include = "+",
251  const std::string sentry = "EndConfigFile" );
252 
253  // Load more value from a file.
254  void load( const std::string fileName )
255  { std::ifstream fs(fileName.c_str()); read(fs); }
256 
257  // Load a file that uses different delimiter or comment or ...
258  // Note: these delimiter, comment, etc. are temporary for this load only.
259  // "" means use existing values
260  void load( const std::string fileName,
261  const std::string delimiter,
262  const std::string comment = "",
263  const std::string include = "",
264  const std::string sentry = "" );
265 
266  // Read more values from stream or a string:
267  void read(std::istream& is);
268  void append(const std::string& s)
269  { std::istringstream ss(s); read(ss); }
270 
271  // Write configuration
272  void write(std::ostream& os) const;
273  void writeAsComment(std::ostream& os) const;
274 
275  // Search for key and read value or optional default value
276  ConvertibleString& getNoCheck( const std::string& key );
277  ConvertibleString get( const std::string& key ) const;
278 
279  inline ConvertibleString& operator[]( const std::string& key )
280  { return getNoCheck(key); }
281  inline ConvertibleString operator[]( const std::string& key ) const
282  { return get(key); }
283 
284  template <typename T> inline T read( const std::string& key ) const;
285  template <typename T> inline T read(
286  const std::string& key, const T& value ) const;
287  template <typename T> inline bool readInto(
288  T& var, const std::string& key ) const;
289  template <typename T> inline bool readInto(
290  T& var, const std::string& key, const T& value ) const;
291 
292  // special string getter. This is really for the python
293  // bindings for just viewing quickly the contents. Hence
294  // also throwing const char* for now, which swig can easily
295  // deal with
296  std::string getstr(const std::string key) const throw (const char*);
297  // with default value
298  std::string getstr(
299  const std::string key,
300  const std::string defval);
301 
302  // Modify keys and values
303  template <typename T> inline void add( std::string key, const T& value );
304  void remove( const std::string& key );
305 
306  // Check whether key exists in configuration
307  bool keyExists( const std::string& key ) const;
308 
309  // Check or change configuration syntax
310  std::string getDelimiter() const { return _delimiter; }
311  std::string getComment() const { return _comment; }
312  std::string getInclude() const { return _include; }
313  std::string getSentry() const { return _sentry; }
314 
315  std::string setDelimiter( const std::string& s )
316  { std::string old = _delimiter; _delimiter = s; return old; }
317  std::string setComment( const std::string& s )
318  { std::string old = _comment; _comment = s; return old; }
319  std::string setInclude( const std::string& s )
320  { std::string old = _include; _include = s; return old; }
321  std::string setSentry( const std::string& s )
322  { std::string old = _sentry; _sentry = s; return old; }
323 
324  size_t size() { return _contents.size(); }
325 
326  protected:
327 
328  static void trim( std::string& s );
329 
330  std::string _delimiter; // separator between key and value
331  std::string _comment; // separator between value and comments
332  std::string _include; // directive for including another file
333  std::string _sentry; // optional string to signal end of file
334  std::map<std::string,ConvertibleString> _contents;
335  // extracted keys and values
336 
337  typedef std::map<std::string,ConvertibleString>::iterator MapIt;
338  typedef std::map<std::string,ConvertibleString>::const_iterator MapCIt;
339  };
340 
341  inline std::ostream& operator<<( std::ostream& os, const ConfigFile& cf )
342  { cf.write(os); return os; }
343  inline std::istream& operator>>( std::istream& is, ConfigFile& cf )
344  { cf.read(is); return is; }
345 
346  template <typename T>
347  T ConfigFile::read(const std::string& key) const
348  {
349  // Read the value corresponding to key
350  std::string key2 = key;
351  trim(key2);
352  MapCIt p = _contents.find(key2);
353  if(p == _contents.end()) {
354 #ifdef NOTHROW
355  std::cerr<<"Key not found: "<<key2<<std::endl;
356  exit(1);
357 #else
358  throw ParameterException(
359  "ConfigFile error: key "+key2+" not found");
360 #endif
361  }
362  T ret;
363  try {
364  ret = p->second;
365  } catch (ParameterException& e) {
366  xdbg<<"Caught ParameterException: \n"<<e.what()<<std::endl;
367  throw ParameterException(
368  "ConfigFile error: Could not convert entry for key " +
369  key2 +
370  " to given type.\nCaught error from ConvertibleString: \n" +
371  e.what());
372  }
373  return ret;
374  }
375 
376 
377  template <typename T>
378  T ConfigFile::read( const std::string& key, const T& value ) const
379  {
380  // Return the value corresponding to key or given default value
381  // if key is not found
382  std::string key2 = key;
383  trim(key2);
384  MapCIt p = _contents.find(key2);
385  if(p == _contents.end()) {
386  return value;
387  } else {
388  T ret;
389  try {
390  ret = p->second;
391  } catch (ParameterException& e) {
392  xdbg<<"Caught ParameterException: \n"<<e.what()<<std::endl;
393  throw ParameterException(
394  "ConfigFile error: Could not convert entry for key " +
395  key2 +
396  " to given type.\nCaught error from ConvertibleString: \n" +
397  e.what());
398  }
399  return ret;
400  }
401  }
402 
403 
404  template <typename T>
405  bool ConfigFile::readInto( T& var, const std::string& key ) const
406  {
407  // Get the value corresponding to key and store in var
408  // Return true if key is found
409  // Otherwise leave var untouched
410  std::string key2 = key;
411  trim(key2);
412  MapCIt p = _contents.find(key2);
413  bool isFound = ( p != _contents.end() );
414  if(isFound) {
415  try {
416  var = p->second;
417  } catch (ParameterException& e) {
418  xdbg<<"Caught ParameterException: \n"<<e.what()<<std::endl;
419  throw ParameterException(
420  "ConfigFile error: Could not convert entry for key " +
421  key2 +
422  " to given type.\nCaught error from ConvertibleString: \n" +
423  e.what());
424  }
425  }
426  return isFound;
427  }
428 
429 
430  template <typename T>
432  T& var, const std::string& key, const T& value ) const
433  {
434  // Get the value corresponding to key and store in var
435  // Return true if key is found
436  // Otherwise set var to given default
437  std::string key2 = key;
438  trim(key2);
439  MapCIt p = _contents.find(key2);
440  bool isFound = ( p != _contents.end() );
441  if(isFound) {
442  try {
443  var = p->second;
444  } catch (ParameterException& e) {
445  xdbg<<"Caught ParameterException: \n"<<e.what()<<std::endl;
446  throw ParameterException(
447  "ConfigFile error: Could not convert entry for key " +
448  key2 +
449  " to given type.\nCaught error from ConvertibleString: \n" +
450  e.what());
451  }
452  } else {
453  var = value;
454  }
455  return isFound;
456  }
457 
458  template <typename T>
459  void ConfigFile::add( std::string key, const T& value )
460  {
461  // Add a key with given value
462  trim(key);
463  _contents[key] = value;
464  }
465 
466 }}}}
467 
468 #endif // CONFIGFILE_H
table::Key< std::string > name
Definition: ApCorrMap.cc:71
ConvertibleString operator[](const std::string &key) const
Definition: ConfigFile.h:281
std::ostream & operator<<(std::ostream &os, const Position &pos)
Definition: Bounds.h:78
std::string setInclude(const std::string &s)
Definition: ConfigFile.h:319
std::string getstr(const std::string key) const
Definition: ConfigFile.cc:101
std::string setComment(const std::string &s)
Definition: ConfigFile.h:317
ConvertibleString & operator=(const T &x)
Definition: ConfigFile.h:78
void load(const std::string fileName)
Definition: ConfigFile.h:254
void write(std::ostream &os) const
Definition: ConfigFile.cc:156
bool keyExists(const std::string &key) const
Definition: ConfigFile.cc:139
std::map< std::string, ConvertibleString >::iterator MapIt
Definition: ConfigFile.h:337
ConvertibleString & operator=(const std::string &rhs)
Definition: ConfigFile.h:71
bool readInto(T &var, const std::string &key) const
Definition: ConfigFile.h:405
ConvertibleString & getNoCheck(const std::string &key)
Definition: ConfigFile.cc:72
int x
std::istream & operator>>(std::istream &os, Position &pos)
Definition: Bounds.h:81
ConvertibleString & operator[](const std::string &key)
Definition: ConfigFile.h:279
void writeAsComment(std::ostream &os) const
Definition: ConfigFile.cc:165
std::map< std::string, ConvertibleString > _contents
Definition: ConfigFile.h:334
std::map< std::string, ConvertibleString >::const_iterator MapCIt
Definition: ConfigFile.h:338
ConvertibleString & operator=(const std::vector< T > &x)
Definition: ConfigFile.h:87
#define xdbg
Definition: dbg.h:70
void add(std::string key, const T &value)
Definition: ConfigFile.h:459
std::string setSentry(const std::string &s)
Definition: ConfigFile.h:321
std::string setDelimiter(const std::string &s)
Definition: ConfigFile.h:315