poly_type.hpp
1 // Author: Mario S. Könz <mskoenz@gmx.net>
2 // Date: 19.08.2015 09:44:17 CEST
3 // File: poly_type.cpp
4 
5 #ifndef FSC_POLY_TYPE_HEADER
6 #define FSC_POLY_TYPE_HEADER
7 
8 #include "boost_any.hpp"
9 #include "fsc_except.hpp"
10 
11 #include <map>
12 #include <iomanip>
13 #include <typeinfo>
14 #include <iostream>
15 #include <stdexcept>
16 #include <type_traits>
17 
18 /* TODO:
19  * default ctor in reject conv
20  */
21 
22 namespace fsc {
24  namespace detail {
25  template<typename T>
26  struct convert {
27  template<typename U>
28  static typename std::enable_if<std::is_convertible<U, T>::value, T>::type from(U const & u) {
29  return u;
30  }
31  template<typename U>
32  static typename std::enable_if<!std::is_convertible<U, T>::value, T>::type from(U const &) {
33  throw fsc::O__o("poly_type error: type '" + std::string(typeid(U).name()) + "' is not convertible to type '" + std::string(typeid(T).name()) + "'");
34  return T(); //TODO, remove default ctor req.
35  }
36  };
37  }//end namespace detail
39 
41  struct poly_type {
42  private:
43  // This class has a templated cast operator that works nicely, but
44  // has ambiguity problems with std::string since it has so many
45  // ctors... hence we drop all cast operators that trouble std::string
46  template<typename T, typename U>
47  struct drop_casts {
48  static constexpr bool value = true;
49  };
50  //~ template<typename U>
51  //~ struct drop_casts<size_t, U> {
52  //~ static constexpr bool value = false;
53  //~ };
54  template<typename U>
55  struct drop_casts<std::initializer_list<char>, U> {
56  static constexpr bool value = false;
57  };
58  template<typename U>
59  struct drop_casts<std::allocator<char>, U> {
60  static constexpr bool value = false;
61  };
62  template<typename U>
63  struct drop_casts<const char*, U> {
64  static constexpr bool value = false;
65  };
66  public:
67  //------------------- structors -------------------
68  poly_type() {}
69  template<typename T>
70  poly_type(T const & t): any(t) {}
71  poly_type(char const * t): any(std::string(t)) {}
72  //------------------- cast -------------------
73  template<typename T, typename enable = std::enable_if_t<drop_casts<T, void>::value>>
74  operator T() const {
75  if(type() == typeid(int)) {
76  return detail::convert<T>::from(boost::any_cast<int>(any));
77  }
78  if(type() == typeid(double)) {
79  return detail::convert<T>::from(boost::any_cast<double>(any));
80  }
81  if(type() == typeid(bool)) {
82  return detail::convert<T>::from(boost::any_cast<bool>(any));
83  }
84  if(type() == typeid(std::string)) {
85  return detail::convert<T>::from(boost::any_cast<std::string>(any));
86  }
87  return T();
88  }
89  //------------------- assign -------------------
90  template<typename T>
91  void operator=(T const & t){
92  any = t;
93  }
94  void operator=(const char * t) { // handle spaecial case since "bla" is not a string
95  any = std::string(t);
96  }
97  void operator=(poly_type const & t){
98  any = t.any;
99  }
100 
101  //------------------- += -= *= /= operator -------------------
102  template<typename T>
103  poly_type & operator+=(T const & t) {
104  return (*this) += poly_type(t);
105  }
106  poly_type & operator+=(char const * t) {
107  return (*this)+=std::string(t);
108  }
109  poly_type & operator+=(poly_type const & t) {
110  if(type() == typeid(std::string)) {
111  std::string as = (*this);
112  std::string bs = t;
113  any = as+bs;
114  } else if(type() == typeid(double) or t.type() == typeid(double)) {
115  double as = (*this);
116  double bs = t;
117  any = as+bs;
118  } else {
119  int as = (*this);
120  int bs = t;
121  any = as+bs;
122  }
123  return (*this);
124  }
125 
126  template<typename T>
127  poly_type & operator-=(T const & t) {
128  return (*this) -= poly_type(t);
129  }
130  poly_type & operator-=(poly_type const & t) {
131  if(type() == typeid(double) or t.type() == typeid(double)) {
132  double as = (*this);
133  double bs = t;
134  any = as-bs;
135  } else {
136  int as = (*this);
137  int bs = t;
138  any = as-bs;
139  }
140  return (*this);
141  }
142 
143  template<typename T>
144  poly_type & operator*=(T const & t) {
145  return (*this) *= poly_type(t);
146  }
147  poly_type & operator*=(poly_type const & t) {
148  if(type() == typeid(double) or t.type() == typeid(double)) {
149  double as = (*this);
150  double bs = t;
151  any = as*bs;
152  } else {
153  int as = (*this);
154  int bs = t;
155  any = as*bs;
156  }
157  return (*this);
158  }
159 
160  template<typename T>
161  poly_type & operator/=(T const & t) {
162  return (*this) /= poly_type(t);
163  }
164  poly_type & operator/=(poly_type const & t) {
165  double as = (*this);
166  double bs = t;
167  any = as/bs;
168  return (*this);
169  }
170 
171  //------------------- const fct -------------------
172  std::type_info const & type() const {
173  return any.type();
174  }
175  template<typename S>
176  void print(S & os) const {
177  if(type() == typeid(bool)) {
178  os << boost::any_cast<bool>(any);
179  }
180  if(type() == typeid(int)) {
181  os << boost::any_cast<int>(any);
182  }
183  if(type() == typeid(double)) {
184  os << boost::any_cast<double>(any);
185  }
186  if(type() == typeid(std::string)) {
187  os << boost::any_cast<std::string>(any);
188  }
189  }
190  private:
191  boost::any any;
192  };
193 
194  std::ostream & operator<<(std::ostream & os, poly_type const & arg) {
195  arg.print(os);
196  return os;
197  }
198 
199  #define FSC_POLY_TYPE_OP_SUPPORT(OP) \
200  poly_type operator OP(poly_type const & a, poly_type const & b) { \
201  poly_type res(a); \
202  res OP##= b; \
203  return res; \
204  } \
205  template<typename T> \
206  poly_type operator OP(poly_type const & p, T const & t) { \
207  return p OP poly_type(t); \
208  } \
209  template<typename T> \
210  poly_type operator OP(T const & t, poly_type const & p) { \
211  return poly_type(t) OP p; \
212  } //
213 
214 
215  #define FSC_POLY_TYPE_OPEQ_SUPPORT(OP, TYPE) \
216  TYPE & operator OP(TYPE & a, fsc::poly_type const & b) { \
217  TYPE t = b; \
218  return a OP t; \
219  } //
220 
221  FSC_POLY_TYPE_OP_SUPPORT(+)
222  FSC_POLY_TYPE_OP_SUPPORT(-)
223  FSC_POLY_TYPE_OP_SUPPORT(/)
224  FSC_POLY_TYPE_OP_SUPPORT(*)
225  FSC_POLY_TYPE_OPEQ_SUPPORT(+=, std::string)
226  FSC_POLY_TYPE_OPEQ_SUPPORT(+=, double)
227  FSC_POLY_TYPE_OPEQ_SUPPORT(-=, double)
228  FSC_POLY_TYPE_OPEQ_SUPPORT(*=, double)
229  FSC_POLY_TYPE_OPEQ_SUPPORT(/=, double)
230  FSC_POLY_TYPE_OPEQ_SUPPORT(+=, int)
231  FSC_POLY_TYPE_OPEQ_SUPPORT(-=, int)
232  FSC_POLY_TYPE_OPEQ_SUPPORT(*=, int)
233  FSC_POLY_TYPE_OPEQ_SUPPORT(/=, int)
234 
235  #undef FSC_POLY_TYPE_OP_SUPPORT
236  #undef FSC_POLY_TYPE_OPEQ_SUPPORT
237 
239 }//end namespace fsc
240 
241 
242 /*
243 int main(int argc, char* argv[]) {
244  std::map<std::string, fsc::poly_type> f;
245 
246  f["cwd"] = "./";
247  f["cwd"] += "home";
248  f["b"] = true;
249 
250  f["i"] = 1;
251  f["i"] -= .1;
252 
253  f["d"] = 1.3;
254  f["d"] = f["d"] + 1;
255 
256  f["i*d"] = f["i"]*f["d"];
257 
258  f["i*d/(2*b)"] = f["i*d"]/(2*f["b"]);
259 
260  f["x"] = "foo";
261  f["y"] = f["x"] + "/bar";
262  f["x"] = "fo1";
263  f["bar"] = f["x"];
264  f["x"] = 1.2;
265  f["x"] = "d";
266 
267 
268  std::string str("f");
269  fsc::poly_type temp("foo");
270 
271  str+=temp;
272 
273  for(auto const & p: f)
274  std::cout << p.first << " = " << p.second << std::endl;
275 
276 
277  return 0;
278 }
279 */
280 #endif //FSC_POLY_TYPE_HEADER
281