Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 1230 was 1064, checked in by rgrieder, 17 years ago
  • replaced all String2Number with ConvertValue
  • replaced all tokenize with SubString
  • dealt with warnings under msvc
  • removed some warnings by placing casts
  • bugfix in audio: local variable pushed into member variable std::vector
  • updated StableHeaders.h
File size: 23.4 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_quaternion)
387            return ConvertValue(output, input.getQuaternion());
388        else if (input.getType() == MT_colourvalue)
389            return ConvertValue(output, input.getColourValue());
390        else if (input.getType() == MT_radian)
391            return ConvertValue(output, input.getRadian());
392        else if (input.getType() == MT_degree)
393            return ConvertValue(output, input.getDegree());
394        else
395            return ConvertValue(output, (MultiTypeString)input);
396    }
397};
398
399
400////////////////////
401// MATH TO STRING //
402////////////////////
403
404// Vector2 to std::string
405template <>
406struct ConverterSpecialized<orxonox::Vector2, std::string, _Explicit_>
407{
408    enum { specialized = true };
409    static bool convert(std::string* output, const orxonox::Vector2& input)
410    {
411        std::ostringstream ostream;
412        if (ostream << input.x << "," << input.y)
413        {
414            (*output) = ostream.str();
415            return true;
416        }
417        return false;
418    }
419};
420
421// Vector3 to std::string
422template <>
423struct ConverterSpecialized<orxonox::Vector3, std::string, _Explicit_>
424{
425    enum { specialized = true };
426    static bool convert(std::string* output, const orxonox::Vector3& input)
427    {
428        std::ostringstream ostream;
429        if (ostream << input.x << "," << input.y << "," << input.z)
430        {
431            (*output) = ostream.str();
432            return true;
433        }
434        return false;
435    }
436};
437
438// Vector4 to std::string
439template <>
440struct ConverterSpecialized<orxonox::Vector4, std::string, _Explicit_>
441{
442    enum { specialized = true };
443    static bool convert(std::string* output, const orxonox::Vector4& input)
444    {
445        std::ostringstream ostream;
446        if (ostream << input.x << "," << input.y << "," << input.z << "," << input.w)
447        {
448            (*output) = ostream.str();
449            return true;
450        }
451        return false;
452    }
453};
454
455// Quaternion to std::string
456template <>
457struct ConverterSpecialized<orxonox::Quaternion, std::string, _Explicit_>
458{
459    enum { specialized = true };
460    static bool convert(std::string* output, const orxonox::Quaternion& input)
461    {
462        std::ostringstream ostream;
463        if (ostream << input.w << "," << input.x << "," << input.y << "," << input.z)
464        {
465            (*output) = ostream.str();
466            return true;
467        }
468        return false;
469    }
470};
471
472// ColourValue to std::string
473template <>
474struct ConverterSpecialized<orxonox::ColourValue, std::string, _Explicit_>
475{
476    enum { specialized = true };
477    static bool convert(std::string* output, const orxonox::ColourValue& input)
478    {
479        std::ostringstream ostream;
480        if (ostream << input.r << "," << input.g << "," << input.b << "," << input.a)
481        {
482            (*output) = ostream.str();
483            return true;
484        }
485        return false;
486    }
487};
488
489
490////////////////////
491// STRING TO MATH //
492////////////////////
493
494// std::string to Vector2
495template <>
496struct ConverterSpecialized<std::string, orxonox::Vector2, _Explicit_>
497{
498    enum { specialized = true };
499    static bool convert(orxonox::Vector2* output, const std::string& input)
500    {
501        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
502        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
503
504        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
505        if (tokens.size() >= 2)
506        {
507            if (!ConvertValue(&(output->x), tokens[0]))
508                return false;
509            if (!ConvertValue(&(output->y), tokens[1]))
510                return false;
511
512            return true;
513        }
514        return false;
515    }
516};
517
518// std::string to Vector3
519template <>
520struct ConverterSpecialized<std::string, orxonox::Vector3, _Explicit_>
521{
522    enum { specialized = true };
523    static bool convert(orxonox::Vector3* output, const std::string& input)
524    {
525        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
526        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
527
528        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
529        if (tokens.size() >= 3)
530        {
531            if (!ConvertValue(&(output->x), tokens[0]))
532                return false;
533            if (!ConvertValue(&(output->y), tokens[1]))
534                return false;
535            if (!ConvertValue(&(output->z), tokens[2]))
536                return false;
537
538            return true;
539        }
540        return false;
541    }
542};
543
544// std::string to Vector4
545template <>
546struct ConverterSpecialized<std::string, orxonox::Vector4, _Explicit_>
547{
548    enum { specialized = true };
549    static bool convert(orxonox::Vector4* output, const std::string& input)
550    {
551        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
552        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
553
554        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
555        if (tokens.size() >= 4)
556        {
557            if (!ConvertValue(&(output->x), tokens[0]))
558                return false;
559            if (!ConvertValue(&(output->y), tokens[1]))
560                return false;
561            if (!ConvertValue(&(output->z), tokens[2]))
562                return false;
563            if (!ConvertValue(&(output->w), tokens[3]))
564                return false;
565
566            return true;
567        }
568        return false;
569    }
570};
571
572// std::string to Quaternion
573template <>
574struct ConverterSpecialized<std::string, orxonox::Quaternion, _Explicit_>
575{
576    enum { specialized = true };
577    static bool convert(orxonox::Quaternion* output, const std::string& input)
578    {
579        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
580        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
581
582        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
583        if (tokens.size() >= 4)
584        {
585            if (!ConvertValue(&(output->w), tokens[0]))
586                return false;
587            if (!ConvertValue(&(output->x), tokens[1]))
588                return false;
589            if (!ConvertValue(&(output->y), tokens[2]))
590                return false;
591            if (!ConvertValue(&(output->z), tokens[3]))
592                return false;
593
594            return true;
595        }
596        return false;
597    }
598};
599
600// std::string to ColourValue
601template <>
602struct ConverterSpecialized<std::string, orxonox::ColourValue, _Explicit_>
603{
604    enum { specialized = true };
605    static bool convert(orxonox::ColourValue* output, const std::string& input)
606    {
607        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
608        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
609
610        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
611        if (tokens.size() >= 4)
612        {
613            if (!ConvertValue(&(output->r), tokens[0]))
614                return false;
615            if (!ConvertValue(&(output->g), tokens[1]))
616                return false;
617            if (!ConvertValue(&(output->b), tokens[2]))
618                return false;
619            if (!ConvertValue(&(output->a), tokens[3]))
620                return false;
621
622            return true;
623        }
624        return false;
625    }
626};
627
628#if ORXONOX_COMPILER == ORXONOX_COMPILER_MSVC
629#pragma warning(pop)
630#endif
631
632#endif /* _Convert_H__ */
Note: See TracBrowser for help on using the repository browser.