Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

Gcc detected a few typos.

  • Property svn:eol-style set to native
File size: 14.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 *      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#include <istream>
42#include <boost/static_assert.hpp>
43
44#include "Math.h"
45#include "Debug.h"
46#include "SubString.h"
47
48///////////////////////////////////
49// Explicit Conversion Functions //
50///////////////////////////////////
51
52// These conversions exhibit ambiguous << or >> operators when using stringstream
53inline bool explicitConversion(std::string* output, const char input)
54{
55    *output = std::string(input, 1);
56    return true;
57}
58inline bool explicitConversion(std::string* output, const unsigned char input)
59{
60    *output = std::string(input, 1);
61    return true;
62}
63inline bool explicitConversion(char* output, const std::string input)
64{
65    if (input != "")
66        *output = input[0];
67    else
68        *output = '\0';
69    return true;
70}
71inline bool explicitConversion(unsigned char* output, const std::string input)
72{
73    if (input != "")
74        *output = input[0];
75    else
76        *output = '\0';
77    return true;
78}
79
80///////////////////////////
81// Static type detection //
82///////////////////////////
83
84/* The idea to use the sizeof() operator on return functions to determine function existance
85   is described in 'Moder C++ design' by Alexandrescu (2001). */
86
87//template <int a, int b>
88//struct TemplateDebugger
89//{
90//    static int debug(int c, int d) { return 0; } //BOOST_STATIC_ASSERT(0); }
91//};
92
93namespace conversionTests
94{
95
96    // Two struct with very different sizes
97    struct VerySmallStruct { char dummy[1]; };
98    struct VeryBigStruct   { char dummy[1024]; }; // Big is surely larger than Small, even with alignments
99}
100
101//namespace generalFunctionTemplate
102//{
103    // Keep this function out of conversion namespaces because the compiler gives a general
104    // template in the same namesapace a higher priority than any specialisation.
105    // This function simply accepts anything but has lower priority than specialisations.
106    // It can be identified by the larger return value.
107    template <class AnyToType, class AnyFromType>
108    conversionTests::VeryBigStruct explicitConversion(AnyToType* output, const AnyFromType input)
109    {
110        // The function is exposed globally because of the "using namespace" in conversionTests.
111        // We have to make sure noboy uses it, so a good compiler error would be nice.
112        *output = (AnyToType)input; // Do not use this function!
113        //BOOST_STATIC_ASSERT(0); // just to be sure
114                return *(new conversionTests::VeryBigStruct());
115    }
116    //conversionTests::VeryBigStruct explicitConversion(...);
117//}
118
119namespace conversionTests
120{
121    //using namespace generalFunctionTemplate; // Why in separate namespace? See above
122
123    // This operators simply accept anything but have lower priority than specialisations.
124    // It can be identified by the larger return value.
125    template <class Any>
126    conversionTests::VeryBigStruct operator<<(std::ostream& outstream, const Any anything);
127    template <class Any>
128    conversionTests::VeryBigStruct operator>>(std::istream& instream,  const Any anything);
129
130    // checks for implicit conversion
131    template <class FromType, class ToType>
132    class ImplicitConversion
133    {
134    private:
135        static VerySmallStruct test(ToType); // only accepts ToType, but is preferred over '...'
136                //template <class AnyType>
137        static VeryBigStruct   test(...);//const AnyType anything);    // accepts anything
138        static FromType object; // helper object to handle private c'tor and d'tor
139    public:
140        enum { exists = sizeof(test(object)) == sizeof(VerySmallStruct) };
141    };
142
143    // checks for explicit conversion with explicitConversion()
144    template <class FromType, class ToType, int asdf>
145    class ExplicitConversion
146    {
147    private:
148        static FromType objectFromType; // helper object to handle private c'tor and d'tor
149        static ToType   objectToType;   // helper object to handle private c'tor and d'tor
150    public:
151        enum { exists = sizeof(explicitConversion(&objectToType, objectFromType)) == sizeof(VerySmallStruct) };
152        static void test();
153    };
154
155    //template <int asdf>
156    //class ExplicitConversion<float, int, asdf>
157    //{
158    //private:
159    //    static float objectFromType; // helper object to handle private c'tor and d'tor
160    //    static int   objectToType;   // helper object to handle private c'tor and d'tor
161    //public:
162    //    enum { exists = sizeof(explicitConversion(&objectToType, objectFromType)) == sizeof(VerySmallStruct) };
163    //    static void test() { TemplateDebugger<sizeof(explicitConversion(&objectToType, objectFromType)), sizeof(VerySmallStruct)>::debug(1,2); }
164    //};
165
166    // checks for conversion via istringstream
167    template <class Type>
168    class IStringStreamOperator
169    {
170        static std::istringstream istream_; // helper object to perform the '>>' operation
171        static Type object;                 // helper object to handle private c'tor and d'tor
172    public:
173        enum { exists = (sizeof(istream_ >> object) < sizeof(VerySmallStruct) + 512) };
174    };
175
176    // checks for conversion via ostringstream
177    template <class Type>
178    class OStringStreamOperator
179    {
180        static std::ostringstream ostream_; // helper object to perform the '<<' operation
181        static Type object;                 // helper object to handle private c'tor and d'tor
182    public:
183        enum { exists = (sizeof(ostream_ << object) < sizeof(VerySmallStruct) + 512) };
184    };
185}
186
187// shortcut without namespace
188template <class FromType, class ToType>
189struct ImplicitConversion
190{ enum { exists = conversionTests::ImplicitConversion<FromType, ToType>::exists }; };
191
192// shortcut without namespace
193template <class FromType, class ToType>
194struct ExplicitConversion
195{ enum { exists = conversionTests::ExplicitConversion<FromType, ToType, 4>::exists }; };
196
197// shortcut without namespace
198template <class Type>
199struct IStringStreamOperator
200{ enum { exists = conversionTests::IStringStreamOperator<Type>::exists }; };
201
202// shortcut without namespace
203template <class Type>
204struct OStringStreamOperator
205{ enum { exists = conversionTests::OStringStreamOperator<Type>::exists }; };
206
207
208///////////////////////////////
209// Conversion Template Stuff //
210///////////////////////////////
211
212namespace conversion
213{
214    // Maps bools to types in order to use function overloading instead of template specialisation (Alexandrescu 2001)
215    template <bool WhetherOrNot>
216    struct ImplicitPossible { };
217    template <bool WhetherOrNot>
218    struct ExplicitPossible { };
219    template <bool WhetherOrNot>
220    struct StringStreamPossible { };
221
222    // No Conversion possible, default template
223    template <class ToType, class FromType, int Dummy>
224    struct Converter
225    {
226        static bool convert(ToType* output, FromType input)
227        {
228            // Do not allow impossible conversions
229            //(*output) = input; // this WILL trigger a compiler error
230            //BOOST_STATIC_ASSERT(sizeof(ToType) == 0); // just to be sure..
231            return false;
232        }
233    };
234}
235
236
237///////////////////////
238//Explicit Conversion//
239///////////////////////
240
241namespace conversion
242{
243    // We can cast explicitely via function overloading, this overwrites any other possible cast
244    template <class ToType, class FromType>
245    inline bool convert(ToType* output, const FromType& input, ExplicitPossible<true>)
246    {
247        // This function can by anywhere globally!
248        //int a = TemplateDebugger<1,2>::debug(1,1);
249        //conversionTests::ExplicitConversion<FromType, ToType, 4>::test();
250        //BOOST_STATIC_ASSERT(0);
251        return explicitConversion(output, input);
252    }
253
254    // No function explict conversion, try implicit cast
255    template <class ToType, class FromType>
256    inline bool convert(ToType* output, const FromType& input, ExplicitPossible<false>)
257    {
258        return convert(output, input, ImplicitPossible<ImplicitConversion<FromType, ToType>::exists>());
259        //return ConverterSpecialised<ToType, FromType>::convert(output, input);
260    }
261}
262
263// template that is used when no explicit template specialisation is available
264template <class ToType, class FromType>
265struct ConverterSpecialised
266{
267    static bool convert(ToType* output, const FromType& input)
268    {
269        // check for explicit conversion via function overloading
270        return conversion::convert(output, input,
271            conversion::ExplicitPossible<ExplicitConversion<FromType, ToType>::exists>());
272    }
273};
274
275namespace conversion
276{
277    /////////////////
278    //Implicit Cast//
279    /////////////////
280
281    // We can cast implicitely
282    template <class ToType, class FromType>
283    inline bool convert(ToType* output, const FromType& input, ImplicitPossible<true>)
284    {
285        (*output) = static_cast<ToType>(input);
286        return true;
287    }
288
289    // No implicit cast, leave it up to << and >>
290    template <class ToType, class FromType>
291    inline bool convert(ToType* output, const FromType& input, ImplicitPossible<false>)
292    {
293        return Converter<ToType, FromType, 0>::convert(output, input);
294    }
295
296
297    /////////////////
298    //OStringStream//
299    /////////////////
300
301    // Conversion via ostringstream
302    template <class FromType>
303    bool convertOStringStream(std::string* output, const FromType& input)
304    {
305        std::ostringstream oss;
306        if (oss << input)
307        {
308            (*output) = oss.str();
309            return true;
310        }
311        else
312            return false;
313    }
314
315    // template that evaluates whether OStringStream is possible
316    template <class FromType, int Dummy>
317    struct Converter<std::string, FromType, Dummy>
318    {
319        // convert to std::string, probe for '<<' stringstream operator
320        static bool convert(std::string* output, const FromType& input)
321        {
322            return convert(output, input, StringStreamPossible<OStringStreamOperator<FromType>::exists>());
323            //conversion::OStringStreamOperator<FromType>::test();
324        }
325
326        // Conversion with ostringstream possible
327        static bool convert(std::string* output, const FromType& input, StringStreamPossible<true>)
328        {
329            return convertOStringStream(output, input);
330        }
331
332        // Conversion with ostringstream not possible
333        static bool convert(std::string* output, const FromType& input, StringStreamPossible<false>)
334        {
335            // Do not allow impossible conversions
336            //(*output) = input; // this WILL trigger a compiler error
337            //BOOST_STATIC_ASSERT(sizeof(ToType) == 0); // just to be sure..
338            return false;
339        }
340    };
341
342
343    /////////////////
344    //IStringStream//
345    /////////////////
346
347    // conversion from std::string via istringstream
348    template <class ToType>
349    bool convertIStringStream(ToType* output, const std::string& input)
350    {
351        std::istringstream iss(input);
352        if (iss >> (*output))
353        {
354            return true;
355        }
356        else
357            return false;
358    }
359
360    // template that evaluates whether IStringStream is possible
361    template <class ToType, int Dummy>
362    struct Converter<ToType, std::string, Dummy>
363    {
364        // convert from std::string, probe for '>>' stringstream operator
365        static bool convert(ToType* output, const std::string& input)
366        {
367            return convert(output, input, StringStreamPossible<IStringStreamOperator<ToType>::exists>());
368        }
369
370        // Conversion with istringstream possible
371        static bool convert(ToType* output, const std::string& input, StringStreamPossible<true>)
372        {
373            return convertIStringStream(output, input);
374        }
375
376        // Conversion with istringstream not possible
377        static bool convert(ToType* output, const std::string& input, StringStreamPossible<false>)
378        {
379            // Do not allow impossible conversions
380            //(*output) = input; // this WILL trigger a compiler error
381            //BOOST_STATIC_ASSERT(sizeof(ToType) == 0); // just to be sure..
382            return false;
383        }
384    };
385
386
387    ///////////////
388    //const char*//
389    ///////////////
390
391    // delegate conversion from const char* via string
392    template <class ToType, int Dummy>
393    struct Converter<ToType, const char*, Dummy>
394    {
395        // convert from const char* via std::string
396        static bool convert(ToType* output, const char* input)
397        { return Converter<ToType, std::string, Dummy>::convert(output, input); }
398    };
399}
400
401
402////////////////////
403//Public Functions//
404////////////////////
405
406/**
407@brief
408    Converts any value to any other as long as there exits a conversion.
409    Otherwise, the conversion will generate a runtime warning.
410*/
411template <class ToType, class FromType>
412inline bool convertValue(ToType* output, const FromType& input)
413{
414    // check whether we can convert one type to the other explicitely via function overloading
415    //conversionTests::ExplicitConversion<FromType, ToType, 4>::test();
416    return ConverterSpecialised<ToType, FromType>::convert(output, input);
417    //return conversion::convert(output, input,
418    //    conversion::ExplicitPossible<ExplicitConversion<FromType, ToType>::exists>());
419}
420
421// Helper function: Calls convertValue with and without default value and returns true if the conversion was successful
422template<class FromType, class ToType>
423static bool ConvertValue(ToType* output, const FromType& input)
424{
425    return convertValue(output, input);
426}
427template<class FromType, class ToType>
428static bool ConvertValue(ToType* output, const FromType& input, const ToType& fallback)
429{
430    if (convertValue(output, input))
431        return true;
432
433    (*output) = fallback;
434    return false;
435}
436
437// Helper function: Calls convertValue with and without default value and returns the converted value
438template<class FromType, class ToType>
439static ToType getConvertedValue(const FromType& input)
440{
441    ToType output = ToType();
442    ConvertValue(&output, input);
443    return output;
444}
445template<class FromType, class ToType>
446static ToType getConvertedValue(const FromType& input, const ToType& fallback)
447{
448    ToType output = fallback;
449    ConvertValue(&output, input, fallback);
450    return output;
451}
452
453#endif /* _Convert_H__ */
Note: See TracBrowser for help on using the repository browser.