Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

Merged most of the core4 revisions back to the trunk except for:

  • orxonox_cast
  • all the radical changes in the input library
  • Property svn:eol-style set to native
File size: 12.6 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"
[3280]45#include "StringUtils.h"
[3232]46#include "TemplateUtils.h"
[1064]47
[2087]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().
[1505]60
[2087]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.
[1505]65
[2087]66    Defining your own functions:
67    There are obviously 4 ways to specifiy a user defined conversion. What should I use?
[1505]68
[2087]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.
[1505]71
[2087]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
[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    };
118}
[1505]119
120
[2087]121///////////////////////
122// ConverterFallback //
123///////////////////////
124
125// Default template for stringstream
126template <class FromType, class ToType>
127struct ConverterStringStream
[1505]128{
[3196]129    FORCEINLINE static bool convert(ToType* output, const FromType& input)
[1505]130    {
[2171]131        return orxonox::ConverterFallback<FromType, ToType>::convert(output, input);
[1505]132    }
133};
134
135
136/////////////
[2087]137// OStream //
[1505]138/////////////
139
[2087]140namespace fallbackTemplates
[1505]141{
[2087]142    template <class FromType>
[3196]143    FORCEINLINE bool operator <<(std::ostream& outstream,  const FromType& input)
[2087]144    {
145        std::string temp;
[2171]146        if (orxonox::ConverterFallback<FromType, std::string>::convert(&temp, input))
[2087]147        {
148            std::operator <<(outstream, temp);
149            return true;
150        }
151        else
152            return false;
153    }
154}
[1505]155
[2087]156// template that evaluates whether we can convert to std::string via ostringstream
[1505]157template <class FromType>
[2087]158struct ConverterStringStream<FromType, std::string>
[1505]159{
[3196]160    FORCEINLINE static bool convert(std::string* output, const FromType& input)
[1505]161    {
[2087]162        using namespace fallbackTemplates;
163        // this operator call only chooses fallbackTemplates::operator<< if there's no other fitting function
[1505]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
[2087]175
176/////////////
177// IStream //
178/////////////
179
180namespace fallbackTemplates
[1625]181{
[2087]182    template <class ToType>
[3196]183    FORCEINLINE bool operator >>(std::istream& instream, ToType& output)
[2087]184    {
[2171]185        return orxonox::ConverterFallback<std::string, ToType>
[2087]186            ::convert(&output, static_cast<std::istringstream&>(instream).str());
187    }
[1625]188}
189
[2087]190// template that evaluates whether we can convert from std::string via ostringstream
[1505]191template <class ToType>
[2087]192struct ConverterStringStream<std::string, ToType>
[1505]193{
[3196]194    FORCEINLINE static bool convert(ToType* output, const std::string& input)
[1505]195    {
[2087]196        using namespace fallbackTemplates;
[1505]197        std::istringstream iss(input);
[2087]198        // this operator call only chooses fallbackTemplates::operator>> if there's no other fitting function
[1505]199        if (iss >> (*output))
[2087]200        {
[1505]201            return true;
[2087]202        }
[1505]203        else
204            return false;
205    }
206};
207
[2171]208namespace orxonox
[1625]209{
[1505]210
[2171]211    ///////////////////
212    // Implicit Cast //
213    ///////////////////
[1625]214
[2171]215    // implicit cast not possible, try stringstream conversion next
216    template <class FromType, class ToType>
[3196]217    FORCEINLINE bool convertImplicitely(ToType* output, const FromType& input, detail::Int2Type<false>)
[1505]218    {
[2171]219        return ConverterStringStream<FromType, ToType>::convert(output, input);
[1505]220    }
221
[2171]222    // We can cast implicitely
223    template <class FromType, class ToType>
[3196]224    FORCEINLINE bool convertImplicitely(ToType* output, const FromType& input, detail::Int2Type<true>)
[2171]225    {
226        (*output) = static_cast<ToType>(input);
[2087]227        return true;
[1505]228    }
229
230
[2171]231    ////////////////////////////////
232    // ConverterExplicit Fallback //
233    ////////////////////////////////
[1505]234
[2171]235    // Default template if no specialisation is available
236    template <class FromType, class ToType>
237    struct ConverterExplicit
238    {
[3234]239        enum { probe = ImplicitConversion<FromType, ToType>::exists };
[3196]240        FORCEINLINE static bool convert(ToType* output, const FromType& input)
[2171]241        {
242            // Try implict cast and probe first. If a simple cast is not possible, it will not compile
243            // We therefore have to out source it into another template function
[3196]244            return convertImplicitely(output, input, detail::Int2Type<probe>());
[2171]245        }
246    };
[2087]247
248
[2171]249    //////////////////////
250    // Public Functions //
251    //////////////////////
[2087]252
[2171]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>
[3196]261    FORCEINLINE bool convertValue(ToType* output, const FromType& input)
[2171]262    {
263        return ConverterExplicit<FromType, ToType>::convert(output, input);
264    }
[2087]265
[2171]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>
[3196]279    FORCEINLINE bool convertValue(ToType* output, const FromType& input, const ToType& fallback)
[1625]280    {
[2171]281        if (convertValue(output, input))
282            return true;
283        else
284        {
285            (*output) = fallback;
286            return false;
287        }
[1625]288    }
289
[2171]290    // Directly returns the converted value, even if the conversion was not successful.
291    template<class FromType, class ToType>
[3196]292    FORCEINLINE ToType getConvertedValue(const FromType& input)
[1505]293    {
[2171]294        ToType output;
295        convertValue(&output, input);
296        return output;
[1505]297    }
[2171]298
299    // Directly returns the converted value, but uses the fallback on failure.
300    template<class FromType, class ToType>
[3196]301    FORCEINLINE ToType getConvertedValue(const FromType& input, const ToType& fallback)
[1505]302    {
[2171]303        ToType output;
304        convertValue(&output, input, fallback);
305        return output;
[1505]306    }
[2171]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>
[3196]311    FORCEINLINE ToType multi_cast(const FromType& input)
[1505]312    {
[2171]313        ToType output;
314        convertValue(&output, input);
315        return output;
[1505]316    }
317
[2171]318    ////////////////////////////////
319    // Special string conversions //
320    ////////////////////////////////
321
322    // Delegate conversion from const char* to std::string
323    template <class ToType>
324    struct ConverterExplicit<const char*, ToType>
[1625]325    {
[3196]326        FORCEINLINE static bool convert(ToType* output, const char* input)
[1625]327        {
[2171]328            return convertValue<std::string, ToType>(output, input);
[1625]329        }
[2171]330    };
331
332    // These conversions would exhibit ambiguous << or >> operators when using stringstream
333    template <>
334    struct ConverterExplicit<char, std::string>
335    {
[3196]336        FORCEINLINE static bool convert(std::string* output, const char input)
[1625]337        {
[2171]338            *output = std::string(1, input);
339            return true;
[1625]340        }
[2171]341    };
342    template <>
343    struct ConverterExplicit<unsigned char, std::string>
344    {
[3196]345        FORCEINLINE static bool convert(std::string* output, const unsigned char input)
[2171]346        {
347            *output = std::string(1, input);
348            return true;
349        }
350    };
351    template <>
352    struct ConverterExplicit<std::string, char>
353    {
[3196]354        FORCEINLINE static bool convert(char* output, const std::string input)
[2171]355        {
356            if (input != "")
357                *output = input[0];
358            else
359                *output = '\0';
360            return true;
361        }
362    };
363    template <>
364    struct ConverterExplicit<std::string, unsigned char>
365    {
[3196]366        FORCEINLINE static bool convert(unsigned char* output, const std::string input)
[2171]367        {
368            if (input != "")
369                *output = input[0];
370            else
371                *output = '\0';
372            return true;
373        }
374    };
[1625]375
[2171]376
377    // bool to std::string
378    template <>
379    struct ConverterExplicit<bool, std::string>
380    {
[3196]381        FORCEINLINE static bool convert(std::string* output, const bool& input)
[2171]382        {
383            if (input)
384              *output = "true";
385            else
386              *output = "false";
[2662]387            return true;
[2171]388        }
389    };
[1625]390
[2171]391    // std::string to bool
392    template <>
393    struct ConverterExplicit<std::string, bool>
394    {
395        static bool convert(bool* output, const std::string& input)
396        {
397            std::string stripped = getLowercase(removeTrailingWhitespaces(input));
398            if (stripped == "true" || stripped == "on" || stripped == "yes")
399            {
400              *output = true;
401              return true;
402            }
403            else if (stripped == "false" || stripped == "off" || stripped == "no")
404            {
405              *output = false;
406              return true;
407            }
408
409            std::istringstream iss(input);
410            if (iss >> (*output))
411                return true;
412            else
413                return false;
414        }
415    };
416}
417
[1052]418#endif /* _Convert_H__ */
Note: See TracBrowser for help on using the repository browser.