OpenKalman
movable_box.hpp
Go to the documentation of this file.
1 /* This file is part of OpenKalman, a header-only C++ library for
2  * Kalman filters and other recursive filters.
3  *
4  * Copyright (c) 2025 Christopher Lee Ogden <ogden@gatech.edu>
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0. If a copy of the MPL was not distributed with this
8  * file, You can obtain one at https://mozilla.org/MPL/2.0/.
9  */
10 
17 #ifndef OPENKALMAN_COMPATIBILITY_MOVABLE_BOX_HPP
18 #define OPENKALMAN_COMPATIBILITY_MOVABLE_BOX_HPP
19 
20 #include <optional>
22 
23 namespace OpenKalman::internal
24 {
25  namespace detail
26  {
27  template<typename T>
28 #ifdef __cpp_lib_concepts
29  concept boxable =
30 #else
31  inline constexpr bool boxable =
32 #endif
33  stdex::move_constructible<T> and std::is_object_v<T>;
34 
35 
36  template<typename Tp>
37 #ifdef __cpp_lib_concepts
38  concept boxable_copyable =
39 #else
40  inline constexpr bool boxable_copyable =
41 #endif
42  stdex::copy_constructible<Tp> and
43  (stdex::copyable<Tp> or (std::is_nothrow_move_constructible_v<Tp> and std::is_nothrow_copy_constructible_v<Tp>));
44 
45 
46  template<typename Tp>
47 #ifdef __cpp_lib_concepts
48  concept boxable_movable =
49 #else
50  inline constexpr bool boxable_movable =
51 #endif
52  (not stdex::copy_constructible<Tp>) and
53  (stdex::movable<Tp> or std::is_nothrow_move_constructible_v<Tp>);
54 
55  }
56 
57 
61 #ifdef __cpp_lib_concepts
62  template<detail::boxable T>
63  struct movable_box : std::optional<T>
64 #else
65  template<typename T, typename = void>
66  struct movable_box;
67 
68  template<typename T>
69  struct movable_box<T, std::enable_if_t<
70  detail::boxable<T> and not detail::boxable_movable<T> and not detail::boxable_copyable<T>>> : std::optional<T>
71 #endif
72  {
73  using std::optional<T>::optional;
74 
75 
76 #ifdef __cpp_lib_concepts
77  constexpr
78  movable_box() noexcept(std::is_nothrow_default_constructible_v<T>) requires std::default_initializable<T>
79 #else
80  template<bool Enable = true, std::enable_if_t<Enable and stdex::default_initializable<T>, int> = 0>
81  constexpr
82  movable_box() noexcept(std::is_nothrow_default_constructible_v<T>)
83 #endif
84  : std::optional<T>{std::in_place} {}
85 
86 
87  constexpr
88  movable_box(const movable_box&) = default;
89 
90 
91  constexpr
92  movable_box(movable_box&&) = default;
93 
94 
95  using std::optional<T>::operator=;
96 
97 
98 #ifdef __cpp_lib_concepts
99  constexpr movable_box&
100  operator=(const movable_box& that) noexcept(std::is_nothrow_copy_constructible_v<T>)
101  requires (not std::copyable<T>) && std::copy_constructible<T>
102 #else
103  template<bool Enable = true, std::enable_if_t<Enable and (not stdex::copyable<T>) && stdex::copy_constructible<T>, int> = 0>
104  constexpr movable_box&
105  operator=(const movable_box& that) noexcept(std::is_nothrow_copy_constructible_v<T>)
106 #endif
107  {
108  if (this != std::addressof(that))
109  {
110  if ((bool) that) this->emplace(*that);
111  else this->reset();
112  }
113  return *this;
114  }
115 
116 
117 #ifdef __cpp_lib_concepts
118  constexpr movable_box&
119  operator=(movable_box&& that) noexcept(std::is_nothrow_move_constructible_v<T>) requires (not std::movable<T>)
120 #else
121  template<bool Enable = true, std::enable_if_t<Enable and (not stdex::movable<T>), int> = 0>
122  constexpr movable_box&
123  operator=(movable_box&& that) noexcept(std::is_nothrow_move_constructible_v<T>)
124 #endif
125  {
126  if (this != std::addressof(that))
127  {
128  if ((bool) that) this->emplace(std::move(*that));
129  else this->reset();
130  }
131  return *this;
132  }
133  };
134 
135 
136 
137 #ifdef __cpp_lib_concepts
138  template<detail::boxable T> requires detail::boxable_movable<T> or detail::boxable_copyable<T>
139  struct movable_box<T>
140 #else
141  template<typename T>
142  struct movable_box<T, std::enable_if_t<detail::boxable<T> and (detail::boxable_movable<T> or detail::boxable_copyable<T>)>>
143 #endif
144  {
145  private:
146 
147  [[no_unique_address]] T M_value = T();
148 
149  public:
150 
151 #ifdef __cpp_lib_concepts
152  constexpr
153  movable_box() requires std::default_initializable<T> = default;
154 #else
155  template<bool Enable = true, std::enable_if_t<Enable and stdex::default_initializable<T>, int> = 0>
156  constexpr
157  movable_box() {};
158 #endif
159 
160 
161 #ifdef __cpp_lib_concepts
162  constexpr explicit
163  movable_box(const T& t) noexcept(std::is_nothrow_copy_constructible_v<T>) requires std::copy_constructible<T>
164 #else
165  template<bool Enable = true, std::enable_if_t<Enable and stdex::copy_constructible<T>, int> = 0>
166  constexpr explicit
167  movable_box(const T& t) noexcept(std::is_nothrow_copy_constructible_v<T>)
168 #endif
169  : M_value(t) {}
170 
171 
172  constexpr explicit
173  movable_box(T&& t) noexcept(std::is_nothrow_move_constructible_v<T>) : M_value(std::move(t)) {}
174 
175 
176 #ifdef __cpp_lib_concepts
177  template<typename...Args> requires std::constructible_from<T, Args...>
178 #else
179  template<typename...Args, std::enable_if_t<stdex::constructible_from<T, Args...>, int> = 0>
180 #endif
181  constexpr explicit
182  movable_box(std::in_place_t, Args&&...args) noexcept(std::is_nothrow_constructible_v<T, Args...>)
183  : M_value(std::forward<Args>(args)...) {}
184 
185 
186  movable_box(const movable_box&) = default;
187 
188  movable_box(movable_box&&) = default;
189 
190 
191 #ifdef __cpp_lib_concepts
192  movable_box& operator=(const movable_box&) requires std::copyable<T> = default;
193 
194 
195  constexpr movable_box&
196  operator=(const movable_box& that) noexcept requires (not std::copyable<T>) and std::copy_constructible<T>
197  {
198  static_assert(std::is_nothrow_copy_constructible_v<T>);
199  if (this != std::addressof(that))
200  {
201  M_value.~T();
202  std::construct_at(std::addressof(M_value), *that);
203  }
204  return *this;
205  }
206 #else
207  constexpr movable_box& operator=(const movable_box& that)
208  {
209  static_assert(stdex::copy_constructible<T> and std::is_nothrow_copy_constructible_v<T>);
210  if constexpr (stdex::copyable<T>)
211  if (this != std::addressof(that))
212  {
213  if constexpr (stdex::copyable<T>)
214  {
215  M_value = that.M_value;
216  }
217  else
218  {
219  M_value.~T();
220  if constexpr (std::is_array_v<T>) return ::new (static_cast<void*>(std::addressof(M_value))) T[1]();
221  else return ::new (static_cast<void*>(std::addressof(M_value))) T(*that);
222  }
223  }
224  return *this;
225  };
226 #endif
227 
228 
229 #ifdef __cpp_lib_concepts
230  movable_box& operator=(movable_box&&) requires std::movable<T> = default;
231 
232 
233  constexpr movable_box&
234  operator=(movable_box&& that) noexcept requires (not std::movable<T>)
235  {
236  static_assert(std::is_nothrow_move_constructible_v<T>);
237  if (this != std::addressof(that))
238  {
239  M_value.~T();
240  std::construct_at(std::addressof(M_value), *that);
241  }
242  return *this;
243  }
244 #else
245  constexpr movable_box& operator=(movable_box&& that) noexcept
246  {
247  static_assert(std::is_nothrow_move_constructible_v<T>);
248  if (this != std::addressof(that))
249  {
250  if constexpr (stdex::movable<T>)
251  {
252  M_value = std::move(that.M_value);
253  }
254  else
255  {
256  M_value.~T();
257  if constexpr (std::is_array_v<T>) return ::new (static_cast<void*>(std::addressof(M_value))) T[1]();
258  else return ::new (static_cast<void*>(std::addressof(M_value))) T(std::move(*that));
259  }
260  }
261  return *this;
262  }
263 #endif
264 
265 
266  constexpr bool
267  has_value() const noexcept { return true; };
268 
269  constexpr T&
270  operator*() & noexcept { return M_value; }
271 
272  constexpr const T&
273  operator*() const & noexcept { return M_value; }
274 
275  constexpr T&&
276  operator*() && noexcept { return std::move(M_value); }
277 
278  constexpr const T&&
279  operator*() const && noexcept { return std::move(M_value); }
280 
281  constexpr T *
282  operator->() noexcept { return std::addressof(M_value); }
283 
284  constexpr const T *
285  operator->() const noexcept { return std::addressof(M_value); }
286 
287  };
288 
289 }
290 
291 #endif
Equivalent to exposition-only "movable-box" from c++23 standard.
Definition: movable_box.hpp:66
Definitions relating to standard c++ library concepts.
Definition: basics.hpp:48