Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 1745 was 1745, checked in by rgrieder, 16 years ago
  • Extended convert a little bit support template specialisations as well.
  • Converted conversion function with Math and std::string to Math.h and .cc
  • 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
241// template that is used when no explicit template specialisation is available
242template <class ToType, class FromType>
243struct ConverterSpecialised
244{
245    static bool convert(ToType* output, const FromType& input)
246    {
247        // check for explicit conversion via function overloading
248        return conversion::convert(output, input,
249            conversion::ExplicitPossible<ExplicitConversion<FromType, ToType>::exists>());
250    }
251};
252
253namespace conversion
254{
255    // We can cast explicitely via function overloading, this overwrites any other possible cast
256    template <class ToType, class FromType>
257    inline bool convert(ToType* output, const FromType& input, ExplicitPossible<true>)
258    {
259        // This function can by anywhere globally!
260        //int a = TemplateDebugger<1,2>::debug(1,1);
261        //conversionTests::ExplicitConversion<FromType, ToType, 4>::test();
262        //BOOST_STATIC_ASSERT(0);
263        return explicitConversion(output, input);
264    }
265
266    // No function explict conversion, try implicit cast
267    template <class ToType, class FromType>
268    inline bool convert(ToType* output, const FromType& input, ExplicitPossible<false>)
269    {
270        return convert(output, input, ImplicitPossible<ImplicitConversion<FromType, ToType>::exists>());
271        //return ConverterSpecialised<ToType, FromType>::convert(output, input);
272    }
273
274
275    /////////////////
276    //Implicit Cast//
277    /////////////////
278
279    // We can cast implicitely
280    template <class ToType, class FromType>
281    inline bool convert(ToType* output, const FromType& input, ImplicitPossible<true>)
282    {
283        (*output) = static_cast<ToType>(input);
284        return true;
285    }
286
287    // No implicit cast, leave it up to << and >>
288    template <class ToType, class FromType>
289    inline bool convert(ToType* output, const FromType& input, ImplicitPossible<false>)
290    {
291        return Converter<ToType, FromType, 0>::convert(output, input);
292    }
293
294
295    /////////////////
296    //OStringStream//
297    /////////////////
298
299    // Conversion via ostringstream
300    template <class FromType>
301    bool convertOStringStream(std::string* output, const FromType& input)
302    {
303        std::ostringstream oss;
304        if (oss << input)
305        {
306            (*output) = oss.str();
307            return true;
308        }
309        else
310            return false;
311    }
312
313    // template that evaluates whether OStringStream is possible
314    template <class FromType, int Dummy>
315    struct Converter<std::string, FromType, Dummy>
316    {
317        // convert to std::string, probe for '<<' stringstream operator
318        static bool convert(std::string* output, const FromType& input)
319        {
320            return convert(output, input, StringStreamPossible<OStringStreamOperator<FromType>::exists>());
321            //conversion::OStringStreamOperator<FromType>::test();
322        }
323
324        // Conversion with ostringstream possible
325        static bool convert(std::string* output, const FromType& input, StringStreamPossible<true>)
326        {
327            return convertOStringStream(output, input);
328        }
329
330        // Conversion with ostringstream not possible
331        static bool convert(std::string* output, const FromType& input, StringStreamPossible<false>)
332        {
333            // Do not allow impossible conversions
334            //(*output) = input; // this WILL trigger a compiler error
335            //BOOST_STATIC_ASSERT(sizeof(ToType) == 0); // just to be sure..
336            return false;
337        }
338    };
339
340
341    /////////////////
342    //IStringStream//
343    /////////////////
344
345    // conversion from std::string via istringstream
346    template <class ToType>
347    bool convertIStringStream(ToType* output, const std::string& input)
348    {
349        std::istringstream iss(input);
350        if (iss >> (*output))
351        {
352            return true;
353        }
354        else
355            return false;
356    }
357
358    // template that evaluates whether IStringStream is possible
359    template <class ToType, int Dummy>
360    struct Converter<ToType, std::string, Dummy>
361    {
362        // convert from std::string, probe for '>>' stringstream operator
363        static bool convert(ToType* output, const std::string& input)
364        {
365            return convert(output, input, StringStreamPossible<IStringStreamOperator<ToType>::exists>());
366        }
367
368        // Conversion with istringstream possible
369        static bool convert(ToType* output, const std::string& input, StringStreamPossible<true>)
370        {
371            return convertIStringStream(output, input);
372        }
373
374        // Conversion with istringstream not possible
375        static bool convert(ToType* output, const std::string& input, StringStreamPossible<false>)
376        {
377            // Do not allow impossible conversions
378            //(*output) = input; // this WILL trigger a compiler error
379            //BOOST_STATIC_ASSERT(sizeof(ToType) == 0); // just to be sure..
380            return false;
381        }
382    };
383
384
385    ///////////////
386    //const char*//
387    ///////////////
388
389    // delegate conversion from const char* via string
390    template <class ToType, int Dummy>
391    struct Converter<ToType, const char*, Dummy>
392    {
393        // convert from const char* via std::string
394        static bool convert(ToType* output, const char* input)
395        { return Converter<ToType, std::string, Dummy>::convert(output, input); }
396    };
397}
398
399
400////////////////////
401//Public Functions//
402////////////////////
403
404/**
405@brief
406    Converts any value to any other as long as there exits a conversion.
407    Otherwise, the conversion will generate a runtime warning.
408*/
409template <class ToType, class FromType>
410inline bool convertValue(ToType* output, const FromType& input)
411{
412    // check whether we can convert one type to the other explicitely via function overloading
413    //conversionTests::ExplicitConversion<FromType, ToType, 4>::test();
414    return ConverterSpecialised<ToType, FromType>::convert(output, input);
415    //return conversion::convert(output, input,
416    //    conversion::ExplicitPossible<ExplicitConversion<FromType, ToType>::exists>());
417}
418
419// Helper function: Calls convertValue with and without default value and returns true if the conversion was successful
420template<class FromType, class ToType>
421static bool ConvertValue(ToType* output, const FromType& input)
422{
423    return convertValue(output, input);
424}
425template<class FromType, class ToType>
426static bool ConvertValue(ToType* output, const FromType& input, const ToType& fallback)
427{
428    if (convertValue(output, input))
429        return true;
430
431    (*output) = fallback;
432    return false;
433}
434
435// Helper function: Calls convertValue with and without default value and returns the converted value
436template<class FromType, class ToType>
437static ToType getConvertedValue(const FromType& input)
438{
439    ToType output = ToType();
440    ConvertValue(&output, input);
441    return output;
442}
443template<class FromType, class ToType>
444static ToType getConvertedValue(const FromType& input, const ToType& fallback)
445{
446    ToType output = fallback;
447    ConvertValue(&output, input, fallback);
448    return output;
449}
450
451#endif /* _Convert_H__ */
Note: See TracBrowser for help on using the repository browser.