Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/cpp11_v2/src/libraries/util/MultiType.h @ 11001

Last change on this file since 11001 was 11001, checked in by landauf, 8 years ago

removed spezializations for MultiType::get≠(), using type-traits instead.

  • Property svn:eol-style set to native
File size: 25.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 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29/**
30    @defgroup MultiType MultiType
31    @ingroup Util
32*/
33
34/**
35    @file
36    @ingroup MultiType
37    @brief Declaration of the MultiType and some helper constructs.
38
39    @anchor MultiTypeExamples
40
41    The MultiType can hold a value of one of the following types:
42     - all primitives (int, float, bool, etc.)
43     - all pointers (void* and T*)
44     - std::string
45     - Vector2, Vector3, Vector4
46     - Quaternion
47     - ColourValue
48     - Radian, Degree
49
50    The MultiType has an internal "type" determined by the first assigned value, using one of these ways:
51     - @ref orxonox::MultiType::MultiType "The constructor"
52     - The assignment operator= (orxonox::MultiType::operator=())
53     - @ref orxonox::MultiType::set() "set(value)"
54
55    If you assign another value of another type, the MultiType keeps "its" type and
56    converts the new value to the old type.
57
58    If you want to change the type, there are three possibilities:
59     - @ref orxonox::MultiType::convert "convert<T>()" sets the type to T and converts the currently assigned value
60     - @ref orxonox::MultiType::reset "reset<T>()" sets the type to T and resets the value to zero using zeroise<T>()
61     - force<T>(value) assigns a new value and changes the type to T.
62
63    Examples:
64    @code
65    MultiType a = 10;       // a has now the type int and the value 10
66    a.set("3.14");          // a has still the type int and "3.14" gets converted, therefore the value is now 3
67    a.force<float>("3.14"); // a has now the type float and "3.14" gets converted to 3.14f
68    a.convert<bool>();      // converts 3.14f to bool, which is true
69    a = false;              // assigns false, this is equivalent to a.setValue(false)
70    @endcode
71
72    You can pass a MultiType to a function as an argument, even if the argument is
73    not of type MultiType. This works, because the MultiType is automatically converted
74    to the right type.
75
76    Example:
77    @code
78    void myfunction(int value)
79    {
80        orxout() << "doubled value is " << (2 * value) << endl;
81    }
82
83    MultiType a = "50";        // Note: We assigned a string
84    myfunction(a);             // a is converted to int and passed to the function, which prints "value is 100"
85    @endcode
86
87    Note however that it is of course quite expensive to convert values, especially std::string <-> value.
88    So if you can, always assign a value with the right type to avoid conversion.
89
90    @note
91    Whenever a value gets converted, there is a boolean return value telling you whether it was
92    successful or not. If it wasn't a zero value is assigned with the help of zeroise<T>().
93*/
94
95#ifndef _MultiType_H__
96#define _MultiType_H__
97
98#include "UtilPrereqs.h"
99
100#include <cassert>
101#include <string>
102#include <OgreVector2.h>
103#include <OgreVector3.h>
104#include <OgreVector4.h>
105#include <OgreQuaternion.h>
106#include <OgreColourValue.h>
107#include <loki/TypeTraits.h>
108#include "Math.h"
109#include "mbool.h"
110
111namespace orxonox
112{
113    /**
114        @brief The MultiType can hold a value of many possible types and convert them to other types.
115
116        The following types are supported by the MultiType:
117         - all primitves
118         - all pointers
119         - string
120         - Vector2, Vector3, Vector4
121         - Quaternion
122         - ColourValue
123         - Radian, Degree
124
125        For more information and some examples see the description @ref MultiTypeExamples "here".
126
127        @see MultiType.h
128    */
129    class _UtilExport MultiType
130    {
131        _UtilExport friend std::ostream& operator<<(std::ostream& outstream, const MultiType& mt);
132        template <typename T> friend class MT_Value;
133
134        struct Type
135        {
136            /**
137                @brief Enum of all possible types of a MultiType.
138            */
139            enum Enum
140            {
141                Null,
142                Char,
143                UnsignedChar,
144                Short,
145                UnsignedShort,
146                Int,
147                UnsignedInt,
148                Long,
149                UnsignedLong,
150                LongLong,
151                UnsignedLongLong,
152                Float,
153                Double,
154                LongDouble,
155                Bool,
156                VoidPointer,
157                String,
158                Vector2,
159                Vector3,
160                Vector4,
161                ColourValue,
162                Quaternion,
163                Radian,
164                Degree
165            };
166        };
167
168    public:
169        /**
170            @brief MT_ValueBase is an almost pure virtual baseclass of MT_Value<T>, which holds the value of the MultiType.
171            This class is only used within the MultiType.
172        */
173        class _UtilExport MT_ValueBase
174        {
175        public:
176            inline MT_ValueBase(void* data, Type::Enum type) : type_(type), bLastConversionSuccessful(true), data_(data) {}
177            virtual inline ~MT_ValueBase() {}
178
179            virtual MT_ValueBase* clone() const = 0;
180
181            virtual void reset() = 0;
182
183            /// Returns the type of the current value.
184            inline const Type::Enum& getType() const { return this->type_; }
185            /// Returns true if the type of the stored value is T.
186            template <typename T> inline bool isType() const { return false; }
187
188            /// Checks whether the value is a default one.
189            inline bool lastConversionSuccessful()   const { return this->bLastConversionSuccessful; }
190
191            virtual bool setValue(const char& value)                 = 0;
192            virtual bool setValue(const unsigned char& value)        = 0;
193            virtual bool setValue(const short& value)                = 0;
194            virtual bool setValue(const unsigned short& value)       = 0;
195            virtual bool setValue(const int& value)                  = 0;
196            virtual bool setValue(const unsigned int& value)         = 0;
197            virtual bool setValue(const long& value)                 = 0;
198            virtual bool setValue(const unsigned long& value)        = 0;
199            virtual bool setValue(const long long& value)            = 0;
200            virtual bool setValue(const unsigned long long& value)   = 0;
201            virtual bool setValue(const float& value)                = 0;
202            virtual bool setValue(const double& value)               = 0;
203            virtual bool setValue(const long double& value)          = 0;
204            virtual bool setValue(const bool& value)                 = 0;
205            virtual bool setValue(      void* const& value)          = 0;
206            virtual bool setValue(const std::string& value)          = 0;
207            virtual bool setValue(const orxonox::Vector2& value)     = 0;
208            virtual bool setValue(const orxonox::Vector3& value)     = 0;
209            virtual bool setValue(const orxonox::Vector4& value)     = 0;
210            virtual bool setValue(const orxonox::ColourValue& value) = 0;
211            virtual bool setValue(const orxonox::Quaternion& value)  = 0;
212            virtual bool setValue(const orxonox::Radian& value)      = 0;
213            virtual bool setValue(const orxonox::Degree& value)      = 0;
214
215            virtual bool setValue(const MultiType& other)            = 0;
216
217            virtual bool getValue(char*                 value) const = 0;
218            virtual bool getValue(unsigned char*        value) const = 0;
219            virtual bool getValue(short*                value) const = 0;
220            virtual bool getValue(unsigned short*       value) const = 0;
221            virtual bool getValue(int*                  value) const = 0;
222            virtual bool getValue(unsigned int*         value) const = 0;
223            virtual bool getValue(long*                 value) const = 0;
224            virtual bool getValue(unsigned long*        value) const = 0;
225            virtual bool getValue(long long*            value) const = 0;
226            virtual bool getValue(unsigned long long*   value) const = 0;
227            virtual bool getValue(float*                value) const = 0;
228            virtual bool getValue(double*               value) const = 0;
229            virtual bool getValue(long double*          value) const = 0;
230            virtual bool getValue(bool*                 value) const = 0;
231            virtual bool getValue(void**                value) const = 0;
232            virtual bool getValue(std::string*          value) const = 0;
233            virtual bool getValue(orxonox::Vector2*     value) const = 0;
234            virtual bool getValue(orxonox::Vector3*     value) const = 0;
235            virtual bool getValue(orxonox::Vector4*     value) const = 0;
236            virtual bool getValue(orxonox::ColourValue* value) const = 0;
237            virtual bool getValue(orxonox::Quaternion*  value) const = 0;
238            virtual bool getValue(orxonox::Radian*      value) const = 0;
239            virtual bool getValue(orxonox::Degree*      value) const = 0;
240
241            template <typename T> T get() const
242            {
243                if (this->isType<T>())
244                    return *reinterpret_cast<const T*>(this->data_);
245                else
246                {
247                    T value;
248                    this->getValue(&value);
249                    return value;
250                }
251            }
252
253            virtual void toString(std::ostream& outstream) const = 0;
254
255            virtual void importData(uint8_t*& mem) = 0;
256            virtual void exportData(uint8_t*& mem) const = 0;
257            virtual uint8_t getSize() const = 0;
258
259            Type::Enum type_;               ///< The type of the current value
260            bool bLastConversionSuccessful; ///< True if the last conversion was successful
261            void* data_;                    ///< For direct access to the value if the type is known
262        };
263
264        public:
265            static const MultiType Null;
266
267            /// Default constructor: Assigns no value and no type. The type will be determined by the first assignment of a value.
268            inline MultiType()                       : value_(nullptr) { }
269            /// Constructor: Assigns the given value and sets the type.
270            template <typename V>
271            inline MultiType(const V& value)         : value_(nullptr) { this->set(value); }
272            /// Copyconstructor: Assigns value and type of the other MultiType.
273            inline MultiType(const MultiType& other) : value_(nullptr) { this->set(other); }
274
275            /// Destructor: Deletes the MT_Value.
276            inline ~MultiType() { if (this->value_) { delete this->value_; } }
277
278            /// Assigns a new value. The value will be converted to the current type of the MultiType.
279            template <typename V> inline MultiType& operator=(const V& value)         { this->set(value); return (*this); }
280            /// Assigns a pointer.
281            template <typename V> inline MultiType& operator=(V* value)               { this->set(value); return (*this); }
282            /// Assigns the value of the other MultiType and converts it to the current type of the MultiType.
283            inline                       MultiType& operator=(const MultiType& other) { this->set(other); return (*this); }
284
285            /// Assigns the given value and converts it to the current type.
286            template <typename V> inline bool set(const V& value)
287            {
288                if (this->value_)
289                    return this->value_->setValue(value);
290
291                this->assignValue(value);
292                return true;
293            }
294            /// Assigns a pointer.
295            template <typename V> inline bool set(V* value)
296            {
297                if (this->value_)
298                    return this->value_->setValue(static_cast<void*>(const_cast<typename Loki::TypeTraits<V>::UnqualifiedType*>(value)));
299
300                this->assignValue(static_cast<void*>(const_cast<typename Loki::TypeTraits<V>::UnqualifiedType*>(value)));
301                return true;
302            }
303            /// Assigns the value of the other MultiType and converts it to the current type.
304            inline bool set(const MultiType& other)
305            {
306                if (this->value_)
307                    return this->value_->setValue(other);
308                else if (other.value_)
309                    this->value_ = other.value_->clone();
310                return true;
311            }
312
313            /// Changes the type to T and assigns the new value (which might be of another type than T - it gets converted).
314            template <typename T, typename V> inline bool force(const V& value)
315            {
316                this->reset<T>();
317                return this->set(value);
318            }
319
320            /// Copies the other MultiType by assigning value and type.
321            inline void copy(const MultiType& other)
322            {
323                if (this == &other)
324                    return;
325                if (this->value_)
326                    delete this->value_;
327                this->value_ = (other.value_) ? other.value_->clone() : nullptr;
328            }
329
330            /// Converts the current value to type T.
331            template <typename T> inline bool convert() { return this->force<T>(MultiType(*this)); }
332
333            /// Resets value and type. Type will be void afterwards and null() returns true.
334            inline void reset() { if (this->value_) delete this->value_; this->value_ = nullptr; }
335            /// Resets the value and changes the internal type to T.
336            template <typename T> inline void reset() { this->assignValue(typename Loki::TypeTraits<T>::UnqualifiedReferredType()); }
337            /// Current value gets overridden with default zero value
338            inline void resetValue() { if (this->value_) this->value_->reset(); }
339
340            /// Returns true if the type of the current value is T.
341            template <typename T> inline bool isType() const { return (this->value_ ? this->value_->isType<T>() : false); }
342            std::string getTypename() const;
343
344            /// Checks whether the last conversion was successful
345            inline bool lastConversionSuccessful() const { return !this->value_ || this->value_->lastConversionSuccessful(); }
346
347            /// Checks if the MT contains no value.
348            inline bool null() const { return !this->value_; }
349
350            /// Conversion operator for all types
351            template <class T> operator T()  const { return this->get<T>(); }
352
353            /// Assigns the value to the given pointer. The value gets converted if the types don't match.
354            template <typename T> inline bool getValue(T* value) const { if (this->value_) { return this->value_->getValue(value); } return false; }
355
356            /// Returns the current value, converted to the requested type.
357            template <typename T> /* for normal types */ typename std::enable_if<!std::is_pointer<T>::value, T>::type
358            inline /*T*/ get() const { return (this->value_ ? this->value_->get<T>() : NilValue<T>()); }
359            /// Returns the current value, converted to a pointer of the requested type.
360            template <typename T> /* for pointers */ typename std::enable_if<std::is_pointer<T>::value, T>::type
361            inline /*T*/ get() const { return this->value_ ? static_cast<T>(this->value_->get<void*>()) : nullptr; }
362
363
364            ///////////////////////////////
365            // network-related functions //
366            ///////////////////////////////
367            /// Saves the value of the MT to a bytestream (pointed at by mem) and increases mem pointer by size of MT
368            inline void exportData(uint8_t*& mem) const
369            {
370                assert(sizeof(Type::Enum) <= 8);
371                *static_cast<uint8_t*>(mem) = this->getType();
372                mem += sizeof(uint8_t);
373                this->value_->exportData(mem);
374            }
375            /// Loads the value of the MT from a bytestream (pointed at by mem) and increases mem pointer by size of MT
376            inline void importData(uint8_t*& mem)
377            {
378                assert(sizeof(Type::Enum) <= 8);
379                this->setType(static_cast<Type::Enum>(*static_cast<uint8_t*>(mem)));
380                mem += sizeof(uint8_t);
381                this->value_->importData(mem);
382            }
383            /// Saves the value of the MT to a bytestream and increases pointer to bytestream by size of MT
384            inline uint8_t*& operator<<(uint8_t*& mem)
385            {
386                importData(mem);
387                return mem;
388            }
389            /// Loads the value of the MT to a bytestream and increases pointer to bytestream by size of MT
390            inline void operator>>(uint8_t*& mem) const
391            {
392                exportData(mem);
393            }
394            inline uint32_t getNetworkSize() const
395            {
396                assert(this->value_);
397                return this->value_->getSize() + sizeof(uint8_t);
398            }
399
400        private:
401            /// Assigns a new value by changing type and creating a new container.
402            template <typename T> inline void assignValue(const T& value)
403            {
404                if (this->isType<T>())
405                    this->value_->setValue(value);
406                else
407                    this->changeValueContainer(value);
408            }
409            /// Assigns a new value by changing type and creating a new container (overload for pointers).
410            template <typename T> inline void assignValue(T* const& value)
411            {
412                if (this->isType<void*>())
413                    this->value_->setValue(static_cast<void*>(value));
414                else
415                    this->changeValueContainer<void*>(value);
416            }
417
418            /// Resets the value and changes the internal type to the given type.
419            inline void setType(Type::Enum type) { this->reset(); this->convert(type); this->resetValue(); }
420            /// Returns the current type.
421            inline Type::Enum getType() const { return (this->value_) ? this->value_->type_ : Type::Null; }
422            /// Converts the current value to the given type.
423            bool convert(Type::Enum type);
424
425            /// Changes the value container.
426            template <typename T> inline void changeValueContainer(const T& value)
427            {
428                if (this->value_)
429                    delete this->value_;
430                this->createNewValueContainer(value);
431            }
432            /// Creates a new value container (works only with specialized types).
433            template <typename T> inline void createNewValueContainer(const T& value)
434            { 
435                // If you reach this code, you used MultiType with an unsupported type T
436                static_assert(sizeof(T) != sizeof(T), "No template specialization available for T");
437            }
438
439            MT_ValueBase* value_; //!< A pointer to the value container
440    };
441
442    /// Puts the MultiType on a stream by using the native << operator of the current type.
443    _UtilExport inline std::ostream& operator<<(std::ostream& outstream, const MultiType& mt)
444    {
445        if (mt.value_)
446            mt.value_->toString(outstream);
447        return outstream;
448    }
449
450    template <> inline bool MultiType::MT_ValueBase::isType<char>()                 const { return this->type_ == Type::Char;             }
451    template <> inline bool MultiType::MT_ValueBase::isType<unsigned char>()        const { return this->type_ == Type::UnsignedChar;     }
452    template <> inline bool MultiType::MT_ValueBase::isType<short>()                const { return this->type_ == Type::Short;            }
453    template <> inline bool MultiType::MT_ValueBase::isType<unsigned short>()       const { return this->type_ == Type::UnsignedShort;    }
454    template <> inline bool MultiType::MT_ValueBase::isType<int>()                  const { return this->type_ == Type::Int;              }
455    template <> inline bool MultiType::MT_ValueBase::isType<unsigned int>()         const { return this->type_ == Type::UnsignedInt;      }
456    template <> inline bool MultiType::MT_ValueBase::isType<long>()                 const { return this->type_ == Type::Long;             }
457    template <> inline bool MultiType::MT_ValueBase::isType<unsigned long>()        const { return this->type_ == Type::UnsignedLong;     }
458    template <> inline bool MultiType::MT_ValueBase::isType<long long>()            const { return this->type_ == Type::LongLong;         }
459    template <> inline bool MultiType::MT_ValueBase::isType<unsigned long long>()   const { return this->type_ == Type::UnsignedLongLong; }
460    template <> inline bool MultiType::MT_ValueBase::isType<float>()                const { return this->type_ == Type::Float;            }
461    template <> inline bool MultiType::MT_ValueBase::isType<double>()               const { return this->type_ == Type::Double;           }
462    template <> inline bool MultiType::MT_ValueBase::isType<long double>()          const { return this->type_ == Type::LongDouble;       }
463    template <> inline bool MultiType::MT_ValueBase::isType<bool>()                 const { return this->type_ == Type::Bool;             }
464    template <> inline bool MultiType::MT_ValueBase::isType<void*>()                const { return this->type_ == Type::VoidPointer;      }
465    template <> inline bool MultiType::MT_ValueBase::isType<std::string>()          const { return this->type_ == Type::String;           }
466    template <> inline bool MultiType::MT_ValueBase::isType<orxonox::Vector2>()     const { return this->type_ == Type::Vector2;          }
467    template <> inline bool MultiType::MT_ValueBase::isType<orxonox::Vector3>()     const { return this->type_ == Type::Vector3;          }
468    template <> inline bool MultiType::MT_ValueBase::isType<orxonox::Vector4>()     const { return this->type_ == Type::Vector4;          }
469    template <> inline bool MultiType::MT_ValueBase::isType<orxonox::ColourValue>() const { return this->type_ == Type::ColourValue;      }
470    template <> inline bool MultiType::MT_ValueBase::isType<orxonox::Quaternion>()  const { return this->type_ == Type::Quaternion;       }
471    template <> inline bool MultiType::MT_ValueBase::isType<orxonox::Radian>()      const { return this->type_ == Type::Radian;           }
472    template <> inline bool MultiType::MT_ValueBase::isType<orxonox::Degree>()      const { return this->type_ == Type::Degree;           }
473
474    template <> inline bool MultiType::set(const char* value)  { return this->set(std::string(value)); }
475    template <> inline bool MultiType::set(const mbool& value) { return this->set((bool)value); }
476
477    // Spezializations for void
478    template <> inline bool MultiType::isType<void>() const { return this->null(); }
479    template <> inline bool MultiType::convert<void>() { this->reset(); return true; }
480
481    template <> _UtilExport void MultiType::createNewValueContainer(const char& value);
482    template <> _UtilExport void MultiType::createNewValueContainer(const unsigned char& value);
483    template <> _UtilExport void MultiType::createNewValueContainer(const short& value);
484    template <> _UtilExport void MultiType::createNewValueContainer(const unsigned short& value);
485    template <> _UtilExport void MultiType::createNewValueContainer(const int& value);
486    template <> _UtilExport void MultiType::createNewValueContainer(const unsigned int& value);
487    template <> _UtilExport void MultiType::createNewValueContainer(const long& value);
488    template <> _UtilExport void MultiType::createNewValueContainer(const unsigned long& value);
489    template <> _UtilExport void MultiType::createNewValueContainer(const long long& value);
490    template <> _UtilExport void MultiType::createNewValueContainer(const unsigned long long& value);
491    template <> _UtilExport void MultiType::createNewValueContainer(const float& value);
492    template <> _UtilExport void MultiType::createNewValueContainer(const double& value);
493    template <> _UtilExport void MultiType::createNewValueContainer(const bool& value);
494    template <> _UtilExport void MultiType::createNewValueContainer(const long double& value);
495    template <> _UtilExport void MultiType::createNewValueContainer(      void* const& value);
496    template <> _UtilExport void MultiType::createNewValueContainer(const std::string& value);
497    template <> _UtilExport void MultiType::createNewValueContainer(const orxonox::Vector2& value);
498    template <> _UtilExport void MultiType::createNewValueContainer(const orxonox::Vector3& value);
499    template <> _UtilExport void MultiType::createNewValueContainer(const orxonox::Vector4& value);
500    template <> _UtilExport void MultiType::createNewValueContainer(const orxonox::ColourValue& value);
501    template <> _UtilExport void MultiType::createNewValueContainer(const orxonox::Quaternion& value);
502    template <> _UtilExport void MultiType::createNewValueContainer(const orxonox::Radian& value);
503    template <> _UtilExport void MultiType::createNewValueContainer(const orxonox::Degree& value);
504}
505
506#endif /* _MultiType_H__ */
Note: See TracBrowser for help on using the repository browser.