Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

Moved Loki library files to separate loki folder in externals.
Also added TypeManip.h (now used in Convert.h) and static_check.h.

  • Property svn:eol-style set to native
File size: 11.9 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
114///////////////////////
115// ConverterFallback //
116///////////////////////
117
118// Default template for stringstream
119template <class FromType, class ToType>
120struct ConverterStringStream
121{
122    FORCEINLINE static bool convert(ToType* output, const FromType& input)
123    {
124        return orxonox::ConverterFallback<FromType, ToType>::convert(output, input);
125    }
126};
127
128
129/////////////
130// OStream //
131/////////////
132
133namespace fallbackTemplates
134{
135    template <class FromType>
136    FORCEINLINE bool operator <<(std::ostream& outstream,  const FromType& input)
137    {
138        std::string temp;
139        if (orxonox::ConverterFallback<FromType, std::string>::convert(&temp, input))
140        {
141            std::operator <<(outstream, temp);
142            return true;
143        }
144        else
145            return false;
146    }
147}
148
149// template that evaluates whether we can convert to std::string via ostringstream
150template <class FromType>
151struct ConverterStringStream<FromType, std::string>
152{
153    FORCEINLINE static bool convert(std::string* output, const FromType& input)
154    {
155        using namespace fallbackTemplates;
156        // this operator call only chooses fallbackTemplates::operator<< if there's no other fitting function
157        std::ostringstream oss;
158        if (oss << input)
159        {
160            (*output) = oss.str();
161            return true;
162        }
163        else
164            return false;
165    }
166};
167
168
169/////////////
170// IStream //
171/////////////
172
173namespace fallbackTemplates
174{
175    template <class ToType>
176    FORCEINLINE bool operator >>(std::istream& instream, ToType& output)
177    {
178        return orxonox::ConverterFallback<std::string, ToType>
179            ::convert(&output, static_cast<std::istringstream&>(instream).str());
180    }
181}
182
183// template that evaluates whether we can convert from std::string via ostringstream
184template <class ToType>
185struct ConverterStringStream<std::string, ToType>
186{
187    FORCEINLINE static bool convert(ToType* output, const std::string& input)
188    {
189        using namespace fallbackTemplates;
190        std::istringstream iss(input);
191        // this operator call only chooses fallbackTemplates::operator>> if there's no other fitting function
192        if (iss >> (*output))
193        {
194            return true;
195        }
196        else
197            return false;
198    }
199};
200
201namespace orxonox
202{
203
204    ///////////////////
205    // Implicit Cast //
206    ///////////////////
207
208    // implicit cast not possible, try stringstream conversion next
209    template <class FromType, class ToType>
210    FORCEINLINE bool convertImplicitely(ToType* output, const FromType& input, Loki::Int2Type<false>)
211    {
212        return ConverterStringStream<FromType, ToType>::convert(output, input);
213    }
214
215    // We can cast implicitely
216    template <class FromType, class ToType>
217    FORCEINLINE bool convertImplicitely(ToType* output, const FromType& input, Loki::Int2Type<true>)
218    {
219        (*output) = static_cast<ToType>(input);
220        return true;
221    }
222
223
224    ////////////////////////////////
225    // ConverterExplicit Fallback //
226    ////////////////////////////////
227
228    // Default template if no specialisation is available
229    template <class FromType, class ToType>
230    struct ConverterExplicit
231    {
232        enum { probe = ImplicitConversion<FromType, ToType>::exists };
233        FORCEINLINE static bool convert(ToType* output, const FromType& input)
234        {
235            // Try implict cast and probe first. If a simple cast is not possible, it will not compile
236            // We therefore have to out source it into another template function
237            return convertImplicitely(output, input, Loki::Int2Type<probe>());
238        }
239    };
240
241
242    //////////////////////
243    // Public Functions //
244    //////////////////////
245
246    /**
247    @brief
248        Converts any value to any other as long as there exists a conversion.
249        Otherwise, the conversion will generate a runtime warning and return false.
250        For information about the different conversion methods (user defined too), see the section
251        'Actual conversion sequence' in this file above.
252    */
253    template <class FromType, class ToType>
254    FORCEINLINE bool convertValue(ToType* output, const FromType& input)
255    {
256        return ConverterExplicit<FromType, ToType>::convert(output, input);
257    }
258
259    // Calls convertValue and returns true if the conversion was successful.
260    // Otherwise the fallback is used.
261    /**
262    @brief
263        Converts any value to any other as long as there exists a conversion.
264        Otherwise, the conversion will generate a runtime warning and return false.
265        For information about the different conversion methods (user defined too), see the section
266        'Actual conversion sequence' in this file above.
267        If the conversion doesn't succeed, 'fallback' is written to '*output'.
268    @param fallback
269        A default value that gets written to '*output' if there is no conversion.
270    */
271    template<class FromType, class ToType>
272    FORCEINLINE bool convertValue(ToType* output, const FromType& input, const ToType& fallback)
273    {
274        if (convertValue(output, input))
275            return true;
276        else
277        {
278            (*output) = fallback;
279            return false;
280        }
281    }
282
283    // Directly returns the converted value, even if the conversion was not successful.
284    template<class FromType, class ToType>
285    FORCEINLINE ToType getConvertedValue(const FromType& input)
286    {
287        ToType output;
288        convertValue(&output, input);
289        return output;
290    }
291
292    // Directly returns the converted value, but uses the fallback on failure.
293    template<class FromType, class ToType>
294    FORCEINLINE ToType getConvertedValue(const FromType& input, const ToType& fallback)
295    {
296        ToType output;
297        convertValue(&output, input, fallback);
298        return output;
299    }
300
301    // Like getConvertedValue, but the template argument order is in reverse.
302    // That means you can call it exactly like static_cast<ToType>(fromTypeValue).
303    template<class ToType, class FromType>
304    FORCEINLINE ToType multi_cast(const FromType& input)
305    {
306        ToType output;
307        convertValue(&output, input);
308        return output;
309    }
310
311    ////////////////////////////////
312    // Special string conversions //
313    ////////////////////////////////
314
315    // Delegate conversion from const char* to std::string
316    template <class ToType>
317    struct ConverterExplicit<const char*, ToType>
318    {
319        FORCEINLINE static bool convert(ToType* output, const char* input)
320        {
321            return convertValue<std::string, ToType>(output, input);
322        }
323    };
324
325    // These conversions would exhibit ambiguous << or >> operators when using stringstream
326    template <>
327    struct ConverterExplicit<char, std::string>
328    {
329        FORCEINLINE static bool convert(std::string* output, const char input)
330        {
331            *output = input;
332            return true;
333        }
334    };
335    template <>
336    struct ConverterExplicit<unsigned char, std::string>
337    {
338        FORCEINLINE static bool convert(std::string* output, const unsigned char input)
339        {
340            *output = input;
341            return true;
342        }
343    };
344    template <>
345    struct ConverterExplicit<std::string, char>
346    {
347        FORCEINLINE static bool convert(char* output, const std::string& input)
348        {
349            if (!input.empty())
350                *output = input[0];
351            else
352                *output = '\0';
353            return true;
354        }
355    };
356    template <>
357    struct ConverterExplicit<std::string, unsigned char>
358    {
359        FORCEINLINE static bool convert(unsigned char* output, const std::string& input)
360        {
361            if (!input.empty())
362                *output = input[0];
363            else
364                *output = '\0';
365            return true;
366        }
367    };
368
369
370    // bool to std::string
371    template <>
372    struct ConverterExplicit<bool, std::string>
373    {
374        FORCEINLINE static bool convert(std::string* output, const bool& input)
375        {
376            if (input)
377              *output = "true";
378            else
379              *output = "false";
380            return true;
381        }
382    };
383
384    // std::string to bool
385    template <>
386    struct _UtilExport ConverterExplicit<std::string, bool>
387    {
388        static bool convert(bool* output, const std::string& input);
389    };
390}
391
392#endif /* _Convert_H__ */
Note: See TracBrowser for help on using the repository browser.