SeqAn3 3.2.0
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
19
20namespace seqan3::detail
21{
22
28template <typename t>
29concept boxable = std::copy_constructible<t> && std::is_object_v<t>;
30
35template <typename t>
36class copyable_wrapper : public std::optional<t>
37{
38public:
39 using std::optional<t>::optional;
40 using std::optional<t>::operator=;
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
116template <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{
124private:
125 t value{};
126
127public:
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
248template <typename t>
249copyable_wrapper(t) -> copyable_wrapper<std::remove_reference_t<t>>;
250
256template <typename t>
257using copyable_wrapper_t = copyable_wrapper<std::remove_reference_t<t>>;
258
259} // namespace seqan3::detail
T addressof(T... args)
T construct_at(T... args)
T emplace(T... args)
T in_place
T invoke(T... args)
T is_nothrow_constructible_v
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)