Merge upstream-vulkan-cts-1.0-dev into master
[platform/upstream/VK-GL-CTS.git] / framework / common / tcuEither.hpp
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 {
92         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 {
101         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>
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 {
119         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 {
128         static bool is (const Either<First, Second>& either)
129         {
130                 return either.isSecond();
131         }
132 };
133
134 template<typename Type, typename First, typename Second>
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>
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>
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>
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>
169 Either<First, Second>::~Either (void)
170 {
171         release();
172 }
173
174 template<typename First, typename Second>
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>
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>
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>
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>
225 bool Either<First, Second>::isFirst (void) const
226 {
227         return m_isFirst;
228 }
229
230 template<typename First, typename Second>
231 bool Either<First, Second>::isSecond (void) const
232 {
233         return !m_isFirst;
234 }
235
236 template<typename First, typename Second>
237 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>
244 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>
252 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>
259 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