blob: 7791a702b3be517c965679d73942f8b3385bee40 [file] [log] [blame]
#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 <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
{
uint8_t m_data[sizeof(First) > sizeof(Second) ? sizeof(First) : sizeof(Second)];
uint64_t 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);
}
} // namespace 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);
} // namespace tcu
#endif // _TCUEITHER_HPP