Coverage Report

Created: 2025-12-20 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/jsoncons/include/jsoncons/detail/expected.hpp
Line
Count
Source
1
/// Copyright 2013-2025 Daniel Parker
2
// Distributed under the Boost license, Version 1.0.
3
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
4
5
// See https://github.com/danielaparker/jsoncons2 for latest version
6
7
#ifndef JSONCONS_DETAIL_EXPECTED_HPP    
8
#define JSONCONS_DETAIL_EXPECTED_HPP    
9
10
#include <system_error>
11
#include <type_traits>
12
#include <jsoncons/config/compiler_support.hpp>
13
#include <jsoncons/detail/utility.hpp>
14
#include <cassert>
15
16
namespace jsoncons {
17
namespace detail {
18
    
19
struct unexpect_t
20
{
21
    explicit unexpect_t() = default; 
22
};
23
24
JSONCONS_INLINE_CONSTEXPR unexpect_t unexpect{};
25
26
template <typename T, typename E>
27
class expected
28
{
29
public:
30
    using value_type = T;
31
    using error_type = E;
32
private:
33
    bool has_value_;
34
    union {
35
        E error_;
36
        T value_;
37
    };
38
public:
39
    template <typename U=T>
40
    expected(typename std::enable_if<std::is_default_constructible<U>::value, int>::type = 0)
41
        : expected(T{})
42
    {
43
    }
44
45
    expected(const T& value) 
46
        : has_value_(true)
47
    {
48
        construct(value);
49
    }
50
51
    expected(T&& value) noexcept
52
13
        : has_value_(true)
53
13
    {
54
13
        construct(std::move(value));
55
13
    }
56
57
    template <typename... Args>    
58
    expected(jsoncons::detail::in_place_t, Args&& ... args) noexcept
59
        : has_value_(true)
60
    {
61
        ::new (&value_) T(std::forward<Args>(args)...);
62
    }
63
64
    template <typename... Args>    
65
    expected(unexpect_t, Args&& ... args) noexcept
66
4.52k
        : has_value_(false)
67
4.52k
    {
68
4.52k
        ::new (&error_) E(std::forward<Args>(args)...);
69
4.52k
    }
jsoncons::detail::expected<jsoncons::basic_json<char, jsoncons::sorted_policy, std::__1::allocator<char> >, jsoncons::read_error>::expected<std::__1::error_code&, unsigned long, unsigned long>(jsoncons::detail::unexpect_t, std::__1::error_code&, unsigned long&&, unsigned long&&)
Line
Count
Source
66
4.52k
        : has_value_(false)
67
4.52k
    {
68
4.52k
        ::new (&error_) E(std::forward<Args>(args)...);
69
4.52k
    }
Unexecuted instantiation: jsoncons::detail::expected<jsoncons::basic_json<char, jsoncons::sorted_policy, std::__1::allocator<char> >, jsoncons::read_error>::expected<jsoncons::conv_errc, unsigned long, unsigned long>(jsoncons::detail::unexpect_t, jsoncons::conv_errc&&, unsigned long&&, unsigned long&&)
70
    
71
    // copy constructors
72
    expected(const expected<T,E>& other) 
73
        : has_value_(other.has_value())
74
    {
75
        if (other)
76
        {
77
            construct(other.value_);
78
        }
79
        else
80
        {
81
            ::new (&error_) E(other.error_);
82
        }
83
    }
84
85
    // move constructors
86
    expected(expected<T,E>&& other) noexcept
87
        : has_value_(other.has_value())
88
    {
89
        if (other)
90
        {
91
            construct(std::move(other.value_));
92
        }
93
        else
94
        {
95
            ::new (&error_) E(other.error_);
96
        }
97
    }
98
99
    ~expected() noexcept
100
4.53k
    {
101
4.53k
        destroy();
102
4.53k
    }
103
104
    expected& operator=(const expected& other)
105
    {
106
        if (other)
107
        {
108
            assign(*other);
109
        }
110
        else
111
        {
112
            destroy();
113
            ::new (&error_) E(other.error_);
114
        }
115
        return *this;
116
    }
117
118
    expected& operator=(expected&& other)
119
    {
120
        if (other)
121
        {
122
            assign(std::move(*other));
123
        }
124
        else
125
        {
126
            destroy();
127
            ::new (&error_) E(other.error_);
128
        }
129
        return *this;
130
    }
131
132
    // value assignment
133
    expected& operator=(const T& v)
134
    {
135
        assign(v);
136
        return *this;
137
    }
138
139
    expected& operator=(T&& v)
140
    {
141
        assign(std::move(v));
142
        return *this;
143
    }
144
145
    constexpr operator bool() const noexcept
146
4.53k
    {
147
4.53k
        return has_value_;
148
4.53k
    }
149
    
150
    constexpr bool has_value() const noexcept
151
    {
152
        return has_value_;
153
    }
154
155
    JSONCONS_CPP14_CONSTEXPR T& value() &
156
    {
157
        if (has_value_)
158
        {
159
            return this->value_;
160
        }
161
        JSONCONS_THROW(std::runtime_error("Bad expected access"));
162
    }
163
164
    JSONCONS_CPP14_CONSTEXPR const T& value() const &
165
    {
166
        if (has_value_)
167
        {
168
            return this->value_;
169
        }
170
        JSONCONS_THROW(std::runtime_error("Bad expected access"));
171
    }
172
173
    JSONCONS_CPP14_CONSTEXPR T&& value() &&
174
    {
175
        if (has_value_)
176
        {
177
            return std::move(this->value_);
178
        }
179
        JSONCONS_THROW(std::runtime_error("Bad expected access"));
180
    }
181
182
    JSONCONS_CPP14_CONSTEXPR const T&& value() const &&
183
    {
184
        if (has_value_)
185
        {
186
            return std::move(this->value_);
187
        }
188
        JSONCONS_THROW(std::runtime_error("Bad expected access"));
189
    }
190
191
    JSONCONS_CPP14_CONSTEXPR E& error() & noexcept
192
13.5k
    {
193
13.5k
        assert(!has_value_);
194
13.5k
        return this->error_;
195
13.5k
    }
196
197
    JSONCONS_CPP14_CONSTEXPR const E& error() const& noexcept
198
    {
199
        assert(!has_value_);
200
        return this->error_;
201
    }
202
203
    JSONCONS_CPP14_CONSTEXPR E&& error() && noexcept
204
    {
205
        assert(!has_value_);
206
        return std::move(this->error_);
207
    }
208
209
    JSONCONS_CPP14_CONSTEXPR const E&& error() const && noexcept
210
    {
211
        assert(!has_value_);
212
        return std::move(this->error_);
213
    }
214
215
    JSONCONS_CPP14_CONSTEXPR const T* operator->() const noexcept
216
    {
217
        return std::addressof(this->value_);
218
    }
219
220
    JSONCONS_CPP14_CONSTEXPR T* operator->() noexcept
221
    {
222
        return std::addressof(this->value_);
223
    }
224
225
    JSONCONS_CPP14_CONSTEXPR const T& operator*() const & noexcept
226
    {
227
        return this->value_;
228
    }
229
230
    JSONCONS_CPP14_CONSTEXPR T& operator*() & noexcept
231
13
    {
232
13
        return this->value_;
233
13
    }
234
235
    JSONCONS_CPP14_CONSTEXPR const T&& operator*() const && noexcept
236
    {
237
        return this->value_;
238
    }
239
240
    JSONCONS_CPP14_CONSTEXPR T&& operator*() && noexcept
241
    {
242
        return this->value_;
243
    }
244
245
    void swap(expected& other) noexcept(std::is_nothrow_move_constructible<T>::value /*&&
246
                                        std::is_nothrow_swappable<T>::value*/)
247
    {
248
        const bool contains_a_value = has_value();
249
        if (contains_a_value == other.has_value())
250
        {
251
            if (contains_a_value)
252
            {
253
                using std::swap;
254
                swap(**this, *other);
255
            }
256
        }
257
        else
258
        {
259
            expected& source = contains_a_value ? *this : other;
260
            expected& target = contains_a_value ? other : *this;
261
            target = expected<T,E>(*source);
262
            source.destroy();
263
            source.error_ = target.error_;
264
        }
265
    }
266
private:
267
    void construct(const T& value) 
268
    {
269
        ::new (&value_) T(value);
270
        has_value_ = true;
271
    }
272
273
    void construct(T&& value) noexcept
274
13
    {
275
13
        ::new (&value_) T(std::move(value));
276
13
        has_value_ = true;
277
13
    }
278
279
    void destroy() noexcept 
280
4.53k
    {
281
4.53k
        if (has_value_) 
282
13
        {
283
13
            value_.~T();
284
13
            has_value_ = false;
285
13
        }
286
4.52k
        else
287
4.52k
        {
288
4.52k
            error_.~E();
289
4.52k
        }
290
4.53k
    }
291
292
    void assign(const T& u) 
293
    {
294
        if (has_value_) 
295
        {
296
            value_ = u;
297
        } 
298
        else 
299
        {
300
            construct(u);
301
        }
302
    }
303
304
    void assign(T&& u) 
305
    {
306
        if (has_value_) 
307
        {
308
            value_ = std::move(u);
309
        } 
310
        else 
311
        {
312
            construct(std::move(u));
313
        }
314
    }
315
};
316
317
template <typename E>
318
class expected<void,E>
319
{
320
public:
321
    using value_type = void;
322
    using error_type = E;
323
private:
324
    bool has_value_;
325
    union {
326
        char dummy_;
327
        E error_;
328
    };
329
public:
330
331
    expected()
332
        : has_value_(true), dummy_{}
333
    {
334
    }
335
336
    template <typename... Args>    
337
    expected(unexpect_t, Args&& ... args) noexcept
338
        : has_value_(false)
339
    {
340
        ::new (&error_) E(std::forward<Args>(args)...);
341
    }
342
    
343
    // copy constructors
344
    expected(const expected<void,E>& other) 
345
        : has_value_(other.has_value()), dummy_{}
346
    {
347
        if (!other)
348
        {
349
            ::new (&error_) E(other.error_);
350
        }
351
    }
352
353
    // move constructors
354
    expected(expected<void,E>&& other) noexcept
355
        : has_value_(other.has_value()), dummy_{}
356
    {
357
        if (!other)
358
        {
359
            ::new (&error_) E(other.error_);
360
        }
361
    }
362
363
    ~expected() noexcept
364
    {
365
        destroy();
366
    }
367
368
    expected& operator=(const expected& other)
369
    {
370
        if (other)
371
        {
372
            assign(*other);
373
        }
374
        else
375
        {
376
            destroy();
377
            ::new (&error_) E(other.error_);
378
        }
379
        return *this;
380
    }
381
382
    expected& operator=(expected&& other)
383
    {
384
        if (other)
385
        {
386
            assign(std::move(*other));
387
        }
388
        else
389
        {
390
            destroy();
391
            ::new (&error_) E(other.error_);
392
        }
393
        return *this;
394
    }
395
396
    constexpr operator bool() const noexcept
397
    {
398
        return has_value_;
399
    }
400
    
401
    constexpr bool has_value() const noexcept
402
    {
403
        return has_value_;
404
    }
405
406
    JSONCONS_CPP14_CONSTEXPR E& error() & noexcept
407
    {
408
        assert(!has_value_);
409
        return this->error_;
410
    }
411
412
    JSONCONS_CPP14_CONSTEXPR const E& error() const& noexcept
413
    {
414
        assert(!has_value_);
415
        return this->error_;
416
    }
417
418
    JSONCONS_CPP14_CONSTEXPR E&& error() && noexcept
419
    {
420
        assert(!has_value_);
421
        return std::move(this->error_);
422
    }
423
424
    JSONCONS_CPP14_CONSTEXPR const E&& error() const && noexcept
425
    {
426
        assert(!has_value_);
427
        return std::move(this->error_);
428
    }
429
430
    void swap(expected& other) noexcept
431
    {
432
        const bool contains_a_value = has_value();
433
        if (contains_a_value == other.has_value())
434
        {
435
            if (contains_a_value)
436
            {
437
                using std::swap;
438
                swap(**this, *other);
439
            }
440
        }
441
        else
442
        {
443
            expected& source = contains_a_value ? *this : other;
444
            expected& target = contains_a_value ? other : *this;
445
            target = expected<void,E>(*source);
446
            source.destroy();
447
            source.error_ = target.error_;
448
        }
449
    }
450
private:
451
    void destroy() noexcept 
452
    {
453
        if (!has_value_) 
454
        {
455
            error_.~E();
456
        }
457
    }
458
};
459
460
template <typename T,typename E>
461
typename std::enable_if<std::is_nothrow_move_constructible<T>::value,void>::type
462
swap(expected<T,E>& lhs, expected<T,E>& rhs) noexcept
463
{
464
    lhs.swap(rhs);
465
}
466
467
} // namespace detail
468
} // namespace jsoncons
469
470
#endif // JSONCONS_DETAIL_EXPECTED_HPP