msbGrid  1.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
parametertree.hh
Go to the documentation of this file.
1 /*****************************************************************************
2 * This program is part of the msbGrid software *
3 * *
4 * msbGrid stands for multi-structured block Grid generator *
5 * *
6 * msbGrid is a free software: you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation, either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * msbGrid is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * See the file COPYING for full copying permissions. *
17 *****************************************************************************/
23 #include <iostream>
24 #include <sstream>
25 #include <algorithm>
26 #include <vector>
27 #include <map>
28 
29 #include <classname.hh>
30 
31 #ifndef _PARAMETER_TREE_HH_
32 #define _PARAMETER_TREE_HH_
33 
34 namespace msbGrid
35 {
36 class ParameterTree;
37 } /* namespace msbGrid */
38 
39 class msbGrid :: ParameterTree
40 {
41  template< typename T >
42  struct Parser;
43 public:
44 
45  typedef std :: vector< std :: string > KeyVector;
46 
47  ParameterTree();
48 
49  static ParameterTree &tree()
50  {
51  static ParameterTree obj_;
52  return obj_;
53  }
54 
55  bool hasKey(const std :: string &key) const;
56 
57  bool hasSub(const std :: string &sub) const;
58 
59  std :: string &operator[] ( const std :: string & key );
60 
61  const std :: string &operator[] ( const std :: string & key ) const;
62 
63  void report(std :: ostream &stream = std :: cout, const std :: string &prefix = "") const;
64 
65  ParameterTree &sub(const std :: string &sub);
66 
67  const ParameterTree &sub(const std :: string &sub) const;
68 
69  std :: string get(const std :: string &key, const std :: string &defaultValue) const;
70 
71  std :: string get(const std :: string &key, const char *defaultValue) const;
72 
73  int get(const std :: string &key, int defaultValue) const;
74 
75  double get(const std :: string &key, double defaultValue) const;
76 
86  template< typename T >
87  T get(const std :: string &key, const T &defaultValue) const
88  {
89  if ( hasKey(key) ) {
90  return get< T >(key);
91  } else {
92  return defaultValue;
93  }
94  }
95 
104  template< class T >
105  T get(const std :: string &key) const
106  {
107  if ( not hasKey(key) ) {
108  std :: cerr << "MSBGRID_THROW : Key '" << key << "' not found in parameter file!\nCalling exit(1)\n";
109  exit(1);
110  }
111 
112  return Parser< T > :: parse( ( * this ) [ key ] );
113 
114  try {
115  return Parser< T > :: parse( ( * this ) [ key ] );
116  }
117 
118  catch(int x)
119  {
120  if ( x == 1 ) {
121  std :: cerr << "MSBGRID_THROW : Cannot parse value \"" << ( * this ) [ key ] << "\" for key \"" << key << "\" as a " << className< T >() << "\nCalling exit(1)\n";
122  exit(1);
123  }
124  }
125  }
126 
127  const KeyVector &getValueKeys() const;
128 
129  const KeyVector &getSubKeys() const;
130 
131 protected:
134 
135  std :: map< std :: string, std :: string > values;
136  std :: map< std :: string, ParameterTree > subs;
137  static std :: string ltrim(const std :: string &s);
138  static std :: string rtrim(const std :: string &s);
139  static std :: vector< std :: string > split(const std :: string &s);
140 
141  // parse into a fixed-size range of iterators
142  template< class Iterator >
143  static void parseRange(const std :: string &str, Iterator it, const Iterator &end)
144  {
145  typedef typename std :: iterator_traits< Iterator > :: value_type Value;
146  std :: istringstream s(str);
147  std :: size_t n = 0;
148  for ( ; it != end; ++it, ++n ) {
149  s >> * it;
150  if ( !s ) {
151  std :: cerr << "Cannot parse value \"" << str << "\" as a range of items of type "
152  << className< Value >() << " (" << n << " items were extracted successfully)\nCalling exit(1)\n";
153  exit(1);
154  }
155  }
156 
157  Value dummy;
158  s >> dummy;
159  // now extraction should have failed, and eof should be set
160  if ( not s.fail() or not s.eof() ) {
161  std :: cerr << "Cannot parse value \"" << str << "\" as a range of " << n << " items of type "
162  << className< Value >() << " (more items than the range can hold)\nCalling exit(1)\n";
163  exit(1);
164  }
165  }
166 };
167 
169 {}
170 
171 void msbGrid :: ParameterTree :: report(std :: ostream &stream, const std :: string &prefix) const
172 {
173  typedef std :: map< std :: string, std :: string > :: const_iterator ValueIt;
174  ValueIt vit = values.begin();
175  ValueIt vend = values.end();
176 
177  for ( ; vit != vend; ++vit ) {
178  stream << vit->first << " = \"" << vit->second << "\"" << std :: endl;
179  }
180 
181  typedef std :: map< std :: string, ParameterTree > :: const_iterator SubIt;
182  SubIt sit = subs.begin();
183  SubIt send = subs.end();
184  for ( ; sit != send; ++sit ) {
185  stream << "[ " << prefix + sit->first << " ]" << std :: endl;
186  ( sit->second ).report(stream, prefix + sit->first + ".");
187  }
188 }
189 
190 bool msbGrid :: ParameterTree :: hasKey(const std :: string &key) const
191 {
192  std :: string :: size_type dot = key.find(".");
193 
194  if ( dot != std :: string :: npos ) {
195  std :: string prefix = key.substr(0, dot);
196  if ( subs.count(prefix) == 0 ) {
197  return false;
198  }
199 
200  const ParameterTree &s = sub(prefix);
201  return s.hasKey( key.substr(dot + 1) );
202  } else {
203  return ( values.count(key) != 0 );
204  }
205 }
206 
207 bool msbGrid :: ParameterTree :: hasSub(const std :: string &key) const
208 {
209  std :: string :: size_type dot = key.find(".");
210 
211  if ( dot != std :: string :: npos ) {
212  std :: string prefix = key.substr(0, dot);
213  if ( subs.count(prefix) == 0 ) {
214  return false;
215  }
216 
217  const ParameterTree &s = sub(prefix);
218  return s.hasSub( key.substr(dot + 1) );
219  } else {
220  return ( subs.count(key) != 0 );
221  }
222 }
223 
225 {
226  std :: string :: size_type dot = key.find(".");
227 
228  if ( dot != std :: string :: npos ) {
229  ParameterTree &s = sub( key.substr(0, dot) );
230  return s.sub( key.substr(dot + 1) );
231  } else {
232  if ( subs.count(key) == 0 ) {
233  subKeys.push_back( key.substr(0, dot) );
234  }
235 
236  return subs [ key ];
237  }
238 }
239 
240 const msbGrid :: ParameterTree &msbGrid :: ParameterTree :: sub(const std :: string &key) const
241 {
242  std :: string :: size_type dot = key.find(".");
243 
244  if ( dot != std :: string :: npos ) {
245  const ParameterTree &s = sub( key.substr(0, dot) );
246  return s.sub( key.substr(dot + 1) );
247  } else {
248  if ( subs.count(key) == 0 ) {
249  std :: cerr << "Key '" << key << "' not found in ParameterTree\nCalling exit(1)\n";
250  exit(1);
251  }
252 
253  return subs.find(key)->second;
254  }
255 }
256 
257 std :: string &msbGrid :: ParameterTree :: operator[] ( const std :: string & key )
258 {
259  std :: string :: size_type dot = key.find(".");
260 
261  if ( dot != std :: string :: npos ) {
262  if ( not ( hasSub( key.substr(0, dot) ) ) ) {
263  subs [ key.substr(0, dot) ];
264  subKeys.push_back( key.substr(0, dot) );
265  }
266 
267  ParameterTree &s = sub( key.substr(0, dot) );
268  return s [ key.substr(dot + 1) ];
269  } else {
270  if ( not ( hasKey(key) ) ) {
271  valueKeys.push_back(key);
272  }
273 
274  return values [ key ];
275  }
276 }
277 
278 const std :: string &msbGrid :: ParameterTree :: operator[] ( const std :: string & key ) const
279 {
280  std :: string :: size_type dot = key.find(".");
281 
282  if ( dot != std :: string :: npos ) {
283  if ( not ( hasSub( key.substr(0, dot) ) ) ) {
284  std :: cerr << "Key '" << key << "' not found in ParameterTree\nCalling exit(1)\n";
285  exit(1);
286  }
287 
288  const ParameterTree &s = sub( key.substr(0, dot) );
289  return s [ key.substr(dot + 1) ];
290  } else {
291  if ( not ( hasKey(key) ) ) {
292  std :: cerr << "Key '" << key << "' not found in ParameterTree\nCalling exit(1)\n";
293  exit(1);
294  }
295 
296  return values.find(key)->second;
297  }
298 }
299 
300 std :: string msbGrid :: ParameterTree :: get(const std :: string &key, const std :: string &defaultValue) const
301 {
302  if ( hasKey(key) ) {
303  return ( * this ) [ key ];
304  } else {
305  return defaultValue;
306  }
307 }
308 
309 std :: string msbGrid :: ParameterTree :: get(const std :: string &key, const char *defaultValue) const
310 {
311  if ( hasKey(key) ) {
312  return ( * this ) [ key ];
313  } else {
314  return defaultValue;
315  }
316 }
317 
318 int msbGrid :: ParameterTree :: get(const std :: string &key, int defaultValue) const
319 {
320  std :: stringstream stream;
321  stream << defaultValue;
322  std :: string ret = get( key, stream.str() );
323 
324  return atoi( ret.c_str() );
325 }
326 
327 double msbGrid :: ParameterTree :: get(const std :: string &key, double defaultValue) const
328 {
329  if ( hasKey(key) ) {
330  return atof( ( * this ) [ key ].c_str() );
331  } else {
332  return defaultValue;
333  }
334 }
335 
336 std :: string msbGrid :: ParameterTree :: ltrim(const std :: string &s)
337 {
338  std :: size_t firstNonWS = s.find_first_not_of(" \t\n\r");
339 
340  if ( firstNonWS != std :: string :: npos ) {
341  return s.substr(firstNonWS);
342  }
343 
344  return std :: string();
345 }
346 
347 std :: string msbGrid :: ParameterTree :: rtrim(const std :: string &s)
348 {
349  std :: size_t lastNonWS = s.find_last_not_of(" \t\n\r");
350 
351  if ( lastNonWS != std :: string :: npos ) {
352  return s.substr(0, lastNonWS + 1);
353  }
354 
355  return std :: string();
356 }
357 
358 std :: vector< std :: string > msbGrid :: ParameterTree :: split(const std :: string &s)
359 {
360  std :: vector< std :: string > substrings;
361  std :: size_t front = 0, back = 0, size = 0;
362 
363  while ( front != std :: string :: npos ) {
364  // find beginning of substring
365  front = s.find_first_not_of(" \t\n\r", back);
366  back = s.find_first_of(" \t\n\r", front);
367  size = back - front;
368  if ( size > 0 ) {
369  substrings.push_back( s.substr(front, size) );
370  }
371  }
372 
373  return substrings;
374 }
375 
377 {
378  return valueKeys;
379 }
380 
382 {
383  return subKeys;
384 }
385 
386 template< typename T >
387 struct msbGrid :: ParameterTree :: Parser
388 {
389  static T parse(const std :: string &str)
390  {
391  T val;
392  std :: istringstream s(str);
393  s >> val;
394  if ( !s ) {
395  std :: cerr << "Cannot parse value \"" << str << "\" as a " << className< T >() << "\nCalling exit(1)\n";
396  exit(1);
397  }
398 
399  T dummy;
400  s >> dummy;
401 
402  // now extraction should have failed, and eof should be set
403  if ( not s.fail() or not s.eof() ) {
404  std :: cerr << "Cannot parse value \"" << str << "\" as a " << className< T >() << "\nCalling exit(1)\n";
405  exit(1);
406  }
407 
408  return val;
409  }
410 };
411 
412 namespace msbGrid
413 {
414 template< typename traits, typename Allocator >
415 struct ParameterTree :: Parser< std :: basic_string< char, traits, Allocator > >
416 {
417  static std :: basic_string< char, traits, Allocator >
418  parse(const std :: string &str)
419  {
420  std :: string trimmed = ltrim( rtrim(str) );
421  return std :: basic_string< char, traits, Allocator >( trimmed.begin(), trimmed.end() );
422  }
423 };
424 
425 template< >
426 struct ParameterTree :: Parser< bool >
427 {
428  struct ToLower
429  {
430  int operator() (int c)
431  {
432  return std :: tolower(c);
433  }
434  };
435 
436  static bool
437  parse(const std :: string &str)
438  {
439  std :: string ret = str;
440 
441  std :: transform( ret.begin(), ret.end(), ret.begin(), ToLower() );
442 
443  if ( ret == "yes" || ret == "true" ) {
444  return true;
445  }
446 
447  if ( ret == "no" || ret == "false" ) {
448  return false;
449  }
450 
451  return ( Parser< int > :: parse(ret) != 0 );
452  }
453 };
454 
455 template< typename T, typename A >
456 struct ParameterTree :: Parser< std :: vector< T, A > >
457 {
458  static std :: vector< T, A >
459  parse(const std :: string &str)
460  {
461  std :: vector< std :: string > sub = split(str);
462  std :: vector< T, A > vec;
463  for ( unsigned int i = 0; i < sub.size(); ++i ) {
464  T val = ParameterTree :: Parser< T > :: parse(sub [ i ]);
465  vec.push_back(val);
466  }
467 
468  return vec;
469  }
470 };
471 }
472 
473 #endif /* #ifndef _PARAMETER_TREE_HH_ */