SeqAn3  3.2.0-rc.1
The Modern C++ library for sequence analysis.
copyable_wrapper.hpp
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------------------------------
2 // Copyright (c) 2006-2022, Knut Reinert & Freie Universität Berlin
3 // Copyright (c) 2016-2022, Knut Reinert & MPI für molekulare Genetik
4 // This file may be used, modified and/or redistributed under the terms of the 3-clause BSD-License
5 // shipped with this file and also available at: https://github.com/seqan/seqan3/blob/master/LICENSE.md
6 // -----------------------------------------------------------------------------------------------------
7 
13 #pragma once
14 
15 #include <functional>
16 #include <optional>
17 
18 #include <seqan3/core/platform.hpp>
19 
20 namespace seqan3::detail
21 {
22 
28 template <typename t>
29 concept boxable = std::copy_constructible<t> && std::is_object_v<t>;
30 
35 template <typename t>
36 class copyable_wrapper : public std::optional<t>
37 {
38 public:
41  constexpr copyable_wrapper(copyable_wrapper const &) = default;
42  constexpr copyable_wrapper(copyable_wrapper &&) = default;
43  constexpr ~copyable_wrapper() = default;
44 
48  constexpr copyable_wrapper() noexcept(std::is_nothrow_default_constructible_v<t>)
49  requires std::default_initializable<t>
50  : copyable_wrapper{std::in_place}
51  {}
52 
54  constexpr copyable_wrapper &
55  operator=(copyable_wrapper const & other) noexcept(std::is_nothrow_copy_constructible_v<t>)
56  requires (!std::copyable<t>)
57  {
58  if (this != std::addressof(other))
59  {
60  if (other)
61  this->emplace(*other);
62  else
63  this->reset();
64  }
65  return *this;
66  }
67 
69  constexpr copyable_wrapper & operator=(copyable_wrapper && other) noexcept(std::is_nothrow_move_constructible_v<t>)
70  requires (!std::movable<t>)
71  {
72  if (this != std::addressof(other))
73  {
74  if (other)
75  this->emplace(std::move(*other));
76  else
77  this->reset();
78  }
79  return *this;
80  }
81 
93  template <typename... args_t>
94  requires std::invocable<t, args_t...>
95  constexpr decltype(auto) operator()(args_t... args) noexcept(std::is_nothrow_invocable_v<t, args_t...>)
96  {
97  return std::invoke(this->value(), std::forward<args_t>(args)...);
98  }
99 
101  template <typename... args_t>
102  requires std::invocable<t, args_t...>
103  constexpr decltype(auto) operator()(args_t... args) const noexcept(std::is_nothrow_invocable_v<t, args_t...>)
104  {
105  return std::invoke(this->value(), std::forward<args_t>(args)...);
106  }
107 };
108 
116 template <boxable t>
117  requires std::copyable<t>
118  || (std::is_nothrow_move_constructible_v<t> && std::is_nothrow_copy_constructible_v<t>)
119 #if SEQAN3_WORKAROUND_DEFAULT_CONSTRUCTIBLE_VIEW // If views must be default constructible, t must also be
120  && std::default_initializable<t>
121 #endif
122  class copyable_wrapper<t>
123 {
124 private:
125  t value{};
126 
127 public:
129  constexpr copyable_wrapper()
130  requires std::default_initializable<t>
131  = default;
132 
133  constexpr copyable_wrapper(copyable_wrapper const &) = default;
134  constexpr copyable_wrapper(copyable_wrapper &&) = default;
135  constexpr ~copyable_wrapper() = default;
136 
138  constexpr copyable_wrapper & operator=(copyable_wrapper const &)
139  requires std::copyable<t>
140  = default;
141 
143  constexpr copyable_wrapper & operator=(copyable_wrapper const & other) noexcept
144  {
145  // Destroy-then-copy
146  if (this != std::addressof(other))
147  {
148  value.~t(); // Call destructor of value
149  std::construct_at(std::addressof(value), *other); // Copy construct
150  }
151  return *this;
152  }
153 
155  constexpr copyable_wrapper & operator=(copyable_wrapper &&)
156  requires std::copyable<t>
157  = default;
158 
160  constexpr copyable_wrapper & operator=(copyable_wrapper && other) noexcept
161  {
162  // Destroy-then-copy
163  if (this != std::addressof(other))
164  {
165  value.~t(); // Call destructor of value
166  std::construct_at(std::addressof(value), std::move(*other)); // Move construct
167  }
168  return *this;
169  }
170 
172  constexpr explicit copyable_wrapper(t const & other) noexcept(std::is_nothrow_copy_constructible_v<t>) :
173  value{other}
174  {}
175 
177  constexpr explicit copyable_wrapper(t && other) noexcept(std::is_nothrow_move_constructible_v<t>) :
178  value{std::move(other)}
179  {}
180 
182  template <typename... args_t>
183  requires std::constructible_from<t, args_t...>
184  constexpr explicit copyable_wrapper(std::in_place_t,
185  args_t... args) noexcept(std::is_nothrow_constructible_v<t, args_t...>) :
186  value{std::forward<args_t>(args)...}
187  {}
188 
190  constexpr bool has_value() const noexcept
191  {
192  return true; // t is copyable, hence we always store a value.
193  }
194 
196  constexpr t & operator*() noexcept
197  {
198  return value;
199  }
200 
202  constexpr t const & operator*() const noexcept
203  {
204  return value;
205  }
206 
208  constexpr t * operator->() noexcept
209  {
210  return std::addressof(value);
211  }
212 
214  constexpr t const * operator->() const noexcept
215  {
216  return std::addressof(value);
217  }
218 
229  template <typename... args_t>
230  requires std::invocable<t, args_t...>
231  constexpr decltype(auto) operator()(args_t... args) noexcept(std::is_nothrow_invocable_v<t, args_t...>)
232  {
233  return std::invoke(value, std::forward<args_t>(args)...);
234  }
235 
237  template <typename... args_t>
238  requires std::invocable<t, args_t...>
239  constexpr decltype(auto) operator()(args_t... args) const noexcept(std::is_nothrow_invocable_v<t, args_t...>)
240  {
241  return std::invoke(value, std::forward<args_t>(args)...);
242  }
243 };
244 
248 template <typename t>
249 copyable_wrapper(t) -> copyable_wrapper<std::remove_reference_t<t>>;
250 
256 template <typename t>
257 using copyable_wrapper_t = copyable_wrapper<std::remove_reference_t<t>>;
258 
259 } // namespace seqan3::detail
T addressof(T... args)
T emplace(T... args)
T forward(T... args)
requires requires
The rank_type of the semi-alphabet; defined as the return type of seqan3::to_rank....
Definition: alphabet/concept.hpp:164
T in_place(T... args)
T invoke(T... args)
SeqAn specific customisations in the standard namespace.
T operator=(T... args)
Provides platform and dependency checks.
#define SEQAN3_WORKAROUND_DEFAULT_CONSTRUCTIBLE_VIEW
A view does not need to be default constructible. This change is first implemented in gcc12.
Definition: platform.hpp:233
T reset(T... args)
T value(T... args)