| #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; |
| }; |
| } DE_WARN_UNUSED_TYPE; |
| |
| 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 |