Embedded Template Library  1.0
variant_new.h
Go to the documentation of this file.
1 
3 /******************************************************************************
4 The MIT License(MIT)
5 
6 Embedded Template Library.
7 https://github.com/ETLCPP/etl
8 https://www.etlcpp.com
9 
10 Copyright(c) 2020 jwellbelove
11 
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files(the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions :
18 
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21 
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29 ******************************************************************************/
30 
31 #ifndef ETL_VARIANT_NEW_INCLUDED
32 #define ETL_VARIANT_NEW_INCLUDED
33 
34 #include <stdint.h>
35 
36 #include "private/new.h"
37 
38 #include "platform.h"
39 #include "utility.h"
40 #include "array.h"
41 #include "largest.h"
42 #include "exception.h"
43 #include "type_traits.h"
44 #include "integral_limits.h"
45 #include "static_assert.h"
46 #include "alignment.h"
47 #include "error_handler.h"
48 #include "null_type.h"
49 
50 #if defined(ETL_COMPILER_KEIL)
51  #pragma diag_suppress 940
52  #pragma diag_suppress 111
53 #endif
54 
55 #undef ETL_FILE
56 #define ETL_FILE "24"
57 
58 #if ETL_CPP11_SUPPORTED
59 
60 //*****************************************************************************
64 //*****************************************************************************
65 
66 namespace etl
67 {
68  //***************************************************************************
71  //***************************************************************************
72  class variant_exception : public exception
73  {
74  public:
75  variant_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
76  : exception(reason_, file_name_, line_number_)
77  {
78  }
79  };
80 
81  //***************************************************************************
84  //***************************************************************************
85  class variant_incorrect_type_exception : public variant_exception
86  {
87  public:
88  variant_incorrect_type_exception(string_type file_name_, numeric_type line_number_)
89  : variant_exception(ETL_ERROR_TEXT("variant: unsupported type", ETL_FILE"A"), file_name_, line_number_)
90  {
91  }
92  };
93 
94  //***************************************************************************
98  //***************************************************************************
99  template <typename... TVariants>
100  class variant
101  {
102  public:
103 
104  //***************************************************************************
106  //***************************************************************************
107  static ETL_CONST_OR_CONSTEXPR size_t npos = -1;
108 
109  private:
110 
111  // All types of variant are friends.
112  template <typename... U>
113  friend class variant;
114 
115  //***************************************************************************
117  //***************************************************************************
118  typedef typename largest_type<TVariants...>::type largest_t;
119 
120  //***************************************************************************
122  //***************************************************************************
123  static const size_t SIZE = sizeof(largest_t);
124 
125  //***************************************************************************
127  //***************************************************************************
128  static const size_t ALIGNMENT = etl::largest_alignment<TVariants...>::value;
129 
130  public:
131 
132  //***************************************************************************
134  //***************************************************************************
135  ~variant()
136  {
137  destruct_current();
138  }
139 
140  //***************************************************************************
143  //***************************************************************************
144  variant()
145  : type_id(UNSUPPORTED_TYPE_ID)
146  {
147  }
148 
149  //***************************************************************************
152  //***************************************************************************
153  template <typename T>
154  variant(const T& value)
155  {
156  ETL_STATIC_ASSERT(etl::index_of<T, TVariants>::value != etl::index_of<T, TVariants>::npos, "Unsupported type");
157 
158  ::new (static_cast<T*>(data)) T(value);
159  type_id = etl::index_of<T, TVariants>::value;
160  }
161 
162  //***************************************************************************
165  //***************************************************************************
166  variant(const variant& other)
167  {
168  switch (other.type_id)
169  {
170  case 0: ::new (static_cast<T1*>(data)) T1(other.get<T1>()); break;
171  case 1: ::new (static_cast<T2*>(data)) T2(other.get<T2>()); break;
172  case 2: ::new (static_cast<T3*>(data)) T3(other.get<T3>()); break;
173  case 3: ::new (static_cast<T4*>(data)) T4(other.get<T4>()); break;
174  case 4: ::new (static_cast<T5*>(data)) T5(other.get<T5>()); break;
175  case 5: ::new (static_cast<T6*>(data)) T6(other.get<T6>()); break;
176  case 6: ::new (static_cast<T7*>(data)) T7(other.get<T7>()); break;
177  case 7: ::new (static_cast<T8*>(data)) T8(other.get<T8>()); break;
178  default: break;
179  }
180 
181  type_id = other.type_id;
182  }
183 
184 #if ETL_CPP11_SUPPORTED && ETL_NOT_USING_STLPORT && !defined(ETL_VARIANT_FORCE_CPP03)
185  //*************************************************************************
187  //*************************************************************************
188  template <typename T, typename... Args>
189  T& emplace(Args&&... args)
190  {
191  ETL_STATIC_ASSERT(Type_Is_Supported<T>::value, "Unsupported type");
192 
193  destruct_current();
194  ::new (static_cast<T*>(data)) T(etl::forward<Args>(args)...);
195  type_id = Type_Id_Lookup<T>::type_id;
196 
197  return *static_cast<T*>(data);
198  }
199 #else
200  //***************************************************************************
202  //***************************************************************************
203  template <typename T, typename TP1>
204  T& emplace(const TP1& value1)
205  {
206  ETL_STATIC_ASSERT(Type_Is_Supported<T>::value, "Unsupported type");
207 
208  destruct_current();
209  ::new (static_cast<T*>(data)) T(value1);
210  type_id = Type_Id_Lookup<T>::type_id;
211 
212  return *static_cast<T*>(data);
213  }
214 
215  //***************************************************************************
217  //***************************************************************************
218  template <typename T, typename TP1, typename TP2>
219  T& emplace(const TP1& value1, const TP2& value2)
220  {
221  ETL_STATIC_ASSERT(Type_Is_Supported<T>::value, "Unsupported type");
222 
223  destruct_current();
224  ::new (static_cast<T*>(data)) T(value1, value2);
225  type_id = Type_Id_Lookup<T>::type_id;
226 
227  return *static_cast<T*>(data);
228  }
229 
230  //***************************************************************************
232  //***************************************************************************
233  template <typename T, typename TP1, typename TP2, typename TP3>
234  T& emplace(const TP1& value1, const TP2& value2, const TP3& value3)
235  {
236  ETL_STATIC_ASSERT(Type_Is_Supported<T>::value, "Unsupported type");
237 
238  destruct_current();
239  ::new (static_cast<T*>(data)) T(value1, value2, value3);
240  type_id = Type_Id_Lookup<T>::type_id;
241 
242  return *static_cast<T*>(data);
243  }
244 
245  //***************************************************************************
247  //***************************************************************************
248  template <typename T, typename TP1, typename TP2, typename TP3, typename TP4>
249  T& emplace(const TP1& value1, const TP2& value2, const TP3& value3, const TP4& value4)
250  {
251  ETL_STATIC_ASSERT(Type_Is_Supported<T>::value, "Unsupported type");
252 
253  destruct_current();
254  ::new (static_cast<T*>(data)) T(value1, value2, value3, value4);
255  type_id = Type_Id_Lookup<T>::type_id;
256 
257  return *static_cast<T*>(data);
258  }
259 #endif
260 
261  //***************************************************************************
264  //***************************************************************************
265  template <typename T>
266  variant& operator =(const T& value)
267  {
268  ETL_STATIC_ASSERT(Type_Is_Supported<T>::value, "Unsupported type");
269 
270  destruct_current();
271  ::new (static_cast<T*>(data)) T(value);
272  type_id = Type_Id_Lookup<T>::type_id;
273 
274  return *this;
275  }
276 
277  //***************************************************************************
280  //***************************************************************************
281  variant& operator =(const variant& other)
282  {
283  if (this != &other)
284  {
285  destruct_current();
286 
287  switch (other.type_id)
288  {
289  case 0: ::new (static_cast<T1*>(data)) T1(other.get<T1>()); break;
290  case 1: ::new (static_cast<T2*>(data)) T2(other.get<T2>()); break;
291  case 2: ::new (static_cast<T3*>(data)) T3(other.get<T3>()); break;
292  case 3: ::new (static_cast<T4*>(data)) T4(other.get<T4>()); break;
293  case 4: ::new (static_cast<T5*>(data)) T5(other.get<T5>()); break;
294  case 5: ::new (static_cast<T6*>(data)) T6(other.get<T6>()); break;
295  case 6: ::new (static_cast<T7*>(data)) T7(other.get<T7>()); break;
296  case 7: ::new (static_cast<T8*>(data)) T8(other.get<T8>()); break;
297  default: break;
298  }
299 
300  type_id = other.type_id;
301  }
302 
303  return *this;
304  }
305 
306  //***************************************************************************
310  //***************************************************************************
311  bool is_same_type(const variant& other) const
312  {
313  return type_id == other.type_id;
314  }
315 
316  //***************************************************************************
320  //***************************************************************************
321  template <typename U1, typename U2, typename U3, typename U4, typename U5, typename U6, typename U7, typename U8>
322  bool is_same_type(const variant<U1, U2, U3, U4, U5, U6, U7, U8>& other) const
323  {
324  bool is_same = false;
325 
326  switch (other.type_id)
327  {
328  case 0: is_same = (type_id == Type_Id_Lookup<U1>::type_id); break;
329  case 1: is_same = (type_id == Type_Id_Lookup<U2>::type_id); break;
330  case 2: is_same = (type_id == Type_Id_Lookup<U3>::type_id); break;
331  case 3: is_same = (type_id == Type_Id_Lookup<U4>::type_id); break;
332  case 4: is_same = (type_id == Type_Id_Lookup<U5>::type_id); break;
333  case 5: is_same = (type_id == Type_Id_Lookup<U6>::type_id); break;
334  case 6: is_same = (type_id == Type_Id_Lookup<U7>::type_id); break;
335  case 7: is_same = (type_id == Type_Id_Lookup<U8>::type_id); break;
336  default: break;
337  }
338 
339  return is_same;
340  }
341 
342  //***************************************************************************
345  //***************************************************************************
346  void call(reader& r)
347  {
348  switch (type_id)
349  {
350  case 0: r.read(static_cast<T1&>(data)); break;
351  case 1: r.read(static_cast<T2&>(data)); break;
352  case 2: r.read(static_cast<T3&>(data)); break;
353  case 3: r.read(static_cast<T4&>(data)); break;
354  case 4: r.read(static_cast<T5&>(data)); break;
355  case 5: r.read(static_cast<T6&>(data)); break;
356  case 6: r.read(static_cast<T7&>(data)); break;
357  case 7: r.read(static_cast<T8&>(data)); break;
358  default: break;
359  }
360  }
361 
362  //***************************************************************************
365  //***************************************************************************
366  bool is_valid() const
367  {
368  return type_id != UNSUPPORTED_TYPE_ID;
369  }
370 
371  //***************************************************************************
374  //***************************************************************************
375  template <typename T>
376  bool is_type() const
377  {
378  return type_id == Type_Id_Lookup<T>::type_id;
379  }
380 
381  //***************************************************************************
383  //***************************************************************************
384  size_t index() const
385  {
386  return type_id;
387  }
388 
389  //***************************************************************************
391  //***************************************************************************
392  void clear()
393  {
394  destruct_current();
395  }
396 
397  //***************************************************************************
401  //***************************************************************************
402  template <typename T>
403  T& get()
404  {
405  ETL_STATIC_ASSERT(Type_Is_Supported<T>::value, "Unsupported type");
406  ETL_ASSERT(is_type<T>(), ETL_ERROR(variant_incorrect_type_exception));
407 
408  return static_cast<T&>(data);
409  }
410 
411  //***************************************************************************
415  //***************************************************************************
416  template <typename T>
417  const T& get() const
418  {
419  ETL_STATIC_ASSERT(Type_Is_Supported<T>::value, "Unsupported type");
420  ETL_ASSERT(is_type<T>(), ETL_ERROR(variant_incorrect_type_exception));
421 
422  return static_cast<const T&>(data);
423  }
424 
425  //***************************************************************************
428  //***************************************************************************
429  template <typename TBase>
430  TBase& upcast()
431  {
432  return upcast_functor<TBase, T1, T2, T3, T4, T5, T6, T7, T8>()(data, type_id);
433  }
434 
435  //***************************************************************************
438  //***************************************************************************
439  template <typename TBase>
440  const TBase& upcast() const
441  {
442  return upcast_functor<TBase, T1, T2, T3, T4, T5, T6, T7, T8>()(data, type_id);
443  }
444 
445  //***************************************************************************
447  //***************************************************************************
448  operator T1&() { return get<T1>(); }
449  operator T2&() { return get<T2>(); }
450  operator T3&() { return get<T3>(); }
451  operator T4&() { return get<T4>(); }
452  operator T5&() { return get<T5>(); }
453  operator T6&() { return get<T6>(); }
454  operator T7&() { return get<T7>(); }
455  operator T8&() { return get<T8>(); }
456 
457  //***************************************************************************
460  //***************************************************************************
461  template <typename T>
462  static bool is_supported_type()
463  {
464  return Type_Is_Supported<T>::value;
465  }
466 
467  private:
468 
469  //***************************************************************************
471  //***************************************************************************
472  void destruct_current()
473  {
474  switch (type_id)
475  {
476  case 0: { static_cast<T1*>(data)->~T1(); break; }
477  case 1: { static_cast<T2*>(data)->~T2(); break; }
478  case 2: { static_cast<T3*>(data)->~T3(); break; }
479  case 3: { static_cast<T4*>(data)->~T4(); break; }
480  case 4: { static_cast<T5*>(data)->~T5(); break; }
481  case 5: { static_cast<T6*>(data)->~T6(); break; }
482  case 6: { static_cast<T7*>(data)->~T7(); break; }
483  case 7: { static_cast<T8*>(data)->~T8(); break; }
484  default: { break; }
485  }
486 
487  type_id = UNSUPPORTED_TYPE_ID;
488  }
489 
490  constexpr size_t NUMBER_OF_VARIANTS = sizeof...(TVariants);
491 
492  //***************************************************************************
495  //***************************************************************************
497 
498  //***************************************************************************
500  //***************************************************************************
501  type_id_t type_id;
502  };
503 }
504 
505 #endif
506 
507 #undef ETL_FILE
508 
509 #endif
#define ETL_ASSERT(b, e)
Definition: error_handler.h:290
exception(string_type reason_, string_type file_, numeric_type line_)
Constructor.
Definition: exception.h:67
Definition: largest.h:227
static bool is_supported_type()
Definition: variant.h:719
T & get()
Definition: variant.h:660
~variant()
Destructor.
Definition: variant.h:200
bool is_same_type(const variant &other) const
Definition: variant.h:568
void call(reader &r)
Definition: variant.h:603
uint_least8_t type_id_t
The type used for ids.
Definition: variant.h:123
reader_type< T1, T2, T3, T4, T5, T6, T7, T8 > reader
The base type for derived readers.
Definition: variant.h:395
bool is_type() const
Definition: variant.h:633
void clear()
Clears the value to 'no valid stored value'.
Definition: variant.h:649
variant & operator=(const T &value)
Definition: variant.h:523
size_t index() const
Gets the index of the type currently stored or UNSUPPORTED_TYPE_ID.
Definition: variant.h:641
static const type_id_t UNSUPPORTED_TYPE_ID
The id a unsupported types.
Definition: variant.h:128
TBase & upcast()
Definition: variant.h:687
T & emplace(const TP1 &value1)
Emplace with one constructor parameter.
Definition: variant.h:461
bool is_valid() const
Definition: variant.h:623
Definition: absolute.h:37
Definition: alignment.h:118