Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/tutorial/src/libraries/util/Convert.h @ 6636

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

Merged presentation2 branch back to trunk.
Major new features:

  • Actual GUI with settings, etc.
  • Improved space ship steering (human interaction)
  • Rocket fire and more particle effects
  • Advanced sound framework
  • Property svn:eol-style set to native
File size: 12.7 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
120///////////////////////
121// ConverterFallback //
122///////////////////////
123
124// Default template for stringstream
125template <class FromType, class ToType>
126struct ConverterStringStream
127{
128    FORCEINLINE static bool convert(ToType* output, const FromType& input)
129    {
130        return orxonox::ConverterFallback<FromType, ToType>::convert(output, input);
131    }
132};
133
134
135/////////////
136// OStream //
137/////////////
138
139namespace fallbackTemplates
140{
141    template <class FromType>
142    FORCEINLINE bool operator <<(std::ostream& outstream,  const FromType& input)
143    {
144        std::string temp;
145        if (orxonox::ConverterFallback<FromType, std::string>::convert(&temp, input))
146        {
147            std::operator <<(outstream, temp);
148            return true;
149        }
150        else
151            return false;
152    }
153}
154
155// template that evaluates whether we can convert to std::string via ostringstream
156template <class FromType>
157struct ConverterStringStream<FromType, std::string>
158{
159    FORCEINLINE static bool convert(std::string* output, const FromType& input)
160    {
161        using namespace fallbackTemplates;
162        // this operator call only chooses fallbackTemplates::operator<< if there's no other fitting function
163        std::ostringstream oss;
164        if (oss << input)
165        {
166            (*output) = oss.str();
167            return true;
168        }
169        else
170            return false;
171    }
172};
173
174
175/////////////
176// IStream //
177/////////////
178
179namespace fallbackTemplates
180{
181    template <class ToType>
182    FORCEINLINE bool operator >>(std::istream& instream, ToType& output)
183    {
184        return orxonox::ConverterFallback<std::string, ToType>
185            ::convert(&output, static_cast<std::istringstream&>(instream).str());
186    }
187}
188
189// template that evaluates whether we can convert from std::string via ostringstream
190template <class ToType>
191struct ConverterStringStream<std::string, ToType>
192{
193    FORCEINLINE static bool convert(ToType* output, const std::string& input)
194    {
195        using namespace fallbackTemplates;
196        std::istringstream iss(input);
197        // this operator call only chooses fallbackTemplates::operator>> if there's no other fitting function
198        if (iss >> (*output))
199        {
200            return true;
201        }
202        else
203            return false;
204    }
205};
206
207namespace orxonox
208{
209
210    ///////////////////
211    // Implicit Cast //
212    ///////////////////
213
214    // implicit cast not possible, try stringstream conversion next
215    template <class FromType, class ToType>
216    FORCEINLINE bool convertImplicitely(ToType* output, const FromType& input, detail::Int2Type<false>)
217    {
218        return ConverterStringStream<FromType, ToType>::convert(output, input);
219    }
220
221    // We can cast implicitely
222    template <class FromType, class ToType>
223    FORCEINLINE bool convertImplicitely(ToType* output, const FromType& input, detail::Int2Type<true>)
224    {
225        (*output) = static_cast<ToType>(input);
226        return true;
227    }
228
229
230    ////////////////////////////////
231    // ConverterExplicit Fallback //
232    ////////////////////////////////
233
234    // Default template if no specialisation is available
235    template <class FromType, class ToType>
236    struct ConverterExplicit
237    {
238        enum { probe = ImplicitConversion<FromType, ToType>::exists };
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            return convertImplicitely(output, input, detail::Int2Type<probe>());
244        }
245    };
246
247
248    //////////////////////
249    // Public Functions //
250    //////////////////////
251
252    /**
253    @brief
254        Converts any value to any other as long as there exists a conversion.
255        Otherwise, the conversion will generate a runtime warning and return false.
256        For information about the different conversion methods (user defined too), see the section
257        'Actual conversion sequence' in this file above.
258    */
259    template <class FromType, class ToType>
260    FORCEINLINE bool convertValue(ToType* output, const FromType& input)
261    {
262        return ConverterExplicit<FromType, ToType>::convert(output, input);
263    }
264
265    // Calls convertValue and returns true if the conversion was successful.
266    // Otherwise the fallback is used.
267    /**
268    @brief
269        Converts any value to any other as long as there exists a conversion.
270        Otherwise, the conversion will generate a runtime warning and return false.
271        For information about the different conversion methods (user defined too), see the section
272        'Actual conversion sequence' in this file above.
273        If the conversion doesn't succeed, 'fallback' is written to '*output'.
274    @param fallback
275        A default value that gets written to '*output' if there is no conversion.
276    */
277    template<class FromType, class ToType>
278    FORCEINLINE bool convertValue(ToType* output, const FromType& input, const ToType& fallback)
279    {
280        if (convertValue(output, input))
281            return true;
282        else
283        {
284            (*output) = fallback;
285            return false;
286        }
287    }
288
289    // Directly returns the converted value, even if the conversion was not successful.
290    template<class FromType, class ToType>
291    FORCEINLINE ToType getConvertedValue(const FromType& input)
292    {
293        ToType output;
294        convertValue(&output, input);
295        return output;
296    }
297
298    // Directly returns the converted value, but uses the fallback on failure.
299    template<class FromType, class ToType>
300    FORCEINLINE ToType getConvertedValue(const FromType& input, const ToType& fallback)
301    {
302        ToType output;
303        convertValue(&output, input, fallback);
304        return output;
305    }
306
307    // Like getConvertedValue, but the template argument order is in reverse.
308    // That means you can call it exactly like static_cast<ToType>(fromTypeValue).
309    template<class ToType, class FromType>
310    FORCEINLINE ToType multi_cast(const FromType& input)
311    {
312        ToType output;
313        convertValue(&output, input);
314        return output;
315    }
316
317    ////////////////////////////////
318    // Special string conversions //
319    ////////////////////////////////
320
321    // Delegate conversion from const char* to std::string
322    template <class ToType>
323    struct ConverterExplicit<const char*, ToType>
324    {
325        FORCEINLINE static bool convert(ToType* output, const char* input)
326        {
327            return convertValue<std::string, ToType>(output, input);
328        }
329    };
330
331    // These conversions would exhibit ambiguous << or >> operators when using stringstream
332    template <>
333    struct ConverterExplicit<char, std::string>
334    {
335        FORCEINLINE static bool convert(std::string* output, const char input)
336        {
337            *output = input;
338            return true;
339        }
340    };
341    template <>
342    struct ConverterExplicit<unsigned char, std::string>
343    {
344        FORCEINLINE static bool convert(std::string* output, const unsigned char input)
345        {
346            *output = input;
347            return true;
348        }
349    };
350    template <>
351    struct ConverterExplicit<std::string, char>
352    {
353        FORCEINLINE static bool convert(char* output, const std::string& input)
354        {
355            if (!input.empty())
356                *output = input[0];
357            else
358                *output = '\0';
359            return true;
360        }
361    };
362    template <>
363    struct ConverterExplicit<std::string, unsigned char>
364    {
365        FORCEINLINE static bool convert(unsigned char* output, const std::string& input)
366        {
367            if (!input.empty())
368                *output = input[0];
369            else
370                *output = '\0';
371            return true;
372        }
373    };
374
375
376    // bool to std::string
377    template <>
378    struct ConverterExplicit<bool, std::string>
379    {
380        FORCEINLINE static bool convert(std::string* output, const bool& input)
381        {
382            if (input)
383              *output = "true";
384            else
385              *output = "false";
386            return true;
387        }
388    };
389
390    // Declarations to avoid StringUtils.h include
391    _UtilExport std::string removeTrailingWhitespaces(const std::string& str);
392    _UtilExport std::string getLowercase(const std::string& str);
393
394    // std::string to bool
395    template <>
396    struct ConverterExplicit<std::string, bool>
397    {
398        static bool convert(bool* output, const std::string& input)
399        {
400            const std::string& stripped = getLowercase(removeTrailingWhitespaces(input));
401            if (stripped == "true" || stripped == "on" || stripped == "yes")
402            {
403                *output = true;
404                return true;
405            }
406            else if (stripped == "false" || stripped == "off" || stripped == "no")
407            {
408                *output = false;
409                return true;
410            }
411
412            std::istringstream iss(input);
413            if (iss >> (*output))
414                return true;
415            else
416                return false;
417        }
418    };
419}
420
421#endif /* _Convert_H__ */
Note: See TracBrowser for help on using the repository browser.