Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core2/src/util/Convert.h @ 1003

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

hopefully solved the conversion problem :)

it's a lot of metaprogramming now but this reduces the risk getting unnecessary compiler errors:
if (convert(a, b))

return true;

else

return convertFallback(a, b);

if convert(a, b) is defined and always used you could still get an error if convertFallback(a, b) uses something (like stream << object) that isn't supported for a or b. but with some template tricks it's possible to not even consider using convertFallback(a, b) at compiletime and avoid the error as long as convert(a, b) is implemented.

util/Conver.h is now opened for curious coders ;)

File size: 23.1 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *
4 *
5 *   License notice:
6 *
7 *   This program is free software; you can redistribute it and/or
8 *   modify it under the terms of the GNU General Public License
9 *   as published by the Free Software Foundation; either version 2
10 *   of the License, or (at your option) any later version.
11 *
12 *   This program is distributed in the hope that it will be useful,
13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 *   GNU General Public License for more details.
16 *
17 *   You should have received a copy of the GNU General Public License
18 *   along with this program; if not, write to the Free Software
19 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 *
21 *   Author:
22 *      Benjamin Grauer
23 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      ...
26 */
27
28/*!
29    @file Convert.h
30    @brief Definition and Implementation of the Convert class.
31*/
32
33#ifndef _Convert_H__
34#define _Convert_H__
35
36#include <string>
37#include <sstream>
38
39#include "UtilPrereqs.h"
40#include "Math.h"
41#include "SubString.h"
42#include "MultiTypeMath.h"
43
44
45//////////
46// Main //
47//////////
48
49// Enum to declare the wanted conversion preference in case of equal type-levels
50enum ConversionPreference
51{
52    CP_PreferToType,
53    CP_PreferFromType,
54};
55
56// Helper classes to determine the preferred partial template specialization
57class _ToType_   {};
58class _FromType_ {};
59class _Explicit_ {};
60
61
62// The default convert functions
63template <class FromType, class ToType, class Type>
64struct ConverterSpecialized
65{
66    enum { specialized = false };
67    static bool convert(ToType* output, const FromType& input)
68    { return false; }
69};
70
71
72// The default convert function if both types are the same
73template <class BothTypes>
74struct ConverterSpecialized<BothTypes, BothTypes, _Explicit_>
75{
76    enum { specialized = true };
77    static bool convert(BothTypes* output, const BothTypes& input)
78    { (*output) = input; return true; }
79};
80
81
82// The possible levels
83#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)
84#define __mid__  1 // Everything that has overloaded << and >> operators to operate on a std::stream
85#define __high__ 2 // Everything that doesn't fullfill the lowerlevel-requirements and therefore needs specialized conversions
86
87// Defines the levels of all types: Default is __high__ so you don't have to define every high-level type
88template <class T> struct ConverterLevel           { enum { level = __high__ }; };
89template <> struct ConverterLevel<std::string>     { enum { level = __mid__ }; };
90template <> struct ConverterLevel<orxonox::Radian> { enum { level = __mid__ }; };
91template <> struct ConverterLevel<orxonox::Degree> { enum { level = __mid__ }; };
92template <> struct ConverterLevel<int>             { enum { level = __low__ }; };
93template <> struct ConverterLevel<unsigned int>    { enum { level = __low__ }; };
94template <> struct ConverterLevel<char>            { enum { level = __low__ }; };
95template <> struct ConverterLevel<unsigned char>   { enum { level = __low__ }; };
96template <> struct ConverterLevel<short>           { enum { level = __low__ }; };
97template <> struct ConverterLevel<unsigned short>  { enum { level = __low__ }; };
98template <> struct ConverterLevel<long>            { enum { level = __low__ }; };
99template <> struct ConverterLevel<unsigned long>   { enum { level = __low__ }; };
100template <> struct ConverterLevel<float>           { enum { level = __low__ }; };
101template <> struct ConverterLevel<double>          { enum { level = __low__ }; };
102template <> struct ConverterLevel<long double>     { enum { level = __low__ }; };
103template <> struct ConverterLevel<bool>            { enum { level = __low__ }; };
104
105
106// Calculates the preference based on the levels of FromType and ToType
107template <int from, int to>
108struct ConverterPreference
109{
110    enum
111    {
112        // The maximum of both levels: element of {0, 1, 2}
113        // max 0: Both types are primitives or have a similar behaviour
114        // max 1: At least one type is not a primitive, but both can be put on a std::stream
115        // max 2: There is at least one generic type that needs specialized conversions
116        max = (from > to) ? from : to,
117
118        // The difference between both levels limited to +-1: element of {-1, 0, 1}
119        // diff -1: The FromType has higher level than the ToType
120        // diff  0: Both types have the same level
121        // diff  1: The ToType has higher level than the FromType
122        diff = ((to - from) > 1) ? 1 : (((to - from) < -1) ? -1 : to - from)
123    };
124};
125
126
127// The default conversion: This usually does nothing
128template <int max, class FromType, class ToType>
129struct ConverterDefault
130{
131    static bool convert(ToType* output, const FromType& input)
132    {
133        return false;
134    }
135};
136// 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>
137template <class FromType, class ToType>
138struct ConverterDefault<0, FromType, ToType>
139{
140    static bool convert(ToType* output, const FromType& input)
141    {
142        (*output) = (ToType)input;
143        return true;
144    }
145};
146
147
148// Converter: Converts input of FromType into output of ToType
149template <int diff, int max, class FromType, class ToType, ConversionPreference pref>
150struct Converter
151{
152    static bool convert(ToType* output, const FromType& input)
153    {
154        return false;
155    }
156};
157// Converter: level{FromType} > level{ToType}
158template <int max, class FromType, class ToType, ConversionPreference pref>
159struct Converter<-1, max, FromType, ToType, pref>
160{   static bool convert(ToType* output, const FromType& input)
161    { 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)); } };
162// Converter: level{FromType} < level{ToType}
163template <int max, class FromType, class ToType, ConversionPreference pref>
164struct Converter<1, max, FromType, ToType, pref>
165{   static bool convert(ToType* output, const FromType& input)
166    { 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)); } };
167// Converter: level{FromType} = level{ToType}
168// CP_PreferToType
169template <int max, class FromType, class ToType>
170struct Converter<0, max, FromType, ToType, CP_PreferToType>
171{   static bool convert(ToType* output, const FromType& input)
172    { 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)); } };
173// CP_PreferFromType
174template <int max, class FromType, class ToType>
175struct Converter<0, max, FromType, ToType, CP_PreferFromType>
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)) : (ConverterSpecialized<FromType, ToType, _ToType_>::specialized) ? (ConverterSpecialized<FromType, ToType, _ToType_>::convert(output, input)) : (ConverterDefault<max, FromType, ToType>::convert(output, input)); } };
178
179
180// Calls the Converter::convertValue function with the correct template type parameters calculated by ConverterPreference
181template <class FromType, class ToType>
182static bool convertValue(ToType* output, const FromType& input, ConversionPreference preference = CP_PreferToType)
183{
184    return (preference == CP_PreferToType) ?
185           Converter<ConverterPreference<ConverterLevel<FromType>::level, ConverterLevel<ToType>::level>::diff,
186                     ConverterPreference<ConverterLevel<FromType>::level, ConverterLevel<ToType>::level>::max,
187                     FromType,
188                     ToType,
189                     CP_PreferToType>::convert(output, input)
190         : Converter<ConverterPreference<ConverterLevel<FromType>::level, ConverterLevel<ToType>::level>::diff,
191                     ConverterPreference<ConverterLevel<FromType>::level, ConverterLevel<ToType>::level>::max,
192                     FromType,
193                     ToType,
194                     CP_PreferFromType>::convert(output, input);
195}
196
197
198// Helper function: Calls convertValue with and without default value and returns true if the conversion was successful
199template<class FromType, class ToType>
200static bool ConvertValue(ToType* output, const FromType& input, ConversionPreference preference = CP_PreferToType)
201{
202    return convertValue(output, input, preference);
203}
204template<class FromType, class ToType>
205static bool ConvertValue(ToType* output, const FromType& input, const ToType& fallback, ConversionPreference preference = CP_PreferToType)
206{
207    if (convertValue(output, input, preference))
208        return true;
209
210    (*output) = fallback;
211    return false;
212}
213
214// Helper function: Calls convertValue with and without default value and returns the converted value
215template<class FromType, class ToType>
216static ToType getConvertedValue(const FromType& input, ConversionPreference preference = CP_PreferToType)
217{
218    ToType output = ToType();
219    ConvertValue(&output, input, preference);
220    return output;
221}
222template<class FromType, class ToType>
223static ToType getConvertedValue(const FromType& input, const ToType& fallback, ConversionPreference preference = CP_PreferToType)
224{
225    ToType output = fallback;
226    ConvertValue(&output, input, fallback, preference);
227    return output;
228}
229
230/////////////////////
231// SPECIALISATIONS //
232/////////////////////
233
234/////////////
235// Samples //
236/////////////
237/*
238// convert everything to xyz
239template <class FromType>
240struct ConverterSpecialized<FromType, xyz, _ToType_>
241{
242    enum { specialized = true };
243    static bool convert(xyz* output, const FromType& input)
244    { return ...; }
245};
246
247// convert xyz to everything
248template <class ToType>
249struct ConverterSpecialized<xyz, ToType, _FromType_>
250{
251    enum { specialized = true };
252    static bool convert(ToType* output, const xyz& input)
253    { return ...; }
254};
255
256// convert abc to xyz
257template <>
258struct ConverterSpecialized<abc, xyz, _Explicit_>
259{
260    enum { specialized = true };
261    static bool convert(xyz* output, const abc& input)
262    { return ...; }
263};
264*/
265
266////////////
267// String //
268////////////
269
270// convert to string
271template <class FromType>
272struct ConverterSpecialized<FromType, std::string, _ToType_>
273{
274    enum { specialized = true };
275    static bool convert(std::string* output, const FromType& input)
276    {
277        std::ostringstream oss;
278        if (oss << input)
279        {
280            (*output) = oss.str();
281            return true;
282        }
283        else
284            return false;
285    }
286};
287
288// convert from string
289template <class ToType>
290struct ConverterSpecialized<std::string, ToType, _FromType_>
291{
292    enum { specialized = true };
293    static bool convert(ToType* output, const std::string& input)
294    {
295        std::istringstream iss(input);
296        if (iss >> (*output))
297            return true;
298        else
299            return false;
300    }
301};
302
303
304////////////////
305// MULTITYPES //
306////////////////
307
308// convert from MultiTypePrimitive
309template <class ToType>
310struct ConverterSpecialized<MultiTypePrimitive, ToType, _FromType_>
311{
312    enum { specialized = true };
313    static bool convert(ToType* output, const MultiTypePrimitive& input)
314    {
315        if (input.getType() == MT_void)
316            return ConvertValue(output, input.getVoid());
317        else if (input.getType() == MT_int)
318            return ConvertValue(output, input.getInt());
319        else if (input.getType() == MT_uint)
320            return ConvertValue(output, input.getUnsignedInt());
321        else if (input.getType() == MT_char)
322            return ConvertValue(output, input.getChar());
323        else if (input.getType() == MT_uchar)
324            return ConvertValue(output, input.getUnsignedChar());
325        else if (input.getType() == MT_short)
326            return ConvertValue(output, input.getShort());
327        else if (input.getType() == MT_ushort)
328            return ConvertValue(output, input.getUnsignedShort());
329        else if (input.getType() == MT_long)
330            return ConvertValue(output, input.getLong());
331        else if (input.getType() == MT_ulong)
332            return ConvertValue(output, input.getUnsignedLong());
333        else if (input.getType() == MT_float)
334            return ConvertValue(output, input.getFloat());
335        else if (input.getType() == MT_double)
336            return ConvertValue(output, input.getDouble());
337        else if (input.getType() == MT_longdouble)
338            return ConvertValue(output, input.getLongDouble());
339        else if (input.getType() == MT_bool)
340            return ConvertValue(output, input.getBool());
341        else
342            return false;
343    }
344};
345
346// convert from MultiTypeString
347template <class ToType>
348struct ConverterSpecialized<MultiTypeString, ToType, _FromType_>
349{
350    enum { specialized = true };
351    static bool convert(ToType* output, const MultiTypeString& input)
352    {
353        if (input.getType() == MT_constchar)
354            return ConvertValue(output, input.getConstChar());
355        else if (input.getType() == MT_string)
356            return ConvertValue(output, input.getString());
357        else
358            return ConvertValue(output, (MultiTypePrimitive)input);
359    }
360};
361
362// convert from MultiTypeMath
363template <class ToType>
364struct ConverterSpecialized<MultiTypeMath, ToType, _FromType_>
365{
366    enum { specialized = true };
367    static bool convert(ToType* output, const MultiTypeMath& input)
368    {
369        if (input.getType() == MT_vector2)
370            return ConvertValue(output, input.getVector2());
371        else if (input.getType() == MT_vector3)
372            return ConvertValue(output, input.getVector3());
373        else if (input.getType() == MT_quaternion)
374            return ConvertValue(output, input.getQuaternion());
375        else if (input.getType() == MT_colourvalue)
376            return ConvertValue(output, input.getColourValue());
377        else if (input.getType() == MT_radian)
378            return ConvertValue(output, input.getRadian());
379        else if (input.getType() == MT_degree)
380            return ConvertValue(output, input.getDegree());
381        else
382            return ConvertValue(output, (MultiTypeString)input);
383    }
384};
385
386
387////////////////////
388// MATH TO STRING //
389////////////////////
390
391// Vector2 to std::string
392template <>
393struct ConverterSpecialized<orxonox::Vector2, std::string, _Explicit_>
394{
395    enum { specialized = true };
396    static bool convert(std::string* output, const orxonox::Vector2& input)
397    {
398        std::ostringstream ostream;
399        if (ostream << input.x << "," << input.y)
400        {
401            (*output) = ostream.str();
402            return true;
403        }
404        return false;
405    }
406};
407
408// Vector3 to std::string
409template <>
410struct ConverterSpecialized<orxonox::Vector3, std::string, _Explicit_>
411{
412    enum { specialized = true };
413    static bool convert(std::string* output, const orxonox::Vector3& input)
414    {
415        std::ostringstream ostream;
416        if (ostream << input.x << "," << input.y << "," << input.z)
417        {
418            (*output) = ostream.str();
419            return true;
420        }
421        return false;
422    }
423};
424
425// Vector4 to std::string
426template <>
427struct ConverterSpecialized<orxonox::Vector4, std::string, _Explicit_>
428{
429    enum { specialized = true };
430    static bool convert(std::string* output, const orxonox::Vector4& input)
431    {
432        std::ostringstream ostream;
433        if (ostream << input.x << "," << input.y << "," << input.z << "," << input.w)
434        {
435            (*output) = ostream.str();
436            return true;
437        }
438        return false;
439    }
440};
441
442// Quaternion to std::string
443template <>
444struct ConverterSpecialized<orxonox::Quaternion, std::string, _Explicit_>
445{
446    enum { specialized = true };
447    static bool convert(std::string* output, const orxonox::Quaternion& input)
448    {
449        std::ostringstream ostream;
450        if (ostream << input.w << "," << input.x << "," << input.y << "," << input.z)
451        {
452            (*output) = ostream.str();
453            return true;
454        }
455        return false;
456    }
457};
458
459// ColourValue to std::string
460template <>
461struct ConverterSpecialized<orxonox::ColourValue, std::string, _Explicit_>
462{
463    enum { specialized = true };
464    static bool convert(std::string* output, const orxonox::ColourValue& input)
465    {
466        std::ostringstream ostream;
467        if (ostream << input.r << "," << input.g << "," << input.b << "," << input.a)
468        {
469            (*output) = ostream.str();
470            return true;
471        }
472        return false;
473    }
474};
475
476
477////////////////////
478// STRING TO MATH //
479////////////////////
480
481// std::string to Vector2
482template <>
483struct ConverterSpecialized<std::string, orxonox::Vector2, _Explicit_>
484{
485    enum { specialized = true };
486    static bool convert(orxonox::Vector2* output, const std::string& input)
487    {
488        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
489        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
490
491        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
492        if (tokens.size() >= 2)
493        {
494            if (!ConvertValue(&(output->x), tokens[0]))
495                return false;
496            if (!ConvertValue(&(output->y), tokens[1]))
497                return false;
498
499            return true;
500        }
501        return false;
502    }
503};
504
505// std::string to Vector3
506template <>
507struct ConverterSpecialized<std::string, orxonox::Vector3, _Explicit_>
508{
509    enum { specialized = true };
510    static bool convert(orxonox::Vector3* output, const std::string& input)
511    {
512        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
513        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
514
515        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
516        if (tokens.size() >= 3)
517        {
518            if (!ConvertValue(&(output->x), tokens[0]))
519                return false;
520            if (!ConvertValue(&(output->y), tokens[1]))
521                return false;
522            if (!ConvertValue(&(output->z), tokens[2]))
523                return false;
524
525            return true;
526        }
527        return false;
528    }
529};
530
531// std::string to Vector4
532template <>
533struct ConverterSpecialized<std::string, orxonox::Vector4, _Explicit_>
534{
535    enum { specialized = true };
536    static bool convert(orxonox::Vector4* 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() >= 4)
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            if (!ConvertValue(&(output->w), tokens[3]))
551                return false;
552
553            return true;
554        }
555        return false;
556    }
557};
558
559// std::string to Quaternion
560template <>
561struct ConverterSpecialized<std::string, orxonox::Quaternion, _Explicit_>
562{
563    enum { specialized = true };
564    static bool convert(orxonox::Quaternion* output, const std::string& input)
565    {
566        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
567        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
568
569        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
570        if (tokens.size() >= 4)
571        {
572            if (!ConvertValue(&(output->w), tokens[0]))
573                return false;
574            if (!ConvertValue(&(output->x), tokens[1]))
575                return false;
576            if (!ConvertValue(&(output->y), tokens[2]))
577                return false;
578            if (!ConvertValue(&(output->z), tokens[3]))
579                return false;
580
581            return true;
582        }
583        return false;
584    }
585};
586
587// std::string to ColourValue
588template <>
589struct ConverterSpecialized<std::string, orxonox::ColourValue, _Explicit_>
590{
591    enum { specialized = true };
592    static bool convert(orxonox::ColourValue* output, const std::string& input)
593    {
594        unsigned int opening_parenthesis, closing_parenthesis = input.find(')');
595        if ((opening_parenthesis = input.find('(')) == std::string::npos) { opening_parenthesis = 0; } else { opening_parenthesis++; }
596
597        SubString tokens(input.substr(opening_parenthesis, closing_parenthesis - opening_parenthesis), ",", SubString::WhiteSpaces, false, '\\', true, '"', true, '\0', '\0', true, '\0');
598        if (tokens.size() >= 4)
599        {
600            if (!ConvertValue(&(output->r), tokens[0]))
601                return false;
602            if (!ConvertValue(&(output->g), tokens[1]))
603                return false;
604            if (!ConvertValue(&(output->b), tokens[2]))
605                return false;
606            if (!ConvertValue(&(output->a), tokens[3]))
607                return false;
608
609            return true;
610        }
611        return false;
612    }
613};
614
615#endif /* _Convert_H__ */
Note: See TracBrowser for help on using the repository browser.