Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/util/Convert.h @ 1505

Last change on this file since 1505 was 1505, checked in by rgrieder, 16 years ago

f* svn: It doesn't even inform you if you attempt to set a non existing property. It is svn:eol-style and not eol-style when using the command by the way…

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