Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/libraries/util/Convert.h @ 7124

Last change on this file since 7124 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
RevLine 
[1052]1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
[1505]3 *                    > www.orxonox.net <
[1052]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:
[2087]23 *      Reto Grieder
[1791]24 *      Fabian 'x3n' Landau
[1052]25 *      Benjamin Grauer
[1505]26 *   Co-authors:
[1052]27 *      ...
28 */
29
30/*!
[2087]31    @file
[1052]32    @brief Definition and Implementation of the Convert class.
33*/
34
[2087]35#ifndef _Converter_H__
36#define _Converter_H__
[1052]37
[1062]38#include "UtilPrereqs.h"
39
[1052]40#include <string>
41#include <sstream>
[1837]42#include <typeinfo>
[1052]43
[1747]44#include "Debug.h"
[3232]45#include "TemplateUtils.h"
[1064]46
[2087]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().
[1505]59
[2087]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.
[1505]64
[2087]65    Defining your own functions:
66    There are obviously 4 ways to specifiy a user defined conversion. What should I use?
[1505]67
[2087]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.
[1505]70
[2087]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
[2171]75namespace orxonox
[1505]76{
[3196]77    namespace detail
[2171]78    {
79        //! Little template that maps integers to entire types (Alexandrescu 2001)
80        template <int I>
81        struct Int2Type { };
82    }
[1505]83
84
[2171]85    ///////////////////
86    // No Conversion //
87    ///////////////////
[1505]88
[2171]89    // Default template. No conversion available at all.
90    template <class FromType, class ToType>
91    struct ConverterFallback
[1505]92    {
[3196]93        FORCEINLINE static bool convert(ToType* output, const FromType& input)
[2171]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    };
[2087]100
[2171]101    // If all else fails, try a dynamic_cast for pointer types.
102    template <class FromType, class ToType>
103    struct ConverterFallback<FromType*, ToType*>
[1505]104    {
[3196]105        FORCEINLINE static bool convert(ToType** output, FromType* const input)
[2087]106        {
[2171]107            ToType* temp = dynamic_cast<ToType*>(input);
108            if (temp)
109            {
110                *output = temp;
111                return true;
112            }
113            else
114                return false;
[2087]115        }
[2171]116    };
117}
[1505]118
119
[2087]120///////////////////////
121// ConverterFallback //
122///////////////////////
123
124// Default template for stringstream
125template <class FromType, class ToType>
126struct ConverterStringStream
[1505]127{
[3196]128    FORCEINLINE static bool convert(ToType* output, const FromType& input)
[1505]129    {
[2171]130        return orxonox::ConverterFallback<FromType, ToType>::convert(output, input);
[1505]131    }
132};
133
134
135/////////////
[2087]136// OStream //
[1505]137/////////////
138
[2087]139namespace fallbackTemplates
[1505]140{
[2087]141    template <class FromType>
[3196]142    FORCEINLINE bool operator <<(std::ostream& outstream,  const FromType& input)
[2087]143    {
144        std::string temp;
[2171]145        if (orxonox::ConverterFallback<FromType, std::string>::convert(&temp, input))
[2087]146        {
147            std::operator <<(outstream, temp);
148            return true;
149        }
150        else
151            return false;
152    }
153}
[1505]154
[2087]155// template that evaluates whether we can convert to std::string via ostringstream
[1505]156template <class FromType>
[2087]157struct ConverterStringStream<FromType, std::string>
[1505]158{
[3196]159    FORCEINLINE static bool convert(std::string* output, const FromType& input)
[1505]160    {
[2087]161        using namespace fallbackTemplates;
162        // this operator call only chooses fallbackTemplates::operator<< if there's no other fitting function
[1505]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
[2087]174
175/////////////
176// IStream //
177/////////////
178
179namespace fallbackTemplates
[1625]180{
[2087]181    template <class ToType>
[3196]182    FORCEINLINE bool operator >>(std::istream& instream, ToType& output)
[2087]183    {
[2171]184        return orxonox::ConverterFallback<std::string, ToType>
[2087]185            ::convert(&output, static_cast<std::istringstream&>(instream).str());
186    }
[1625]187}
188
[2087]189// template that evaluates whether we can convert from std::string via ostringstream
[1505]190template <class ToType>
[2087]191struct ConverterStringStream<std::string, ToType>
[1505]192{
[3196]193    FORCEINLINE static bool convert(ToType* output, const std::string& input)
[1505]194    {
[2087]195        using namespace fallbackTemplates;
[1505]196        std::istringstream iss(input);
[2087]197        // this operator call only chooses fallbackTemplates::operator>> if there's no other fitting function
[1505]198        if (iss >> (*output))
[2087]199        {
[1505]200            return true;
[2087]201        }
[1505]202        else
203            return false;
204    }
205};
206
[2171]207namespace orxonox
[1625]208{
[1505]209
[2171]210    ///////////////////
211    // Implicit Cast //
212    ///////////////////
[1625]213
[2171]214    // implicit cast not possible, try stringstream conversion next
215    template <class FromType, class ToType>
[3196]216    FORCEINLINE bool convertImplicitely(ToType* output, const FromType& input, detail::Int2Type<false>)
[1505]217    {
[2171]218        return ConverterStringStream<FromType, ToType>::convert(output, input);
[1505]219    }
220
[2171]221    // We can cast implicitely
222    template <class FromType, class ToType>
[3196]223    FORCEINLINE bool convertImplicitely(ToType* output, const FromType& input, detail::Int2Type<true>)
[2171]224    {
225        (*output) = static_cast<ToType>(input);
[2087]226        return true;
[1505]227    }
228
229
[2171]230    ////////////////////////////////
231    // ConverterExplicit Fallback //
232    ////////////////////////////////
[1505]233
[2171]234    // Default template if no specialisation is available
235    template <class FromType, class ToType>
236    struct ConverterExplicit
237    {
[3234]238        enum { probe = ImplicitConversion<FromType, ToType>::exists };
[3196]239        FORCEINLINE static bool convert(ToType* output, const FromType& input)
[2171]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
[3196]243            return convertImplicitely(output, input, detail::Int2Type<probe>());
[2171]244        }
245    };
[2087]246
247
[2171]248    //////////////////////
249    // Public Functions //
250    //////////////////////
[2087]251
[2171]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>
[3196]260    FORCEINLINE bool convertValue(ToType* output, const FromType& input)
[2171]261    {
262        return ConverterExplicit<FromType, ToType>::convert(output, input);
263    }
[2087]264
[2171]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>
[3196]278    FORCEINLINE bool convertValue(ToType* output, const FromType& input, const ToType& fallback)
[1625]279    {
[2171]280        if (convertValue(output, input))
281            return true;
282        else
283        {
284            (*output) = fallback;
285            return false;
286        }
[1625]287    }
288
[2171]289    // Directly returns the converted value, even if the conversion was not successful.
290    template<class FromType, class ToType>
[3196]291    FORCEINLINE ToType getConvertedValue(const FromType& input)
[1505]292    {
[2171]293        ToType output;
294        convertValue(&output, input);
295        return output;
[1505]296    }
[2171]297
298    // Directly returns the converted value, but uses the fallback on failure.
299    template<class FromType, class ToType>
[3196]300    FORCEINLINE ToType getConvertedValue(const FromType& input, const ToType& fallback)
[1505]301    {
[2171]302        ToType output;
303        convertValue(&output, input, fallback);
304        return output;
[1505]305    }
[2171]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>
[3196]310    FORCEINLINE ToType multi_cast(const FromType& input)
[1505]311    {
[2171]312        ToType output;
313        convertValue(&output, input);
314        return output;
[1505]315    }
316
[2171]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>
[1625]324    {
[3196]325        FORCEINLINE static bool convert(ToType* output, const char* input)
[1625]326        {
[2171]327            return convertValue<std::string, ToType>(output, input);
[1625]328        }
[2171]329    };
330
331    // These conversions would exhibit ambiguous << or >> operators when using stringstream
332    template <>
333    struct ConverterExplicit<char, std::string>
334    {
[3196]335        FORCEINLINE static bool convert(std::string* output, const char input)
[1625]336        {
[6417]337            *output = input;
[2171]338            return true;
[1625]339        }
[2171]340    };
341    template <>
342    struct ConverterExplicit<unsigned char, std::string>
343    {
[3196]344        FORCEINLINE static bool convert(std::string* output, const unsigned char input)
[2171]345        {
[6417]346            *output = input;
[2171]347            return true;
348        }
349    };
350    template <>
351    struct ConverterExplicit<std::string, char>
352    {
[6417]353        FORCEINLINE static bool convert(char* output, const std::string& input)
[2171]354        {
[6417]355            if (!input.empty())
[2171]356                *output = input[0];
357            else
358                *output = '\0';
359            return true;
360        }
361    };
362    template <>
363    struct ConverterExplicit<std::string, unsigned char>
364    {
[6417]365        FORCEINLINE static bool convert(unsigned char* output, const std::string& input)
[2171]366        {
[6417]367            if (!input.empty())
[2171]368                *output = input[0];
369            else
370                *output = '\0';
371            return true;
372        }
373    };
[1625]374
[2171]375
376    // bool to std::string
377    template <>
378    struct ConverterExplicit<bool, std::string>
379    {
[3196]380        FORCEINLINE static bool convert(std::string* output, const bool& input)
[2171]381        {
382            if (input)
383              *output = "true";
384            else
385              *output = "false";
[2662]386            return true;
[2171]387        }
388    };
[1625]389
[6417]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
[2171]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        {
[6417]400            const std::string& stripped = getLowercase(removeTrailingWhitespaces(input));
[2171]401            if (stripped == "true" || stripped == "on" || stripped == "yes")
402            {
[6417]403                *output = true;
404                return true;
[2171]405            }
406            else if (stripped == "false" || stripped == "off" || stripped == "no")
407            {
[6417]408                *output = false;
409                return true;
[2171]410            }
411
412            std::istringstream iss(input);
413            if (iss >> (*output))
414                return true;
415            else
416                return false;
417        }
418    };
419}
420
[1052]421#endif /* _Convert_H__ */
Note: See TracBrowser for help on using the repository browser.