[Orxonox-commit 6345] r11002 - in code/branches/cpp11_v2: src/libraries/network/synchronisable src/libraries/util test/util
landauf at orxonox.net
landauf at orxonox.net
Wed Dec 30 21:13:15 CET 2015
Author: landauf
Date: 2015-12-30 21:13:14 +0100 (Wed, 30 Dec 2015)
New Revision: 11002
Modified:
code/branches/cpp11_v2/src/libraries/network/synchronisable/Synchronisable.h
code/branches/cpp11_v2/src/libraries/util/Math.h
code/branches/cpp11_v2/src/libraries/util/MultiType.h
code/branches/cpp11_v2/test/util/MultiTypeTest.cc
Log:
MultiType now supports strongly typed enum classes. Their values are cast to the underlying type.
MultiType now also uses additional static_asserts to ensure that it is only used with supported values.
Modified: code/branches/cpp11_v2/src/libraries/network/synchronisable/Synchronisable.h
===================================================================
--- code/branches/cpp11_v2/src/libraries/network/synchronisable/Synchronisable.h 2015-12-30 19:53:54 UTC (rev 11001)
+++ code/branches/cpp11_v2/src/libraries/network/synchronisable/Synchronisable.h 2015-12-30 20:13:14 UTC (rev 11002)
@@ -206,25 +206,25 @@
namespace detail
{
template <class T, bool = std::is_enum<T>::value>
- struct RealType;
+ struct UnderlyingType;
template <class T>
- struct RealType<T, true> { typedef typename std::underlying_type<T>::type type; };
+ struct UnderlyingType<T, true> { typedef typename std::underlying_type<T>::type type; };
template <class T>
- struct RealType<T, false> { typedef T type; };
+ struct UnderlyingType<T, false> { typedef T type; };
}
template <class T>
void Synchronisable::registerVariable(T& variable, uint8_t mode, NetworkCallbackBase *cb, bool bidirectional)
{
- typedef typename detail::RealType<T>::type RealType;
+ typedef typename detail::UnderlyingType<T>::type UnderlyingType;
if (bidirectional)
{
- syncList_.push_back(new SynchronisableVariableBidirectional<RealType>(reinterpret_cast<RealType&>(variable), mode, cb));
+ syncList_.push_back(new SynchronisableVariableBidirectional<UnderlyingType>(reinterpret_cast<UnderlyingType&>(variable), mode, cb));
this->dataSize_ += syncList_.back()->getSize(state_);
}
else
{
- syncList_.push_back(new SynchronisableVariable<RealType>(reinterpret_cast<RealType&>(variable), mode, cb));
+ syncList_.push_back(new SynchronisableVariable<UnderlyingType>(reinterpret_cast<UnderlyingType&>(variable), mode, cb));
if ( this->state_ == mode )
this->dataSize_ += syncList_.back()->getSize(state_);
}
@@ -254,12 +254,12 @@
template <class T>
void Synchronisable::registerVariable( std::set<T>& variable, uint8_t mode, NetworkCallbackBase *cb, bool bidirectional)
{
- typedef typename detail::RealType<T>::type RealType;
+ typedef typename detail::UnderlyingType<T>::type UnderlyingType;
SynchronisableVariableBase* sv;
if (bidirectional)
- sv = new SynchronisableVariableBidirectional<std::set<RealType>>(reinterpret_cast<std::set<RealType>&>(variable), mode, cb);
+ sv = new SynchronisableVariableBidirectional<std::set<UnderlyingType>>(reinterpret_cast<std::set<UnderlyingType>&>(variable), mode, cb);
else
- sv = new SynchronisableVariable<std::set<RealType>>(reinterpret_cast<std::set<RealType>&>(variable), mode, cb);
+ sv = new SynchronisableVariable<std::set<UnderlyingType>>(reinterpret_cast<std::set<UnderlyingType>&>(variable), mode, cb);
syncList_.push_back(sv);
stringList_.push_back(sv);
}
Modified: code/branches/cpp11_v2/src/libraries/util/Math.h
===================================================================
--- code/branches/cpp11_v2/src/libraries/util/Math.h 2015-12-30 19:53:54 UTC (rev 11001)
+++ code/branches/cpp11_v2/src/libraries/util/Math.h 2015-12-30 20:13:14 UTC (rev 11002)
@@ -46,6 +46,7 @@
#include <cmath>
#include <cstdlib>
#include <random>
+#include <type_traits>
#include <OgreMath.h>
#include <OgreVector2.h>
@@ -177,12 +178,18 @@
for @c float it's 0.0f. For a @c std::string the function returns "" and for
@c Vector3 you get <tt>Vector3(0, 0, 0)</tt>.
*/
- template <typename T>
- inline T zeroise()
+ template <typename T> /* for normal classes */ typename std::enable_if<!std::is_enum<T>::value, T>::type
+ inline /*T*/ zeroise()
{
// If you reach this code, you abused zeroise()!
static_assert(sizeof(T) != sizeof(T), "No template specialization available for T");
}
+ /// Implementation for enum classes: uses the underlying type to create a zero value.
+ template <typename T> /* for enum classes */ typename std::enable_if<std::is_enum<T>::value, T>::type
+ inline /*T*/ zeroise()
+ {
+ return static_cast<T>(zeroise<typename std::underlying_type<T>::type>());
+ }
template <> inline char zeroise<char>() { return 0; }
template <> inline unsigned char zeroise<unsigned char>() { return 0; }
Modified: code/branches/cpp11_v2/src/libraries/util/MultiType.h
===================================================================
--- code/branches/cpp11_v2/src/libraries/util/MultiType.h 2015-12-30 19:53:54 UTC (rev 11001)
+++ code/branches/cpp11_v2/src/libraries/util/MultiType.h 2015-12-30 20:13:14 UTC (rev 11002)
@@ -182,9 +182,22 @@
/// Returns the type of the current value.
inline const Type::Enum& getType() const { return this->type_; }
- /// Returns true if the type of the stored value is T.
- template <typename T> inline bool isType() const { return false; }
+ /// Returns true if the type of the stored value is T. Note: the actual implementations for all supported types are defined outside of the class.
+ template <typename T> /* for normal classes */ typename std::enable_if<!std::is_enum<T>::value, bool>::type
+ inline /*bool*/ isType() const
+ {
+ // If you reach this code, you used MultiType with an unsupported type T
+ static_assert(sizeof(T) != sizeof(T), "No template specialization available for T");
+ return false;
+ }
+ /// Implementation for enum classes: Returns true if the type of the stored value is the underlying type of T.
+ template <typename T> /* for enum classes */ typename std::enable_if<std::is_enum<T>::value, bool>::type
+ inline /*bool*/ isType() const
+ {
+ return this->isType<typename std::underlying_type<T>::type>();
+ }
+
/// Checks whether the value is a default one.
inline bool lastConversionSuccessful() const { return this->bLastConversionSuccessful; }
@@ -214,6 +227,20 @@
virtual bool setValue(const MultiType& other) = 0;
+ template <typename T> /* for normal classes */ typename std::enable_if<!std::is_enum<T>::value, bool>::type
+ inline /*bool*/ setValue(const T& value)
+ {
+ // If you reach this code, you used MultiType with an unsupported type T
+ static_assert(sizeof(T) != sizeof(T), "No template specialization available for T");
+ return false;
+ }
+ template <typename T> /* for enum classes */ typename std::enable_if<std::is_enum<T>::value, bool>::type
+ inline /*bool*/ setValue(const T& value)
+ {
+ typedef typename std::underlying_type<T>::type UnderlyingType;
+ return this->setValue(reinterpret_cast<const UnderlyingType&>(value));
+ }
+
virtual bool getValue(char* value) const = 0;
virtual bool getValue(unsigned char* value) const = 0;
virtual bool getValue(short* value) const = 0;
@@ -238,6 +265,20 @@
virtual bool getValue(orxonox::Radian* value) const = 0;
virtual bool getValue(orxonox::Degree* value) const = 0;
+ template <typename T> /* for normal classes */ typename std::enable_if<!std::is_enum<T>::value, bool>::type
+ inline /*bool*/ getValue(T* value) const
+ {
+ // If you reach this code, you used MultiType with an unsupported type T
+ static_assert(sizeof(T) != sizeof(T), "No template specialization available for T");
+ return false;
+ }
+ template <typename T> /* for enum classes */ typename std::enable_if<std::is_enum<T>::value, bool>::type
+ inline /*bool*/ getValue(T* value) const
+ {
+ typedef typename std::underlying_type<T>::type UnderlyingType;
+ return this->getValue(reinterpret_cast<UnderlyingType*>(value));
+ }
+
template <typename T> T get() const
{
if (this->isType<T>())
@@ -430,11 +471,19 @@
this->createNewValueContainer(value);
}
/// Creates a new value container (works only with specialized types).
- template <typename T> inline void createNewValueContainer(const T& value)
+ template <typename T> /* for normal classes */ typename std::enable_if<!std::is_enum<T>::value>::type
+ inline /*void*/ createNewValueContainer(const T& value)
{
// If you reach this code, you used MultiType with an unsupported type T
static_assert(sizeof(T) != sizeof(T), "No template specialization available for T");
}
+ /// Creates a new value container (implementation for enum classes that must be cast to the underlying type).
+ template <typename T> /* for enum classes */ typename std::enable_if<std::is_enum<T>::value>::type
+ inline /*void*/ createNewValueContainer(const T& value)
+ {
+ typedef typename std::underlying_type<T>::type UnderlyingType;
+ this->createNewValueContainer<UnderlyingType>(reinterpret_cast<const UnderlyingType&>(value));
+ }
MT_ValueBase* value_; //!< A pointer to the value container
};
Modified: code/branches/cpp11_v2/test/util/MultiTypeTest.cc
===================================================================
--- code/branches/cpp11_v2/test/util/MultiTypeTest.cc 2015-12-30 19:53:54 UTC (rev 11001)
+++ code/branches/cpp11_v2/test/util/MultiTypeTest.cc 2015-12-30 20:13:14 UTC (rev 11002)
@@ -696,4 +696,243 @@
EXPECT_TRUE(mt.null());
}
+
+ ///////////////////////////////
+ // Strongly typed enum class //
+ ///////////////////////////////
+ enum class EnumWithChar : unsigned char
+ {
+ ValueA = 'A',
+ ValueB = 'B',
+ ValueC = 'C',
+ };
+ enum class EnumWithInt
+ {
+ Value1 = 50,
+ Value2 = 0,
+ Value3,
+ };
+
+ TEST(MultiType, Enum_Constructor)
+ {
+ // Constructor:
+ {
+ MultiType mt = EnumWithChar::ValueA;
+
+ EXPECT_TRUE(mt.isType<EnumWithChar>());
+ EXPECT_EQ(EnumWithChar::ValueA, mt.get<EnumWithChar>());
+ }
+ {
+ MultiType mt = MultiType(EnumWithInt::Value1);
+
+ EXPECT_TRUE(mt.isType<EnumWithInt>());
+ EXPECT_EQ(EnumWithInt::Value1, mt.get<EnumWithInt>());
+ }
+ }
+
+ TEST(MultiType, Enum_Assignment)
+ {
+ // operator=:
+ MultiType mt;
+ mt = EnumWithChar::ValueB;
+
+ EXPECT_TRUE(mt.isType<EnumWithChar>());
+ EXPECT_EQ(EnumWithChar::ValueB, mt.get<EnumWithChar>());
+ }
+
+ TEST(MultiType, Enum_Set)
+ {
+ // set(value):
+ {
+ MultiType mt;
+ mt.set(EnumWithInt::Value2); // assign enum to an empty MultiType
+
+ EXPECT_TRUE(mt.isType<EnumWithInt>());
+ EXPECT_EQ(EnumWithInt::Value2, mt.get<EnumWithInt>());
+ }
+ {
+ MultiType mt = "string";
+ mt.set(EnumWithChar::ValueC); // assign enum to a MultiType with type std::string
+
+ EXPECT_TRUE(mt.isType<std::string>());
+ EXPECT_EQ("C", mt.get<std::string>());
+ }
+ {
+ MultiType mt = EnumWithChar::ValueA;
+ mt.set(EnumWithChar::ValueB); // assign enum to a MultiType with type std::string
+
+ EXPECT_TRUE(mt.isType<EnumWithChar>());
+ EXPECT_EQ(EnumWithChar::ValueB, mt.get<EnumWithChar>());
+ }
+ {
+ MultiType mt = EnumWithInt::Value3;
+ mt.set("50"); // assign enum to a MultiType with type std::string
+
+ EXPECT_TRUE(mt.isType<EnumWithInt>());
+ EXPECT_EQ(EnumWithInt::Value1, mt.get<EnumWithInt>());
+ }
+ }
+
+ TEST(MultiType, Enum_Force)
+ {
+ // force(value):
+ {
+ MultiType mt = "string";
+ EXPECT_TRUE(mt.isType<std::string>());
+ EXPECT_EQ("string", mt.get<std::string>());
+
+ mt.force<EnumWithChar>("C");
+
+ EXPECT_TRUE(mt.isType<EnumWithChar>());
+ EXPECT_EQ(EnumWithChar::ValueC, mt.get<EnumWithChar>());
+ }
+ {
+ MultiType mt = EnumWithChar::ValueA;
+ EXPECT_TRUE(mt.isType<EnumWithChar>());
+ EXPECT_EQ(EnumWithChar::ValueA, mt.get<EnumWithChar>());
+
+ mt.force<std::string>(EnumWithChar::ValueB);
+
+ EXPECT_TRUE(mt.isType<std::string>());
+ EXPECT_EQ("B", mt.get<std::string>());
+ }
+ }
+
+ TEST(MultiType, Enum_Convert)
+ {
+ // convert():
+ {
+ MultiType mt = "C";
+ mt.convert<EnumWithChar>();
+
+ EXPECT_TRUE(mt.isType<EnumWithChar>());
+ EXPECT_EQ(EnumWithChar::ValueC, mt.get<EnumWithChar>());
+ }
+ {
+ MultiType mt = EnumWithChar::ValueA;
+ mt.convert<std::string>();
+
+ EXPECT_TRUE(mt.isType<std::string>());
+ EXPECT_EQ("A", mt.get<std::string>());
+ }
+ }
+
+ TEST(MultiType, Enum_Reset)
+ {
+ // reset():
+ {
+ MultiType mt = EnumWithChar::ValueA;
+ mt.reset<EnumWithChar>();
+
+ EXPECT_TRUE(mt.isType<EnumWithChar>());
+ EXPECT_TRUE(mt.isType<unsigned char>());
+ EXPECT_EQ('\0', mt.get<unsigned char>());
+ }
+ {
+ MultiType mt = "string";
+ mt.reset<EnumWithInt>();
+
+ EXPECT_TRUE(mt.isType<EnumWithInt>());
+ EXPECT_TRUE(mt.isType<int>());
+ EXPECT_EQ(0, mt.get<int>());
+ }
+ }
+
+ TEST(MultiType, Enum_IsType)
+ {
+ // isType():
+ {
+ MultiType mt = EnumWithChar::ValueB;
+ EXPECT_TRUE(mt.isType<EnumWithChar>());
+ EXPECT_TRUE(mt.isType<unsigned char>());
+ EXPECT_FALSE(mt.isType<char>());
+ EXPECT_FALSE(mt.isType<int>());
+ EXPECT_FALSE(mt.isType<bool>());
+ EXPECT_FALSE(mt.isType<std::string>());
+ }
+ {
+ MultiType mt = EnumWithInt::Value3;
+ EXPECT_TRUE(mt.isType<EnumWithInt>());
+ EXPECT_TRUE(mt.isType<int>());
+ EXPECT_FALSE(mt.isType<unsigned char>());
+ EXPECT_FALSE(mt.isType<char>());
+ EXPECT_FALSE(mt.isType<bool>());
+ EXPECT_FALSE(mt.isType<std::string>());
+ }
+ }
+
+ TEST(MultiType, Enum_ConversionOperator)
+ {
+ // conversion operator:
+ {
+ MultiType mt = EnumWithChar::ValueA;
+ EnumWithChar value = mt;
+ EXPECT_EQ(EnumWithChar::ValueA, value);
+ }
+ {
+ MultiType mt = 'B';
+ EnumWithChar value = mt;
+ EXPECT_EQ(EnumWithChar::ValueB, value);
+ }
+ {
+ MultiType mt = EnumWithInt::Value1;
+ std::string value = mt;
+ EXPECT_EQ("50", value);
+ }
+ }
+
+ TEST(MultiType, Enum_GetValue)
+ {
+ // getValue():
+ {
+ MultiType mt = EnumWithChar::ValueA;
+ EnumWithChar value;
+ mt.getValue(&value);
+ EXPECT_EQ(EnumWithChar::ValueA, value);
+ }
+ {
+ MultiType mt = 'B';
+ EnumWithChar value;
+ mt.getValue(&value);
+ EXPECT_EQ(EnumWithChar::ValueB, value);
+ }
+ {
+ MultiType mt = EnumWithInt::Value1;
+ std::string value;
+ mt.getValue(&value);
+ EXPECT_EQ("50", value);
+ }
+ }
+
+ TEST(MultiType, Enum_Get)
+ {
+ // get():
+ {
+ MultiType mt = EnumWithChar::ValueB;
+ EXPECT_EQ(EnumWithChar::ValueB, mt.get<EnumWithChar>());
+
+ EXPECT_EQ('B', mt.get<unsigned char>());
+ EXPECT_EQ("B", mt.get<std::string>());
+ EXPECT_EQ(66, mt.get<int>());
+ EXPECT_TRUE(mt.get<bool>());
+ }
+ {
+ MultiType mt = EnumWithInt::Value1;
+ EXPECT_EQ(EnumWithInt::Value1, mt.get<EnumWithInt>());
+
+ EXPECT_EQ('2', mt.get<unsigned char>());
+ EXPECT_EQ("50", mt.get<std::string>());
+ EXPECT_EQ(50, mt.get<int>());
+ EXPECT_TRUE(mt.get<bool>());
+ }
+ {
+ MultiType mt = EnumWithInt::Value2;
+ EXPECT_EQ(EnumWithInt::Value2, mt.get<EnumWithInt>());
+
+ EXPECT_EQ('\0', mt.get<unsigned char>());
+ EXPECT_EQ("0", mt.get<std::string>());
+ EXPECT_EQ(0, mt.get<int>());
+ EXPECT_FALSE(mt.get<bool>());
+ }
+ }
}
More information about the Orxonox-commit
mailing list