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 <cmath> // for NaN
39
40
41#include "Type.h"
42#include "TypeUtils.h" // for typesetter
43
44
45
46
47// // using namespace std;
48
49namespace drain {
50
51
52
54
67class Caster {
68
69
70
71public:
72
74
77 inline
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
249protected:
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
494template <>
495inline
496void Caster::link(Caster &c){
497 link(c.ptr, c.getType());
498}
499
500
501template <>
502void Caster::updateType<void>();
503
504template <>
505void Caster::updateType<std::string>();
506
508template <>
509void Caster::updateType<Caster>();
510
511
512template <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
558template <>
559inline
560void Caster::put<bool>(void *p, const bool & x) const {
561 //(this->*putBool)(p,x);
562 (this->putBool)(p,x);
563}
564
565template <>
566inline
567void Caster::put<char>(void *p, const char & x) const {
568 (this->putChar)(p,x);
569}
570
571template <>
572inline
573void Caster::put<unsigned char>(void *p, const unsigned char & x) const {
574 (this->putUChar)(p,x);
575}
576
577template <> inline
578void Caster::put<int>(void *p, const int & x) const {
579 // (this->putInt)(p,x);
580 (this->putInt)(p,x);
581}
582
583template <> inline
584void Caster::put<unsigned int>(void *p, const unsigned int & x) const {
585 (this->putUInt)(p,x);
586}
587
588template <> inline
589void Caster::put<long>(void *p, const long & x) const {
590 (this->putLong)(p,x);
591}
592
593template <> inline
594void Caster::put<unsigned long>(void *p, const unsigned long & x) const {
595 (this->putULong)(p,x);
596}
597
598template <> inline
599void Caster::put<float>(void *p, const float& x) const {
600 (this->putFloat)(p,x);
601}
602
603template <> inline
604void Caster::put<double>(void *p, const double & x) const {
605 (this->putDouble)(p,x);
606}
607
608template <> inline
609void 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/*
631template <> inline
632void Caster::toOStr(std::ostream & ostr, void *p) const {
633 (this->*toOStr)(p,x);
634}
635 */
636
637template <> inline
638bool Caster::get<bool>(const void *p) const {
639 return (this->getBool)(p);
640}
641
642
643template <> inline
644char Caster::get<char>(const void *p) const {
645 return (this->getChar)(p);
646}
647
648template <> inline
649unsigned char Caster::get<unsigned char>(const void *p) const {
650 return (this->getUChar)(p);
651}
652
653template <> inline
654short Caster::get<short>(const void *p) const {
655 return (this->getShort)(p);
656}
657
658template <> inline
659unsigned short Caster::get<unsigned short>(const void *p) const {
660 return (this->getUShort)(p);
661}
662
663template <> inline
664int Caster::get<int>(const void *p) const {
665 return (this->getInt)(p);
666}
667
668template <> inline
669unsigned int Caster::get<unsigned int>(const void *p) const {
670 return (this->getUInt)(p);
671}
672
673template <> inline
674long Caster::get<long>(const void *p) const {
675 return (this->getLong)(p);
676}
677
678template <> inline
679unsigned long Caster::get<unsigned long>(const void *p) const {
680 return (this->getULong)(p);
681}
682
683template <> inline
684float Caster::get<float>(const void *p) const {
685 return (this->getFloat)(p);
686}
687
688template <> inline
689double Caster::get<double>(const void *p) const {
690 return (this->getDouble)(p);
691}
692
694
695template <> inline
696std::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.
723template <>
724inline
725void Caster::translateT<void>(const Caster &c, const void *ptrC, void *ptr){ // const {
726}
727
728// Writes to buffer of Caster pointed by ptr.
729template <>
730inline
731void 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
738template <>
739inline
740double Caster::getFromVoidT<double>(const void *p){
741 return NAN;
742}
743
744
745// Specialisation for floats returns NAN.
746template <>
747inline
748float Caster::getFromVoidT<float>(const void *p){
749 return NAN;
750}
751
753
756template <>
757inline
758bool Caster::compareT<void>(const void *ptr, const Caster &c, const void *cPtr){ // const {
759 return false;
760}
761
762
763// VOID
765template <>
766inline
767std::ostream & Caster::toOStreamT<void>(std::ostream &ostr, const void *p){ // const {
768 return ostr;
769}
770
771// BOOL
773template <>
774inline
775std::ostream & Caster::toOStreamT<bool>(std::ostream &ostr, const void *p){
776 ostr << (*(const bool *)p ? "true" : "false");
777 return ostr;
778}
779
781template <>
782inline
783std::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
790template <>
791inline
792std::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
797template <>
798inline
799std::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
std::ostream & toOStream(std::ostream &ostr) const
Write data to output stream.
Definition Caster.h:242
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
std::ostream & toOStream(std::ostream &ostr, const void *p) const
Write data to output stream.
Definition Caster.h:236
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 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
const std::type_info & getType() const
Returns type_info of the current type.
Definition Caster.h:144
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
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
std::ostream &(* toOStreamPtr)(std::ostream &ostr, const void *p)
Write to stream.
Definition Caster.h:297
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
static std::istream & fromStreamT(std::istream &istr, const void *p)
Output.
Definition Caster.h:478
static std::ostream & toOStreamT(std::ostream &ostr, const void *p)
Output.
Definition Caster.h:434
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
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