Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core3/src/util/Convert.h @ 1586

Last change on this file since 1586 was 1586, checked in by landauf, 16 years ago

moved Debug.h, OutputHandler and OutputBuffer to util, to make COUT(x) available everywhere

  • Property svn:eol-style set to native
File size: 23.1 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Benjamin Grauer
24 *      Fabian 'x3n' Landau
25 *   Co-authors:
26 *      ...
27 */
28
29/*!
30    @file Convert.h
31    @brief Definition and Implementation of the Convert class.
32*/
33
34#ifndef _Convert_H__
35#define _Convert_H__
36
37#include "UtilPrereqs.h"
38
39#include <string>
40#include <sstream>
41
42#include "Math.h"
43#include "Debug.h"
44#include "SubString.h"
45#include "MultiTypeMath.h"
46
47// disable annoying warning about forcing value to boolean
48#if ORXONOX_COMPILER == ORXONOX_COMPILER_MSVC
49#pragma warning(push)
50#pragma warning(disable:4100 4800)
51#endif
52
53
54//////////
55// MAIN //
56//////////
57
58// Enum to declare the wanted conversion preference in case of equal type-levels
59enum ConversionPreference
60{
61    CP_PreferToType,
62    CP_PreferFromType,
63};
64
65// Helper classes to determine the preferred partial template specialization
66class _ToType_   {};
67class _FromType_ {};
68class _Explicit_ {};
69
70
71// The default convert functions
72template <class FromType, class ToType, class Type>
73struct ConverterSpecialized
74{
75    enum { specialized = false };
76    static bool convert(ToType* output, const FromType& input)
77    {
78        COUT(2) << "Warning: Couldn't convert a value." << std::endl;
79        return false;
80    }
81};
82
83
84// The default convert function if both types are the same
85template <class BothTypes>
86struct ConverterSpecialized<BothTypes, BothTypes, _Explicit_>
87{
88    enum { specialized = true };
89    static bool convert(BothTypes* output, const BothTypes& input)
90    { (*output) = input; return true; }
91};
92
93
94// The possible levels
95#define __low__  0 // Everything that is or behaves like a primitive type (an can be converted with a typecast to every other low-level type)
96#define __mid__  1 // Everything that has overloaded << and >> operators to operate on a std::stream
97#define __high__ 2 // Everything that doesn't fullfill the lowerlevel-requirements and therefore needs specialized conversions
98
99// Defines the levels of all types: Default is __high__ so you don't have to define every high-level type
100template <class T> struct ConverterLevel           { enum { level = __high__ }; };
101template <> struct ConverterLevel<std::string>     { enum { level = __mid__ }; };
102template <> struct ConverterLevel<orxonox::Radian> { enum { level = __mid__ }; };
103template <> struct ConverterLevel<orxonox::Degree> { enum { level = __mid__ }; };
104template <> struct ConverterLevel<int>             { enum { level = __low__ }; };
105template <> struct ConverterLevel<unsigned int>    { enum { level = __low__ }; };
106template <> struct ConverterLevel<char>            { enum { level = __low__ }; };
107template <> struct ConverterLevel<unsigned char>   { enum { level = __low__ }; };
108template <> struct ConverterLevel<short>           { enum { level = __low__ }; };
109template <> struct ConverterLevel<unsigned short>  { enum { level = __low__ }; };
110template <> struct ConverterLevel<long>            { enum { level = __low__ }; };
111template <> struct ConverterLevel<unsigned long>   { enum { level = __low__ }; };
112template <> struct ConverterLevel<float>           { enum { level = __low__ }; };
113template <> struct ConverterLevel<double>          { enum { level = __low__ }; };
114template <> struct ConverterLevel<long double>     { enum { level = __low__ }; };
115template <> struct ConverterLevel<bool>            { enum { level = __low__ }; };
116
117
118// Calculates the preference based on the levels of FromType and ToType
119template <int from, int to>
120struct ConverterPreference
121{
122    enum
123    {
124        // The maximum of both levels: element of {0, 1, 2}
125        // max 0: Both types are primitives or have a similar behaviour
126        // max 1: At least one type is not a primitive, but both can be put on a std::stream
127        // max 2: There is at least one generic type that needs specialized conversions
128        max = (from > to) ? from : to,
129
130        // The difference between both levels limited to +-1: element of {-1, 0, 1}
131        // diff -1: The FromType has higher level than the ToType
132        // diff  0: Both types have the same level
133        // diff  1: The ToType has higher level than the FromType
134        diff = ((to - from) > 1) ? 1 : (((to - from) < -1) ? -1 : to - from)
135    };
136};
137
138
139// The default conversion: This usually does nothing
140template <int max, class FromType, class ToType>
141struct ConverterDefault
142{
143    static bool convert(ToType* output, const FromType& input)
144    {
145        COUT(2) << "Warning: Couldn't convert a value." << std::endl;
146        return false;
147    }
148};
149// The default conversion for primitives: A typecast (defined over two partial specialized templates to exclude all non-primitive types and classes)    template <int max, class FromType, class ToType>
150template <class FromType, class ToType>
151struct ConverterDefault<0, FromType, ToType>
152{
153    static bool convert(ToType* output, const FromType& input)
154    {
155        (*output) = (ToType)input;
156        return true;
157    }
158};
159
160
161// Converter: Converts input of FromType into output of ToType
162template <int diff, int max, class FromType, class ToType, ConversionPreference pref>
163struct Converter
164{
165    static bool convert(ToType* output, const FromType& input)
166    {
167        return false;
168    }
169};
170// Converter: level{FromType} > level{ToType}
171template <int max, class FromType, class ToType, ConversionPreference pref>
172struct Converter<-1, max, FromType, ToType, pref>
173{   static bool convert(ToType* output, const FromType& input)
174    { return (ConverterSpecialized<FromType, ToType, _Explicit_>::specialized) ? (ConverterSpecialized<FromType, ToType, _Explicit_>::convert(output, input)) : (ConverterSpecialized<FromType, ToType, _FromType_>::specialized) ? (ConverterSpecialized<FromType, ToType, _FromType_>::convert(output, input)) : (ConverterDefault<max, FromType, ToType>::convert(output, input)); } };
175// Converter: level{FromType} < level{ToType}
176template <int max, class FromType, class ToType, ConversionPreference pref>
177struct Converter<1, max, FromType, ToType, pref>
178{   static bool convert(ToType* output, const FromType& input)
179    { return (ConverterSpecialized<FromType, ToType, _Explicit_>::specialized) ? (ConverterSpecialized<FromType, ToType, _Explicit_>::convert(output, input)) : (ConverterSpecialized<FromType, ToType, _ToType_>::specialized) ? (ConverterSpecialized<FromType, ToType, _ToType_>::convert(output, input)) : (ConverterDefault<max, FromType, ToType>::convert(output, input)); } };
180// Converter: level{FromType} = level{ToType}
181// CP_PreferToType
182template <int max, class FromType, class ToType>
183struct Converter<0, max, FromType, ToType, CP_PreferToType>
184{   static bool convert(ToType* output, const FromType& input)
185    { return (ConverterSpecialized<FromType, ToType, _Explicit_>::specialized) ? (ConverterSpecialized<FromType, ToType, _Explicit_>::convert(output, input)) : (ConverterSpecialized<FromType, ToType, _ToType_>::specialized) ? (ConverterSpecialized<FromType, ToType, _ToType_>::convert(output, input)) : (ConverterSpecialized<FromType, ToType, _FromType_>::specialized) ? (ConverterSpecialized<FromType, ToType, _FromType_>::convert(output, input)) : (ConverterDefault<max, FromType, ToType>::convert(output, input)); } };
186// CP_PreferFromType
187template <int max, class FromType, class ToType>
188struct Converter<0, max, FromType, ToType, CP_PreferFromType>
189{   static bool convert(ToType* output, const FromType& input)
190    { return (ConverterSpecialized<FromType, ToType, _Explicit_>::specialized) ? (ConverterSpecialized<FromType, ToType, _Explicit_>::convert(output, input)) : (ConverterSpecialized<FromType, ToType, _FromType_>::specialized) ? (ConverterSpecialized<FromType, ToType, _FromType_>::convert(output, input)) : (ConverterSpecialized<FromType, ToType, _ToType_>::specialized) ? (ConverterSpecialized<FromType, ToType, _ToType_>::convert(output, input)) : (ConverterDefault<max, FromType, ToType>::convert(output, input)); } };
191
192
193// Calls the Converter::convertValue function with the correct template type parameters calculated by ConverterPreference
194template <class FromType, class ToType>
195static bool convertValue(ToType* output, const FromType& input, ConversionPreference preference = CP_PreferToType)
196{
197    return (preference == CP_PreferToType) ?
198           Converter<ConverterPreference<ConverterLevel<FromType>::level, ConverterLevel<ToType>::level>::diff,
199                     ConverterPreference<ConverterLevel<FromType>::level, ConverterLevel<ToType>::level>::max,
200                     FromType,
201                     ToType,
202                     CP_PreferToType>::convert(output, input)
203         : Converter<ConverterPreference<ConverterLevel<FromType>::level, ConverterLevel<ToType>::level>::diff,
204                     ConverterPreference<ConverterLevel<FromType>::level, ConverterLevel<ToType>::level>::max,
205                     FromType,
206                     ToType,
207                     CP_PreferFromType>::convert(output, input);
208}
209
210
211//////////////////////
212// HELPER FUNCTIONS //
213//////////////////////
214
215// Helper function: Calls convertValue with and without default value and returns true if the conversion was successful
216template<class FromType, class ToType>
217static bool ConvertValue(ToType* output, const FromType& input, ConversionPreference preference = CP_PreferToType)
218{
219    return convertValue(output, input, preference);
220}
221template<class FromType, class ToType>
222static bool ConvertValue(ToType* output, const FromType& input, const ToType& fallback, ConversionPreference preference = CP_PreferToType)
223{
224    if (convertValue(output, input, preference))
225        return true;
226
227    (*output) = fallback;
228    return false;
229}
230
231// Helper function: Calls convertValue with and without default value and returns the converted value
232template<class FromType, class ToType>
233static ToType getConvertedValue(const FromType& input, ConversionPreference preference = CP_PreferToType)
234{
235    ToType output = ToType();
236    ConvertValue(&output, input, preference);
237    return output;
238}
239template<class FromType, class ToType>
240static ToType getConvertedValue(const FromType& input, const ToType& fallback, ConversionPreference preference = CP_PreferToType)
241{
242    ToType output = fallback;
243    ConvertValue(&output, input, fallback, preference);
244    return output;
245}
246
247
248/////////////////////
249// SPECIALIZATIONS //
250/////////////////////
251
252/////////////
253// SAMPLES //
254/////////////
255/*
256// convert everything to xyz
257template <class FromType>
258struct ConverterSpecialized<FromType, xyz, _ToType_>
259{
260    enum { specialized = true };
261    static bool convert(xyz* output, const FromType& input)
262    { return ...; }
263};
264
265// convert xyz to everything
266template <class ToType>
267struct ConverterSpecialized<xyz, ToType, _FromType_>
268{
269    enum { specialized = true };
270    static bool convert(ToType* output, const xyz& input)
271    { return ...; }
272};
273
274// convert abc to xyz
275template <>
276struct ConverterSpecialized<abc, xyz, _Explicit_>
277{
278    enum { specialized = true };
279    static bool convert(xyz* output, const abc& input)
280    { return ...; }
281};
282*/
283
284////////////
285// STRING //
286////////////
287
288// convert to string
289template <class FromType>
290struct ConverterSpecialized<FromType, std::string, _ToType_>
291{
292    enum { specialized = true };
293    static bool convert(std::string* output, const FromType& input)
294    {
295        std::ostringstream oss;
296        if (oss << input)
297        {
298            (*output) = oss.str();
299            return true;
300        }
301        else
302            return false;
303    }
304};
305
306// convert from string
307template <class ToType>
308struct ConverterSpecialized<std::string, ToType, _FromType_>
309{
310    enum { specialized = true };
311    static bool convert(ToType* output, const std::string& input)
312    {
313        std::istringstream iss(input);
314        if (iss >> (*output))
315            return true;
316        else
317            return false;
318    }
319};
320
321
322////////////////
323// MULTITYPES //
324////////////////
325
326// convert from MultiTypePrimitive
327template <class ToType>
328struct ConverterSpecialized<MultiTypePrimitive, ToType, _FromType_>
329{
330    enum { specialized = true };
331    static bool convert(ToType* output, const MultiTypePrimitive& input)
332    {
333        if (input.getType() == MT_void)
334            return ConvertValue(output, input.getVoid());
335        else if (input.getType() == MT_int)
336            return ConvertValue(output, input.getInt());
337        else if (input.getType() == MT_uint)
338            return ConvertValue(output, input.getUnsignedInt());
339        else if (input.getType() == MT_char)
340            return ConvertValue(output, input.getChar());
341        else if (input.getType() == MT_uchar)
342            return ConvertValue(output, input.getUnsignedChar());
343        else if (input.getType() == MT_short)
344            return ConvertValue(output, input.getShort());
345        else if (input.getType() == MT_ushort)
346            return ConvertValue(output, input.getUnsignedShort());
347        else if (input.getType() == MT_long)
348            return ConvertValue(output, input.getLong());
349        else if (input.getType() == MT_ulong)
350            return ConvertValue(output, input.getUnsignedLong());
351        else if (input.getType() == MT_float)
352            return ConvertValue(output, input.getFloat());
353        else if (input.getType() == MT_double)
354            return ConvertValue(output, input.getDouble());
355        else if (input.getType() == MT_longdouble)
356            return ConvertValue(output, input.getLongDouble());
357        else if (input.getType() == MT_bool)
358            return ConvertValue(output, input.getBool());
359        else
360            return false;
361    }
362};
363
364// convert from MultiTypeString
365template <class ToType>
366struct ConverterSpecialized<MultiTypeString, ToType, _FromType_>
367{
368    enum { specialized = true };
369    static bool convert(ToType* output, const MultiTypeString& input)
370    {
371        if (input.getType() == MT_constchar)
372            return ConvertValue(output, input.getConstChar());
373        else if (input.getType() == MT_string)
374            return ConvertValue(output, input.getString());
375        else
376            return ConvertValue(output, (MultiTypePrimitive)input);
377    }
378};
379
380// convert from MultiTypeMath
381template <class ToType>
382struct ConverterSpecialized<MultiTypeMath, ToType, _FromType_>
383{
384    enum { specialized = true };
385    static bool convert(ToType* output, const MultiTypeMath& input)
386    {
387        if (input.getType() == MT_vector2)
388            return ConvertValue(output, input.getVector2());
389        else if (input.getType() == MT_vector3)
390            return ConvertValue(output, input.getVector3());
391        else if (input.getType() == MT_vector4)
392            return ConvertValue(output, input.getVector4());
393        else if (input.getType() == MT_quaternion)
394            return ConvertValue(output, input.getQuaternion());
395        else if (input.getType() == MT_colourvalue)
396            return ConvertValue(output, input.getColourValue());
397        else if (input.getType() == MT_radian)
398            return ConvertValue(output, input.getRadian());
399        else if (input.getType() == MT_degree)
400            return ConvertValue(output, input.getDegree());
401        else
402            return ConvertValue(output, (MultiTypeString)input);
403    }
404};
405
406
407////////////////////
408// MATH TO STRING //
409////////////////////
410
411// Vector2 to std::string
412template <>
413struct ConverterSpecialized<orxonox::Vector2, std::string, _Explicit_>
414{
415    enum { specialized = true };
416    static bool convert(std::string* output, const orxonox::Vector2& input)
417    {
418        std::ostringstream ostream;
419        if (ostream << input.x << "," << input.y)
420        {
421            (*output) = ostream.str();
422            return true;
423        }
424        return false;
425    }
426};
427
428// Vector3 to std::string
429template <>
430struct ConverterSpecialized<orxonox::Vector3, std::string, _Explicit_>
431{
432    enum { specialized = true };
433    static bool convert(std::string* output, const orxonox::Vector3& input)
434    {
435        std::ostringstream ostream;
436        if (ostream << input.x << "," << input.y << "," << input.z)
437        {
438            (*output) = ostream.str();
439            return true;
440        }
441        return false;
442    }
443};
444
445// Vector4 to std::string
446template <>
447struct ConverterSpecialized<orxonox::Vector4, std::string, _Explicit_>
448{
449    enum { specialized = true };
450    static bool convert(std::string* output, const orxonox::Vector4& input)
451    {
452        std::ostringstream ostream;
453        if (ostream << input.x << "," << input.y << "," << input.z << "," << input.w)
454        {
455            (*output) = ostream.str();
456            return true;
457        }
458        return false;
459    }
460};
461
462// Quaternion to std::string
463template <>
464struct ConverterSpecialized<orxonox::Quaternion, std::string, _Explicit_>
465{
466    enum { specialized = true };
467    static bool convert(std::string* output, const orxonox::Quaternion& input)
468    {
469        std::ostringstream ostream;
470        if (ostream << input.w << "," << input.x << "," << input.y << "," << input.z)
471        {
472            (*output) = ostream.str();
473            return true;
474        }
475        return false;
476    }
477};
478
479// ColourValue to std::string
480template <>
481struct ConverterSpecialized<orxonox::ColourValue, std::string, _Explicit_>
482{
483    enum { specialized = true };
484    static bool convert(std::string* output, const orxonox::ColourValue& input)
485    {
486        std::ostringstream ostream;
487        if (ostream << input.r << "," << input.g << "," << input.b << "," << input.a)
488        {
489            (*output) = ostream.str();
490            return true;
491        }
492        return false;
493    }
494};
495
496
497////////////////////
498// STRING TO MATH //
499////////////////////
500
501// std::string to Vector2
502template <>
503struct ConverterSpecialized<std::string, orxonox::Vector2, _Explicit_>
504{
505    enum { specialized = true };
506    static bool convert(orxonox::Vector2* output, const std::string& input)
507    {
508        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
509        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
510
511        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
512        if (tokens.size() >= 2)
513        {
514            if (!ConvertValue(&(output->x), tokens[0]))
515                return false;
516            if (!ConvertValue(&(output->y), tokens[1]))
517                return false;
518
519            return true;
520        }
521        return false;
522    }
523};
524
525// std::string to Vector3
526template <>
527struct ConverterSpecialized<std::string, orxonox::Vector3, _Explicit_>
528{
529    enum { specialized = true };
530    static bool convert(orxonox::Vector3* output, const std::string& input)
531    {
532        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
533        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
534
535        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
536        if (tokens.size() >= 3)
537        {
538            if (!ConvertValue(&(output->x), tokens[0]))
539                return false;
540            if (!ConvertValue(&(output->y), tokens[1]))
541                return false;
542            if (!ConvertValue(&(output->z), tokens[2]))
543                return false;
544
545            return true;
546        }
547        return false;
548    }
549};
550
551// std::string to Vector4
552template <>
553struct ConverterSpecialized<std::string, orxonox::Vector4, _Explicit_>
554{
555    enum { specialized = true };
556    static bool convert(orxonox::Vector4* output, const std::string& input)
557    {
558        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
559        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
560
561        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
562        if (tokens.size() >= 4)
563        {
564            if (!ConvertValue(&(output->x), tokens[0]))
565                return false;
566            if (!ConvertValue(&(output->y), tokens[1]))
567                return false;
568            if (!ConvertValue(&(output->z), tokens[2]))
569                return false;
570            if (!ConvertValue(&(output->w), tokens[3]))
571                return false;
572
573            return true;
574        }
575        return false;
576    }
577};
578
579// std::string to Quaternion
580template <>
581struct ConverterSpecialized<std::string, orxonox::Quaternion, _Explicit_>
582{
583    enum { specialized = true };
584    static bool convert(orxonox::Quaternion* output, const std::string& input)
585    {
586        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
587        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
588
589        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
590        if (tokens.size() >= 4)
591        {
592            if (!ConvertValue(&(output->w), tokens[0]))
593                return false;
594            if (!ConvertValue(&(output->x), tokens[1]))
595                return false;
596            if (!ConvertValue(&(output->y), tokens[2]))
597                return false;
598            if (!ConvertValue(&(output->z), tokens[3]))
599                return false;
600
601            return true;
602        }
603        return false;
604    }
605};
606
607// std::string to ColourValue
608template <>
609struct ConverterSpecialized<std::string, orxonox::ColourValue, _Explicit_>
610{
611    enum { specialized = true };
612    static bool convert(orxonox::ColourValue* output, const std::string& input)
613    {
614        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
615        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
616
617        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
618        if (tokens.size() >= 4)
619        {
620            if (!ConvertValue(&(output->r), tokens[0]))
621                return false;
622            if (!ConvertValue(&(output->g), tokens[1]))
623                return false;
624            if (!ConvertValue(&(output->b), tokens[2]))
625                return false;
626            if (!ConvertValue(&(output->a), tokens[3]))
627                return false;
628
629            return true;
630        }
631        return false;
632    }
633};
634
635#if ORXONOX_COMPILER == ORXONOX_COMPILER_MSVC
636#pragma warning(pop)
637#endif
638
639#endif /* _Convert_H__ */
Note: See TracBrowser for help on using the repository browser.