Publishing 2019 R1 content
[platform/upstream/dldt.git] / inference-engine / thirdparty / fluid / modules / gapi / include / opencv2 / gapi / util / variant.hpp
1 // This file is part of OpenCV project.
2 // It is subject to the license terms in the LICENSE file found in the top-level directory
3 // of this distribution and at http://opencv.org/license.html.
4 //
5 // Copyright (C) 2018-2019 Intel Corporation
6
7
8 #ifndef OPENCV_GAPI_UTIL_VARIANT_HPP
9 #define OPENCV_GAPI_UTIL_VARIANT_HPP
10
11 #include <array>
12 #include <type_traits>
13
14 #include "opencv2/gapi/util/throw.hpp"
15 #include "opencv2/gapi/util/util.hpp" // max_of_t
16
17 // A poor man's `variant` implementation, incompletely modeled against C++17 spec.
18 namespace cv
19 {
20 namespace util
21 {
22     namespace detail
23     {
24         template<std::size_t I, typename Target, typename First, typename... Remaining>
25         struct type_list_index_helper
26         {
27             static const constexpr bool is_same = std::is_same<Target, First>::value;
28             static const constexpr std::size_t value =
29                 std::conditional<is_same, std::integral_constant<std::size_t, I>, type_list_index_helper<I + 1, Target, Remaining...>>::type::value;
30         };
31
32         template<std::size_t I, typename Target, typename First>
33         struct type_list_index_helper<I, Target, First>
34         {
35             static_assert(std::is_same<Target, First>::value, "Type not found");
36             static const constexpr std::size_t value = I;
37         };
38
39
40         template<class T, class U, class V> using are_different =
41             std::enable_if<!std::is_same<typename std::decay<T>::type,
42                                          typename std::decay<U>::type>::value,
43                            V>;
44     }
45
46     template<typename Target, typename... Types>
47     struct type_list_index
48     {
49         static const constexpr std::size_t value = detail::type_list_index_helper<0, Target, Types...>::value;
50     };
51
52     class bad_variant_access: public std::exception
53     {
54     public:
55         virtual const char *what() const noexcept override
56         {
57             return "Bad variant access";
58         }
59     };
60
61     // Interface ///////////////////////////////////////////////////////////////
62     struct monostate {};
63     inline bool operator==(const util::monostate&, const util::monostate&)
64     {
65         return true;
66     }
67
68     template<typename... Ts> // FIXME: no references, arrays, and void
69     class variant
70     {
71         // FIXME: Replace with std::aligned_union after gcc4.8 support is dropped
72         static constexpr const std::size_t S = cv::detail::max_of_t<sizeof(Ts)...>::value;
73         static constexpr const std::size_t A = cv::detail::max_of_t<alignof(Ts)...>::value;
74         using Memory = typename std::aligned_storage<S, A>::type[1];
75
76         template<typename T> struct cctr_h {
77             static void help(Memory memory, const Memory from) {
78                 new (memory) T(*reinterpret_cast<const T*>(from));
79             }
80         };
81
82         template<typename T> struct vctr_h {
83             static void help(Memory memory, const void* pval) {
84                 new (memory) T(*reinterpret_cast<const T*>(pval));
85             }
86         };
87
88         template<typename T> struct mctr_h {
89             static void help(Memory memory, void *pval) {
90                 new (memory) T(std::move(*reinterpret_cast<T*>(pval)));
91             }
92         };
93
94         template<typename T> struct copy_h {
95             static void help(Memory to, const Memory from) {
96                 *reinterpret_cast<T*>(to) = *reinterpret_cast<const T*>(from);
97             }
98         };
99
100         template<typename T> struct move_h {
101             static void help(Memory to, const Memory from) {
102                 *reinterpret_cast<T*>(to) = std::move(*reinterpret_cast<const T*>(from));
103             }
104         };
105
106         template<typename T> struct swap_h {
107             static void help(Memory to, Memory from) {
108                 std::swap(*reinterpret_cast<T*>(to), *reinterpret_cast<T*>(from));
109             }
110         };
111
112         template<typename T> struct dtor_h {
113             static void help(Memory memory) {
114                 (void) memory; // MSCV warning
115                 reinterpret_cast<T*>(memory)->~T();
116             }
117         };
118
119         template<typename T> struct equal_h {
120             static bool help(const Memory lhs, const Memory rhs) {
121                 const T& t_lhs = *reinterpret_cast<const T*>(lhs);
122                 const T& t_rhs = *reinterpret_cast<const T*>(rhs);
123                 return t_lhs == t_rhs;
124             }
125         };
126
127         typedef void (*CCtr) (Memory, const Memory);  // Copy c-tor (variant)
128         typedef void (*VCtr) (Memory, const void*);   // Copy c-tor (value)
129         typedef void (*MCtr) (Memory, void*);         // Generic move c-tor
130         typedef void (*Copy) (Memory, const Memory);  // Copy assignment
131         typedef void (*Move) (Memory, const Memory);  // Move assignment
132         typedef void (*Swap) (Memory, Memory);        // Swap
133         typedef void (*Dtor) (Memory);                // Destructor
134
135         typedef bool (*Equal)(const Memory, const Memory); // Equality test (external)
136
137         static constexpr std::array<CCtr, sizeof...(Ts)> cctrs(){ return {{(&cctr_h<Ts>::help)...}};}
138         static constexpr std::array<VCtr, sizeof...(Ts)> vctrs(){ return {{(&vctr_h<Ts>::help)...}};}
139         static constexpr std::array<MCtr, sizeof...(Ts)> mctrs(){ return {{(&mctr_h<Ts>::help)...}};}
140         static constexpr std::array<Copy, sizeof...(Ts)> cpyrs(){ return {{(&copy_h<Ts>::help)...}};}
141         static constexpr std::array<Move, sizeof...(Ts)> mvers(){ return {{(&move_h<Ts>::help)...}};}
142         static constexpr std::array<Swap, sizeof...(Ts)> swprs(){ return {{(&swap_h<Ts>::help)...}};}
143         static constexpr std::array<Dtor, sizeof...(Ts)> dtors(){ return {{(&dtor_h<Ts>::help)...}};}
144
145         std::size_t m_index = 0;
146
147     protected:
148         template<typename T, typename... Us> friend T& get(variant<Us...> &v);
149         template<typename T, typename... Us> friend const T& get(const variant<Us...> &v);
150         template<typename... Us> friend bool operator==(const variant<Us...> &lhs,
151                                                         const variant<Us...> &rhs);
152         Memory memory;
153
154     public:
155         // Constructors
156         variant() noexcept;
157         variant(const variant& other);
158         variant(variant&& other) noexcept;
159         template<typename T> explicit variant(const T& t);
160         // are_different is a SFINAE trick to avoid variant(T &&t) with T=variant
161         // for some reason, this version is called instead of variant(variant&& o) when
162         // variant is used in STL containers (examples: vector assignment)
163         template<typename T> explicit variant(T&& t, typename detail::are_different<variant, T, int>::type = 0);
164         // template<class T, class... Args> explicit variant(Args&&... args);
165         // FIXME: other constructors
166
167         // Destructor
168         ~variant();
169
170         // Assignment
171         variant& operator=(const variant& rhs);
172         variant& operator=(variant &&rhs) noexcept;
173
174         // SFINAE trick to avoid operator=(T&&) with T=variant<>, see comment above
175         template<class T>
176         typename detail::are_different<variant, T, variant&>
177         ::type operator=(T&& t) noexcept;
178
179         // Observers
180         std::size_t index() const noexcept;
181         // FIXME: valueless_by_exception()
182
183         // Modifiers
184         // FIXME: emplace()
185         void swap(variant &rhs) noexcept;
186
187         // Non-C++17x!
188         template<typename T> static constexpr std::size_t index_of();
189     };
190
191     // FIMXE: visit
192
193     template<typename T, typename... Types>
194     T& get(util::variant<Types...> &v);
195
196     template<typename T, typename... Types>
197     const T& get(const util::variant<Types...> &v);
198
199     template<typename T, typename... Types>
200     bool holds_alternative(const util::variant<Types...> &v) noexcept;
201
202     // FIXME: T&&, const TT&& versions.
203
204     // Implementation //////////////////////////////////////////////////////////
205     template<typename... Ts>
206     variant<Ts...>::variant() noexcept
207     {
208         typedef typename std::tuple_element<0, std::tuple<Ts...> >::type TFirst;
209         new (memory) TFirst();
210     }
211
212     template<typename... Ts>
213     variant<Ts...>::variant(const variant &other)
214         : m_index(other.m_index)
215     {
216         (cctrs()[m_index])(memory, other.memory);
217     }
218
219     template<typename... Ts>
220     variant<Ts...>::variant(variant &&other) noexcept
221         : m_index(other.m_index)
222     {
223         (mctrs()[m_index])(memory, other.memory);
224     }
225
226     template<typename... Ts>
227     template<class T>
228     variant<Ts...>::variant(const T& t)
229         : m_index(util::type_list_index<T, Ts...>::value)
230     {
231         (vctrs()[m_index])(memory, &t);
232     }
233
234     template<typename... Ts>
235     template<class T>
236     variant<Ts...>::variant(T&& t, typename detail::are_different<variant, T, int>::type)
237         : m_index(util::type_list_index<typename std::remove_reference<T>::type, Ts...>::value)
238     {
239         (mctrs()[m_index])(memory, &t);
240     }
241
242     template<typename... Ts>
243     variant<Ts...>::~variant()
244     {
245         (dtors()[m_index])(memory);
246     }
247
248     template<typename... Ts>
249     variant<Ts...>& variant<Ts...>::operator=(const variant<Ts...> &rhs)
250     {
251         if (m_index != rhs.m_index)
252         {
253             (dtors()[    m_index])(memory);
254             (cctrs()[rhs.m_index])(memory, rhs.memory);
255             m_index = rhs.m_index;
256         }
257         else
258         {
259             (cpyrs()[rhs.m_index])(memory, rhs.memory);
260         }
261         return *this;
262     }
263
264     template<typename... Ts>
265     variant<Ts...>& variant<Ts...>::operator=(variant<Ts...> &&rhs) noexcept
266     {
267         if (m_index != rhs.m_index)
268         {
269             (dtors()[    m_index])(memory);
270             (mctrs()[rhs.m_index])(memory, rhs.memory);
271             m_index = rhs.m_index;
272         }
273         else
274         {
275             (mvers()[rhs.m_index])(memory, rhs.memory);
276         }
277         return *this;
278     }
279
280     template<typename... Ts>
281     template<class T> typename detail::are_different<variant<Ts...>, T, variant<Ts...>&>
282     ::type variant<Ts...>::operator=(T&& t) noexcept
283     {
284         // FIXME: No version with implicit type conversion available!
285         static const constexpr std::size_t t_index =
286             util::type_list_index<T, Ts...>::value;
287
288         if (t_index == m_index)
289         {
290             util::get<T>(*this) = std::move(t);
291             return *this;
292         }
293         else return (*this = variant(std::move(t)));
294     }
295
296     template<typename... Ts>
297     std::size_t util::variant<Ts...>::index() const noexcept
298     {
299         return m_index;
300     }
301
302     template<typename... Ts>
303     void variant<Ts...>::swap(variant<Ts...> &rhs) noexcept
304     {
305         if (m_index == rhs.index())
306         {
307             (swprs()[m_index](memory, rhs.memory));
308         }
309         else
310         {
311             variant<Ts...> tmp(std::move(*this));
312             *this = std::move(rhs);
313             rhs   = std::move(tmp);
314         }
315     }
316
317     template<typename... Ts>
318     template<typename T>
319     constexpr std::size_t variant<Ts...>::index_of()
320     {
321         return util::type_list_index<T, Ts...>::value; // FIXME: tests!
322     }
323
324     template<typename T, typename... Types>
325     T& get(util::variant<Types...> &v)
326     {
327         const constexpr std::size_t t_index =
328             util::type_list_index<T, Types...>::value;
329
330         if (v.index() == t_index)
331             return reinterpret_cast<T&>(v.memory);
332         else
333             throw_error(bad_variant_access());
334     }
335
336     template<typename T, typename... Types>
337     const T& get(const util::variant<Types...> &v)
338     {
339         const constexpr std::size_t t_index =
340             util::type_list_index<T, Types...>::value;
341
342         if (v.index() == t_index)
343             return reinterpret_cast<const T&>(v.memory);
344         else
345             throw_error(bad_variant_access());
346     }
347
348     template<typename T, typename... Types>
349     bool holds_alternative(const util::variant<Types...> &v) noexcept
350     {
351         return v.index() == util::variant<Types...>::template index_of<T>();
352     }
353
354     template<typename... Us> bool operator==(const variant<Us...> &lhs,
355                                              const variant<Us...> &rhs)
356     {
357         using V = variant<Us...>;
358
359         // Instantiate table only here since it requires operator== for <Us...>
360         // <Us...> should have operator== only if this one is used, not in general
361         static const std::array<typename V::Equal, sizeof...(Us)> eqs = {
362             {(&V::template equal_h<Us>::help)...}
363         };
364         if (lhs.index() != rhs.index())
365             return false;
366         return (eqs[lhs.index()])(lhs.memory, rhs.memory);
367     }
368
369     template<typename... Us> bool operator!=(const variant<Us...> &lhs,
370                                              const variant<Us...> &rhs)
371     {
372         return !(lhs == rhs);
373     }
374 } // namespace cv
375 } // namespace util
376
377 #endif // OPENCV_GAPI_UTIL_VARIANT_HPP