Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

bugfix + cleanup

  • Property svn:eol-style set to native
File size: 19.9 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
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    {
77        COUT(2) << "Warning: Couldn't convert a value." << std::endl;
78        return false;
79    }
80};
81
82
83// The default convert function if both types are the same
84template <class BothTypes>
85struct ConverterSpecialized<BothTypes, BothTypes, _Explicit_>
86{
87    enum { specialized = true };
88    static bool convert(BothTypes* output, const BothTypes& input)
89    { (*output) = input; return true; }
90};
91
92
93// The possible levels
94#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)
95#define __mid__  1 // Everything that has overloaded << and >> operators to operate on a std::stream
96#define __high__ 2 // Everything that doesn't fullfill the lowerlevel-requirements and therefore needs specialized conversions
97
98// Defines the levels of all types: Default is __high__ so you don't have to define every high-level type
99template <class T> struct ConverterLevel           { enum { level = __high__ }; };
100template <> struct ConverterLevel<std::string>     { enum { level = __mid__ }; };
101template <> struct ConverterLevel<orxonox::Radian> { enum { level = __mid__ }; };
102template <> struct ConverterLevel<orxonox::Degree> { enum { level = __mid__ }; };
103template <> struct ConverterLevel<int>             { enum { level = __low__ }; };
104template <> struct ConverterLevel<unsigned int>    { enum { level = __low__ }; };
105template <> struct ConverterLevel<char>            { enum { level = __low__ }; };
106template <> struct ConverterLevel<unsigned char>   { enum { level = __low__ }; };
107template <> struct ConverterLevel<short>           { enum { level = __low__ }; };
108template <> struct ConverterLevel<unsigned short>  { enum { level = __low__ }; };
109template <> struct ConverterLevel<long>            { enum { level = __low__ }; };
110template <> struct ConverterLevel<unsigned long>   { enum { level = __low__ }; };
111template <> struct ConverterLevel<float>           { enum { level = __low__ }; };
112template <> struct ConverterLevel<double>          { enum { level = __low__ }; };
113template <> struct ConverterLevel<long double>     { enum { level = __low__ }; };
114template <> struct ConverterLevel<bool>            { enum { level = __low__ }; };
115
116
117// Calculates the preference based on the levels of FromType and ToType
118template <int from, int to>
119struct ConverterPreference
120{
121    enum
122    {
123        // The maximum of both levels: element of {0, 1, 2}
124        // max 0: Both types are primitives or have a similar behaviour
125        // max 1: At least one type is not a primitive, but both can be put on a std::stream
126        // max 2: There is at least one generic type that needs specialized conversions
127        max = (from > to) ? from : to,
128
129        // The difference between both levels limited to +-1: element of {-1, 0, 1}
130        // diff -1: The FromType has higher level than the ToType
131        // diff  0: Both types have the same level
132        // diff  1: The ToType has higher level than the FromType
133        diff = ((to - from) > 1) ? 1 : (((to - from) < -1) ? -1 : to - from)
134    };
135};
136
137
138// The default conversion: This usually does nothing
139template <int max, class FromType, class ToType>
140struct ConverterDefault
141{
142    static bool convert(ToType* output, const FromType& input)
143    {
144        COUT(2) << "Warning: Couldn't convert a value." << std::endl;
145        return false;
146    }
147};
148// 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>
149template <class FromType, class ToType>
150struct ConverterDefault<0, FromType, ToType>
151{
152    static bool convert(ToType* output, const FromType& input)
153    {
154        (*output) = (ToType)input;
155        return true;
156    }
157};
158
159
160// Converter: Converts input of FromType into output of ToType
161template <int diff, int max, class FromType, class ToType, ConversionPreference pref>
162struct Converter
163{
164    static bool convert(ToType* output, const FromType& input)
165    {
166        return false;
167    }
168};
169// Converter: level{FromType} > level{ToType}
170template <int max, class FromType, class ToType, ConversionPreference pref>
171struct Converter<-1, max, FromType, ToType, pref>
172{   static bool convert(ToType* output, const FromType& input)
173    { 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)); } };
174// Converter: level{FromType} < level{ToType}
175template <int max, class FromType, class ToType, ConversionPreference pref>
176struct Converter<1, max, FromType, ToType, pref>
177{   static bool convert(ToType* output, const FromType& input)
178    { 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)); } };
179// Converter: level{FromType} = level{ToType}
180// CP_PreferToType
181template <int max, class FromType, class ToType>
182struct Converter<0, max, FromType, ToType, CP_PreferToType>
183{   static bool convert(ToType* output, const FromType& input)
184    { 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)); } };
185// CP_PreferFromType
186template <int max, class FromType, class ToType>
187struct Converter<0, max, FromType, ToType, CP_PreferFromType>
188{   static bool convert(ToType* output, const FromType& input)
189    { 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)); } };
190
191
192// Calls the Converter::convertValue function with the correct template type parameters calculated by ConverterPreference
193template <class FromType, class ToType>
194static bool convertValue(ToType* output, const FromType& input, ConversionPreference preference = CP_PreferToType)
195{
196    return (preference == CP_PreferToType) ?
197           Converter<ConverterPreference<ConverterLevel<FromType>::level, ConverterLevel<ToType>::level>::diff,
198                     ConverterPreference<ConverterLevel<FromType>::level, ConverterLevel<ToType>::level>::max,
199                     FromType,
200                     ToType,
201                     CP_PreferToType>::convert(output, input)
202         : Converter<ConverterPreference<ConverterLevel<FromType>::level, ConverterLevel<ToType>::level>::diff,
203                     ConverterPreference<ConverterLevel<FromType>::level, ConverterLevel<ToType>::level>::max,
204                     FromType,
205                     ToType,
206                     CP_PreferFromType>::convert(output, input);
207}
208
209
210//////////////////////
211// HELPER FUNCTIONS //
212//////////////////////
213
214// Helper function: Calls convertValue with and without default value and returns true if the conversion was successful
215template<class FromType, class ToType>
216static bool ConvertValue(ToType* output, const FromType& input, ConversionPreference preference = CP_PreferToType)
217{
218    return convertValue(output, input, preference);
219}
220template<class FromType, class ToType>
221static bool ConvertValue(ToType* output, const FromType& input, const ToType& fallback, ConversionPreference preference = CP_PreferToType)
222{
223    if (convertValue(output, input, preference))
224        return true;
225
226    (*output) = fallback;
227    return false;
228}
229
230// Helper function: Calls convertValue with and without default value and returns the converted value
231template<class FromType, class ToType>
232static ToType getConvertedValue(const FromType& input, ConversionPreference preference = CP_PreferToType)
233{
234    ToType output = ToType();
235    ConvertValue(&output, input, preference);
236    return output;
237}
238template<class FromType, class ToType>
239static ToType getConvertedValue(const FromType& input, const ToType& fallback, ConversionPreference preference = CP_PreferToType)
240{
241    ToType output = fallback;
242    ConvertValue(&output, input, fallback, preference);
243    return output;
244}
245
246
247/////////////////////
248// SPECIALIZATIONS //
249/////////////////////
250
251/////////////
252// SAMPLES //
253/////////////
254/*
255// convert everything to xyz
256template <class FromType>
257struct ConverterSpecialized<FromType, xyz, _ToType_>
258{
259    enum { specialized = true };
260    static bool convert(xyz* output, const FromType& input)
261    { return ...; }
262};
263
264// convert xyz to everything
265template <class ToType>
266struct ConverterSpecialized<xyz, ToType, _FromType_>
267{
268    enum { specialized = true };
269    static bool convert(ToType* output, const xyz& input)
270    { return ...; }
271};
272
273// convert abc to xyz
274template <>
275struct ConverterSpecialized<abc, xyz, _Explicit_>
276{
277    enum { specialized = true };
278    static bool convert(xyz* output, const abc& input)
279    { return ...; }
280};
281*/
282
283////////////
284// STRING //
285////////////
286
287// convert to string
288template <class FromType>
289struct ConverterSpecialized<FromType, std::string, _ToType_>
290{
291    enum { specialized = true };
292    static bool convert(std::string* output, const FromType& input)
293    {
294        std::ostringstream oss;
295        if (oss << input)
296        {
297            (*output) = oss.str();
298            return true;
299        }
300        else
301            return false;
302    }
303};
304
305// convert from string
306template <class ToType>
307struct ConverterSpecialized<std::string, ToType, _FromType_>
308{
309    enum { specialized = true };
310    static bool convert(ToType* output, const std::string& input)
311    {
312        std::istringstream iss(input);
313        if (iss >> (*output))
314            return true;
315        else
316            return false;
317    }
318};
319
320
321
322////////////////////
323// MATH TO STRING //
324////////////////////
325
326// Vector2 to std::string
327template <>
328struct ConverterSpecialized<orxonox::Vector2, std::string, _Explicit_>
329{
330    enum { specialized = true };
331    static bool convert(std::string* output, const orxonox::Vector2& input)
332    {
333        std::ostringstream ostream;
334        if (ostream << input.x << "," << input.y)
335        {
336            (*output) = ostream.str();
337            return true;
338        }
339        return false;
340    }
341};
342
343// Vector3 to std::string
344template <>
345struct ConverterSpecialized<orxonox::Vector3, std::string, _Explicit_>
346{
347    enum { specialized = true };
348    static bool convert(std::string* output, const orxonox::Vector3& input)
349    {
350        std::ostringstream ostream;
351        if (ostream << input.x << "," << input.y << "," << input.z)
352        {
353            (*output) = ostream.str();
354            return true;
355        }
356        return false;
357    }
358};
359
360// Vector4 to std::string
361template <>
362struct ConverterSpecialized<orxonox::Vector4, std::string, _Explicit_>
363{
364    enum { specialized = true };
365    static bool convert(std::string* output, const orxonox::Vector4& input)
366    {
367        std::ostringstream ostream;
368        if (ostream << input.x << "," << input.y << "," << input.z << "," << input.w)
369        {
370            (*output) = ostream.str();
371            return true;
372        }
373        return false;
374    }
375};
376
377// Quaternion to std::string
378template <>
379struct ConverterSpecialized<orxonox::Quaternion, std::string, _Explicit_>
380{
381    enum { specialized = true };
382    static bool convert(std::string* output, const orxonox::Quaternion& input)
383    {
384        std::ostringstream ostream;
385        if (ostream << input.w << "," << input.x << "," << input.y << "," << input.z)
386        {
387            (*output) = ostream.str();
388            return true;
389        }
390        return false;
391    }
392};
393
394// ColourValue to std::string
395template <>
396struct ConverterSpecialized<orxonox::ColourValue, std::string, _Explicit_>
397{
398    enum { specialized = true };
399    static bool convert(std::string* output, const orxonox::ColourValue& input)
400    {
401        std::ostringstream ostream;
402        if (ostream << input.r << "," << input.g << "," << input.b << "," << input.a)
403        {
404            (*output) = ostream.str();
405            return true;
406        }
407        return false;
408    }
409};
410
411
412////////////////////
413// STRING TO MATH //
414////////////////////
415
416// std::string to Vector2
417template <>
418struct ConverterSpecialized<std::string, orxonox::Vector2, _Explicit_>
419{
420    enum { specialized = true };
421    static bool convert(orxonox::Vector2* output, const std::string& input)
422    {
423        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
424        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
425
426        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
427        if (tokens.size() >= 2)
428        {
429            if (!ConvertValue(&(output->x), tokens[0]))
430                return false;
431            if (!ConvertValue(&(output->y), tokens[1]))
432                return false;
433
434            return true;
435        }
436        return false;
437    }
438};
439
440// std::string to Vector3
441template <>
442struct ConverterSpecialized<std::string, orxonox::Vector3, _Explicit_>
443{
444    enum { specialized = true };
445    static bool convert(orxonox::Vector3* output, const std::string& input)
446    {
447        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
448        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
449
450        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
451        if (tokens.size() >= 3)
452        {
453            if (!ConvertValue(&(output->x), tokens[0]))
454                return false;
455            if (!ConvertValue(&(output->y), tokens[1]))
456                return false;
457            if (!ConvertValue(&(output->z), tokens[2]))
458                return false;
459
460            return true;
461        }
462        return false;
463    }
464};
465
466// std::string to Vector4
467template <>
468struct ConverterSpecialized<std::string, orxonox::Vector4, _Explicit_>
469{
470    enum { specialized = true };
471    static bool convert(orxonox::Vector4* output, const std::string& input)
472    {
473        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
474        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
475
476        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
477        if (tokens.size() >= 4)
478        {
479            if (!ConvertValue(&(output->x), tokens[0]))
480                return false;
481            if (!ConvertValue(&(output->y), tokens[1]))
482                return false;
483            if (!ConvertValue(&(output->z), tokens[2]))
484                return false;
485            if (!ConvertValue(&(output->w), tokens[3]))
486                return false;
487
488            return true;
489        }
490        return false;
491    }
492};
493
494// std::string to Quaternion
495template <>
496struct ConverterSpecialized<std::string, orxonox::Quaternion, _Explicit_>
497{
498    enum { specialized = true };
499    static bool convert(orxonox::Quaternion* 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() >= 4)
506        {
507            if (!ConvertValue(&(output->w), tokens[0]))
508                return false;
509            if (!ConvertValue(&(output->x), tokens[1]))
510                return false;
511            if (!ConvertValue(&(output->y), tokens[2]))
512                return false;
513            if (!ConvertValue(&(output->z), tokens[3]))
514                return false;
515
516            return true;
517        }
518        return false;
519    }
520};
521
522// std::string to ColourValue
523template <>
524struct ConverterSpecialized<std::string, orxonox::ColourValue, _Explicit_>
525{
526    enum { specialized = true };
527    static bool convert(orxonox::ColourValue* output, const std::string& input)
528    {
529        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
530        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
531
532        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
533        if (tokens.size() >= 4)
534        {
535            if (!ConvertValue(&(output->r), tokens[0]))
536                return false;
537            if (!ConvertValue(&(output->g), tokens[1]))
538                return false;
539            if (!ConvertValue(&(output->b), tokens[2]))
540                return false;
541            if (!ConvertValue(&(output->a), tokens[3]))
542                return false;
543
544            return true;
545        }
546        return false;
547    }
548};
549
550#if ORXONOX_COMPILER == ORXONOX_COMPILER_MSVC
551#pragma warning(pop)
552#endif
553
554#endif /* _Convert_H__ */
Note: See TracBrowser for help on using the repository browser.