/src/Fast-CDR/include/fastcdr/xcdr/optional.hpp
Line | Count | Source |
1 | | // Copyright 2023 Proyectos y Sistemas de Mantenimiento SL (eProsima). |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | // |
15 | | #ifndef _FASTCDR_XCDR_OPTIONAL_HPP_ |
16 | | #define _FASTCDR_XCDR_OPTIONAL_HPP_ |
17 | | |
18 | | #include <new> |
19 | | #include <utility> |
20 | | |
21 | | #include "detail/optional.hpp" |
22 | | #include "../exceptions/BadOptionalAccessException.hpp" |
23 | | |
24 | | namespace eprosima { |
25 | | namespace fastcdr { |
26 | | |
27 | | //! An empty class type used to indicate optional type with uninitialized state. |
28 | | struct nullopt_t |
29 | | { |
30 | | constexpr explicit nullopt_t( |
31 | | int) |
32 | 0 | { |
33 | 0 | } |
34 | | |
35 | | }; |
36 | | |
37 | | /*! |
38 | | * @brief nullopt is a constant of type nullopt_t that is used to indicate optional type with uninitialized state. |
39 | | */ |
40 | | static constexpr nullopt_t nullopt {0}; |
41 | | |
42 | | /*! |
43 | | * @brief This class template manages an optional contained value, i.e. a value that may or may not be present. |
44 | | */ |
45 | | template<class T> |
46 | | class optional |
47 | | { |
48 | | public: |
49 | | |
50 | | using type = T; |
51 | | |
52 | | //! Default constructor |
53 | | optional() = default; |
54 | | |
55 | | //! Copy constructor from an instance of the templated class. |
56 | | optional( |
57 | | const T& val) noexcept |
58 | | { |
59 | | ::new(&storage_.val_)T(val); |
60 | | storage_.engaged_ = true; |
61 | | } |
62 | | |
63 | | //! Move constructor from an instance of the templated class. |
64 | | optional( |
65 | | T&& val) noexcept |
66 | | { |
67 | | ::new(&storage_.val_)T(std::move(val)); |
68 | | storage_.engaged_ = true; |
69 | | } |
70 | | |
71 | | //! Copy constructor. |
72 | | optional( |
73 | | const optional<T>& val) noexcept |
74 | | { |
75 | | if (val.storage_.engaged_) |
76 | | { |
77 | | ::new(&storage_.val_)T(val.storage_.val_); |
78 | | storage_.engaged_ = true; |
79 | | } |
80 | | } |
81 | | |
82 | | //! Move constructor. |
83 | | optional( |
84 | | optional<T>&& val) noexcept |
85 | | { |
86 | | if (val.storage_.engaged_) |
87 | | { |
88 | | ::new(&storage_.val_)T(std::move(val.storage_.val_)); |
89 | | storage_.engaged_ = true; |
90 | | } |
91 | | } |
92 | | |
93 | | //! Destructor |
94 | | ~optional() |
95 | | #if defined(__GNUC__) && __GNUC__ >= 12 |
96 | | __attribute__( |
97 | | (noinline)) |
98 | | #endif // if defined(__GNUC__) && __GNUC__ >= 12 |
99 | | = default; |
100 | | |
101 | | /*! |
102 | | * @brief Constructs the contained value in-place |
103 | | * |
104 | | * @param[in] _args The arguments to pass to the constructor. |
105 | | */ |
106 | | template<class ... Args> void emplace( |
107 | | Args&&... _args) |
108 | | { |
109 | | reset(); |
110 | | storage_.val_.T(std::forward<Args>(_args)...); |
111 | | storage_.engaged_ = true; |
112 | | } |
113 | | |
114 | | /*! |
115 | | * @brief Reset the state of the optional |
116 | | * |
117 | | * @param[in] initial_engaged True value initializes the state with a default instance of the templated class. |
118 | | * False value leaves the optional in a uninitialized state. |
119 | | */ |
120 | | void reset( |
121 | | bool initial_engaged = false) |
122 | | { |
123 | | if (storage_.engaged_) |
124 | | { |
125 | | storage_.val_.~T(); |
126 | | } |
127 | | storage_.engaged_ = initial_engaged; |
128 | | if (storage_.engaged_) |
129 | | { |
130 | | ::new(&storage_.val_)T(); |
131 | | } |
132 | | } |
133 | | |
134 | | /*! |
135 | | * @brief Returns the contained value. |
136 | | * |
137 | | * @return The contained value. |
138 | | * @exception exception::BadOptionalAccessException This exception is thrown when the optional is uninitialized. |
139 | | */ |
140 | | T& value()& |
141 | | { |
142 | | if (!storage_.engaged_) |
143 | | { |
144 | | throw exception::BadOptionalAccessException( |
145 | | exception::BadOptionalAccessException::BAD_OPTIONAL_ACCESS_MESSAGE_DEFAULT); |
146 | | } |
147 | | |
148 | | return storage_.val_; |
149 | | } |
150 | | |
151 | | /*! |
152 | | * @brief Returns the contained value. |
153 | | * |
154 | | * @return The contained value. |
155 | | * @exception exception::BadOptionalAccessException This exception is thrown when the optional is uninitialized. |
156 | | */ |
157 | | const T& value() const& |
158 | | { |
159 | | if (!storage_.engaged_) |
160 | | { |
161 | | throw exception::BadOptionalAccessException( |
162 | | exception::BadOptionalAccessException::BAD_OPTIONAL_ACCESS_MESSAGE_DEFAULT); |
163 | | } |
164 | | |
165 | | return storage_.val_; |
166 | | } |
167 | | |
168 | | /*! |
169 | | * @brief Returns the contained value. |
170 | | * |
171 | | * @return The contained value. |
172 | | * @exception exception::BadOptionalAccessException This exception is thrown when the optional is uninitialized. |
173 | | */ |
174 | | T&& value() && |
175 | | { |
176 | | if (!storage_.engaged_) |
177 | | { |
178 | | throw exception::BadOptionalAccessException( |
179 | | exception::BadOptionalAccessException::BAD_OPTIONAL_ACCESS_MESSAGE_DEFAULT); |
180 | | } |
181 | | |
182 | | return std::move(storage_.val_); |
183 | | } |
184 | | |
185 | | /*! |
186 | | * @brief Returns the contained value. |
187 | | * |
188 | | * @return The contained value. |
189 | | * @exception exception::BadOptionalAccessException This exception is thrown when the optional is uninitialized. |
190 | | */ |
191 | | const T&& value() const&& |
192 | | { |
193 | | if (!storage_.engaged_) |
194 | | { |
195 | | throw exception::BadOptionalAccessException( |
196 | | exception::BadOptionalAccessException::BAD_OPTIONAL_ACCESS_MESSAGE_DEFAULT); |
197 | | } |
198 | | |
199 | | return std::move(storage_.val_); |
200 | | } |
201 | | |
202 | | /*! |
203 | | * @brief Checks whether the optional contains a value. |
204 | | * |
205 | | * @return Whether the optional contains a value. |
206 | | */ |
207 | | bool has_value() const |
208 | | { |
209 | | return storage_.engaged_; |
210 | | } |
211 | | |
212 | | //! Assigns content from an optional. |
213 | | optional& operator =( |
214 | | const optional& opt) |
215 | | #if defined(__GNUC__) && __GNUC__ >= 12 |
216 | | __attribute__( |
217 | | (noinline)) |
218 | | #endif // if defined(__GNUC__) && __GNUC__ >= 12 |
219 | | { |
220 | | reset(); |
221 | | storage_.engaged_ = opt.storage_.engaged_; |
222 | | if (opt.storage_.engaged_) |
223 | | { |
224 | | ::new(&storage_.val_)T(opt.storage_.val_); |
225 | | } |
226 | | return *this; |
227 | | } |
228 | | |
229 | | //! Assigns content from an optional. |
230 | | optional& operator =( |
231 | | optional&& opt) |
232 | | #if defined(__GNUC__) && __GNUC__ >= 12 |
233 | | __attribute__( |
234 | | (noinline)) |
235 | | #endif // if defined(__GNUC__) && __GNUC__ >= 12 |
236 | | { |
237 | | reset(); |
238 | | storage_.engaged_ = opt.storage_.engaged_; |
239 | | if (opt.storage_.engaged_) |
240 | | { |
241 | | ::new(&storage_.val_)T(std::move(opt.storage_.val_)); |
242 | | } |
243 | | return *this; |
244 | | } |
245 | | |
246 | | //! Assigns content from an instance of the templated class. |
247 | | optional& operator =( |
248 | | const T& val) |
249 | | { |
250 | | reset(); |
251 | | ::new(&storage_.val_)T(val); |
252 | | storage_.engaged_ = true; |
253 | | return *this; |
254 | | } |
255 | | |
256 | | //! Assigns content from an instance of the templated class. |
257 | | optional& operator =( |
258 | | T&& val) |
259 | | { |
260 | | reset(); |
261 | | ::new(&storage_.val_)T(std::move(val)); |
262 | | storage_.engaged_ = true; |
263 | | return *this; |
264 | | } |
265 | | |
266 | | //! Uninitialized the optional. |
267 | | optional& operator = ( |
268 | | nullopt_t) noexcept |
269 | | { |
270 | | reset(); |
271 | | return *this; |
272 | | } |
273 | | |
274 | | //! Compares optional values. |
275 | | bool operator ==( |
276 | | const optional& opt_val) const |
277 | | { |
278 | | return opt_val.storage_.engaged_ == storage_.engaged_ && |
279 | | (storage_.engaged_ ? opt_val.storage_.val_ == storage_.val_ : true); |
280 | | } |
281 | | |
282 | | //! Compares optional values. |
283 | | bool operator !=( |
284 | | const optional& opt_val) const |
285 | | { |
286 | | return !operator ==(opt_val); |
287 | | } |
288 | | |
289 | | /*! |
290 | | * @brief Accesses the contained value. |
291 | | * |
292 | | * The behavior is undefined if *this does not contain a value. |
293 | | * |
294 | | * @return The contained value. |
295 | | */ |
296 | | T& operator *() & noexcept |
297 | | { |
298 | | return storage_.val_; |
299 | | } |
300 | | |
301 | | /*! |
302 | | * @brief Accesses the contained value. |
303 | | * |
304 | | * The behavior is undefined if *this does not contain a value. |
305 | | * |
306 | | * @return The contained value. |
307 | | */ |
308 | | const T& operator *() const& noexcept |
309 | | { |
310 | | return storage_.val_; |
311 | | } |
312 | | |
313 | | /*! |
314 | | * @brief Accesses the contained value. |
315 | | * |
316 | | * The behavior is undefined if *this does not contain a value. |
317 | | * |
318 | | * @return The contained value. |
319 | | */ |
320 | | T && operator *() && noexcept |
321 | | { |
322 | | return std::move(storage_.val_); |
323 | | } |
324 | | |
325 | | /*! |
326 | | * @brief Accesses the contained value. |
327 | | * |
328 | | * The behavior is undefined if *this does not contain a value. |
329 | | * |
330 | | * @return The contained value. |
331 | | */ |
332 | | const T && operator*() const && noexcept |
333 | | { |
334 | | return std::move(storage_.val_); |
335 | | } |
336 | | |
337 | | /*! |
338 | | * @brief Accesses the contained value. |
339 | | * |
340 | | * The behavior is undefined if *this does not contain a value. |
341 | | * |
342 | | * @return The contained value. |
343 | | */ |
344 | | T* operator ->() noexcept |
345 | | { |
346 | | return std::addressof(storage_.val_); |
347 | | } |
348 | | |
349 | | /*! |
350 | | * @brief Accesses the contained value. |
351 | | * |
352 | | * The behavior is undefined if *this does not contain a value. |
353 | | * |
354 | | * @return The contained value. |
355 | | */ |
356 | | const T* operator ->() const noexcept |
357 | | { |
358 | | return std::addressof(storage_.val_); |
359 | | } |
360 | | |
361 | | //! Checks whether the optional contains a value. |
362 | | explicit operator bool() const noexcept |
363 | | { |
364 | | return storage_.engaged_; |
365 | | } |
366 | | |
367 | | private: |
368 | | |
369 | | detail::optional_storage<T> storage_; |
370 | | }; |
371 | | |
372 | | } // namespace fastcdr |
373 | | } // namespace eprosima |
374 | | |
375 | | #endif //_FASTCDR_XCDR_OPTIONAL_HPP_ |