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 * uint64_t.
36 * \note This type always uses at least sizeof(bool) + max(sizeof(First*),
37 * sizeof(Second*)) + sizeof(uint64_t) 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 uint8_t m_data[sizeof(First) > sizeof(Second) ? sizeof(First) : sizeof(Second)];
79 uint64_t 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 } // namespace 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) : m_isFirst(true)
156 {
157 m_first = new (m_data) First(first);
158 }
159
160 template <typename First, typename Second>
Either(const Second & second)161 Either<First, Second>::Either(const Second &second) : m_isFirst(false)
162 {
163 m_second = new (m_data) Second(second);
164 }
165
166 template <typename First, typename Second>
~Either(void)167 Either<First, Second>::~Either(void)
168 {
169 release();
170 }
171
172 template <typename First, typename Second>
Either(const Either<First,Second> & other)173 Either<First, Second>::Either(const Either<First, Second> &other) : m_isFirst(other.m_isFirst)
174 {
175 if (m_isFirst)
176 m_first = new (m_data) First(*other.m_first);
177 else
178 m_second = new (m_data) Second(*other.m_second);
179 }
180
181 template <typename First, typename Second>
operator =(const Either<First,Second> & other)182 Either<First, Second> &Either<First, Second>::operator=(const Either<First, Second> &other)
183 {
184 if (this == &other)
185 return *this;
186
187 release();
188
189 m_isFirst = other.m_isFirst;
190
191 if (m_isFirst)
192 m_first = new (m_data) First(*other.m_first);
193 else
194 m_second = new (m_data) Second(*other.m_second);
195
196 return *this;
197 }
198
199 template <typename First, typename Second>
operator =(const First & first)200 Either<First, Second> &Either<First, Second>::operator=(const First &first)
201 {
202 release();
203
204 m_isFirst = true;
205 m_first = new (m_data) First(first);
206
207 return *this;
208 }
209
210 template <typename First, typename Second>
operator =(const Second & second)211 Either<First, Second> &Either<First, Second>::operator=(const Second &second)
212 {
213 release();
214
215 m_isFirst = false;
216 m_second = new (m_data) Second(second);
217
218 return *this;
219 }
220
221 template <typename First, typename Second>
isFirst(void) const222 bool Either<First, Second>::isFirst(void) const
223 {
224 return m_isFirst;
225 }
226
227 template <typename First, typename Second>
isSecond(void) const228 bool Either<First, Second>::isSecond(void) const
229 {
230 return !m_isFirst;
231 }
232
233 template <typename First, typename Second>
getFirst(void) const234 const First &Either<First, Second>::getFirst(void) const
235 {
236 DE_ASSERT(isFirst());
237 return *m_first;
238 }
239
240 template <typename First, typename Second>
getSecond(void) const241 const Second &Either<First, Second>::getSecond(void) const
242 {
243 DE_ASSERT(isSecond());
244 return *m_second;
245 }
246
247 template <typename First, typename Second>
248 template <typename Type>
get(void) const249 const Type &Either<First, Second>::get(void) const
250 {
251 return EitherDetail::get<Type, First, Second>(*this);
252 }
253
254 template <typename First, typename Second>
255 template <typename Type>
is(void) const256 bool Either<First, Second>::is(void) const
257 {
258 return EitherDetail::is<Type, First, Second>(*this);
259 }
260
261 void Either_selfTest(void);
262
263 } // namespace tcu
264
265 #endif // _TCUEITHER_HPP
266