pstore2
maybe.hpp
Go to the documentation of this file.
1 //===- include/pstore/support/maybe.hpp -------------------*- mode: C++ -*-===//
2 //* _ *
3 //* _ __ ___ __ _ _ _| |__ ___ *
4 //* | '_ ` _ \ / _` | | | | '_ \ / _ \ *
5 //* | | | | | | (_| | |_| | |_) | __/ *
6 //* |_| |_| |_|\__,_|\__, |_.__/ \___| *
7 //* |___/ *
8 //===----------------------------------------------------------------------===//
9 //
10 // Part of the pstore project, under the Apache License v2.0 with LLVM Exceptions.
11 // See https://github.com/SNSystems/pstore/blob/master/LICENSE.txt for license
12 // information.
13 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
14 //
15 //===----------------------------------------------------------------------===//
23 
24 #ifndef PSTORE_SUPPORT_MAYBE_HPP
25 #define PSTORE_SUPPORT_MAYBE_HPP
26 
27 #include <new>
28 #include <stdexcept>
29 
30 #include "pstore/adt/utility.hpp"
33 
34 
35 namespace pstore {
36 
37  namespace details {
38 
39  template <typename T>
40  struct remove_cvref {
41  using type = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
42  };
43  template <typename T>
44  using remove_cvref_t = typename remove_cvref<T>::type;
45 
46  } // end namespace details
47 
48  template <typename T, typename = typename std::enable_if<!std::is_reference<T>::value>::type>
49  class maybe {
50  public:
51  using value_type = T;
52 
53  static_assert (std::is_object<value_type>::value,
54  "Instantiation of maybe<> with a non-object type is undefined behavior.");
55  static_assert (std::is_nothrow_destructible<value_type>::value,
56  "Instantiation of maybe<> with an object type that is not noexcept "
57  "destructible is undefined behavior.");
58 
60  constexpr maybe () noexcept = default;
61 
64  template <typename U,
65  typename = typename std::enable_if<
66  std::is_constructible<T, U &&>::value &&
67  !std::is_same<typename details::remove_cvref_t<U>, maybe<T>>::value>::type>
68  explicit maybe (U && value) noexcept (std::is_nothrow_move_constructible<T>::value &&
69  std::is_nothrow_copy_constructible<T>::value &&
70  !std::is_convertible<U &&, T>::value)
71  : valid_{true} {
72 
73  new (&storage_) T (std::forward<U> (value));
74  }
75 
76  template <typename... Args>
77  explicit maybe (in_place_t const inp, Args &&... args)
78  : valid_{true} {
79  (void) inp;
80  new (&storage_) T (std::forward<Args> (args)...);
81  }
82 
86  maybe (maybe const & other) noexcept (std::is_nothrow_copy_constructible<T>::value) {
87  if (other.valid_) {
88  new (&storage_) T (*other);
89  valid_ = true;
90  }
91  }
92 
97  maybe (maybe && other) noexcept (std::is_nothrow_move_constructible<T>::value) {
98  if (other.valid_) {
99  new (&storage_) T (std::move (*other));
100  valid_ = true;
101  }
102  }
103 
104  ~maybe () noexcept { this->reset (); }
105 
107  void reset () noexcept {
108  if (valid_) {
109  // Set valid_ to false before calling the dtor.
110  valid_ = false;
111  reinterpret_cast<T const *> (&storage_)->~T ();
112  }
113  }
114 
115  maybe & operator= (maybe const & other) noexcept (
116  std::is_nothrow_copy_assignable<T>::value &&
117  std::is_nothrow_copy_constructible<T>::value) {
118  if (&other != this) {
119  if (!other.has_value ()) {
120  this->reset ();
121  } else {
122  this->operator= (other.value ());
123  }
124  }
125  return *this;
126  }
127 
128  maybe &
129  operator= (maybe && other) noexcept (std::is_nothrow_move_assignable<T>::value &&
130  std::is_nothrow_move_constructible<T>::value) {
131 
132  if (&other != this) {
133  if (!other.has_value ()) {
134  this->reset ();
135  } else {
136  this->operator= (std::forward<T> (other.value ()));
137  }
138  }
139  return *this;
140  }
141 
142 
143  template <typename U,
144  typename = typename std::enable_if<
145  std::is_constructible<T, U &&>::value &&
146  !std::is_same<typename details::remove_cvref_t<U>, maybe<T>>::value>::type>
147  maybe & operator= (U && other) noexcept (
148  std::is_nothrow_copy_assignable<T>::value && std::is_nothrow_copy_constructible<
149  T>::value && std::is_nothrow_move_assignable<T>::value &&
150  std::is_nothrow_move_constructible<T>::value) {
151 
152  if (valid_) {
153  T temp = std::forward<U> (other);
154  std::swap (this->value (), temp);
155  } else {
156  new (&storage_) T (std::forward<U> (other));
157  valid_ = true;
158  }
159  return *this;
160  }
161 
167  template <typename... Args>
168  T & emplace (Args &&... args) {
169  if (valid_) {
170  T temp (std::forward<Args> (args)...);
171  std::swap (this->value (), temp);
172  } else {
173  new (&storage_) T (std::forward<Args> (args)...);
174  valid_ = true;
175  }
176  return this->value ();
177  }
178 
179  bool operator== (maybe const & other) const {
180  return this->has_value () == other.has_value () &&
181  (!this->has_value () || this->value () == other.value ());
182  }
183  bool operator!= (maybe const & other) const { return !operator== (other); }
184 
186  T const & operator* () const noexcept { return *(operator-> ()); }
188  T & operator* () noexcept { return *(operator-> ()); }
190  T const * operator-> () const noexcept {
191  PSTORE_ASSERT (valid_);
192  return reinterpret_cast<T const *> (&storage_);
193  }
195  T * operator-> () noexcept {
196  PSTORE_ASSERT (valid_);
197  return reinterpret_cast<T *> (&storage_);
198  }
199 
201  constexpr explicit operator bool () const noexcept { return valid_; }
203  constexpr bool has_value () const noexcept { return valid_; }
204 
205  T const & value () const noexcept { return value_impl (*this); }
206  T & value () noexcept { return value_impl (*this); }
207 
208  template <typename U>
209  constexpr T value_or (U && default_value) const {
210  return this->has_value () ? this->value () : default_value;
211  }
212 
213  private:
214  template <typename Maybe, typename ResultType = typename inherit_const<Maybe, T>::type>
215  static ResultType & value_impl (Maybe && m) noexcept {
216  PSTORE_ASSERT (m.has_value ());
217  return *m;
218  }
219 
220  bool valid_ = false;
221  typename std::aligned_storage<sizeof (T), alignof (T)>::type storage_;
222  };
223 
224 
225  // just
226  // ~~~~
227  template <typename T>
228  constexpr decltype (auto) just (T && value) {
229  return maybe<typename details::remove_cvref_t<T>>{std::forward<T> (value)};
230  }
231 
232  template <typename T, typename... Args>
233  constexpr decltype (auto) just (in_place_t const inp, Args &&... args) {
234  (void) inp;
235  return maybe<typename details::remove_cvref_t<T>>{in_place, std::forward<Args> (args)...};
236  }
237 
238  // nothing
239  // ~~~~~~~
240  template <typename T>
241  constexpr decltype (auto) nothing () noexcept {
243  }
244 
251  template <typename T, typename Function>
252  auto operator>>= (maybe<T> && t, Function f) -> decltype (f (*t)) {
253  if (t) {
254  return f (*t);
255  }
257  }
258 
259 } // namespace pstore
260 
261 #endif // PSTORE_SUPPORT_MAYBE_HPP
Definition: maybe.hpp:40
Provides definitions needed by the code that are available in C++17 <utility>.
maybe(maybe &&other) noexcept(std::is_nothrow_move_constructible< T >::value)
Move constructor: If other contains a value, initializes the contained value with the expression std:...
Definition: maybe.hpp:97
maybe(U &&value) noexcept(std::is_nothrow_move_constructible< T >::value &&std::is_nothrow_copy_constructible< T >::value &&!std::is_convertible< U &&, T >::value)
Constructs an optional object that contains a value, initialized with the expression std::forward<U>(...
Definition: maybe.hpp:68
Definition: print.cpp:18
constexpr bool has_value() const noexcept
checks whether the object contains a value
Definition: maybe.hpp:203
A utility template intended to simplify the writing of the const- and non-const variants of member fu...
maybe(maybe const &other) noexcept(std::is_nothrow_copy_constructible< T >::value)
Copy constructor: If other contains a value, initializes the contained value with the expression *oth...
Definition: maybe.hpp:86
Definition: utility.hpp:24
Definition: nonpod2.cpp:40
void reset() noexcept
If *this contains a value, destroy it. *this does not contain a value after this call.
Definition: maybe.hpp:107
An implementation of the standard assert() macro with the exception that it will, on failure...
Definition: maybe.hpp:49
T & emplace(Args &&... args)
Constructs the contained value in-place.
Definition: maybe.hpp:168