Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 8324 was 7401, checked in by landauf, 14 years ago

merged doc branch back to trunk

  • Property svn:eol-style set to native
File size: 15.2 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
[7401]30/**
31    @defgroup Convert Conversion functions
32    @ingroup Util
[1052]33*/
34
[7401]35/** Functions that convert values between different types.
36@file
37@ingroup Convert
38@par Usage
39    There are three ways to use the conversions depending on what you need. <br>
40    - For simply converting values without having to know whether the conversion
41      was successful (for instance float --> string), use orxonox::multi_cast
42      which effectively works exactly like static_cast, etc.
43      @code
44        float input = 42.0;
45        std::string output = multi_cast<std::string>(input);
46      @endcode
47    - If you care about whether the conversion was successful,
48      use orxonox::convertValue.
49      @code
50        std::string input("3.4");
51        float output;
52        bool success = convertValue(&output, input);
53      @endcode
54    - If you care about success and if you can also feed a fallback value,
55      use orxonox::convertValue.
56      @code
57        std::string input("3.4");
58        float output;
59        bool success = convertValue(&output, input, 0.0);
60      @endcode
61    - If success doesn't matter but you can feed a fallback value,
62      use orxonox::getConvertedValue.
63      @code
64        std::string input("3.4");
65        float output = getConvertedValue(input, 0.0);
66      @endcode
67@details
68    The back end of these functions are the actual implementations for the
69    specific conversions, for instance from Ogre::Vector3 to std::string and
70    vice versa. Some of them also use the iostream operators. <br>
71    The real deal is evaluating which function is needed for a conversion based
72    on the input and output type. But there are lots of catches in conjunction
73    with templates which explains why there are so many functions in this file.
74    <br> <br>
75@par Search Order
76    Finding the right function is governed by priority rules: <br>
77    -# (Partial) template specialisation of orxonox::ConverterExplicit::convert()
78    -# An implicit conversion. This includes 'FooBar' to 'int' if FooBar
79       defines operator int() or float().
80    -# Global or member operators for iostream when converting from or
81       to std::string (and FROM const char*)
82    -# (Partial) template specialisation of orxonox::ConverterFallback::convert()
83    -# Fallback function that displays "Could not convert value" with type
84       information obtained from typeid().
85@par Implementing conversion functions
86    To do that you probably need to know a thing or two about the types
87    involved. So, get ready with that. <br>
88    Usually the best way to do it is specialising of the orxonox::ConverterFallback
89    template, like this:
90    @code
91    template <>
92    struct _UtilExport ConverterFallback<std::string, MyType>
93    {
94        static bool convert(MyType* output, const std::string& input)
95        {
96           ...
97           return success;
98        }
99    };
100    @endcode
101    This piece of code converts an std::string to MyType and returns whether the
102    conversion was successful. You can also use partial specialisation.<br>
103    The advantage with orxonox::ConverterFallback is that it has a low priority
104    meaning that when there is an implicit conversion or an iostream method, that
105    comes first and you don't have to deal with it (and the accompanying
106    function call ambiguity). <br>
107    However sometimes you would like to explicitely replace such a conversion.
108    That's where orxonox::ConverterExplicit comes in handy (for instance we
109    replaced the operator << conversions for Ogre::VectorX with our own functions).
110@note
111    There has to be an exact type match when using template specialisations. <br>
112    Template specialisations can be defined after including this file.
113    But any implicit cast function or iostream operator has to be included
114    in this file!
115@par Understanding the Code
116    In order to understand how the templates work, it is probably best to study
117    the functions in order of calling. There are lots of comments explaining
118    what happens, but you'll need to understand a deal about partial template
119    specialisation and function headers are matched in C++.
120*/
121
[2087]122#ifndef _Converter_H__
123#define _Converter_H__
[1052]124
[1062]125#include "UtilPrereqs.h"
126
[1052]127#include <string>
128#include <sstream>
[1837]129#include <typeinfo>
[7266]130#include <loki/TypeManip.h>
[1052]131
[1747]132#include "Debug.h"
[7305]133#include "ImplicitConversion.h"
[1064]134
[2171]135namespace orxonox
[1505]136{
[2171]137    ///////////////////
138    // No Conversion //
139    ///////////////////
[1505]140
[7401]141    /// Default template. No conversion available at all.
[2171]142    template <class FromType, class ToType>
143    struct ConverterFallback
[1505]144    {
[3196]145        FORCEINLINE static bool convert(ToType* output, const FromType& input)
[2171]146        {
147            COUT(2) << "Could not convert value of type " << typeid(FromType).name()
148                    << " to type " << typeid(ToType).name() << std::endl;
149            return false;
150        }
151    };
[2087]152
[7401]153    /// If all else fails, try a dynamic_cast for pointer types.
[2171]154    template <class FromType, class ToType>
155    struct ConverterFallback<FromType*, ToType*>
[1505]156    {
[3196]157        FORCEINLINE static bool convert(ToType** output, FromType* const input)
[2087]158        {
[2171]159            ToType* temp = dynamic_cast<ToType*>(input);
160            if (temp)
161            {
162                *output = temp;
163                return true;
164            }
165            else
166                return false;
[2087]167        }
[2171]168    };
169}
[1505]170
171
[2087]172///////////////////////
173// ConverterFallback //
174///////////////////////
175
[7401]176/** Fallback template for stringstream
177@details
178    Neither FromType nor ToType was std::string, therefore
179    delegate to orxonox::ConverterFallback
180*/
[2087]181template <class FromType, class ToType>
182struct ConverterStringStream
[1505]183{
[3196]184    FORCEINLINE static bool convert(ToType* output, const FromType& input)
[1505]185    {
[2171]186        return orxonox::ConverterFallback<FromType, ToType>::convert(output, input);
[1505]187    }
188};
189
190
191/////////////
[2087]192// OStream //
[1505]193/////////////
194
[7401]195/// Extra namespace to avoid exposing the iostream operators in it
[2087]196namespace fallbackTemplates
[1505]197{
[7401]198    /// Fallback operator <<() (delegates to orxonox::ConverterFallback)
[2087]199    template <class FromType>
[3196]200    FORCEINLINE bool operator <<(std::ostream& outstream,  const FromType& input)
[2087]201    {
202        std::string temp;
[2171]203        if (orxonox::ConverterFallback<FromType, std::string>::convert(&temp, input))
[2087]204        {
205            std::operator <<(outstream, temp);
206            return true;
207        }
208        else
209            return false;
210    }
211}
[1505]212
[7401]213/// Template that evaluates whether we can convert to std::string via ostringstream
[1505]214template <class FromType>
[2087]215struct ConverterStringStream<FromType, std::string>
[1505]216{
[3196]217    FORCEINLINE static bool convert(std::string* output, const FromType& input)
[1505]218    {
[2087]219        using namespace fallbackTemplates;
[7401]220        // this operator call only chooses fallbackTemplates::operator<<()
221        // if there's no other fitting function
[1505]222        std::ostringstream oss;
[7401]223        // Note: std::ostream has operator!() to tell whether any error flag was set
[1505]224        if (oss << input)
225        {
226            (*output) = oss.str();
227            return true;
228        }
229        else
230            return false;
231    }
232};
233
[2087]234
235/////////////
236// IStream //
237/////////////
238
239namespace fallbackTemplates
[1625]240{
[7401]241    /// Fallback operator >>() (delegates to orxonox::ConverterFallback)
[2087]242    template <class ToType>
[3196]243    FORCEINLINE bool operator >>(std::istream& instream, ToType& output)
[2087]244    {
[7401]245        std::string input(static_cast<std::istringstream&>(instream).str());
246        return orxonox::ConverterFallback<std::string, ToType>::convert(&output, input);
[2087]247    }
[1625]248}
249
[7401]250/// Template that evaluates whether we can convert from std::string via istringstream
[1505]251template <class ToType>
[2087]252struct ConverterStringStream<std::string, ToType>
[1505]253{
[3196]254    FORCEINLINE static bool convert(ToType* output, const std::string& input)
[1505]255    {
[2087]256        using namespace fallbackTemplates;
[7401]257        // this operator call chooses fallbackTemplates::operator>>()
258        // only if there's no other fitting function
[1505]259        std::istringstream iss(input);
[7401]260        // Note: std::istream has operator!() to tell whether any error flag was set
[1505]261        if (iss >> (*output))
[2087]262        {
[1505]263            return true;
[2087]264        }
[1505]265        else
266            return false;
267    }
268};
269
[2171]270namespace orxonox
[1625]271{
[2171]272    ///////////////////
273    // Implicit Cast //
274    ///////////////////
[1625]275
[7401]276    /// %Template delegates to ::ConverterStringStream
[2171]277    template <class FromType, class ToType>
[7266]278    FORCEINLINE bool convertImplicitely(ToType* output, const FromType& input, Loki::Int2Type<false>)
[1505]279    {
[2171]280        return ConverterStringStream<FromType, ToType>::convert(output, input);
[1505]281    }
282
[7401]283    /// Makes an implicit cast from \a FromType to \a ToType
[2171]284    template <class FromType, class ToType>
[7266]285    FORCEINLINE bool convertImplicitely(ToType* output, const FromType& input, Loki::Int2Type<true>)
[2171]286    {
287        (*output) = static_cast<ToType>(input);
[2087]288        return true;
[1505]289    }
290
291
[2171]292    ////////////////////////////////
293    // ConverterExplicit Fallback //
294    ////////////////////////////////
[1505]295
[7401]296    /** Default template if no orxonox::ConverterExplicit is available
297    @details
298        Evaluates whether \a FromType can be implicitly converted to \a ToType
299        by the use the ImplicitConversion magic.
300    */
[2171]301    template <class FromType, class ToType>
302    struct ConverterExplicit
303    {
[3234]304        enum { probe = ImplicitConversion<FromType, ToType>::exists };
[3196]305        FORCEINLINE static bool convert(ToType* output, const FromType& input)
[2171]306        {
[7401]307            // Use the probe's value to delegate to the right function
[7266]308            return convertImplicitely(output, input, Loki::Int2Type<probe>());
[2171]309        }
310    };
[2087]311
312
[2171]313    //////////////////////
314    // Public Functions //
315    //////////////////////
[2087]316
[2171]317    /**
318    @brief
319        Converts any value to any other as long as there exists a conversion.
[7401]320    @details
[2171]321        Otherwise, the conversion will generate a runtime warning and return false.
[7401]322    @see Convert.h
323    @param output
324        A pointer to the variable where the converted value will be stored
325    @param input
326        The original value
[2171]327    */
328    template <class FromType, class ToType>
[3196]329    FORCEINLINE bool convertValue(ToType* output, const FromType& input)
[2171]330    {
331        return ConverterExplicit<FromType, ToType>::convert(output, input);
332    }
[2087]333
[2171]334    // Calls convertValue and returns true if the conversion was successful.
335    // Otherwise the fallback is used.
336    /**
337    @brief
338        Converts any value to any other as long as there exists a conversion.
339        Otherwise, the conversion will generate a runtime warning and return false.
[7401]340        If the conversion doesn't succeed, \a fallback is written to \a output.
341    @see Convert.h
342    @param output
343        A pointer to the variable where the converted value will be stored
344    @param input
345        The original value
[2171]346    @param fallback
347        A default value that gets written to '*output' if there is no conversion.
348    */
349    template<class FromType, class ToType>
[3196]350    FORCEINLINE bool convertValue(ToType* output, const FromType& input, const ToType& fallback)
[1625]351    {
[2171]352        if (convertValue(output, input))
353            return true;
354        else
355        {
356            (*output) = fallback;
357            return false;
358        }
[1625]359    }
360
[7401]361    /// Directly returns the converted value, but uses the fallback on failure. @see convertValue
[2171]362    template<class FromType, class ToType>
[3196]363    FORCEINLINE ToType getConvertedValue(const FromType& input, const ToType& fallback)
[1505]364    {
[2171]365        ToType output;
366        convertValue(&output, input, fallback);
367        return output;
[1505]368    }
[2171]369
[7401]370    /**
371    @brief
372        Converts any value to any other as long as there exists a conversion.
373    @details
374        Use exactly the way you use static_cast, etc. <br>
375        A failed conversion will return a default instance of \a ToType
376        (possibly uninitialised)
377    @see Convert.h
378    @param input
379        The original value
380    */
[2171]381    template<class ToType, class FromType>
[3196]382    FORCEINLINE ToType multi_cast(const FromType& input)
[1505]383    {
[2171]384        ToType output;
385        convertValue(&output, input);
386        return output;
[1505]387    }
388
[2171]389    ////////////////////////////////
390    // Special string conversions //
391    ////////////////////////////////
392
[7401]393    /// Delegates conversion from const char* to std::string
[2171]394    template <class ToType>
395    struct ConverterExplicit<const char*, ToType>
[1625]396    {
[3196]397        FORCEINLINE static bool convert(ToType* output, const char* input)
[1625]398        {
[2171]399            return convertValue<std::string, ToType>(output, input);
[1625]400        }
[2171]401    };
402
[7401]403    /// Conversion would exhibit ambiguous << or >> operators when using iostream
[2171]404    template <>
405    struct ConverterExplicit<char, std::string>
406    {
[3196]407        FORCEINLINE static bool convert(std::string* output, const char input)
[1625]408        {
[6417]409            *output = input;
[2171]410            return true;
[1625]411        }
[2171]412    };
[7401]413    /// Conversion would exhibit ambiguous << or >> operators when using iostream
[2171]414    template <>
415    struct ConverterExplicit<unsigned char, std::string>
416    {
[3196]417        FORCEINLINE static bool convert(std::string* output, const unsigned char input)
[2171]418        {
[6417]419            *output = input;
[2171]420            return true;
421        }
422    };
[7401]423    /// Conversion would exhibit ambiguous << or >> operators when using iostream
[2171]424    template <>
425    struct ConverterExplicit<std::string, char>
426    {
[6417]427        FORCEINLINE static bool convert(char* output, const std::string& input)
[2171]428        {
[6417]429            if (!input.empty())
[2171]430                *output = input[0];
431            else
432                *output = '\0';
433            return true;
434        }
435    };
[7401]436    /// Conversion would exhibit ambiguous << or >> operators when using iostream
[2171]437    template <>
438    struct ConverterExplicit<std::string, unsigned char>
439    {
[6417]440        FORCEINLINE static bool convert(unsigned char* output, const std::string& input)
[2171]441        {
[6417]442            if (!input.empty())
[2171]443                *output = input[0];
444            else
445                *output = '\0';
446            return true;
447        }
448    };
[1625]449
[2171]450
[7401]451    /// Conversion from bool to std::string
[2171]452    template <>
453    struct ConverterExplicit<bool, std::string>
454    {
[3196]455        FORCEINLINE static bool convert(std::string* output, const bool& input)
[2171]456        {
457            if (input)
458              *output = "true";
459            else
460              *output = "false";
[2662]461            return true;
[2171]462        }
463    };
[1625]464
[7401]465    /// Conversion from std::string to bool
[2171]466    template <>
[7163]467    struct _UtilExport ConverterExplicit<std::string, bool>
[2171]468    {
[7163]469        static bool convert(bool* output, const std::string& input);
[2171]470    };
471}
472
[1052]473#endif /* _Convert_H__ */
Note: See TracBrowser for help on using the repository browser.