Embedded Template Library  1.0
optional.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) 2015 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_OPTIONAL_INCLUDED
32 #define ETL_OPTIONAL_INCLUDED
33 
34 #include "platform.h"
35 #include "alignment.h"
36 #include "type_traits.h"
37 #include "exception.h"
38 #include "error_handler.h"
39 #include "utility.h"
40 #include "placement_new.h"
41 
42 namespace etl
43 {
44  //*****************************************************************************
47  //*****************************************************************************
48  class nullopt_t
49  {
50  public:
51 
52  // Convertible to any type of null non-member pointer.
53  template<class T>
54  operator T*() const
55  {
56  return 0;
57  }
58 
59  private:
60 
61  // Can't take address of nullopt.
62  void operator&() const;
63  };
64 
65  //*****************************************************************************
68  //*****************************************************************************
69  const nullopt_t nullopt = {};
70 
71  //***************************************************************************
74  //***************************************************************************
76  {
77  public:
78 
79  optional_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
80  : exception(reason_, file_name_, line_number_)
81  {
82  }
83  };
84 
85  //***************************************************************************
88  //***************************************************************************
90  {
91  public:
92 
93  optional_invalid(string_type file_name_, numeric_type line_number_)
94  : optional_exception("optional: invalid", file_name_, line_number_)
95  {
96  }
97  };
98 
99  //*****************************************************************************
105  //*****************************************************************************
106  template <typename T>
107  class optional
108  {
109  public:
110 
111  //***************************************************************************
113  //***************************************************************************
115  : valid(false)
116  {
117  }
118 
119  //***************************************************************************
121  //***************************************************************************
123  : valid(false)
124  {
125  }
126 
127  //***************************************************************************
129  //***************************************************************************
130  optional(const optional& other)
131  : valid(bool(other))
132  {
133  if (valid)
134  {
135  ::new (storage.template get_address<T>()) T(other.value());
136  }
137  }
138 
139 #if ETL_CPP11_SUPPORTED
140  //***************************************************************************
142  //***************************************************************************
143  optional(optional&& other)
144  : valid(bool(other))
145  {
146  if (valid)
147  {
148  ::new (storage.template get_address<T>()) T(etl::move(other.value()));
149  }
150  }
151 #endif
152 
153  //***************************************************************************
155  //***************************************************************************
156  optional(const T& value_)
157  {
158  ::new (storage.template get_address<T>()) T(value_);
159  valid = true;
160  }
161 
162 #if ETL_CPP11_SUPPORTED
163  //***************************************************************************
165  //***************************************************************************
166  optional(T&& value_)
167  {
168  ::new (storage.template get_address<T>()) T(etl::move(value_));
169  valid = true;
170  }
171 #endif
172 
173  //***************************************************************************
175  //***************************************************************************
177  {
178  if (valid)
179  {
180  storage.template get_reference<T>().~T();
181  }
182  }
183 
184  //***************************************************************************
186  //***************************************************************************
188  {
189  if (valid)
190  {
191  storage.template get_reference<T>().~T();
192  valid = false;
193  }
194 
195  return *this;
196  }
197 
198  //***************************************************************************
200  //***************************************************************************
201  optional& operator =(const optional& other)
202  {
203  if (this != &other)
204  {
205  if (valid && !bool(other))
206  {
207  storage.template get_reference<T>().~T();
208  valid = false;
209  }
210  else if (bool(other))
211  {
212  if (valid)
213  {
214  storage.template get_reference<T>() = other.value();
215  }
216  else
217  {
218  ::new (storage.template get_address<T>()) T(other.value());
219  valid = true;
220  }
221  }
222  }
223 
224  return *this;
225  }
226 
227 #if ETL_CPP11_SUPPORTED
228  //***************************************************************************
230  //***************************************************************************
231  optional& operator =(optional&& other)
232  {
233  if (this != &other)
234  {
235  if (valid && !bool(other))
236  {
237  storage.template get_reference<T>().~T();
238  valid = false;
239  }
240  else if (bool(other))
241  {
242  if (valid)
243  {
244  storage.template get_reference<T>() = etl::move(other.value());
245  }
246  else
247  {
248  ::new (storage.template get_address<T>()) T(etl::move(other.value()));
249  valid = true;
250  }
251  }
252  }
253 
254  return *this;
255  }
256 #endif
257 
258  //***************************************************************************
260  //***************************************************************************
261  optional& operator =(const T& value_)
262  {
263  if (valid)
264  {
265  storage.template get_reference<T>() = value_;
266  }
267  else
268  {
269  ::new (storage.template get_address<T>()) T(value_);
270  valid = true;
271  }
272 
273  return *this;
274  }
275 
276 #if ETL_CPP11_SUPPORTED
277  //***************************************************************************
279  //***************************************************************************
280  optional& operator =(T&& value_)
281  {
282  if (valid)
283  {
284  storage.template get_reference<T>() = etl::move(value_);
285  }
286  else
287  {
288  ::new (storage.template get_address<T>()) T(etl::move(value_));
289  valid = true;
290  }
291 
292  return *this;
293  }
294 #endif
295 
296  //***************************************************************************
298  //***************************************************************************
300  {
301 #if defined(ETL_DEBUG)
302  ETL_ASSERT(valid, ETL_ERROR(optional_invalid));
303 #endif
304 
305  return storage.template get_address<T>();
306  }
307 
308  //***************************************************************************
310  //***************************************************************************
311  const T* operator ->() const
312  {
313 #if defined(ETL_DEBUG)
314  ETL_ASSERT(valid, ETL_ERROR(optional_invalid));
315 #endif
316 
317  return storage.template get_address<T>();
318  }
319 
320  //***************************************************************************
322  //***************************************************************************
324  {
325 #if defined(ETL_DEBUG)
326  ETL_ASSERT(valid, ETL_ERROR(optional_invalid));
327 #endif
328 
329  return storage.template get_reference<T>();
330  }
331 
332  //***************************************************************************
334  //***************************************************************************
335  const T& operator *() const
336  {
337 #if defined(ETL_DEBUG)
338  ETL_ASSERT(valid, ETL_ERROR(optional_invalid));
339 #endif
340 
341  return storage.template get_reference<T>();
342  }
343 
344  //***************************************************************************
346  //***************************************************************************
347  ETL_EXPLICIT operator bool() const
348  {
349  return valid;
350  }
351 
352  //***************************************************************************
353  // Check whether optional contains value
354  //***************************************************************************
355  ETL_CONSTEXPR bool has_value() const ETL_NOEXCEPT
356  {
357  return valid;
358  }
359 
360 
361  //***************************************************************************
363  //***************************************************************************
364  T& value()
365  {
366 #if defined(ETL_DEBUG)
367  ETL_ASSERT(valid, ETL_ERROR(optional_invalid));
368 #endif
369 
370  return storage.template get_reference<T>();
371  }
372 
373  //***************************************************************************
375  //***************************************************************************
376  const T& value() const
377  {
378 #if defined(ETL_DEBUG)
379  ETL_ASSERT(valid, ETL_ERROR(optional_invalid));
380 #endif
381 
382  return storage.template get_reference<T>();
383  }
384 
385  //***************************************************************************
387  //***************************************************************************
388  T value_or(T default_value) const
389  {
390  return valid ? value() : default_value;
391  }
392 
393  //***************************************************************************
395  //***************************************************************************
396  void swap(optional& other)
397  {
398  optional temp(*this);
399  *this = other;
400  other = temp;
401  }
402 
403  //***************************************************************************
405  //***************************************************************************
406  void reset()
407  {
408  if (valid)
409  {
410  storage.template get_reference<T>().~T();
411  valid = false;
412  }
413  }
414 
415 #if ETL_CPP11_SUPPORTED && ETL_NOT_USING_STLPORT && !defined(ETL_OPTIONAL_FORCE_CPP03)
416  //*************************************************************************
419  //*************************************************************************
420  template <typename ... Args>
421  void emplace(Args && ... args)
422  {
423  if (valid)
424  {
425  // Destroy the old one.
426  storage.template get_reference<T>().~T();
427  }
428 
429  ::new (storage.template get_address<T>()) T(ETL_OR_STD::forward<Args>(args)...);
430  valid = true;
431  }
432 #else
433  //*************************************************************************
436  //*************************************************************************
437  template <typename T1>
438  void emplace(const T1& value1)
439  {
440  if (valid)
441  {
442  // Destroy the old one.
443  storage.template get_reference<T>().~T();
444  }
445 
446  ::new (storage.template get_address<T>()) T(value1);
447  valid = true;
448  }
449 
450  //*************************************************************************
453  //*************************************************************************
454  template <typename T1, typename T2>
455  void emplace(const T1& value1, const T2& value2)
456  {
457  if (valid)
458  {
459  // Destroy the old one.
460  storage.template get_reference<T>().~T();
461  }
462 
463  ::new (storage.template get_address<T>()) T(value1, value2);
464  valid = true;
465  }
466 
467  //*************************************************************************
470  //*************************************************************************
471  template <typename T1, typename T2, typename T3>
472  void emplace(const T1& value1, const T2& value2, const T3& value3)
473  {
474  if (valid)
475  {
476  // Destroy the old one.
477  storage.template get_reference<T>().~T();
478  }
479 
480  ::new (storage.template get_address<T>()) T(value1, value2, value3);
481  valid = true;
482  }
483 
484  //*************************************************************************
487  //*************************************************************************
488  template <typename T1, typename T2, typename T3, typename T4>
489  void emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
490  {
491  if (valid)
492  {
493  // Destroy the old one.
494  storage.template get_reference<T>().~T();
495  }
496 
497  ::new (storage.template get_address<T>()) T(value1, value2, value3, value4);
498  valid = true;
499  }
500 #endif
501 
502  private:
503 
504  typename etl::aligned_storage_as<sizeof(T), T>::type storage;
505  bool valid;
506  };
507 
508  //***************************************************************************
510  //***************************************************************************
511  template <typename T>
512  bool operator ==(const etl::optional<T>& lhs, const etl::optional<T>& rhs)
513  {
514  if (bool(lhs) != bool(rhs))
515  {
516  return false;
517  }
518  else if (!bool(lhs) && !bool(rhs))
519  {
520  return true;
521  }
522  else
523  {
524  return lhs.value() == rhs.value();
525  }
526  }
527 
528  //***************************************************************************
530  //***************************************************************************
531  template <typename T>
532  bool operator !=(const etl::optional<T>& lhs, const etl::optional<T>& rhs)
533  {
534  return !(lhs == rhs);
535  }
536 
537  //***************************************************************************
539  //***************************************************************************
540  template <typename T>
541  bool operator <(const etl::optional<T>& lhs, const etl::optional<T>& rhs)
542  {
543  if (!bool(rhs))
544  {
545  return false;
546  }
547  else if (!bool(lhs))
548  {
549  return true;
550  }
551  else
552  {
553  return lhs.value() < rhs.value();
554  }
555  }
556 
557  //***************************************************************************
559  //***************************************************************************
560  template <typename T>
561  bool operator <=(const etl::optional<T>& lhs, const etl::optional<T>& rhs)
562  {
563  if (!bool(lhs))
564  {
565  return true;
566  }
567  else if (!bool(rhs))
568  {
569  return false;
570  }
571  else
572  {
573  return lhs.value() <= rhs.value();
574  }
575  }
576 
577  //***************************************************************************
579  //***************************************************************************
580  template <typename T>
581  bool operator >(const etl::optional<T>& lhs, const etl::optional<T>& rhs)
582  {
583  if (!bool(lhs))
584  {
585  return false;
586  }
587  else if (!bool(rhs))
588  {
589  return true;
590  }
591  else
592  {
593  return lhs.value() > rhs.value();
594  }
595  }
596 
597  //***************************************************************************
599  //***************************************************************************
600  template <typename T>
601  bool operator >=(const etl::optional<T>& lhs, const etl::optional<T>& rhs)
602  {
603  if (!bool(rhs))
604  {
605  return true;
606  }
607  else if (!bool(lhs))
608  {
609  return false;
610  }
611  else
612  {
613  return lhs.value() >= rhs.value();
614  }
615  }
616 
617  //***************************************************************************
619  //***************************************************************************
620  template <typename T>
622  {
623  return !bool(lhs);
624  }
625 
626  //***************************************************************************
628  //***************************************************************************
629  template <typename T>
631  {
632  return !bool(rhs);
633  }
634 
635  //***************************************************************************
637  //***************************************************************************
638  template <typename T>
640  {
641  return !(lhs == etl::nullopt);
642  }
643 
644  //***************************************************************************
646  //***************************************************************************
647  template <typename T>
649  {
650  return !(etl::nullopt == rhs);
651  }
652 
653  //***************************************************************************
655  //***************************************************************************
656  template <typename T>
658  {
659  return false;
660  }
661 
662  //***************************************************************************
664  //***************************************************************************
665  template <typename T>
667  {
668  return bool(rhs);
669  }
670 
671  //***************************************************************************
673  //***************************************************************************
674  template <typename T>
676  {
677  return !bool(lhs);
678  }
679 
680  //***************************************************************************
682  //***************************************************************************
683  template <typename T>
685  {
686  return true;
687  }
688 
689  //***************************************************************************
691  //***************************************************************************
692  template <typename T>
694  {
695  return bool(lhs);
696  }
697 
698  //***************************************************************************
700  //***************************************************************************
701  template <typename T>
703  {
704  return false;
705  }
706 
707  //***************************************************************************
709  //***************************************************************************
710  template <typename T>
712  {
713  return true;
714  }
715 
716  //***************************************************************************
718  //***************************************************************************
719  template <typename T>
721  {
722  return !bool(rhs);
723  }
724 
725  //***************************************************************************
727  //**************************************************************************
728  template <typename T, typename U>
729  bool operator ==(const etl::optional<T>& lhs, const U& rhs)
730  {
731  return bool(lhs) ? lhs.value() == rhs : false;
732  }
733 
734  //***************************************************************************
736  //**************************************************************************
737  template <typename T, typename U>
738  bool operator !=(const etl::optional<T>& lhs, const U& rhs)
739  {
740  return !(lhs == rhs);
741  }
742 
743  //***************************************************************************
745  //**************************************************************************
746  template <typename T, typename U>
747  bool operator ==(const U& lhs, const etl::optional<T>& rhs)
748  {
749  return bool(rhs) ? rhs.value() == lhs : false;
750  }
751 
752  //***************************************************************************
754  //**************************************************************************
755  template <typename T, typename U>
756  bool operator !=(const U& lhs, const etl::optional<T>& rhs)
757  {
758  return !(lhs == rhs);
759  }
760 
761  //***************************************************************************
763  //***************************************************************************
764  template <typename T, typename U>
765  bool operator <(const etl::optional<T>& lhs, const U& rhs)
766  {
767  return bool(lhs) ? lhs.value() < rhs : true;
768  }
769 
770  //***************************************************************************
772  //***************************************************************************
773  template <typename T, typename U>
774  bool operator <(const U& lhs, const etl::optional<T>& rhs)
775  {
776  return bool(rhs) ? lhs < rhs.value() : false;
777  }
778 
779  //***************************************************************************
781  //***************************************************************************
782  template <typename T, typename U>
783  bool operator <=(const etl::optional<T>& lhs, const U& rhs)
784  {
785  return bool(lhs) ? lhs.value() <= rhs : true;
786  }
787 
788  //***************************************************************************
790  //***************************************************************************
791  template <typename T, typename U>
792  bool operator <=(const U& lhs, const etl::optional<T>& rhs)
793  {
794  return bool(rhs) ? lhs <= rhs.value() : false;
795  }
796 
797  //***************************************************************************
799  //***************************************************************************
800  template <typename T, typename U>
801  bool operator >(const etl::optional<T>& lhs, const U& rhs)
802  {
803  return bool(lhs) ? lhs.value() > rhs : false;
804  }
805 
806  //***************************************************************************
808  //***************************************************************************
809  template <typename T, typename U>
810  bool operator >(const U& lhs, const etl::optional<T>& rhs)
811  {
812  return bool(rhs) ? lhs > rhs.value() : true;
813  }
814 
815  //***************************************************************************
817  //***************************************************************************
818  template <typename T, typename U>
819  bool operator >=(const etl::optional<T>& lhs, const U& rhs)
820  {
821  return bool(lhs) ? lhs.value() >= rhs : false;
822  }
823 
824  //***************************************************************************
826  //***************************************************************************
827  template <typename T, typename U>
828  bool operator >=(const U& lhs, const etl::optional<T>& rhs)
829  {
830  return bool(rhs) ? lhs >= rhs.value() : true;
831  }
832 
833  //***************************************************************************
835  //***************************************************************************
836  template <typename T>
838  {
840  }
841 }
842 
843 //*************************************************************************
845 //*************************************************************************
846 template <typename T>
848 {
849  lhs.swap(rhs);
850 }
851 
852 #endif
Definition: optional.h:49
Definition: optional.h:108
const T & value() const
Get a const reference to the value.
Definition: optional.h:376
void swap(optional &other)
Swaps this value with another.
Definition: optional.h:396
void emplace(const T1 &value1, const T2 &value2)
Definition: optional.h:455
void emplace(const T1 &value1, const T2 &value2, const T3 &value3)
Definition: optional.h:472
optional(etl::nullopt_t)
Constructor with nullopt.
Definition: optional.h:122
void emplace(const T1 &value1)
Definition: optional.h:438
optional()
Constructor.
Definition: optional.h:114
T * operator->()
Pointer operator.
Definition: optional.h:299
T value_or(T default_value) const
Gets the value or a default if no valid.
Definition: optional.h:388
T & value()
Get a reference to the value.
Definition: optional.h:364
~optional()
Destructor.
Definition: optional.h:176
T & operator*()
Dereference operator.
Definition: optional.h:323
void reset()
Reset back to invalid.
Definition: optional.h:406
optional & operator=(etl::nullopt_t)
Assignment operator from nullopt.
Definition: optional.h:187
optional(const T &value_)
Constructor from value type.
Definition: optional.h:156
optional(const optional &other)
Copy constructor.
Definition: optional.h:130
void emplace(const T1 &value1, const T2 &value2, const T3 &value3, const T4 &value4)
Definition: optional.h:489
Definition: alignment.h:210
#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: exception.h:47
Definition: optional.h:76
Definition: optional.h:90
Definition: absolute.h:37
bool operator>(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition: array.h:633
bool operator>=(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition: array.h:645
bool operator!=(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition: array.h:594
etl::optional< typename etl::decay< T >::type > make_optional(T &value)
Make an optional.
Definition: optional.h:837
bool operator==(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition: array.h:582
const nullopt_t nullopt
Definition: optional.h:69
bool operator<(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition: array.h:606
bool operator<=(const etl::array< T, SIZE > &lhs, const etl::array< T, SIZE > &rhs)
Definition: array.h:621