Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/archive/tutorialHS08/src/util/Convert.h

Last change on this file was 1846, checked in by rgrieder, 16 years ago

Merged Revisions 1831 - 1845 to tutorial. This is an update from the trunk.

  • 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#include <typeinfo>
42
43#include "Math.h"
44#include "Debug.h"
45#include "SubString.h"
46#include "String.h"
47
48// disable annoying warning about forcing value to boolean
49#if ORXONOX_COMPILER == ORXONOX_COMPILER_MSVC
50#pragma warning(push)
51#pragma warning(disable:4100 4800)
52#endif
53
54
55//////////
56// MAIN //
57//////////
58
59// Enum to declare the wanted conversion preference in case of equal type-levels
60enum ConversionPreference
61{
62    CP_PreferToType,
63    CP_PreferFromType,
64};
65
66// Helper classes to determine the preferred partial template specialization
67class _ToType_   {};
68class _FromType_ {};
69class _Explicit_ {};
70
71
72// The default convert functions
73template <class FromType, class ToType, class Type>
74struct ConverterSpecialized
75{
76    enum { specialized = false };
77    static bool convert(ToType* output, const FromType& input)
78    {
79        COUT(2) << "Warning: Couldn't convert a value: From \"" << typeid(FromType).name() << "\" to \"" << typeid(ToType).name() << "\"" << std::endl;
80        return false;
81    }
82};
83
84
85// The default convert function if both types are the same
86template <class BothTypes>
87struct ConverterSpecialized<BothTypes, BothTypes, _Explicit_>
88{
89    enum { specialized = true };
90    static bool convert(BothTypes* output, const BothTypes& input)
91    { (*output) = input; return true; }
92};
93
94
95// The possible levels
96#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)
97#define __mid__  1 // Everything that has overloaded << and >> operators to operate on a std::stream
98#define __high__ 2 // Everything that doesn't fullfill the lowerlevel-requirements and therefore needs specialized conversions
99
100// Defines the levels of all types: Default is __high__ so you don't have to define every high-level type
101template <class T> struct ConverterLevel              { enum { level = __high__ }; };
102template <> struct ConverterLevel<std::string>        { enum { level = __mid__ }; };
103template <> struct ConverterLevel<orxonox::Radian>    { enum { level = __mid__ }; };
104template <> struct ConverterLevel<orxonox::Degree>    { enum { level = __mid__ }; };
105template <> struct ConverterLevel<int>                { enum { level = __low__ }; };
106template <> struct ConverterLevel<unsigned int>       { enum { level = __low__ }; };
107template <> struct ConverterLevel<char>               { enum { level = __low__ }; };
108template <> struct ConverterLevel<unsigned char>      { enum { level = __low__ }; };
109template <> struct ConverterLevel<short>              { enum { level = __low__ }; };
110template <> struct ConverterLevel<unsigned short>     { enum { level = __low__ }; };
111template <> struct ConverterLevel<long>               { enum { level = __low__ }; };
112template <> struct ConverterLevel<unsigned long>      { enum { level = __low__ }; };
113template <> struct ConverterLevel<long long>          { enum { level = __low__ }; };
114template <> struct ConverterLevel<unsigned long long> { enum { level = __low__ }; };
115template <> struct ConverterLevel<float>              { enum { level = __low__ }; };
116template <> struct ConverterLevel<double>             { enum { level = __low__ }; };
117template <> struct ConverterLevel<long double>        { enum { level = __low__ }; };
118template <> struct ConverterLevel<bool>               { enum { level = __low__ }; };
119
120
121// Calculates the preference based on the levels of FromType and ToType
122template <int from, int to>
123struct ConverterPreference
124{
125    enum
126    {
127        // The maximum of both levels: element of {0, 1, 2}
128        // max 0: Both types are primitives or have a similar behaviour
129        // max 1: At least one type is not a primitive, but both can be put on a std::stream
130        // max 2: There is at least one generic type that needs specialized conversions
131        max = (from > to) ? from : to,
132
133        // The difference between both levels limited to +-1: element of {-1, 0, 1}
134        // diff -1: The FromType has higher level than the ToType
135        // diff  0: Both types have the same level
136        // diff  1: The ToType has higher level than the FromType
137        diff = ((to - from) > 1) ? 1 : (((to - from) < -1) ? -1 : to - from)
138    };
139};
140
141
142// The default conversion: This usually does nothing
143template <int max, class FromType, class ToType>
144struct ConverterDefault
145{
146    static bool convert(ToType* output, const FromType& input)
147    {
148        COUT(2) << "Warning: Couldn't convert a value: From \"" << typeid(FromType).name() << "\" to \"" << typeid(ToType).name() << "\"" << std::endl;
149        return false;
150    }
151};
152// 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>
153template <class FromType, class ToType>
154struct ConverterDefault<0, FromType, ToType>
155{
156    static bool convert(ToType* output, const FromType& input)
157    {
158        (*output) = (ToType)input;
159        return true;
160    }
161};
162
163
164// Converter: Converts input of FromType into output of ToType
165template <int diff, int max, class FromType, class ToType, ConversionPreference pref>
166struct Converter
167{
168    static bool convert(ToType* output, const FromType& input)
169    {
170        return false;
171    }
172};
173// Converter: level{FromType} > level{ToType}
174template <int max, class FromType, class ToType, ConversionPreference pref>
175struct Converter<-1, max, FromType, ToType, pref>
176{   static bool convert(ToType* output, const FromType& input)
177    { 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)); } };
178// Converter: level{FromType} < level{ToType}
179template <int max, class FromType, class ToType, ConversionPreference pref>
180struct Converter<1, max, FromType, ToType, pref>
181{   static bool convert(ToType* output, const FromType& input)
182    { 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)); } };
183// Converter: level{FromType} = level{ToType}
184// CP_PreferToType
185template <int max, class FromType, class ToType>
186struct Converter<0, max, FromType, ToType, CP_PreferToType>
187{   static bool convert(ToType* output, const FromType& input)
188    { 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)); } };
189// CP_PreferFromType
190template <int max, class FromType, class ToType>
191struct Converter<0, max, FromType, ToType, CP_PreferFromType>
192{   static bool convert(ToType* output, const FromType& input)
193    { 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)); } };
194
195
196// Calls the Converter::convertValue function with the correct template type parameters calculated by ConverterPreference
197template <class FromType, class ToType>
198static bool convertValue(ToType* output, const FromType& input, ConversionPreference preference = CP_PreferToType)
199{
200    return (preference == CP_PreferToType) ?
201           Converter<ConverterPreference<ConverterLevel<FromType>::level, ConverterLevel<ToType>::level>::diff,
202                     ConverterPreference<ConverterLevel<FromType>::level, ConverterLevel<ToType>::level>::max,
203                     FromType,
204                     ToType,
205                     CP_PreferToType>::convert(output, input)
206         : Converter<ConverterPreference<ConverterLevel<FromType>::level, ConverterLevel<ToType>::level>::diff,
207                     ConverterPreference<ConverterLevel<FromType>::level, ConverterLevel<ToType>::level>::max,
208                     FromType,
209                     ToType,
210                     CP_PreferFromType>::convert(output, input);
211}
212
213
214//////////////////////
215// HELPER FUNCTIONS //
216//////////////////////
217
218// Helper function: Calls convertValue with and without default value and returns true if the conversion was successful
219template<class FromType, class ToType>
220static bool ConvertValue(ToType* output, const FromType& input, ConversionPreference preference = CP_PreferToType)
221{
222    return convertValue(output, input, preference);
223}
224template<class FromType, class ToType>
225static bool ConvertValue(ToType* output, const FromType& input, const ToType& fallback, ConversionPreference preference = CP_PreferToType)
226{
227    if (convertValue(output, input, preference))
228        return true;
229
230    (*output) = fallback;
231    return false;
232}
233
234// Helper function: Calls convertValue with and without default value and returns the converted value
235template<class FromType, class ToType>
236static ToType getConvertedValue(const FromType& input, ConversionPreference preference = CP_PreferToType)
237{
238    ToType output = ToType();
239    ConvertValue(&output, input, preference);
240    return output;
241}
242template<class FromType, class ToType>
243static ToType getConvertedValue(const FromType& input, const ToType& fallback, ConversionPreference preference = CP_PreferToType)
244{
245    ToType output = fallback;
246    ConvertValue(&output, input, fallback, preference);
247    return output;
248}
249
250
251/////////////////////
252// SPECIALIZATIONS //
253/////////////////////
254
255/////////////
256// SAMPLES //
257/////////////
258/*
259// convert everything to xyz
260template <class FromType>
261struct ConverterSpecialized<FromType, xyz, _ToType_>
262{
263    enum { specialized = true };
264    static bool convert(xyz* output, const FromType& input)
265    { return ...; }
266};
267
268// convert xyz to everything
269template <class ToType>
270struct ConverterSpecialized<xyz, ToType, _FromType_>
271{
272    enum { specialized = true };
273    static bool convert(ToType* output, const xyz& input)
274    { return ...; }
275};
276
277// convert abc to xyz
278template <>
279struct ConverterSpecialized<abc, xyz, _Explicit_>
280{
281    enum { specialized = true };
282    static bool convert(xyz* output, const abc& input)
283    { return ...; }
284};
285*/
286
287////////////
288// STRING //
289////////////
290
291// convert to string
292template <class FromType>
293struct ConverterSpecialized<FromType, std::string, _ToType_>
294{
295    enum { specialized = true };
296    static bool convert(std::string* output, const FromType& input)
297    {
298        std::ostringstream oss;
299        if (oss << input)
300        {
301            (*output) = oss.str();
302            return true;
303        }
304        else
305            return false;
306    }
307};
308
309// convert to string Shortcut
310template <class FromType>
311std::string convertToString(FromType value)
312{
313  return getConvertedValue<FromType, std::string>(value);
314}
315
316// convert from string
317template <class ToType>
318struct ConverterSpecialized<std::string, ToType, _FromType_>
319{
320    enum { specialized = true };
321    static bool convert(ToType* output, const std::string& input)
322    {
323        std::istringstream iss(input);
324        if (iss >> (*output))
325            return true;
326        else
327            return false;
328    }
329};
330
331// convert from string Shortcut
332template <class ToType>
333ToType convertFromString(std::string str)
334{
335  return getConvertedValue<std::string, ToType>(str);
336}
337
338
339//////////
340// MATH //
341//////////
342// convert everything to Degree
343template <class FromType>
344struct ConverterSpecialized<FromType, Ogre::Degree, _ToType_>
345{
346    enum { specialized = true };
347    static bool convert(Ogre::Degree* output, const FromType& input)
348    {
349        float angle = 0;
350        bool success = ConvertValue<FromType, float>(&angle, input);
351        (*output) = angle;
352        return success;
353    }
354};
355
356// convert everything to Radian
357template <class FromType>
358struct ConverterSpecialized<FromType, Ogre::Radian, _ToType_>
359{
360    enum { specialized = true };
361    static bool convert(Ogre::Radian* output, const FromType& input)
362    {
363        float angle = 0;
364        bool success = ConvertValue<FromType, float>(&angle, input);
365        (*output) = angle;
366        return success;
367    }
368};
369
370
371////////////////////
372// MATH TO STRING //
373////////////////////
374
375// bool to std::string
376template <>
377struct ConverterSpecialized<bool, std::string, _Explicit_>
378{
379    enum { specialized = true };
380    static bool convert(std::string* output, const bool& input)
381    {
382        if (input)
383          *output = "true";
384        else
385          *output = "false";
386        return false;
387    }
388};
389
390// Vector2 to std::string
391template <>
392struct ConverterSpecialized<orxonox::Vector2, std::string, _Explicit_>
393{
394    enum { specialized = true };
395    static bool convert(std::string* output, const orxonox::Vector2& input)
396    {
397        std::ostringstream ostream;
398        if (ostream << input.x << "," << input.y)
399        {
400            (*output) = ostream.str();
401            return true;
402        }
403        return false;
404    }
405};
406
407// Vector3 to std::string
408template <>
409struct ConverterSpecialized<orxonox::Vector3, std::string, _Explicit_>
410{
411    enum { specialized = true };
412    static bool convert(std::string* output, const orxonox::Vector3& input)
413    {
414        std::ostringstream ostream;
415        if (ostream << input.x << "," << input.y << "," << input.z)
416        {
417            (*output) = ostream.str();
418            return true;
419        }
420        return false;
421    }
422};
423
424// Vector4 to std::string
425template <>
426struct ConverterSpecialized<orxonox::Vector4, std::string, _Explicit_>
427{
428    enum { specialized = true };
429    static bool convert(std::string* output, const orxonox::Vector4& input)
430    {
431        std::ostringstream ostream;
432        if (ostream << input.x << "," << input.y << "," << input.z << "," << input.w)
433        {
434            (*output) = ostream.str();
435            return true;
436        }
437        return false;
438    }
439};
440
441// Quaternion to std::string
442template <>
443struct ConverterSpecialized<orxonox::Quaternion, std::string, _Explicit_>
444{
445    enum { specialized = true };
446    static bool convert(std::string* output, const orxonox::Quaternion& input)
447    {
448        std::ostringstream ostream;
449        if (ostream << input.w << "," << input.x << "," << input.y << "," << input.z)
450        {
451            (*output) = ostream.str();
452            return true;
453        }
454        return false;
455    }
456};
457
458// ColourValue to std::string
459template <>
460struct ConverterSpecialized<orxonox::ColourValue, std::string, _Explicit_>
461{
462    enum { specialized = true };
463    static bool convert(std::string* output, const orxonox::ColourValue& input)
464    {
465        std::ostringstream ostream;
466        if (ostream << input.r << "," << input.g << "," << input.b << "," << input.a)
467        {
468            (*output) = ostream.str();
469            return true;
470        }
471        return false;
472    }
473};
474
475
476////////////////////
477// STRING TO MATH //
478////////////////////
479
480// std::string to bool
481template <>
482struct ConverterSpecialized<std::string, bool, _Explicit_>
483{
484    enum { specialized = true };
485    static bool convert(bool* output, const std::string& input)
486    {
487        std::string stripped = getLowercase(removeTrailingWhitespaces(input));
488        if (stripped == "true" || stripped == "on" || stripped == "yes")
489        {
490          *output = true;
491          return true;
492        }
493        else if (stripped == "false" || stripped == "off" || stripped == "no")
494        {
495          *output = false;
496          return true;
497        }
498
499        std::istringstream iss(input);
500        if (iss >> (*output))
501            return true;
502        else
503            return false;
504    }
505};
506
507// std::string to Vector2
508template <>
509struct ConverterSpecialized<std::string, orxonox::Vector2, _Explicit_>
510{
511    enum { specialized = true };
512    static bool convert(orxonox::Vector2* output, const std::string& input)
513    {
514        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
515        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
516
517        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
518        if (tokens.size() >= 2)
519        {
520            if (!ConvertValue(&(output->x), tokens[0]))
521                return false;
522            if (!ConvertValue(&(output->y), tokens[1]))
523                return false;
524
525            return true;
526        }
527        return false;
528    }
529};
530
531// std::string to Vector3
532template <>
533struct ConverterSpecialized<std::string, orxonox::Vector3, _Explicit_>
534{
535    enum { specialized = true };
536    static bool convert(orxonox::Vector3* output, const std::string& input)
537    {
538        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
539        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
540
541        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
542        if (tokens.size() >= 3)
543        {
544            if (!ConvertValue(&(output->x), tokens[0]))
545                return false;
546            if (!ConvertValue(&(output->y), tokens[1]))
547                return false;
548            if (!ConvertValue(&(output->z), tokens[2]))
549                return false;
550
551            return true;
552        }
553        return false;
554    }
555};
556
557// std::string to Vector4
558template <>
559struct ConverterSpecialized<std::string, orxonox::Vector4, _Explicit_>
560{
561    enum { specialized = true };
562    static bool convert(orxonox::Vector4* output, const std::string& input)
563    {
564        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
565        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
566
567        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
568        if (tokens.size() >= 4)
569        {
570            if (!ConvertValue(&(output->x), tokens[0]))
571                return false;
572            if (!ConvertValue(&(output->y), tokens[1]))
573                return false;
574            if (!ConvertValue(&(output->z), tokens[2]))
575                return false;
576            if (!ConvertValue(&(output->w), tokens[3]))
577                return false;
578
579            return true;
580        }
581        return false;
582    }
583};
584
585// std::string to Quaternion
586template <>
587struct ConverterSpecialized<std::string, orxonox::Quaternion, _Explicit_>
588{
589    enum { specialized = true };
590    static bool convert(orxonox::Quaternion* output, const std::string& input)
591    {
592        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
593        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
594
595        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
596        if (tokens.size() >= 4)
597        {
598            if (!ConvertValue(&(output->w), tokens[0]))
599                return false;
600            if (!ConvertValue(&(output->x), tokens[1]))
601                return false;
602            if (!ConvertValue(&(output->y), tokens[2]))
603                return false;
604            if (!ConvertValue(&(output->z), tokens[3]))
605                return false;
606
607            return true;
608        }
609        return false;
610    }
611};
612
613// std::string to ColourValue
614template <>
615struct ConverterSpecialized<std::string, orxonox::ColourValue, _Explicit_>
616{
617    enum { specialized = true };
618    static bool convert(orxonox::ColourValue* output, const std::string& input)
619    {
620        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
621        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
622
623        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
624        if (tokens.size() >= 3)
625        {
626            if (!ConvertValue(&(output->r), tokens[0]))
627                return false;
628            if (!ConvertValue(&(output->g), tokens[1]))
629                return false;
630            if (!ConvertValue(&(output->b), tokens[2]))
631                return false;
632            if (tokens.size() >= 4)
633            {
634                if (!ConvertValue(&(output->a), tokens[3]))
635                    return false;
636            }
637            else
638                output->a = 1.0;
639
640            return true;
641        }
642        return false;
643    }
644};
645
646
647///////////////////////////
648// Static type detection //
649///////////////////////////
650
651/**
652    Template class that determines whether type T converts implicitly to type U.
653@note
654    This allows to detect type conversion at compile time.
655    From 'Modern C++ Design' (Alexandrescu 2001).
656*/
657template <class T, class U>
658class StaticConversion
659{
660    class Small { char dummy[1]; };
661    class Big   { char dummy[1024]; };
662    static Small Test(U);
663    static Big   Test(...);
664    static T MakeT();
665public:
666    enum { exists = sizeof(Test(MakeT())) == sizeof(Small) };
667};
668
669#if ORXONOX_COMPILER == ORXONOX_COMPILER_MSVC
670#pragma warning(pop)
671#endif
672
673#endif /* _Convert_H__ */
Note: See TracBrowser for help on using the repository browser.