Type.h
1 /*
2 
3 MIT License
4 
5 Copyright (c) 2017 FMI Open Development / Markus Peura, first.last@fmi.fi
6 
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to deal
9 in the Software without restriction, including without limitation the rights
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 copies of the Software, and to permit persons to whom the Software is
12 furnished to do so, subject to the following conditions:
13 
14 The above copyright notice and this permission notice shall be included in all
15 copies or substantial portions of the Software.
16 
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 SOFTWARE.
24 
25 */
26 /*
27 Part of Rack development has been done in the BALTRAD projects part-financed
28 by the European Union (European Regional Development Fund and European
29 Neighbourhood Partnership Instrument, Baltic Sea Region Programme 2007-2013)
30 */
31 #ifndef DRAIN_TYPE
32 #define DRAIN_TYPE
33 
34 #include <typeinfo>
35 //#include <type_traits>
36 //#include <limits>
37 #include <list>
38 #include <set>
39 #include <stdexcept>
40 
41 //#include "Log.h"
42 #include "RegExp.h"
43 
44 namespace drain {
45 
46 
48 
51 class Type {
52 public:
53 
54  inline
55  Type() : currentType(&typeid(void)) { //, typeMin(0), typeMax(0) {
56  }
57 
58  inline
59  Type(const Type & t) : currentType(t.currentType) { //, typeMin(t.typeMin), typeMax(t.typeMax) { // FIX 0 0
60  //std::cerr << __FUNCTION__ << "(const &)" << std::endl;
61  }
62 
63  template <class T>
64  Type(const T & t) : currentType(&typeid(void)){
65  setType(t);
66  }
67 
68 
69  template <class T>
70  inline
71  void setType(){
72  //std::cerr << __FUNCTION__ << "<T>()" << std::endl;
73  currentType = & typeid(T);
74  }
75 
76 
78 
81  template <class T>
82  inline
83  void setType(const T & t){
84  call<typeSetter>(*this, t);
85  }
86 
87  // TODO for std::strings.
88  template <class T>
89  inline
90  Type & operator=(const T & t){
91  setType(t);
92  return *this;
93  }
94 
95  inline
96  operator const std::type_info & () const {return (*currentType); }
97 
98  inline
99  operator char () const {return getTypeChar(*currentType); }
100 
101  inline
102  operator std::string () const {return std::string(1, getTypeChar(*currentType)); }
103 
104 
106  inline
107  const std::type_info & getType() const {
108  return *currentType;
109  }
110 
111 
113 
132  static
133  inline
134  const std::type_info & getTypeInfo(char t){
135 
136  switch (t) {
137  case 'c':
138  return typeid(char);
139  case 'C':
140  return typeid(unsigned char);
141  case 's':
142  return typeid(short);
143  case 'S':
144  return typeid(unsigned short);
145  case 'i':
146  return typeid(int);
147  case 'I':
148  return typeid(unsigned int);
149  case 'l':
150  return typeid(long);
151  case 'L':
152  return typeid(unsigned long);
153  case 'f':
154  return typeid(float);
155  case 'd':
156  return typeid(double);
157  case 'B':
158  return typeid(bool);
159  case '$': // deprecated?
160  case '#':
161  return typeid(std::string);
162  case '*':
163  return typeid(void);
164  default:
165  //Logger mout("Type", std::string(__FUNCTION__)+"(char c)");
166  //Logger mout(__FILE__, __FUNCTION__);
167  //mout.error(" undefined type: '" , t , "'=" , (int)t );
168  std::cerr << __FILE__ << ' ' << __FUNCTION__ << " undefined type: '" << t << "'=" << (int)t << std::endl;
169  //mout.error(" undefined type: '" , t , "'=" , (int)t );
170  throw std::runtime_error("undefined type");
171  return typeid(void);
172  }
173 
174  }
175 
176  static
177  inline
178  char getTypeChar(const std::type_info & t){
179  if (t == typeid(char))
180  return 'c';
181  else if (t == typeid(unsigned char))
182  return 'C';
183  else if (t == typeid(short))
184  return 's';
185  else if (t == typeid(unsigned short))
186  return 'S';
187  else if (t == typeid(int))
188  return 'i';
189  else if (t == typeid(unsigned int))
190  return 'I';
191  else if (t == typeid(long))
192  return 'l';
193  else if (t == typeid(unsigned long))
194  return 'L';
195  else if (t == typeid(float))
196  return 'f';
197  else if (t == typeid(double))
198  return 'd';
199  else if (t == typeid(bool))
200  return 'B';
201  else if (t == typeid(void))
202  return '*';
203  else if (t == typeid(std::string))
204  return '#';
205  else if (t == typeid(const char *))
206  return '#';
207  else if (t == typeid(char *))
208  return '#';
209  else {
210  return 'x'; // = "extension"
211  }
212  }
213 
215 
221  template <class F, class T>
222  static
223  T call(const std::type_info & t){ // ORIGINAL
224 
225  //std::cout << "Calling call with " << t.name() << " (" << getTypeChar(t) << ")\n";
226  // NOTE: STL uses string comparison!!!
227  if (t == typeid(char)){
228  return F::template callback<char,T>();
229  }
230  else if (t == typeid(unsigned char)) {
231  return F::template callback<unsigned char,T>();
232  }
233  else if (t == typeid(int)) {
234  return F::template callback<int,T>();
235  }
236  else if (t == typeid(unsigned int)) {
237  return F::template callback<unsigned int,T>();
238  }
239  else if (t == typeid(short int)) {
240  return F::template callback<short int,T>();
241  }
242  else if (t == typeid(unsigned short int)) {
243  return F::template callback<unsigned short int,T>();
244  }
245  else if (t == typeid(long int)) {
246  return F::template callback<long int,T>();
247  }
248  else if (t == typeid(unsigned long int)) {
249  return F::template callback<unsigned long int,T>();
250  }
251  else if (t == typeid(float)) {
252  return F::template callback<float,T>();
253  }
254  else if (t == typeid(double)) {
255  return F::template callback<double,T>();
256  }
257  else if (t == typeid(bool)) {
258  return F::template callback<bool,T>();
259  }
260  else if (t == typeid(void)) {
261  return F::template callback<void,T>();
262  }
263  else if (t == typeid(std::string)) {
264  return F::template callback<std::string,T>();
265  }
266  /*
267  else if (Type::call<isEnum>(t)){ // NEW 2023
268  // Problem: looping if not enum...
269  return F::template callback<int,T>();
270  }
271  */
272  else {
273  std::cerr << __FILE__ << ' ' << __FUNCTION__ << "unimplemented type: ..." << t.name() << std::endl;
274  //mout.error(" undefined type: '" , t , "'=" , (int)t );
275  throw std::runtime_error("unimplemented type: ...");
276  //Logger mout(__FILE__, __FUNCTION__);
277  // mout.error("unimplemented type: ...", t.name(), " NOTE: enums suppressed");
278  //return T(); //F::template callback<char,T>();
279  // Problem with ref types
280  return F::template callback<char,T>();
281  }
282 
283  }
284 
286 
291  template <class F, class D, class S>
292  static inline
293  D call(const S & typeCode){
294  return call<F,D>(getTypeInfo(typeCode));
295  }
296 
298 
304  template <class F, class S>
305  static inline
306  typename F::value_t call(const S & typeCode){
307  return call<F,typename F::value_t>(getTypeInfo(typeCode));
308  }
309 
310 
312 
338  template <class F, class T>
339  static
340  void call(T & target, const std::type_info &t){ // const Type &type){
341 
342  if (t == typeid(char))
343  F::template callback<char>(target);
344  else if (t == typeid(unsigned char))
345  F::template callback<unsigned char>(target);
346  else if (t == typeid(int))
347  F::template callback<int>(target);
348  else if (t == typeid(unsigned int))
349  F::template callback<unsigned int>(target);
350  else if (t == typeid(short))
351  F::template callback<short>(target);
352  else if (t == typeid(unsigned short))
353  F::template callback<unsigned short>(target);
354  else if (t == typeid(long))
355  F::template callback<long>(target);
356  else if (t == typeid(unsigned long))
357  F::template callback<unsigned long>(target);
358  else if (t == typeid(float))
359  F::template callback<float>(target);
360  else if (t == typeid(double))
361  F::template callback<double>(target);
362  else if (t == typeid(bool))
363  F::template callback<bool>(target);
364  else if (t == typeid(std::string))
365  F::template callback<std::string>(target);
366  else if (t == typeid(void)) {
367  F::template callback<void>(target);
368  }
369  /*
370  else if (Type::call<isEnum>(t)){
371  F::template callback<int>(target);
372  }
373  */
374  else {
375  std::cerr << __FILE__ << ' ' << __FUNCTION__ << "unimplemented type: ..." << t.name() << std::endl;
376  //mout.error(" undefined type: '" , t , "'=" , (int)t );
377  throw std::runtime_error("unimplemented type: ...");
378 
379  //Logger mout(__FILE__, __FUNCTION__);
380  //mout.error("unimplemented type: ...", t.name(), " NOTE: enums suppressed");
381  // throw std::runtime_error(std::string(": unimplemented type: ") + t.name() + " NOTE: enums suppressed");
382  return;
383  }
384  }
385 
387 
396  template <class F, class T, class T2>
397  static
398  void call(T & target, const T2 &t){
399  call<F>(target, getTypeInfo(t));
400  }
401 
402 
403 
405 
408  static
409  inline
410  const std::type_info & getTypeInfo(const char *typeCode){
411  if ((typeCode != NULL) && (*typeCode != '\0'))
412  return getTypeInfo(*typeCode);
413  else if (typeCode == NULL)
414  return getTypeInfo('*');
415  else
416  throw std::runtime_error(std::string("Type::operator=, not unit-length std::string: ") + typeCode);
417  }
418 
420 
423  static
424  inline
425  const std::type_info & getTypeInfo(const std::string & typeCode){
426  if (typeCode.length() == 1)
427  return getTypeInfo(typeCode.at(0));
428  else if (typeCode.empty())
429  return getTypeInfo('*');
430  else
431  throw std::runtime_error(std::string("Type::operator=, not unit-length std::string: ") + typeCode);
432  }
433 
435  static
436  inline
437  const std::type_info & getTypeInfo(const Type & t){
438  return t;
439  }
440 
441  /*
442  static
443  const drain::RegExp trueRegExp;
444 
445  static
446  const drain::RegExp falseRegExp;
447  */
448 
450 
453  /*
454  static
455  const std::type_info & guessType(const std::string & value);
456 
458  template <class C>
459  static
460  const std::type_info & guessArrayType(const C & container);
461  */
462 
463  static inline
464  std::ostream & toStream(std::ostream & ostr, const Type &t){
465  const std::type_info & type = t.getType();
466  ostr << Type::getTypeChar(type) << '@'; // << Type::call<drain::sizeGetter>(type);
467  return ostr;
468  }
469 
470  static inline
471  std::ostream & toStreamFull(std::ostream & ostr, const Type &t){
472  toStream(ostr, t);
473  //const std::type_info & type = t.getType();
474  // ostr << ' '<< '(' << Type::getMin<double>(type) << ',' << Type::call<drain::typeMax,double>(type) << ')';
475  /*
476  if (isSigned(type)){
477  //if (true){
478  ostr << " +/-";
479  }
480  */
481  return ostr;
482  }
483 
484  struct isEnum {
485 
486  typedef bool value_t;
487 
492  template <class S, class T>
493  static
494  T callback(){
495  return std::is_enum<S>::value;
496  }
497 
498 
499  };
500 
501 protected:
502 
507  struct typeSetter {
508 
513  template <class T>
514  static inline
515  void callback(Type & target){
516  //Logger mout(monitor, "Type", __FUNCTION__);
517  target.setType<T>();
518  }
519 
520  };
521 
522  const std::type_info *currentType;
523 
524 };
525 
526 
528 inline
529 std::ostream & operator<<(std::ostream & ostr, const Type &t){
530  Type::toStream(ostr, t);
531  return ostr;
532 }
533 
534 
535 
536 // default implementation
537 /*
538 
539 */
540 template <typename T>
541 struct TypeName
542 {
543 
544  // Recommended... See also: TreeXML
545  static const std::string & str(){
546  return name;
547  }
548 
549  /*
550  static const char* get(){
551  return name.c_str();
552  }
553  */
554 
555 
556 protected:
557 
558  static const std::string name;
559 
560 };
561 
563 template <typename T>
564 const std::string TypeName<T>::name(typeid(T).name());
565 
567 #define DRAIN_TYPENAME(tname) template <> const std::string TypeName<tname>::name
569 #define DRAIN_TYPENAME_DEF(tname) template <> const std::string TypeName<tname>::name(#tname)
570 
571 //#define DRAIN_TYPENAME_T(cname,T) template <class T> struct TypeName<cname<T> > {static const std::string & str(){static const std::string n=drain::StringBuilder<>(#cname, '<', drain::TypeName<T>::str(),'>'); return name;}
572 #define DRAIN_TYPENAME_T(cname,T) template <class T> struct TypeName<cname<T> > {static const std::string & str(){static const std::string n=drain::StringBuilder<>(#cname, '<', drain::TypeName<T>::str(),'>'); return n;}}
573 
574 
576 // (Unless the string returned by typeid is sufficient.)
577 
578 
579 DRAIN_TYPENAME(void);
580 DRAIN_TYPENAME(bool);
581 DRAIN_TYPENAME(char);
582 DRAIN_TYPENAME(unsigned char);
583 DRAIN_TYPENAME(short);
584 DRAIN_TYPENAME(unsigned short);
585 DRAIN_TYPENAME(int);
586 DRAIN_TYPENAME(unsigned int);
587 DRAIN_TYPENAME(long);
588 DRAIN_TYPENAME(unsigned long);
589 DRAIN_TYPENAME(float);
590 DRAIN_TYPENAME(double);
591 DRAIN_TYPENAME(char *);
592 DRAIN_TYPENAME(const char *); // why const separately...?
593 DRAIN_TYPENAME(std::string);
594 
595 template <typename T>
596 struct TypeName<std::initializer_list<T> > {
597 
598  static const std::string & str(){
599  static std::string name;
600  if (name.empty()){
601  name = "std::initializer_list<";
603  name += ">";
604  //name = drain::StringBuilder("std::initializer_list<", drain::TypeName<T>::get(), ">");
605  }
606  return name;
607  }
608 
609  /*
610  static const char* get(){
611  static std::string name;
612  if (name.empty()){
613  name = "std::initializer_list<";
614  name += drain::TypeName<T>::get();
615  name += ">";
616  //name = drain::StringBuilder("std::initializer_list<", drain::TypeName<T>::get(), ">");
617  }
618  return name.c_str();
619  }
620  */
621 
622 };
623 
624 
625 template <typename T>
626 struct TypeName<std::vector<T> > {
627 
628  static const std::string & str(){
629  static std::string name;
630  if (name.empty()){
631  name = "std::vector<"; // + drain::TypeName<T>::get() + ">";
633  name += ">";
634  //name = drain::StringBuilder("std::initializer_list<", drain::TypeName<T>::get(), ">");
635  }
636  return name;
637  }
638 
639  /*
640  static const char* get(){
641  static std::string name;
642  if (name.empty()){
643  //name = drain::StringBuilder("std::vector<", drain::TypeName<T>::get(), ">");
644  name = "std::vector<"; // + drain::TypeName<T>::get() + ">";
645  name += drain::TypeName<T>::get();
646  name += ">";
647  }
648  return name.c_str();
649  }
650  */
651 };
652 
653 
655 
659 class simpleName {
660 
661 public:
662 
663  typedef std::string value_t;
664  // typedef const std::string & value_t;
665 
670  template <class S, class T>
671  static
672  T callback(){
673  //return TypeName<S>::get();
674  return TypeName<S>::str();
675  }
676 
677 
678 };
679 
680 
681 
682 } // drain::
683 
684 #endif
Utilities related to std::type_info.
Definition: Type.h:51
static std::ostream & toStream(std::ostream &ostr, const Type &t)
Given a string, check if it could be stored as int or double instead of std::string .
Definition: Type.h:464
static const std::type_info & getTypeInfo(const char *typeCode)
Returns the type corresponding to a single-character string.
Definition: Type.h:410
const std::type_info & getType() const
Deprecated! Use cast (above) instead?
Definition: Type.h:107
static void call(T &target, const std::type_info &t)
Static function call without parameters on a single target of type T.
Definition: Type.h:340
static const std::type_info & getTypeInfo(char t)
Returns the base type associated with a character key.
Definition: Type.h:134
void setType(const T &t)
Set current type to t.
Definition: Type.h:83
static T call(const std::type_info &t)
Calls a static function that has no parameters.
Definition: Type.h:223
static F::value_t call(const S &typeCode)
A shorthand for functors with a fixed return type, hence D = F::value_t.
Definition: Type.h:306
static D call(const S &typeCode)
New, preferred implementation: a single if-then structure once and for all.
Definition: Type.h:293
static const std::type_info & getTypeInfo(const std::string &typeCode)
Returns the type corresponding to a single-character string.
Definition: Type.h:425
static void call(T &target, const T2 &t)
Static function call with a single parameter.
Definition: Type.h:398
static const std::type_info & getTypeInfo(const Type &t)
Convenience. Purpose is to have a full set of getTypeInfo commands for templated constructs.
Definition: Type.h:437
Returns the basic type (integer, float, bool, string, void) as a string.
Definition: Type.h:659
static T callback()
Definition: Type.h:672
Definition: DataSelector.cpp:1277
Definition: Type.h:542
static const std::string name
Default implementation: name returned by std::type_info::name()
Definition: Type.h:558
Definition: Type.h:484
static T callback()
Definition: Type.h:494
Definition: Type.h:507
static void callback(Type &target)
Definition: Type.h:515