Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

Added new 'MultiType', replacing MultiTypePrimitive, MultiTypeString and MultiTypeMath. MultiType can hold all types MultiTypeMath was able to hold, namely all primitives, pointers, string and several math objects (vector2, 3 and 4, quaternion, colourvalue, radian, degree).

The new MultiType has a completely changed behaviour, I'll explain this on a wiki page somewhen.
But to say the most important things in a few words:
The MultiType has a fixed type. This type is determined by the first assigned value (by using setValue(value), operator=(value) or MultiType(value)). Every other value getting assigned later, will be converted to the first type. But you can change the type (setType<T>()), convert the value (convert<T>()) or force the type of a newly assigned value manually (setValue<T>(value)) by using template functions.

In contrast, the old MultiTypeMath changed it's internal type whenever a new type was assigned. So be aware of this important change.

At the moment I can't see any issues, but there might very well be several problems yet to discover, so further tests will be done.

  • Property svn:eol-style set to native
File size: 23.2 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.