ALPSCore reference
dict_value_impl.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1998-2018 ALPS Collaboration. See COPYRIGHT.TXT
3  * All rights reserved. Use is subject to license terms. See LICENSE.TXT
4  * For use in publications, see ACKNOWLEDGE.TXT
5  */
6 
13 #include <alps/utilities/short_print.hpp> // for streaming of vectors
14 #include <boost/type_index.hpp> // for pretty-printing user types in error messages
15 #include <boost/integer_traits.hpp>
16 
17 #include <boost/static_assert.hpp> // FIXME:C++11 replace by std feature
18 
19 #include <type_traits>
20 
21 // namespace std {
22 // // Printing of a vector
23 // // FIXME: pollutes std:: namespace and is a bad practice, what if user has one's own vector printer???
24 // template <typename T>
25 // inline std::ostream& operator<<(std::ostream& strm, const std::vector<T>& vec)
26 // {
27 // typedef std::vector<T> vtype;
28 // typedef typename vtype::const_iterator itype;
29 
30 // strm << "[";
31 // itype it=vec.begin();
32 // const itype end=vec.end();
33 
34 // if (end!=it) {
35 // strm << *it;
36 // for (++it; end!=it; ++it) {
37 // strm << ", " << *it;
38 // }
39 // }
40 // strm << "]";
41 
42 // return strm;
43 // }
44 // }
45 
46 namespace alps {
47  namespace params_ns {
48 
49 
50  namespace detail {
51  template <bool V> struct yes_no {};
52  template <> struct yes_no<true> : public std::true_type { typedef bool yes; };
53  template <> struct yes_no<false> : public std::false_type { typedef bool no; };
54 
55  template <typename T>
56  struct is_bool : public yes_no<std::is_same<T,bool>::value> {};
57 
58  // bool type is NOT integral for the purposes of this code
59  template <typename T>
60  struct is_integral : public yes_no<std::is_integral<T>::value && !is_bool<T>::value> {};
61 
62  // type is allowed: bool, integral, char* or other supported
63  // FIXME: should use `is_convertible`. Postponed till simplification refactoring
64  template <typename T>
65  struct is_allowed : public yes_no<
66  is_bool<T>::value
67  || std::is_same<char*, T>::value
68  || std::is_same<const char*, T>::value
69  || is_integral<T>::value
70  || is_supported<T>::value> {};
71 
72  // signed value: integral and signed
73  template <typename T>
74  struct is_signed : public yes_no<std::is_signed<T>::value && is_integral<T>::value> {};
75 
76  // unsigned value: integral and unsigned
77  template <typename T>
78  struct is_unsigned : public yes_no<std::is_unsigned<T>::value && is_integral<T>::value> {};
79 
80  // meta-predicate: conversion bool->integral
81  template <typename FROM, typename TO>
82  struct is_bool_to_integral
83  : public yes_no<is_bool<FROM>::value && is_integral<TO>::value>
84  {};
85 
86  // meta-predicate: conversion signed->integral
87  template <typename FROM, typename TO>
88  struct is_sig_to_intgl
89  : public yes_no<is_signed<FROM>::value && is_integral<TO>::value>
90  {};
91 
92  // meta-predicate: conversion unsigned->integral
93  template <typename FROM, typename TO>
94  struct is_unsig_to_intgl
95  : public yes_no<is_unsigned<FROM>::value && is_integral<TO>::value>
96  {};
97 
98  // meta-predicate: conversion integral->floating_point
99  template <typename FROM, typename TO>
100  struct is_intgl_to_fp
101  : public yes_no<is_integral<FROM>::value && std::is_floating_point<TO>::value>
102  {};
103 
104  // meta-predicate: general conversion, not caught by other ones
105  template <typename FROM, typename TO>
106  struct is_other_conversion
107  : public yes_no<!is_bool_to_integral<FROM,TO>::value &&
108  !is_sig_to_intgl<FROM,TO>::value &&
109  !is_unsig_to_intgl<FROM,TO>::value &&
110  !is_intgl_to_fp<FROM,TO>::value
111  >
112  {};
113 
114  // meta-predicate: both types are unsigned
115  template <typename A, typename B>
116  struct is_both_unsigned
117  : public yes_no<is_unsigned<A>::value && is_unsigned<B>::value>
118  {};
119 
120  // meta-predicate: both types are signed
121  template <typename A, typename B>
122  struct is_both_signed
123  : public yes_no<is_signed<A>::value && is_signed<B>::value>
124  {};
125 
126  // meta-predicate: first type is signed, the other is unsigned
127  template <typename A, typename B>
128  struct is_signed_unsigned
129  : public yes_no<is_signed<A>::value && is_unsigned<B>::value>
130  {};
131 
132  // meta-predicate: one of the types, but not the other, is bool
133  template <typename A, typename B>
134  struct is_either_bool
135  : public yes_no< (is_bool<A>::value && !is_bool<B>::value) ||
136  (!is_bool<A>::value && is_bool<B>::value) >
137  {};
138 
139  // meta-predicate: floating-point conversion between different types
140  template <typename A, typename B>
141  struct is_fp_conv
142  : public yes_no< std::is_floating_point<A>::value &&
143  std::is_floating_point<B>::value &&
144  !std::is_same<A,B>::value>
145  {};
146 
147  // meta-predicate: other comparison
148  template <typename A, typename B>
149  struct is_other_cmp
150  : public yes_no<!is_either_bool<A,B>::value &&
151  !is_both_signed<A,B>::value && !is_both_unsigned<A,B>::value &&
152  !is_signed_unsigned<A,B>::value && !is_signed_unsigned<B,A>::value &&
153  !is_intgl_to_fp<A,B>::value && !is_intgl_to_fp<B,A>::value &&
154  !is_fp_conv<A,B>::value>
155  {};
156 
157 
158  // catch-all definition of pretty-printing for unknown types
159  // FIXME: better design may be to define a separate class for it,
160  // in order to catch unintentional use of type_info<T> on unsupported types?
161  template <typename T>
162  struct type_info {
163  static std::string pretty_name() {
164  return boost::typeindex::type_id<T>().pretty_name();
165  }
166  };
167 
168  namespace visitor {
170  template <typename LHS_T>
171  struct getter: public boost::static_visitor<LHS_T> {
172 
174  LHS_T apply(const LHS_T& val) const {
175  return val; // no conversion
176  }
177 
179  template <typename RHS_T>
180  LHS_T apply(const RHS_T& val, typename is_bool_to_integral<RHS_T,LHS_T>::yes =true) const {
181  return val;
182  }
183 
185  template <typename RHS_T>
186  LHS_T apply(const RHS_T& val, typename is_intgl_to_fp<RHS_T,LHS_T>::yes =true) const {
187  return val;
188  }
189 
191  template <typename RHS_T>
192  LHS_T apply(const RHS_T& val, typename is_unsig_to_intgl<RHS_T,LHS_T>::yes =true) const {
193  typedef typename std::make_unsigned<LHS_T>::type U_LHS_T;
194  const U_LHS_T max_num=boost::integer_traits<LHS_T>::const_max; // always possible
195  // compare 2 unsigned
196  if (val>max_num)
197  throw exception::value_mismatch("", "Integer overflow detected: unsigned integer too large");
198  return val;
199  }
200 
202  template <typename RHS_T>
203  LHS_T apply(const RHS_T& val, typename is_sig_to_intgl<RHS_T,LHS_T>::yes =true) const {
204  typedef typename std::make_signed<LHS_T>::type S_LHS_T;
205  typedef typename std::make_unsigned<LHS_T>::type U_LHS_T;
206  typedef typename std::make_unsigned<RHS_T>::type U_RHS_T;
207 
208  const S_LHS_T min_num=boost::integer_traits<LHS_T>::const_min; // always possible
209 
210  if (val<min_num)
211  throw exception::value_mismatch("", "Integer underflow detected: signed integer too small");
212 
213  if (val<0) return val; // always within range
214 
215  const U_LHS_T max_num=boost::integer_traits<LHS_T>::const_max; // always possible
216  const U_RHS_T uval=val; // as val>=0, it's always correct
217  // compare 2 unsigned
218  if (uval>max_num)
219  throw exception::value_mismatch("", "Integer overflow detected: signed integer too large");
220  return val;
221  }
222 
224  template <typename RHS_T>
225  LHS_T apply(const RHS_T& val, typename is_other_conversion<RHS_T,LHS_T>::yes =true) const {
226  std::string rhs_name=detail::type_info<RHS_T>::pretty_name();
227  std::string lhs_name=detail::type_info<LHS_T>::pretty_name();
228  throw exception::type_mismatch("","Types do not match;"
229  " conversion " + rhs_name + " --> " + lhs_name);
230  }
231 
232 
234  template <typename RHS_T>
235  LHS_T operator()(const RHS_T& val) const {
236  return apply(val);
237  }
238  };
239 
241  template <>
242  struct getter<bool>: public boost::static_visitor<bool> {
243 
245  bool apply(const bool& val) const {
246  return val; // no conversion
247  }
248 
250  template <typename RHS_T>
251  bool apply(const RHS_T& val) const {
252  std::string rhs_name=detail::type_info<RHS_T>::pretty_name();
253  throw exception::type_mismatch("","Cannot convert non-bool type "+rhs_name+" to bool");
254  }
255 
257  template <typename RHS_T>
258  bool operator()(const RHS_T& val) const {
259  return apply(val);
260  }
261  };
262 
264  template <typename X>
265  class check_type : public boost::static_visitor<bool> {
266  public:
268  bool operator()(const X& val) const { return true; }
269 
271  template <typename T>
272  bool operator()(const T& val) const { return false; }
273  };
274 
275 
277  template <typename RHS_T>
278  class comparator : public boost::static_visitor<int> {
279  const RHS_T& rhs_;
280 
281  template <typename A, typename B>
282  static bool cmp_(const A& a, const B& b) { return (a==b)? 0 : (a<b)? -1:1; }
283 
284  public:
285  comparator(const RHS_T& rhs): rhs_(rhs) {}
286 
288  int operator()(const RHS_T& lhs) const {
289  return cmp_(lhs,rhs_);
290  }
291 
293  template <typename LHS_T>
294  int operator()(const LHS_T& lhs) const {
295  return apply(lhs,rhs_);
296  }
297 
299  template <typename LHS_T>
300  int apply(const LHS_T& lhs, const RHS_T& rhs,
301  typename is_either_bool<LHS_T,RHS_T>::yes =true) const {
302  std::string lhs_name=detail::type_info<LHS_T>::pretty_name();
303  std::string rhs_name=detail::type_info<RHS_T>::pretty_name();
304  throw exception::type_mismatch("","Attempt to compare a boolean value with an incompatible type "+
305  lhs_name + "<=>" + rhs_name);
306  }
307 
309  template <typename LHS_T>
310  int apply(const LHS_T& lhs, const RHS_T& rhs, typename is_both_signed<LHS_T,RHS_T>::yes =true) const {
311  return cmp_(lhs,rhs);
312  }
313 
315  template <typename LHS_T>
316  int apply(const LHS_T& lhs, const RHS_T& rhs, typename is_both_unsigned<LHS_T,RHS_T>::yes =true) const {
317  return cmp_(lhs,rhs);
318  }
319 
321  template <typename LHS_T>
322  int apply(const LHS_T& lhs, const RHS_T& rhs, typename is_signed_unsigned<LHS_T,RHS_T>::yes =true) const {
323  typedef typename std::make_unsigned<LHS_T>::type U_LHS_T;
324  if (lhs<0) return -1;
325  // lhs is non-negative..
326  U_LHS_T u_lhs=static_cast<U_LHS_T>(lhs); // always valid for lhs>=0
327  return cmp_(u_lhs, rhs);
328  }
329 
331  template <typename LHS_T>
332  int apply(const LHS_T& lhs, const RHS_T& rhs, typename is_signed_unsigned<RHS_T,LHS_T>::yes =true) const {
333  return -apply(rhs,lhs);
334  }
335 
337  template <typename LHS_T>
338  int apply(const LHS_T& lhs, const RHS_T& rhs, typename is_intgl_to_fp<LHS_T,RHS_T>::yes =true) const {
339  return cmp_(lhs, rhs);
340  }
341 
343  template <typename LHS_T>
344  int apply(const LHS_T& lhs, const RHS_T& rhs, typename is_intgl_to_fp<RHS_T,LHS_T>::yes =true) const {
345  return cmp_(lhs, rhs);
346  }
347 
349  template <typename LHS_T>
350  int apply(const LHS_T& lhs, const RHS_T& rhs, typename is_fp_conv<RHS_T,LHS_T>::yes =true) const {
351  return cmp_(lhs, rhs);
352  }
353 
355  template <typename LHS_T>
356  int apply(const LHS_T& lhs, const RHS_T& rhs, typename is_other_cmp<LHS_T,RHS_T>::yes =true) const {
357  std::string lhs_name=detail::type_info<LHS_T>::pretty_name();
358  std::string rhs_name=detail::type_info<RHS_T>::pretty_name();
359  throw exception::type_mismatch("","Attempt to compare incompatible types "+
360  lhs_name + "<=>" + rhs_name);
361  }
362  };
363 
364  } // ::visitor
365  } //::detail
366 
367  template <typename F>
368  typename F::result_type dict_value::apply_visitor(F& visitor) const {
369  return boost::apply_visitor(visitor, val_);
370  }
371 
372  template <typename F>
373  typename F::result_type dict_value::apply_visitor(const F& visitor) const {
374  return boost::apply_visitor(visitor, val_);
375  }
376 
377  inline bool dict_value::empty() const {
378  return val_.which()==0; // NOTE: relies on `None` being the first type
379  }
380 
381  template <typename X>
382  inline bool dict_value::isType() const {
383  return apply_visitor(detail::visitor::check_type<X>());
384  }
385 
386  template <typename T>
387  inline const T& dict_value::operator=(const T& rhs) {
388  val_=rhs;
389  return rhs;
390  }
391 
392  inline const char* dict_value::operator=(const char* rhs) {
393  val_=std::string(rhs);
394  return rhs;
395  }
396 
397  template <typename T>
398  inline T dict_value::as() const {
399  BOOST_STATIC_ASSERT_MSG(detail::is_allowed<T>::value, "The type is not supported by dictionary");
400  if (this->empty()) throw exception::uninitialized_value(name_,"Attempt to read uninitialized value");
401  try {
402  return apply_visitor(detail::visitor::getter<T>());
403  } catch (exception::exception_base& exc) {
404  exc.set_name(name_);
405  throw;
406  }
407  }
408 
409  // template <typename T,
410  // typename std::enable_if<detail::is_allowed<T>::value, int> =0>
411  // inline dict_value::operator T() const {
412  // // BOOST_STATIC_ASSERT_MSG(detail::is_allowed<T>::value, "The type is not supported by the dictionary");
413  // return as<T>();
414  // }
415 
416  inline void dict_value::clear() { val_=None(); }
417 
418  template <typename T>
419  inline int dict_value::compare(const T& rhs) const
420  {
421  BOOST_STATIC_ASSERT_MSG(detail::is_allowed<T>::value, "The type is not supported by dictionary");
422  if (this->empty()) throw exception::uninitialized_value(name_,"Attempt to compare uninitialized value");
423  try {
424  return apply_visitor(detail::visitor::comparator<T>(rhs));
425  } catch(exception::exception_base& exc) {
426  exc.set_name(name_);
427  throw;
428  }
429  }
430 
432 
437  template <typename F>
438  inline typename F::result_type apply_visitor(F& visitor, const dict_value& dv)
439  {
440  return dv.apply_visitor(visitor);
441  }
442 
444 
449  template <typename F>
450  inline typename F::result_type apply_visitor(const F& visitor, const dict_value& dv)
451  {
452  return dv.apply_visitor(visitor);
453  }
454 
455  template <typename T>
456  inline bool operator==(const T& lhs, const dict_value& rhs) { return rhs.compare(lhs)==0; }
457 
458  // template <typename T>
459  // inline bool operator<(const T& lhs, const dict_value& rhs) {return false; }
460 
461  // template <typename T>
462  // inline bool operator>(const T& lhs, const dict_value& rhs) {return false; }
463 
464  template <typename T>
465  inline bool operator!=(const T& lhs, const dict_value& rhs) { return rhs.compare(lhs)!=0; }
466 
467  // template <typename T>
468  // inline bool operator>=(const T& lhs, const dict_value& rhs) {return false; }
469 
470  // template <typename T>
471  // inline bool operator<=(const T& lhs, const dict_value& rhs) {return false; }
472 
473  template <typename T>
474  inline bool operator==(const dict_value& lhs, const T& rhs) { return lhs.compare(rhs)==0; }
475 
476  // template <typename T>
477  // inline bool operator<(const dict_value& lhs, const T& rhs) {return false; }
478 
479  // template <typename T>
480  // inline bool operator>(const dict_value& lhs, const T& rhs) {return false; }
481 
482  template <typename T>
483  inline bool operator!=(const dict_value& lhs, const T& rhs) {return lhs.compare(rhs)!=0; }
484 
485  // template <typename T>
486  // inline bool operator>=(const dict_value& lhs, const T& rhs) {return false; }
487 
488  // template <typename T>
489  // inline bool operator<=(const dict_value& lhs, const T& rhs) {return false; }
490 
491  inline bool operator==(const dict_value& lhs, const dict_value& rhs) {return lhs.compare(rhs)==0; }
492 
493  // inline bool operator<(const dict_value& lhs, const dict_value& rhs) {return false; }
494 
495  // inline bool operator>(const dict_value& lhs, const dict_value& rhs) {return false; }
496 
497  inline bool operator!=(const dict_value& lhs, const dict_value& rhs) {return lhs.compare(rhs)!=0; }
498 
499  // inline bool operator>=(const dict_value& lhs, const dict_value& rhs) {return false; }
500 
501  // inline bool operator<=(const dict_value& lhs, const dict_value& rhs) {return false; }
502 
503  inline bool operator==(const dict_value& lhs, const char* rhs) {return lhs.compare(std::string(rhs))==0; }
504 
505  // inline bool operator<(const dict_value& lhs, const char* rhs) {return false; }
506 
507  // inline bool operator>(const dict_value& lhs, const char* rhs) {return false; }
508 
509  inline bool operator!=(const dict_value& lhs, const char* rhs) {return lhs.compare(std::string(rhs))!=0; }
510 
511  // inline bool operator>=(const dict_value& lhs, const char* rhs) {return false; }
512 
513  // inline bool operator<=(const dict_value& lhs, const char* rhs) {return false; }
514 
515  inline bool operator==(const char* lhs, const dict_value& rhs) {return rhs.compare(std::string(lhs))==0; }
516 
517  // inline bool operator<(const char* lhs, const dict_value& rhs) {return false; }
518 
519  // inline bool operator>(const char* lhs, const dict_value& rhs) {return false; }
520 
521  inline bool operator!=(const char* lhs, const dict_value& rhs) {return rhs.compare(std::string(lhs))!=0; }
522 
523  // inline bool operator>=(const char* lhs, const dict_value& rhs) {return false; }
524 
525  // inline bool operator<=(const char* lhs, const dict_value& rhs) {return false; }
526 
527  } // params_ns::
528 
529 
530 #ifdef ALPS_HAVE_MPI
531  namespace mpi {
532  inline void broadcast(const alps::mpi::communicator &comm, alps::params_ns::dict_value& val, int root)
533  {
534  val.broadcast(comm, root);
535  }
536  }
537 #endif
538 
539 } // alps::
void set_name(const std::string &name)
F::result_type apply_visitor(const F &visitor, const dict_value &dv)
Const-access visitor to the bound value.
void broadcast(C const &c, P &p, int r=0)
Definition: api.hpp:56
const T & operator=(const T &rhs)
Assignment operator (with conversion)
bool operator==(const dictionary &lhs, const dictionary &rhs)
Definition: dictionary.hpp:96
Exception for using uninitialized value.
Encapsulation of an MPI communicator and some communicator-related operations.
Definition: mpi.hpp:111
F::result_type apply_visitor(F &visitor, dictionary::const_iterator it)
Const-access visitor to a value by an iterator.
Definition: dictionary.hpp:110
bool isType() const
check the type of the containing value
void clear()
Reset to an empty value.
bool empty() const
whether the value contains None
T as() const
Shortcut for explicit conversion to a target type.
General exception (base class)
detail::None None
"Empty value" type
Definition: dict_value.hpp:66
bool operator!=(const dictionary &lhs, const dictionary &rhs)
Definition: dictionary.hpp:100
F::result_type apply_visitor(F &visitor) const
Const-access visitor to the bound value.
int compare(const T &rhs) const
Comparison.