Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/consolecommands3/src/libraries/util/Convert.h @ 7687

Last change on this file since 7687 was 7179, checked in by landauf, 14 years ago

merged consolecommands2 to consolecommands3

  • Property svn:eol-style set to native
File size: 13.0 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:
[7163]66    There are obviously 4 ways to specify a user defined conversion. What should you 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
[7163]72    make use of ConverterExplicit. We have to do this for the Ogre classes for instance because they
73    define stream operators we don't particulary like.
[2087]74*/
75
[2171]76namespace orxonox
[1505]77{
[3196]78    namespace detail
[2171]79    {
80        //! Little template that maps integers to entire types (Alexandrescu 2001)
81        template <int I>
82        struct Int2Type { };
83    }
[1505]84
85
[2171]86    ///////////////////
87    // No Conversion //
88    ///////////////////
[1505]89
[2171]90    // Default template. No conversion available at all.
91    template <class FromType, class ToType>
92    struct ConverterFallback
[1505]93    {
[3196]94        FORCEINLINE static bool convert(ToType* output, const FromType& input)
[2171]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    };
[2087]101
[2171]102    // If all else fails, try a dynamic_cast for pointer types.
103    template <class FromType, class ToType>
104    struct ConverterFallback<FromType*, ToType*>
[1505]105    {
[3196]106        FORCEINLINE static bool convert(ToType** output, FromType* const input)
[2087]107        {
[2171]108            ToType* temp = dynamic_cast<ToType*>(input);
109            if (temp)
110            {
111                *output = temp;
112                return true;
113            }
114            else
115                return false;
[2087]116        }
[2171]117    };
[7179]118
119    ////////////
120    // upcast //
121    ////////////
122    namespace detail
123    {
124        // perform a static cast if ToType is a base of FromType
125        template<class ToType, class FromType>
126        FORCEINLINE ToType upcast(FromType input, detail::Int2Type<true>)
127        {
128            return static_cast<ToType>(input);
129        }
130
131        // return zero if ToType is not a base of FromType
132        template<class ToType, class FromType>
133        FORCEINLINE ToType upcast(FromType input, detail::Int2Type<false>)
134        {
135            return 0;
136        }
137    }
138
139    // performs an upcast if ToType is a base of FromType, returns zero otherwise
140    template <class ToType, class FromType>
141    FORCEINLINE ToType upcast(FromType input)
142    {
143        enum { probe = ImplicitConversion<FromType, ToType>::exists };
144        return detail::upcast<ToType, FromType>(input, detail::Int2Type<probe>());
145    }
[2171]146}
[1505]147
148
[2087]149///////////////////////
150// ConverterFallback //
151///////////////////////
152
153// Default template for stringstream
154template <class FromType, class ToType>
155struct ConverterStringStream
[1505]156{
[3196]157    FORCEINLINE static bool convert(ToType* output, const FromType& input)
[1505]158    {
[2171]159        return orxonox::ConverterFallback<FromType, ToType>::convert(output, input);
[1505]160    }
161};
162
163
164/////////////
[2087]165// OStream //
[1505]166/////////////
167
[2087]168namespace fallbackTemplates
[1505]169{
[2087]170    template <class FromType>
[3196]171    FORCEINLINE bool operator <<(std::ostream& outstream,  const FromType& input)
[2087]172    {
173        std::string temp;
[2171]174        if (orxonox::ConverterFallback<FromType, std::string>::convert(&temp, input))
[2087]175        {
176            std::operator <<(outstream, temp);
177            return true;
178        }
179        else
180            return false;
181    }
182}
[1505]183
[2087]184// template that evaluates whether we can convert to std::string via ostringstream
[1505]185template <class FromType>
[2087]186struct ConverterStringStream<FromType, std::string>
[1505]187{
[3196]188    FORCEINLINE static bool convert(std::string* output, const FromType& input)
[1505]189    {
[2087]190        using namespace fallbackTemplates;
191        // this operator call only chooses fallbackTemplates::operator<< if there's no other fitting function
[1505]192        std::ostringstream oss;
193        if (oss << input)
194        {
195            (*output) = oss.str();
196            return true;
197        }
198        else
199            return false;
200    }
201};
202
[2087]203
204/////////////
205// IStream //
206/////////////
207
208namespace fallbackTemplates
[1625]209{
[2087]210    template <class ToType>
[3196]211    FORCEINLINE bool operator >>(std::istream& instream, ToType& output)
[2087]212    {
[2171]213        return orxonox::ConverterFallback<std::string, ToType>
[2087]214            ::convert(&output, static_cast<std::istringstream&>(instream).str());
215    }
[1625]216}
217
[2087]218// template that evaluates whether we can convert from std::string via ostringstream
[1505]219template <class ToType>
[2087]220struct ConverterStringStream<std::string, ToType>
[1505]221{
[3196]222    FORCEINLINE static bool convert(ToType* output, const std::string& input)
[1505]223    {
[2087]224        using namespace fallbackTemplates;
[1505]225        std::istringstream iss(input);
[2087]226        // this operator call only chooses fallbackTemplates::operator>> if there's no other fitting function
[1505]227        if (iss >> (*output))
[2087]228        {
[1505]229            return true;
[2087]230        }
[1505]231        else
232            return false;
233    }
234};
235
[2171]236namespace orxonox
[1625]237{
[1505]238
[2171]239    ///////////////////
240    // Implicit Cast //
241    ///////////////////
[1625]242
[2171]243    // implicit cast not possible, try stringstream conversion next
244    template <class FromType, class ToType>
[3196]245    FORCEINLINE bool convertImplicitely(ToType* output, const FromType& input, detail::Int2Type<false>)
[1505]246    {
[2171]247        return ConverterStringStream<FromType, ToType>::convert(output, input);
[1505]248    }
249
[2171]250    // We can cast implicitely
251    template <class FromType, class ToType>
[3196]252    FORCEINLINE bool convertImplicitely(ToType* output, const FromType& input, detail::Int2Type<true>)
[2171]253    {
254        (*output) = static_cast<ToType>(input);
[2087]255        return true;
[1505]256    }
257
258
[2171]259    ////////////////////////////////
260    // ConverterExplicit Fallback //
261    ////////////////////////////////
[1505]262
[2171]263    // Default template if no specialisation is available
264    template <class FromType, class ToType>
265    struct ConverterExplicit
266    {
[3234]267        enum { probe = ImplicitConversion<FromType, ToType>::exists };
[3196]268        FORCEINLINE static bool convert(ToType* output, const FromType& input)
[2171]269        {
270            // Try implict cast and probe first. If a simple cast is not possible, it will not compile
271            // We therefore have to out source it into another template function
[3196]272            return convertImplicitely(output, input, detail::Int2Type<probe>());
[2171]273        }
274    };
[2087]275
276
[2171]277    //////////////////////
278    // Public Functions //
279    //////////////////////
[2087]280
[2171]281    /**
282    @brief
283        Converts any value to any other as long as there exists a conversion.
284        Otherwise, the conversion will generate a runtime warning and return false.
285        For information about the different conversion methods (user defined too), see the section
286        'Actual conversion sequence' in this file above.
287    */
288    template <class FromType, class ToType>
[3196]289    FORCEINLINE bool convertValue(ToType* output, const FromType& input)
[2171]290    {
291        return ConverterExplicit<FromType, ToType>::convert(output, input);
292    }
[2087]293
[2171]294    // Calls convertValue and returns true if the conversion was successful.
295    // Otherwise the fallback is used.
296    /**
297    @brief
298        Converts any value to any other as long as there exists a conversion.
299        Otherwise, the conversion will generate a runtime warning and return false.
300        For information about the different conversion methods (user defined too), see the section
301        'Actual conversion sequence' in this file above.
302        If the conversion doesn't succeed, 'fallback' is written to '*output'.
303    @param fallback
304        A default value that gets written to '*output' if there is no conversion.
305    */
306    template<class FromType, class ToType>
[3196]307    FORCEINLINE bool convertValue(ToType* output, const FromType& input, const ToType& fallback)
[1625]308    {
[2171]309        if (convertValue(output, input))
310            return true;
311        else
312        {
313            (*output) = fallback;
314            return false;
315        }
[1625]316    }
317
[2171]318    // Directly returns the converted value, even if the conversion was not successful.
319    template<class FromType, class ToType>
[3196]320    FORCEINLINE ToType getConvertedValue(const FromType& input)
[1505]321    {
[2171]322        ToType output;
323        convertValue(&output, input);
324        return output;
[1505]325    }
[2171]326
327    // Directly returns the converted value, but uses the fallback on failure.
328    template<class FromType, class ToType>
[3196]329    FORCEINLINE ToType getConvertedValue(const FromType& input, const ToType& fallback)
[1505]330    {
[2171]331        ToType output;
332        convertValue(&output, input, fallback);
333        return output;
[1505]334    }
[2171]335
336    // Like getConvertedValue, but the template argument order is in reverse.
337    // That means you can call it exactly like static_cast<ToType>(fromTypeValue).
338    template<class ToType, class FromType>
[3196]339    FORCEINLINE ToType multi_cast(const FromType& input)
[1505]340    {
[2171]341        ToType output;
342        convertValue(&output, input);
343        return output;
[1505]344    }
345
[2171]346    ////////////////////////////////
347    // Special string conversions //
348    ////////////////////////////////
349
350    // Delegate conversion from const char* to std::string
351    template <class ToType>
352    struct ConverterExplicit<const char*, ToType>
[1625]353    {
[3196]354        FORCEINLINE static bool convert(ToType* output, const char* input)
[1625]355        {
[2171]356            return convertValue<std::string, ToType>(output, input);
[1625]357        }
[2171]358    };
359
360    // These conversions would exhibit ambiguous << or >> operators when using stringstream
361    template <>
362    struct ConverterExplicit<char, std::string>
363    {
[3196]364        FORCEINLINE static bool convert(std::string* output, const char input)
[1625]365        {
[6417]366            *output = input;
[2171]367            return true;
[1625]368        }
[2171]369    };
370    template <>
371    struct ConverterExplicit<unsigned char, std::string>
372    {
[3196]373        FORCEINLINE static bool convert(std::string* output, const unsigned char input)
[2171]374        {
[6417]375            *output = input;
[2171]376            return true;
377        }
378    };
379    template <>
380    struct ConverterExplicit<std::string, char>
381    {
[6417]382        FORCEINLINE static bool convert(char* output, const std::string& input)
[2171]383        {
[6417]384            if (!input.empty())
[2171]385                *output = input[0];
386            else
387                *output = '\0';
388            return true;
389        }
390    };
391    template <>
392    struct ConverterExplicit<std::string, unsigned char>
393    {
[6417]394        FORCEINLINE static bool convert(unsigned char* output, const std::string& input)
[2171]395        {
[6417]396            if (!input.empty())
[2171]397                *output = input[0];
398            else
399                *output = '\0';
400            return true;
401        }
402    };
[1625]403
[2171]404
405    // bool to std::string
406    template <>
407    struct ConverterExplicit<bool, std::string>
408    {
[3196]409        FORCEINLINE static bool convert(std::string* output, const bool& input)
[2171]410        {
411            if (input)
412              *output = "true";
413            else
414              *output = "false";
[2662]415            return true;
[2171]416        }
417    };
[1625]418
[2171]419    // std::string to bool
420    template <>
[7163]421    struct _UtilExport ConverterExplicit<std::string, bool>
[2171]422    {
[7163]423        static bool convert(bool* output, const std::string& input);
[2171]424    };
425}
426
[1052]427#endif /* _Convert_H__ */
Note: See TracBrowser for help on using the repository browser.