Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

merged consolecommands3 branch back to trunk.

note: the console command interface has changed completely, but the documentation is not yet up to date. just copy an existing command and change it to your needs, it's pretty self-explanatory. also the include files related to console commands are now located in core/command/. in the game it should work exactly like before, except for some changes in the auto-completion.

  • Property svn:eol-style set to native
File size: 12.8 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    */
281    template <class FromType, class ToType>
282    FORCEINLINE bool convertValue(ToType* output, const FromType& input)
283    {
284        return ConverterExplicit<FromType, ToType>::convert(output, input);
285    }
286
287    // Calls convertValue and returns true if the conversion was successful.
288    // Otherwise the fallback is used.
289    /**
290    @brief
291        Converts any value to any other as long as there exists a conversion.
292        Otherwise, the conversion will generate a runtime warning and return false.
293        For information about the different conversion methods (user defined too), see the section
294        'Actual conversion sequence' in this file above.
295        If the conversion doesn't succeed, 'fallback' is written to '*output'.
296    @param fallback
297        A default value that gets written to '*output' if there is no conversion.
298    */
299    template<class FromType, class ToType>
300    FORCEINLINE bool convertValue(ToType* output, const FromType& input, const ToType& fallback)
301    {
302        if (convertValue(output, input))
303            return true;
304        else
305        {
306            (*output) = fallback;
307            return false;
308        }
309    }
310
311    // Directly returns the converted value, even if the conversion was not successful.
312    template<class FromType, class ToType>
313    FORCEINLINE ToType getConvertedValue(const FromType& input)
314    {
315        ToType output;
316        convertValue(&output, input);
317        return output;
318    }
319
320    // Directly returns the converted value, but uses the fallback on failure.
321    template<class FromType, class ToType>
322    FORCEINLINE ToType getConvertedValue(const FromType& input, const ToType& fallback)
323    {
324        ToType output;
325        convertValue(&output, input, fallback);
326        return output;
327    }
328
329    // Like getConvertedValue, but the template argument order is in reverse.
330    // That means you can call it exactly like static_cast<ToType>(fromTypeValue).
331    template<class ToType, class FromType>
332    FORCEINLINE ToType multi_cast(const FromType& input)
333    {
334        ToType output;
335        convertValue(&output, input);
336        return output;
337    }
338
339    ////////////////////////////////
340    // Special string conversions //
341    ////////////////////////////////
342
343    // Delegate conversion from const char* to std::string
344    template <class ToType>
345    struct ConverterExplicit<const char*, ToType>
346    {
347        FORCEINLINE static bool convert(ToType* output, const char* input)
348        {
349            return convertValue<std::string, ToType>(output, input);
350        }
351    };
352
353    // These conversions would exhibit ambiguous << or >> operators when using stringstream
354    template <>
355    struct ConverterExplicit<char, std::string>
356    {
357        FORCEINLINE static bool convert(std::string* output, const char input)
358        {
359            *output = input;
360            return true;
361        }
362    };
363    template <>
364    struct ConverterExplicit<unsigned char, std::string>
365    {
366        FORCEINLINE static bool convert(std::string* output, const unsigned char input)
367        {
368            *output = input;
369            return true;
370        }
371    };
372    template <>
373    struct ConverterExplicit<std::string, char>
374    {
375        FORCEINLINE static bool convert(char* output, const std::string& input)
376        {
377            if (!input.empty())
378                *output = input[0];
379            else
380                *output = '\0';
381            return true;
382        }
383    };
384    template <>
385    struct ConverterExplicit<std::string, unsigned char>
386    {
387        FORCEINLINE static bool convert(unsigned char* output, const std::string& input)
388        {
389            if (!input.empty())
390                *output = input[0];
391            else
392                *output = '\0';
393            return true;
394        }
395    };
396
397
398    // bool to std::string
399    template <>
400    struct ConverterExplicit<bool, std::string>
401    {
402        FORCEINLINE static bool convert(std::string* output, const bool& input)
403        {
404            if (input)
405              *output = "true";
406            else
407              *output = "false";
408            return true;
409        }
410    };
411
412    // std::string to bool
413    template <>
414    struct _UtilExport ConverterExplicit<std::string, bool>
415    {
416        static bool convert(bool* output, const std::string& input);
417    };
418}
419
420#endif /* _Convert_H__ */
Note: See TracBrowser for help on using the repository browser.