Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

Elaborated documentation for util/Convert.

  • Property svn:eol-style set to native
File size: 16.2 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    // upcast //
166    ////////////
167    namespace detail
168    {
169        // perform a static cast if ToType is a base of FromType
170        template<class ToType, class FromType>
171        FORCEINLINE ToType upcast(FromType input, Loki::Int2Type<true>)
172        {
173            return static_cast<ToType>(input);
174        }
175
176        // return zero if ToType is not a base of FromType
177        template<class ToType, class FromType>
178        FORCEINLINE ToType upcast(FromType input, Loki::Int2Type<false>)
179        {
180            return 0;
181        }
182    }
183
184    // performs an upcast if ToType is a base of FromType, returns zero otherwise
185    template <class ToType, class FromType>
186    FORCEINLINE ToType upcast(FromType input)
187    {
188        enum { probe = ImplicitConversion<FromType, ToType>::exists };
189        return detail::upcast<ToType, FromType>(input, Loki::Int2Type<probe>());
190    }
191}
192
193
194///////////////////////
195// ConverterFallback //
196///////////////////////
197
198/** Fallback template for stringstream
199@details
200    Neither FromType nor ToType was std::string, therefore
201    delegate to orxonox::ConverterFallback
202*/
203template <class FromType, class ToType>
204struct ConverterStringStream
205{
206    FORCEINLINE static bool convert(ToType* output, const FromType& input)
207    {
208        return orxonox::ConverterFallback<FromType, ToType>::convert(output, input);
209    }
210};
211
212
213/////////////
214// OStream //
215/////////////
216
217/// Extra namespace to avoid exposing the iostream operators in it
218namespace fallbackTemplates
219{
220    /// Fallback operator <<() (delegates to orxonox::ConverterFallback)
221    template <class FromType>
222    FORCEINLINE bool operator <<(std::ostream& outstream,  const FromType& input)
223    {
224        std::string temp;
225        if (orxonox::ConverterFallback<FromType, std::string>::convert(&temp, input))
226        {
227            std::operator <<(outstream, temp);
228            return true;
229        }
230        else
231            return false;
232    }
233}
234
235/// Template that evaluates whether we can convert to std::string via ostringstream
236template <class FromType>
237struct ConverterStringStream<FromType, std::string>
238{
239    FORCEINLINE static bool convert(std::string* output, const FromType& input)
240    {
241        using namespace fallbackTemplates;
242        // this operator call only chooses fallbackTemplates::operator<<()
243        // if there's no other fitting function
244        std::ostringstream oss;
245        // Note: std::ostream has operator!() to tell whether any error flag was set
246        if (oss << input)
247        {
248            (*output) = oss.str();
249            return true;
250        }
251        else
252            return false;
253    }
254};
255
256
257/////////////
258// IStream //
259/////////////
260
261namespace fallbackTemplates
262{
263    /// Fallback operator >>() (delegates to orxonox::ConverterFallback)
264    template <class ToType>
265    FORCEINLINE bool operator >>(std::istream& instream, ToType& output)
266    {
267        std::string input(static_cast<std::istringstream&>(instream).str());
268        return orxonox::ConverterFallback<std::string, ToType>::convert(&output, input);
269    }
270}
271
272/// Template that evaluates whether we can convert from std::string via istringstream
273template <class ToType>
274struct ConverterStringStream<std::string, ToType>
275{
276    FORCEINLINE static bool convert(ToType* output, const std::string& input)
277    {
278        using namespace fallbackTemplates;
279        // this operator call chooses fallbackTemplates::operator>>()
280        // only if there's no other fitting function
281        std::istringstream iss(input);
282        // Note: std::istream has operator!() to tell whether any error flag was set
283        if (iss >> (*output))
284        {
285            return true;
286        }
287        else
288            return false;
289    }
290};
291
292namespace orxonox
293{
294    ///////////////////
295    // Implicit Cast //
296    ///////////////////
297
298    /// %Template delegates to ::ConverterStringStream
299    template <class FromType, class ToType>
300    FORCEINLINE bool convertImplicitely(ToType* output, const FromType& input, Loki::Int2Type<false>)
301    {
302        return ConverterStringStream<FromType, ToType>::convert(output, input);
303    }
304
305    /// Makes an implicit cast from \a FromType to \a ToType
306    template <class FromType, class ToType>
307    FORCEINLINE bool convertImplicitely(ToType* output, const FromType& input, Loki::Int2Type<true>)
308    {
309        (*output) = static_cast<ToType>(input);
310        return true;
311    }
312
313
314    ////////////////////////////////
315    // ConverterExplicit Fallback //
316    ////////////////////////////////
317
318    /** Default template if no orxonox::ConverterExplicit is available
319    @details
320        Evaluates whether \a FromType can be implicitly converted to \a ToType
321        by the use the ImplicitConversion magic.
322    */
323    template <class FromType, class ToType>
324    struct ConverterExplicit
325    {
326        enum { probe = ImplicitConversion<FromType, ToType>::exists };
327        FORCEINLINE static bool convert(ToType* output, const FromType& input)
328        {
329            // Use the probe's value to delegate to the right function
330            return convertImplicitely(output, input, Loki::Int2Type<probe>());
331        }
332    };
333
334
335    //////////////////////
336    // Public Functions //
337    //////////////////////
338
339    /**
340    @brief
341        Converts any value to any other as long as there exists a conversion.
342    @details
343        Otherwise, the conversion will generate a runtime warning and return false.
344    @see Convert.h
345    @param output
346        A pointer to the variable where the converted value will be stored
347    @param input
348        The original value
349    */
350    template <class FromType, class ToType>
351    FORCEINLINE bool convertValue(ToType* output, const FromType& input)
352    {
353        return ConverterExplicit<FromType, ToType>::convert(output, input);
354    }
355
356    // Calls convertValue and returns true if the conversion was successful.
357    // Otherwise the fallback is used.
358    /**
359    @brief
360        Converts any value to any other as long as there exists a conversion.
361        Otherwise, the conversion will generate a runtime warning and return false.
362        If the conversion doesn't succeed, \a fallback is written to \a output.
363    @see Convert.h
364    @param output
365        A pointer to the variable where the converted value will be stored
366    @param input
367        The original value
368    @param fallback
369        A default value that gets written to '*output' if there is no conversion.
370    */
371    template<class FromType, class ToType>
372    FORCEINLINE bool convertValue(ToType* output, const FromType& input, const ToType& fallback)
373    {
374        if (convertValue(output, input))
375            return true;
376        else
377        {
378            (*output) = fallback;
379            return false;
380        }
381    }
382
383    template<class FromType, class ToType>
384    FORCEINLINE ToType getConvertedValue(const FromType& input)
385    {
386        ToType output;
387        convertValue(&output, input);
388        return output;
389    }
390
391    /// Directly returns the converted value, but uses the fallback on failure. @see convertValue
392    template<class FromType, class ToType>
393    FORCEINLINE ToType getConvertedValue(const FromType& input, const ToType& fallback)
394    {
395        ToType output;
396        convertValue(&output, input, fallback);
397        return output;
398    }
399
400    /**
401    @brief
402        Converts any value to any other as long as there exists a conversion.
403    @details
404        Use exactly the way you use static_cast, etc. <br>
405        A failed conversion will return a default instance of \a ToType
406        (possibly uninitialised)
407    @see Convert.h
408    @param input
409        The original value
410    */
411    template<class ToType, class FromType>
412    FORCEINLINE ToType multi_cast(const FromType& input)
413    {
414        ToType output;
415        convertValue(&output, input);
416        return output;
417    }
418
419    ////////////////////////////////
420    // Special string conversions //
421    ////////////////////////////////
422
423    /// Delegates conversion from const char* to std::string
424    template <class ToType>
425    struct ConverterExplicit<const char*, ToType>
426    {
427        FORCEINLINE static bool convert(ToType* output, const char* input)
428        {
429            return convertValue<std::string, ToType>(output, input);
430        }
431    };
432
433    /// Conversion would exhibit ambiguous << or >> operators when using iostream
434    template <>
435    struct ConverterExplicit<char, std::string>
436    {
437        FORCEINLINE static bool convert(std::string* output, const char input)
438        {
439            *output = input;
440            return true;
441        }
442    };
443    /// Conversion would exhibit ambiguous << or >> operators when using iostream
444    template <>
445    template <>
446    struct ConverterExplicit<unsigned char, std::string>
447    {
448        FORCEINLINE static bool convert(std::string* output, const unsigned char input)
449        {
450            *output = input;
451            return true;
452        }
453    };
454    /// Conversion would exhibit ambiguous << or >> operators when using iostream
455    template <>
456    template <>
457    struct ConverterExplicit<std::string, char>
458    {
459        FORCEINLINE static bool convert(char* output, const std::string& input)
460        {
461            if (!input.empty())
462                *output = input[0];
463            else
464                *output = '\0';
465            return true;
466        }
467    };
468    /// Conversion would exhibit ambiguous << or >> operators when using iostream
469    template <>
470    struct ConverterExplicit<std::string, unsigned char>
471    {
472        FORCEINLINE static bool convert(unsigned char* output, const std::string& input)
473        {
474            if (!input.empty())
475                *output = input[0];
476            else
477                *output = '\0';
478            return true;
479        }
480    };
481
482
483    /// Conversion from bool to std::string
484    template <>
485    struct ConverterExplicit<bool, std::string>
486    {
487        FORCEINLINE static bool convert(std::string* output, const bool& input)
488        {
489            if (input)
490              *output = "true";
491            else
492              *output = "false";
493            return true;
494        }
495    };
496
497    /// Conversion from std::string to bool
498    template <>
499    struct _UtilExport ConverterExplicit<std::string, bool>
500    {
501        static bool convert(bool* output, const std::string& input);
502    };
503}
504
505#endif /* _Convert_H__ */
Note: See TracBrowser for help on using the repository browser.