Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 7331 was 7297, checked in by landauf, 14 years ago

fixed lots of Doxygen warnings

Note: Doxygen prints a warning if only a part of the parameters of a function are documented.

Added documentation for missing parameters (as good as I could), removed documentation of obsolete parameters and fixed names of renamed parameters.
Some parameters are tagged with "FIXME", please replace this with an appropriate documentation if you know what it does.

  • Property svn:eol-style set to native
File size: 13.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/*!
31    @file
32    @brief Definition and Implementation of the Convert class.
33*/
34
35#ifndef _Converter_H__
36#define _Converter_H__
37
38#include "UtilPrereqs.h"
39
40#include <string>
41#include <sstream>
42#include <typeinfo>
43#include <loki/TypeManip.h>
44
45#include "Debug.h"
46#include "TemplateUtils.h"
47
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().
60
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.
65
66    Defining your own functions:
67    There are obviously 4 ways to specify a user defined conversion. What should you use?
68
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.
71
72    However if you want to overwrite an implicit conversion or an iostream operator, you really need to
73    make use of ConverterExplicit. We have to do this for the Ogre classes for instance because they
74    define stream operators we don't particulary like.
75*/
76
77namespace orxonox
78{
79    ///////////////////
80    // No Conversion //
81    ///////////////////
82
83    // Default template. No conversion available at all.
84    template <class FromType, class ToType>
85    struct ConverterFallback
86    {
87        FORCEINLINE static bool convert(ToType* output, const FromType& input)
88        {
89            COUT(2) << "Could not convert value of type " << typeid(FromType).name()
90                    << " to type " << typeid(ToType).name() << std::endl;
91            return false;
92        }
93    };
94
95    // If all else fails, try a dynamic_cast for pointer types.
96    template <class FromType, class ToType>
97    struct ConverterFallback<FromType*, ToType*>
98    {
99        FORCEINLINE static bool convert(ToType** output, FromType* const input)
100        {
101            ToType* temp = dynamic_cast<ToType*>(input);
102            if (temp)
103            {
104                *output = temp;
105                return true;
106            }
107            else
108                return false;
109        }
110    };
111
112    ////////////
113    // upcast //
114    ////////////
115    namespace detail
116    {
117        // perform a static cast if ToType is a base of FromType
118        template<class ToType, class FromType>
119        FORCEINLINE ToType upcast(FromType input, Loki::Int2Type<true>)
120        {
121            return static_cast<ToType>(input);
122        }
123
124        // return zero if ToType is not a base of FromType
125        template<class ToType, class FromType>
126        FORCEINLINE ToType upcast(FromType input, Loki::Int2Type<false>)
127        {
128            return 0;
129        }
130    }
131
132    // performs an upcast if ToType is a base of FromType, returns zero otherwise
133    template <class ToType, class FromType>
134    FORCEINLINE ToType upcast(FromType input)
135    {
136        enum { probe = ImplicitConversion<FromType, ToType>::exists };
137        return detail::upcast<ToType, FromType>(input, Loki::Int2Type<probe>());
138    }
139}
140
141
142///////////////////////
143// ConverterFallback //
144///////////////////////
145
146// Default template for stringstream
147template <class FromType, class ToType>
148struct ConverterStringStream
149{
150    FORCEINLINE static bool convert(ToType* output, const FromType& input)
151    {
152        return orxonox::ConverterFallback<FromType, ToType>::convert(output, input);
153    }
154};
155
156
157/////////////
158// OStream //
159/////////////
160
161namespace fallbackTemplates
162{
163    template <class FromType>
164    FORCEINLINE bool operator <<(std::ostream& outstream,  const FromType& input)
165    {
166        std::string temp;
167        if (orxonox::ConverterFallback<FromType, std::string>::convert(&temp, input))
168        {
169            std::operator <<(outstream, temp);
170            return true;
171        }
172        else
173            return false;
174    }
175}
176
177// template that evaluates whether we can convert to std::string via ostringstream
178template <class FromType>
179struct ConverterStringStream<FromType, std::string>
180{
181    FORCEINLINE static bool convert(std::string* output, const FromType& input)
182    {
183        using namespace fallbackTemplates;
184        // this operator call only chooses fallbackTemplates::operator<< if there's no other fitting function
185        std::ostringstream oss;
186        if (oss << input)
187        {
188            (*output) = oss.str();
189            return true;
190        }
191        else
192            return false;
193    }
194};
195
196
197/////////////
198// IStream //
199/////////////
200
201namespace fallbackTemplates
202{
203    template <class ToType>
204    FORCEINLINE bool operator >>(std::istream& instream, ToType& output)
205    {
206        return orxonox::ConverterFallback<std::string, ToType>
207            ::convert(&output, static_cast<std::istringstream&>(instream).str());
208    }
209}
210
211// template that evaluates whether we can convert from std::string via ostringstream
212template <class ToType>
213struct ConverterStringStream<std::string, ToType>
214{
215    FORCEINLINE static bool convert(ToType* output, const std::string& input)
216    {
217        using namespace fallbackTemplates;
218        std::istringstream iss(input);
219        // this operator call only chooses fallbackTemplates::operator>> if there's no other fitting function
220        if (iss >> (*output))
221        {
222            return true;
223        }
224        else
225            return false;
226    }
227};
228
229namespace orxonox
230{
231
232    ///////////////////
233    // Implicit Cast //
234    ///////////////////
235
236    // implicit cast not possible, try stringstream conversion next
237    template <class FromType, class ToType>
238    FORCEINLINE bool convertImplicitely(ToType* output, const FromType& input, Loki::Int2Type<false>)
239    {
240        return ConverterStringStream<FromType, ToType>::convert(output, input);
241    }
242
243    // We can cast implicitely
244    template <class FromType, class ToType>
245    FORCEINLINE bool convertImplicitely(ToType* output, const FromType& input, Loki::Int2Type<true>)
246    {
247        (*output) = static_cast<ToType>(input);
248        return true;
249    }
250
251
252    ////////////////////////////////
253    // ConverterExplicit Fallback //
254    ////////////////////////////////
255
256    // Default template if no specialisation is available
257    template <class FromType, class ToType>
258    struct ConverterExplicit
259    {
260        enum { probe = ImplicitConversion<FromType, ToType>::exists };
261        FORCEINLINE static bool convert(ToType* output, const FromType& input)
262        {
263            // Try implict cast and probe first. If a simple cast is not possible, it will not compile
264            // We therefore have to out source it into another template function
265            return convertImplicitely(output, input, Loki::Int2Type<probe>());
266        }
267    };
268
269
270    //////////////////////
271    // Public Functions //
272    //////////////////////
273
274    /**
275    @brief
276        Converts any value to any other as long as there exists a conversion.
277        Otherwise, the conversion will generate a runtime warning and return false.
278        For information about the different conversion methods (user defined too), see the section
279        'Actual conversion sequence' in this file above.
280    @param output
281        A pointer to the variable where the converted value will be stored
282    @param input
283        The original value
284    */
285    template <class FromType, class ToType>
286    FORCEINLINE bool convertValue(ToType* output, const FromType& input)
287    {
288        return ConverterExplicit<FromType, ToType>::convert(output, input);
289    }
290
291    // Calls convertValue and returns true if the conversion was successful.
292    // Otherwise the fallback is used.
293    /**
294    @brief
295        Converts any value to any other as long as there exists a conversion.
296        Otherwise, the conversion will generate a runtime warning and return false.
297        For information about the different conversion methods (user defined too), see the section
298        'Actual conversion sequence' in this file above.
299        If the conversion doesn't succeed, 'fallback' is written to '*output'.
300    @param output
301        A pointer to the variable where the converted value will be stored
302    @param input
303        The original value
304    @param fallback
305        A default value that gets written to '*output' if there is no conversion.
306    */
307    template<class FromType, class ToType>
308    FORCEINLINE bool convertValue(ToType* output, const FromType& input, const ToType& fallback)
309    {
310        if (convertValue(output, input))
311            return true;
312        else
313        {
314            (*output) = fallback;
315            return false;
316        }
317    }
318
319    // Directly returns the converted value, even if the conversion was not successful.
320    template<class FromType, class ToType>
321    FORCEINLINE ToType getConvertedValue(const FromType& input)
322    {
323        ToType output;
324        convertValue(&output, input);
325        return output;
326    }
327
328    // Directly returns the converted value, but uses the fallback on failure.
329    template<class FromType, class ToType>
330    FORCEINLINE ToType getConvertedValue(const FromType& input, const ToType& fallback)
331    {
332        ToType output;
333        convertValue(&output, input, fallback);
334        return output;
335    }
336
337    // Like getConvertedValue, but the template argument order is in reverse.
338    // That means you can call it exactly like static_cast<ToType>(fromTypeValue).
339    template<class ToType, class FromType>
340    FORCEINLINE ToType multi_cast(const FromType& input)
341    {
342        ToType output;
343        convertValue(&output, input);
344        return output;
345    }
346
347    ////////////////////////////////
348    // Special string conversions //
349    ////////////////////////////////
350
351    // Delegate conversion from const char* to std::string
352    template <class ToType>
353    struct ConverterExplicit<const char*, ToType>
354    {
355        FORCEINLINE static bool convert(ToType* output, const char* input)
356        {
357            return convertValue<std::string, ToType>(output, input);
358        }
359    };
360
361    // These conversions would exhibit ambiguous << or >> operators when using stringstream
362    template <>
363    struct ConverterExplicit<char, std::string>
364    {
365        FORCEINLINE static bool convert(std::string* output, const char input)
366        {
367            *output = input;
368            return true;
369        }
370    };
371    template <>
372    struct ConverterExplicit<unsigned char, std::string>
373    {
374        FORCEINLINE static bool convert(std::string* output, const unsigned char input)
375        {
376            *output = input;
377            return true;
378        }
379    };
380    template <>
381    struct ConverterExplicit<std::string, char>
382    {
383        FORCEINLINE static bool convert(char* output, const std::string& input)
384        {
385            if (!input.empty())
386                *output = input[0];
387            else
388                *output = '\0';
389            return true;
390        }
391    };
392    template <>
393    struct ConverterExplicit<std::string, unsigned char>
394    {
395        FORCEINLINE static bool convert(unsigned char* output, const std::string& input)
396        {
397            if (!input.empty())
398                *output = input[0];
399            else
400                *output = '\0';
401            return true;
402        }
403    };
404
405
406    // bool to std::string
407    template <>
408    struct ConverterExplicit<bool, std::string>
409    {
410        FORCEINLINE static bool convert(std::string* output, const bool& input)
411        {
412            if (input)
413              *output = "true";
414            else
415              *output = "false";
416            return true;
417        }
418    };
419
420    // std::string to bool
421    template <>
422    struct _UtilExport ConverterExplicit<std::string, bool>
423    {
424        static bool convert(bool* output, const std::string& input);
425    };
426}
427
428#endif /* _Convert_H__ */
Note: See TracBrowser for help on using the repository browser.