Caster.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_CASTER
32 #define DRAIN_CASTER
33 
34 
35 #include <cstddef> // nullptr
36 #include <stdexcept>
37 #include <iostream>
38 #include <cmath> // for NaN
39 
40 
41 #include "Type.h"
42 #include "TypeUtils.h" // for typesetter
43 
44 
45 
46 
47 // // using namespace std;
48 
49 namespace drain {
50 
51 
52 
54 
67 class Caster {
68 
69 
70 
71 public:
72 
74 
77  inline
78  Caster (){
79  unsetType();
80  };
81 
83 
85  inline
86  Caster (const Caster &c){
87  //std::cerr << "Caster:: warning: copy const;" << std::endl;
88  setType(c.getType());
89  ptr = c.ptr;
90  };
91 
92  inline virtual
93  ~Caster(){};
94 
95  inline
96  void link(void *p, const std::type_info &t){
97  ptr = p;
98  setType(t);
99  }
100 
101  template <class T>
102  inline
103  void link(T *p){
104  link(p, typeid(T));
105  }
106 
107  template <class T>
108  inline
109  void link(T &p){
110  link(&p, typeid(T));
111  }
112 
113 
115 
118  inline
119  void setType(const std::type_info &t){
120  Type::call<drain::typesetter>(*this, t);
121  }
122 
124  //
125  // Note: updateType planned to be renamed "directly" to setType?
126  template <class F>
127  inline
128  void setType(){
129  updateType<F>();
130  }
131 
133  virtual inline
134  bool requestType(const std::type_info & t){
135  return getType() == t;
136  }
137 
139  void unsetType(); // inline not possible here due to template<> (?)
140 
141 
143  inline
144  const std::type_info & getType() const { return *type; };
145 
146  inline
147  bool typeIsSet() const { return type != &typeid(void); };
148 
150  inline
151  size_t getElementSize() const { return byteSize; };
152 
153 
155  // => See the base type implementations below.
156  template <class T>
157  void put(void *p, const T & x) const {
158  if (typeIsSet()){
159  std::stringstream sstr;
160  sstr << x;
161  //std::cerr << "Caster::put(p, T x): stringstream conversion: " << x << "=>" << sstr.str() << std::endl;
162  put(p, sstr.str());
163  }
164  else {
165  throw std::runtime_error(std::string("Caster::put(void *, const T & ), type unset"));
166  }
167  }
168 
170  template <class T>
171  inline
172  void put(const T & x) const { // NEW
173  put(this->ptr, x);
174  }
175 
176  // Consider assigning default type (std::string?)
177  /*
178  * Notice that assigning to \c char is potentially ambiguous.
179  * char c;
180  * put(&c, "67"); // 6 or 67 or ascii('6') ?
181  * put(&c, "C"); // 0 or 67 == ascii('C') ?
182  */
183  void put(void *p, const char * x) const;
184 
186  inline
187  void put(const char * x) const { // NEW
188  put(this->ptr, x);
189  }
190 
191 
193  template <class T>
194  T get(const void *p) const {
195  throw std::runtime_error(std::string("Caster::get() unimplemented output type: ") + typeid(T).name());
196  return T();
197  }
198 
199  template <class T>
200  inline
201  T get() const { // NEW
202  return get<T>(this->ptr);
203  }
204 
205 
207  inline
208  void translate(const Caster &c, const void *ptrC, void *ptr) const {
209  //(this->*translatePtr)(c, ptrC, ptr);
210  (*translatePtr)(c, ptrC, ptr);
211  };
212 
213 
215  inline
216  void translate(const Caster &c) const { // NEW
217  //(this->*translatePtr)(c, c.ptr, this->ptr);
218  (*translatePtr)(c, c.ptr, this->ptr);
219  };
220 
221 
222  // New 2024/05
223  inline
224  bool compare(const void *ptr, const Caster &c, const void *cPtr) const {
225  return (*comparePtr)(ptr, c, cPtr);
226  }
227 
228  // New 2024/05
229  inline
230  std::istream & fromStream(std::istream & istr, const void *p) const{
231  return (*fromStreamPtr)(istr, p);
232  }
233 
235  inline
236  std::ostream & toOStream(std::ostream &ostr, const void *p) const {
237  return (*toOStreamPtr)(ostr,p);
238  }
239 
241  inline
242  std::ostream & toOStream(std::ostream &ostr) const { // NEW
243  return (*toOStreamPtr)(ostr, this->ptr);
244  }
245 
247  void *ptr = nullptr; // NEW, visible for CastableIterator
248 
249 protected:
250 
251 
253  template <class F>
254  void updateType();
255 
256 
257  //void updateCasterType();
258 
259  // New / experimental
260  void (* putBool)(void *p, const bool &x);
261  void (* putInt)(void *p, const int &x);
262  void (* putChar)(void *p, const char &x);
263  void (* putUChar)(void *p, const unsigned char &x);
264  void (* putUInt)(void *p, const unsigned int &x);
265  void (* putShort)(void *p, const short &x);
266  void (* putUShort)(void *p, const unsigned short &x);
267  void (* putLong)(void *p, const long &x);
268  void (* putULong)(void *p, const unsigned long &x);
269  void (* putFloat)(void *p, const float &x);
270  void (* putDouble)(void *p, const double &x);
271 
272 
273  char (* getChar)(const void *p);
274  unsigned char (* getUChar)(const void *p);
275  int (* getInt)(const void *p);
276  unsigned int (* getUInt)(const void *p);
277  short (* getShort)(const void *p);
278  unsigned short (* getUShort)(const void *p);
279  long (* getLong)(const void *p);
280  unsigned long (* getULong)(const void *p);
281  float (* getFloat)(const void *p);
282  double (* getDouble)(const void *p);
283 
284  bool (* getBool)(const void *p);
285 
286 
288  //void (Caster::* translatePtr)(const Caster &c, const void *ptrC, void *ptr) const;
289  void (* translatePtr)(const Caster &c, const void *ptrC, void *ptr);
290 
291  // New
292  //bool (Caster::* comparePtr)(const Caster &c, size_t i) const = nullptr;
293  bool (* comparePtr)(const void *, const Caster &c, const void *) = nullptr;
294 
296  // std::ostream & (Caster::* toOStreamPtr)(std::ostream &ostr, const void *p) const;
297  std::ostream & (* toOStreamPtr)(std::ostream &ostr, const void *p);
298  std::istream & (* fromStreamPtr)(std::istream &istr, const void *p) = nullptr;
299 
301  /*
302  * \tparam T - outer type
303  * \tparam F - inner type
304  */
305  template <class T,class F>
306  static inline
307  void putT(void *p, const T &x) {
308  *(F*)p = static_cast<F>(x);
309  }
310 
311 
313  template <class T>
314  static inline
315  void putToVoidT(void *p, const T &x) {
316  }
317 
319 
324  template <class T>
325  static inline
326  void putToStringT(void *p, const T &x) {
327  std::stringstream sstr;
328  sstr << x;
329  *(std::string*)p = sstr.str();
330  }
331 
332 
333  // Future member: enables forwarding value x to a Caster.
334  template <class T>
335  static inline
336  void putToCasterT(void *p, const T &x) {
337  Caster &c = *(Caster *)p;
338  // std::cerr << __FUNCTION__ << "(p, T x): x=" << x << std::endl;
339  // std::cerr << __FUNCTION__ << "(p, T x): dst=" << c.getType().name() << std::endl;
340  c.put(c.ptr, x);
341  // std::cerr << __FUNCTION__ << "(p, T x): (string)" << c.get<std::string>(c.ptr) << std::endl;
342  // std::cerr << __FUNCTION__ << "(p, T x): (double)" << c.get<double>(c.ptr) << std::endl;
343  }
344 
345 
346 
348 
352  template <class T,class F>
353  static inline
354  T getT(const void *p) {
355  return static_cast<T>(*(F*)p);
356  }
357 
359 
364  template <class T>
365  static inline
366  T getFromVoidT(const void *p){
367  static const T t(0);
368  //static const T t(NAN);
369  return t;
370  }
371 
373  /*
374  * \tparam T - output type
375  *
376  * The internal storage type is std::string.
377  *
378  */
379  template <class T>
380  static inline
381  T getFromStringT(const void *p) {
382  T x(0); // why (0) ?
383  std::stringstream sstr;
384  sstr << *(const std::string *)p;
385  sstr >> x;
386  return x;
387  }
388 
389  // Future member: enables forwarding from a Caster.
390  /*
391  template <class T>
392  static inline
393  T getFromCasterT(const void *p) {
394  const Caster &c = *(const Caster *)p;
395  //std::cerr << c.getType().name() << " <- " << x << std::endl;
396  return c.get<T>(c.ptr); // or even c.get<T>()
397  }
398  */
399 
400 
402 
405  template <class F>
406  static
407  void translateT(const Caster &c, const void *ptrC, void *ptr) { // const {
408  //std::cerr << "Caster::" << __FUNCTION__ << ": " << c.getType().name() << std::endl;
409  *(F *)ptr = c.get<F>(ptrC);
410  }
411 
413 
416  template <class F>
417  static
418  bool compareT(const void *ptr, const Caster &c, const void *cPtr){ // const
419 
420  if (ptr == nullptr)
421  return false;
422 
423  if (cPtr == nullptr)
424  return false;
425 
426  return (*(F *)ptr == c.get<F>(cPtr));
427  // return false;
428  // return this->get<F>(i) == c.get<F>(i);
429  }
430 
432  template <class F>
433  static
434  std::ostream & toOStreamT(std::ostream & ostr, const void *p) { //const {
435  if (p != nullptr)
436  ostr << *(F*)p;
437  return ostr;
438  }
439 
440  template <class F>
441  static
442  std::ostream & toOStreamFloats(std::ostream & ostr, const void *p){
443 
444  if (!p)
445  throw std::runtime_error("Caster::toOStreamT<double>:: null ptr as argument");
446 
447  const F d = *(F *)p;
448 
449  if (std::isnan(d)){
450  ostr << "null"; // JSON has no NaN (only true, false and null)
451  //ostr << "NaN"; // JSONtree std literal
452  }
453  /* TODO: add at least one decimal for floating-point numbers ".0"
454  else if ((d == rint(d)) && (abs(d) < 1.0E+5)){
455  //ostr << std::ios::fixed << std::setprecision(2) << d;
456 
457  const std::streamsize prec = ostr.precision();
458  // // const std::ios_base::fmtflags flags = ostr.setf(std::ios::fixed, std::ios::floatfield );
459 
460  ostr.precision(1);
461  ostr << d;
462  // // ostr.setf(flags);
463  ostr.precision(prec);
464 
465  }
466  */
467  else {
468  ostr << d;
469  }
470 
471  return ostr;
472 
473  }
474 
476  template <class F>
477  static
478  std::istream & fromStreamT(std::istream & istr, const void *p) { //const {
479  if (p != nullptr){
480  istr >> *(F*)p;
481  }
482  return istr;
483  }
484 
485 
487  const std::type_info *type;
488 
490  size_t byteSize;
491 
492 };
493 
494 template <>
495 inline
496 void Caster::link(Caster &c){
497  link(c.ptr, c.getType());
498 }
499 
500 
501 template <>
502 void Caster::updateType<void>();
503 
504 template <>
505 void Caster::updateType<std::string>();
506 
508 template <>
509 void Caster::updateType<Caster>();
510 
511 
512 template <class F>
514 
515  if (!std::is_fundamental<F>::value){
516  throw std::runtime_error(std::string(__FILE__) + __FUNCTION__ + ':' + typeid(F).name() + ": cannot convert to basic types");
517  return;
518  }
519 
520 
521  type = & typeid(F);
522  byteSize = sizeof(F)/sizeof(char);
523 
525  putBool = & Caster::putT<bool,F>;
526  putInt = & Caster::putT<int,F>;
527  putChar = & Caster::putT<char,F>;
528  putUChar = & Caster::putT<unsigned char,F>;
529  putUInt = & Caster::putT<unsigned int,F>;
530  putShort = & Caster::putT<short,F>;
531  putUShort = & Caster::putT<unsigned short,F>;
532  putLong = & Caster::putT<long int,F>;
533  putULong = & Caster::putT<unsigned long,F>;
534  putFloat = & Caster::putT<float,F>;
535  putDouble = & Caster::putT<double,F>;
536 
537  getBool = & Caster::getT<bool,F>;
538  getInt = & Caster::getT<int,F>;
539  getChar = & Caster::getT<char,F>;
540  getUChar = & Caster::getT<unsigned char,F>;
541  getUInt = & Caster::getT<unsigned int,F>;
542  getShort = & Caster::getT<short,F>;
543  getUShort = & Caster::getT<unsigned short,F>;
544  getLong = & Caster::getT<long,F>;
545  getULong = & Caster::getT<unsigned long,F>;
546  getFloat = & Caster::getT<float,F>;
547  getDouble = & Caster::getT<double,F>;
548 
549  translatePtr = & Caster::translateT<F>;
550  comparePtr = & Caster::compareT<F>;
551 
552  toOStreamPtr = & Caster::toOStreamT<F>;
553  fromStreamPtr = & Caster::fromStreamT<F>;
554 }
555 
556 
557 
558 template <>
559 inline
560 void Caster::put<bool>(void *p, const bool & x) const {
561  //(this->*putBool)(p,x);
562  (this->putBool)(p,x);
563 }
564 
565 template <>
566 inline
567 void Caster::put<char>(void *p, const char & x) const {
568  (this->putChar)(p,x);
569 }
570 
571 template <>
572 inline
573 void Caster::put<unsigned char>(void *p, const unsigned char & x) const {
574  (this->putUChar)(p,x);
575 }
576 
577 template <> inline
578 void Caster::put<int>(void *p, const int & x) const {
579  // (this->putInt)(p,x);
580  (this->putInt)(p,x);
581 }
582 
583 template <> inline
584 void Caster::put<unsigned int>(void *p, const unsigned int & x) const {
585  (this->putUInt)(p,x);
586 }
587 
588 template <> inline
589 void Caster::put<long>(void *p, const long & x) const {
590  (this->putLong)(p,x);
591 }
592 
593 template <> inline
594 void Caster::put<unsigned long>(void *p, const unsigned long & x) const {
595  (this->putULong)(p,x);
596 }
597 
598 template <> inline
599 void Caster::put<float>(void *p, const float& x) const {
600  (this->putFloat)(p,x);
601 }
602 
603 template <> inline
604 void Caster::put<double>(void *p, const double & x) const {
605  (this->putDouble)(p,x);
606 }
607 
608 template <> inline
609 void Caster::put<std::string>(void *p, const std::string & x) const {
610  //put(p, x.c_str()); Dangerous, if F = std::string
611 
612  //std::cerr << "Laita std::string x=" << x << std::endl;
613  if (getType() == typeid(std::string))
614  *(std::string *)p = x;
615  else if (getType() == typeid(char)){
616  // std::cout << "note: experimental str to char\n";
617  if (x.empty())
618  p = nullptr; //'\0'; // NULL, 0 ?
619  else {
620  if (x.size() > 1)
621  std::cerr << "Caster::put<std::string>() warning: single-char dst, assigned 1st of multi-char '"<< x << "'\n";
622  *(char *)p = x.at(0);
623  }
624  }
625  else
626  put(p, x.c_str());
627 
628 }
629 
630 /*
631 template <> inline
632 void Caster::toOStr(std::ostream & ostr, void *p) const {
633  (this->*toOStr)(p,x);
634 }
635  */
636 
637 template <> inline
638 bool Caster::get<bool>(const void *p) const {
639  return (this->getBool)(p);
640 }
641 
642 
643 template <> inline
644 char Caster::get<char>(const void *p) const {
645  return (this->getChar)(p);
646 }
647 
648 template <> inline
649 unsigned char Caster::get<unsigned char>(const void *p) const {
650  return (this->getUChar)(p);
651 }
652 
653 template <> inline
654 short Caster::get<short>(const void *p) const {
655  return (this->getShort)(p);
656 }
657 
658 template <> inline
659 unsigned short Caster::get<unsigned short>(const void *p) const {
660  return (this->getUShort)(p);
661 }
662 
663 template <> inline
664 int Caster::get<int>(const void *p) const {
665  return (this->getInt)(p);
666 }
667 
668 template <> inline
669 unsigned int Caster::get<unsigned int>(const void *p) const {
670  return (this->getUInt)(p);
671 }
672 
673 template <> inline
674 long Caster::get<long>(const void *p) const {
675  return (this->getLong)(p);
676 }
677 
678 template <> inline
679 unsigned long Caster::get<unsigned long>(const void *p) const {
680  return (this->getULong)(p);
681 }
682 
683 template <> inline
684 float Caster::get<float>(const void *p) const {
685  return (this->getFloat)(p);
686 }
687 
688 template <> inline
689 double Caster::get<double>(const void *p) const {
690  return (this->getDouble)(p);
691 }
692 
694 
695 template <> inline
696 std::string Caster::get<std::string>(const void *p) const {
697 
698  // void is handled by toOStr, but this is faster.
699  if (getType() == typeid(void)){
700  static const std::string empty;
701  return empty;
702  }
703  else if (getType() == typeid(char)){
704  // std::cout << "note: experimental char to str\n";
705  return std::string(1, *(char *)p); // NOTE: this does not handle char array of more elements!
706  }
707  else if (getType() == typeid(bool)){
708  return *(const bool *)p ? "true" : "false";
709  }
710  else if (getType() == typeid(std::string)){
711  return *(const std::string *)p;
712  }
713  else {
714  std::stringstream sstr;
715  toOStream(sstr, p);
716  // sstr << (this->getDouble)(p);
717  return sstr.str();
718  }
719 }
720 
721 
722 // Does nothing, leaves ptr intact.
723 template <>
724 inline
725 void Caster::translateT<void>(const Caster &c, const void *ptrC, void *ptr){ // const {
726 }
727 
728 // Writes to buffer of Caster pointed by ptr.
729 template <>
730 inline
731 void Caster::translateT<Caster>(const Caster &c, const void *ptrC, void *ptr){ // const {
732  Caster & c2 = *(Caster *)ptr;
733  c2.translate(c, ptrC, c2.ptr);
734  //*(F *)ptr = c.get<F>(ptrC);
735 }
736 
738 template <>
739 inline
740 double Caster::getFromVoidT<double>(const void *p){
741  return NAN;
742 }
743 
744 
745 // Specialisation for floats returns NAN.
746 template <>
747 inline
748 float Caster::getFromVoidT<float>(const void *p){
749  return NAN;
750 }
751 
753 
756 template <>
757 inline
758 bool Caster::compareT<void>(const void *ptr, const Caster &c, const void *cPtr){ // const {
759  return false;
760 }
761 
762 
763 // VOID
765 template <>
766 inline
767 std::ostream & Caster::toOStreamT<void>(std::ostream &ostr, const void *p){ // const {
768  return ostr;
769 }
770 
771 // BOOL
773 template <>
774 inline
775 std::ostream & Caster::toOStreamT<bool>(std::ostream &ostr, const void *p){
776  ostr << (*(const bool *)p ? "true" : "false");
777  return ostr;
778 }
779 
781 template <>
782 inline
783 std::ostream & Caster::toOStreamT<Caster>(std::ostream &ostr, const void *p){ // const {
784  const Caster &c = *(const Caster *)p;
785  c.toOStream(ostr);
786  return ostr;
787 }
788 
789 // Yes, to get trailing period and zero: .0
790 template <>
791 inline
792 std::ostream & Caster::toOStreamT<float>(std::ostream & ostr, const void *p){
793  return toOStreamFloats<float>(ostr, p);
794 }
795 
796 // Yes, to get trailing period and zero: .0
797 template <>
798 inline
799 std::ostream & Caster::toOStreamT<double>(std::ostream & ostr, const void *p){
800  return toOStreamFloats<double>(ostr, p);
801 }
802 
803 
804 
805 } // namespace drain
806 
807 
808 #endif
809 
810 // Drain
Definition: Caster.h:67
void updateType()
Sets pointers to the type-dependent conversion functions.
Definition: Caster.h:513
void put(const T &x) const
Write to internal pointer using put(this->ptr, x).
Definition: Caster.h:172
void put(const char *x) const
Write to internal pointer, calls put(this->ptr, x).
Definition: Caster.h:187
const std::type_info * type
Current type.
Definition: Caster.h:487
const std::type_info & getType() const
Returns type_info of the current type.
Definition: Caster.h:144
static T getFromVoidT(const void *p)
This default implementation is for integral numeric types, returns zero. Specialisation for floats re...
Definition: Caster.h:366
static std::ostream & toOStreamT(std::ostream &ostr, const void *p)
Output.
Definition: Caster.h:434
static std::istream & fromStreamT(std::istream &istr, const void *p)
Output.
Definition: Caster.h:478
static T getT(const void *p)
The main handler converting input to output.
Definition: Caster.h:354
T get(const void *p) const
Default implementation throws an error. See specialized implementation below.
Definition: Caster.h:194
void unsetType()
calls void setType<void>().
Definition: Caster.cpp:134
std::ostream &(* toOStreamPtr)(std::ostream &ostr, const void *p)
Write to stream.
Definition: Caster.h:297
static bool compareT(const void *ptr, const Caster &c, const void *cPtr)
Checks equality through base type casting.
Definition: Caster.h:418
static void putToVoidT(void *p, const T &x)
Void - does nothing, regardless of input type.
Definition: Caster.h:315
size_t getElementSize() const
Returns the size of the base type (size of an element, not of element array).
Definition: Caster.h:151
void setType(const std::type_info &t)
Calls setType<T>() for which typeid(T) = t.
Definition: Caster.h:119
Caster()
Default constructor. Leaves the type undefined.
Definition: Caster.h:78
std::ostream & toOStream(std::ostream &ostr, const void *p) const
Write data to output stream.
Definition: Caster.h:236
virtual bool requestType(const std::type_info &t)
Utility for derived classes, which may be able to adapt memory array type as well.
Definition: Caster.h:134
size_t byteSize
Size of target memory (target object) in bytes.
Definition: Caster.h:490
void translate(const Caster &c) const
Convert from str Caster.
Definition: Caster.h:216
void(* translatePtr)(const Caster &c, const void *ptrC, void *ptr)
Convert from str pointer and Caster.
Definition: Caster.h:289
void setType()
Sets pointers to the type-dependent conversion functions.
Definition: Caster.h:128
void translate(const Caster &c, const void *ptrC, void *ptr) const
Convert from str pointer and Caster.
Definition: Caster.h:208
static T getFromStringT(const void *p)
The main handler converting input to output.
Definition: Caster.h:381
void * ptr
Future member: enables setting Caster type.
Definition: Caster.h:247
void put(void *p, const T &x) const
Default conversion (for unconventional types). Uses std::stringstream for conversion.
Definition: Caster.h:157
static void putToStringT(void *p, const T &x)
A handler for converting input to a std::string.
Definition: Caster.h:326
std::ostream & toOStream(std::ostream &ostr) const
Write data to output stream.
Definition: Caster.h:242
Caster(const Caster &c)
Copy constructor. Copies the type.
Definition: Caster.h:86
static void translateT(const Caster &c, const void *ptrC, void *ptr)
Casts from ptrC to ptr.
Definition: Caster.h:407
static void putT(void *p, const T &x)
Convert input of base type to internally applied base type.
Definition: Caster.h:307
Definition: DataSelector.cpp:1277