xref: /aosp_15_r20/external/deqp/framework/common/tcuEither.hpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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