Support Class Library
A set of tools providing classes and utility
Optional.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <scl/macros.h>
12 #include <scl/utils/toString.h>
13 #include <scl/utils/RawStorage.h>
15 #include <iostream>
16 
17 #include <scl/tools/iostream/nl.h>
19 
20 #include <scl/concepts/require.h>
21 #include <scl/concepts/Movable.h>
22 
23 namespace scl{
24  namespace utils{
28  struct None final{
29  constexpr bool operator==(None) const{ return true; }
30  constexpr bool operator!=(None) const{ return false; }
31  constexpr bool operator<(None) const{ return false; }
32  constexpr bool operator<=(None) const{ return true; }
33  constexpr bool operator>(None) const{ return false; }
34  constexpr bool operator>=(None) const{ return true; }
35  };
36 
41  constexpr None none = None{};
42 
47  template <>
48  struct ToString<None>{
53  constexpr stringLiteral operator()(const None&) const{
54  return "[none ; scl::utils::None]";
55  }
56  };
57 
64  template <class T>
65  class Optional{
66  protected:
72 
73  public:
74  using value_type = META::remove_cv_ref_t<T>;
75 
76  public:
82  constexpr static Optional fromPointer(const T* ptr){
83  return !ptr ? Optional{none} : Optional{*ptr};
84  }
85 
86  constexpr static Optional fromPointer(std::nullptr_t){
87  return none;
88  }
89 
96  template <class... Args>
97  static Optional inplace(Args&&... args){
98  Optional ret = none;
99  value_type value{std::forward<Args>(args)...};
100  ret = std::move(value);
101  return std::move(ret);
102  }
103 
109  static Optional ref(const value_type& ref){
110  Optional ret = none;
111  ret.payload.construct(ref);
112  return ret;
113  }
114 
118  Optional() : payload{} {
119  }
120 
125  bool hasValue() const{
126  return this->payload.hasValue();
127  }
128 
134  const value_type& get() const{
135  if(!this->hasValue())
137 
138  return this->payload.get();
139  }
140 
145  Optional(const value_type& value){
146  this->payload.construct(value);
147  }
148 
154  Optional& operator=(const value_type& value){
155  this->payload.construct(value);
156  return *this;
157  }
158 
163  Optional(const Optional& o){
164  if(o.hasValue())
165  this->payload.construct(o.get());
166  };
167 
174  if(rhs.hasValue())
175  this->payload.construct(rhs.get());
176 
177  return *this;
178  };
179 
185  operator const value_type&() const{ return this->get(); }
186 
195  if(rhs.hasValue())
196  this->payload = std::move(rhs.payload);
197  };
198 
207  Optional& operator=(Optional&& rhs) noexcept{
208  if(rhs.hasValue())
209  this->payload = std::move(rhs.payload);
210  return *this;
211  };
212 
213 
214  public:
220  }
221 
228  this->payload.reset();
229  return *this;
230  }
231 
232 #define TPL template <class U, class = META::enable_if_t<\
233  !META::is_same<META::decay_t<U>, META::decay_t<T>>()\
234  && !META::is_same<META::decay_t<U>, None>()\
235  && !META::is_same<META::decay_t<U>, Optional>()\
236 >>
237 
242  TPL
243  Optional(const U& value){
244  this->payload.construct(value);
245  }
246 
253  TPL
254  Optional& operator=(const U& value){
255  this->payload.construct(value);
256  return *this;
257  }
258 
264  TPL
265  Optional(U&& value){
266  this->payload.construct(std::forward<U&&>(value));
267  }
268 
275  TPL
276  Optional& operator=(U&& value){
277  this->payload.construct(std::forward<U&&>(value));
278  return *this;
279  }
280 
281 #undef TPL
282 
288  const value_type& value() const{ return this->get(); }
289 
295  realConst(value_type*) ptr() const{ return &(this->get()); }
296 
301  operator bool() const{ return this->hasValue(); }
302 
308  const value_type& operator*() const{ return this->get(); }
309 
315  realConst(value_type*) operator->() const{ return this->ptr(); }
316 
322  const value_type& orElse(const value_type& defaultValue) const{
323  return this->hasValue() ? this->get() : defaultValue;
324  }
325 
332  template <class F>
333  const Optional& doIfPresent(F&& f) const{
334  if(this->hasValue())
335  f(this->get());
336 
337  return *this;
338  }
339 
343  template <class F>
344  const Optional& ifSome(F&& f) const{
345  return this->doIfPresent(std::forward<F>(f));
346  }
347 
354  template <class F>
355  const Optional& doIfEmpty(F&& f) const{
356  if(!this->hasValue())
357  f();
358 
359  return *this;
360  }
361 
365  template <class F>
366  const Optional& ifNone(F&& f) const{
367  return this->doIfEmpty(std::forward<F>(f));
368  }
369 
376  template <class E>
377  const value_type& orThrow(const E& e) const{
378  if(this->hasValue())
379  return this->get();
380 
381  throw e;
382  }
383 
391  template <class U, class F>
392  Optional<U> map(F&& mapper) const{
393  if(this->hasValue()){
394  const value_type& _ = this->get();
395  return mapper(_);
396  }
397 
398  return none;
399  }
400 
404  template <class U, class F>
405  Optional<U> mapTo(F&& mapper) const{ return this->map<U>(mapper); }
406 
413  template <class F>
414  Optional<T> filter(F predicate) const{
415  if(this->hasValue()){
416  const value_type& _ = this->get();
417  return predicate(_) ? Optional<T>{_} : Optional<T>{};
418  }
419 
420  return none;
421  }
422 
430  template <class U, class F>
431  Optional<U> flatMap(F&& mapper) const{
432  return this->hasValue() ? mapper(this->get()) : none;
433  }
434 
438  template <class U, class F>
439  Optional<U> flatMapTo(F&& mapper) const{
440  return this->flatMap<U>(std::forward<F>(mapper));
441  }
442 
443  public:
444  bool operator==(None) const{ return !this->hasValue(); }
445  friend bool operator==(None, const Optional& o){ return o == none; }
446 
447  bool operator<(None) const{ return false; }
448  friend bool operator<(None, const Optional&){ return true; }
449 
450  bool operator<=(None) const{ return (*this) == none; }
451  friend bool operator<=(None, const Optional&){ return true; }
452 
453  bool operator>(None) const{ return true; }
454  friend bool operator>(None, const Optional&){ return false; }
455 
456  bool operator>=(None) const{ return true; }
457  friend bool operator>=(None, const Optional& o){ return o <= none; }
458 
459  bool operator!=(None) const{ return !((*this) == none); }
460  friend bool operator!=(None, const Optional& o){ return o != none; }
461 
462 #define SCL_TPL template <class U, class = META::enable_if_t<\
463  !META::is_same<U, None>()\
464  && !META::is_same<U, Optional>()\
465  && !META::is_instance<scl::utils::Optional, U>()\
466 >>
467  SCL_TPL
468  bool operator==(const U& t) const{ return this->hasValue() && this->value() == t; }
469  SCL_TPL
470  bool operator!=(const U& t) const{ return !((*this) == t); }
471  SCL_TPL
472  bool operator<(const U& t) const{ return !this->hasValue() || this->value() < t; }
473  SCL_TPL
474  bool operator<=(const U& t) const{ return (*this) == t || (*this) < t; }
475  SCL_TPL
476  bool operator>(const U& t) const{ return !((*this) <= t); }
477  SCL_TPL
478  bool operator>=(const U& t) const{ return !((*this) < t); }
479 
480  SCL_TPL
481  friend bool operator==(const U& t, const Optional& o){ return o == t; }
482  SCL_TPL
483  friend bool operator!=(const U& t, const Optional& o){ return o != t; }
484  SCL_TPL
485  friend bool operator<(const U& t, const Optional& o){ return o > t; }
486  SCL_TPL
487  friend bool operator<=(const U& t, const Optional& o){ return o >= t; }
488  SCL_TPL
489  friend bool operator>(const U& t, const Optional& o){ return o < t; }
490  SCL_TPL
491  friend bool operator>=(const U& t, const Optional& o){ return o <= t; }
492 #undef SCL_TPL
493 
494 #define SCL_TPL template<class U/*, class = META::enable_if_t<!META::is_same<U,T>()>*/>
495  SCL_TPL
496  bool operator==(const Optional<U>& o) const{
497  if(!this->hasValue())
498  return !o.hasValue();
499 
500  return o.hasValue() && this->value() == o.value();
501  }
502 
503  SCL_TPL
504  bool operator!=(const Optional<U>& o) const{ return !((*this) == o); }
505 
506  SCL_TPL
507  bool operator<(const Optional<U>& o) const{
508  if(!this->hasValue())
509  return o.hasValue();
510 
511  return o.hasValue() && this->value() < o.value();
512  }
513 
514  SCL_TPL
515  bool operator<=(const Optional<U>& o) const{ return (*this) == o || (*this) < o; }
516 
517  SCL_TPL
518  bool operator>(const Optional<U>& o) const{ return o < (*this); }
519 
520  SCL_TPL
521  bool operator>=(const Optional<U>& o) const{ return o <= (*this); }
522 #undef SCL_TPL
523  };
524 
525  template <class T>
527  META::defines_scl_to_string<T>()
528  >>{
529  std::string operator()(const Optional<T>& opt){
530  return opt.hasValue() ? asString(*opt) : asString(none);
531  }
532  };
533  }
534 }
bool hasValue() const
Determine whether or not the storage holds a value.
Definition: RawStorage.h:170
Optional(const U &value)
Implicit conversion copy constructor.
Definition: Optional.h:243
bool operator==(const Optional< U > &o) const
Definition: Optional.h:496
Optional & operator=(Optional &&rhs) noexcept
Move assignment operator.
Definition: Optional.h:207
Optional()
Default construct (no value)
Definition: Optional.h:118
Optional< U > flatMap(F &&mapper) const
Flat maps this optional to an optional of another type.
Definition: Optional.h:431
bool operator<(const U &t) const
Definition: Optional.h:472
An empty class serving as the type of an empty Optional<T>
Definition: Optional.h:28
bool operator!=(const U &t) const
Definition: Optional.h:470
friend bool operator<(const U &t, const Optional &o)
Definition: Optional.h:485
static Optional inplace(Args &&... args)
Construct an optional inplace.
Definition: Optional.h:97
friend bool operator<=(const U &t, const Optional &o)
Definition: Optional.h:487
friend bool operator<=(None, const Optional &)
Definition: Optional.h:451
Global namespace of the SCL.
Definition: alias.hpp:3
scl::tools::meta ::remove_cv_ref_t< Lhs > value_type
Definition: Optional.h:74
bool operator<=(None) const
Definition: Optional.h:450
bool operator>(const U &t) const
Definition: Optional.h:476
static constexpr Optional fromPointer(std::nullptr_t)
Definition: Optional.h:86
Optional< U > map(F &&mapper) const
Maps this Optional<T> to an Optional<U> via the provided mapper function (T -> U) ...
Definition: Optional.h:392
#define META
Definition: macros.h:8
const value_type & get() const
Retrieves the value stored in this Optional<T>
Definition: Optional.h:134
#define realConst(type)
Definition: macros.h:3
constexpr bool operator>(None) const
Definition: Optional.h:33
static Optional ref(const value_type &ref)
Construct an optional from a reference to an object.
Definition: Optional.h:109
bool operator>=(None) const
Definition: Optional.h:456
bool operator==(const U &t) const
Definition: Optional.h:468
friend bool operator==(const U &t, const Optional &o)
Definition: Optional.h:481
T & get()
Access the underlying data.
Definition: RawStorage.h:114
constexpr const char * operator()(const None &) const
String representation of a None object.
Definition: Optional.h:53
const value_type *const ptr() const
Get an immutable pointer to the contained value.
Definition: Optional.h:295
friend bool operator>=(None, const Optional &o)
Definition: Optional.h:457
friend bool operator>(const U &t, const Optional &o)
Definition: Optional.h:489
friend bool operator<(None, const Optional &)
Definition: Optional.h:448
#define TPL
Definition: Optional.h:232
const Optional & doIfPresent(F &&f) const
Calls a function if the value is present.
Definition: Optional.h:333
Optional(const Optional &o)
Copy constructor.
Definition: Optional.h:163
const value_type & operator*() const
Access to the value.
Definition: Optional.h:308
const Optional & ifNone(F &&f) const
Alias for scl::utils::Optional::doIfEmpty.
Definition: Optional.h:366
Optional(const value_type &value)
Creates a non empty optional with the given value (copy)
Definition: Optional.h:145
Optional & operator=(const U &value)
Implicit conversion copy assignment.
Definition: Optional.h:254
friend bool operator>=(const U &t, const Optional &o)
Definition: Optional.h:491
friend bool operator!=(None, const Optional &o)
Definition: Optional.h:460
bool operator!=(None) const
Definition: Optional.h:459
Optional< U > flatMapTo(F &&mapper) const
Alias for Optional::flatMap.
Definition: Optional.h:439
constexpr bool operator>=(None) const
Definition: Optional.h:34
T * ptr(Args &&... args)
Creates a pointer in-place with the given set of arguments (using new)
Definition: ptr.h:16
bool operator<=(const U &t) const
Definition: Optional.h:474
constexpr bool operator<(None) const
Definition: Optional.h:31
Optional(U &&value)
Implicit conversion move constructor.
Definition: Optional.h:265
const value_type & orThrow(const E &e) const
Tries to retrieve the value, throws the given exception if there&#39;s none.
Definition: Optional.h:377
bool operator==(None) const
Definition: Optional.h:444
Exception class used when attempting to access the value of an empty scl::utils::Optional.
friend bool operator>(None, const Optional &)
Definition: Optional.h:454
A class that allows the use of optional types (might be there)
Definition: Optional.h:65
Optional & operator=(U &&value)
Implicit conversion move assignment.
Definition: Optional.h:276
Optional(None _)
Instantiate an optional via an instance of None.
Definition: Optional.h:219
constexpr None none
A constant global variable of type None.
Definition: Optional.h:41
friend bool operator==(None, const Optional &o)
Definition: Optional.h:445
bool operator>=(const U &t) const
Definition: Optional.h:478
bool hasValue() const
Determines whether or not this Optional<T> is empty.
Definition: Optional.h:125
Optional< T > filter(F predicate) const
Filters the value according to the given predicate.
Definition: Optional.h:414
constexpr scl::utils::Placeholder _
Definition: Placeholder.h:39
const value_type & orElse(const value_type &defaultValue) const
Retrieves the value if there&#39;s one or return the default value provided.
Definition: Optional.h:322
#define SCL_TPL
Definition: Optional.h:494
Class that handles raw storage (and manual memory management) for a variable type.
Definition: RawStorage.h:14
bool operator>(None) const
Definition: Optional.h:453
friend bool operator!=(const U &t, const Optional &o)
Definition: Optional.h:483
Optional(Optional &&rhs)
Move constructor.
Definition: Optional.h:194
constexpr bool operator!=(None) const
Definition: Optional.h:30
Optional & operator=(None _)
Assign from None.
Definition: Optional.h:227
Optional & operator=(const Optional &rhs)
Copy assignment operator.
Definition: Optional.h:173
constexpr bool operator==(None) const
Definition: Optional.h:29
constexpr bool operator<=(None) const
Definition: Optional.h:32
static constexpr Optional fromPointer(const T *ptr)
Construct an optional from a pointer.
Definition: Optional.h:82
bool operator>=(const Optional< U > &o) const
Definition: Optional.h:521
bool operator>(const Optional< U > &o) const
Definition: Optional.h:518
const value_type & value() const
A semantic alias for Optional<T>::get.
Definition: Optional.h:288
const Optional & doIfEmpty(F &&f) const
Calls a function if there is no value.
Definition: Optional.h:355
bool operator!=(const Optional< U > &o) const
Definition: Optional.h:504
Optional< U > mapTo(F &&mapper) const
Alias for Optional::map.
Definition: Optional.h:405
#define asString
Definition: macros.h:9
bool operator<(None) const
Definition: Optional.h:447
Optional & operator=(const value_type &value)
Assign a value to this optional.
Definition: Optional.h:154
T & construct(Args &&... args)
Alias for RawStorage::constructor.
Definition: RawStorage.h:89
RawStorage & reset()
Alias for RawStorage::destroy.
Definition: RawStorage.h:104
#define stringLiteral
Definition: macros.h:4
RawStorage< T > payload
A raw storage to hold an instance of the object.
Definition: Optional.h:71
const Optional & ifSome(F &&f) const
Alias for scl::utils::Optional::doIfPresent.
Definition: Optional.h:344
typename std::enable_if< B, T >::type enable_if_t
An handy type alias for the result of std::enable_if.
Definition: enable_if.h:12
const value_type *const operator->() const
Get an immutable pointer to the stored value.
Definition: Optional.h:315