Add tcuEither that contains one of two different types.
authorMika Isojärvi <misojarvi@google.com>
Wed, 28 Jan 2015 21:46:17 +0000 (13:46 -0800)
committerMika Isojärvi <misojarvi@google.com>
Thu, 12 Feb 2015 00:33:57 +0000 (16:33 -0800)
tcuEither class contains one of two different types. Basicly it works
like union with two types, but also tracks which one it contains.

Change-Id: I2183c2dcc947b1a3c6af6abd6dca37318c32107e

Android.mk
framework/common/CMakeLists.txt
framework/common/tcuEither.cpp [new file with mode: 0644]
framework/common/tcuEither.hpp [new file with mode: 0644]
modules/internal/ditFrameworkTests.cpp

index 4d3e6d5..9a69f89 100644 (file)
@@ -49,6 +49,7 @@ LOCAL_SRC_FILES := \
        framework/common/tcuRenderTarget.cpp \
        framework/common/tcuResource.cpp \
        framework/common/tcuRGBA.cpp \
+       framework/common/tcuEither.cpp \
        framework/common/tcuStringTemplate.cpp \
        framework/common/tcuSurface.cpp \
        framework/common/tcuTestCase.cpp \
index 9f5bd47..4396797 100644 (file)
@@ -77,6 +77,8 @@ set(TCUTIL_SRCS
        tcuSeedBuilder.cpp
        tcuMaybe.hpp
        tcuMaybe.cpp
+       tcuEither.hpp
+       tcuEither.cpp
        )
 
 set(TCUTIL_LIBS
diff --git a/framework/common/tcuEither.cpp b/framework/common/tcuEither.cpp
new file mode 100644 (file)
index 0000000..64b9737
--- /dev/null
@@ -0,0 +1,297 @@
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program Tester Core
+ * ----------------------------------------
+ *
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Template class that is either type of Left or Right.
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuEither.hpp"
+
+namespace tcu
+{
+namespace
+{
+
+enum
+{
+       COPYCHECK_VALUE = 1637423219
+};
+
+class TestClassWithConstructor
+{
+public:
+       TestClassWithConstructor (int i)
+               : m_i                   (i)
+               , m_copyCheck   (COPYCHECK_VALUE)
+       {
+       }
+
+       ~TestClassWithConstructor (void)
+       {
+               TCU_CHECK(m_copyCheck == COPYCHECK_VALUE);
+       }
+
+       TestClassWithConstructor (const TestClassWithConstructor& other)
+               : m_i                   (other.m_i)
+               , m_copyCheck   (other.m_copyCheck)
+       {
+       }
+
+       TestClassWithConstructor& operator= (const TestClassWithConstructor& other)
+       {
+               TCU_CHECK(m_copyCheck == COPYCHECK_VALUE);
+
+               if (this == &other)
+                       return *this;
+
+               m_i = other.m_i;
+               m_copyCheck = other.m_copyCheck;
+
+               TCU_CHECK(m_copyCheck == COPYCHECK_VALUE);
+
+               return *this;
+       }
+
+       int getValue (void) const
+       {
+               TCU_CHECK(m_copyCheck == COPYCHECK_VALUE);
+
+               return m_i;
+       }
+
+private:
+       int m_i;
+       int m_copyCheck;
+};
+
+} // anonymous
+
+void Either_selfTest (void)
+{
+       // Simple test for first
+       {
+               const int                                       intValue        = 1503457782;
+               const Either<int, float>        either          (intValue);
+
+               TCU_CHECK(either.isFirst());
+               TCU_CHECK(!either.isSecond());
+
+               TCU_CHECK(either.is<int>());
+               TCU_CHECK(!either.is<float>());
+
+               TCU_CHECK(either.getFirst() == intValue);
+               TCU_CHECK(either.get<int>() == intValue);
+       }
+
+       // Simple test for second
+       {
+               const float                                     floatValue      = 0.43223332995f;
+               const Either<int, float>        either          (floatValue);
+
+               TCU_CHECK(!either.isFirst());
+               TCU_CHECK(either.isSecond());
+
+               TCU_CHECK(!either.is<int>());
+               TCU_CHECK(either.is<float>());
+
+               TCU_CHECK(either.getSecond() == floatValue);
+               TCU_CHECK(either.get<float>() == floatValue);
+       }
+
+       // Assign first value
+       {
+               const int                       intValue        = 1942092699;
+               const float                     floatValue      = 0.43223332995f;
+               Either<int, float>      either          (floatValue);
+
+               either = intValue;
+
+               TCU_CHECK(either.isFirst());
+               TCU_CHECK(!either.isSecond());
+
+               TCU_CHECK(either.is<int>());
+               TCU_CHECK(!either.is<float>());
+
+               TCU_CHECK(either.getFirst() == intValue);
+               TCU_CHECK(either.get<int>() == intValue);
+       }
+
+       // Assign second value
+       {
+               const int                       intValue        = 1942092699;
+               const float                     floatValue      = 0.43223332995f;
+               Either<int, float>      either          (intValue);
+
+               either = floatValue;
+
+               TCU_CHECK(!either.isFirst());
+               TCU_CHECK(either.isSecond());
+
+               TCU_CHECK(!either.is<int>());
+               TCU_CHECK(either.is<float>());
+
+               TCU_CHECK(either.getSecond() == floatValue);
+               TCU_CHECK(either.get<float>() == floatValue);
+       }
+
+       // Assign first either value
+       {
+               const int                                       intValue        = 1942092699;
+               const float                                     floatValue      = 0.43223332995f;
+               Either<int, float>                      either          (floatValue);
+               const Either<int, float>        otherEither     (intValue);
+
+               either = otherEither;
+
+               TCU_CHECK(either.isFirst());
+               TCU_CHECK(!either.isSecond());
+
+               TCU_CHECK(either.is<int>());
+               TCU_CHECK(!either.is<float>());
+
+               TCU_CHECK(either.getFirst() == intValue);
+               TCU_CHECK(either.get<int>() == intValue);
+       }
+
+       // Assign second either value
+       {
+               const int                                       intValue        = 1942092699;
+               const float                                     floatValue      = 0.43223332995f;
+               Either<int, float>                      either          (intValue);
+               const Either<int, float>        otherEither     (floatValue);
+
+               either = otherEither;
+
+               TCU_CHECK(!either.isFirst());
+               TCU_CHECK(either.isSecond());
+
+               TCU_CHECK(!either.is<int>());
+               TCU_CHECK(either.is<float>());
+
+               TCU_CHECK(either.getSecond() == floatValue);
+               TCU_CHECK(either.get<float>() == floatValue);
+       }
+
+       // Simple test for first with constructor
+       {
+               const TestClassWithConstructor                          testObject      (171899615);
+               const Either<TestClassWithConstructor, int>     either          (testObject);
+
+               TCU_CHECK(either.isFirst());
+               TCU_CHECK(!either.isSecond());
+
+               TCU_CHECK(either.is<TestClassWithConstructor>());
+               TCU_CHECK(!either.is<int>());
+
+               TCU_CHECK(either.getFirst().getValue() == testObject.getValue());
+               TCU_CHECK(either.get<TestClassWithConstructor>().getValue() == testObject.getValue());
+       }
+
+       // Simple test for second with constructor
+       {
+               const TestClassWithConstructor                          testObject      (171899615);
+               const Either<int, TestClassWithConstructor>     either          (testObject);
+
+               TCU_CHECK(!either.isFirst());
+               TCU_CHECK(either.isSecond());
+
+               TCU_CHECK(either.is<TestClassWithConstructor>());
+               TCU_CHECK(!either.is<int>());
+
+               TCU_CHECK(either.getSecond().getValue() == testObject.getValue());
+               TCU_CHECK(either.get<TestClassWithConstructor>().getValue() == testObject.getValue());
+       }
+
+       // Assign first with constructor
+       {
+               const int                                                               intValue        = 1942092699;
+               const TestClassWithConstructor                  testObject      (171899615);
+               Either<TestClassWithConstructor, int>   either          (intValue);
+
+               either = testObject;
+
+               TCU_CHECK(either.isFirst());
+               TCU_CHECK(!either.isSecond());
+
+               TCU_CHECK(either.is<TestClassWithConstructor>());
+               TCU_CHECK(!either.is<int>());
+
+               TCU_CHECK(either.getFirst().getValue() == testObject.getValue());
+               TCU_CHECK(either.get<TestClassWithConstructor>().getValue() == testObject.getValue());
+       }
+
+       // Assign second with constructor
+       {
+               const int                                                               intValue        = 1942092699;
+               const TestClassWithConstructor                  testObject      (171899615);
+               Either<int, TestClassWithConstructor>   either          (intValue);
+
+               either = testObject;
+
+               TCU_CHECK(!either.isFirst());
+               TCU_CHECK(either.isSecond());
+
+               TCU_CHECK(either.is<TestClassWithConstructor>());
+               TCU_CHECK(!either.is<int>());
+
+               TCU_CHECK(either.getSecond().getValue() == testObject.getValue());
+               TCU_CHECK(either.get<TestClassWithConstructor>().getValue() == testObject.getValue());
+       }
+
+       // Assign first either with constructor
+       {
+               const int                                                                       intValue        = 1942092699;
+               const TestClassWithConstructor                          testObject      (171899615);
+               Either<TestClassWithConstructor, int>           either          (intValue);
+               const Either<TestClassWithConstructor, int>     otherEither     (testObject);
+
+               either = otherEither;
+
+               TCU_CHECK(either.isFirst());
+               TCU_CHECK(!either.isSecond());
+
+               TCU_CHECK(either.is<TestClassWithConstructor>());
+               TCU_CHECK(!either.is<int>());
+
+               TCU_CHECK(either.getFirst().getValue() == testObject.getValue());
+               TCU_CHECK(either.get<TestClassWithConstructor>().getValue() == testObject.getValue());
+       }
+
+       // Assign second either with constructor
+       {
+               const int                                                                       intValue        = 1942092699;
+               const TestClassWithConstructor                          testObject      (171899615);
+               Either<int, TestClassWithConstructor>           either          (intValue);
+               const Either<int, TestClassWithConstructor>     otherEither     (testObject);
+
+
+               either = testObject;
+
+               TCU_CHECK(!either.isFirst());
+               TCU_CHECK(either.isSecond());
+
+               TCU_CHECK(either.is<TestClassWithConstructor>());
+               TCU_CHECK(!either.is<int>());
+
+               TCU_CHECK(either.getSecond().getValue() == testObject.getValue());
+               TCU_CHECK(either.get<TestClassWithConstructor>().getValue() == testObject.getValue());
+       }
+}
+
+} // tcu
diff --git a/framework/common/tcuEither.hpp b/framework/common/tcuEither.hpp
new file mode 100644 (file)
index 0000000..47a3c49
--- /dev/null
@@ -0,0 +1,268 @@
+#ifndef _TCUEITHER_HPP
+#define _TCUEITHER_HPP
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program Tester Core
+ * ----------------------------------------
+ *
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Template class that is either type of First or Second.
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+
+namespace tcu
+{
+
+/*--------------------------------------------------------------------*//*!
+ * \brief Object containing Either First or Second type of object
+ *
+ * \note Type First and Second are always aligned to same alignment as
+ *              deUint64.
+ * \note This type always uses at least sizeof(bool) + max(sizeof(First*),
+ *              sizeof(Second*)) + sizeof(deUint64) of memory.
+ *//*--------------------------------------------------------------------*/
+template<typename First, typename Second>
+class Either
+{
+public:
+                                       Either          (const First& first);
+                                       Either          (const Second& second);
+                                       ~Either         (void);
+
+                                       Either          (const Either<First, Second>& other);
+       Either&                 operator=       (const Either<First, Second>& other);
+
+       Either&                 operator=       (const First& first);
+       Either&                 operator=       (const Second& second);
+
+       bool                    isFirst         (void) const;
+       bool                    isSecond        (void) const;
+
+       const First&    getFirst        (void) const;
+       const Second&   getSecond       (void) const;
+
+       template<typename Type>
+       const Type&             get                     (void) const;
+
+       template<typename Type>
+       bool                    is                      (void) const;
+
+private:
+       void                    release         (void);
+
+       bool                    m_isFirst;
+
+       union
+       {
+               First*          m_first;
+               Second*         m_second;
+       };
+
+       union
+       {
+               deUint8         m_data[sizeof(First) > sizeof(Second) ? sizeof(First) : sizeof(Second)];
+               deUint64        m_align;
+       };
+};
+
+namespace EitherDetail
+{
+
+template<typename Type, typename First, typename Second>
+struct Get;
+
+template<typename First, typename Second>
+struct Get<First, First, Second>
+{
+       static const First& get (const Either<First, Second>& either)
+       {
+               return either.getFirst();
+       }
+};
+
+template<typename First, typename Second>
+struct Get<Second, First, Second>
+{
+       static const Second& get (const Either<First, Second>& either)
+       {
+               return either.getSecond();
+       }
+};
+
+template<typename Type, typename First, typename Second>
+const Type& get (const Either<First, Second>& either)
+{
+       return Get<Type, First, Second>::get(either);
+}
+
+template<typename Type, typename First, typename Second>
+struct Is;
+
+template<typename First, typename Second>
+struct Is<First, First, Second>
+{
+       static bool is (const Either<First, Second>& either)
+       {
+               return either.isFirst();
+       }
+};
+
+template<typename First, typename Second>
+struct Is<Second, First, Second>
+{
+       static bool is (const Either<First, Second>& either)
+       {
+               return either.isSecond();
+       }
+};
+
+template<typename Type, typename First, typename Second>
+bool is (const Either<First, Second>& either)
+{
+       return Is<Type, First, Second>::is(either);
+}
+
+} // EitherDetail
+
+template<typename First, typename Second>
+void Either<First, Second>::release (void)
+{
+       if (m_isFirst)
+               m_first->~First();
+       else
+               m_second->~Second();
+
+       m_isFirst       = true;
+       m_first         = DE_NULL;
+}
+
+template<typename First, typename Second>
+Either<First, Second>::Either (const First& first)
+       : m_isFirst     (true)
+{
+       m_first = new(m_data)First(first);
+}
+
+template<typename First, typename Second>
+Either<First, Second>::Either (const Second& second)
+       : m_isFirst (false)
+{
+       m_second = new(m_data)Second(second);
+}
+
+template<typename First, typename Second>
+Either<First, Second>::~Either (void)
+{
+       release();
+}
+
+template<typename First, typename Second>
+Either<First, Second>::Either (const Either<First, Second>& other)
+       : m_isFirst     (other.m_isFirst)
+{
+       if (m_isFirst)
+               m_first = new(m_data)First(*other.m_first);
+       else
+               m_second = new(m_data)Second(*other.m_second);
+}
+
+template<typename First, typename Second>
+Either<First, Second>& Either<First, Second>::operator= (const Either<First, Second>& other)
+{
+       if (this == &other)
+               return *this;
+
+       release();
+
+       m_isFirst = other.m_isFirst;
+
+       if (m_isFirst)
+               m_first = new(m_data)First(*other.m_first);
+       else
+               m_second = new(m_data)Second(*other.m_second);
+
+       return *this;
+}
+
+template<typename First, typename Second>
+Either<First, Second>& Either<First, Second>::operator= (const First& first)
+{
+       release();
+
+       m_isFirst = true;
+       m_first = new(m_data)First(first);
+
+       return *this;
+}
+
+template<typename First, typename Second>
+Either<First, Second>& Either<First, Second>::operator= (const Second& second)
+{
+       release();
+
+       m_isFirst = false;
+       m_second = new(m_data)Second(second);
+
+       return *this;
+}
+
+template<typename First, typename Second>
+bool Either<First, Second>::isFirst (void) const
+{
+       return m_isFirst;
+}
+
+template<typename First, typename Second>
+bool Either<First, Second>::isSecond (void) const
+{
+       return !m_isFirst;
+}
+
+template<typename First, typename Second>
+const First& Either<First, Second>::getFirst (void) const
+{
+       DE_ASSERT(isFirst());
+       return *m_first;
+}
+
+template<typename First, typename Second>
+const Second& Either<First, Second>::getSecond (void) const
+{
+       DE_ASSERT(isSecond());
+       return *m_second;
+}
+
+template<typename First, typename Second>
+template<typename Type>
+const Type& Either<First, Second>::get (void) const
+{
+       return EitherDetail::get<Type, First, Second>(*this);
+}
+
+template<typename First, typename Second>
+template<typename Type>
+bool Either<First, Second>::is (void) const
+{
+       return EitherDetail::is<Type, First, Second>(*this);
+}
+
+void Either_selfTest (void);
+
+} // tcu
+
+#endif // _TCUEITHER_HPP
index 1061668..ec8f241 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "ditFrameworkTests.hpp"
 #include "tcuFloatFormat.hpp"
+#include "tcuEither.hpp"
 #include "tcuTestLog.hpp"
 #include "tcuCommandLine.hpp"
 
@@ -556,6 +557,8 @@ public:
        {
                addChild(new SelfCheckCase(m_testCtx, "float_format","tcu::FloatFormat_selfTest()",
                                                                   tcu::FloatFormat_selfTest));
+               addChild(new SelfCheckCase(m_testCtx, "either","tcu::Either_selfTest()",
+                                                                  tcu::Either_selfTest));
        }
 };