Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/network/src/util/Convert.h @ 1446

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

merged console branch into network branch

after several heavy troubles it compiles, but there is still a bug I couldn't fix: orxonox crashes as soon as one presses a key after opening the console… maybe someone else sees the problem?

File size: 23.5 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.