/src/Fast-CDR/include/fastcdr/xcdr/optional.hpp
Line | Count | Source (jump to first uncovered line) |
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() = default; |
95 | | |
96 | | /*! |
97 | | * @brief Constructs the contained value in-place |
98 | | * |
99 | | * @param[in] _args The arguments to pass to the constructor. |
100 | | */ |
101 | | template<class ... Args> void emplace( |
102 | | Args&&... _args) |
103 | | { |
104 | | reset(); |
105 | | storage_.val_.T(std::forward<Args>(_args)...); |
106 | | storage_.engaged_ = true; |
107 | | } |
108 | | |
109 | | /*! |
110 | | * @brief Reset the state of the optional |
111 | | * |
112 | | * @param[in] initial_engaged True value initializes the state with a default instance of the templated class. |
113 | | * False value leaves the optional in a uninitialized state. |
114 | | */ |
115 | | void reset( |
116 | | bool initial_engaged = false) |
117 | | { |
118 | | if (storage_.engaged_) |
119 | | { |
120 | | storage_.val_.~T(); |
121 | | } |
122 | | storage_.engaged_ = initial_engaged; |
123 | | if (storage_.engaged_) |
124 | | { |
125 | | ::new(&storage_.val_)T(); |
126 | | } |
127 | | } |
128 | | |
129 | | /*! |
130 | | * @brief Returns the contained value. |
131 | | * |
132 | | * @return The contained value. |
133 | | * @exception exception::BadOptionalAccessException This exception is thrown when the optional is uninitialized. |
134 | | */ |
135 | | T& value()& |
136 | | { |
137 | | if (!storage_.engaged_) |
138 | | { |
139 | | throw exception::BadOptionalAccessException( |
140 | | exception::BadOptionalAccessException::BAD_OPTIONAL_ACCESS_MESSAGE_DEFAULT); |
141 | | } |
142 | | |
143 | | return storage_.val_; |
144 | | } |
145 | | |
146 | | /*! |
147 | | * @brief Returns the contained value. |
148 | | * |
149 | | * @return The contained value. |
150 | | * @exception exception::BadOptionalAccessException This exception is thrown when the optional is uninitialized. |
151 | | */ |
152 | | const T& value() const& |
153 | | { |
154 | | if (!storage_.engaged_) |
155 | | { |
156 | | throw exception::BadOptionalAccessException( |
157 | | exception::BadOptionalAccessException::BAD_OPTIONAL_ACCESS_MESSAGE_DEFAULT); |
158 | | } |
159 | | |
160 | | return storage_.val_; |
161 | | } |
162 | | |
163 | | /*! |
164 | | * @brief Returns the contained value. |
165 | | * |
166 | | * @return The contained value. |
167 | | * @exception exception::BadOptionalAccessException This exception is thrown when the optional is uninitialized. |
168 | | */ |
169 | | T&& value() && |
170 | | { |
171 | | if (!storage_.engaged_) |
172 | | { |
173 | | throw exception::BadOptionalAccessException( |
174 | | exception::BadOptionalAccessException::BAD_OPTIONAL_ACCESS_MESSAGE_DEFAULT); |
175 | | } |
176 | | |
177 | | return std::move(storage_.val_); |
178 | | } |
179 | | |
180 | | /*! |
181 | | * @brief Returns the contained value. |
182 | | * |
183 | | * @return The contained value. |
184 | | * @exception exception::BadOptionalAccessException This exception is thrown when the optional is uninitialized. |
185 | | */ |
186 | | const T&& value() const&& |
187 | | { |
188 | | if (!storage_.engaged_) |
189 | | { |
190 | | throw exception::BadOptionalAccessException( |
191 | | exception::BadOptionalAccessException::BAD_OPTIONAL_ACCESS_MESSAGE_DEFAULT); |
192 | | } |
193 | | |
194 | | return std::move(storage_.val_); |
195 | | } |
196 | | |
197 | | /*! |
198 | | * @brief Checks whether the optional contains a value. |
199 | | * |
200 | | * @return Whether the optional contains a value. |
201 | | */ |
202 | | bool has_value() const |
203 | | { |
204 | | return storage_.engaged_; |
205 | | } |
206 | | |
207 | | //! Assigns content from an optional. |
208 | | optional& operator =( |
209 | | const optional& opt) |
210 | | { |
211 | | reset(); |
212 | | storage_.engaged_ = opt.storage_.engaged_; |
213 | | if (opt.storage_.engaged_) |
214 | | { |
215 | | ::new(&storage_.val_)T(opt.storage_.val_); |
216 | | } |
217 | | return *this; |
218 | | } |
219 | | |
220 | | //! Assigns content from an optional. |
221 | | optional& operator =( |
222 | | optional&& opt) |
223 | | { |
224 | | reset(); |
225 | | storage_.engaged_ = opt.storage_.engaged_; |
226 | | if (opt.storage_.engaged_) |
227 | | { |
228 | | ::new(&storage_.val_)T(std::move(opt.storage_.val_)); |
229 | | } |
230 | | return *this; |
231 | | } |
232 | | |
233 | | //! Assigns content from an instance of the templated class. |
234 | | optional& operator =( |
235 | | const T& val) |
236 | | { |
237 | | reset(); |
238 | | ::new(&storage_.val_)T(val); |
239 | | storage_.engaged_ = true; |
240 | | return *this; |
241 | | } |
242 | | |
243 | | //! Assigns content from an instance of the templated class. |
244 | | optional& operator =( |
245 | | T&& val) |
246 | | { |
247 | | reset(); |
248 | | ::new(&storage_.val_)T(std::move(val)); |
249 | | storage_.engaged_ = true; |
250 | | return *this; |
251 | | } |
252 | | |
253 | | //! Uninitialized the optional. |
254 | | optional& operator = ( |
255 | | nullopt_t) noexcept |
256 | | { |
257 | | reset(); |
258 | | return *this; |
259 | | } |
260 | | |
261 | | //! Compares optional values. |
262 | | bool operator ==( |
263 | | const optional& opt_val) const |
264 | | { |
265 | | return opt_val.storage_.engaged_ == storage_.engaged_ && |
266 | | (storage_.engaged_ ? opt_val.storage_.val_ == storage_.val_ : true); |
267 | | } |
268 | | |
269 | | //! Compares optional values. |
270 | | bool operator !=( |
271 | | const optional& opt_val) const |
272 | | { |
273 | | return !operator ==(opt_val); |
274 | | } |
275 | | |
276 | | /*! |
277 | | * @brief Accesses the contained value. |
278 | | * |
279 | | * The behavior is undefined if *this does not contain a value. |
280 | | * |
281 | | * @return The contained value. |
282 | | */ |
283 | | T& operator *() & noexcept |
284 | | { |
285 | | return storage_.val_; |
286 | | } |
287 | | |
288 | | /*! |
289 | | * @brief Accesses the contained value. |
290 | | * |
291 | | * The behavior is undefined if *this does not contain a value. |
292 | | * |
293 | | * @return The contained value. |
294 | | */ |
295 | | const T& operator *() const& noexcept |
296 | | { |
297 | | return storage_.val_; |
298 | | } |
299 | | |
300 | | /*! |
301 | | * @brief Accesses the contained value. |
302 | | * |
303 | | * The behavior is undefined if *this does not contain a value. |
304 | | * |
305 | | * @return The contained value. |
306 | | */ |
307 | | T&& operator *() && noexcept |
308 | | { |
309 | | return std::move(storage_.val_); |
310 | | } |
311 | | |
312 | | /*! |
313 | | * @brief Accesses the contained value. |
314 | | * |
315 | | * The behavior is undefined if *this does not contain a value. |
316 | | * |
317 | | * @return The contained value. |
318 | | */ |
319 | | const T&& operator *() const&& noexcept |
320 | | { |
321 | | return std::move(storage_.val_); |
322 | | } |
323 | | |
324 | | /*! |
325 | | * @brief Accesses the contained value. |
326 | | * |
327 | | * The behavior is undefined if *this does not contain a value. |
328 | | * |
329 | | * @return The contained value. |
330 | | */ |
331 | | T* operator ->() noexcept |
332 | | { |
333 | | return std::addressof(storage_.val_); |
334 | | } |
335 | | |
336 | | /*! |
337 | | * @brief Accesses the contained value. |
338 | | * |
339 | | * The behavior is undefined if *this does not contain a value. |
340 | | * |
341 | | * @return The contained value. |
342 | | */ |
343 | | const T* operator ->() const noexcept |
344 | | { |
345 | | return std::addressof(storage_.val_); |
346 | | } |
347 | | |
348 | | //! Checks whether the optional contains a value. |
349 | | explicit operator bool() const noexcept |
350 | | { |
351 | | return storage_.engaged_; |
352 | | } |
353 | | |
354 | | private: |
355 | | |
356 | | detail::optional_storage<T> storage_; |
357 | | }; |
358 | | |
359 | | } // namespace fastcdr |
360 | | } // namespace eprosima |
361 | | |
362 | | #endif //_FASTCDR_XCDR_OPTIONAL_HPP_ |