SDK  2.1.4 [async]
CloudBackend Software Development Kit - SDK API for C++
Optional.h
1 #ifndef cbe__util__Optional_h__
2 #define cbe__util__Optional_h__
3 
4 #include <new> // placement new
5 #include <stdexcept> // std::exception
6 #include <type_traits> // std::aligned_storage
7 #include <utility> // std::forward, std::move
8 
9 namespace cbe {
10  namespace util {
11 
19 template <typename T>
20 class Optional {
21  bool hasValue_ = false;
22  // Byte array allocating the memory for an instance of T
23  using RawMemory = typename std::aligned_storage<sizeof(T), alignof(T)>::type;
24  RawMemory payLoad[1]; // Conceptually: unsigned char payLoad[sizeof(T)];
25 public:
30  Optional() = default;
31 
36  Optional(const T& value) : hasValue_{true} {
37  // Copy construct the instance of T in the raw memory of payLoad with help
38  // placement new
39  new (payLoad) T{value};
40  }
45  Optional(T&& value) noexcept(std::is_nothrow_move_constructible<T>::value)
46  : hasValue_{true} {
47  // Move construct ditto ...
48  new (payLoad) T{std::move(value)};
49  }
50 
55  Optional(const Optional& rh) : hasValue_{rh.hasValue_} {
56  if (hasValue_) {
57  new (payLoad) T{rh.value_cast()}; // Copy construction
58  }
59  }
64  Optional(Optional&& rh) noexcept(std::is_nothrow_move_constructible<T>::value)
65  : hasValue_{rh.hasValue_} {
66  if (hasValue_) {
67  new (payLoad) T{std::move(rh.value_cast())}; // Move construction
68  }
69  }
70 
75  Optional& operator=(const Optional& rh) {
76  Optional tmp{rh}; // Deep copy of rh, implemented in terms of the copy ctor
77  swap(tmp /* other */); // Primary purpose of swap: Transfer state from the
78  // deep copied rh into tmp, from tmp to left-hand-side
79  // object
80  return *this;
81  }
86  Optional& operator=(Optional&& rh) noexcept {
87  // The primary task is to move rh to this (i.e., left-hand-side).
88  // If we swap, we move rh to this, but also move this to rh
89  swap(rh /* other */);
90  return *this;
91  }
92 
93  ~Optional() {
94  reset(); // Destruct possible present value object
95  };
96 
102  class BadAccess : public std::runtime_error {
103  using std::runtime_error::runtime_error; // Inherit base class' ctors
104  };
105 
110  T& value() {
111  if(!hasValue_) {
112  throw BadAccess{"Value access of an empty Optional"};
113  }
114  return value_cast();
115  }
116  T& operator*() {
117  return value();
118  }
119  T* operator->() {
120  return &value();
121  }
122 
127  const T& value() const {
128  // Implemented in terms of the non-const value() method above.
129  // Cast way the const-ness, i.e., const Optional* -> Optional*
130  return const_cast<Optional*>(this)->value();
131  }
132  const T& operator*() const {
133  return value();
134  }
135  const T* operator->() const {
136  return &value();
137  }
138 
143  bool hasValue() const noexcept { return hasValue_; }
172  explicit operator bool() const noexcept { return hasValue(); }
173 
179  void reset() {
180  if (hasValue_) {
181  value_cast().~T(); // Apply the destructor on the value object
182  hasValue_ = false;
183  }
184  }
189  void swap(Optional& other) noexcept {
190  if (this != &other) {
191  if (!other.hasValue_) {
192  if (hasValue_) {
193  // Move construct lh into rh
194  new (&other) Optional{std::move(value_cast())};
195  // Reset this side since other side originally was reset
196  reset();
197  }
198  } else {
199  if (!hasValue_) {
200  // Move construct rh into lh with hwlp from placement new
201  new (this) Optional{std::move(other.value_cast())};
202  // Reset other side since this side originally was reset
203  other.reset();
204  } else {
205  std::swap(value_cast(), other.value_cast());
206  }
207  }
208  }
209  }
210 
217  template <typename... ArgTs>
218  void emplace(ArgTs&&... args) {
219  reset();
220  new (payLoad) T(std::forward<ArgTs>(args)...);
221  hasValue_ = true;
222  }
223 private:
224  inline T& value_cast() noexcept {
225  // Cast the memory buffer, RawBuffer*, to value's type, T*, and dereference
226  return *reinterpret_cast<T*>(payLoad);
227  }
228  inline const T& value_cast() const noexcept {
229  return const_cast<Optional*>(this)->value_cast();;
230  }
231 }; // class Optional
232 
233  } // namespace util
234 } // namespace cbe
235 
236 
237 #endif // #ifndef cbe__util__Optional_h__
Thrown by value() method when accessing an object that does not contain a value.
Definition: Optional.h:102
Class template Optional manages an optional contained value - i.e., a value that is either present or...
Definition: Optional.h:20
Optional(const Optional &rh)
Copy ctor.
Definition: Optional.h:55
const T & value() const
Value access const method.
Definition: Optional.h:127
Optional(const T &value)
Copy value ctor.
Definition: Optional.h:36
void emplace(ArgTs &&... args)
Constructs the contained value in-place. If *this already contains a value before the call,...
Definition: Optional.h:218
Optional & operator=(const Optional &rh)
Copy assignment operator.
Definition: Optional.h:75
Optional & operator=(Optional &&rh) noexcept
Move assignment operator.
Definition: Optional.h:86
Optional()=default
Creates an empty Optional, i.e., no value present.
T & value()
Value access non-const method.
Definition: Optional.h:110
void reset()
Invalidates possible contained value. The contained value will be destructed.
Definition: Optional.h:179
bool hasValue() const noexcept
Checks whether a value is present.
Definition: Optional.h:143
Optional(T &&value) noexcept(std::is_nothrow_move_constructible< T >::value)
Move value ctor.
Definition: Optional.h:45
void swap(Optional &other) noexcept
Swaps the contents with those of other.
Definition: Optional.h:189
Optional(Optional &&rh) noexcept(std::is_nothrow_move_constructible< T >::value)
Move ctor.
Definition: Optional.h:64
Root namespace for the CloudBackend SDK API.
Definition: Account.h:22