Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/doc/src/libraries/util/Convert.h @ 7365

Last change on this file since 7365 was 7365, checked in by rgrieder, 14 years ago

Removed obsolete code from Convert.h and replaced last occurrences of getConvertedValue with just two arguments.

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