#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 * uint64_t. * \note This type always uses at least sizeof(bool) + max(sizeof(First*), * sizeof(Second*)) + sizeof(uint64_t) of memory. *//*--------------------------------------------------------------------*/ template class Either { public: Either(const First &first); Either(const Second &second); ~Either(void); Either(const Either &other); Either &operator=(const Either &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 const Type &get(void) const; template bool is(void) const; private: void release(void); bool m_isFirst; union { First *m_first; Second *m_second; }; union { uint8_t m_data[sizeof(First) > sizeof(Second) ? sizeof(First) : sizeof(Second)]; uint64_t m_align; }; } DE_WARN_UNUSED_TYPE; namespace EitherDetail { template struct Get; template struct Get { static const First &get(const Either &either) { return either.getFirst(); } }; template struct Get { static const Second &get(const Either &either) { return either.getSecond(); } }; template const Type &get(const Either &either) { return Get::get(either); } template struct Is; template struct Is { static bool is(const Either &either) { return either.isFirst(); } }; template struct Is { static bool is(const Either &either) { return either.isSecond(); } }; template bool is(const Either &either) { return Is::is(either); } } // namespace EitherDetail template void Either::release(void) { if (m_isFirst) m_first->~First(); else m_second->~Second(); m_isFirst = true; m_first = DE_NULL; } template Either::Either(const First &first) : m_isFirst(true) { m_first = new (m_data) First(first); } template Either::Either(const Second &second) : m_isFirst(false) { m_second = new (m_data) Second(second); } template Either::~Either(void) { release(); } template Either::Either(const Either &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 Either &Either::operator=(const Either &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 Either &Either::operator=(const First &first) { release(); m_isFirst = true; m_first = new (m_data) First(first); return *this; } template Either &Either::operator=(const Second &second) { release(); m_isFirst = false; m_second = new (m_data) Second(second); return *this; } template bool Either::isFirst(void) const { return m_isFirst; } template bool Either::isSecond(void) const { return !m_isFirst; } template const First &Either::getFirst(void) const { DE_ASSERT(isFirst()); return *m_first; } template const Second &Either::getSecond(void) const { DE_ASSERT(isSecond()); return *m_second; } template template const Type &Either::get(void) const { return EitherDetail::get(*this); } template template bool Either::is(void) const { return EitherDetail::is(*this); } void Either_selfTest(void); } // namespace tcu #endif // _TCUEITHER_HPP