Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core3/src/util/Convert.h @ 1766

Last change on this file since 1766 was 1766, checked in by rgrieder, 16 years ago

test files, no real content.

  • Property svn:eol-style set to native
File size: 19.3 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 *      Benjamin Grauer
24 *      Fabian 'x3n' Landau
25 *   Co-authors:
26 *      ...
27 */
28
29/*!
30    @file Convert.h
31    @brief Definition and Implementation of the Convert class.
32*/
33
34#ifndef _Convert_H__
35#define _Convert_H__
36
37#include "UtilPrereqs.h"
38
39#include <string>
40#include <sstream>
41
42#include "Math.h"
43#include "Debug.h"
44
45// Gcc generates warnings when implicitely casting from float to int for instance.
46// This is however exactly what convertValue does, so we need to suppress the warnings.
47// They only occur in when using the ImplicitConversion template.
48#if ORXONOX_COMPILER == ORXONOX_COMPILER_GCC
49#  pragma GCC system_header
50#endif
51
52///////////////////////////////////
53// Explicit Conversion Functions //
54///////////////////////////////////
55
56
57///////////////////////////////////////////////
58// Static detection for conversion functions //
59///////////////////////////////////////////////
60
61/* The idea to use the sizeof() operator on return functions to determine function existance
62   is described in 'Moder C++ design' by Alexandrescu (2001). */
63
64namespace conversionTests
65{
66    // A struct that is guaranteed to be larger than any return type of our conversion functions.
67    // So we simply add all the sizes of the return types plus a little bit more.
68    struct VeryBigStruct
69    {
70        char intSize[sizeof(int)];
71        char issSize[sizeof(std::istringstream)];
72        char ossSize[sizeof(std::ostringstream)];
73        char boolSize[sizeof(bool)];
74        char addingMore[4096]; // just to be sure ;)
75    };
76}
77
78namespace separate_namespace
79{
80    // We want to keep the templates for the convert functions out of global namespace so that there
81    // are no ambiguities. These templates are never used anyway, they only serve to detect whether
82    // there is a global funciton for a specific conversion or not.
83    // Now why not putting this in namespace 'conversionTests'?
84    // I can not tell for sure, but I think there is a bug in msvc 8. It chooses this general template
85    // (if it was in 'conversionTests') over a better fitting function in global namespace.
86    // The solution is to use another namespace and then apply the 'using' directive in 'conversionTests'.
87    // Unfortunately there is a (somewhat documented) bug in msvc 8 that exposes namespace members
88    // globally when applying the 'using' directive in a namespace. And it so happens that the bug is
89    // triggered in this file. This unwanted global exposure hopefully doesn't cause ambiguities.
90    template <class AnyToType, class AnyFromType>
91    conversionTests::VeryBigStruct explicitConversion(AnyToType* output, const AnyFromType input)
92    {
93        // We have to make sure noboy uses it , so a good compiler error would be nice.
94        *output = (AnyToType)input; // Do not use this function!
95        // gcc does some syntax checking anyway. So return a correct value that is not a temporary.
96            return *(new conversionTests::VeryBigStruct());
97    }
98}
99
100namespace conversionTests
101{
102    // Part of the msvc hack. See above in the namespace for more explanations.
103    using namespace separate_namespace;
104
105    // These operators simply accept anything but have lower priority than specialisations
106    // or exact-match non-template functions.
107    // They can be identified by the larger return value.
108    // We put these in a seperate namespace to avoid conflicts with ambiguities.
109    template <class Any>
110    conversionTests::VeryBigStruct operator<<(std::ostream& outstream, const Any anything);
111    template <class Any>
112    conversionTests::VeryBigStruct operator>>(std::istream& instream,  const Any anything);
113
114    template <class FromType, class ToType>
115    class ImplicitConversion
116    {
117    private:
118        ImplicitConversion(); ImplicitConversion(const ImplicitConversion&); ~ImplicitConversion();
119        // Gets chosen only if there is an implicit conversion from FromType to ToType.
120        static int test(ToType);
121        // Accepts any argument. Why do we not use a template? The reason is that with templates,
122        // the function above is only taken iff it is an exact type match. But since we want to
123        // check for implicit conversion, we have to use the ellipsis.
124        static VeryBigStruct   test(...);
125        static FromType object; // helper object to handle private c'tor and d'tor
126    public:
127        // test(object) has only 'VerySmallStruct' return type iff the compiler doesn't choose test(...)
128        enum { exists = !(sizeof(test(object)) == sizeof(VeryBigStruct)) };
129    };
130
131    template <class FromType, class ToType>
132    class ExplicitConversion
133    {
134    private:
135        ExplicitConversion(); ExplicitConversion(const ExplicitConversion&); ~ExplicitConversion();
136        static FromType objectFromType; // helper object to handle private c'tor and d'tor
137        static ToType   objectToType;   // helper object to handle private c'tor and d'tor
138    public:
139        enum { exists = !(sizeof(explicitConversion(&objectToType, objectFromType)) == sizeof(VeryBigStruct)) };
140    };
141
142    template <class Type>
143    class IStringStreamOperator
144    {
145        IStringStreamOperator(); IStringStreamOperator(const IStringStreamOperator&); ~IStringStreamOperator();
146        static std::istringstream istream_; // helper object to perform the '>>' operation
147        static Type object;                 // helper object to handle private c'tor and d'tor
148    public:
149        enum { exists = !(sizeof(istream_ >> object) == sizeof(VeryBigStruct)) };
150    };
151
152    template <class Type>
153    class OStringStreamOperator
154    {
155        OStringStreamOperator(); OStringStreamOperator(const OStringStreamOperator&); ~OStringStreamOperator();
156        static std::ostringstream ostream_; // helper object to perform the '<<' operation
157        static Type object;                 // helper object to handle private c'tor and d'tor
158    public:
159        enum { exists = !(sizeof(ostream_ << object) == sizeof(VeryBigStruct)) };
160    };
161}
162
163/* Shortcuts because we usually don't have a namespace in util/ but need one here for the conversion tests*/
164
165/**
166@brief
167    Checks for an implicit conversion FromType --> TyType.
168    This also works for user defined conversion operators.
169    Usage: ImplicitConversion<FromType, ToType>::exists
170*/
171template <class FromType, class ToType>
172struct ImplicitConversion
173{ enum { exists = conversionTests::ImplicitConversion<FromType, ToType>::exists }; };
174
175/**
176@brief
177    Checks for an explicit conversion FromType --> TyType via 'explicConversion()' function.
178    There has to e an exact type match for a success!
179    Usage: ExplicitConversion<FromType, ToType>::exists
180*/
181template <class FromType, class ToType>
182struct ExplicitConversion
183{ enum { exists = conversionTests::ExplicitConversion<FromType, ToType>::exists }; };
184
185/**
186@brief
187    Checks for an explicit conversion std::string --> TyType via >> operator.
188    There has to e an exact type match for a success!
189    Usage: IStringStreamConversion<FromType, ToType>::exists
190*/
191template <class Type>
192struct IStringStreamOperator
193{ enum { exists = conversionTests::IStringStreamOperator<Type>::exists }; };
194
195/**
196@brief
197    Checks for an explicit conversion std::string --> TyType via << operator.
198    There has to e an exact type match for a success!
199    Usage: OStringStreamConversion<FromType, ToType>::exists
200*/
201template <class Type>
202struct OStringStreamOperator
203{ enum { exists = conversionTests::OStringStreamOperator<Type>::exists }; };
204
205
206
207////////////////////////////////////
208//// ACTUAL CONVERSION SEQUENCE ////
209////////////////////////////////////
210/*
211    There is a distinct priority when choosing the right conversion function:
212    Overwrites:
213    1. (Partial) template specialisation of ConverterExplicit::convert
214    2. Global functions explicitConversion(ToType* output, const FromType input)
215    Fallbacks:
216    3. Any possible implicit conversion. This includes FooBar --> int if FooBar defines operator float().
217    4. Global or member operators for stringstream when converting from or to std::string (or FROM const char*)
218    5. Function that simply displays "Could not convert value" with information obtained from typeid().
219
220    A note: There has to be an exact type match (or according to the rules of template spec.) except for 3.
221
222    There are obviously a lot of ways to specifiy a user defined conversion. What should I use?
223    When using any non-template function based conversion (implicit conversion, explicitConversion, << or >>)
224    then you should consider that this function has to be defined prior to including this file.
225    If you do not whish do do that, you will have to spcecialsize the ConverterExplicit template.
226    There is a not so obvious advantage of the other way (non-template): You could declare each conversion function
227    in the Prereqs file of the corresponding library. Then you can use the conversion everywhere.
228    This is not possible with template specialisations even when defining them in this file (You would create
229    a circular dependency when using a class from Core for instance, because complete template specialisations
230    get compiled anyway (there is no template parameter)).
231*/
232
233// Put everything in a namespace to avoid unnecessary exposure
234// Note that the textual order of the functions is in reverse.
235namespace conversion
236{
237    // Maps bools to types in order to use function overloading instead of template specialisation (Alexandrescu 2001)
238    template <bool WhetherOrNot>
239    struct ImplicitPossible { };
240    template <bool WhetherOrNot>
241    struct ExplicitPossible { };
242    template <bool WhetherOrNot>
243    struct StringStreamPossible { };
244
245
246    ///////////////////
247    // No Conversion //
248    ///////////////////
249
250    // Default template, no Conversion possible
251    template <class ToType, class FromType, int Dummy>
252    struct ConverterSS
253    {
254        static bool convert(ToType* output, FromType input)
255        {
256            COUT(2) << "Could not convert value of type " << typeid(FromType).name()
257                    << " to type " << typeid(ToType).name() << std::endl;
258            return false;
259        }
260    };
261
262
263    ///////////////////
264    // OStringStream //
265    ///////////////////
266
267    // Conversion via ostringstream
268    template <class FromType>
269    inline bool convertOStringStream(std::string* output, const FromType& input)
270    {
271        std::ostringstream oss;
272        if (oss << input)
273        {
274            (*output) = oss.str();
275            return true;
276        }
277        else
278            return false;
279    }
280
281    // template that evaluates whether OStringStream is possible for conversions to std::string
282    template <class FromType, int Dummy>
283    struct ConverterSS<std::string, FromType, Dummy>
284    {
285        // probe for '<<' stringstream operator
286        static bool convert(std::string* output, const FromType& input)
287        {
288            const bool probe = OStringStreamOperator<FromType>::exists;
289            return convert(output, input, StringStreamPossible<probe>());
290        }
291        // Conversion with ostringstream possible
292        static bool convert(std::string* output, const FromType& input, StringStreamPossible<true>)
293        {
294            return convertOStringStream(output, input);
295        }
296        // Conversion with ostringstream not possible
297        static bool convert(std::string* output, const FromType& input, StringStreamPossible<false>)
298        {
299            COUT(2) << "Could not convert value of type " << typeid(FromType).name()
300                    << " to std::string" << std::endl;
301            return false;
302        }
303    };
304
305
306    ///////////////////
307    // IStringStream //
308    ///////////////////
309
310    // conversion from std::string via istringstream
311    template <class ToType>
312    inline bool convertIStringStream(ToType* output, const std::string& input)
313    {
314        std::istringstream iss(input);
315        if (iss >> (*output))
316        {
317            return true;
318        }
319        else
320            return false;
321    }
322
323    // template that evaluates whether IStringStream is possible for conversions from std::string
324    template <class ToType, int Dummy>
325    struct ConverterSS<ToType, std::string, Dummy>
326    {
327        // probe for '>>' stringstream operator
328        static bool convert(ToType* output, const std::string& input)
329        {
330            const bool probe = IStringStreamOperator<ToType>::exists;
331            return convert(output, input, StringStreamPossible<probe>());
332        }
333        // Conversion with istringstream possible
334        static bool convert(ToType* output, const std::string& input, StringStreamPossible<true>)
335        {
336            return convertIStringStream(output, input);
337        }
338        // Conversion with istringstream not possible
339        static bool convert(ToType* output, const std::string& input, StringStreamPossible<false>)
340        {
341            COUT(2) << "Could not convert std::string value to type " << typeid(ToType).name() << std::endl;
342            return false;
343        }
344    };
345
346
347    ///////////////////
348    // Implicit Cast //
349    ///////////////////
350
351    // We can cast implicitely
352    template <class ToType, class FromType>
353    inline bool convert(ToType* output, const FromType& input, ImplicitPossible<true>)
354    {
355        (*output) = static_cast<ToType>(input);
356        return true;
357    }
358
359    // No implicit cast, leave it up to << and >> via template spcialisation
360    template <class ToType, class FromType>
361    inline bool convert(ToType* output, const FromType& input, ImplicitPossible<false>)
362    {
363        return ConverterSS<ToType, FromType, 0>::convert(output, input);
364    }
365
366
367    /////////////////////////
368    // Explicit Conversion //
369    /////////////////////////
370
371    // We can convert explicitely via function overloading
372    template <class ToType, class FromType>
373    inline bool convert(ToType* output, const FromType& input, ExplicitPossible<true>)
374    {
375        // This function can by anywhere globally!
376        return explicitConversion(output, input);
377    }
378
379    // No explict conversion via explicitConversion(), try implicit cast
380    template <class ToType, class FromType>
381    inline bool convert(ToType* output, const FromType& input, ExplicitPossible<false>)
382    {
383        const bool probe = ImplicitConversion<FromType, ToType>::exists;
384        return convert(output, input, ImplicitPossible<probe>());
385    }
386}
387
388// We usually don't have a namespace in util/ but it would still be desirable to lock
389// everything internal away in namespace conversion.
390// However this template can be specialised everywhere.
391
392// Template that is used when no explicit template specialisation is available
393// try explicitConversion() function next.
394template <class ToType, class FromType>
395struct ConverterExplicit
396{
397    static bool convert(ToType* output, const FromType& input)
398    {
399        // check for explicit conversion via function overloading
400        const bool probe = ExplicitConversion<FromType, ToType>::exists;
401        return conversion::convert(output, input, conversion::ExplicitPossible<probe>());
402    }
403};
404
405
406//////////////////////
407// Public Functions //
408//////////////////////
409
410/**
411@brief
412    Converts any value to any other as long as there exits a conversion.
413    Otherwise, the conversion will generate a runtime warning.
414    For information about the different conversion methods (user defined too), see the section
415    'Actual conversion sequence' in this file above.
416*/
417template <class ToType, class FromType>
418inline bool convertValue(ToType* output, const FromType& input)
419{
420    // check whether we can convert one type to the other explicitely via explicit template specialisations
421    return ConverterExplicit<ToType, FromType>::convert(output, input);
422}
423
424// For compatibility reasons. The same, but with capital ConvertValue
425template<class FromType, class ToType>
426inline bool ConvertValue(ToType* output, const FromType& input)
427{
428    return convertValue(output, input);
429}
430
431// Calls convertValue and returns true if the conversion was successful.
432// Otherwise the fallback is used.
433template<class FromType, class ToType>
434inline bool ConvertValue(ToType* output, const FromType& input, const ToType& fallback)
435{
436    if (convertValue(output, input))
437        return true;
438
439    (*output) = fallback;
440    return false;
441}
442
443// Directly returns the converted value, even if the conversion was not successful.
444template<class FromType, class ToType>
445inline ToType getConvertedValue(const FromType& input)
446{
447    ToType output;
448    ConvertValue(&output, input);
449    return output;
450}
451
452// Directly returns the converted value, but uses the fallback on failure.
453template<class FromType, class ToType>
454inline ToType getConvertedValue(const FromType& input, const ToType& fallback)
455{
456    ToType output;
457    ConvertValue(&output, input, fallback);
458    return output;
459}
460
461// Like getConvertedValue, but the template argument order is in reverse.
462// That means you can call it exactly like static_cast<ToType>(fromTypeValue).
463template<class ToType, class FromType>
464inline ToType conversion_cast(const FromType& input)
465{
466    ToType output;
467    ConvertValue(&output, input);
468    return output;
469}
470
471// Like conversion_cast above, but uses a fallback on failure.
472template<class ToType, class FromType>
473inline ToType conversion_cast(const FromType& input, const ToType& fallback)
474{
475    ToType output;
476    ConvertValue(&output, input, fallback);
477    return output;
478}
479
480
481///////////////////////////////////////
482// Explicit Template Specialisations //
483///////////////////////////////////////
484
485// delegate conversion from const char* to std::string
486template <class ToType>
487struct ConverterExplicit<ToType, const char*>
488{
489    static bool convert(ToType* output, const char* input)
490    {
491        return ConverterExplicit<ToType, std::string>::convert(output, input);
492    }
493};
494
495// These conversions would exhibit ambiguous << or >> operators when using stringstream
496template <> struct ConverterExplicit<std::string, char>
497{
498    static bool convert(std::string* output, const char input)
499    {
500        *output = std::string(1, input);
501        return true;
502    }
503};
504template <> struct ConverterExplicit<std::string, unsigned char>
505{
506    static bool convert(std::string* output, const unsigned char input)
507    {
508        *output = std::string(1, input);
509        return true;
510    }
511};
512template <> struct ConverterExplicit<char, std::string>
513{
514    static bool convert(char* output, const std::string input)
515    {
516        if (input != "")
517            *output = input[0];
518        else
519            *output = '\0';
520        return true;
521    }
522};
523template <> struct ConverterExplicit<unsigned char, std::string>
524{
525    static bool convert(unsigned char* output, const std::string input)
526    {
527        if (input != "")
528            *output = input[0];
529        else
530            *output = '\0';
531        return true;
532    }
533};
534
535#endif /* _Convert_H__ */
Note: See TracBrowser for help on using the repository browser.