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 
28 namespace 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  *//*--------------------------------------------------------------------*/
39 template<typename First, typename Second>
40 class Either
41 {
42 public:
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 
65 private:
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 
83 namespace EitherDetail
84 {
85 
86 template<typename Type, typename First, typename Second>
87 struct Get;
88 
89 template<typename First, typename Second>
90 struct Get<First, First, Second>
91 {
gettcu::EitherDetail::Get92 	static const First& get (const Either<First, Second>& either)
93 	{
94 		return either.getFirst();
95 	}
96 };
97 
98 template<typename First, typename Second>
99 struct Get<Second, First, Second>
100 {
gettcu::EitherDetail::Get101 	static const Second& get (const Either<First, Second>& either)
102 	{
103 		return either.getSecond();
104 	}
105 };
106 
107 template<typename Type, typename First, typename Second>
get(const Either<First,Second> & either)108 const Type& get (const Either<First, Second>& either)
109 {
110 	return Get<Type, First, Second>::get(either);
111 }
112 
113 template<typename Type, typename First, typename Second>
114 struct Is;
115 
116 template<typename First, typename Second>
117 struct Is<First, First, Second>
118 {
istcu::EitherDetail::Is119 	static bool is (const Either<First, Second>& either)
120 	{
121 		return either.isFirst();
122 	}
123 };
124 
125 template<typename First, typename Second>
126 struct Is<Second, First, Second>
127 {
istcu::EitherDetail::Is128 	static bool is (const Either<First, Second>& either)
129 	{
130 		return either.isSecond();
131 	}
132 };
133 
134 template<typename Type, typename First, typename Second>
is(const Either<First,Second> & either)135 bool is (const Either<First, Second>& either)
136 {
137 	return Is<Type, First, Second>::is(either);
138 }
139 
140 } // EitherDetail
141 
142 template<typename First, typename Second>
release(void)143 void 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 
154 template<typename First, typename Second>
Either(const First & first)155 Either<First, Second>::Either (const First& first)
156 	: m_isFirst	(true)
157 {
158 	m_first = new(m_data)First(first);
159 }
160 
161 template<typename First, typename Second>
Either(const Second & second)162 Either<First, Second>::Either (const Second& second)
163 	: m_isFirst (false)
164 {
165 	m_second = new(m_data)Second(second);
166 }
167 
168 template<typename First, typename Second>
~Either(void)169 Either<First, Second>::~Either (void)
170 {
171 	release();
172 }
173 
174 template<typename First, typename Second>
Either(const Either<First,Second> & other)175 Either<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 
184 template<typename First, typename Second>
operator =(const Either<First,Second> & other)185 Either<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 
202 template<typename First, typename Second>
operator =(const First & first)203 Either<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 
213 template<typename First, typename Second>
operator =(const Second & second)214 Either<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 
224 template<typename First, typename Second>
isFirst(void) const225 bool Either<First, Second>::isFirst (void) const
226 {
227 	return m_isFirst;
228 }
229 
230 template<typename First, typename Second>
isSecond(void) const231 bool Either<First, Second>::isSecond (void) const
232 {
233 	return !m_isFirst;
234 }
235 
236 template<typename First, typename Second>
getFirst(void) const237 const First& Either<First, Second>::getFirst (void) const
238 {
239 	DE_ASSERT(isFirst());
240 	return *m_first;
241 }
242 
243 template<typename First, typename Second>
getSecond(void) const244 const Second& Either<First, Second>::getSecond (void) const
245 {
246 	DE_ASSERT(isSecond());
247 	return *m_second;
248 }
249 
250 template<typename First, typename Second>
251 template<typename Type>
get(void) const252 const Type& Either<First, Second>::get (void) const
253 {
254 	return EitherDetail::get<Type, First, Second>(*this);
255 }
256 
257 template<typename First, typename Second>
258 template<typename Type>
is(void) const259 bool Either<First, Second>::is (void) const
260 {
261 	return EitherDetail::is<Type, First, Second>(*this);
262 }
263 
264 void Either_selfTest (void);
265 
266 } // tcu
267 
268 #endif // _TCUEITHER_HPP
269