Loading...
Searching...
No Matches
Caster.h
1/*
2
3MIT License
4
5Copyright (c) 2017 FMI Open Development / Markus Peura, first.last@fmi.fi
6
7Permission is hereby granted, free of charge, to any person obtaining a copy
8of this software and associated documentation files (the "Software"), to deal
9in the Software without restriction, including without limitation the rights
10to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11copies of the Software, and to permit persons to whom the Software is
12furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in all
15copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23SOFTWARE.
24
25*/
26/*
27Part of Rack development has been done in the BALTRAD projects part-financed
28by the European Union (European Regional Development Fund and European
29Neighbourhood 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 <sstream>
39#include <cmath> // for NaN
40
41
42//#include "TypeName.h"
43//#include "TypeUtils.h" // for typesetter
44#include "Type.h"
45
46
47
48// // using namespace std;
49
50namespace drain {
51
52
53
55
68class Caster {
69
70
71
72public:
73
75
78 inline
80 unsetType();
81 };
82
84
86 inline
87 Caster (const Caster &c){
88 //std::cerr << "Caster:: warning: copy const;" << std::endl;
89 setType(c.getType());
90 ptr = c.ptr;
91 };
92
93 inline virtual
94 ~Caster(){};
95
96 inline
97 void link(void *p, const std::type_info &t){
98 ptr = p;
99 setType(t);
100 }
101
102 template <class T>
103 inline
104 void link(T *p){
105 link(p, typeid(T));
106 }
107
108 template <class T>
109 inline
110 void link(T &p){
111 link(&p, typeid(T));
112 }
113
114
116
119 inline
120 void setType(const std::type_info &t){
121 Type::call<drain::Type::typeSetter>(*this, t);
122 }
123
125 //
126 // Note: updateType planned to be renamed "directly" to setType?
127 template <class F>
128 inline
129 void setType(){
130 updateType<F>();
131 }
132
134 virtual inline
135 bool requestType(const std::type_info & t){
136 return getType() == t;
137 }
138
140 void unsetType(); // inline not possible here due to template<> (?)
141
142
144 inline
145 const std::type_info & getType() const { return *type; };
146
147 inline
148 bool typeIsSet() const { return type != &typeid(void); };
149
151 inline
152 size_t getElementSize() const { return byteSize; };
153
154
156 // => See the base type implementations below.
157 template <class T>
158 void put(void *p, const T & x) const {
159 if (typeIsSet()){
160 std::stringstream sstr;
161 sstr << x;
162 //std::cerr << "Caster::put(p, T x): stringstream conversion: " << x << "=>" << sstr.str() << std::endl;
163 put(p, sstr.str());
164 }
165 else {
166 throw std::runtime_error(std::string("Caster::put(void *, const T & ), type unset"));
167 }
168 }
169
171 template <class T>
172 inline
173 void put(const T & x) const { // NEW
174 put(this->ptr, x);
175 }
176
177 // Consider assigning default type (std::string?)
178 /*
179 * Notice that assigning to \c char is potentially ambiguous.
180 * char c;
181 * put(&c, "67"); // 6 or 67 or ascii('6') ?
182 * put(&c, "C"); // 0 or 67 == ascii('C') ?
183 */
184 void put(void *p, const char * x) const;
185
187 inline
188 void put(const char * x) const { // NEW
189 put(this->ptr, x);
190 }
191
192
194 template <class T>
195 T get(const void *p) const {
196 throw std::runtime_error(std::string("Caster::get() unimplemented output type: ") + typeid(T).name());
197 return T();
198 }
199
200 template <class T>
201 inline
202 T get() const { // NEW
203 return get<T>(this->ptr);
204 }
205
206
208 inline
209 void translate(const Caster &c, const void *ptrC, void *ptr) const {
210 //(this->*translatePtr)(c, ptrC, ptr);
211 (*translatePtr)(c, ptrC, ptr);
212 };
213
214
216 inline
217 void translate(const Caster &c) const { // NEW
218 //(this->*translatePtr)(c, c.ptr, this->ptr);
219 (*translatePtr)(c, c.ptr, this->ptr);
220 };
221
222
223 // New 2024/05
224 inline
225 bool compare(const void *ptr, const Caster &c, const void *cPtr) const {
226 return (*comparePtr)(ptr, c, cPtr);
227 }
228
229 // New 2024/05
230 inline
231 std::istream & fromStream(std::istream & istr, const void *p) const{
232 return (*fromStreamPtr)(istr, p);
233 }
234
236 inline
237 std::ostream & toOStream(std::ostream &ostr, const void *p) const {
238 return (*toOStreamPtr)(ostr,p);
239 }
240
242 inline
243 std::ostream & toOStream(std::ostream &ostr) const { // NEW
244 return (*toOStreamPtr)(ostr, this->ptr);
245 }
246
248 void *ptr = nullptr; // NEW, visible for CastableIterator
249
250protected:
251
252
254 template <class F>
255 void updateType();
256
257
258 //void updateCasterType();
259
260 // New / experimental
261 void (* putBool)(void *p, const bool &x);
262 void (* putInt)(void *p, const int &x);
263 void (* putChar)(void *p, const char &x);
264 void (* putUChar)(void *p, const unsigned char &x);
265 void (* putUInt)(void *p, const unsigned int &x);
266 void (* putShort)(void *p, const short &x);
267 void (* putUShort)(void *p, const unsigned short &x);
268 void (* putLong)(void *p, const long &x);
269 void (* putULong)(void *p, const unsigned long &x);
270 void (* putFloat)(void *p, const float &x);
271 void (* putDouble)(void *p, const double &x);
272
273
274 char (* getChar)(const void *p);
275 unsigned char (* getUChar)(const void *p);
276 int (* getInt)(const void *p);
277 unsigned int (* getUInt)(const void *p);
278 short (* getShort)(const void *p);
279 unsigned short (* getUShort)(const void *p);
280 long (* getLong)(const void *p);
281 unsigned long (* getULong)(const void *p);
282 float (* getFloat)(const void *p);
283 double (* getDouble)(const void *p);
284
285 bool (* getBool)(const void *p);
286
287
289 //void (Caster::* translatePtr)(const Caster &c, const void *ptrC, void *ptr) const;
290 void (* translatePtr)(const Caster &c, const void *ptrC, void *ptr);
291
292 // New
293 //bool (Caster::* comparePtr)(const Caster &c, size_t i) const = nullptr;
294 bool (* comparePtr)(const void *, const Caster &c, const void *) = nullptr;
295
297 // std::ostream & (Caster::* toOStreamPtr)(std::ostream &ostr, const void *p) const;
298 std::ostream & (* toOStreamPtr)(std::ostream &ostr, const void *p);
299 std::istream & (* fromStreamPtr)(std::istream &istr, const void *p) = nullptr;
300
302 /*
303 * \tparam T - outer type
304 * \tparam F - inner type
305 */
306 template <class T,class F>
307 static inline
308 void putT(void *p, const T &x) {
309 *(F*)p = static_cast<F>(x);
310 }
311
312
314 template <class T>
315 static inline
316 void putToVoidT(void *p, const T &x) {
317 }
318
320
325 template <class T>
326 static inline
327 void putToStringT(void *p, const T &x) {
328 std::stringstream sstr;
329 sstr << x;
330 *(std::string*)p = sstr.str();
331 }
332
333
334 // Future member: enables forwarding value x to a Caster.
335 template <class T>
336 static inline
337 void putToCasterT(void *p, const T &x) {
338 Caster &c = *(Caster *)p;
339 // std::cerr << __FUNCTION__ << "(p, T x): x=" << x << std::endl;
340 // std::cerr << __FUNCTION__ << "(p, T x): dst=" << c.getType().name() << std::endl;
341 c.put(c.ptr, x);
342 // std::cerr << __FUNCTION__ << "(p, T x): (string)" << c.get<std::string>(c.ptr) << std::endl;
343 // std::cerr << __FUNCTION__ << "(p, T x): (double)" << c.get<double>(c.ptr) << std::endl;
344 }
345
346
347
349
353 template <class T,class F>
354 static inline
355 T getT(const void *p) {
356 return static_cast<T>(*(F*)p);
357 }
358
360
365 template <class T>
366 static inline
367 T getFromVoidT(const void *p){
368 static const T t(0);
369 //static const T t(NAN);
370 return t;
371 }
372
374 /*
375 * \tparam T - output type
376 *
377 * The internal storage type is std::string.
378 *
379 */
380 template <class T>
381 static inline
382 T getFromStringT(const void *p) {
383 T x(0); // why (0) ?
384 std::stringstream sstr;
385 sstr << *(const std::string *)p;
386 sstr >> x;
387 return x;
388 }
389
390 // Future member: enables forwarding from a Caster.
391 /*
392 template <class T>
393 static inline
394 T getFromCasterT(const void *p) {
395 const Caster &c = *(const Caster *)p;
396 //std::cerr << c.getType().name() << " <- " << x << std::endl;
397 return c.get<T>(c.ptr); // or even c.get<T>()
398 }
399 */
400
401
403
406 template <class F>
407 static
408 void translateT(const Caster &c, const void *ptrC, void *ptr) { // const {
409 //std::cerr << "Caster::" << __FUNCTION__ << ": " << c.getType().name() << std::endl;
410 *(F *)ptr = c.get<F>(ptrC);
411 }
412
414
417 template <class F>
418 static
419 bool compareT(const void *ptr, const Caster &c, const void *cPtr){ // const
420
421 if (ptr == nullptr)
422 return false;
423
424 if (cPtr == nullptr)
425 return false;
426
427 return (*(F *)ptr == c.get<F>(cPtr));
428 // return false;
429 // return this->get<F>(i) == c.get<F>(i);
430 }
431
433 template <class F>
434 static
435 std::ostream & toOStreamT(std::ostream & ostr, const void *p) { //const {
436 if (p != nullptr)
437 ostr << *(F*)p;
438 return ostr;
439 }
440
441 template <class F>
442 static
443 std::ostream & toOStreamFloats(std::ostream & ostr, const void *p){
444
445 if (!p)
446 throw std::runtime_error("Caster::toOStreamT<double>:: null ptr as argument");
447
448 const F d = *(F *)p;
449
450 if (std::isnan(d)){
451 ostr << "null"; // JSON has no NaN (only true, false and null)
452 //ostr << "NaN"; // JSONtree std literal
453 }
454 /* TODO: add at least one decimal for floating-point numbers ".0"
455 else if ((d == rint(d)) && (abs(d) < 1.0E+5)){
456 //ostr << std::ios::fixed << std::setprecision(2) << d;
457
458 const std::streamsize prec = ostr.precision();
459 // // const std::ios_base::fmtflags flags = ostr.setf(std::ios::fixed, std::ios::floatfield );
460
461 ostr.precision(1);
462 ostr << d;
463 // // ostr.setf(flags);
464 ostr.precision(prec);
465
466 }
467 */
468 else {
469 ostr << d;
470 }
471
472 return ostr;
473
474 }
475
477 template <class F>
478 static
479 std::istream & fromStreamT(std::istream & istr, const void *p) { //const {
480 if (p != nullptr){
481 istr >> *(F*)p;
482 }
483 return istr;
484 }
485
486
488 const std::type_info *type;
489
491 size_t byteSize;
492
493};
494
495template <>
496inline
497void Caster::link(Caster &c){
498 link(c.ptr, c.getType());
499}
500
501
502template <>
503void Caster::updateType<void>();
504
505template <>
506void Caster::updateType<std::string>();
507
509template <>
510void Caster::updateType<Caster>();
511
512
513template <class F>
515
516 if (!std::is_fundamental<F>::value){
517 throw std::runtime_error(std::string(__FILE__) + __FUNCTION__ + ':' + typeid(F).name() + ": cannot convert to basic types");
518 return;
519 }
520
521
522 type = & typeid(F);
523 byteSize = sizeof(F)/sizeof(char);
524
526 putBool = & Caster::putT<bool,F>;
527 putInt = & Caster::putT<int,F>;
528 putChar = & Caster::putT<char,F>;
529 putUChar = & Caster::putT<unsigned char,F>;
530 putUInt = & Caster::putT<unsigned int,F>;
531 putShort = & Caster::putT<short,F>;
532 putUShort = & Caster::putT<unsigned short,F>;
533 putLong = & Caster::putT<long int,F>;
534 putULong = & Caster::putT<unsigned long,F>;
535 putFloat = & Caster::putT<float,F>;
536 putDouble = & Caster::putT<double,F>;
537
538 getBool = & Caster::getT<bool,F>;
539 getInt = & Caster::getT<int,F>;
540 getChar = & Caster::getT<char,F>;
541 getUChar = & Caster::getT<unsigned char,F>;
542 getUInt = & Caster::getT<unsigned int,F>;
543 getShort = & Caster::getT<short,F>;
544 getUShort = & Caster::getT<unsigned short,F>;
545 getLong = & Caster::getT<long,F>;
546 getULong = & Caster::getT<unsigned long,F>;
547 getFloat = & Caster::getT<float,F>;
548 getDouble = & Caster::getT<double,F>;
549
550 translatePtr = & Caster::translateT<F>;
551 comparePtr = & Caster::compareT<F>;
552
553 toOStreamPtr = & Caster::toOStreamT<F>;
554 fromStreamPtr = & Caster::fromStreamT<F>;
555}
556
557
558
559template <>
560inline
561void Caster::put<bool>(void *p, const bool & x) const {
562 //(this->*putBool)(p,x);
563 (this->putBool)(p,x);
564}
565
566template <>
567inline
568void Caster::put<char>(void *p, const char & x) const {
569 (this->putChar)(p,x);
570}
571
572template <>
573inline
574void Caster::put<unsigned char>(void *p, const unsigned char & x) const {
575 (this->putUChar)(p,x);
576}
577
578template <> inline
579void Caster::put<int>(void *p, const int & x) const {
580 // (this->putInt)(p,x);
581 (this->putInt)(p,x);
582}
583
584template <> inline
585void Caster::put<unsigned int>(void *p, const unsigned int & x) const {
586 (this->putUInt)(p,x);
587}
588
589template <> inline
590void Caster::put<long>(void *p, const long & x) const {
591 (this->putLong)(p,x);
592}
593
594template <> inline
595void Caster::put<unsigned long>(void *p, const unsigned long & x) const {
596 (this->putULong)(p,x);
597}
598
599template <> inline
600void Caster::put<float>(void *p, const float& x) const {
601 (this->putFloat)(p,x);
602}
603
604template <> inline
605void Caster::put<double>(void *p, const double & x) const {
606 (this->putDouble)(p,x);
607}
608
609template <> inline
610void Caster::put<std::string>(void *p, const std::string & x) const {
611 //put(p, x.c_str()); Dangerous, if F = std::string
612
613 //std::cerr << "Laita std::string x=" << x << std::endl;
614 if (getType() == typeid(std::string))
615 *(std::string *)p = x;
616 else if (getType() == typeid(char)){
617 // std::cout << "note: experimental str to char\n";
618 if (x.empty())
619 p = nullptr; //'\0'; // NULL, 0 ?
620 else {
621 if (x.size() > 1)
622 std::cerr << "Caster::put<std::string>() warning: single-char dst, assigned 1st of multi-char '"<< x << "'\n";
623 *(char *)p = x.at(0);
624 }
625 }
626 else
627 put(p, x.c_str());
628
629}
630
631/*
632template <> inline
633void Caster::toOStr(std::ostream & ostr, void *p) const {
634 (this->*toOStr)(p,x);
635}
636 */
637
638template <> inline
639bool Caster::get<bool>(const void *p) const {
640 return (this->getBool)(p);
641}
642
643
644template <> inline
645char Caster::get<char>(const void *p) const {
646 return (this->getChar)(p);
647}
648
649template <> inline
650unsigned char Caster::get<unsigned char>(const void *p) const {
651 return (this->getUChar)(p);
652}
653
654template <> inline
655short Caster::get<short>(const void *p) const {
656 return (this->getShort)(p);
657}
658
659template <> inline
660unsigned short Caster::get<unsigned short>(const void *p) const {
661 return (this->getUShort)(p);
662}
663
664template <> inline
665int Caster::get<int>(const void *p) const {
666 return (this->getInt)(p);
667}
668
669template <> inline
670unsigned int Caster::get<unsigned int>(const void *p) const {
671 return (this->getUInt)(p);
672}
673
674template <> inline
675long Caster::get<long>(const void *p) const {
676 return (this->getLong)(p);
677}
678
679template <> inline
680unsigned long Caster::get<unsigned long>(const void *p) const {
681 return (this->getULong)(p);
682}
683
684template <> inline
685float Caster::get<float>(const void *p) const {
686 return (this->getFloat)(p);
687}
688
689template <> inline
690double Caster::get<double>(const void *p) const {
691 return (this->getDouble)(p);
692}
693
695
696template <> inline
697std::string Caster::get<std::string>(const void *p) const {
698
699 // void is handled by toOStr, but this is faster.
700 if (getType() == typeid(void)){
701 static const std::string empty;
702 return empty;
703 }
704 else if (getType() == typeid(char)){
705 // std::cout << "note: experimental char to str\n";
706 return std::string(1, *(char *)p); // NOTE: this does not handle char array of more elements!
707 }
708 else if (getType() == typeid(bool)){
709 return *(const bool *)p ? "true" : "false";
710 }
711 else if (getType() == typeid(std::string)){
712 return *(const std::string *)p;
713 }
714 else {
715 std::stringstream sstr;
716 toOStream(sstr, p);
717 // sstr << (this->getDouble)(p);
718 return sstr.str();
719 }
720}
721
722
723// Does nothing, leaves ptr intact.
724template <>
725inline
726void Caster::translateT<void>(const Caster &c, const void *ptrC, void *ptr){ // const {
727}
728
729// Writes to buffer of Caster pointed by ptr.
730template <>
731inline
732void Caster::translateT<Caster>(const Caster &c, const void *ptrC, void *ptr){ // const {
733 Caster & c2 = *(Caster *)ptr;
734 c2.translate(c, ptrC, c2.ptr);
735 //*(F *)ptr = c.get<F>(ptrC);
736}
737
739template <>
740inline
741double Caster::getFromVoidT<double>(const void *p){
742 return NAN;
743}
744
745
746// Specialisation for floats returns NAN.
747template <>
748inline
749float Caster::getFromVoidT<float>(const void *p){
750 return NAN;
751}
752
754
757template <>
758inline
759bool Caster::compareT<void>(const void *ptr, const Caster &c, const void *cPtr){ // const {
760 return false;
761}
762
763
764// VOID
766template <>
767inline
768std::ostream & Caster::toOStreamT<void>(std::ostream &ostr, const void *p){ // const {
769 return ostr;
770}
771
772// BOOL
774template <>
775inline
776std::ostream & Caster::toOStreamT<bool>(std::ostream &ostr, const void *p){
777 ostr << (*(const bool *)p ? "true" : "false");
778 return ostr;
779}
780
782template <>
783inline
784std::ostream & Caster::toOStreamT<Caster>(std::ostream &ostr, const void *p){ // const {
785 const Caster &c = *(const Caster *)p;
786 c.toOStream(ostr);
787 return ostr;
788}
789
790// Yes, to get trailing period and zero: .0
791template <>
792inline
793std::ostream & Caster::toOStreamT<float>(std::ostream & ostr, const void *p){
794 return toOStreamFloats<float>(ostr, p);
795}
796
797// Yes, to get trailing period and zero: .0
798template <>
799inline
800std::ostream & Caster::toOStreamT<double>(std::ostream & ostr, const void *p){
801 return toOStreamFloats<double>(ostr, p);
802}
803
804
805
806} // namespace drain
807
808
809#endif
810
811// Drain
Definition Caster.h:68
std::ostream & toOStream(std::ostream &ostr) const
Write data to output stream.
Definition Caster.h:243
void updateType()
Sets pointers to the type-dependent conversion functions.
Definition Caster.h:514
void put(const T &x) const
Write to internal pointer using put(this->ptr, x).
Definition Caster.h:173
void put(const char *x) const
Write to internal pointer, calls put(this->ptr, x).
Definition Caster.h:188
const std::type_info * type
Current type.
Definition Caster.h:488
std::ostream & toOStream(std::ostream &ostr, const void *p) const
Write data to output stream.
Definition Caster.h:237
static T getFromVoidT(const void *p)
This default implementation is for integral numeric types, returns zero. Specialisation for floats re...
Definition Caster.h:367
static T getT(const void *p)
The main handler converting input to output.
Definition Caster.h:355
T get(const void *p) const
Default implementation throws an error. See specialized implementation below.
Definition Caster.h:195
void unsetType()
calls void setType<void>().
Definition Caster.cpp:135
const std::type_info & getType() const
Returns type_info of the current type.
Definition Caster.h:145
static bool compareT(const void *ptr, const Caster &c, const void *cPtr)
Checks equality through base type casting.
Definition Caster.h:419
static void putToVoidT(void *p, const T &x)
Void - does nothing, regardless of input type.
Definition Caster.h:316
size_t getElementSize() const
Returns the size of the base type (size of an element, not of element array).
Definition Caster.h:152
void setType(const std::type_info &t)
Calls setType<T>() for which typeid(T) = t.
Definition Caster.h:120
Caster()
Default constructor. Leaves the type undefined.
Definition Caster.h:79
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:135
size_t byteSize
Size of target memory (target object) in bytes.
Definition Caster.h:491
void translate(const Caster &c) const
Convert from str Caster.
Definition Caster.h:217
void(* translatePtr)(const Caster &c, const void *ptrC, void *ptr)
Convert from str pointer and Caster.
Definition Caster.h:290
std::ostream &(* toOStreamPtr)(std::ostream &ostr, const void *p)
Write to stream.
Definition Caster.h:298
void setType()
Sets pointers to the type-dependent conversion functions.
Definition Caster.h:129
void translate(const Caster &c, const void *ptrC, void *ptr) const
Convert from str pointer and Caster.
Definition Caster.h:209
static T getFromStringT(const void *p)
The main handler converting input to output.
Definition Caster.h:382
void * ptr
Future member: enables setting Caster type.
Definition Caster.h:248
static std::istream & fromStreamT(std::istream &istr, const void *p)
Output.
Definition Caster.h:479
static std::ostream & toOStreamT(std::ostream &ostr, const void *p)
Output.
Definition Caster.h:435
void put(void *p, const T &x) const
Default conversion (for unconventional types). Uses std::stringstream for conversion.
Definition Caster.h:158
static void putToStringT(void *p, const T &x)
A handler for converting input to a std::string.
Definition Caster.h:327
Caster(const Caster &c)
Copy constructor. Copies the type.
Definition Caster.h:87
static void translateT(const Caster &c, const void *ptrC, void *ptr)
Casts from ptrC to ptr.
Definition Caster.h:408
static void putT(void *p, const T &x)
Convert input of base type to internally applied base type.
Definition Caster.h:308
Definition DataSelector.cpp:1277