Coverage Report

Created: 2026-05-23 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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_