Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/consolecommands2/src/libraries/util/Convert.h @ 7774

Last change on this file since 7774 was 6452, checked in by landauf, 15 years ago

merged current state of the new cc system to the updated branch

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