Coverage Report

Created: 2025-06-13 06:46

/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_