Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/ai2/src/libraries/util/Convert.h @ 8721

Last change on this file since 8721 was 8706, checked in by dafrick, 13 years ago

Merging presentation branch back into trunk.
There are many new features and also a lot of other changes and bugfixes, if you want to know, digg through the svn log.
Not everything is yet working as it should, but it should be fairly stable. If you habe any bug reports, just send me an email.

  • Property svn:eol-style set to native
File size: 15.3 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    @defgroup Convert Conversion functions
32    @ingroup Util
33*/
34
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
122#ifndef _Converter_H__
123#define _Converter_H__
124
125#include "UtilPrereqs.h"
126
127#include <string>
128#include <sstream>
129#include <typeinfo>
130#include <loki/TypeManip.h>
131
132#include "Debug.h"
133#include "ImplicitConversion.h"
134
135namespace orxonox
136{
137    ///////////////////
138    // No Conversion //
139    ///////////////////
140
141    /// Default template. No conversion available at all.
142    template <class FromType, class ToType>
143    struct ConverterFallback
144    {
145        ORX_FORCEINLINE static bool convert(ToType* /*output*/, const FromType& /*input*/)
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    };
152
153    /// If all else fails, try a dynamic_cast for pointer types.
154    template <class FromType, class ToType>
155    struct ConverterFallback<FromType*, ToType*>
156    {
157        ORX_FORCEINLINE static bool convert(ToType** output, FromType* const input)
158        {
159            ToType* temp = dynamic_cast<ToType*>(input);
160            if (temp)
161            {
162                *output = temp;
163                return true;
164            }
165            else
166                return false;
167        }
168    };
169}
170
171
172///////////////////////
173// ConverterFallback //
174///////////////////////
175
176/** Fallback template for stringstream
177@details
178    Neither FromType nor ToType was std::string, therefore
179    delegate to orxonox::ConverterFallback
180*/
181template <class FromType, class ToType>
182struct ConverterStringStream
183{
184    ORX_FORCEINLINE static bool convert(ToType* output, const FromType& input)
185    {
186        return orxonox::ConverterFallback<FromType, ToType>::convert(output, input);
187    }
188};
189
190
191/////////////
192// OStream //
193/////////////
194
195/// Extra namespace to avoid exposing the iostream operators in it
196namespace fallbackTemplates
197{
198    /// Fallback operator <<() (delegates to orxonox::ConverterFallback)
199    template <class FromType>
200    ORX_FORCEINLINE bool operator <<(std::ostream& outstream,  const FromType& input)
201    {
202        std::string temp;
203        if (orxonox::ConverterFallback<FromType, std::string>::convert(&temp, input))
204        {
205            std::operator <<(outstream, temp);
206            return true;
207        }
208        else
209            return false;
210    }
211}
212
213/// Template that evaluates whether we can convert to std::string via ostringstream
214template <class FromType>
215struct ConverterStringStream<FromType, std::string>
216{
217    ORX_FORCEINLINE static bool convert(std::string* output, const FromType& input)
218    {
219        using namespace fallbackTemplates;
220        // this operator call only chooses fallbackTemplates::operator<<()
221        // if there's no other fitting function
222        std::ostringstream oss;
223        // Note: std::ostream has operator!() to tell whether any error flag was set
224        if (oss << input)
225        {
226            (*output) = oss.str();
227            return true;
228        }
229        else
230            return false;
231    }
232};
233
234
235/////////////
236// IStream //
237/////////////
238
239namespace fallbackTemplates
240{
241    /// Fallback operator >>() (delegates to orxonox::ConverterFallback)
242    template <class ToType>
243    ORX_FORCEINLINE bool operator >>(std::istream& instream, ToType& output)
244    {
245        std::string input(static_cast<std::istringstream&>(instream).str());
246        return orxonox::ConverterFallback<std::string, ToType>::convert(&output, input);
247    }
248}
249
250/// Template that evaluates whether we can convert from std::string via istringstream
251template <class ToType>
252struct ConverterStringStream<std::string, ToType>
253{
254    ORX_FORCEINLINE static bool convert(ToType* output, const std::string& input)
255    {
256        using namespace fallbackTemplates;
257        // this operator call chooses fallbackTemplates::operator>>()
258        // only if there's no other fitting function
259        std::istringstream iss(input);
260        // Note: std::istream has operator!() to tell whether any error flag was set
261        if (iss >> (*output))
262        {
263            return true;
264        }
265        else
266            return false;
267    }
268};
269
270namespace orxonox
271{
272    ///////////////////
273    // Implicit Cast //
274    ///////////////////
275
276    /// %Template delegates to ::ConverterStringStream
277    template <class FromType, class ToType>
278    ORX_FORCEINLINE bool convertImplicitely(ToType* output, const FromType& input, Loki::Int2Type<false>)
279    {
280        return ConverterStringStream<FromType, ToType>::convert(output, input);
281    }
282
283    /// Makes an implicit cast from \a FromType to \a ToType
284    template <class FromType, class ToType>
285    ORX_FORCEINLINE bool convertImplicitely(ToType* output, const FromType& input, Loki::Int2Type<true>)
286    {
287        (*output) = static_cast<ToType>(input);
288        return true;
289    }
290
291
292    ////////////////////////////////
293    // ConverterExplicit Fallback //
294    ////////////////////////////////
295
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    */
301    template <class FromType, class ToType>
302    struct ConverterExplicit
303    {
304        enum { probe = ImplicitConversion<FromType, ToType>::exists };
305        ORX_FORCEINLINE static bool convert(ToType* output, const FromType& input)
306        {
307            // Use the probe's value to delegate to the right function
308            return convertImplicitely(output, input, Loki::Int2Type<probe>());
309        }
310    };
311
312
313    //////////////////////
314    // Public Functions //
315    //////////////////////
316
317    /**
318    @brief
319        Converts any value to any other as long as there exists a conversion.
320    @details
321        Otherwise, the conversion will generate a runtime warning and return false.
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
327    */
328    template <class FromType, class ToType>
329    ORX_FORCEINLINE bool convertValue(ToType* output, const FromType& input)
330    {
331        return ConverterExplicit<FromType, ToType>::convert(output, input);
332    }
333
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.
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
346    @param fallback
347        A default value that gets written to '*output' if there is no conversion.
348    */
349    template<class FromType, class ToType>
350    ORX_FORCEINLINE bool convertValue(ToType* output, const FromType& input, const ToType& fallback)
351    {
352        if (convertValue(output, input))
353            return true;
354        else
355        {
356            (*output) = fallback;
357            return false;
358        }
359    }
360
361    /// Directly returns the converted value, but uses the fallback on failure. @see convertValue
362    template<class FromType, class ToType>
363    ORX_FORCEINLINE ToType getConvertedValue(const FromType& input, const ToType& fallback)
364    {
365        ToType output;
366        convertValue(&output, input, fallback);
367        return output;
368    }
369
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    */
381    template<class ToType, class FromType>
382    ORX_FORCEINLINE ToType multi_cast(const FromType& input)
383    {
384        ToType output;
385        convertValue(&output, input);
386        return output;
387    }
388
389    ////////////////////////////////
390    // Special string conversions //
391    ////////////////////////////////
392
393    /// Delegates conversion from const char* to std::string
394    template <class ToType>
395    struct ConverterExplicit<const char*, ToType>
396    {
397        ORX_FORCEINLINE static bool convert(ToType* output, const char* input)
398        {
399            return convertValue<std::string, ToType>(output, input);
400        }
401    };
402
403    /// Conversion would exhibit ambiguous << or >> operators when using iostream
404    template <>
405    struct ConverterExplicit<char, std::string>
406    {
407        ORX_FORCEINLINE static bool convert(std::string* output, const char input)
408        {
409            *output = input;
410            return true;
411        }
412    };
413    /// Conversion would exhibit ambiguous << or >> operators when using iostream
414    template <>
415    struct ConverterExplicit<unsigned char, std::string>
416    {
417        ORX_FORCEINLINE static bool convert(std::string* output, const unsigned char input)
418        {
419            *output = input;
420            return true;
421        }
422    };
423    /// Conversion would exhibit ambiguous << or >> operators when using iostream
424    template <>
425    struct ConverterExplicit<std::string, char>
426    {
427        ORX_FORCEINLINE static bool convert(char* output, const std::string& input)
428        {
429            if (!input.empty())
430                *output = input[0];
431            else
432                *output = '\0';
433            return true;
434        }
435    };
436    /// Conversion would exhibit ambiguous << or >> operators when using iostream
437    template <>
438    struct ConverterExplicit<std::string, unsigned char>
439    {
440        ORX_FORCEINLINE static bool convert(unsigned char* output, const std::string& input)
441        {
442            if (!input.empty())
443                *output = input[0];
444            else
445                *output = '\0';
446            return true;
447        }
448    };
449
450
451    /// Conversion from bool to std::string
452    template <>
453    struct ConverterExplicit<bool, std::string>
454    {
455        ORX_FORCEINLINE static bool convert(std::string* output, const bool& input)
456        {
457            if (input)
458              *output = "true";
459            else
460              *output = "false";
461            return true;
462        }
463    };
464
465    /// Conversion from std::string to bool
466    template <>
467    struct _UtilExport ConverterExplicit<std::string, bool>
468    {
469        static bool convert(bool* output, const std::string& input);
470    };
471}
472
473#endif /* _Convert_H__ */
Note: See TracBrowser for help on using the repository browser.