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 7 /** @file dict_value.cpp 8 Contains implementation of some alps::params_ns::dict_value members */ 9 10 #include <boost/version.hpp> 11 12 #include <alps/params/dict_value.hpp> 13 #include <alps/params/hdf5_variant.hpp> 14 15 #ifdef ALPS_HAVE_MPI 16 #include <alps/params/mpi_variant.hpp> 17 #endif 18 19 namespace alps { 20 namespace params_ns { 21 22 namespace detail { 23 namespace visitor { 24 25 /// Visitor to compare 2 value of dict_value type 26 /** @note Values are comparable iff they are of the same type (FIXME!) */ 27 class comparator2 : public boost::static_visitor<int> { 28 template <typename A, typename B> cmp_(const A & a,const B & b)29 static bool cmp_(const A& a, const B& b) { return (a==b)? 0 : (a<b)? -1:1; } 30 31 public: 32 /// Called by apply_visitor for bound values of different types 33 template <typename LHS_T, typename RHS_T> operator ()(const LHS_T & lhs,const RHS_T & rhs) const34 int operator()(const LHS_T& lhs, const RHS_T& rhs) const { 35 std::string lhs_name=detail::type_info<LHS_T>::pretty_name(); 36 std::string rhs_name=detail::type_info<RHS_T>::pretty_name(); 37 throw exception::type_mismatch("","Attempt to compare dictionary values containing " 38 "incompatible types "+ 39 lhs_name + "<=>" + rhs_name); 40 } 41 42 /// Called by apply_visitor for bound values of the same type 43 template <typename LHS_RHS_T> operator ()(const LHS_RHS_T & lhs,const LHS_RHS_T & rhs) const44 int operator()(const LHS_RHS_T& lhs, const LHS_RHS_T& rhs) const { 45 return cmp_(lhs,rhs); 46 } 47 48 /// Called by apply_visitor for bound values both having None type operator ()(const dict_value::None & lhs,const dict_value::None & rhs) const49 int operator()(const dict_value::None& lhs, const dict_value::None& rhs) const { 50 return 1; 51 } 52 53 54 // FIXME:TODO: 55 // Same types: compare directly 56 // Integral types: compare using signs (extract it to a separate namespace/class) 57 // FP types: compare directly 58 // Everything else: throw 59 }; 60 61 /// Visitor to test for exact equality (name and value) 62 class equals2 : public boost::static_visitor<bool> { 63 public: 64 /// Called when bound values have the same type 65 template <typename LHS_RHS_T> operator ()(const LHS_RHS_T & lhs,const LHS_RHS_T & rhs) const66 bool operator()(const LHS_RHS_T& lhs, const LHS_RHS_T& rhs) const { 67 return lhs==rhs; 68 } 69 70 /// Called when bound types are different 71 template <typename LHS_T, typename RHS_T> operator ()(const LHS_T & lhs,const RHS_T & rhs) const72 bool operator()(const LHS_T& lhs, const RHS_T& rhs) const{ 73 return false; 74 } 75 76 /// Called when LHS is None 77 template <typename RHS_T> operator ()(const dict_value::None &,const RHS_T &) const78 bool operator()(const dict_value::None&, const RHS_T&) const { 79 return false; 80 } 81 82 /// Called when RHS is None 83 template <typename LHS_T> operator ()(const LHS_T &,const dict_value::None &) const84 bool operator()(const LHS_T&, const dict_value::None&) const { 85 return false; 86 } 87 88 /// Called when both are None operator ()(const dict_value::None &,const dict_value::None &) const89 bool operator()(const dict_value::None&, const dict_value::None&) const { 90 return true; 91 } 92 }; 93 94 } // visitor:: 95 96 } // detail:: 97 compare(const dict_value & rhs) const98 int dict_value::compare(const dict_value& rhs) const 99 { 100 if (this->empty() || rhs.empty()) throw exception::uninitialized_value(name_+"<=>"+rhs.name_,"Attempt to compare uninitialized value"); 101 102 try { 103 return boost::apply_visitor(detail::visitor::comparator2(), val_, rhs.val_); 104 } catch (exception::exception_base& exc) { 105 exc.set_name(name_+"<=>"+rhs.name_); 106 throw; 107 } 108 } 109 equals(const dict_value & rhs) const110 bool dict_value::equals(const dict_value& rhs) const 111 { 112 return boost::apply_visitor(detail::visitor::equals2(), val_, rhs.val_); 113 } 114 save(alps::hdf5::archive & ar) const115 void dict_value::save(alps::hdf5::archive& ar) const { 116 if (this->empty()) return; 117 alps::hdf5::write_variant<detail::dict_all_types>(ar, val_); 118 } 119 load(alps::hdf5::archive & ar)120 void dict_value::load(alps::hdf5::archive& ar) { 121 const std::string context=ar.get_context(); 122 std::string::size_type slash_pos=context.find_last_of("/"); 123 if (slash_pos==std::string::npos) slash_pos=0; else ++slash_pos; 124 name_=context.substr(slash_pos); 125 val_=alps::hdf5::read_variant<detail::dict_all_types>(ar); 126 } 127 128 namespace { 129 struct typestring_visitor : public boost::static_visitor<std::string> { 130 template <typename T> operator ()alps::params_ns::__anon528a127b0111::typestring_visitor131 std::string operator()(const T& val) const { 132 std::string ret=detail::type_info<T>::pretty_name(); 133 return ret; 134 } 135 }; 136 137 // Printing of a vector 138 // FIXME!!! Consolidate with other definitions and move to alps::utilities 139 template <typename T> operator <<(std::ostream & strm,const std::vector<T> & vec)140 inline std::ostream& operator<<(std::ostream& strm, const std::vector<T>& vec) 141 { 142 typedef std::vector<T> vtype; 143 typedef typename vtype::const_iterator itype; 144 145 strm << "["; 146 itype it=vec.begin(); 147 const itype end=vec.end(); 148 149 if (end!=it) { 150 strm << *it; 151 for (++it; end!=it; ++it) { 152 strm << ", " << *it; 153 } 154 } 155 strm << "]"; 156 157 return strm; 158 } 159 160 struct print_visitor { 161 #if __cplusplus == 201402L && BOOST_VERSION == 105800 162 // Workaround for a bug in boost 1.58 with C++14. 163 // Defining `result_type` as a reference type 164 // leads to a compilation error; 165 // however, C++14 is able to deduce the type of the result 166 // without `result_type` being defined. 167 #else 168 typedef std::ostream& result_type; 169 #endif 170 std::ostream& os_; 171 print_visitoralps::params_ns::__anon528a127b0111::print_visitor172 print_visitor(std::ostream& os) : os_(os) {} 173 174 template <typename T> operator ()alps::params_ns::__anon528a127b0111::print_visitor175 std::ostream& operator()(const T& val) const { 176 return os_ << val; 177 } 178 operator ()alps::params_ns::__anon528a127b0111::print_visitor179 std::ostream& operator()(const dict_value::None&) const { 180 throw std::logic_error("print_visitor: This is not expected to be called"); 181 } 182 }; 183 184 } 185 print(std::ostream & s,const dict_value & dv,bool terse)186 std::ostream& print(std::ostream& s, const dict_value& dv, bool terse) { 187 if (dv.empty()) { 188 s << "[NONE]"; 189 if (!terse) s << " (type: None)"; 190 } else { 191 // s << dv.val_; 192 boost::apply_visitor(print_visitor(s), dv.val_); 193 if (!terse) s << " (type: " << boost::apply_visitor(typestring_visitor(), dv.val_) << ")"; 194 } 195 if (!terse) s << " (name='" << dv.name_ << "')"; 196 return s; 197 } 198 199 #ifdef ALPS_HAVE_MPI broadcast(const alps::mpi::communicator & comm,int root)200 void dict_value::broadcast(const alps::mpi::communicator& comm, int root) 201 { 202 using alps::mpi::broadcast; 203 broadcast(comm, name_, root); 204 broadcast<detail::dict_all_types>(comm, val_, root); 205 } 206 #endif 207 208 209 } // params_ns:: 210 } // alps:: 211