Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

added comments to all my classes in util

  • Property svn:eol-style set to native
File size: 23.0 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *      Benjamin Grauer
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 "String.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: From \"" << typeid(FromType).name() << "\" to \"" << typeid(ToType).name() << "\"" << 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<long long>          { enum { level = __low__ }; };
113template <> struct ConverterLevel<unsigned long long> { enum { level = __low__ }; };
114template <> struct ConverterLevel<float>              { enum { level = __low__ }; };
115template <> struct ConverterLevel<double>             { enum { level = __low__ }; };
116template <> struct ConverterLevel<long double>        { enum { level = __low__ }; };
117template <> struct ConverterLevel<bool>               { enum { level = __low__ }; };
118
119
120// Calculates the preference based on the levels of FromType and ToType
121template <int from, int to>
122struct ConverterPreference
123{
124    enum
125    {
126        // The maximum of both levels: element of {0, 1, 2}
127        // max 0: Both types are primitives or have a similar behaviour
128        // max 1: At least one type is not a primitive, but both can be put on a std::stream
129        // max 2: There is at least one generic type that needs specialized conversions
130        max = (from > to) ? from : to,
131
132        // The difference between both levels limited to +-1: element of {-1, 0, 1}
133        // diff -1: The FromType has higher level than the ToType
134        // diff  0: Both types have the same level
135        // diff  1: The ToType has higher level than the FromType
136        diff = ((to - from) > 1) ? 1 : (((to - from) < -1) ? -1 : to - from)
137    };
138};
139
140
141// The default conversion: This usually does nothing
142template <int max, class FromType, class ToType>
143struct ConverterDefault
144{
145    static bool convert(ToType* output, const FromType& input)
146    {
147        COUT(2) << "Warning: Couldn't convert a value: From \"" << typeid(FromType).name() << "\" to \"" << typeid(ToType).name() << "\"" << std::endl;
148        return false;
149    }
150};
151// 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>
152template <class FromType, class ToType>
153struct ConverterDefault<0, FromType, ToType>
154{
155    static bool convert(ToType* output, const FromType& input)
156    {
157        (*output) = (ToType)input;
158        return true;
159    }
160};
161
162
163// Converter: Converts input of FromType into output of ToType
164template <int diff, int max, class FromType, class ToType, ConversionPreference pref>
165struct Converter
166{
167    static bool convert(ToType* output, const FromType& input)
168    {
169        return false;
170    }
171};
172// Converter: level{FromType} > level{ToType}
173template <int max, class FromType, class ToType, ConversionPreference pref>
174struct Converter<-1, max, FromType, ToType, pref>
175{   static bool convert(ToType* output, const FromType& input)
176    { 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)); } };
177// Converter: level{FromType} < level{ToType}
178template <int max, class FromType, class ToType, ConversionPreference pref>
179struct Converter<1, max, FromType, ToType, pref>
180{   static bool convert(ToType* output, const FromType& input)
181    { 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)); } };
182// Converter: level{FromType} = level{ToType}
183// CP_PreferToType
184template <int max, class FromType, class ToType>
185struct Converter<0, max, FromType, ToType, CP_PreferToType>
186{   static bool convert(ToType* output, const FromType& input)
187    { 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)); } };
188// CP_PreferFromType
189template <int max, class FromType, class ToType>
190struct Converter<0, max, FromType, ToType, CP_PreferFromType>
191{   static bool convert(ToType* output, const FromType& input)
192    { 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)); } };
193
194
195// Calls the Converter::convertValue function with the correct template type parameters calculated by ConverterPreference
196template <class FromType, class ToType>
197static bool convertValue(ToType* output, const FromType& input, ConversionPreference preference = CP_PreferToType)
198{
199    return (preference == CP_PreferToType) ?
200           Converter<ConverterPreference<ConverterLevel<FromType>::level, ConverterLevel<ToType>::level>::diff,
201                     ConverterPreference<ConverterLevel<FromType>::level, ConverterLevel<ToType>::level>::max,
202                     FromType,
203                     ToType,
204                     CP_PreferToType>::convert(output, input)
205         : Converter<ConverterPreference<ConverterLevel<FromType>::level, ConverterLevel<ToType>::level>::diff,
206                     ConverterPreference<ConverterLevel<FromType>::level, ConverterLevel<ToType>::level>::max,
207                     FromType,
208                     ToType,
209                     CP_PreferFromType>::convert(output, input);
210}
211
212
213//////////////////////
214// HELPER FUNCTIONS //
215//////////////////////
216
217// Helper function: Calls convertValue with and without default value and returns true if the conversion was successful
218template<class FromType, class ToType>
219static bool ConvertValue(ToType* output, const FromType& input, ConversionPreference preference = CP_PreferToType)
220{
221    return convertValue(output, input, preference);
222}
223template<class FromType, class ToType>
224static bool ConvertValue(ToType* output, const FromType& input, const ToType& fallback, ConversionPreference preference = CP_PreferToType)
225{
226    if (convertValue(output, input, preference))
227        return true;
228
229    (*output) = fallback;
230    return false;
231}
232
233// Helper function: Calls convertValue with and without default value and returns the converted value
234template<class FromType, class ToType>
235static ToType getConvertedValue(const FromType& input, ConversionPreference preference = CP_PreferToType)
236{
237    ToType output = ToType();
238    ConvertValue(&output, input, preference);
239    return output;
240}
241template<class FromType, class ToType>
242static ToType getConvertedValue(const FromType& input, const ToType& fallback, ConversionPreference preference = CP_PreferToType)
243{
244    ToType output = fallback;
245    ConvertValue(&output, input, fallback, preference);
246    return output;
247}
248
249
250/////////////////////
251// SPECIALIZATIONS //
252/////////////////////
253
254/////////////
255// SAMPLES //
256/////////////
257/*
258// convert everything to xyz
259template <class FromType>
260struct ConverterSpecialized<FromType, xyz, _ToType_>
261{
262    enum { specialized = true };
263    static bool convert(xyz* output, const FromType& input)
264    { return ...; }
265};
266
267// convert xyz to everything
268template <class ToType>
269struct ConverterSpecialized<xyz, ToType, _FromType_>
270{
271    enum { specialized = true };
272    static bool convert(ToType* output, const xyz& input)
273    { return ...; }
274};
275
276// convert abc to xyz
277template <>
278struct ConverterSpecialized<abc, xyz, _Explicit_>
279{
280    enum { specialized = true };
281    static bool convert(xyz* output, const abc& input)
282    { return ...; }
283};
284*/
285
286////////////
287// STRING //
288////////////
289
290// convert to string
291template <class FromType>
292struct ConverterSpecialized<FromType, std::string, _ToType_>
293{
294    enum { specialized = true };
295    static bool convert(std::string* output, const FromType& input)
296    {
297        std::ostringstream oss;
298        if (oss << input)
299        {
300            (*output) = oss.str();
301            return true;
302        }
303        else
304            return false;
305    }
306};
307
308// convert to string Shortcut
309template <class FromType>
310std::string convertToString(FromType value)
311{
312  return getConvertedValue<FromType, std::string>(value);
313}
314
315// convert from string
316template <class ToType>
317struct ConverterSpecialized<std::string, ToType, _FromType_>
318{
319    enum { specialized = true };
320    static bool convert(ToType* output, const std::string& input)
321    {
322        std::istringstream iss(input);
323        if (iss >> (*output))
324            return true;
325        else
326            return false;
327    }
328};
329
330// convert from string Shortcut
331template <class ToType>
332ToType convertFromString(std::string str)
333{
334  return getConvertedValue<std::string, ToType>(str);
335}
336
337
338//////////
339// MATH //
340//////////
341// convert everything to Degree
342template <class FromType>
343struct ConverterSpecialized<FromType, Ogre::Degree, _ToType_>
344{
345    enum { specialized = true };
346    static bool convert(Ogre::Degree* output, const FromType& input)
347    {
348        float angle = 0;
349        bool success = ConvertValue<FromType, float>(&angle, input);
350        (*output) = angle;
351        return success;
352    }
353};
354
355// convert everything to Radian
356template <class FromType>
357struct ConverterSpecialized<FromType, Ogre::Radian, _ToType_>
358{
359    enum { specialized = true };
360    static bool convert(Ogre::Radian* output, const FromType& input)
361    {
362        float angle = 0;
363        bool success = ConvertValue<FromType, float>(&angle, input);
364        (*output) = angle;
365        return success;
366    }
367};
368
369
370////////////////////
371// MATH TO STRING //
372////////////////////
373
374// bool to std::string
375template <>
376struct ConverterSpecialized<bool, std::string, _Explicit_>
377{
378    enum { specialized = true };
379    static bool convert(std::string* output, const bool& input)
380    {
381        if (input)
382          *output = "true";
383        else
384          *output = "false";
385        return false;
386    }
387};
388
389// Vector2 to std::string
390template <>
391struct ConverterSpecialized<orxonox::Vector2, std::string, _Explicit_>
392{
393    enum { specialized = true };
394    static bool convert(std::string* output, const orxonox::Vector2& input)
395    {
396        std::ostringstream ostream;
397        if (ostream << input.x << "," << input.y)
398        {
399            (*output) = ostream.str();
400            return true;
401        }
402        return false;
403    }
404};
405
406// Vector3 to std::string
407template <>
408struct ConverterSpecialized<orxonox::Vector3, std::string, _Explicit_>
409{
410    enum { specialized = true };
411    static bool convert(std::string* output, const orxonox::Vector3& input)
412    {
413        std::ostringstream ostream;
414        if (ostream << input.x << "," << input.y << "," << input.z)
415        {
416            (*output) = ostream.str();
417            return true;
418        }
419        return false;
420    }
421};
422
423// Vector4 to std::string
424template <>
425struct ConverterSpecialized<orxonox::Vector4, std::string, _Explicit_>
426{
427    enum { specialized = true };
428    static bool convert(std::string* output, const orxonox::Vector4& input)
429    {
430        std::ostringstream ostream;
431        if (ostream << input.x << "," << input.y << "," << input.z << "," << input.w)
432        {
433            (*output) = ostream.str();
434            return true;
435        }
436        return false;
437    }
438};
439
440// Quaternion to std::string
441template <>
442struct ConverterSpecialized<orxonox::Quaternion, std::string, _Explicit_>
443{
444    enum { specialized = true };
445    static bool convert(std::string* output, const orxonox::Quaternion& input)
446    {
447        std::ostringstream ostream;
448        if (ostream << input.w << "," << input.x << "," << input.y << "," << input.z)
449        {
450            (*output) = ostream.str();
451            return true;
452        }
453        return false;
454    }
455};
456
457// ColourValue to std::string
458template <>
459struct ConverterSpecialized<orxonox::ColourValue, std::string, _Explicit_>
460{
461    enum { specialized = true };
462    static bool convert(std::string* output, const orxonox::ColourValue& input)
463    {
464        std::ostringstream ostream;
465        if (ostream << input.r << "," << input.g << "," << input.b << "," << input.a)
466        {
467            (*output) = ostream.str();
468            return true;
469        }
470        return false;
471    }
472};
473
474
475////////////////////
476// STRING TO MATH //
477////////////////////
478
479// std::string to bool
480template <>
481struct ConverterSpecialized<std::string, bool, _Explicit_>
482{
483    enum { specialized = true };
484    static bool convert(bool* output, const std::string& input)
485    {
486        std::string stripped = getLowercase(removeTrailingWhitespaces(input));
487        if (stripped == "true" || stripped == "on" || stripped == "yes")
488        {
489          *output = true;
490          return true;
491        }
492        else if (stripped == "false" || stripped == "off" || stripped == "no")
493        {
494          *output = false;
495          return true;
496        }
497
498        std::istringstream iss(input);
499        if (iss >> (*output))
500            return true;
501        else
502            return false;
503    }
504};
505
506// std::string to Vector2
507template <>
508struct ConverterSpecialized<std::string, orxonox::Vector2, _Explicit_>
509{
510    enum { specialized = true };
511    static bool convert(orxonox::Vector2* output, const std::string& input)
512    {
513        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
514        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
515
516        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
517        if (tokens.size() >= 2)
518        {
519            if (!ConvertValue(&(output->x), tokens[0]))
520                return false;
521            if (!ConvertValue(&(output->y), tokens[1]))
522                return false;
523
524            return true;
525        }
526        return false;
527    }
528};
529
530// std::string to Vector3
531template <>
532struct ConverterSpecialized<std::string, orxonox::Vector3, _Explicit_>
533{
534    enum { specialized = true };
535    static bool convert(orxonox::Vector3* output, const std::string& input)
536    {
537        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
538        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
539
540        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
541        if (tokens.size() >= 3)
542        {
543            if (!ConvertValue(&(output->x), tokens[0]))
544                return false;
545            if (!ConvertValue(&(output->y), tokens[1]))
546                return false;
547            if (!ConvertValue(&(output->z), tokens[2]))
548                return false;
549
550            return true;
551        }
552        return false;
553    }
554};
555
556// std::string to Vector4
557template <>
558struct ConverterSpecialized<std::string, orxonox::Vector4, _Explicit_>
559{
560    enum { specialized = true };
561    static bool convert(orxonox::Vector4* output, const std::string& input)
562    {
563        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
564        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
565
566        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
567        if (tokens.size() >= 4)
568        {
569            if (!ConvertValue(&(output->x), tokens[0]))
570                return false;
571            if (!ConvertValue(&(output->y), tokens[1]))
572                return false;
573            if (!ConvertValue(&(output->z), tokens[2]))
574                return false;
575            if (!ConvertValue(&(output->w), tokens[3]))
576                return false;
577
578            return true;
579        }
580        return false;
581    }
582};
583
584// std::string to Quaternion
585template <>
586struct ConverterSpecialized<std::string, orxonox::Quaternion, _Explicit_>
587{
588    enum { specialized = true };
589    static bool convert(orxonox::Quaternion* output, const std::string& input)
590    {
591        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
592        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
593
594        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
595        if (tokens.size() >= 4)
596        {
597            if (!ConvertValue(&(output->w), tokens[0]))
598                return false;
599            if (!ConvertValue(&(output->x), tokens[1]))
600                return false;
601            if (!ConvertValue(&(output->y), tokens[2]))
602                return false;
603            if (!ConvertValue(&(output->z), tokens[3]))
604                return false;
605
606            return true;
607        }
608        return false;
609    }
610};
611
612// std::string to ColourValue
613template <>
614struct ConverterSpecialized<std::string, orxonox::ColourValue, _Explicit_>
615{
616    enum { specialized = true };
617    static bool convert(orxonox::ColourValue* output, const std::string& input)
618    {
619        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
620        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
621
622        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
623        if (tokens.size() >= 3)
624        {
625            if (!ConvertValue(&(output->r), tokens[0]))
626                return false;
627            if (!ConvertValue(&(output->g), tokens[1]))
628                return false;
629            if (!ConvertValue(&(output->b), tokens[2]))
630                return false;
631            if (tokens.size() >= 4)
632            {
633                if (!ConvertValue(&(output->a), tokens[3]))
634                    return false;
635            }
636            else
637                output->a = 1.0;
638
639            return true;
640        }
641        return false;
642    }
643};
644
645
646///////////////////////////
647// Static type detection //
648///////////////////////////
649
650/**
651    Template class that determines whether type T converts implicitly to type U.
652@note
653    This allows to detect type conversion at compile time.
654    From 'Modern C++ Design' (Alexandrescu 2001).
655*/
656template <class T, class U>
657class StaticConversion
658{
659    class Small { char dummy[1]; };
660    class Big   { char dummy[1024]; };
661    static Small Test(U);
662    static Big   Test(...);
663    static T MakeT();
664public:
665    enum { exists = sizeof(Test(MakeT())) == sizeof(Small) };
666};
667
668#if ORXONOX_COMPILER == ORXONOX_COMPILER_MSVC
669#pragma warning(pop)
670#endif
671
672#endif /* _Convert_H__ */
Note: See TracBrowser for help on using the repository browser.