SeqAn3 3.4.0-rc.1
The Modern C++ library for sequence analysis.
Loading...
Searching...
No Matches
copyable_wrapper.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2006-2024 Knut Reinert & Freie Universität Berlin
2// SPDX-FileCopyrightText: 2016-2024 Knut Reinert & MPI für molekulare Genetik
3// SPDX-License-Identifier: BSD-3-Clause
4
10#pragma once
11
12#include <functional>
13#include <optional>
14
16
17namespace seqan3::detail
18{
19
25template <typename t>
26concept boxable = std::copy_constructible<t> && std::is_object_v<t>;
27
32template <typename t>
33class copyable_wrapper : public std::optional<t>
34{
35public:
36 using std::optional<t>::optional;
37 using std::optional<t>::operator=;
38 constexpr copyable_wrapper(copyable_wrapper const &) = default;
39 constexpr copyable_wrapper(copyable_wrapper &&) = default;
40 constexpr ~copyable_wrapper() = default;
41
45 constexpr copyable_wrapper() noexcept(std::is_nothrow_default_constructible_v<t>)
46 requires std::default_initializable<t>
47 : copyable_wrapper{std::in_place}
48 {}
49
51 constexpr copyable_wrapper &
52 operator=(copyable_wrapper const & other) noexcept(std::is_nothrow_copy_constructible_v<t>)
53 requires (!std::copyable<t>)
54 {
55 if (this != std::addressof(other))
56 {
57 if (other)
58 this->emplace(*other);
59 else
60 this->reset();
61 }
62 return *this;
63 }
64
66 constexpr copyable_wrapper & operator=(copyable_wrapper && other) noexcept(std::is_nothrow_move_constructible_v<t>)
67 requires (!std::movable<t>)
68 {
69 if (this != std::addressof(other))
70 {
71 if (other)
72 this->emplace(std::move(*other));
73 else
74 this->reset();
75 }
76 return *this;
77 }
78
90 template <typename... args_t>
91 requires std::invocable<t, args_t...>
92 constexpr decltype(auto) operator()(args_t... args) noexcept(std::is_nothrow_invocable_v<t, args_t...>)
93 {
94 return std::invoke(this->value(), std::forward<args_t>(args)...);
95 }
96
98 template <typename... args_t>
99 requires std::invocable<t, args_t...>
100 constexpr decltype(auto) operator()(args_t... args) const noexcept(std::is_nothrow_invocable_v<t, args_t...>)
101 {
102 return std::invoke(this->value(), std::forward<args_t>(args)...);
103 }
104};
105
113template <boxable t>
114 requires std::copyable<t>
115 || (std::is_nothrow_move_constructible_v<t> && std::is_nothrow_copy_constructible_v<t>)
116#if SEQAN3_WORKAROUND_DEFAULT_CONSTRUCTIBLE_VIEW // If views must be default constructible, t must also be
117 && std::default_initializable<t>
118#endif
119 class copyable_wrapper<t>
120{
121private:
122 t value{};
123
124public:
126 constexpr copyable_wrapper()
127 requires std::default_initializable<t>
128 = default;
129
130 constexpr copyable_wrapper(copyable_wrapper const &) = default;
131 constexpr copyable_wrapper(copyable_wrapper &&) = default;
132 constexpr ~copyable_wrapper() = default;
133
135 constexpr copyable_wrapper & operator=(copyable_wrapper const &)
136 requires std::copyable<t>
137 = default;
138
140 constexpr copyable_wrapper & operator=(copyable_wrapper const & other) noexcept
141 {
142 // Destroy-then-copy
143 if (this != std::addressof(other))
144 {
145 value.~t(); // Call destructor of value
146 std::construct_at(std::addressof(value), *other); // Copy construct
147 }
148 return *this;
149 }
150
152 constexpr copyable_wrapper & operator=(copyable_wrapper &&)
153 requires std::copyable<t>
154 = default;
155
157 constexpr copyable_wrapper & operator=(copyable_wrapper && other) noexcept
158 {
159 // Destroy-then-copy
160 if (this != std::addressof(other))
161 {
162 value.~t(); // Call destructor of value
163 std::construct_at(std::addressof(value), std::move(*other)); // Move construct
164 }
165 return *this;
166 }
167
169 constexpr explicit copyable_wrapper(t const & other) noexcept(std::is_nothrow_copy_constructible_v<t>) :
170 value{other}
171 {}
172
174 constexpr explicit copyable_wrapper(t && other) noexcept(std::is_nothrow_move_constructible_v<t>) :
175 value{std::move(other)}
176 {}
177
179 template <typename... args_t>
180 requires std::constructible_from<t, args_t...>
181 constexpr explicit copyable_wrapper(std::in_place_t,
182 args_t... args) noexcept(std::is_nothrow_constructible_v<t, args_t...>) :
183 value{std::forward<args_t>(args)...}
184 {}
185
187 constexpr bool has_value() const noexcept
188 {
189 return true; // t is copyable, hence we always store a value.
190 }
191
193 constexpr t & operator*() noexcept
194 {
195 return value;
196 }
197
199 constexpr t const & operator*() const noexcept
200 {
201 return value;
202 }
203
205 constexpr t * operator->() noexcept
206 {
207 return std::addressof(value);
208 }
209
211 constexpr t const * operator->() const noexcept
212 {
213 return std::addressof(value);
214 }
215
226 template <typename... args_t>
227 requires std::invocable<t, args_t...>
228 constexpr decltype(auto) operator()(args_t... args) noexcept(std::is_nothrow_invocable_v<t, args_t...>)
229 {
230 return std::invoke(value, std::forward<args_t>(args)...);
231 }
232
234 template <typename... args_t>
235 requires std::invocable<t, args_t...>
236 constexpr decltype(auto) operator()(args_t... args) const noexcept(std::is_nothrow_invocable_v<t, args_t...>)
237 {
238 return std::invoke(value, std::forward<args_t>(args)...);
239 }
240};
241
245template <typename t>
246copyable_wrapper(t) -> copyable_wrapper<std::remove_reference_t<t>>;
247
253template <typename t>
254using copyable_wrapper_t = copyable_wrapper<std::remove_reference_t<t>>;
255
256} // namespace seqan3::detail
T addressof(T... args)
T construct_at(T... args)
T emplace(T... args)
T forward(T... args)
T in_place
T invoke(T... args)
T is_nothrow_constructible_v
T move(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:216
T reset(T... args)
T value(T... args)
Hide me