1#ifndef _TCUEITHER_HPP
2#define _TCUEITHER_HPP
3/*-------------------------------------------------------------------------
4 * drawElements Quality Program Tester Core
5 * ----------------------------------------
6 *
7 * Copyright 2015 The Android Open Source Project
8 *
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 *      http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 *
21 *//*!
22 * \file
23 * \brief Template class that is either type of First or Second.
24 *//*--------------------------------------------------------------------*/
25
26#include "tcuDefs.hpp"
27
28namespace tcu
29{
30
31/*--------------------------------------------------------------------*//*!
32 * \brief Object containing Either First or Second type of object
33 *
34 * \note Type First and Second are always aligned to same alignment as
35 * 		 deUint64.
36 * \note This type always uses at least sizeof(bool) + max(sizeof(First*),
37 * 		 sizeof(Second*)) + sizeof(deUint64) of memory.
38 *//*--------------------------------------------------------------------*/
39template<typename First, typename Second>
40class Either
41{
42public:
43					Either		(const First& first);
44					Either		(const Second& second);
45					~Either		(void);
46
47					Either		(const Either<First, Second>& other);
48	Either&			operator=	(const Either<First, Second>& other);
49
50	Either&			operator=	(const First& first);
51	Either&			operator=	(const Second& second);
52
53	bool			isFirst		(void) const;
54	bool			isSecond	(void) const;
55
56	const First&	getFirst	(void) const;
57	const Second&	getSecond	(void) const;
58
59	template<typename Type>
60	const Type&		get			(void) const;
61
62	template<typename Type>
63	bool			is			(void) const;
64
65private:
66	void			release		(void);
67
68	bool			m_isFirst;
69
70	union
71	{
72		First*		m_first;
73		Second*		m_second;
74	};
75
76	union
77	{
78		deUint8		m_data[sizeof(First) > sizeof(Second) ? sizeof(First) : sizeof(Second)];
79		deUint64	m_align;
80	};
81} DE_WARN_UNUSED_TYPE;
82
83namespace EitherDetail
84{
85
86template<typename Type, typename First, typename Second>
87struct Get;
88
89template<typename First, typename Second>
90struct Get<First, First, Second>
91{
92	static const First& get (const Either<First, Second>& either)
93	{
94		return either.getFirst();
95	}
96};
97
98template<typename First, typename Second>
99struct Get<Second, First, Second>
100{
101	static const Second& get (const Either<First, Second>& either)
102	{
103		return either.getSecond();
104	}
105};
106
107template<typename Type, typename First, typename Second>
108const Type& get (const Either<First, Second>& either)
109{
110	return Get<Type, First, Second>::get(either);
111}
112
113template<typename Type, typename First, typename Second>
114struct Is;
115
116template<typename First, typename Second>
117struct Is<First, First, Second>
118{
119	static bool is (const Either<First, Second>& either)
120	{
121		return either.isFirst();
122	}
123};
124
125template<typename First, typename Second>
126struct Is<Second, First, Second>
127{
128	static bool is (const Either<First, Second>& either)
129	{
130		return either.isSecond();
131	}
132};
133
134template<typename Type, typename First, typename Second>
135bool is (const Either<First, Second>& either)
136{
137	return Is<Type, First, Second>::is(either);
138}
139
140} // EitherDetail
141
142template<typename First, typename Second>
143void Either<First, Second>::release (void)
144{
145	if (m_isFirst)
146		m_first->~First();
147	else
148		m_second->~Second();
149
150	m_isFirst	= true;
151	m_first		= DE_NULL;
152}
153
154template<typename First, typename Second>
155Either<First, Second>::Either (const First& first)
156	: m_isFirst	(true)
157{
158	m_first = new(m_data)First(first);
159}
160
161template<typename First, typename Second>
162Either<First, Second>::Either (const Second& second)
163	: m_isFirst (false)
164{
165	m_second = new(m_data)Second(second);
166}
167
168template<typename First, typename Second>
169Either<First, Second>::~Either (void)
170{
171	release();
172}
173
174template<typename First, typename Second>
175Either<First, Second>::Either (const Either<First, Second>& other)
176	: m_isFirst	(other.m_isFirst)
177{
178	if (m_isFirst)
179		m_first = new(m_data)First(*other.m_first);
180	else
181		m_second = new(m_data)Second(*other.m_second);
182}
183
184template<typename First, typename Second>
185Either<First, Second>& Either<First, Second>::operator= (const Either<First, Second>& other)
186{
187	if (this == &other)
188		return *this;
189
190	release();
191
192	m_isFirst = other.m_isFirst;
193
194	if (m_isFirst)
195		m_first = new(m_data)First(*other.m_first);
196	else
197		m_second = new(m_data)Second(*other.m_second);
198
199	return *this;
200}
201
202template<typename First, typename Second>
203Either<First, Second>& Either<First, Second>::operator= (const First& first)
204{
205	release();
206
207	m_isFirst = true;
208	m_first = new(m_data)First(first);
209
210	return *this;
211}
212
213template<typename First, typename Second>
214Either<First, Second>& Either<First, Second>::operator= (const Second& second)
215{
216	release();
217
218	m_isFirst = false;
219	m_second = new(m_data)Second(second);
220
221	return *this;
222}
223
224template<typename First, typename Second>
225bool Either<First, Second>::isFirst (void) const
226{
227	return m_isFirst;
228}
229
230template<typename First, typename Second>
231bool Either<First, Second>::isSecond (void) const
232{
233	return !m_isFirst;
234}
235
236template<typename First, typename Second>
237const First& Either<First, Second>::getFirst (void) const
238{
239	DE_ASSERT(isFirst());
240	return *m_first;
241}
242
243template<typename First, typename Second>
244const Second& Either<First, Second>::getSecond (void) const
245{
246	DE_ASSERT(isSecond());
247	return *m_second;
248}
249
250template<typename First, typename Second>
251template<typename Type>
252const Type& Either<First, Second>::get (void) const
253{
254	return EitherDetail::get<Type, First, Second>(*this);
255}
256
257template<typename First, typename Second>
258template<typename Type>
259bool Either<First, Second>::is (void) const
260{
261	return EitherDetail::is<Type, First, Second>(*this);
262}
263
264void Either_selfTest (void);
265
266} // tcu
267
268#endif // _TCUEITHER_HPP
269