Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 3232 was 3232, checked in by rgrieder, 15 years ago

Moved implicit conversion detection from Convert.h to the new TemplateUtils.h file.

  • Property svn:eol-style set to native
File size: 13.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 *      Reto Grieder
24 *      Fabian 'x3n' Landau
25 *      Benjamin Grauer
26 *   Co-authors:
27 *      ...
28 */
29
30/*!
31    @file
32    @brief Definition and Implementation of the Convert class.
33*/
34
35#ifndef _Converter_H__
36#define _Converter_H__
37
38#include "UtilPrereqs.h"
39
40#include <string>
41#include <sstream>
42#include <typeinfo>
43
44#include "Debug.h"
45#include "String.h"
46#include "TemplateUtils.h"
47
48////////////////////////////////////
49//// ACTUAL CONVERSION SEQUENCE ////
50////////////////////////////////////
51/*
52    There is a distinct priority when choosing the right conversion function:
53    Overwrite:
54    1. (Partial) template specialisation of ConverterExplicit::convert()
55    Fallbacks:
56    2. Any possible implicit conversion. This includes 'FooBar' --> 'int' if FooBar defines operator float().
57    3. Global or member operators for stringstream when converting from or to std::string (or FROM const char*)
58    4. (Partial) template specialisation of ConverterFallback::convert()
59    5. Function that simply displays "Could not convert value" with type information obtained from typeid().
60
61    Notes:
62    There has to be an exact type match when using template specialisations.
63    Template specialisations can be defined after including this file. Any implicit cast function or iostream
64    operator has to be declared BEFORE this file gets parsed.
65
66    Defining your own functions:
67    There are obviously 4 ways to specifiy a user defined conversion. What should I use?
68
69    Usually, ConverterFallback fits quite well. You won't have to deal with the conversion from
70    'MyClass' to 'MyClass' by using another explicit template specialisation to avoid ambiguities.
71
72    However if you want to overwrite an implicit conversion or an iostream operator, you really need to
73    make use of ConverterExplicit.
74*/
75
76namespace orxonox
77{
78    namespace detail
79    {
80        //! Little template that maps integers to entire types (Alexandrescu 2001)
81        template <int I>
82        struct Int2Type { };
83    }
84
85
86    ///////////////////
87    // No Conversion //
88    ///////////////////
89
90    // Default template. No conversion available at all.
91    template <class FromType, class ToType>
92    struct ConverterFallback
93    {
94        FORCEINLINE static bool convert(ToType* output, const FromType& input)
95        {
96            COUT(2) << "Could not convert value of type " << typeid(FromType).name()
97                    << " to type " << typeid(ToType).name() << std::endl;
98            return false;
99        }
100    };
101
102    // If all else fails, try a dynamic_cast for pointer types.
103    template <class FromType, class ToType>
104    struct ConverterFallback<FromType*, ToType*>
105    {
106        FORCEINLINE static bool convert(ToType** output, FromType* const input)
107        {
108            ToType* temp = dynamic_cast<ToType*>(input);
109            if (temp)
110            {
111                *output = temp;
112                return true;
113            }
114            else
115                return false;
116        }
117    };
118}
119
120
121///////////////////////
122// ConverterFallback //
123///////////////////////
124
125// Default template for stringstream
126template <class FromType, class ToType>
127struct ConverterStringStream
128{
129    FORCEINLINE static bool convert(ToType* output, const FromType& input)
130    {
131        return orxonox::ConverterFallback<FromType, ToType>::convert(output, input);
132    }
133};
134
135
136/////////////
137// OStream //
138/////////////
139
140namespace fallbackTemplates
141{
142    template <class FromType>
143    FORCEINLINE bool operator <<(std::ostream& outstream,  const FromType& input)
144    {
145        std::string temp;
146        if (orxonox::ConverterFallback<FromType, std::string>::convert(&temp, input))
147        {
148            std::operator <<(outstream, temp);
149            return true;
150        }
151        else
152            return false;
153    }
154}
155
156// template that evaluates whether we can convert to std::string via ostringstream
157template <class FromType>
158struct ConverterStringStream<FromType, std::string>
159{
160    FORCEINLINE static bool convert(std::string* output, const FromType& input)
161    {
162        using namespace fallbackTemplates;
163        // this operator call only chooses fallbackTemplates::operator<< if there's no other fitting function
164        std::ostringstream oss;
165        if (oss << input)
166        {
167            (*output) = oss.str();
168            return true;
169        }
170        else
171            return false;
172    }
173};
174
175
176/////////////
177// IStream //
178/////////////
179
180namespace fallbackTemplates
181{
182    template <class ToType>
183    FORCEINLINE bool operator >>(std::istream& instream, ToType& output)
184    {
185        return orxonox::ConverterFallback<std::string, ToType>
186            ::convert(&output, static_cast<std::istringstream&>(instream).str());
187    }
188}
189
190// template that evaluates whether we can convert from std::string via ostringstream
191template <class ToType>
192struct ConverterStringStream<std::string, ToType>
193{
194    FORCEINLINE static bool convert(ToType* output, const std::string& input)
195    {
196        using namespace fallbackTemplates;
197        std::istringstream iss(input);
198        // this operator call only chooses fallbackTemplates::operator>> if there's no other fitting function
199        if (iss >> (*output))
200        {
201            return true;
202        }
203        else
204            return false;
205    }
206};
207
208namespace orxonox
209{
210
211    ///////////////////
212    // Implicit Cast //
213    ///////////////////
214
215    // implicit cast not possible, try stringstream conversion next
216    template <class FromType, class ToType>
217    FORCEINLINE bool convertImplicitely(ToType* output, const FromType& input, detail::Int2Type<false>)
218    {
219        return ConverterStringStream<FromType, ToType>::convert(output, input);
220    }
221
222    // We can cast implicitely
223    template <class FromType, class ToType>
224    FORCEINLINE bool convertImplicitely(ToType* output, const FromType& input, detail::Int2Type<true>)
225    {
226        (*output) = static_cast<ToType>(input);
227        return true;
228    }
229
230
231    ////////////////////////////////
232    // ConverterExplicit Fallback //
233    ////////////////////////////////
234
235    // Default template if no specialisation is available
236    template <class FromType, class ToType>
237    struct ConverterExplicit
238    {
239        FORCEINLINE static bool convert(ToType* output, const FromType& input)
240        {
241            // Try implict cast and probe first. If a simple cast is not possible, it will not compile
242            // We therefore have to out source it into another template function
243            const bool probe = ImplicitConversion<FromType, ToType>::exists;
244            return convertImplicitely(output, input, detail::Int2Type<probe>());
245        }
246    };
247
248
249    //////////////////////
250    // Public Functions //
251    //////////////////////
252
253    /**
254    @brief
255        Converts any value to any other as long as there exists a conversion.
256        Otherwise, the conversion will generate a runtime warning and return false.
257        For information about the different conversion methods (user defined too), see the section
258        'Actual conversion sequence' in this file above.
259    */
260    template <class FromType, class ToType>
261    FORCEINLINE bool convertValue(ToType* output, const FromType& input)
262    {
263        return ConverterExplicit<FromType, ToType>::convert(output, input);
264    }
265
266    // Calls convertValue and returns true if the conversion was successful.
267    // Otherwise the fallback is used.
268    /**
269    @brief
270        Converts any value to any other as long as there exists a conversion.
271        Otherwise, the conversion will generate a runtime warning and return false.
272        For information about the different conversion methods (user defined too), see the section
273        'Actual conversion sequence' in this file above.
274        If the conversion doesn't succeed, 'fallback' is written to '*output'.
275    @param fallback
276        A default value that gets written to '*output' if there is no conversion.
277    */
278    template<class FromType, class ToType>
279    FORCEINLINE bool convertValue(ToType* output, const FromType& input, const ToType& fallback)
280    {
281        if (convertValue(output, input))
282            return true;
283        else
284        {
285            (*output) = fallback;
286            return false;
287        }
288    }
289
290    // Directly returns the converted value, even if the conversion was not successful.
291    template<class FromType, class ToType>
292    FORCEINLINE ToType getConvertedValue(const FromType& input)
293    {
294        ToType output;
295        convertValue(&output, input);
296        return output;
297    }
298
299    // Directly returns the converted value, but uses the fallback on failure.
300    template<class FromType, class ToType>
301    FORCEINLINE ToType getConvertedValue(const FromType& input, const ToType& fallback)
302    {
303        ToType output;
304        convertValue(&output, input, fallback);
305        return output;
306    }
307
308    // Like getConvertedValue, but the template argument order is in reverse.
309    // That means you can call it exactly like static_cast<ToType>(fromTypeValue).
310    template<class ToType, class FromType>
311    FORCEINLINE ToType multi_cast(const FromType& input)
312    {
313        ToType output;
314        convertValue(&output, input);
315        return output;
316    }
317
318    // convert to string Shortcut
319    template <class FromType>
320    FORCEINLINE std::string convertToString(FromType value)
321    {
322        return getConvertedValue<FromType, std::string>(value);
323    }
324
325    // convert from string Shortcut
326    template <class ToType>
327    FORCEINLINE ToType convertFromString(std::string str)
328    {
329        return getConvertedValue<std::string, ToType>(str);
330    }
331
332    ////////////////////////////////
333    // Special string conversions //
334    ////////////////////////////////
335
336    // Delegate conversion from const char* to std::string
337    template <class ToType>
338    struct ConverterExplicit<const char*, ToType>
339    {
340        FORCEINLINE static bool convert(ToType* output, const char* input)
341        {
342            return convertValue<std::string, ToType>(output, input);
343        }
344    };
345
346    // These conversions would exhibit ambiguous << or >> operators when using stringstream
347    template <>
348    struct ConverterExplicit<char, std::string>
349    {
350        FORCEINLINE static bool convert(std::string* output, const char input)
351        {
352            *output = std::string(1, input);
353            return true;
354        }
355    };
356    template <>
357    struct ConverterExplicit<unsigned char, std::string>
358    {
359        FORCEINLINE static bool convert(std::string* output, const unsigned char input)
360        {
361            *output = std::string(1, input);
362            return true;
363        }
364    };
365    template <>
366    struct ConverterExplicit<std::string, char>
367    {
368        FORCEINLINE static bool convert(char* output, const std::string input)
369        {
370            if (input != "")
371                *output = input[0];
372            else
373                *output = '\0';
374            return true;
375        }
376    };
377    template <>
378    struct ConverterExplicit<std::string, unsigned char>
379    {
380        FORCEINLINE static bool convert(unsigned char* output, const std::string input)
381        {
382            if (input != "")
383                *output = input[0];
384            else
385                *output = '\0';
386            return true;
387        }
388    };
389
390
391    // bool to std::string
392    template <>
393    struct ConverterExplicit<bool, std::string>
394    {
395        FORCEINLINE static bool convert(std::string* output, const bool& input)
396        {
397            if (input)
398              *output = "true";
399            else
400              *output = "false";
401            return true;
402        }
403    };
404
405    // std::string to bool
406    template <>
407    struct ConverterExplicit<std::string, bool>
408    {
409        static bool convert(bool* output, const std::string& input)
410        {
411            std::string stripped = getLowercase(removeTrailingWhitespaces(input));
412            if (stripped == "true" || stripped == "on" || stripped == "yes")
413            {
414              *output = true;
415              return true;
416            }
417            else if (stripped == "false" || stripped == "off" || stripped == "no")
418            {
419              *output = false;
420              return true;
421            }
422
423            std::istringstream iss(input);
424            if (iss >> (*output))
425                return true;
426            else
427                return false;
428        }
429    };
430}
431
432#endif /* _Convert_H__ */
Note: See TracBrowser for help on using the repository browser.