Flow123d
type_base.cc
Go to the documentation of this file.
1 /*
2  * input_type.cc
3  *
4  * Created on: Mar 29, 2012
5  * Author: jb
6  */
7 
8 
9 
10 #include <limits>
11 #include <ios>
12 #include <map>
13 #include <vector>
14 #include <string>
15 #include <iomanip>
16 
17 #include "system/system.hh"
18 
19 #include <boost/type_traits.hpp>
20 #include <boost/tokenizer.hpp>
21 #include <boost/shared_ptr.hpp>
22 #include <boost/make_shared.hpp>
23 #include <boost/algorithm/string.hpp>
24 
25 #include "type_base.hh"
26 #include "type_record.hh"
27 #include "type_output.hh"
28 #include <boost/algorithm/string.hpp>
29 
30 
31 namespace Input {
32 namespace Type {
33 
34 using namespace std;
35 
36 
37 
38 /*******************************************************************
39  * implementation of TypeBase
40  */
41 
42 
43 
45  TypeBase::lazy_object_set().insert(this);
46 }
47 
48 
49 
51 {
52  TypeBase::lazy_object_set().insert(this);
53 }
54 
55 
56 
59  TypeBase::LazyObjectsSet::iterator it =set.find(this);
60  ASSERT( it != set.end(), "Missing pointer in lazy_object_set to '%s'.\n", this->type_name().c_str());
61  TypeBase::lazy_object_set().erase(it);
62 }
63 
64 
65 bool TypeBase::is_valid_identifier(const string& key) {
66  namespace ba = boost::algorithm;
67  return ba::all( key, ba::is_lower() || ba::is_digit() || ba::is_any_of("_") );
68 }
69 
70 
71 string TypeBase::desc() const {
72  stringstream ss;
73  ss << OutputText(this,1);
74  return ss.str();
75 }
76 
77 
78 
80  static LazyTypeVector lazy_type_list;
81  return lazy_type_list;
82 }
83 
84 
85 
87  // TODO: dynamic cast as the switch may be expensive, in such case use some notification about type
88 
89  // first finish all lazy input types save Selection (we have to leave open Selection in AbstractType key TYPE)
90  for (LazyTypeVector::iterator it=lazy_type_list().begin(); it!=lazy_type_list().end(); it++) {
91  if (boost::dynamic_pointer_cast<Selection>(*it) == 0) {
92  (*it)->finish();
93  }
94  }
95 
96  // then finalize abstract records so that no type can derive from them
97  for (LazyTypeVector::iterator it=lazy_type_list().begin(); it!=lazy_type_list().end(); it++)
98  {
99  boost::shared_ptr<AbstractRecord> a_rec_ptr = boost::dynamic_pointer_cast<AbstractRecord>(*it);
100  if ( a_rec_ptr!= 0) a_rec_ptr->no_more_descendants();
101  }
102 
103  // at last finish all selections (including those in AbstractRecord)
104  for (LazyTypeVector::iterator it=lazy_type_list().begin(); it!=lazy_type_list().end(); it++) {
105  if (! (*it)->finish()) xprintf(PrgErr, "Can not finish '%s' during lazy_finish.\n", (*it)->type_name().c_str() );
106  }
107 
108  lazy_type_list().clear();
109 
110 }
111 
112 
113 
114 
116  static LazyObjectsSet set_;
117  return set_;
118 }
119 
120 
121 
123  return lazy_object_set().find(ptr) != lazy_object_set().end();
124 }
125 
126 
127 
128 std::ostream& operator<<(std::ostream& stream, const TypeBase& type) {
129  return ( stream << OutputText(&type, 1) );
130 }
131 
132 
133 
134 /**********************************************************************************
135  * implementation of Type::Array
136  */
137 
138 
140  return data_->finish();
141 }
142 
143 
144 
146 {
147  if (finished) return true;
148 
149  if (p_type_of_values != 0)
150  {
151  if (! was_constructed(p_type_of_values) ) return false;
152 
153  if (dynamic_cast<const AbstractRecord *>(p_type_of_values) != 0)
154  {
155  AbstractRecord *ar = (AbstractRecord *)dynamic_cast<const AbstractRecord *>(p_type_of_values);
156  boost::shared_ptr<const TypeBase> type_copy = boost::make_shared<const AbstractRecord>(*ar);
157  type_of_values_ = type_copy;
158  p_type_of_values = 0;
159  }
160  else if (dynamic_cast<const Record *>(p_type_of_values) != 0)
161  {
162  Record *r = (Record *)dynamic_cast<const Record *>(p_type_of_values);
163  boost::shared_ptr<const TypeBase> type_copy = boost::make_shared<const Record>(*r);
164  type_of_values_ = type_copy;
165  p_type_of_values = 0;
166  }
167  else if (dynamic_cast<const Selection *>(p_type_of_values) != 0)
168  {
169  Selection *s = (Selection *)dynamic_cast<const Selection *>(p_type_of_values);
170  boost::shared_ptr<const TypeBase> type_copy = boost::make_shared<const Selection>(*s);
171  type_of_values_ = type_copy;
172  p_type_of_values = 0;
173  }
174  else if (dynamic_cast<const Array *>(p_type_of_values) != 0)
175  xprintf(PrgErr, "Should not happen!\n");
176  /*
177  Array *a = (Array *)dynamic_cast<const Array *>(p_type_of_values);
178  boost::shared_ptr<const TypeBase> type_copy = boost::make_shared<const Array>(*a);
179  type_of_values_ = type_copy;
180  p_type_of_values = 0;*/
181 
182  }
183 
184  return (finished = true);
185 }
186 
187 
188 
189 string Array::type_name() const {
190  return "array_of_" + data_->type_of_values_->type_name();
191 }
192 
193 string Array::full_type_name() const {
194  return "array_of_" + data_->type_of_values_->type_name();
195 }
196 
197 
198 
199 bool Array::operator==(const TypeBase &other) const {
200  return typeid(*this) == typeid(other) &&
201  (*data_->type_of_values_ == static_cast<const Array *>(&other)->get_sub_type() );
202 }
203 
204 
205 
206 bool Array::valid_default(const string &str) const {
207  if ( this->match_size( 1 ) ) {
208  return get_sub_type().valid_default( str );
209  } else {
210  THROW( ExcWrongDefault() << EI_DefaultStr( str ) << EI_TypeName(type_name()));
211  }
212 }
213 
214 
215 /**********************************************************************************
216  * implementation and explicit instantiation of Array constructor template
217  */
218 
219 template <class ValueType>
220 Array::Array(const ValueType &type, unsigned int min_size, unsigned int max_size)
221 : data_(boost::make_shared<ArrayData>(min_size, max_size))
222 {
223  // ASSERT MESSAGE: The type of declared keys has to be a class derived from TypeBase.
224  BOOST_STATIC_ASSERT( (boost::is_base_of<TypeBase, ValueType >::value) );
225  ASSERT( min_size <= max_size, "Wrong limits for size of Input::Type::Array, min: %d, max: %d\n", min_size, max_size);
226 
227  // Records, AbstractRecords and Selections need not be initialized
228  // at the moment, so we save the reference of type and update
229  // the array later in finish().
230  if ( (boost::is_base_of<Record, ValueType>::value ||
231  boost::is_base_of<Selection, ValueType>::value)
232  && ! TypeBase::was_constructed(&type) ) {
233  //xprintf(Warn,"In construction of Array of Lazy type %s with copy declaration. Potential problem with order of static initializations.\n",
234  // type.type_name().c_str());
235  data_->p_type_of_values = &type;
236  TypeBase::lazy_type_list().push_back( boost::make_shared<Array>( *this ) );
237  } else {
238  data_->p_type_of_values = NULL;
239  boost::shared_ptr<const TypeBase> type_copy = boost::make_shared<ValueType>(type);
240  data_->type_of_values_ = type_copy;
241  data_->finished=true;
242  }
243 }
244 
245 // explicit instantiation
246 
247 #define ARRAY_CONSTRUCT(TYPE) \
248 template Array::Array(const TYPE &type, unsigned int min_size, unsigned int max_size)
249 
250 ARRAY_CONSTRUCT(String);
251 ARRAY_CONSTRUCT(Integer);
252 ARRAY_CONSTRUCT(Double);
253 ARRAY_CONSTRUCT(Bool);
254 ARRAY_CONSTRUCT(FileName);
255 ARRAY_CONSTRUCT(Selection);
256 ARRAY_CONSTRUCT(Array);
257 ARRAY_CONSTRUCT(Record);
258 ARRAY_CONSTRUCT(AbstractRecord);
259 
260 
261 /**********************************************************************************
262  * implementation of Type::Scalar ... and descendants.
263  */
264 
265 string Scalar::full_type_name() const {
266  return type_name();
267 }
268 
269 /**********************************************************************************
270  * implementation of Type::Bool
271  */
272 
273 
274 bool Bool::valid_default(const string &str) const {
275  from_default(str);
276  return true;
277 }
278 
279 
280 
281 bool Bool::from_default(const string &str) const {
282  if (str == "true" ) {
283  return true;
284  } else
285  if (str == "false") {
286  return false;
287  } else {
288  THROW( ExcWrongDefault() << EI_DefaultStr( str ) << EI_TypeName(type_name()));
289  }
290 }
291 
292 
293 string Bool::type_name() const {
294  return "Bool";
295 }
296 
297 
298 /**********************************************************************************
299  * implementation of Type::Integer
300  */
301 
302 bool Integer::match(int value) const {
303  return ( value >=lower_bound_ && value <= upper_bound_);
304 }
305 
306 
307 
308 int Integer::from_default(const string &str) const {
309  std::istringstream stream(str);
310  int value;
311  stream >> value;
312 
313  if (stream && stream.eof() && match(value)) {
314  return value;
315  } else {
316  THROW( ExcWrongDefault() << EI_DefaultStr( str ) << EI_TypeName(type_name()));
317  }
318 }
319 
320 
321 
322 bool Integer::valid_default(const string &str) const
323 {
324  from_default(str);
325  return true;
326 }
327 
328 
329 
330 string Integer::type_name() const {
331  return "Integer";
332 }
333 
334 
335 /**********************************************************************************
336  * implementation of Type::Double
337  */
338 
339 bool Double::match(double value) const {
340  return ( value >=lower_bound_ && value <= upper_bound_);
341 }
342 
343 
344 
345 double Double::from_default(const string &str) const {
346  std::istringstream stream(str);
347  double value;
348  stream >> value;
349 
350  if (stream && stream.eof() && match(value)) {
351  return value;
352  } else {
353  THROW( ExcWrongDefault() << EI_DefaultStr( str ) << EI_TypeName(type_name()));
354  }
355 }
356 
357 
358 
359 bool Double::valid_default(const string &str) const
360 {
361  from_default(str);
362  return true;
363 }
364 
365 
366 
367 
368 string Double::type_name() const {
369  return "Double";
370 }
371 
372 
373 /**********************************************************************************
374  * implementation of Type::FileName
375  */
376 
377 /*
378 std::ostream& FileName::documentation(std::ostream& stream,DocType extensive, unsigned int pad) const {
379  if (extensive == full_after_record) return stream;
380 
381  stream << "FileName of ";
382  switch (type_) {
383  case ::FilePath::input_file:
384  stream << "input file";
385  break;
386  case ::FilePath::output_file:
387  stream << "output file";
388  break;
389  default:
390  stream << "file with unknown type";
391  break;
392  }
393  return stream;
394 }
395 */
396 
397 
398 string FileName::type_name() const {
399  switch (type_) {
400  case ::FilePath::input_file:
401  return "FileName_input";
402  case ::FilePath::output_file:
403  return "FileName_output";
404  default:
405  return "FileName";
406  }
407 }
408 
409 
410 
411 bool FileName::match(const string &str) const {
412  return (type_ == ::FilePath::input_file) || (str[0] != DIR_DELIMITER); // output files can not be absolute
413 }
414 
415 
416 /**********************************************************************************
417  * implementation of Type::String
418  */
419 
420 
421 
422 string String::type_name() const {
423  return "String";
424 }
425 
426 
427 
428 
429 bool String::valid_default(const string &str) const {
430  if (! match(str)) {
431  THROW( ExcWrongDefault() << EI_DefaultStr( str ) << EI_TypeName(type_name()));
432  }
433  return true;
434 }
435 
436 
437 
438 string String::from_default(const string &str) const {
439  valid_default(str);
440  return str;
441 }
442 
443 
444 
445 bool String::match(const string &str) const {
446  return true;
447 }
448 
449 
450 
451 } // closing namespace Type
452 } // closing namespace Input
453 
454 
455